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.82 by root, Tue Jan 9 01:28:32 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
4 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
10 Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team 5 Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 6 Copyright (C) 1992 Frank Tore Johansen
12 7
13 This program is free software; you can redistribute it and/or modify 8 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
22 17
23 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 21
27 The authors can be reached via e-mail at crossfire-devel@real-time.com 22 The authors can be reached via e-mail at <crossfire@schmorp.de>
28*/ 23*/
29 24
30#include <global.h> 25#include <global.h>
31#include <object.h> 26#include <object.h>
32#include <tod.h> 27#include <tod.h>
37# ifdef HAVE_CRYPT_H 32# ifdef HAVE_CRYPT_H
38# include <crypt.h> 33# include <crypt.h>
39# endif 34# endif
40#endif 35#endif
41 36
42#ifndef __CEXTRACT__
43# include <sproto.h> 37#include <sproto.h>
44#endif
45
46#ifdef HAVE_TIME_H
47# include <time.h> 38#include <time.h>
48#endif
49 39
50#include <../random_maps/random_map.h> 40#include <../random_maps/random_map.h>
51#include <../random_maps/rproto.h> 41#include <../random_maps/rproto.h>
52#include "path.h" 42#include "path.h"
53 43
56}; 46};
57 47
58void 48void
59version (object *op) 49version (object *op)
60{ 50{
61 if (op != NULL) 51 if (op)
62 clear_win_info (op); 52 clear_win_info (op);
63 53
64 new_draw_info_format (NDI_UNIQUE, 0, op, "This is Crossfire v%s", VERSION); 54 new_draw_info_format (NDI_UNIQUE, 0, op, "This is Crossfire+ v%s", VERSION);
65 55
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:"); 56 new_draw_info (NDI_UNIQUE, 0, op, "Authors and contributors to this program:");
57 new_draw_info (NDI_UNIQUE, 0, op, "Marc A. Lehmann <pcg@goof.com>");
58 new_draw_info (NDI_UNIQUE, 0, op, "Robin Redeker <elmex@x-paste.de>");
59 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)"); 60 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)"); 61 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)"); 62 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)"); 63 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)"); 64 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)"); 65 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)"); 66 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)"); 67 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)"); 68 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)"); 69 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)"); 70 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)"); 71 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)"); 72 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)"); 73 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)"); 74 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)"); 75 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)"); 76 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)"); 77 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)"); 78 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)"); 79 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)"); 80 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)"); 81 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)"); 82 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)"); 83 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)"); 84 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)"); 85 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)"); 86 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)"); 87 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)"); 88 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)"); 89 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)"); 90 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)"); 91 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)"); 92 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)"); 93 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)"); 94 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)"); 95 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)"); 96 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)"); 97 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]"); 98 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"); 99 new_draw_info (NDI_UNIQUE, 0, op, "Chachkoff Yann <yann.chachkoff@mailandnews.com>\n");
100
112 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:"); 101 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:");
113 new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner"); 102 new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner");
114 new_draw_info (NDI_UNIQUE, 0, op, "David Gervais [david_eg@mail.com]"); 103 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]"); 104 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]"); 105 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]"); 106 new_draw_info (NDI_UNIQUE, 0, op, "MÃ¥rten Woxberg <maxmc@telia.com>");
118 new_draw_info (NDI_UNIQUE, 0, op, "And many more!"); 107 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} 108}
193 109
194/* This is a basic little function to put the player back to his 110/* This is a basic little function to put the player back to his
195 * savebed. We do some error checking - its possible that the 111 * savebed. We do some error checking - its possible that the
196 * savebed map may no longer exist, so we make sure the player 112 * savebed map may no longer exist, so we make sure the player
197 * goes someplace. 113 * goes someplace.
198 */ 114 */
199void 115void
200enter_player_savebed (object *op) 116enter_player_savebed (object *op)
201{ 117{
202 mapstruct *oldmap = op->map; 118 object *tmp = object::create ();
203 object *tmp;
204
205 tmp = get_object ();
206
207 EXIT_PATH (tmp) = op->contr->savebed_map; 119 EXIT_PATH (tmp) = op->contr->savebed_map;
208 EXIT_X (tmp) = op->contr->bed_x; 120 EXIT_X (tmp) = op->contr->bed_x;
209 EXIT_Y (tmp) = op->contr->bed_y; 121 EXIT_Y (tmp) = op->contr->bed_y;
210 enter_exit (op, tmp); 122 op->enter_exit (tmp);
211 /* If the player has not changed maps and the name does not match 123 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} 124}
251 125
252/* 126/*
253 * enter_map(): Moves the player and pets from current map (if any) to 127 * 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 128 * 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 129 * 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 130 * whatever reason. If default map coordinates are to be used, then
257 * the function that calls this should figure them out. 131 * the function that calls this should figure them out.
258 */ 132 */
259static void 133void
260enter_map (object *op, mapstruct *newmap, int x, int y) 134object::enter_map (maptile *newmap, int x, int y)
261{ 135{
262 mapstruct *oldmap = op->map; 136 if (destroyed () || !newmap || newmap->in_memory != MAP_IN_MEMORY)
137 return;
263 138
264 if (out_of_map (newmap, x, y)) 139 if (out_of_map (newmap, x, y))
265 { 140 {
266 LOG (llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", newmap->path, x, y); 141 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); 142 x = newmap->enter_x;
268 y = MAP_ENTER_Y (newmap); 143 y = newmap->enter_y;
269 if (out_of_map (newmap, x, y)) 144 if (out_of_map (newmap, x, y))
270 { 145 {
271 LOG (llevError, "enter_map: map %s provides invalid default enter location (%d, %d) > (%d, %d)\n", 146 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)); 147 &newmap->path, x, y, newmap->width, newmap->height);
273 new_draw_info (NDI_UNIQUE, 0, op, "The exit is closed"); 148 new_draw_info (NDI_UNIQUE, 0, this, "The exit is closed");
274 return; 149 return;
275 } 150 }
276 } 151 }
152
153 if (contr && map != newmap && map)
154 if (INVOKE_MAP (LEAVE, map, ARG_PLAYER (contr)))
155 return;
156
157 // remove, so stupid ob_locked does not trigger a failure
158 remove ();
159
277 /* try to find a spot for the player */ 160 /* try to find a spot for the player */
278 if (ob_blocked (op, newmap, x, y)) 161 if (ob_blocked (this, newmap, x, y))
279 { /* First choice blocked */ 162 { /* First choice blocked */
280 /* We try to find a spot for the player, starting closest in. 163 /* 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, 164 * 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 165 * So for example, if the north space is free, you would always end up there even
283 * if other spaces around are available. 166 * if other spaces around are available.
284 * Note that for the second and third calls, we could start at a position other 167 * 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. 168 * than one, but then we could end up on the other side of walls and so forth.
286 */ 169 */
287 int i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE1 + 1); 170 int i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE1 + 1);
288 171
289 if (i == -1) 172 if (i == -1)
290 { 173 {
291 i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE2 + 1); 174 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE2 + 1);
292 if (i == -1) 175 if (i == -1)
293 i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE); 176 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE);
294 } 177 }
178
295 if (i != -1) 179 if (i != -1)
296 { 180 {
297 x += freearr_x[i]; 181 x += freearr_x[i];
298 y += freearr_y[i]; 182 y += freearr_y[i];
299 } 183 }
300 else 184 else
301 {
302 /* not much we can do in this case. */ 185 /* 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); 186 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 { 187 }
309 INVOKE_PLAYER (MAP_CHANGE, op->contr, ARG_MAP (op->map), ARG_MAP (newmap)); 188
310 INVOKE_MAP (LEAVE, op->map, ARG_PLAYER (op->contr)); 189 if (contr && map != newmap)
311 } 190 {
191 if (INVOKE_PLAYER (MAP_CHANGE, contr, ARG_MAP (newmap), ARG_INT (x), ARG_INT (y)))
192 return;
312 193
313 /* If it is a player login, he has yet to be inserted anyplace. 194 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. 195 return;
315 */ 196 }
316 if (!QUERY_FLAG (op, FLAG_REMOVED))
317 remove_ob (op);
318 197
319 /* remove_ob clears these so they must be reset after the remove_ob call */
320 op->x = x; 198 this->x = x;
321 op->y = y; 199 this->y = y;
322 op->map = newmap; 200 map = newmap;
201
323 insert_ob_in_map (op, op->map, NULL, INS_NO_WALK_ON); 202 insert_ob_in_map (this, map, 0, INS_NO_WALK_ON);
324 203
325 INVOKE_MAP (ENTER, op->map, ARG_PLAYER (op->contr)); 204 enemy = 0;
326 205
327 if (!op->contr->hidden)
328 newmap->players++;
329
330 newmap->timeout = 0;
331 op->enemy = NULL;
332
333 if (op->contr) 206 if (contr)
334 { 207 {
335 strcpy (op->contr->maplevel, newmap->path); 208 contr->maplevel = newmap->path;
336 op->contr->count = 0; 209 contr->count = 0;
337 } 210 }
338 211
339 /* Update any golems */ 212 /* Update any golems */
340 if (op->type == PLAYER && op->contr->ranges[range_golem] != NULL) 213 if (type == PLAYER && contr->ranges[range_golem])
341 { 214 {
342 int i = find_free_spot (op->contr->ranges[range_golem], newmap, 215 int i = find_free_spot (contr->ranges[range_golem], newmap,
343 x, y, 1, SIZEOFFREE); 216 x, y, 1, SIZEOFFREE);
344 217
345 remove_ob (op->contr->ranges[range_golem]);
346 if (i == -1) 218 if (i == -1)
347 { 219 {
348 remove_friendly_object (op->contr->ranges[range_golem]); 220 contr->ranges[range_golem]->destroy ();
349 free_object (op->contr->ranges[range_golem]);
350 op->contr->ranges[range_golem] = NULL; 221 contr->ranges[range_golem] = 0;
351 op->contr->golem_count = 0;
352 } 222 }
353 else 223 else
354 { 224 {
355 object *tmp;
356
357 for (tmp = op->contr->ranges[range_golem]; tmp != NULL; tmp = tmp->more) 225 for (object *tmp = contr->ranges[range_golem]; tmp; tmp = tmp->more)
358 { 226 {
359 tmp->x = x + freearr_x[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x); 227 tmp->x = x + freearr_x[i] + (tmp->arch ? 0 : tmp->arch->clone.x);
360 tmp->y = y + freearr_y[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y); 228 tmp->y = y + freearr_y[i] + (tmp->arch ? 0 : tmp->arch->clone.y);
361 tmp->map = newmap; 229 tmp->map = newmap;
362 } 230 }
231
363 insert_ob_in_map (op->contr->ranges[range_golem], newmap, NULL, 0); 232 insert_ob_in_map (contr->ranges[range_golem], newmap, NULL, 0);
364 op->contr->ranges[range_golem]->direction = 233 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); 234 find_dir_2 (x - contr->ranges[range_golem]->x, y - contr->ranges[range_golem]->y);
366 } 235 }
367 } 236 }
368 op->direction = 0;
369 237
370 /* since the players map is already loaded, we don't need to worry 238 /* since the players map is already loaded, we don't need to worry
371 * about pending objects. 239 * about pending objects.
372 */ 240 */
373 remove_all_pets (newmap); 241 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} 242}
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 243
989/* process_players1 and process_players2 do all the player related stuff. 244/* 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 245 * 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 246 * 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 247 * by the various functions. process_players1() does the processing before
993 * objects have been updated, process_players2() does the processing that 248 * objects have been updated, process_players2() does the processing that
994 * is needed after the players have been updated. 249 * is needed after the players have been updated.
995 */ 250 */
996 251static void
997void 252process_players1 ()
998process_players1 (mapstruct *map)
999{ 253{
1000 int flag; 254 int flag;
1001 player *pl, *plnext;
1002 255
1003 /* Basically, we keep looping until all the players have done their actions. */ 256 /* Basically, we keep looping until all the players have done their actions. */
1004 for (flag = 1; flag != 0;) 257 for (flag = 1; flag != 0;)
1005 { 258 {
1006 flag = 0; 259 flag = 0;
1007 for (pl = first_player; pl != NULL; pl = plnext) 260 for_all_players (pl)
1008 { 261 {
1009 plnext = pl->next; /* In case a player exits the game in handle_player() */ 262 pl->refcnt_chk ();
1010 263
1011 if (pl->ob == NULL) 264 if (!pl->ob || !pl->ns || !pl->ob->active)
1012 continue; 265 continue;
1013 266
1014 if (map != NULL && pl->ob->map != map)
1015 continue;
1016
1017 if (pl->ob->speed_left > 0) 267 if (pl->ob->speed_left > 0)
1018 {
1019 if (handle_newcs_player (pl->ob)) 268 if (handle_newcs_player (pl->ob))
1020 flag = 1; 269 flag = 1;
1021 } /* end if player has speed left */
1022 270
1023 /* If the player is not actively playing, don't make a 271 /* If the player is not actively playing, don't make a
1024 * backup save - nothing to save anyway. Plus, the 272 * backup save - nothing to save anyway. Plus, the
1025 * map may not longer be valid. This can happen when the 273 * map may not longer be valid. This can happen when the
1026 * player quits - they exist for purposes of tracking on the map, 274 * player quits - they exist for purposes of tracking on the map,
1027 * but don't actually reside on any actual map. 275 * but don't actually reside on any actual map.
1028 */ 276 */
1029 if (QUERY_FLAG (pl->ob, FLAG_REMOVED)) 277 if (QUERY_FLAG (pl->ob, FLAG_REMOVED))
1030 continue; 278 continue;
1031
1032#ifdef AUTOSAVE
1033 /* check for ST_PLAYING state so that we don't try to save off when
1034 * the player is logging in.
1035 */
1036 if ((pl->last_save_tick + AUTOSAVE) < (uint32) pticks && pl->state == ST_PLAYING)
1037 {
1038 /* Don't save the player on unholy ground. Instead, increase the
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;
1047// }
1048 }
1049#endif
1050 } /* end of for loop for all the players */ 279 } /* end of for loop for all the players */
1051 } /* for flag */ 280 } /* for flag */
1052 for (pl = first_player; pl != NULL; pl = pl->next) 281
282 for_all_players (pl)
1053 { 283 {
1054 if (map != NULL && (pl->ob == NULL || pl->ob->map != map)) 284 if (!pl->ob || !pl->ns || !pl->ob->active)
1055 continue; 285 continue;
286
1056 if (settings.casting_time == TRUE) 287 if (settings.casting_time)
1057 { 288 {
1058 if (pl->ob->casting_time > 0) 289 if (pl->ob->casting_time > 0)
1059 { 290 {
1060 pl->ob->casting_time--; 291 pl->ob->casting_time--;
1061 pl->ob->start_holding = 1; 292 pl->ob->start_holding = 1;
1062 } 293 }
294
1063 /* set spell_state so we can update the range in stats field */ 295 /* set spell_state so we can update the range in stats field */
1064 if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1)) 296 if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1))
1065 {
1066 pl->ob->start_holding = 0; 297 pl->ob->start_holding = 0;
1067 } 298 }
1068 } 299
1069 do_some_living (pl->ob); 300 do_some_living (pl->ob);
1070 /* draw(pl->ob); *//* updated in socket code */
1071 } 301 }
1072} 302}
1073 303
1074void 304static void
1075process_players2 (mapstruct *map) 305process_players2 ()
1076{ 306{
1077 player *pl;
1078
1079 /* Then check if any players should use weapon-speed instead of speed */ 307 /* Then check if any players should use weapon-speed instead of speed */
1080 for (pl = first_player; pl != NULL; pl = pl->next) 308 for_all_players (pl)
1081 { 309 {
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 - 310 /* The code that did weapon_sp handling here was out of place -
1093 * this isn't called until after the player has finished there 311 * 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 312 * actions, and is thus out of place. All we do here is bounds
1095 * checking. 313 * checking.
1096 */ 314 */
1102 /* This needs to be here - if the player is running, we need to 320 /* 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 321 * clear this each tick, but new commands are not being received
1104 * so execute_newserver_command() is never called 322 * so execute_newserver_command() is never called
1105 */ 323 */
1106 pl->has_hit = 0; 324 pl->has_hit = 0;
1107
1108 } 325 }
1109 else if (pl->ob->speed_left > pl->ob->speed) 326 else if (pl->ob->speed_left > pl->ob->speed)
1110 pl->ob->speed_left = pl->ob->speed; 327 pl->ob->speed_left = pl->ob->speed;
1111 } 328 }
1112} 329}
1113 330
1114void 331void
1115process_events (mapstruct *map) 332process_events ()
1116{ 333{
1117 object *op;
1118 object *marker = get_object ();
1119 tag_t tag;
1120
1121 process_players1 (map); 334 process_players1 ();
1122 335
1123 marker->active_next = active_objects; 336 for_all_actives (op)
1124
1125 if (marker->active_next)
1126 marker->active_next->active_prev = marker;
1127
1128 marker->active_prev = NULL;
1129 active_objects = marker;
1130
1131 while (marker->active_next)
1132 { 337 {
1133 op = marker->active_next;
1134 tag = op->count;
1135
1136 /* Move marker forward - swap op and marker */
1137 op->active_prev = marker->active_prev;
1138
1139 if (op->active_prev)
1140 op->active_prev->active_next = op;
1141 else
1142 active_objects = op;
1143
1144 marker->active_next = op->active_next;
1145
1146 if (marker->active_next)
1147 marker->active_next->active_prev = marker;
1148
1149 marker->active_prev = op;
1150 op->active_next = marker;
1151
1152 /* Now process op */ 338 /* Now process op */
1153 if (QUERY_FLAG (op, FLAG_FREED)) 339 if (QUERY_FLAG (op, FLAG_FREED))
1154 { 340 {
1155 LOG (llevError, "BUG: process_events(): Free object on list\n"); 341 LOG (llevError, "BUG: process_events(): Free object on list\n");
1156 op->speed = 0; 342 op->set_speed (0);
1157 update_ob_speed (op);
1158 continue; 343 continue;
1159 } 344 }
1160 345
1161 /* I've seen occasional crashes due to this - the object is removed, 346 /* 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 347 * and thus the map it points to (last map it was on) may be bogus
1169 * around. 354 * around.
1170 */ 355 */
1171 if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY) 356 if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY)
1172 { 357 {
1173 LOG (llevError, "BUG: process_events(): Removed object on list\n"); 358 LOG (llevError, "BUG: process_events(): Removed object on list\n");
1174 dump_object (op); 359 char *dump = dump_object (op);
1175 LOG (llevError, errmsg); 360 LOG (llevError, dump);
1176 free_object (op); 361 free (dump);
362 op->destroy ();
1177 continue; 363 continue;
1178 } 364 }
1179 365
1180 if (!op->speed) 366 if (!op->has_active_speed ())
1181 { 367 {
1182 LOG (llevError, "BUG: process_events(): Object %s has no speed, " "but is on active list\n", &op->arch->name); 368 LOG (llevError, "BUG: process_events(): Object %s has no speed (%f), "
1183 update_ob_speed (op); 369 "but is on active list\n", op->debug_desc (), op->speed);
370 op->set_speed (0);
1184 continue; 371 continue;
1185 } 372 }
1186 373
1187 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP && map == NULL) 374 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP)
1188 { 375 {
1189 LOG (llevError, "BUG: process_events(): Object without map or " "inventory is on active list: %s (%d)\n", &op->name, op->count); 376 LOG (llevError, "BUG: process_events(): Object without map or "
377 "inventory is on active list: %s (%d)\n", &op->name, op->count);
1190 op->speed = 0; 378 op->set_speed (0);
1191 update_ob_speed (op);
1192 continue; 379 continue;
1193 } 380 }
1194 381
1195 if (map != NULL && op->map != map)
1196 continue;
1197
1198 /* Animate the object. Bug of feature that andim_speed 382 /* Animate the object. Bug or feature that anim_speed
1199 * is based on ticks, and not the creatures speed? 383 * is based on ticks, and not the creatures speed?
1200 */ 384 */
1201 if (op->anim_speed && op->last_anim >= op->anim_speed) 385 if (op->anim_speed && op->last_anim >= op->anim_speed)
1202 { 386 {
1203 if ((op->type == PLAYER) || (op->type == MONSTER)) 387 if ((op->type == PLAYER))
1204 animate_object (op, op->facing); 388 animate_object (op, op->facing);
1205 else 389 else
1206 animate_object (op, op->direction); 390 animate_object (op, op->direction);
1207 391
1208 op->last_anim = 1; 392 op->last_anim = 1;
1226 LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null"); 410 LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null");
1227 } 411 }
1228#endif 412#endif
1229 --op->speed_left; 413 --op->speed_left;
1230 process_object (op); 414 process_object (op);
415
1231 if (was_destroyed (op, tag)) 416 if (op->destroyed ())
1232 continue; 417 continue;
1233 } 418 }
419
1234 if (settings.casting_time == TRUE && op->casting_time > 0) 420 if (settings.casting_time == TRUE && op->casting_time > 0)
1235 op->casting_time--; 421 op->casting_time--;
422
1236 if (op->speed_left <= 0) 423 if (op->speed_left <= 0)
1237 op->speed_left += FABS (op->speed); 424 op->speed_left += FABS (op->speed);
1238 } 425 }
1239 426
1240 /* Remove marker object from active list */ 427 process_players2 ();
1241 if (marker->active_prev != NULL) 428}
1242 marker->active_prev->active_next = NULL; 429
430/* clean up everything before exiting */
431void
432emergency_save ()
433{
434 LOG (llevDebug, "emergency save begin.\n");
435
436 maptile::emergency_save ();
437
438 LOG (llevDebug, "saving book archive.\n");
439 write_book_archive ();
440
441 LOG (llevDebug, "emergency save done.\n");
442}
443
444// send all clients some informational text
445static void
446cleanup_inform (const char *cause, bool make_core)
447{
448 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "The server will now shutdown.\n");
449 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "Cause for this shtudown: %s\n", cause);
450
451 if (make_core)
452 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "This is considered a crash.\n");
1243 else 453 else
1244 active_objects = NULL; 454 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "This is considered to be a clean shutdown.\n");
1245 455
1246 process_players2 (map); 456 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "%s\n", CLEANUP_MESSAGE);
1247 457
1248 free_object (marker); 458 flush_sockets ();
1249}
1250
1251void
1252clean_tmp_files (void)
1253{
1254 mapstruct *m, *next;
1255
1256 LOG (llevInfo, "Cleaning up...\n");
1257
1258 /* We save the maps - it may not be intuitive why, but if there are unique
1259 * items, we need to save the map so they get saved off. Perhaps we should
1260 * just make a special function that only saves the unique items.
1261 */
1262 for (m = first_map; m != NULL; m = next)
1263 {
1264 next = m->next;
1265 if (m->in_memory == MAP_IN_MEMORY)
1266 {
1267 /* If we want to reuse the temp maps, swap it out (note that will also
1268 * update the log file. Otherwise, save the map (mostly for unique item
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 */
1273
1274 /* XXX The above comment is dead wrong */
1275 if (settings.recycle_tmp_maps == TRUE)
1276 swap_map (m);
1277 else
1278 {
1279 new_save_map (m, 0); /* note we save here into a overlay map */
1280 clean_tmp_map (m);
1281 }
1282 }
1283 }
1284 write_todclock (); /* lets just write the clock here */
1285} 459}
1286 460
1287/* clean up everything before exiting */ 461/* clean up everything before exiting */
1288void 462void
1289cleanup (void) 463cleanup (const char *cause, bool make_core)
1290{ 464{
465 LOG (llevError, "cleanup cause: %s\n", cause);
466
467 if (!make_core)
468 cleanup_inform (cause, make_core);
469
1291 LOG (llevDebug, "Cleanup called. freeing data.\n"); 470 LOG (llevDebug, "cleanup begin.\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 471
1308/* LOG(llevDebug, ss_dump_table(0xff));*/ 472 if (init_done && !in_cleanup)
1309#endif 473 {
474 in_cleanup = true;
475 emergency_save ();
476 }
477 else
478 in_cleanup = true;
479
480 LOG (llevDebug, "running cleanup handlers.\n");
481 INVOKE_GLOBAL (CLEANUP);
482
483 LOG (llevDebug, "cleanup done.\n");
484
485 if (make_core)
486 {
487 cleanup_inform (cause, make_core);
488 abort ();
489 }
490 else
1310 exit (0); 491 _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
1319 * cleanup. We also leave that loop to actually handle the freeing
1320 * of the data.
1321 */
1322 if (pl->ob->type != DEAD_OBJECT)
1323 {
1324 pl->socket.status = Ns_Dead;
1325
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 }
1350} 492}
1351 493
1352int 494int
1353forbid_play (void) 495forbid_play (void)
1354{ 496{
1368 510
1369 while (fgets (buf, MAX_BUF, fp)) 511 while (fgets (buf, MAX_BUF, fp))
1370 { 512 {
1371 if (buf[0] == '#') 513 if (buf[0] == '#')
1372 continue; 514 continue;
515
1373 if (!strncmp (buf, "msg", 3)) 516 if (!strncmp (buf, "msg", 3))
1374 { 517 {
1375 if (forbit) 518 if (forbit)
1376 while (fgets (buf, MAX_BUF, fp)) /* print message */ 519 while (fgets (buf, MAX_BUF, fp)) /* print message */
1377 fputs (buf, logfile); 520 fputs (buf, logfile);
1378 break; 521 break;
1379
1380 } 522 }
1381 else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3) 523 else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3)
1382 { 524 {
1383 LOG (llevDebug, "Warning: Incomplete line in permission file ignored.\n"); 525 LOG (llevDebug, "Warning: Incomplete line in permission file ignored.\n");
1384 continue; 526 continue;
1398 return 0; 540 return 0;
1399#endif 541#endif
1400} 542}
1401 543
1402/* 544/*
1403 * do_specials() is a collection of functions to call from time to time. 545 * do_specials() is a collection of functions to call from time to time.
1404 * Modified 2000-1-14 MSW to use the global pticks count to determine how 546 * Modified 2000-1-14 MSW to use the global pticks count to determine how
1405 * often to do things. This will allow us to spred them out more often. 547 * often to do things. This will allow us to spred them out more often.
1406 * I use prime numbers for the factor count - in that way, it is less likely 548 * I use prime numbers for the factor count - in that way, it is less likely
1407 * these actions will fall on the same tick (compared to say using 500/2500/15000 549 * these actions will fall on the same tick (compared to say using 500/2500/15000
1408 * which would mean on that 15,000 tick count a whole bunch of stuff gets 550 * which would mean on that 15,000 tick count a whole bunch of stuff gets
1416extern unsigned long todtick; 558extern unsigned long todtick;
1417 559
1418void 560void
1419do_specials (void) 561do_specials (void)
1420{ 562{
1421
1422#ifdef WATCHDOG
1423 if (!(pticks % 503))
1424 watchdog ();
1425#endif
1426
1427 if (!(pticks % PTICKS_PER_CLOCK)) 563 if (!(pticks % PTICKS_PER_CLOCK))
1428 tick_the_clock (); 564 tick_the_clock ();
1429 565
1430 if (!(pticks % 7)) 566 if (!(pticks % 7))
1431 shstr::gc (); 567 shstr::gc ();
1432 568
1433 if (!(pticks % 79))
1434 flush_old_maps (); /* Clears the tmp-files of maps which have reset */
1435
1436 if (!(pticks % 2503)) 569 if (!(pticks % 2503))
1437 fix_weight (); /* Hack to fix weightproblems caused by bugs */ 570 fix_weight (); /* Hack to fix weightproblems caused by bugs */
1438 571
1439 if (!(pticks % 2521))
1440 metaserver_update (); /* 2500 ticks is about 5 minutes */
1441
1442 if (!(pticks % 5003)) 572 if (!(pticks % 5003))
1443 write_book_archive (); 573 write_book_archive ();
1444 574
1445 if (!(pticks % 5009)) 575 if (!(pticks % 5009))
1446 clean_friendly_list (); 576 clean_friendly_list ();
1453} 583}
1454 584
1455void 585void
1456server_tick () 586server_tick ()
1457{ 587{
1458 nroferrors = 0; 588 // first do the user visible stuff
1459
1460 doeric_server (); 589 doeric_server ();
1461 INVOKE_GLOBAL (CLOCK); 590 INVOKE_GLOBAL (CLOCK);
1462 process_events (NULL); /* "do" something with objects with speed */ 591 process_events (); /* "do" something with objects with speed */
1463 flush_sockets (); 592 flush_sockets ();
1464 check_active_maps (); /* Removes unused maps after a certain timeout */ 593
594 // then do some bookkeeping, should not really be here
1465 do_specials (); /* Routines called from time to time. */ 595 do_specials (); /* Routines called from time to time. */
1466 object::free_mortals (); 596 attachable::check_mortals ();
1467 597
1468 ++pticks; 598 ++pticks;
1469} 599}
1470 600
1471int 601int
1472main (int argc, char **argv) 602main (int argc, char **argv)
1473{ 603{
1474 settings.argc = argc; 604 settings.argc = argc;
1475 settings.argv = argv; 605 settings.argv = argv;
1476 606
1477 cfperl_init ();
1478
1479 init (argc, argv); 607 init (argc, argv);
1480 608
1481 initPlugins (); 609 initPlugins ();
1482 610
1483 for (;;) 611 for (;;)
1484 cfperl_main (); 612 cfperl_main ();
1485
1486 // unreached
1487 emergency_save (0);
1488 cleanup ();
1489
1490 return 0;
1491} 613}
614

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines