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.22 by root, Sat Sep 9 21:48:29 2006 UTC vs.
Revision 1.63 by root, Sat Dec 30 16:56:16 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines