ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/main.C
(Generate patch)

Comparing deliantra/server/server/main.C (file contents):
Revision 1.23 by root, Sun Sep 10 15:59:57 2006 UTC vs.
Revision 1.71 by root, Mon Jan 1 15:32:40 2007 UTC

1
2/*
3 * static char *rcsid_main_c =
4 * "$Id: main.C,v 1.23 2006/09/10 15:59:57 root Exp $";
5 */
6
7/* 1/*
8 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
9 3
10 Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team 4 Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
22 16
23 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 20
27 The authors can be reached via e-mail at crossfire-devel@real-time.com 21 The authors can be reached via e-mail at <crossfire@schmorp.de>
28*/ 22*/
29 23
30#include <global.h> 24#include <global.h>
31#include <object.h> 25#include <object.h>
32#include <tod.h> 26#include <tod.h>
37# ifdef HAVE_CRYPT_H 31# ifdef HAVE_CRYPT_H
38# include <crypt.h> 32# include <crypt.h>
39# endif 33# endif
40#endif 34#endif
41 35
42#ifndef __CEXTRACT__
43# include <sproto.h> 36#include <sproto.h>
44#endif
45
46#ifdef HAVE_TIME_H
47# include <time.h> 37#include <time.h>
48#endif
49 38
50#include <../random_maps/random_map.h> 39#include <../random_maps/random_map.h>
51#include <../random_maps/rproto.h> 40#include <../random_maps/rproto.h>
52#include "path.h" 41#include "path.h"
53 42
56}; 45};
57 46
58void 47void
59version (object *op) 48version (object *op)
60{ 49{
61 if (op != NULL) 50 if (op)
62 clear_win_info (op); 51 clear_win_info (op);
63 52
64 new_draw_info_format (NDI_UNIQUE, 0, op, "This is Crossfire v%s", VERSION); 53 new_draw_info_format (NDI_UNIQUE, 0, op, "This is Crossfire+ v%s", VERSION);
65 54
66/* If in a socket, don't print out the list of authors. It confuses the
67 * crossclient program.
68 */
69 if (op == NULL)
70 return;
71 new_draw_info (NDI_UNIQUE, 0, op, "Authors and contributors to this program:"); 55 new_draw_info (NDI_UNIQUE, 0, op, "Authors and contributors to this program:");
56 new_draw_info (NDI_UNIQUE, 0, op, "Marc A. Lehmann <pcg@goof.com>");
57 new_draw_info (NDI_UNIQUE, 0, op, "Robin Redeker <elmex@x-paste.de>");
58 new_draw_info (NDI_UNIQUE, 0, op, "Pippijn van Steenhoven <pip88nl@gmail.com>");
72 new_draw_info (NDI_UNIQUE, 0, op, "mwedel@sonic.net (Mark Wedel)"); 59 new_draw_info (NDI_UNIQUE, 0, op, "Mark Wedel <mwedel@sonic.net>");
73 new_draw_info (NDI_UNIQUE, 0, op, "frankj@ifi.uio.no (Frank Tore Johansen)"); 60 new_draw_info (NDI_UNIQUE, 0, op, "Frank Tore Johansen <frankj@ifi.uio.no>");
74 new_draw_info (NDI_UNIQUE, 0, op, "kjetilho@ifi.uio.no (Kjetil Torgrim Homme)"); 61 new_draw_info (NDI_UNIQUE, 0, op, "Kjetil Torgrim Homme <kjetilho@ifi.uio.no>");
75 new_draw_info (NDI_UNIQUE, 0, op, "tvangod@ecst.csuchico.edu (Tyler Van Gorder)"); 62 new_draw_info (NDI_UNIQUE, 0, op, "Tyler Van Gorder <tvangod@ecst.csuchico.edu>");
76 new_draw_info (NDI_UNIQUE, 0, op, "elmroth@cd.chalmers.se (Tony Elmroth)"); 63 new_draw_info (NDI_UNIQUE, 0, op, "Tony Elmroth <elmroth@cd.chalmers.se>");
77 new_draw_info (NDI_UNIQUE, 0, op, "dougal.scott@fcit.monasu.edu.au (Dougal Scott)"); 64 new_draw_info (NDI_UNIQUE, 0, op, "Dougal Scott <dougal.scott@fcit.monasu.edu.au>");
78 new_draw_info (NDI_UNIQUE, 0, op, "wchuang@athena.mit.edu (William)"); 65 new_draw_info (NDI_UNIQUE, 0, op, "William <wchuang@athena.mit.edu>");
79 new_draw_info (NDI_UNIQUE, 0, op, "ftww@cs.su.oz.au (Geoff Bailey)"); 66 new_draw_info (NDI_UNIQUE, 0, op, "Geoff Bailey <ftww@cs.su.oz.au>");
80 new_draw_info (NDI_UNIQUE, 0, op, "jorgens@flipper.pvv.unit.no (Kjetil Wiekhorst Jxrgensen)"); 67 new_draw_info (NDI_UNIQUE, 0, op, "Kjetil Wiekhorst Jørgensen <jorgens@flipper.pvv.unit.no>");
81 new_draw_info (NDI_UNIQUE, 0, op, "c.blackwood@rdt.monash.edu.au (Cameron Blackwood)"); 68 new_draw_info (NDI_UNIQUE, 0, op, "Cameron Blackwood <c.blackwood@rdt.monash.edu.au>");
82 new_draw_info (NDI_UNIQUE, 0, op, "jtraub+@cmu.edu (Joseph L. Traub)"); 69 new_draw_info (NDI_UNIQUE, 0, op, "Joseph L. Traub <jtraub+@cmu.edu>");
83 new_draw_info (NDI_UNIQUE, 0, op, "rgg@aaii.oz.au (Rupert G. Goldie)"); 70 new_draw_info (NDI_UNIQUE, 0, op, "Rupert G. Goldie <rgg@aaii.oz.au>");
84 new_draw_info (NDI_UNIQUE, 0, op, "eanders+@cmu.edu (Eric A. Anderson)"); 71 new_draw_info (NDI_UNIQUE, 0, op, "Eric A. Anderson <eanders+@cmu.edu>");
85 new_draw_info (NDI_UNIQUE, 0, op, "eneq@Prag.DoCS.UU.SE (Rickard Eneqvist)"); 72 new_draw_info (NDI_UNIQUE, 0, op, "Rickard Eneqvist <eneq@Prag.DoCS.UU.SE>");
86 new_draw_info (NDI_UNIQUE, 0, op, "Jarkko.Sonninen@lut.fi (Jarkko Sonninen)"); 73 new_draw_info (NDI_UNIQUE, 0, op, "Jarkko Sonninen <Jarkko.Sonninen@lut.fi>");
87 new_draw_info (NDI_UNIQUE, 0, op, "kholland@sunlab.cit.cornell.du (Karl Holland)"); 74 new_draw_info (NDI_UNIQUE, 0, op, "Karl Holland <kholland@sunlab.cit.cornell.du>");
88 new_draw_info (NDI_UNIQUE, 0, op, "vick@bern.docs.uu.se (Mikael Lundgren)"); 75 new_draw_info (NDI_UNIQUE, 0, op, "Mikael Lundgren <vick@bern.docs.uu.se>");
89 new_draw_info (NDI_UNIQUE, 0, op, "mol@meryl.csd.uu.se (Mikael Olsson)"); 76 new_draw_info (NDI_UNIQUE, 0, op, "Mikael Olsson <mol@meryl.csd.uu.se>");
90 new_draw_info (NDI_UNIQUE, 0, op, "Tero.Haatanen@lut.fi (Tero Haatanen)"); 77 new_draw_info (NDI_UNIQUE, 0, op, "Tero Haatanen <Tero.Haatanen@lut.fi>");
91 new_draw_info (NDI_UNIQUE, 0, op, "ylitalo@student.docs.uu.se (Lasse Ylitalo)"); 78 new_draw_info (NDI_UNIQUE, 0, op, "Lasse Ylitalo <ylitalo@student.docs.uu.se>");
92 new_draw_info (NDI_UNIQUE, 0, op, "anipa@guru.magic.fi (Niilo Neuvo)"); 79 new_draw_info (NDI_UNIQUE, 0, op, "Niilo Neuvo <anipa@guru.magic.fi>");
93 new_draw_info (NDI_UNIQUE, 0, op, "mta@modeemi.cs.tut.fi (Markku J{rvinen)"); 80 new_draw_info (NDI_UNIQUE, 0, op, "Markku J{rvinen <mta@modeemi.cs.tut.fi>");
94 new_draw_info (NDI_UNIQUE, 0, op, "meunier@inf.enst.fr (Sylvain Meunier)"); 81 new_draw_info (NDI_UNIQUE, 0, op, "Sylvain Meunier <meunier@inf.enst.fr>");
95 new_draw_info (NDI_UNIQUE, 0, op, "jfosback@darmok.uoregon.edu (Jason Fosback)"); 82 new_draw_info (NDI_UNIQUE, 0, op, "Jason Fosback <jfosback@darmok.uoregon.edu>");
96 new_draw_info (NDI_UNIQUE, 0, op, "cedman@capitalist.princeton.edu (Carl Edman)"); 83 new_draw_info (NDI_UNIQUE, 0, op, "Carl Edman <cedman@capitalist.princeton.edu>");
97 new_draw_info (NDI_UNIQUE, 0, op, "henrich@crh.cl.msu.edu (Charles Henrich)"); 84 new_draw_info (NDI_UNIQUE, 0, op, "Charles Henrich <henrich@crh.cl.msu.edu>");
98 new_draw_info (NDI_UNIQUE, 0, op, "schmid@fb3-s7.math.tu-berlin.de (Gregor Schmid)"); 85 new_draw_info (NDI_UNIQUE, 0, op, "Gregor Schmid <schmid@fb3-s7.math.tu-berlin.de>");
99 new_draw_info (NDI_UNIQUE, 0, op, "quinet@montefiore.ulg.ac.be (Raphael Quinet)"); 86 new_draw_info (NDI_UNIQUE, 0, op, "Raphael Quinet <quinet@montefiore.ulg.ac.be>");
100 new_draw_info (NDI_UNIQUE, 0, op, "jam@modeemi.cs.tut.fi (Jari Vanhala)"); 87 new_draw_info (NDI_UNIQUE, 0, op, "Jari Vanhala <jam@modeemi.cs.tut.fi>");
101 new_draw_info (NDI_UNIQUE, 0, op, "kivinen@joker.cs.hut.fi (Tero Kivinen)"); 88 new_draw_info (NDI_UNIQUE, 0, op, "Tero Kivinen <kivinen@joker.cs.hut.fi>");
102 new_draw_info (NDI_UNIQUE, 0, op, "peterm@soda.berkeley.edu (Peter Mardahl)"); 89 new_draw_info (NDI_UNIQUE, 0, op, "Peter Mardahl <peterm@soda.berkeley.edu>");
103 new_draw_info (NDI_UNIQUE, 0, op, "matt@cs.odu.edu (Matthew Zeher)"); 90 new_draw_info (NDI_UNIQUE, 0, op, "Matthew Zeher <matt@cs.odu.edu>");
104 new_draw_info (NDI_UNIQUE, 0, op, "srt@sun-dimas.aero.org (Scott R. Turner)"); 91 new_draw_info (NDI_UNIQUE, 0, op, "Scott R. Turner <srt@sun-dimas.aero.org>");
105 new_draw_info (NDI_UNIQUE, 0, op, "huma@netcom.com (Ben Fennema)"); 92 new_draw_info (NDI_UNIQUE, 0, op, "Ben Fennema <huma@netcom.com>");
106 new_draw_info (NDI_UNIQUE, 0, op, "njw@cs.city.ac.uk (Nick Williams)"); 93 new_draw_info (NDI_UNIQUE, 0, op, "Nick Williams <njw@cs.city.ac.uk>");
107 new_draw_info (NDI_UNIQUE, 0, op, "Wacren@Gin.ObsPM.Fr (Laurent Wacrenier)"); 94 new_draw_info (NDI_UNIQUE, 0, op, "Laurent Wacrenier <Wacren@Gin.ObsPM.Fr>");
108 new_draw_info (NDI_UNIQUE, 0, op, "thomas@astro.psu.edu (Brian Thomas)"); 95 new_draw_info (NDI_UNIQUE, 0, op, "Brian Thomas <thomas@astro.psu.edu>");
109 new_draw_info (NDI_UNIQUE, 0, op, "jsm@axon.ksc.nasa.gov (John Steven Moerk)"); 96 new_draw_info (NDI_UNIQUE, 0, op, "John Steven Moerk <jsm@axon.ksc.nasa.gov>");
110 new_draw_info (NDI_UNIQUE, 0, op, "Delbecq David [david.delbecq@mailandnews.com]"); 97 new_draw_info (NDI_UNIQUE, 0, op, "Delbecq David <david.delbecq@mailandnews.com>");
111 new_draw_info (NDI_UNIQUE, 0, op, "Chachkoff Yann [yann.chachkoff@mailandnews.com]\n"); 98 new_draw_info (NDI_UNIQUE, 0, op, "Chachkoff Yann <yann.chachkoff@mailandnews.com>\n");
99
112 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:"); 100 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:");
113 new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner"); 101 new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner");
114 new_draw_info (NDI_UNIQUE, 0, op, "David Gervais [david_eg@mail.com]"); 102 new_draw_info (NDI_UNIQUE, 0, op, "David Gervais <david_eg@mail.com>");
115 new_draw_info (NDI_UNIQUE, 0, op, "Mitsuhiro Itakura [ita@gold.koma.jaeri.go.jp]"); 103 new_draw_info (NDI_UNIQUE, 0, op, "Mitsuhiro Itakura <ita@gold.koma.jaeri.go.jp>");
116 new_draw_info (NDI_UNIQUE, 0, op, "Hansjoerg Malthaner [hansjoerg.malthaner@danet.de]"); 104 new_draw_info (NDI_UNIQUE, 0, op, "Hansjoerg Malthaner <hansjoerg.malthaner@danet.de>");
117 new_draw_info (NDI_UNIQUE, 0, op, "Mårten Woxberg [maxmc@telia.com]"); 105 new_draw_info (NDI_UNIQUE, 0, op, "MÃ¥rten Woxberg <maxmc@telia.com>");
118 new_draw_info (NDI_UNIQUE, 0, op, "And many more!"); 106 new_draw_info (NDI_UNIQUE, 0, op, "And many more!");
119}
120
121void
122info_keys (object *op)
123{
124 clear_win_info (op);
125 new_draw_info (NDI_UNIQUE, 0, op, "Push `hjklynub' to walk in a direction.");
126 new_draw_info (NDI_UNIQUE, 0, op, "Shift + dir = fire, Ctrl + dir = run");
127 new_draw_info (NDI_UNIQUE, 0, op, "(To fire at yourself, hit `.'");
128 new_draw_info (NDI_UNIQUE, 0, op, "To attack, walk into the monsters.");
129 new_draw_info (NDI_UNIQUE, 0, op, "\" = speak ' = extended command");
130 new_draw_info (NDI_UNIQUE, 0, op, "i = inventory , = get : = look");
131 new_draw_info (NDI_UNIQUE, 0, op, "<> = rotate d = drop ? = help");
132 new_draw_info (NDI_UNIQUE, 0, op, "a = apply A = apply below t = throw");
133 new_draw_info (NDI_UNIQUE, 0, op, "e = examine E = exa below @ = autopick");
134 new_draw_info (NDI_UNIQUE, 0, op, "C = configure s = brace v = version");
135 new_draw_info (NDI_UNIQUE, 0, op, "+- = change range <tab> = browse spells");
136 new_draw_info (NDI_UNIQUE, 0, op, "x = change inventory type");
137 new_draw_info (NDI_UNIQUE, 0, op, "Mouse: L = examine, M = apply, R = drop/get");
138 new_draw_info (NDI_UNIQUE, 0, op, "'help = info about extended commands.");
139 new_draw_info (NDI_UNIQUE, 0, op, "Ctrl-R = refresh Ctrl-C = clear");
140 new_draw_info (NDI_UNIQUE, 0, op, "You can type a number before most commands.");
141 new_draw_info (NDI_UNIQUE, 0, op, "(For instance 3d drops 3 items.)");
142}
143
144void
145start_info (object *op)
146{
147 char buf[MAX_BUF];
148
149 sprintf (buf, "Welcome to Crossfire, v%s!", VERSION);
150 new_draw_info (NDI_UNIQUE, 0, op, buf);
151 new_draw_info (NDI_UNIQUE, 0, op, "Press `?' for help");
152 new_draw_info (NDI_UNIQUE, 0, op, " ");
153 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, op, "%s entered the game.", &op->name);
154 if (!op->contr->name_changed)
155 {
156 new_draw_info (NDI_UNIQUE, 0, op, "Note that you must set your name with the name");
157 new_draw_info (NDI_UNIQUE, 0, op, "command to enter the highscore list.");
158 new_draw_info (NDI_UNIQUE, 0, op, "(You can also use the crossfire.name X-resource.)");
159 }
160}
161
162/* Really, there is no reason to crypt the passwords any system. But easier
163 * to just leave this enabled for backward compatibility. Put the
164 * simple case at top - no encryption - makes it easier to read.
165 */
166char *
167crypt_string (char *str, char *salt)
168{
169#if defined(WIN32) || (defined(__FreeBSD__) && !defined(HAVE_LIBDES))
170 return (str);
171#else
172 static char *c = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
173 char s[2];
174
175 if (salt == NULL)
176 s[0] = c[RANDOM () % (int) strlen (c)], s[1] = c[RANDOM () % (int) strlen (c)];
177 else
178 s[0] = salt[0], s[1] = salt[1];
179
180# ifdef HAVE_LIBDES
181 return (char *) des_crypt (str, s);
182# endif
183 /* Default case - just use crypt */
184 return (char *) crypt (str, s);
185#endif
186}
187
188int
189check_password (char *typed, char *crypted)
190{
191 return !strcmp (crypt_string (typed, crypted), crypted);
192} 107}
193 108
194/* This is a basic little function to put the player back to his 109/* This is a basic little function to put the player back to his
195 * savebed. We do some error checking - its possible that the 110 * savebed. We do some error checking - its possible that the
196 * savebed map may no longer exist, so we make sure the player 111 * savebed map may no longer exist, so we make sure the player
197 * goes someplace. 112 * goes someplace.
198 */ 113 */
199void 114void
200enter_player_savebed (object *op) 115enter_player_savebed (object *op)
201{ 116{
202 mapstruct *oldmap = op->map; 117 object *tmp = object::create ();
203 object *tmp;
204
205 tmp = get_object ();
206
207 EXIT_PATH (tmp) = op->contr->savebed_map; 118 EXIT_PATH (tmp) = op->contr->savebed_map;
208 EXIT_X (tmp) = op->contr->bed_x; 119 EXIT_X (tmp) = op->contr->bed_x;
209 EXIT_Y (tmp) = op->contr->bed_y; 120 EXIT_Y (tmp) = op->contr->bed_y;
210 enter_exit (op, tmp); 121 op->enter_exit (tmp);
211 /* If the player has not changed maps and the name does not match 122 tmp->destroy ();
212 * that of the savebed, his savebed map is gone. Lets go back
213 * to the emergency path. Update what the players savebed is
214 * while we're at it.
215 */
216 if (oldmap == op->map && strcmp (op->contr->savebed_map, oldmap->path))
217 {
218 LOG (llevDebug, "Player %s savebed location %s is invalid - going to emergency location (%s)\n",
219 settings.emergency_mapname, &op->name, op->contr->savebed_map);
220 strcpy (op->contr->savebed_map, settings.emergency_mapname);
221 op->contr->bed_x = settings.emergency_x;
222 op->contr->bed_y = settings.emergency_y;
223 EXIT_PATH (tmp) = op->contr->savebed_map;
224 EXIT_X (tmp) = op->contr->bed_x;
225 EXIT_Y (tmp) = op->contr->bed_y;
226 enter_exit (op, tmp);
227 }
228 free_object (tmp);
229}
230
231/* All this really is is a glorified remove_object that also updates
232 * the counts on the map if needed.
233 */
234void
235leave_map (object *op)
236{
237 mapstruct *oldmap = op->map;
238
239 remove_ob (op);
240
241 if (oldmap)
242 {
243 if (!op->contr->hidden)
244 oldmap->players--;
245 if (oldmap->players <= 0)
246 { /* can be less than zero due to errors in tracking this */
247 set_map_timeout (oldmap);
248 }
249 }
250} 123}
251 124
252/* 125/*
253 * enter_map(): Moves the player and pets from current map (if any) to 126 * enter_map(): Moves the player and pets from current map (if any) to
254 * new map. map, x, y must be set. map is the map we are moving the 127 * new map. map, x, y must be set. map is the map we are moving the
255 * player to - it could be the map he just came from if the load failed for 128 * player to - it could be the map he just came from if the load failed for
256 * whatever reason. If default map coordinates are to be used, then 129 * whatever reason. If default map coordinates are to be used, then
257 * the function that calls this should figure them out. 130 * the function that calls this should figure them out.
258 */ 131 */
259static void 132void
260enter_map (object *op, mapstruct *newmap, int x, int y) 133object::enter_map (maptile *newmap, int x, int y)
261{ 134{
262 mapstruct *oldmap = op->map; 135 if (destroyed () || !newmap)
136 return;
263 137
264 if (out_of_map (newmap, x, y)) 138 if (out_of_map (newmap, x, y))
265 { 139 {
266 LOG (llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", newmap->path, x, y); 140 LOG (llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", &newmap->path, x, y);
267 x = MAP_ENTER_X (newmap); 141 x = newmap->enter_x;
268 y = MAP_ENTER_Y (newmap); 142 y = newmap->enter_y;
269 if (out_of_map (newmap, x, y)) 143 if (out_of_map (newmap, x, y))
270 { 144 {
271 LOG (llevError, "enter_map: map %s provides invalid default enter location (%d, %d) > (%d, %d)\n", 145 LOG (llevError, "enter_map: map %s provides invalid default enter location (%d, %d) > (%d, %d)\n",
272 newmap->path, x, y, MAP_WIDTH (newmap), MAP_HEIGHT (newmap)); 146 &newmap->path, x, y, newmap->width, newmap->height);
273 new_draw_info (NDI_UNIQUE, 0, op, "The exit is closed"); 147 new_draw_info (NDI_UNIQUE, 0, this, "The exit is closed");
274 return; 148 return;
275 } 149 }
276 } 150 }
151
152 if (map && map != newmap)
153 if (INVOKE_MAP (LEAVE, map, ARG_PLAYER (contr)))
154 return;
155
156 /* If it is a player login, he has yet to be inserted anyplace.
157 * otherwise, we need to deal with removing the player here.
158 */
159 remove ();
160
277 /* try to find a spot for the player */ 161 /* try to find a spot for the player */
278 if (ob_blocked (op, newmap, x, y)) 162 if (ob_blocked (this, newmap, x, y))
279 { /* First choice blocked */ 163 { /* First choice blocked */
280 /* We try to find a spot for the player, starting closest in. 164 /* We try to find a spot for the player, starting closest in.
281 * We could use find_first_free_spot, but that doesn't randomize it at all, 165 * We could use find_first_free_spot, but that doesn't randomize it at all,
282 * So for example, if the north space is free, you would always end up there even 166 * So for example, if the north space is free, you would always end up there even
283 * if other spaces around are available. 167 * if other spaces around are available.
284 * Note that for the second and third calls, we could start at a position other 168 * Note that for the second and third calls, we could start at a position other
285 * than one, but then we could end up on the other side of walls and so forth. 169 * than one, but then we could end up on the other side of walls and so forth.
286 */ 170 */
287 int i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE1 + 1); 171 int i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE1 + 1);
288 172
289 if (i == -1) 173 if (i == -1)
290 { 174 {
291 i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE2 + 1); 175 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE2 + 1);
292 if (i == -1) 176 if (i == -1)
293 i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE); 177 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE);
294 } 178 }
179
295 if (i != -1) 180 if (i != -1)
296 { 181 {
297 x += freearr_x[i]; 182 x += freearr_x[i];
298 y += freearr_y[i]; 183 y += freearr_y[i];
299 } 184 }
300 else 185 else
301 {
302 /* not much we can do in this case. */ 186 /* not much we can do in this case. */
303 LOG (llevInfo, "enter_map: Could not find free spot for player - will dump on top of object (%s: %d, %d)\n", newmap->path, x, y); 187 LOG (llevInfo, "enter_map: Could not find free spot for player - will dump on top of object (%s: %d, %d)\n", &newmap->path, x, y);
304 }
305 } /* end if looking for free spot */
306
307 if (op->map != NULL)
308 { 188 }
309 INVOKE_PLAYER (MAP_CHANGE, op->contr, ARG_MAP (op->map), ARG_MAP (newmap)); 189
310 INVOKE_MAP (LEAVE, op->map, ARG_PLAYER (op->contr)); 190 if (map != newmap && contr)
311 } 191 {
192 if (INVOKE_PLAYER (MAP_CHANGE, contr, ARG_MAP (newmap), ARG_INT (x), ARG_INT (y)))
193 return;
312 194
313 /* If it is a player login, he has yet to be inserted anyplace. 195 if (INVOKE_MAP (ENTER, newmap, ARG_PLAYER (contr), ARG_INT (x), ARG_INT (y)))
314 * otherwise, we need to deal with removing the player here. 196 return;
315 */ 197 }
316 if (!QUERY_FLAG (op, FLAG_REMOVED))
317 remove_ob (op);
318 198
319 /* remove_ob clears these so they must be reset after the remove_ob call */
320 op->x = x; 199 this->x = x;
321 op->y = y; 200 this->y = y;
322 op->map = newmap; 201 map = newmap;
202
323 insert_ob_in_map (op, op->map, NULL, INS_NO_WALK_ON); 203 insert_ob_in_map (this, map, 0, INS_NO_WALK_ON);
324 204
325 INVOKE_MAP (ENTER, op->map, ARG_PLAYER (op->contr));
326
327 if (!op->contr->hidden)
328 newmap->players++;
329
330 newmap->timeout = 0;
331 op->enemy = NULL; 205 enemy = NULL;
332 206
333 if (op->contr) 207 if (contr)
334 { 208 {
335 strcpy (op->contr->maplevel, newmap->path); 209 contr->maplevel = newmap->path;
336 op->contr->count = 0; 210 contr->count = 0;
337 } 211 }
338 212
339 /* Update any golems */ 213 /* Update any golems */
340 if (op->type == PLAYER && op->contr->ranges[range_golem] != NULL) 214 if (type == PLAYER && contr->ranges[range_golem])
341 { 215 {
342 int i = find_free_spot (op->contr->ranges[range_golem], newmap, 216 int i = find_free_spot (contr->ranges[range_golem], newmap,
343 x, y, 1, SIZEOFFREE); 217 x, y, 1, SIZEOFFREE);
344 218
345 remove_ob (op->contr->ranges[range_golem]); 219 contr->ranges[range_golem]->remove ();
220
346 if (i == -1) 221 if (i == -1)
347 { 222 {
348 remove_friendly_object (op->contr->ranges[range_golem]); 223 remove_friendly_object (contr->ranges[range_golem]);
349 free_object (op->contr->ranges[range_golem]); 224 contr->ranges[range_golem]->destroy ();
350 op->contr->ranges[range_golem] = NULL; 225 contr->ranges[range_golem] = 0;
351 op->contr->golem_count = 0;
352 } 226 }
353 else 227 else
354 { 228 {
355 object *tmp;
356
357 for (tmp = op->contr->ranges[range_golem]; tmp != NULL; tmp = tmp->more) 229 for (object *tmp = contr->ranges[range_golem]; tmp != NULL; tmp = tmp->more)
358 { 230 {
359 tmp->x = x + freearr_x[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x); 231 tmp->x = x + freearr_x[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x);
360 tmp->y = y + freearr_y[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y); 232 tmp->y = y + freearr_y[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y);
361 tmp->map = newmap; 233 tmp->map = newmap;
362 } 234 }
235
363 insert_ob_in_map (op->contr->ranges[range_golem], newmap, NULL, 0); 236 insert_ob_in_map (contr->ranges[range_golem], newmap, NULL, 0);
364 op->contr->ranges[range_golem]->direction = 237 contr->ranges[range_golem]->direction =
365 find_dir_2 (op->x - op->contr->ranges[range_golem]->x, op->y - op->contr->ranges[range_golem]->y); 238 find_dir_2 (x - contr->ranges[range_golem]->x, y - contr->ranges[range_golem]->y);
366 } 239 }
367 } 240 }
241
368 op->direction = 0; 242 direction = 0;
369 243
370 /* since the players map is already loaded, we don't need to worry 244 /* since the players map is already loaded, we don't need to worry
371 * about pending objects. 245 * about pending objects.
372 */ 246 */
373 remove_all_pets (newmap); 247 remove_all_pets (newmap);
374
375 /* If the player is changing maps, we need to do some special things
376 * Do this after the player is on the new map - otherwise the force swap of the
377 * old map does not work.
378 */
379 if (oldmap != newmap)
380 {
381 if (oldmap) /* adjust old map */
382 {
383 oldmap->players--;
384
385 if (oldmap->players <= 0) /* can be less than zero due to errors in tracking this */
386 set_map_timeout (oldmap);
387 }
388 }
389} 248}
390
391void
392set_map_timeout (mapstruct *oldmap)
393{
394#if MAP_MAXTIMEOUT
395 oldmap->timeout = MAP_TIMEOUT (oldmap);
396 /* Do MINTIMEOUT first, so that MAXTIMEOUT is used if that is
397 * lower than the min value.
398 */
399# if MAP_MINTIMEOUT
400 if (oldmap->timeout < MAP_MINTIMEOUT)
401 {
402 oldmap->timeout = MAP_MINTIMEOUT;
403 }
404# endif
405 if (oldmap->timeout > MAP_MAXTIMEOUT)
406 {
407 oldmap->timeout = MAP_MAXTIMEOUT;
408 }
409#else
410 /* save out the map */
411 swap_map (oldmap);
412#endif /* MAP_MAXTIMEOUT */
413}
414
415
416/* clean_path takes a path and replaces all / with _
417 * We do a strcpy so that we do not change the original string.
418 */
419char *
420clean_path (const char *file)
421{
422 static char newpath[MAX_BUF], *cp;
423
424 strncpy (newpath, file, MAX_BUF - 1);
425 newpath[MAX_BUF - 1] = '\0';
426 for (cp = newpath; *cp != '\0'; cp++)
427 {
428 if (*cp == '/')
429 *cp = '_';
430 }
431 return newpath;
432}
433
434
435/* unclean_path takes a path and replaces all _ with /
436 * This basically undoes clean path.
437 * We do a strcpy so that we do not change the original string.
438 * We are smart enough to start after the last / in case we
439 * are getting passed a string that points to a unique map
440 * path.
441 */
442char *
443unclean_path (const char *src)
444{
445 static char newpath[MAX_BUF], *cp;
446
447 cp = strrchr (src, '/');
448 if (cp)
449 strncpy (newpath, cp + 1, MAX_BUF - 1);
450 else
451 strncpy (newpath, src, MAX_BUF - 1);
452 newpath[MAX_BUF - 1] = '\0';
453
454 for (cp = newpath; *cp != '\0'; cp++)
455 {
456 if (*cp == '_')
457 *cp = '/';
458 }
459 return newpath;
460}
461
462
463/* The player is trying to enter a randomly generated map. In this case, generate the
464 * random map as needed.
465 */
466
467static void
468enter_random_map (object *pl, object *exit_ob)
469{
470 mapstruct *new_map;
471 char newmap_name[HUGE_BUF], *cp;
472 static int reference_number = 0;
473 RMParms rp;
474
475 memset (&rp, 0, sizeof (RMParms));
476 rp.Xsize = -1;
477 rp.Ysize = -1;
478 rp.region = get_region_by_map (exit_ob->map);
479 if (exit_ob->msg)
480 set_random_map_variable (&rp, exit_ob->msg);
481 rp.origin_x = exit_ob->x;
482 rp.origin_y = exit_ob->y;
483 strcpy (rp.origin_map, pl->map->path);
484
485 /* If we have a final_map, use it as a base name to give some clue
486 * as where the player is. Otherwise, use the origin map.
487 * Take the last component (after the last slash) to give
488 * shorter names without bogus slashes.
489 */
490 if (rp.final_map[0])
491 {
492 cp = strrchr (rp.final_map, '/');
493 if (!cp)
494 cp = rp.final_map;
495 }
496 else
497 {
498 char buf[HUGE_BUF];
499
500 cp = strrchr (rp.origin_map, '/');
501 if (!cp)
502 cp = rp.origin_map;
503 /* Need to strip of any trailing digits, if it has them */
504 strcpy (buf, cp);
505 while (isdigit (buf[strlen (buf) - 1]))
506 buf[strlen (buf) - 1] = 0;
507 cp = buf;
508 }
509
510 sprintf (newmap_name, "/random/%s%04d", cp + 1, reference_number++);
511
512 /* now to generate the actual map. */
513 new_map = generate_random_map (newmap_name, &rp);
514
515 /* Update the exit_ob so it now points directly at the newly created
516 * random maps. Not that it is likely to happen, but it does mean that a
517 * exit in a unique map leading to a random map will not work properly.
518 * It also means that if the created random map gets reset before
519 * the exit leading to it, that the exit will no longer work.
520 */
521 if (new_map)
522 {
523 int x, y;
524
525 x = EXIT_X (exit_ob) = MAP_ENTER_X (new_map);
526 y = EXIT_Y (exit_ob) = MAP_ENTER_Y (new_map);
527 EXIT_PATH (exit_ob) = newmap_name;
528 strcpy (new_map->path, newmap_name);
529 enter_map (pl, new_map, x, y);
530 }
531}
532
533/* The player is trying to enter a non-randomly generated template map. In this
534 * case, use a map file for a template
535 */
536
537static void
538enter_fixed_template_map (object *pl, object *exit_ob)
539{
540 mapstruct *new_map;
541 char tmpnum[32], exitpath[HUGE_BUF], resultname[HUGE_BUF], tmpstring[HUGE_BUF], *sourcemap;
542 const char *new_map_name;
543
544 /* Split the exit path string into two parts, one
545 * for where to store the map, and one for were
546 * to generate the map from.
547 */
548 snprintf (exitpath, sizeof (exitpath), "%s", EXIT_PATH (exit_ob) + 2);
549 sourcemap = strchr (exitpath, '!');
550 if (!sourcemap)
551 {
552 new_draw_info_format (NDI_UNIQUE, 0, pl, "The %s is closed.", &exit_ob->name);
553 /* Should only occur when no source map is set.
554 */
555 LOG (llevError, "enter_fixed_template_map: Exit %s (%d,%d) on map %s has no source template.\n",
556 &exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path);
557 return;
558 }
559 *sourcemap++ = '\0';
560
561 /* If we are not coming from a template map, we can use relative directories
562 * for the map to generate from.
563 */
564 if (!exit_ob->map->templatemap)
565 {
566 sourcemap = path_combine_and_normalize (exit_ob->map->path, sourcemap);
567 }
568
569 /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
570 * of the exit, and the name of the map the exit is on, respectively.
571 */
572 sprintf (tmpnum, "%d", exit_ob->x);
573 replace (exitpath, "%x", tmpnum, resultname, sizeof (resultname));
574
575 sprintf (tmpnum, "%d", exit_ob->y);
576 sprintf (tmpstring, "%s", resultname);
577 replace (tmpstring, "%y", tmpnum, resultname, sizeof (resultname));
578
579 sprintf (tmpstring, "%s", resultname);
580 replace (tmpstring, "%n", exit_ob->map->name, resultname, sizeof (resultname));
581
582 /* If we are coming from another template map, use reletive paths unless
583 * indicated otherwise.
584 */
585 if (exit_ob->map->templatemap && (resultname[0] != '/'))
586 {
587 new_map_name = path_combine_and_normalize (exit_ob->map->path, resultname);
588 }
589 else
590 {
591 new_map_name = create_template_pathname (resultname);
592 }
593
594 /* Attempt to load the map, if unable to, then
595 * create the map from the template.
596 */
597 new_map = ready_map_name (new_map_name, MAP_PLAYER_UNIQUE);
598 if (!new_map)
599 {
600 new_map = load_original_map (create_pathname (sourcemap), MAP_PLAYER_UNIQUE);
601 if (new_map)
602 fix_auto_apply (new_map);
603 }
604
605 if (new_map)
606 {
607 /* set the path of the map to where it should be
608 * so we don't just save over the source map.
609 */
610 strcpy (new_map->path, new_map_name);
611 new_map->templatemap = 1;
612 enter_map (pl, new_map, EXIT_X (exit_ob), EXIT_Y (exit_ob));
613 }
614 else
615 {
616 new_draw_info_format (NDI_UNIQUE, 0, pl, "The %s is closed.", &exit_ob->name);
617 /* Should only occur when an invalid source map is set.
618 */
619 LOG (llevDebug, "enter_fixed_template_map: Exit %s (%d,%d) on map %s leads no where.\n",
620 &exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path);
621 }
622}
623
624
625/* The player is trying to enter a randomly generated template map. In this
626 * case, generate the map as needed.
627 */
628
629static void
630enter_random_template_map (object *pl, object *exit_ob)
631{
632 mapstruct *new_map;
633 char tmpnum[32], resultname[HUGE_BUF], tmpstring[HUGE_BUF];
634 const char *new_map_name;
635 RMParms rp;
636
637 /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
638 * of the exit, and the name of the map the exit is on, respectively.
639 */
640 sprintf (tmpnum, "%d", exit_ob->x);
641 replace (EXIT_PATH (exit_ob) + 3, "%x", tmpnum, resultname, sizeof (resultname));
642
643 sprintf (tmpnum, "%d", exit_ob->y);
644 sprintf (tmpstring, "%s", resultname);
645 replace (tmpstring, "%y", tmpnum, resultname, sizeof (resultname));
646
647 sprintf (tmpstring, "%s", resultname);
648 replace (tmpstring, "%n", exit_ob->map->name, resultname, sizeof (resultname));
649
650 /* If we are coming from another template map, use reletive paths unless
651 * indicated otherwise.
652 */
653 if (exit_ob->map->templatemap && (resultname[0] != '/'))
654 {
655 new_map_name = path_combine_and_normalize (exit_ob->map->path, resultname);
656 }
657 else
658 {
659 new_map_name = create_template_pathname (resultname);
660 }
661
662 new_map = ready_map_name (new_map_name, MAP_PLAYER_UNIQUE);
663 if (!new_map)
664 {
665 memset (&rp, 0, sizeof (RMParms));
666 rp.Xsize = -1;
667 rp.Ysize = -1;
668 rp.region = get_region_by_map (exit_ob->map);
669 if (exit_ob->msg)
670 set_random_map_variable (&rp, exit_ob->msg);
671 rp.origin_x = exit_ob->x;
672 rp.origin_y = exit_ob->y;
673 strcpy (rp.origin_map, pl->map->path);
674
675 /* now to generate the actual map. */
676 new_map = generate_random_map (new_map_name, &rp);
677 }
678
679
680 /* Update the exit_ob so it now points directly at the newly created
681 * random maps. Not that it is likely to happen, but it does mean that a
682 * exit in a unique map leading to a random map will not work properly.
683 * It also means that if the created random map gets reset before
684 * the exit leading to it, that the exit will no longer work.
685 */
686 if (new_map)
687 {
688 int x, y;
689
690 x = EXIT_X (exit_ob) = MAP_ENTER_X (new_map);
691 y = EXIT_Y (exit_ob) = MAP_ENTER_Y (new_map);
692 new_map->templatemap = 1;
693 enter_map (pl, new_map, x, y);
694 }
695}
696
697
698/* Code to enter/detect a character entering a unique map.
699 */
700static void
701enter_unique_map (object *op, object *exit_ob)
702{
703 char apartment[HUGE_BUF];
704 mapstruct *newmap;
705
706 if (EXIT_PATH (exit_ob)[0] == '/')
707 {
708 sprintf (apartment, "%s/%s/%s/%s", settings.localdir, settings.playerdir, &op->name, clean_path (EXIT_PATH (exit_ob)));
709 newmap = ready_map_name (apartment, MAP_PLAYER_UNIQUE);
710 if (!newmap)
711 {
712 newmap = load_original_map (create_pathname (EXIT_PATH (exit_ob)), MAP_PLAYER_UNIQUE);
713 if (newmap)
714 fix_auto_apply (newmap);
715 }
716 }
717 else
718 { /* relative directory */
719 char reldir[HUGE_BUF], tmpc[HUGE_BUF], *cp;
720
721 if (exit_ob->map->unique)
722 {
723
724 strcpy (reldir, unclean_path (exit_ob->map->path));
725
726 /* Need to copy this over, as clean_path only has one static return buffer */
727 strcpy (tmpc, clean_path (reldir));
728 /* Remove final component, if any */
729 if ((cp = strrchr (tmpc, '_')) != NULL)
730 *cp = 0;
731
732 sprintf (apartment, "%s/%s/%s/%s_%s", settings.localdir, settings.playerdir, &op->name, tmpc, clean_path (EXIT_PATH (exit_ob)));
733
734 newmap = ready_map_name (apartment, MAP_PLAYER_UNIQUE);
735 if (!newmap)
736 {
737 newmap = load_original_map (create_pathname (path_combine_and_normalize (reldir, EXIT_PATH (exit_ob))), MAP_PLAYER_UNIQUE);
738 if (newmap)
739 fix_auto_apply (newmap);
740 }
741 }
742 else
743 {
744 /* The exit is unique, but the map we are coming from is not unique. So
745 * use the basic logic - don't need to demangle the path name
746 */
747 sprintf (apartment, "%s/%s/%s/%s", settings.localdir,
748 settings.playerdir, &op->name, clean_path (path_combine_and_normalize (exit_ob->map->path, EXIT_PATH (exit_ob))));
749 newmap = ready_map_name (apartment, MAP_PLAYER_UNIQUE);
750 if (!newmap)
751 {
752 newmap = ready_map_name (path_combine_and_normalize (exit_ob->map->path, EXIT_PATH (exit_ob)), 0);
753 if (newmap)
754 fix_auto_apply (newmap);
755 }
756 }
757 }
758
759 if (newmap)
760 {
761 strcpy (newmap->path, apartment);
762 newmap->unique = 1;
763 enter_map (op, newmap, EXIT_X (exit_ob), EXIT_Y (exit_ob));
764 }
765 else
766 {
767 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s is closed.", &exit_ob->name);
768 /* Perhaps not critical, but I would think that the unique maps
769 * should be new enough this does not happen. This also creates
770 * a strange situation where some players could perhaps have visited
771 * such a map before it was removed, so they have the private
772 * map, but other players can't get it anymore.
773 */
774 LOG (llevDebug, "enter_unique_map: Exit %s (%d,%d) on map %s is leads no where.\n",
775 &exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path);
776 }
777
778}
779
780
781/* Tries to move 'op' to exit_ob. op is the character or monster that is
782 * using the exit, where exit_ob is the exit object (boat, door, teleporter,
783 * etc.) if exit_ob is null, then op->contr->maplevel contains that map to
784 * move the object to. This is used when loading the player.
785 *
786 * Largely redone by MSW 2001-01-21 - this function was overly complex
787 * and had some obscure bugs.
788 */
789
790void
791enter_exit (object *op, object *exit_ob)
792{
793#define PORTAL_DESTINATION_NAME "Town portal destination" /* this one should really be in a header file */
794 object *tmp;
795
796 /* It may be nice to support other creatures moving across
797 * exits, but right now a lot of the code looks at op->contr,
798 * so thta is an RFE.
799 */
800 if (op->type != PLAYER)
801 return;
802
803 /* First, lets figure out what map the player is going to go to */
804 if (exit_ob)
805 {
806
807 /* check to see if we make a template map */
808 if (EXIT_PATH (exit_ob) && EXIT_PATH (exit_ob)[1] == '@')
809 {
810 if (EXIT_PATH (exit_ob)[2] == '!')
811 {
812 /* generate a template map randomly */
813 enter_random_template_map (op, exit_ob);
814 }
815 else
816 {
817 /* generate a template map from a fixed template */
818 enter_fixed_template_map (op, exit_ob);
819 }
820 }
821 /* check to see if we make a randomly generated map */
822 else if (EXIT_PATH (exit_ob) && EXIT_PATH (exit_ob)[1] == '!')
823 {
824 enter_random_map (op, exit_ob);
825 }
826 else if (QUERY_FLAG (exit_ob, FLAG_UNIQUE))
827 {
828 enter_unique_map (op, exit_ob);
829 }
830 else
831 {
832 int x = EXIT_X (exit_ob), y = EXIT_Y (exit_ob);
833
834 /* 'Normal' exits that do not do anything special
835 * Simple enough we don't need another routine for it.
836 */
837 mapstruct *newmap;
838
839 if (exit_ob->map)
840 {
841 newmap = ready_map_name (path_combine_and_normalize (exit_ob->map->path, EXIT_PATH (exit_ob)), 0);
842 /* Random map was previously generated, but is no longer about. Lets generate a new
843 * map.
844 */
845 if (!newmap && !strncmp (EXIT_PATH (exit_ob), "/random/", 8))
846 {
847 /* Maps that go down have a message set. However, maps that go
848 * up, don't. If the going home has reset, there isn't much
849 * point generating a random map, because it won't match the maps.
850 */
851 if (exit_ob->msg)
852 {
853 enter_random_map (op, exit_ob);
854 }
855 else
856 {
857 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s is closed.", &exit_ob->name);
858 return;
859 }
860
861 /* For exits that cause damages (like pits). Don't know if any
862 * random maps use this or not.
863 */
864 if (exit_ob->stats.dam && op->type == PLAYER)
865 hit_player (op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
866 return;
867 }
868 }
869 else
870 {
871 /* For word of recall and other force objects
872 * They contain the full pathname of the map to go back to,
873 * so we don't need to normalize it.
874 * But we do need to see if it is unique or not
875 */
876 if (!strncmp (EXIT_PATH (exit_ob), settings.localdir, strlen (settings.localdir)))
877 newmap = ready_map_name (EXIT_PATH (exit_ob), MAP_PLAYER_UNIQUE);
878 else
879 newmap = ready_map_name (EXIT_PATH (exit_ob), 0);
880 }
881 if (!newmap)
882 {
883 if (exit_ob->name)
884 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s is closed.", &exit_ob->name);
885 /* don't cry to momma if name is not set - as in tmp objects
886 * used by the savebed code and character creation */
887 return;
888 }
889
890 /* This supports the old behaviour, but it really should not be used.
891 * I will note for example that with this method, it is impossible to
892 * set 0,0 destination coordinates. Really, if we want to support
893 * using the new maps default coordinates, the exit ob should use
894 * something like -1, -1 so it is clear to do that.
895 */
896 if (x == 0 && y == 0)
897 {
898 x = MAP_ENTER_X (newmap);
899 y = MAP_ENTER_Y (newmap);
900 LOG (llevDebug, "enter_exit: Exit %s (%d,%d) on map %s is 0 destination coordinates\n",
901 &exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map ? exit_ob->map->path : "<nil>");
902 }
903
904 /* mids 02/13/2002 if exit is damned, update players death & WoR home-position and delete town portal */
905 if (QUERY_FLAG (exit_ob, FLAG_DAMNED))
906 {
907 /* remove an old force with a slaying field == PORTAL_DESTINATION_NAME */
908 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
909 {
910 if (tmp->type == FORCE && tmp->slaying && !strcmp (tmp->slaying, PORTAL_DESTINATION_NAME))
911 break;
912 }
913 if (tmp)
914 {
915 remove_ob (tmp);
916 free_object (tmp);
917 }
918
919 strcpy (op->contr->savebed_map, path_combine_and_normalize (exit_ob->map->path, EXIT_PATH (exit_ob)));
920 op->contr->bed_x = EXIT_X (exit_ob), op->contr->bed_y = EXIT_Y (exit_ob);
921 save_player (op, 1);
922 /* LOG(llevDebug,"enter_exit: Taking damned exit %s to (%d,%d) on map %s\n",
923 * exit_ob->name?exit_ob->name:"(none)", exit_ob->x, exit_ob->y,
924 * path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob))); */
925 }
926
927 enter_map (op, newmap, x, y);
928 }
929 /* For exits that cause damages (like pits) */
930 if (exit_ob->stats.dam && op->type == PLAYER)
931 hit_player (op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
932 }
933 else
934 {
935 int flags = 0;
936 mapstruct *newmap;
937
938
939 /* Hypothetically, I guess its possible that a standard map matches
940 * the localdir, but that seems pretty unlikely - unlikely enough that
941 * I'm not going to attempt to try to deal with that possibility.
942 * We use the fact that when a player saves on a unique map, it prepends
943 * the localdir to that name. So its an easy way to see of the map is
944 * unique or not.
945 */
946 if (!strncmp (op->contr->maplevel, settings.localdir, strlen (settings.localdir)))
947 flags = MAP_PLAYER_UNIQUE;
948
949 /* newmap returns the map (if already loaded), or loads it for
950 * us.
951 */
952 newmap = ready_map_name (op->contr->maplevel, flags);
953 if (!newmap)
954 {
955 LOG (llevError, "enter_exit: Pathname to map does not exist! (%s)\n", op->contr->maplevel);
956 newmap = ready_map_name (settings.emergency_mapname, 0);
957 op->x = settings.emergency_x;
958 op->y = settings.emergency_y;
959 /* If we can't load the emergency map, something is probably really
960 * screwed up, so bail out now.
961 */
962 if (!newmap)
963 {
964 LOG (llevError, "enter_exit: could not load emergency map? Fatal error\n");
965 abort ();
966 }
967 }
968 enter_map (op, newmap, op->x, op->y);
969 }
970}
971
972/*
973 * process_active_maps(): Works like process_events(), but it only
974 * processes maps which a player is on.
975 *
976 */
977
978#if 0 // dead code, schmorp
979void
980process_active_maps ()
981{
982 for (mapstruct *map = first_map; map != NULL; map = map->next)
983 if (map->in_memory == MAP_IN_MEMORY)
984 if (players_on_map (map, TRUE))
985 process_events (map);
986}
987#endif
988 249
989/* process_players1 and process_players2 do all the player related stuff. 250/* process_players1 and process_players2 do all the player related stuff.
990 * I moved it out of process events and process_map. This was to some 251 * I moved it out of process events and process_map. This was to some
991 * extent for debugging as well as to get a better idea of the time used 252 * extent for debugging as well as to get a better idea of the time used
992 * by the various functions. process_players1() does the processing before 253 * by the various functions. process_players1() does the processing before
993 * objects have been updated, process_players2() does the processing that 254 * objects have been updated, process_players2() does the processing that
994 * is needed after the players have been updated. 255 * is needed after the players have been updated.
995 */ 256 */
996 257static void
997void 258process_players1 ()
998process_players1 (mapstruct *map)
999{ 259{
1000 int flag; 260 int flag;
1001 player *pl, *plnext;
1002 261
1003 /* Basically, we keep looping until all the players have done their actions. */ 262 /* Basically, we keep looping until all the players have done their actions. */
1004 for (flag = 1; flag != 0;) 263 for (flag = 1; flag != 0;)
1005 { 264 {
1006 flag = 0; 265 flag = 0;
1007 for (pl = first_player; pl != NULL; pl = plnext) 266 for_all_players (pl)
1008 { 267 {
1009 plnext = pl->next; /* In case a player exits the game in handle_player() */ 268 pl->refcnt_chk ();
1010 269
1011 if (pl->ob == NULL) 270 if (!pl->ob || !pl->ns || !pl->ob->active ())
1012 continue; 271 continue;
1013 272
1014 if (map != NULL && pl->ob->map != map)
1015 continue;
1016
1017 if (pl->ob->speed_left > 0) 273 if (pl->ob->speed_left > 0)
1018 {
1019 if (handle_newcs_player (pl->ob)) 274 if (handle_newcs_player (pl->ob))
1020 flag = 1; 275 flag = 1;
1021 } /* end if player has speed left */
1022 276
1023 /* If the player is not actively playing, don't make a 277 /* If the player is not actively playing, don't make a
1024 * backup save - nothing to save anyway. Plus, the 278 * backup save - nothing to save anyway. Plus, the
1025 * map may not longer be valid. This can happen when the 279 * map may not longer be valid. This can happen when the
1026 * player quits - they exist for purposes of tracking on the map, 280 * player quits - they exist for purposes of tracking on the map,
1031 285
1032#ifdef AUTOSAVE 286#ifdef AUTOSAVE
1033 /* check for ST_PLAYING state so that we don't try to save off when 287 /* check for ST_PLAYING state so that we don't try to save off when
1034 * the player is logging in. 288 * the player is logging in.
1035 */ 289 */
1036 if ((pl->last_save_tick + AUTOSAVE) < (uint32) pticks && pl->state == ST_PLAYING) 290 if ((pl->last_save_tick + AUTOSAVE) < (uint32) pticks && pl->ns->state == ST_PLAYING)
1037 { 291 {
1038 /* Don't save the player on unholy ground. Instead, increase the 292 pl->ob->contr->save ();
1039 * tick time so it will be about 10 seconds before we try and save
1040 * again.
1041 */
1042// if (get_map_flags(pl->ob->map, NULL, pl->ob->x, pl->ob->y, NULL, NULL) & P_NO_CLERIC) {
1043// pl->last_save_tick += 100;
1044// } else {
1045 save_player (pl->ob, 1);
1046 pl->last_save_tick = pticks; 293 pl->last_save_tick = pticks;
1047// }
1048 } 294 }
1049#endif 295#endif
1050 } /* end of for loop for all the players */ 296 } /* end of for loop for all the players */
1051 } /* for flag */ 297 } /* for flag */
1052 for (pl = first_player; pl != NULL; pl = pl->next) 298
299 for_all_players (pl)
1053 { 300 {
1054 if (map != NULL && (pl->ob == NULL || pl->ob->map != map)) 301 if (!pl->ob || !pl->ns || !pl->ob->active ())
1055 continue; 302 continue;
303
1056 if (settings.casting_time == TRUE) 304 if (settings.casting_time)
1057 { 305 {
1058 if (pl->ob->casting_time > 0) 306 if (pl->ob->casting_time > 0)
1059 { 307 {
1060 pl->ob->casting_time--; 308 pl->ob->casting_time--;
1061 pl->ob->start_holding = 1; 309 pl->ob->start_holding = 1;
1062 } 310 }
311
1063 /* set spell_state so we can update the range in stats field */ 312 /* set spell_state so we can update the range in stats field */
1064 if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1)) 313 if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1))
1065 {
1066 pl->ob->start_holding = 0; 314 pl->ob->start_holding = 0;
1067 } 315 }
1068 } 316
1069 do_some_living (pl->ob); 317 do_some_living (pl->ob);
1070 /* draw(pl->ob); *//* updated in socket code */
1071 } 318 }
1072} 319}
1073 320
1074void 321static void
1075process_players2 (mapstruct *map) 322process_players2 ()
1076{ 323{
1077 player *pl;
1078
1079 /* Then check if any players should use weapon-speed instead of speed */ 324 /* Then check if any players should use weapon-speed instead of speed */
1080 for (pl = first_player; pl != NULL; pl = pl->next) 325 for_all_players (pl)
1081 { 326 {
1082 if (map != NULL)
1083 {
1084 if (pl->ob == NULL || QUERY_FLAG (pl->ob, FLAG_REMOVED))
1085 continue;
1086 else if (pl->loading != NULL) /* Player is blocked */
1087 pl->ob->speed_left -= pl->ob->speed;
1088 if (pl->ob->map != map)
1089 continue;
1090 }
1091
1092 /* The code that did weapon_sp handling here was out of place - 327 /* The code that did weapon_sp handling here was out of place -
1093 * this isn't called until after the player has finished there 328 * this isn't called until after the player has finished there
1094 * actions, and is thus out of place. All we do here is bounds 329 * actions, and is thus out of place. All we do here is bounds
1095 * checking. 330 * checking.
1096 */ 331 */
1102 /* This needs to be here - if the player is running, we need to 337 /* This needs to be here - if the player is running, we need to
1103 * clear this each tick, but new commands are not being received 338 * clear this each tick, but new commands are not being received
1104 * so execute_newserver_command() is never called 339 * so execute_newserver_command() is never called
1105 */ 340 */
1106 pl->has_hit = 0; 341 pl->has_hit = 0;
1107
1108 } 342 }
1109 else if (pl->ob->speed_left > pl->ob->speed) 343 else if (pl->ob->speed_left > pl->ob->speed)
1110 pl->ob->speed_left = pl->ob->speed; 344 pl->ob->speed_left = pl->ob->speed;
1111 } 345 }
1112} 346}
1113 347
1114void 348void
1115process_events (mapstruct *map) 349process_events ()
1116{ 350{
1117 object *op; 351 object *op;
1118 object *marker = get_object ();
1119 tag_t tag;
1120 352
353 static object_ptr marker_;
354
355 if (!marker_)
356 marker_ = object::create ();
357
358 object *marker = marker_;
359
1121 process_players1 (map); 360 process_players1 ();
1122 361
1123 marker->active_next = active_objects; 362 marker->active_next = active_objects;
1124 363
1125 if (marker->active_next) 364 if (marker->active_next)
1126 marker->active_next->active_prev = marker; 365 marker->active_next->active_prev = marker;
1127 366
1128 marker->active_prev = NULL; 367 marker->active_prev = 0;
1129 active_objects = marker; 368 active_objects = marker;
1130 369
1131 while (marker->active_next) 370 while (marker->active_next)
1132 { 371 {
1133 op = marker->active_next; 372 op = marker->active_next;
1134 tag = op->count;
1135 373
1136 /* Move marker forward - swap op and marker */ 374 /* Move marker forward - swap op and marker */
1137 op->active_prev = marker->active_prev; 375 op->active_prev = marker->active_prev;
1138 376
1139 if (op->active_prev) 377 if (op->active_prev)
1151 389
1152 /* Now process op */ 390 /* Now process op */
1153 if (QUERY_FLAG (op, FLAG_FREED)) 391 if (QUERY_FLAG (op, FLAG_FREED))
1154 { 392 {
1155 LOG (llevError, "BUG: process_events(): Free object on list\n"); 393 LOG (llevError, "BUG: process_events(): Free object on list\n");
1156 op->speed = 0; 394 op->set_speed (0);
1157 update_ob_speed (op);
1158 continue; 395 continue;
1159 } 396 }
1160 397
1161 /* I've seen occasional crashes due to this - the object is removed, 398 /* I've seen occasional crashes due to this - the object is removed,
1162 * and thus the map it points to (last map it was on) may be bogus 399 * and thus the map it points to (last map it was on) may be bogus
1169 * around. 406 * around.
1170 */ 407 */
1171 if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY) 408 if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY)
1172 { 409 {
1173 LOG (llevError, "BUG: process_events(): Removed object on list\n"); 410 LOG (llevError, "BUG: process_events(): Removed object on list\n");
1174 dump_object (op); 411 char *dump = dump_object (op);
1175 LOG (llevError, errmsg); 412 LOG (llevError, dump);
1176 free_object (op); 413 free (dump);
414 op->destroy ();
1177 continue; 415 continue;
1178 } 416 }
1179 417
1180 if (!op->speed) 418 if (!op->has_active_speed ())
1181 { 419 {
1182 LOG (llevError, "BUG: process_events(): Object %s has no speed, " "but is on active list\n", &op->arch->name); 420 LOG (llevError, "BUG: process_events(): Object %s has no speed (%f), "
1183 update_ob_speed (op); 421 "but is on active list\n", op->debug_desc (), op->speed);
422 op->set_speed (0);
1184 continue; 423 continue;
1185 } 424 }
1186 425
1187 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP && map == NULL) 426 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP)
1188 { 427 {
1189 LOG (llevError, "BUG: process_events(): Object without map or " "inventory is on active list: %s (%d)\n", &op->name, op->count); 428 LOG (llevError, "BUG: process_events(): Object without map or "
429 "inventory is on active list: %s (%d)\n", &op->name, op->count);
1190 op->speed = 0; 430 op->set_speed (0);
1191 update_ob_speed (op);
1192 continue; 431 continue;
1193 } 432 }
1194 433
1195 if (map != NULL && op->map != map)
1196 continue;
1197
1198 /* Animate the object. Bug of feature that andim_speed 434 /* Animate the object. Bug or feature that anim_speed
1199 * is based on ticks, and not the creatures speed? 435 * is based on ticks, and not the creatures speed?
1200 */ 436 */
1201 if (op->anim_speed && op->last_anim >= op->anim_speed) 437 if (op->anim_speed && op->last_anim >= op->anim_speed)
1202 { 438 {
1203 if ((op->type == PLAYER) || (op->type == MONSTER)) 439 if ((op->type == PLAYER))
1204 animate_object (op, op->facing); 440 animate_object (op, op->facing);
1205 else 441 else
1206 animate_object (op, op->direction); 442 animate_object (op, op->direction);
1207 443
1208 op->last_anim = 1; 444 op->last_anim = 1;
1226 LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null"); 462 LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null");
1227 } 463 }
1228#endif 464#endif
1229 --op->speed_left; 465 --op->speed_left;
1230 process_object (op); 466 process_object (op);
467
1231 if (was_destroyed (op, tag)) 468 if (op->destroyed ())
1232 continue; 469 continue;
1233 } 470 }
471
1234 if (settings.casting_time == TRUE && op->casting_time > 0) 472 if (settings.casting_time == TRUE && op->casting_time > 0)
1235 op->casting_time--; 473 op->casting_time--;
474
1236 if (op->speed_left <= 0) 475 if (op->speed_left <= 0)
1237 op->speed_left += FABS (op->speed); 476 op->speed_left += FABS (op->speed);
1238 } 477 }
1239 478
1240 /* Remove marker object from active list */ 479 /* Remove marker object from active list */
1241 if (marker->active_prev != NULL) 480 if (marker->active_prev != NULL)
1242 marker->active_prev->active_next = NULL; 481 marker->active_prev->active_next = NULL;
1243 else 482 else
1244 active_objects = NULL; 483 active_objects = NULL;
1245 484
1246 process_players2 (map); 485 process_players2 ();
1247
1248 free_object (marker);
1249} 486}
1250 487
488/* clean up everything before exiting */
1251void 489void
1252clean_tmp_files (void) 490emergency_save ()
1253{ 491{
1254 mapstruct *m, *next; 492 LOG (llevDebug, "emergency save begin.\n");
1255 493
1256 LOG (llevInfo, "Cleaning up...\n"); 494 LOG (llevDebug, "saving players.\n");
495 for_all_players (pl)
496 pl->save (1);
1257 497
1258 /* We save the maps - it may not be intuitive why, but if there are unique 498// for_all_players (pl)
1259 * items, we need to save the map so they get saved off. Perhaps we should 499// if (pl->ob)
1260 * just make a special function that only saves the unique items. 500// pl->ob->remove ();
1261 */ 501
1262 for (m = first_map; m != NULL; m = next) 502 LOG (llevDebug, "saving maps.\n");
503 maptile::emergency_save ();
504
505 LOG (llevDebug, "saving book archive.\n");
506 write_book_archive ();
507
508 LOG (llevDebug, "emergency save done.\n");
509}
510
511/* clean up everything before exiting */
512void
513cleanup (bool make_core)
514{
515 LOG (llevDebug, "cleanup begin.\n");
516
517 if (init_done && !in_cleanup)
518 {
519 in_cleanup = true;
520 emergency_save ();
1263 { 521 }
1264 next = m->next; 522 else
1265 if (m->in_memory == MAP_IN_MEMORY) 523 in_cleanup = true;
524
525 LOG (llevDebug, "running cleanup handlers.\n");
526 INVOKE_GLOBAL (CLEANUP);
527
528 LOG (llevDebug, "cleanup done.\n");
529
530 if (make_core)
531 abort ();
532 else
533 _exit (0);
534}
535
536void
537leave (player *pl, int draw_exit)
538{
539 if (pl)
540 {
541 if (pl->ob->type != DEAD_OBJECT)
1266 { 542 {
1267 /* If we want to reuse the temp maps, swap it out (note that will also 543 /* If a hidden dm dropped connection do not create
1268 * update the log file. Otherwise, save the map (mostly for unique item 544 * inconsistencies by showing that they have left the game
1269 * stuff). Note that the clean_tmp_map is called after the end of
1270 * the for loop but is in the #else bracket. IF we are recycling the maps,
1271 * we certainly don't want the temp maps removed.
1272 */ 545 */
1273 546 if (!(QUERY_FLAG (pl->ob, FLAG_WIZ) && pl->ob->contr->hidden)
1274 /* XXX The above comment is dead wrong */ 547 && draw_exit)
1275 if (settings.recycle_tmp_maps == TRUE)
1276 swap_map (m);
1277 else
1278 { 548 {
1279 new_save_map (m, 0); /* note we save here into a overlay map */ 549 if (pl->ob->map)
1280 clean_tmp_map (m); 550 {
551 INVOKE_PLAYER (LOGOUT, pl);
552 LOG (llevInfo, "LOGOUT: Player named %s from ip %s\n", &pl->ob->name, pl->ns->host);
553 }
554
555 char buf[MAX_BUF];
556
557 sprintf (buf, "%s left the game.", &pl->ob->name);
558 new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, 0, buf);
1281 } 559 }
1282 }
1283 }
1284 write_todclock (); /* lets just write the clock here */
1285}
1286 560
1287/* clean up everything before exiting */ 561 pl->ob->remove ();
1288void 562 pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */
1289cleanup (void) 563 }
1290{
1291 LOG (llevDebug, "Cleanup called. freeing data.\n");
1292 clean_tmp_files ();
1293 write_book_archive ();
1294#ifdef MEMORY_DEBUG
1295 free_all_maps ();
1296 free_style_maps ();
1297 free_all_object_data ();
1298 free_all_archs ();
1299 free_all_treasures ();
1300 free_all_images ();
1301 free_all_newserver ();
1302 free_all_recipes ();
1303 free_all_readable ();
1304 free_all_god ();
1305 free_all_anim ();
1306 /* See what the string data that is out there that hasn't been freed. */
1307 564
1308/* LOG(llevDebug, ss_dump_table(0xff));*/
1309#endif
1310 exit (0);
1311}
1312
1313void
1314leave (player *pl, int draw_exit)
1315{
1316 if (pl != NULL)
1317 {
1318 /* We do this so that the socket handling routine can do the final 565 /* We do this so that the socket handling routine can do the final
1319 * cleanup. We also leave that loop to actually handle the freeing 566 * cleanup. We also leave that loop to actually handle the freeing
1320 * of the data. 567 * of the data.
1321 */ 568 */
1322 if (pl->ob->type != DEAD_OBJECT) 569 if (pl->ns)
1323 { 570 pl->ns->destroy ();
1324 pl->socket.status = Ns_Dead;
1325 571
1326 /* If a hidden dm dropped connection do not create
1327 * inconsistencies by showing that they have left the game
1328 */
1329 if (!(QUERY_FLAG (pl->ob, FLAG_WIZ) && pl->ob->contr->hidden)
1330 && draw_exit && (pl->state != ST_GET_NAME && pl->state != ST_GET_PASSWORD && pl->state != ST_CONFIRM_PASSWORD))
1331 {
1332 if (pl->ob->map)
1333 {
1334 INVOKE_PLAYER (LOGOUT, pl);
1335 LOG (llevInfo, "LOGOUT: Player named %s from ip %s\n", &pl->ob->name, pl->socket.host);
1336 }
1337
1338 char buf[MAX_BUF];
1339
1340 sprintf (buf, "%s left the game.", &pl->ob->name);
1341 new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, buf);
1342 }
1343
1344 if (!QUERY_FLAG (pl->ob, FLAG_REMOVED))
1345 leave_map (pl->ob);
1346
1347 pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */
1348 }
1349 } 572 }
1350} 573}
1351 574
1352int 575int
1353forbid_play (void) 576forbid_play (void)
1416extern unsigned long todtick; 639extern unsigned long todtick;
1417 640
1418void 641void
1419do_specials (void) 642do_specials (void)
1420{ 643{
1421
1422#ifdef WATCHDOG
1423 if (!(pticks % 503))
1424 watchdog ();
1425#endif
1426
1427 if (!(pticks % PTICKS_PER_CLOCK)) 644 if (!(pticks % PTICKS_PER_CLOCK))
1428 tick_the_clock (); 645 tick_the_clock ();
1429 646
1430 if (!(pticks % 7)) 647 if (!(pticks % 7))
1431 shstr::gc (); 648 shstr::gc ();
1432 649
1433 if (!(pticks % 79))
1434 flush_old_maps (); /* Clears the tmp-files of maps which have reset */
1435
1436 if (!(pticks % 2503)) 650 if (!(pticks % 2503))
1437 fix_weight (); /* Hack to fix weightproblems caused by bugs */ 651 fix_weight (); /* Hack to fix weightproblems caused by bugs */
1438 652
1439 if (!(pticks % 2521))
1440 metaserver_update (); /* 2500 ticks is about 5 minutes */
1441
1442 if (!(pticks % 5003)) 653 if (!(pticks % 5003))
1443 write_book_archive (); 654 write_book_archive ();
1444 655
1445 if (!(pticks % 5009)) 656 if (!(pticks % 5009))
1446 clean_friendly_list (); 657 clean_friendly_list ();
1453} 664}
1454 665
1455void 666void
1456server_tick () 667server_tick ()
1457{ 668{
1458 nroferrors = 0; 669 // first do the user visible stuff
1459
1460 doeric_server (); 670 doeric_server ();
1461 INVOKE_GLOBAL (CLOCK); 671 INVOKE_GLOBAL (CLOCK);
1462 process_events (NULL); /* "do" something with objects with speed */ 672 process_events (); /* "do" something with objects with speed */
1463 flush_sockets (); 673 flush_sockets ();
1464 check_active_maps (); /* Removes unused maps after a certain timeout */ 674
675 // then do some bookkeeping, should not really be here
1465 do_specials (); /* Routines called from time to time. */ 676 do_specials (); /* Routines called from time to time. */
1466 object::free_mortals (); 677 attachable::check_mortals ();
1467 678
1468 ++pticks; 679 ++pticks;
1469} 680}
1470 681
1471int 682int
1472main (int argc, char **argv) 683main (int argc, char **argv)
1473{ 684{
1474 settings.argc = argc; 685 settings.argc = argc;
1475 settings.argv = argv; 686 settings.argv = argv;
1476 687
1477 cfperl_init ();
1478
1479 init (argc, argv); 688 init (argc, argv);
1480 689
1481 initPlugins (); 690 initPlugins ();
1482 691
1483 for (;;) 692 for (;;)
1484 cfperl_main (); 693 cfperl_main ();
1485 694
1486 // unreached
1487 emergency_save (0);
1488 cleanup (); 695 cleanup (true);
1489
1490 return 0;
1491} 696}
697

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines