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.20 by root, Mon Sep 4 11:08:00 2006 UTC vs.
Revision 1.80 by pippijn, Sat Jan 6 14:42:30 2007 UTC

1/*
2 * static char *rcsid_main_c =
3 * "$Id: main.C,v 1.20 2006/09/04 11:08:00 root Exp $";
4 */
5
6/* 1/*
7 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
8 3
4 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
9 Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team 5 Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen 6 Copyright (C) 1992 Frank Tore Johansen
11 7
12 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
13 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
21 17
22 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
23 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 21
26 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>
27*/ 23*/
28 24
29#include <global.h> 25#include <global.h>
30#include <object.h> 26#include <object.h>
31#include <tod.h> 27#include <tod.h>
32 28
33#ifdef HAVE_DES_H 29#ifdef HAVE_DES_H
34#include <des.h> 30# include <des.h>
35#else 31#else
36# ifdef HAVE_CRYPT_H 32# ifdef HAVE_CRYPT_H
37# include <crypt.h> 33# include <crypt.h>
38# endif 34# endif
39#endif 35#endif
40 36
41#ifndef __CEXTRACT__
42#include <sproto.h> 37#include <sproto.h>
43#endif
44
45#ifdef HAVE_TIME_H
46#include <time.h> 38#include <time.h>
47#endif
48 39
49#include <../random_maps/random_map.h> 40#include <../random_maps/random_map.h>
50#include <../random_maps/rproto.h> 41#include <../random_maps/rproto.h>
51#include "path.h" 42#include "path.h"
52 43
53static char days[7][4] = { 44static char days[7][4] = {
54 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 45 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
55}; 46};
56 47
57void 48void
58version (object * op) 49version (object *op)
59{ 50{
60 if (op != NULL) 51 if (op)
61 clear_win_info (op); 52 clear_win_info (op);
62 53
63 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);
64 55
65/* If in a socket, don't print out the list of authors. It confuses the
66 * crossclient program.
67 */
68 if (op == NULL)
69 return;
70 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>");
71 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>");
72 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>");
73 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>");
74 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>");
75 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>");
76 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>");
77 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>");
78 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>");
79 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>");
80 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>");
81 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>");
82 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>");
83 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>");
84 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>");
85 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>");
86 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>");
87 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>");
88 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>");
89 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>");
90 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>");
91 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>");
92 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>");
93 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>");
94 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>");
95 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>");
96 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>");
97 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>");
98 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>");
99 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>");
100 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>");
101 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>");
102 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>");
103 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>");
104 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>");
105 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>");
106 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>");
107 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>");
108 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>");
109 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>");
110 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
111 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:"); 101 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:");
112 new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner"); 102 new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner");
113 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>");
114 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>");
115 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>");
116 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>");
117 new_draw_info (NDI_UNIQUE, 0, op, "And many more!"); 107 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} 108}
192 109
193/* 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
194 * savebed. We do some error checking - its possible that the 111 * savebed. We do some error checking - its possible that the
195 * 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
196 * goes someplace. 113 * goes someplace.
197 */ 114 */
198void 115void
199enter_player_savebed (object * op) 116enter_player_savebed (object *op)
200{ 117{
201 mapstruct *oldmap = op->map; 118 object *tmp = object::create ();
202 object *tmp;
203
204 tmp = get_object ();
205
206 EXIT_PATH (tmp) = op->contr->savebed_map; 119 EXIT_PATH (tmp) = op->contr->savebed_map;
207 EXIT_X (tmp) = op->contr->bed_x; 120 EXIT_X (tmp) = op->contr->bed_x;
208 EXIT_Y (tmp) = op->contr->bed_y; 121 EXIT_Y (tmp) = op->contr->bed_y;
209 enter_exit (op, tmp); 122 op->enter_exit (tmp);
210 /* If the player has not changed maps and the name does not match 123 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} 124}
250 125
251/* 126/*
252 * 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
253 * 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
254 * 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
255 * whatever reason. If default map coordinates are to be used, then 130 * whatever reason. If default map coordinates are to be used, then
256 * the function that calls this should figure them out. 131 * the function that calls this should figure them out.
257 */ 132 */
258static void 133void
259enter_map (object * op, mapstruct * newmap, int x, int y) 134object::enter_map (maptile *newmap, int x, int y)
260{ 135{
261 mapstruct *oldmap = op->map; 136 if (destroyed () || !newmap || newmap->in_memory != MAP_IN_MEMORY)
137 return;
262 138
263 if (out_of_map (newmap, x, y)) 139 if (out_of_map (newmap, x, y))
264 { 140 {
265 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);
266 x = MAP_ENTER_X (newmap); 142 x = newmap->enter_x;
267 y = MAP_ENTER_Y (newmap); 143 y = newmap->enter_y;
268 if (out_of_map (newmap, x, y)) 144 if (out_of_map (newmap, x, y))
269 { 145 {
270 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",
271 newmap->path, x, y, MAP_WIDTH (newmap), MAP_HEIGHT (newmap)); 147 &newmap->path, x, y, newmap->width, newmap->height);
272 new_draw_info (NDI_UNIQUE, 0, op, "The exit is closed"); 148 new_draw_info (NDI_UNIQUE, 0, this, "The exit is closed");
273 return; 149 return;
274 } 150 }
275 } 151 }
152
153 if (contr && map != newmap && map)
154 if (INVOKE_MAP (LEAVE, map, ARG_PLAYER (contr)))
155 return;
156
157 /* If it is a player login, he has yet to be inserted anyplace.
158 * otherwise, we need to deal with removing the player here.
159 */
160 remove ();
161
276 /* try to find a spot for the player */ 162 /* try to find a spot for the player */
277 if (ob_blocked (op, newmap, x, y)) 163 if (ob_blocked (this, newmap, x, y))
278 { /* First choice blocked */ 164 { /* First choice blocked */
279 /* We try to find a spot for the player, starting closest in. 165 /* 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, 166 * 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 167 * So for example, if the north space is free, you would always end up there even
282 * if other spaces around are available. 168 * if other spaces around are available.
283 * Note that for the second and third calls, we could start at a position other 169 * 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. 170 * than one, but then we could end up on the other side of walls and so forth.
285 */ 171 */
286 int i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE1 + 1); 172 int i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE1 + 1);
173
287 if (i == -1) 174 if (i == -1)
288 { 175 {
289 i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE2 + 1); 176 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE2 + 1);
290 if (i == -1) 177 if (i == -1)
291 i = find_free_spot (op, newmap, x, y, 1, SIZEOFFREE); 178 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE);
292 } 179 }
180
293 if (i != -1) 181 if (i != -1)
294 { 182 {
295 x += freearr_x[i]; 183 x += freearr_x[i];
296 y += freearr_y[i]; 184 y += freearr_y[i];
297 } 185 }
298 else 186 else
299 {
300 /* not much we can do in this case. */ 187 /* 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); 188 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 { 189 }
307 INVOKE_PLAYER (MAP_CHANGE, op->contr, ARG_MAP (op->map), ARG_MAP (newmap)); 190
308 INVOKE_MAP (LEAVE, op->map, ARG_PLAYER (op->contr)); 191 if (contr && map != newmap)
309 } 192 {
193 if (INVOKE_PLAYER (MAP_CHANGE, contr, ARG_MAP (newmap), ARG_INT (x), ARG_INT (y)))
194 return;
310 195
311 /* If it is a player login, he has yet to be inserted anyplace. 196 if (INVOKE_MAP (ENTER, newmap, ARG_PLAYER (contr), ARG_INT (x), ARG_INT (y)))
312 * otherwise, we need to deal with removing the player here. 197 return;
313 */ 198 }
314 if (!QUERY_FLAG (op, FLAG_REMOVED))
315 remove_ob (op);
316 199
317 /* remove_ob clears these so they must be reset after the remove_ob call */
318 op->x = x; 200 this->x = x;
319 op->y = y; 201 this->y = y;
320 op->map = newmap; 202 map = newmap;
203
321 insert_ob_in_map (op, op->map, NULL, INS_NO_WALK_ON); 204 insert_ob_in_map (this, map, 0, INS_NO_WALK_ON);
322 205
323 INVOKE_MAP (ENTER, op->map, ARG_PLAYER (op->contr));
324
325 if (!op->contr->hidden)
326 newmap->players++;
327
328 newmap->timeout = 0;
329 op->enemy = NULL; 206 enemy = NULL;
330 207
331 if (op->contr) 208 if (contr)
332 { 209 {
333 strcpy (op->contr->maplevel, newmap->path); 210 contr->maplevel = newmap->path;
334 op->contr->count = 0; 211 contr->count = 0;
335 } 212 }
336 213
337 /* Update any golems */ 214 /* Update any golems */
338 if (op->type == PLAYER && op->contr->ranges[range_golem] != NULL) 215 if (type == PLAYER && contr->ranges[range_golem])
339 { 216 {
340 int i = find_free_spot (op->contr->ranges[range_golem], newmap, 217 int i = find_free_spot (contr->ranges[range_golem], newmap,
341 x, y, 1, SIZEOFFREE); 218 x, y, 1, SIZEOFFREE);
342 remove_ob (op->contr->ranges[range_golem]); 219
220 contr->ranges[range_golem]->remove ();
221
343 if (i == -1) 222 if (i == -1)
344 { 223 {
345 remove_friendly_object (op->contr->ranges[range_golem]); 224 remove_friendly_object (contr->ranges[range_golem]);
346 free_object (op->contr->ranges[range_golem]); 225 contr->ranges[range_golem]->destroy ();
347 op->contr->ranges[range_golem] = NULL; 226 contr->ranges[range_golem] = 0;
348 op->contr->golem_count = 0;
349 } 227 }
350 else 228 else
351 { 229 {
352 object *tmp;
353 for (tmp = op->contr->ranges[range_golem]; tmp != NULL; tmp = tmp->more) 230 for (object *tmp = contr->ranges[range_golem]; tmp != NULL; tmp = tmp->more)
354 { 231 {
355 tmp->x = x + freearr_x[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.x); 232 tmp->x = x + freearr_x[i] + (tmp->arch ? 0 : tmp->arch->clone.x);
356 tmp->y = y + freearr_y[i] + (tmp->arch == NULL ? 0 : tmp->arch->clone.y); 233 tmp->y = y + freearr_y[i] + (tmp->arch ? 0 : tmp->arch->clone.y);
357 tmp->map = newmap; 234 tmp->map = newmap;
358 } 235 }
236
359 insert_ob_in_map (op->contr->ranges[range_golem], newmap, NULL, 0); 237 insert_ob_in_map (contr->ranges[range_golem], newmap, NULL, 0);
360 op->contr->ranges[range_golem]->direction = 238 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); 239 find_dir_2 (x - contr->ranges[range_golem]->x, y - contr->ranges[range_golem]->y);
362 } 240 }
363 } 241 }
364 op->direction = 0;
365 242
366 /* since the players map is already loaded, we don't need to worry 243 /* since the players map is already loaded, we don't need to worry
367 * about pending objects. 244 * about pending objects.
368 */ 245 */
369 remove_all_pets (newmap); 246 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} 247}
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
412/* clean_path takes a path and replaces all / with _
413 * We do a strcpy so that we do not change the original string.
414 */
415char *
416clean_path (const char *file)
417{
418 static char newpath[MAX_BUF], *cp;
419
420 strncpy (newpath, file, MAX_BUF - 1);
421 newpath[MAX_BUF - 1] = '\0';
422 for (cp = newpath; *cp != '\0'; cp++)
423 {
424 if (*cp == '/')
425 *cp = '_';
426 }
427 return newpath;
428}
429
430
431/* unclean_path takes a path and replaces all _ with /
432 * This basically undoes clean path.
433 * 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
435 * are getting passed a string that points to a unique map
436 * path.
437 */
438char *
439unclean_path (const char *src)
440{
441 static char newpath[MAX_BUF], *cp;
442
443 cp = strrchr (src, '/');
444 if (cp)
445 strncpy (newpath, cp + 1, MAX_BUF - 1);
446 else
447 strncpy (newpath, src, MAX_BUF - 1);
448 newpath[MAX_BUF - 1] = '\0';
449
450 for (cp = newpath; *cp != '\0'; cp++)
451 {
452 if (*cp == '_')
453 *cp = '/';
454 }
455 return newpath;
456}
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 248
980/* process_players1 and process_players2 do all the player related stuff. 249/* 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 250 * 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 251 * 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 252 * by the various functions. process_players1() does the processing before
984 * objects have been updated, process_players2() does the processing that 253 * objects have been updated, process_players2() does the processing that
985 * is needed after the players have been updated. 254 * is needed after the players have been updated.
986 */ 255 */
987 256static void
988void 257process_players1 ()
989process_players1 (mapstruct * map)
990{ 258{
991 int flag; 259 int flag;
992 player *pl, *plnext;
993 260
994 /* Basically, we keep looping until all the players have done their actions. */ 261 /* Basically, we keep looping until all the players have done their actions. */
995 for (flag = 1; flag != 0;) 262 for (flag = 1; flag != 0;)
996 { 263 {
997 flag = 0; 264 flag = 0;
998 for (pl = first_player; pl != NULL; pl = plnext) 265 for_all_players (pl)
999 { 266 {
1000 plnext = pl->next; /* In case a player exits the game in handle_player() */ 267 pl->refcnt_chk ();
1001 268
1002 if (pl->ob == NULL) 269 if (!pl->ob || !pl->ns || !pl->ob->active ())
1003 continue; 270 continue;
1004 271
1005 if (map != NULL && pl->ob->map != map)
1006 continue;
1007
1008 if (pl->ob->speed_left > 0) 272 if (pl->ob->speed_left > 0)
1009 {
1010 if (handle_newcs_player (pl->ob)) 273 if (handle_newcs_player (pl->ob))
1011 flag = 1; 274 flag = 1;
1012 } /* end if player has speed left */
1013 275
1014 /* If the player is not actively playing, don't make a 276 /* If the player is not actively playing, don't make a
1015 * backup save - nothing to save anyway. Plus, the 277 * backup save - nothing to save anyway. Plus, the
1016 * map may not longer be valid. This can happen when the 278 * map may not longer be valid. This can happen when the
1017 * player quits - they exist for purposes of tracking on the map, 279 * player quits - they exist for purposes of tracking on the map,
1022 284
1023#ifdef AUTOSAVE 285#ifdef AUTOSAVE
1024 /* check for ST_PLAYING state so that we don't try to save off when 286 /* check for ST_PLAYING state so that we don't try to save off when
1025 * the player is logging in. 287 * the player is logging in.
1026 */ 288 */
1027 if ((pl->last_save_tick + AUTOSAVE) < pticks && pl->state == ST_PLAYING) 289 if ((pl->last_save_tick + AUTOSAVE) < (uint32) pticks && pl->ns->state == ST_PLAYING)
1028 { 290 {
1029 /* Don't save the player on unholy ground. Instead, increase the 291 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; 292 pl->last_save_tick = pticks;
1038// }
1039 } 293 }
1040#endif 294#endif
1041 } /* end of for loop for all the players */ 295 } /* end of for loop for all the players */
1042 } /* for flag */ 296 } /* for flag */
1043 for (pl = first_player; pl != NULL; pl = pl->next) 297
298 for_all_players (pl)
1044 { 299 {
1045 if (map != NULL && (pl->ob == NULL || pl->ob->map != map)) 300 if (!pl->ob || !pl->ns || !pl->ob->active ())
1046 continue; 301 continue;
302
1047 if (settings.casting_time == TRUE) 303 if (settings.casting_time)
1048 { 304 {
1049 if (pl->ob->casting_time > 0) 305 if (pl->ob->casting_time > 0)
1050 { 306 {
1051 pl->ob->casting_time--; 307 pl->ob->casting_time--;
1052 pl->ob->start_holding = 1; 308 pl->ob->start_holding = 1;
1053 } 309 }
310
1054 /* set spell_state so we can update the range in stats field */ 311 /* set spell_state so we can update the range in stats field */
1055 if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1)) 312 if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1))
1056 {
1057 pl->ob->start_holding = 0; 313 pl->ob->start_holding = 0;
1058 } 314 }
1059 } 315
1060 do_some_living (pl->ob); 316 do_some_living (pl->ob);
1061 /* draw(pl->ob);*//* updated in socket code */
1062 } 317 }
1063} 318}
1064 319
1065void 320static void
1066process_players2 (mapstruct * map) 321process_players2 ()
1067{ 322{
1068 player *pl;
1069
1070 /* Then check if any players should use weapon-speed instead of speed */ 323 /* Then check if any players should use weapon-speed instead of speed */
1071 for (pl = first_player; pl != NULL; pl = pl->next) 324 for_all_players (pl)
1072 { 325 {
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 - 326 /* The code that did weapon_sp handling here was out of place -
1084 * this isn't called until after the player has finished there 327 * 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 328 * actions, and is thus out of place. All we do here is bounds
1086 * checking. 329 * checking.
1087 */ 330 */
1093 /* This needs to be here - if the player is running, we need to 336 /* 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 337 * clear this each tick, but new commands are not being received
1095 * so execute_newserver_command() is never called 338 * so execute_newserver_command() is never called
1096 */ 339 */
1097 pl->has_hit = 0; 340 pl->has_hit = 0;
1098
1099 } 341 }
1100 else if (pl->ob->speed_left > pl->ob->speed) 342 else if (pl->ob->speed_left > pl->ob->speed)
1101 pl->ob->speed_left = pl->ob->speed; 343 pl->ob->speed_left = pl->ob->speed;
1102 } 344 }
1103} 345}
1104 346
1105void 347void
1106process_events (mapstruct * map) 348process_events ()
1107{ 349{
1108 object *op; 350 object *op;
1109 object *marker = get_object ();
1110 tag_t tag;
1111 351
352 static object_ptr marker_;
353
354 if (!marker_)
355 marker_ = object::create ();
356
357 object *marker = marker_;
358
1112 process_players1 (map); 359 process_players1 ();
1113 360
1114 marker->active_next = active_objects; 361 marker->active_next = active_objects;
1115 362
1116 if (marker->active_next) 363 if (marker->active_next)
1117 marker->active_next->active_prev = marker; 364 marker->active_next->active_prev = marker;
1118 365
1119 marker->active_prev = NULL; 366 marker->active_prev = 0;
1120 active_objects = marker; 367 active_objects = marker;
1121 368
1122 while (marker->active_next) 369 while (marker->active_next)
1123 { 370 {
1124 op = marker->active_next; 371 op = marker->active_next;
1125 tag = op->count;
1126 372
1127 /* Move marker forward - swap op and marker */ 373 /* Move marker forward - swap op and marker */
1128 op->active_prev = marker->active_prev; 374 op->active_prev = marker->active_prev;
1129 375
1130 if (op->active_prev) 376 if (op->active_prev)
1142 388
1143 /* Now process op */ 389 /* Now process op */
1144 if (QUERY_FLAG (op, FLAG_FREED)) 390 if (QUERY_FLAG (op, FLAG_FREED))
1145 { 391 {
1146 LOG (llevError, "BUG: process_events(): Free object on list\n"); 392 LOG (llevError, "BUG: process_events(): Free object on list\n");
1147 op->speed = 0; 393 op->set_speed (0);
1148 update_ob_speed (op);
1149 continue; 394 continue;
1150 } 395 }
1151 396
1152 /* I've seen occasional crashes due to this - the object is removed, 397 /* 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 398 * and thus the map it points to (last map it was on) may be bogus
1160 * around. 405 * around.
1161 */ 406 */
1162 if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY) 407 if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY)
1163 { 408 {
1164 LOG (llevError, "BUG: process_events(): Removed object on list\n"); 409 LOG (llevError, "BUG: process_events(): Removed object on list\n");
1165 dump_object (op); 410 char *dump = dump_object (op);
1166 LOG (llevError, errmsg); 411 LOG (llevError, dump);
1167 free_object (op); 412 free (dump);
413 op->destroy ();
1168 continue; 414 continue;
1169 } 415 }
1170 416
1171 if (!op->speed) 417 if (!op->has_active_speed ())
1172 { 418 {
1173 LOG (llevError, "BUG: process_events(): Object %s has no speed, " "but is on active list\n", &op->arch->name); 419 LOG (llevError, "BUG: process_events(): Object %s has no speed (%f), "
1174 update_ob_speed (op); 420 "but is on active list\n", op->debug_desc (), op->speed);
421 op->set_speed (0);
1175 continue; 422 continue;
1176 } 423 }
1177 424
1178 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP && map == NULL) 425 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP)
1179 { 426 {
1180 LOG (llevError, "BUG: process_events(): Object without map or " "inventory is on active list: %s (%d)\n", &op->name, op->count); 427 LOG (llevError, "BUG: process_events(): Object without map or "
428 "inventory is on active list: %s (%d)\n", &op->name, op->count);
1181 op->speed = 0; 429 op->set_speed (0);
1182 update_ob_speed (op);
1183 continue; 430 continue;
1184 } 431 }
1185 432
1186 if (map != NULL && op->map != map)
1187 continue;
1188
1189 /* Animate the object. Bug of feature that andim_speed 433 /* Animate the object. Bug or feature that anim_speed
1190 * is based on ticks, and not the creatures speed? 434 * is based on ticks, and not the creatures speed?
1191 */ 435 */
1192 if (op->anim_speed && op->last_anim >= op->anim_speed) 436 if (op->anim_speed && op->last_anim >= op->anim_speed)
1193 { 437 {
1194 if ((op->type == PLAYER) || (op->type == MONSTER)) 438 if ((op->type == PLAYER))
1195 animate_object (op, op->facing); 439 animate_object (op, op->facing);
1196 else 440 else
1197 animate_object (op, op->direction); 441 animate_object (op, op->direction);
1198 442
1199 op->last_anim = 1; 443 op->last_anim = 1;
1217 LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null"); 461 LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null");
1218 } 462 }
1219#endif 463#endif
1220 --op->speed_left; 464 --op->speed_left;
1221 process_object (op); 465 process_object (op);
466
1222 if (was_destroyed (op, tag)) 467 if (op->destroyed ())
1223 continue; 468 continue;
1224 } 469 }
470
1225 if (settings.casting_time == TRUE && op->casting_time > 0) 471 if (settings.casting_time == TRUE && op->casting_time > 0)
1226 op->casting_time--; 472 op->casting_time--;
473
1227 if (op->speed_left <= 0) 474 if (op->speed_left <= 0)
1228 op->speed_left += FABS (op->speed); 475 op->speed_left += FABS (op->speed);
1229 } 476 }
1230 477
1231 /* Remove marker object from active list */ 478 /* Remove marker object from active list */
1232 if (marker->active_prev != NULL) 479 if (marker->active_prev != NULL)
1233 marker->active_prev->active_next = NULL; 480 marker->active_prev->active_next = NULL;
1234 else 481 else
1235 active_objects = NULL; 482 active_objects = NULL;
1236 483
1237 process_players2 (map); 484 process_players2 ();
1238
1239 free_object (marker);
1240}
1241
1242void
1243clean_tmp_files (void)
1244{
1245 mapstruct *m, *next;
1246
1247 LOG (llevInfo, "Cleaning up...\n");
1248
1249 /* We save the maps - it may not be intuitive why, but if there are unique
1250 * items, we need to save the map so they get saved off. Perhaps we should
1251 * just make a special function that only saves the unique items.
1252 */
1253 for (m = first_map; m != NULL; m = next)
1254 {
1255 next = m->next;
1256 if (m->in_memory == MAP_IN_MEMORY)
1257 {
1258 /* If we want to reuse the temp maps, swap it out (note that will also
1259 * update the log file. Otherwise, save the map (mostly for unique item
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 */
1264
1265 /* XXX The above comment is dead wrong */
1266 if (settings.recycle_tmp_maps == TRUE)
1267 swap_map (m);
1268 else
1269 {
1270 new_save_map (m, 0); /* note we save here into a overlay map */
1271 clean_tmp_map (m);
1272 }
1273 }
1274 }
1275 write_todclock (); /* lets just write the clock here */
1276} 485}
1277 486
1278/* clean up everything before exiting */ 487/* clean up everything before exiting */
1279void 488void
1280cleanup (void) 489emergency_save ()
1281{ 490{
1282 LOG (llevDebug, "Cleanup called. freeing data.\n"); 491 LOG (llevDebug, "emergency save begin.\n");
1283 clean_tmp_files (); 492
493 LOG (llevDebug, "saving players.\n");
494 for_all_players (pl)
495 if (pl->enable_save && pl->ob && pl->ns)
496 {
497 pl->save (true);
498 pl->enable_save = true;
499 }
500
501// for_all_players (pl)
502// if (pl->ob)
503// pl->ob->remove ();
504
505 LOG (llevDebug, "saving maps.\n");
506 maptile::emergency_save ();
507
508 LOG (llevDebug, "saving book archive.\n");
1284 write_book_archive (); 509 write_book_archive ();
1285#ifdef MEMORY_DEBUG 510
1286 free_all_maps (); 511 LOG (llevDebug, "emergency save done.\n");
1287 free_style_maps (); 512}
1288 free_all_object_data (); 513
1289 free_all_archs (); 514// send all clients some informational text
1290 free_all_treasures (); 515static void
1291 free_all_images (); 516cleanup_inform (const char *cause, bool make_core)
1292 free_all_newserver (); 517{
1293 free_all_recipes (); 518 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "The server will now shutdown.\n");
1294 free_all_readable (); 519 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "Cause for this shtudown: %s\n", cause);
1295 free_all_god (); 520
1296 free_all_anim (); 521 if (make_core)
1297 /* See what the string data that is out there that hasn't been freed. */ 522 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "This is considered a crash.\n");
1298/* LOG(llevDebug, ss_dump_table(0xff));*/ 523 else
1299#endif 524 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "This is considered to be a clean shutdown.\n");
525
526 new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_RED, 0, 0, "%s\n", CLEANUP_MESSAGE);
527
528 flush_sockets ();
529}
530
531/* clean up everything before exiting */
532void
533cleanup (const char *cause, bool make_core)
534{
535 LOG (llevError, "cleanup cause: %s\n", cause);
536
537 if (!make_core)
538 cleanup_inform (cause, make_core);
539
540 LOG (llevDebug, "cleanup begin.\n");
541
542 if (init_done && !in_cleanup)
543 {
544 in_cleanup = true;
545 emergency_save ();
546 }
547 else
548 in_cleanup = true;
549
550 LOG (llevDebug, "running cleanup handlers.\n");
551 INVOKE_GLOBAL (CLEANUP);
552
553 LOG (llevDebug, "cleanup done.\n");
554
555 if (make_core)
556 {
557 cleanup_inform (cause, make_core);
558 abort ();
559 }
560 else
1300 exit (0); 561 _exit (0);
1301}
1302
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
1309 * cleanup. We also leave that loop to actually handle the freeing
1310 * of the data.
1311 */
1312 if (pl->ob->type != DEAD_OBJECT)
1313 {
1314 pl->socket.status = Ns_Dead;
1315
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 }
1339} 562}
1340 563
1341int 564int
1342forbid_play (void) 565forbid_play (void)
1343{ 566{
1357 580
1358 while (fgets (buf, MAX_BUF, fp)) 581 while (fgets (buf, MAX_BUF, fp))
1359 { 582 {
1360 if (buf[0] == '#') 583 if (buf[0] == '#')
1361 continue; 584 continue;
585
1362 if (!strncmp (buf, "msg", 3)) 586 if (!strncmp (buf, "msg", 3))
1363 { 587 {
1364 if (forbit) 588 if (forbit)
1365 while (fgets (buf, MAX_BUF, fp)) /* print message */ 589 while (fgets (buf, MAX_BUF, fp)) /* print message */
1366 fputs (buf, logfile); 590 fputs (buf, logfile);
1367 break; 591 break;
1368
1369 } 592 }
1370 else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3) 593 else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3)
1371 { 594 {
1372 LOG (llevDebug, "Warning: Incomplete line in permission file ignored.\n"); 595 LOG (llevDebug, "Warning: Incomplete line in permission file ignored.\n");
1373 continue; 596 continue;
1387 return 0; 610 return 0;
1388#endif 611#endif
1389} 612}
1390 613
1391/* 614/*
1392 * do_specials() is a collection of functions to call from time to time. 615 * do_specials() is a collection of functions to call from time to time.
1393 * Modified 2000-1-14 MSW to use the global pticks count to determine how 616 * Modified 2000-1-14 MSW to use the global pticks count to determine how
1394 * often to do things. This will allow us to spred them out more often. 617 * often to do things. This will allow us to spred them out more often.
1395 * I use prime numbers for the factor count - in that way, it is less likely 618 * I use prime numbers for the factor count - in that way, it is less likely
1396 * these actions will fall on the same tick (compared to say using 500/2500/15000 619 * these actions will fall on the same tick (compared to say using 500/2500/15000
1397 * which would mean on that 15,000 tick count a whole bunch of stuff gets 620 * which would mean on that 15,000 tick count a whole bunch of stuff gets
1405extern unsigned long todtick; 628extern unsigned long todtick;
1406 629
1407void 630void
1408do_specials (void) 631do_specials (void)
1409{ 632{
1410
1411#ifdef WATCHDOG
1412 if (!(pticks % 503))
1413 watchdog ();
1414#endif
1415
1416 if (!(pticks % PTICKS_PER_CLOCK)) 633 if (!(pticks % PTICKS_PER_CLOCK))
1417 tick_the_clock (); 634 tick_the_clock ();
1418 635
1419 if (!(pticks % 7)) 636 if (!(pticks % 7))
1420 shstr::gc (); 637 shstr::gc ();
1421 638
1422 if (!(pticks % 79))
1423 flush_old_maps (); /* Clears the tmp-files of maps which have reset */
1424
1425 if (!(pticks % 2503)) 639 if (!(pticks % 2503))
1426 fix_weight (); /* Hack to fix weightproblems caused by bugs */ 640 fix_weight (); /* Hack to fix weightproblems caused by bugs */
1427 641
1428 if (!(pticks % 2521))
1429 metaserver_update (); /* 2500 ticks is about 5 minutes */
1430
1431 if (!(pticks % 5003)) 642 if (!(pticks % 5003))
1432 write_book_archive (); 643 write_book_archive ();
1433 644
1434 if (!(pticks % 5009)) 645 if (!(pticks % 5009))
1435 clean_friendly_list (); 646 clean_friendly_list ();
1442} 653}
1443 654
1444void 655void
1445server_tick () 656server_tick ()
1446{ 657{
1447 nroferrors = 0; 658 // first do the user visible stuff
1448
1449 doeric_server (); 659 doeric_server ();
1450 INVOKE_GLOBAL (CLOCK); 660 INVOKE_GLOBAL (CLOCK);
1451 process_events (NULL); /* "do" something with objects with speed */ 661 process_events (); /* "do" something with objects with speed */
1452 flush_sockets (); 662 flush_sockets ();
1453 check_active_maps (); /* Removes unused maps after a certain timeout */ 663
664 // then do some bookkeeping, should not really be here
1454 do_specials (); /* Routines called from time to time. */ 665 do_specials (); /* Routines called from time to time. */
666 attachable::check_mortals ();
1455 667
1456 ++pticks; 668 ++pticks;
1457} 669}
1458 670
1459int 671int
1460main (int argc, char **argv) 672main (int argc, char **argv)
1461{ 673{
1462 settings.argc = argc; 674 settings.argc = argc;
1463 settings.argv = argv; 675 settings.argv = argv;
1464 676
1465 cfperl_init ();
1466
1467 init (argc, argv); 677 init (argc, argv);
1468 678
1469 initPlugins (); 679 initPlugins ();
1470 680
1471 for (;;) 681 for (;;)
1472 cfperl_main (); 682 cfperl_main ();
1473
1474 // unreached
1475 emergency_save (0);
1476 cleanup ();
1477
1478 return 0;
1479} 683}
684

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines