ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/main.C
Revision: 1.94
Committed: Wed Mar 14 04:12:29 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.93: +1 -3 lines
Log Message:
- rewrote more face handling code
- automatically send smooth faces, as the client will need them anyways
  and it makes little sense to wait for the client to axk for it. of course,
  gcfclient suffers from weird ordering problems again.
- UP_OBJ_FACE was often abused in situations where other things changed,
  updated lots of spaces, probably more to be done.
- update_smooth became so small that inlining it actually clarified
  the code. similar for update_space, which is not inlined for other reasons.
- faces were not initialised properly
- add versioncheck for face data
- rewrite invisibility handling a bit: god finger etc. now makes you blink,
  blinking routine has changed to be less annoying and more useful while
  still indicating invisibleness.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.84 * CrossFire, A Multiplayer game
3     *
4     * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5     * Copyright (C) 2001-2003 Mark Wedel & Crossfire Development Team
6     * Copyright (C) 1992 Frank Tore Johansen
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *
22     * The authors can be reached via e-mail at <crossfire@schmorp.de>
23     */
24 elmex 1.1
25     #include <global.h>
26     #include <object.h>
27     #include <tod.h>
28    
29 root 1.47 #include <sproto.h>
30     #include <time.h>
31 elmex 1.1
32     #include <../random_maps/random_map.h>
33     #include <../random_maps/rproto.h>
34     #include "path.h"
35    
36     static char days[7][4] = {
37 root 1.20 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
38     };
39 elmex 1.1
40 root 1.20 void
41 root 1.23 version (object *op)
42 root 1.20 {
43 root 1.71 if (op)
44 root 1.20 clear_win_info (op);
45 elmex 1.1
46 root 1.71 new_draw_info_format (NDI_UNIQUE, 0, op, "This is Crossfire+ v%s", VERSION);
47 root 1.63
48 root 1.20 new_draw_info (NDI_UNIQUE, 0, op, "Authors and contributors to this program:");
49 root 1.63 new_draw_info (NDI_UNIQUE, 0, op, "Marc A. Lehmann <pcg@goof.com>");
50     new_draw_info (NDI_UNIQUE, 0, op, "Robin Redeker <elmex@x-paste.de>");
51     new_draw_info (NDI_UNIQUE, 0, op, "Pippijn van Steenhoven <pip88nl@gmail.com>");
52 root 1.84 new_draw_info (NDI_UNIQUE, 0, op, "");
53     new_draw_info (NDI_UNIQUE, 0, op, "Authors and contributors to the original Crossfire:");
54 root 1.63 new_draw_info (NDI_UNIQUE, 0, op, "Mark Wedel <mwedel@sonic.net>");
55     new_draw_info (NDI_UNIQUE, 0, op, "Frank Tore Johansen <frankj@ifi.uio.no>");
56     new_draw_info (NDI_UNIQUE, 0, op, "Kjetil Torgrim Homme <kjetilho@ifi.uio.no>");
57     new_draw_info (NDI_UNIQUE, 0, op, "Tyler Van Gorder <tvangod@ecst.csuchico.edu>");
58     new_draw_info (NDI_UNIQUE, 0, op, "Tony Elmroth <elmroth@cd.chalmers.se>");
59     new_draw_info (NDI_UNIQUE, 0, op, "Dougal Scott <dougal.scott@fcit.monasu.edu.au>");
60     new_draw_info (NDI_UNIQUE, 0, op, "William <wchuang@athena.mit.edu>");
61     new_draw_info (NDI_UNIQUE, 0, op, "Geoff Bailey <ftww@cs.su.oz.au>");
62 root 1.71 new_draw_info (NDI_UNIQUE, 0, op, "Kjetil Wiekhorst Jørgensen <jorgens@flipper.pvv.unit.no>");
63 root 1.63 new_draw_info (NDI_UNIQUE, 0, op, "Cameron Blackwood <c.blackwood@rdt.monash.edu.au>");
64     new_draw_info (NDI_UNIQUE, 0, op, "Joseph L. Traub <jtraub+@cmu.edu>");
65     new_draw_info (NDI_UNIQUE, 0, op, "Rupert G. Goldie <rgg@aaii.oz.au>");
66     new_draw_info (NDI_UNIQUE, 0, op, "Eric A. Anderson <eanders+@cmu.edu>");
67     new_draw_info (NDI_UNIQUE, 0, op, "Rickard Eneqvist <eneq@Prag.DoCS.UU.SE>");
68     new_draw_info (NDI_UNIQUE, 0, op, "Jarkko Sonninen <Jarkko.Sonninen@lut.fi>");
69     new_draw_info (NDI_UNIQUE, 0, op, "Karl Holland <kholland@sunlab.cit.cornell.du>");
70     new_draw_info (NDI_UNIQUE, 0, op, "Mikael Lundgren <vick@bern.docs.uu.se>");
71     new_draw_info (NDI_UNIQUE, 0, op, "Mikael Olsson <mol@meryl.csd.uu.se>");
72     new_draw_info (NDI_UNIQUE, 0, op, "Tero Haatanen <Tero.Haatanen@lut.fi>");
73     new_draw_info (NDI_UNIQUE, 0, op, "Lasse Ylitalo <ylitalo@student.docs.uu.se>");
74     new_draw_info (NDI_UNIQUE, 0, op, "Niilo Neuvo <anipa@guru.magic.fi>");
75     new_draw_info (NDI_UNIQUE, 0, op, "Markku J{rvinen <mta@modeemi.cs.tut.fi>");
76     new_draw_info (NDI_UNIQUE, 0, op, "Sylvain Meunier <meunier@inf.enst.fr>");
77     new_draw_info (NDI_UNIQUE, 0, op, "Jason Fosback <jfosback@darmok.uoregon.edu>");
78     new_draw_info (NDI_UNIQUE, 0, op, "Carl Edman <cedman@capitalist.princeton.edu>");
79     new_draw_info (NDI_UNIQUE, 0, op, "Charles Henrich <henrich@crh.cl.msu.edu>");
80     new_draw_info (NDI_UNIQUE, 0, op, "Gregor Schmid <schmid@fb3-s7.math.tu-berlin.de>");
81     new_draw_info (NDI_UNIQUE, 0, op, "Raphael Quinet <quinet@montefiore.ulg.ac.be>");
82     new_draw_info (NDI_UNIQUE, 0, op, "Jari Vanhala <jam@modeemi.cs.tut.fi>");
83     new_draw_info (NDI_UNIQUE, 0, op, "Tero Kivinen <kivinen@joker.cs.hut.fi>");
84     new_draw_info (NDI_UNIQUE, 0, op, "Peter Mardahl <peterm@soda.berkeley.edu>");
85     new_draw_info (NDI_UNIQUE, 0, op, "Matthew Zeher <matt@cs.odu.edu>");
86     new_draw_info (NDI_UNIQUE, 0, op, "Scott R. Turner <srt@sun-dimas.aero.org>");
87     new_draw_info (NDI_UNIQUE, 0, op, "Ben Fennema <huma@netcom.com>");
88     new_draw_info (NDI_UNIQUE, 0, op, "Nick Williams <njw@cs.city.ac.uk>");
89     new_draw_info (NDI_UNIQUE, 0, op, "Laurent Wacrenier <Wacren@Gin.ObsPM.Fr>");
90     new_draw_info (NDI_UNIQUE, 0, op, "Brian Thomas <thomas@astro.psu.edu>");
91     new_draw_info (NDI_UNIQUE, 0, op, "John Steven Moerk <jsm@axon.ksc.nasa.gov>");
92     new_draw_info (NDI_UNIQUE, 0, op, "Delbecq David <david.delbecq@mailandnews.com>");
93     new_draw_info (NDI_UNIQUE, 0, op, "Chachkoff Yann <yann.chachkoff@mailandnews.com>\n");
94 root 1.84 new_draw_info (NDI_UNIQUE, 0, op, "");
95 root 1.20 new_draw_info (NDI_UNIQUE, 0, op, "Images and art:");
96     new_draw_info (NDI_UNIQUE, 0, op, "Peter Gardner");
97 root 1.63 new_draw_info (NDI_UNIQUE, 0, op, "David Gervais <david_eg@mail.com>");
98     new_draw_info (NDI_UNIQUE, 0, op, "Mitsuhiro Itakura <ita@gold.koma.jaeri.go.jp>");
99     new_draw_info (NDI_UNIQUE, 0, op, "Hansjoerg Malthaner <hansjoerg.malthaner@danet.de>");
100     new_draw_info (NDI_UNIQUE, 0, op, "Mårten Woxberg <maxmc@telia.com>");
101 root 1.84 new_draw_info (NDI_UNIQUE, 0, op, "");
102 root 1.20 new_draw_info (NDI_UNIQUE, 0, op, "And many more!");
103     }
104    
105 elmex 1.1 /* This is a basic little function to put the player back to his
106     * savebed. We do some error checking - its possible that the
107     * savebed map may no longer exist, so we make sure the player
108     * goes someplace.
109     */
110 root 1.20 void
111 root 1.23 enter_player_savebed (object *op)
112 elmex 1.1 {
113 root 1.63 object *tmp = object::create ();
114 root 1.20 EXIT_PATH (tmp) = op->contr->savebed_map;
115     EXIT_X (tmp) = op->contr->bed_x;
116     EXIT_Y (tmp) = op->contr->bed_y;
117 root 1.62 op->enter_exit (tmp);
118 root 1.41 tmp->destroy ();
119 elmex 1.1 }
120    
121     /*
122 root 1.62 * enter_map(): Moves the player and pets from current map (if any) to
123 elmex 1.1 * new map. map, x, y must be set. map is the map we are moving the
124     * player to - it could be the map he just came from if the load failed for
125     * whatever reason. If default map coordinates are to be used, then
126     * the function that calls this should figure them out.
127     */
128 root 1.62 void
129     object::enter_map (maptile *newmap, int x, int y)
130 root 1.20 {
131 root 1.72 if (destroyed () || !newmap || newmap->in_memory != MAP_IN_MEMORY)
132 root 1.69 return;
133    
134 root 1.20 if (out_of_map (newmap, x, y))
135     {
136 root 1.62 LOG (llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", &newmap->path, x, y);
137 root 1.58 x = newmap->enter_x;
138     y = newmap->enter_y;
139 root 1.20 if (out_of_map (newmap, x, y))
140     {
141     LOG (llevError, "enter_map: map %s provides invalid default enter location (%d, %d) > (%d, %d)\n",
142 root 1.62 &newmap->path, x, y, newmap->width, newmap->height);
143     new_draw_info (NDI_UNIQUE, 0, this, "The exit is closed");
144 root 1.20 return;
145     }
146     }
147 root 1.31
148 root 1.78 if (contr && map != newmap && map)
149 root 1.65 if (INVOKE_MAP (LEAVE, map, ARG_PLAYER (contr)))
150     return;
151    
152 root 1.82 // remove, so stupid ob_locked does not trigger a failure
153 root 1.65 remove ();
154    
155 root 1.20 /* try to find a spot for the player */
156 root 1.62 if (ob_blocked (this, newmap, x, y))
157 root 1.20 { /* First choice blocked */
158     /* We try to find a spot for the player, starting closest in.
159     * We could use find_first_free_spot, but that doesn't randomize it at all,
160     * So for example, if the north space is free, you would always end up there even
161     * if other spaces around are available.
162     * Note that for the second and third calls, we could start at a position other
163     * than one, but then we could end up on the other side of walls and so forth.
164     */
165 root 1.62 int i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE1 + 1);
166 root 1.23
167 root 1.20 if (i == -1)
168     {
169 root 1.62 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE2 + 1);
170 root 1.20 if (i == -1)
171 root 1.62 i = find_free_spot (this, newmap, x, y, 1, SIZEOFFREE);
172 root 1.20 }
173 root 1.31
174 root 1.20 if (i != -1)
175     {
176     x += freearr_x[i];
177     y += freearr_y[i];
178     }
179     else
180 root 1.62 /* not much we can do in this case. */
181     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);
182     }
183 elmex 1.1
184 root 1.78 if (contr && map != newmap)
185 root 1.69 {
186     if (INVOKE_PLAYER (MAP_CHANGE, contr, ARG_MAP (newmap), ARG_INT (x), ARG_INT (y)))
187     return;
188 root 1.31
189 root 1.69 if (INVOKE_MAP (ENTER, newmap, ARG_PLAYER (contr), ARG_INT (x), ARG_INT (y)))
190     return;
191     }
192 root 1.20
193 root 1.62 this->x = x;
194     this->y = y;
195     map = newmap;
196 root 1.20
197 root 1.62 insert_ob_in_map (this, map, 0, INS_NO_WALK_ON);
198 root 1.20
199 root 1.82 enemy = 0;
200 root 1.20
201 root 1.62 if (contr)
202 root 1.20 {
203 root 1.70 contr->maplevel = newmap->path;
204 root 1.62 contr->count = 0;
205 root 1.20 }
206    
207     /* Update any golems */
208 root 1.62 if (type == PLAYER && contr->ranges[range_golem])
209 root 1.20 {
210 root 1.86 int i = find_free_spot (contr->ranges[range_golem], newmap, x, y, 1, SIZEOFFREE);
211 root 1.23
212 root 1.86 if (i < 0)
213 root 1.20 {
214 root 1.62 contr->ranges[range_golem]->destroy ();
215     contr->ranges[range_golem] = 0;
216 root 1.20 }
217     else
218     {
219 root 1.86 newmap->insert (contr->ranges[range_golem], x + freearr_x[i], y + freearr_y[i]);
220 root 1.31
221 root 1.62 contr->ranges[range_golem]->direction =
222     find_dir_2 (x - contr->ranges[range_golem]->x, y - contr->ranges[range_golem]->y);
223 root 1.14 }
224 elmex 1.1 }
225 root 1.31
226 root 1.20 /* since the players map is already loaded, we don't need to worry
227     * about pending objects.
228     */
229     remove_all_pets (newmap);
230 elmex 1.1 }
231    
232     /* process_players1 and process_players2 do all the player related stuff.
233     * I moved it out of process events and process_map. This was to some
234     * extent for debugging as well as to get a better idea of the time used
235     * by the various functions. process_players1() does the processing before
236     * objects have been updated, process_players2() does the processing that
237     * is needed after the players have been updated.
238     */
239 root 1.46 static void
240     process_players1 ()
241 elmex 1.1 {
242 root 1.20 /* Basically, we keep looping until all the players have done their actions. */
243 root 1.94 for (int flag = 1; flag != 0;)
244 root 1.20 {
245     flag = 0;
246 root 1.56 for_all_players (pl)
247 root 1.20 {
248 root 1.56 pl->refcnt_chk ();
249 elmex 1.1
250 root 1.81 if (!pl->ob || !pl->ns || !pl->ob->active)
251 root 1.20 continue;
252    
253 root 1.89 if (pl->ob->speed_left > 0 && pl->ns)
254 root 1.56 if (handle_newcs_player (pl->ob))
255     flag = 1;
256 root 1.20
257     /* If the player is not actively playing, don't make a
258     * backup save - nothing to save anyway. Plus, the
259     * map may not longer be valid. This can happen when the
260     * player quits - they exist for purposes of tracking on the map,
261     * but don't actually reside on any actual map.
262     */
263     if (QUERY_FLAG (pl->ob, FLAG_REMOVED))
264     continue;
265     } /* end of for loop for all the players */
266     } /* for flag */
267 root 1.46
268 root 1.55 for_all_players (pl)
269 root 1.20 {
270 root 1.81 if (!pl->ob || !pl->ns || !pl->ob->active)
271 root 1.56 continue;
272    
273 root 1.46 if (settings.casting_time)
274 root 1.20 {
275     if (pl->ob->casting_time > 0)
276     {
277     pl->ob->casting_time--;
278     pl->ob->start_holding = 1;
279 root 1.14 }
280 root 1.46
281 root 1.20 /* set spell_state so we can update the range in stats field */
282     if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1))
283 root 1.46 pl->ob->start_holding = 0;
284 root 1.14 }
285 root 1.46
286 root 1.20 do_some_living (pl->ob);
287 elmex 1.1 }
288     }
289    
290 root 1.46 static void
291     process_players2 ()
292 elmex 1.1 {
293 root 1.20 /* Then check if any players should use weapon-speed instead of speed */
294 root 1.55 for_all_players (pl)
295 root 1.20 {
296     /* The code that did weapon_sp handling here was out of place -
297     * this isn't called until after the player has finished there
298     * actions, and is thus out of place. All we do here is bounds
299     * checking.
300     */
301     if (pl->has_hit)
302     {
303     if (pl->ob->speed_left > pl->weapon_sp)
304     pl->ob->speed_left = pl->weapon_sp;
305 root 1.14
306 root 1.20 /* This needs to be here - if the player is running, we need to
307     * clear this each tick, but new commands are not being received
308     * so execute_newserver_command() is never called
309     */
310     pl->has_hit = 0;
311     }
312     else if (pl->ob->speed_left > pl->ob->speed)
313     pl->ob->speed_left = pl->ob->speed;
314 elmex 1.1 }
315     }
316    
317 root 1.20 void
318 root 1.46 process_events ()
319 root 1.20 {
320 root 1.46 process_players1 ();
321 elmex 1.1
322 root 1.81 for_all_actives (op)
323 root 1.20 {
324     /* Now process op */
325     if (QUERY_FLAG (op, FLAG_FREED))
326     {
327     LOG (llevError, "BUG: process_events(): Free object on list\n");
328 root 1.59 op->set_speed (0);
329 root 1.20 continue;
330     }
331    
332     /* I've seen occasional crashes due to this - the object is removed,
333     * and thus the map it points to (last map it was on) may be bogus
334     * The real bug is to try to find out the cause of this - someone
335     * is probably calling remove_ob without either an insert_ob or
336     * free_object afterwards, leaving an object dangling. But I'd
337     * rather log this and continue on instead of crashing.
338     * Don't remove players - when a player quits, the object is in
339     * sort of a limbo, of removed, but something we want to keep
340     * around.
341     */
342     if (QUERY_FLAG (op, FLAG_REMOVED) && op->type != PLAYER && op->map && op->map->in_memory != MAP_IN_MEMORY)
343     {
344     LOG (llevError, "BUG: process_events(): Removed object on list\n");
345 root 1.36 char *dump = dump_object (op);
346     LOG (llevError, dump);
347     free (dump);
348 root 1.41 op->destroy ();
349 root 1.20 continue;
350 root 1.14 }
351    
352 elmex 1.66 if (!op->has_active_speed ())
353 root 1.20 {
354 elmex 1.66 LOG (llevError, "BUG: process_events(): Object %s has no speed (%f), "
355     "but is on active list\n", op->debug_desc (), op->speed);
356 root 1.59 op->set_speed (0);
357 root 1.20 continue;
358 root 1.14 }
359    
360 root 1.46 if (op->map == NULL && op->env == NULL && op->name && op->type != MAP)
361 root 1.20 {
362 root 1.46 LOG (llevError, "BUG: process_events(): Object without map or "
363     "inventory is on active list: %s (%d)\n", &op->name, op->count);
364 root 1.59 op->set_speed (0);
365 root 1.20 continue;
366 root 1.14 }
367    
368 root 1.46 /* Animate the object. Bug or feature that anim_speed
369 root 1.20 * is based on ticks, and not the creatures speed?
370     */
371     if (op->anim_speed && op->last_anim >= op->anim_speed)
372     {
373 root 1.90 animate_object (op, op->type == PLAYER ? op->facing : op->direction);
374 root 1.14
375 root 1.20 op->last_anim = 1;
376     }
377     else
378     op->last_anim++;
379 elmex 1.1
380 root 1.20 if (op->speed_left > 0)
381     {
382 elmex 1.1 #if 0
383 root 1.20 /* I've seen occasional crashes in move_symptom() with it
384     * crashing because op is removed - add some debugging to
385     * track if it is removed at this point.
386     * This unfortunately is a bit too verbose it seems - not sure
387     * why - I think what happens is a map is freed or something and
388     * some objects get 'lost' - removed never to be reclaimed.
389     * removed objects generally shouldn't exist.
390     */
391     if (QUERY_FLAG (op, FLAG_REMOVED))
392     {
393     LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null");
394 root 1.14 }
395 elmex 1.1 #endif
396 root 1.20 --op->speed_left;
397     process_object (op);
398 root 1.28
399     if (op->destroyed ())
400 root 1.20 continue;
401 root 1.14 }
402 root 1.28
403 root 1.20 if (settings.casting_time == TRUE && op->casting_time > 0)
404     op->casting_time--;
405 root 1.28
406 root 1.20 if (op->speed_left <= 0)
407     op->speed_left += FABS (op->speed);
408 elmex 1.1 }
409    
410 root 1.46 process_players2 ();
411 elmex 1.1 }
412    
413 root 1.62 /* clean up everything before exiting */
414 root 1.20 void
415 root 1.62 emergency_save ()
416 root 1.20 {
417 root 1.62 LOG (llevDebug, "emergency save begin.\n");
418 elmex 1.1
419 root 1.83 cfperl_emergency_save ();
420 root 1.62
421     LOG (llevDebug, "saving book archive.\n");
422     write_book_archive ();
423 root 1.47
424 root 1.62 LOG (llevDebug, "emergency save done.\n");
425 elmex 1.1 }
426    
427 root 1.79 // send all clients some informational text
428     static void
429     cleanup_inform (const char *cause, bool make_core)
430     {
431 root 1.83 int flags = NDI_UNIQUE | NDI_ALL | (make_core ? NDI_RED : NDI_GREEN);
432    
433     new_draw_info_format (flags, 0, 0, "The server will now shutdown.\n");
434 root 1.86 new_draw_info_format (flags, 0, 0, "Cause for this shutdown: %s\n", cause);
435 root 1.79
436     if (make_core)
437 root 1.86 new_draw_info_format (flags, 0, 0, "This is considered a crash, but all maps and players have been saved.\n");
438 root 1.79 else
439 root 1.88 new_draw_info_format (flags, 0, 0, "This is considered to be a clean shutdown, and all maps and players will be saved now.\n");
440 root 1.79
441 root 1.83 new_draw_info_format (flags, 0, 0, "%s\n", CLEANUP_MESSAGE);
442 root 1.79
443     flush_sockets ();
444     }
445    
446 elmex 1.1 /* clean up everything before exiting */
447 root 1.20 void
448 root 1.79 cleanup (const char *cause, bool make_core)
449 elmex 1.1 {
450 root 1.84 if (make_core)
451 root 1.85 fork_abort (cause);
452 root 1.84
453 root 1.79 LOG (llevError, "cleanup cause: %s\n", cause);
454    
455     if (!make_core)
456     cleanup_inform (cause, make_core);
457    
458 root 1.62 LOG (llevDebug, "cleanup begin.\n");
459    
460 root 1.65 if (init_done && !in_cleanup)
461 root 1.67 {
462     in_cleanup = true;
463     emergency_save ();
464     }
465     else
466     in_cleanup = true;
467 root 1.29
468 root 1.62 LOG (llevDebug, "running cleanup handlers.\n");
469     INVOKE_GLOBAL (CLEANUP);
470 root 1.23
471 root 1.62 LOG (llevDebug, "cleanup done.\n");
472 root 1.25
473 root 1.49 if (make_core)
474 root 1.79 {
475     cleanup_inform (cause, make_core);
476 root 1.91 cfperl_cleanup (make_core);
477 root 1.84 _exit (1);
478 root 1.79 }
479 root 1.49 else
480 root 1.88 {
481     new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_GREEN, 0, 0, "Maps and players successfully saved, exiting.\n");
482     new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_GREEN, 0, 0, "And again: " CLEANUP_MESSAGE "\n");
483     flush_sockets ();
484 root 1.91 cfperl_cleanup (make_core);
485 root 1.88 _exit (0);
486     }
487 elmex 1.1 }
488    
489 root 1.20 int
490     forbid_play (void)
491 elmex 1.1 {
492     #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
493 root 1.20 char buf[MAX_BUF], day[MAX_BUF];
494     FILE *fp;
495     time_t clock;
496     struct tm *tm;
497     int i, start, stop, forbit = 0, comp;
498    
499     clock = time (NULL);
500     tm = (struct tm *) localtime (&clock);
501 root 1.14
502 root 1.20 sprintf (buf, "%s/%s", settings.confdir, PERM_FILE);
503     if ((fp = open_and_uncompress (buf, 0, &comp)) == NULL)
504     return 0;
505    
506     while (fgets (buf, MAX_BUF, fp))
507     {
508     if (buf[0] == '#')
509     continue;
510 root 1.73
511 root 1.20 if (!strncmp (buf, "msg", 3))
512     {
513     if (forbit)
514     while (fgets (buf, MAX_BUF, fp)) /* print message */
515     fputs (buf, logfile);
516     break;
517     }
518     else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3)
519     {
520     LOG (llevDebug, "Warning: Incomplete line in permission file ignored.\n");
521     continue;
522 root 1.14 }
523    
524 root 1.20 for (i = 0; i < 7; i++)
525     {
526     if (!strncmp (buf, days[i], 3) && (tm->tm_wday == i) && (tm->tm_hour >= start) && (tm->tm_hour < stop))
527     forbit = 1;
528 root 1.14 }
529 elmex 1.1 }
530    
531 root 1.20 close_and_delete (fp, comp);
532 elmex 1.1
533 root 1.20 return forbit;
534 elmex 1.1 #else
535 root 1.20 return 0;
536 elmex 1.1 #endif
537     }
538    
539     /*
540 root 1.73 * do_specials() is a collection of functions to call from time to time.
541 elmex 1.1 * Modified 2000-1-14 MSW to use the global pticks count to determine how
542     * often to do things. This will allow us to spred them out more often.
543     * I use prime numbers for the factor count - in that way, it is less likely
544     * these actions will fall on the same tick (compared to say using 500/2500/15000
545     * which would mean on that 15,000 tick count a whole bunch of stuff gets
546     * done). Of course, there can still be times where multiple specials are
547     * done on the same tick, but that will happen very infrequently
548     *
549     * I also think this code makes it easier to see how often we really are
550     * doing the various things.
551     */
552    
553     extern unsigned long todtick;
554    
555 root 1.20 void
556     do_specials (void)
557     {
558     if (!(pticks % PTICKS_PER_CLOCK))
559     tick_the_clock ();
560 elmex 1.1
561 root 1.20 if (!(pticks % 7))
562     shstr::gc ();
563 root 1.18
564 root 1.20 if (!(pticks % 2503))
565     fix_weight (); /* Hack to fix weightproblems caused by bugs */
566 elmex 1.1
567 root 1.20 if (!(pticks % 5003))
568     write_book_archive ();
569 elmex 1.1
570 root 1.20 if (!(pticks % 5009))
571     clean_friendly_list ();
572 elmex 1.1
573 root 1.20 if (!(pticks % 5011))
574     obsolete_parties ();
575 elmex 1.1
576 root 1.20 if (!(pticks % 12503))
577     fix_luck ();
578 elmex 1.1 }
579    
580 root 1.20 void
581     server_tick ()
582 root 1.2 {
583 root 1.44 // first do the user visible stuff
584 root 1.20 doeric_server ();
585 root 1.12 INVOKE_GLOBAL (CLOCK);
586 root 1.46 process_events (); /* "do" something with objects with speed */
587 root 1.20 flush_sockets ();
588 root 1.44
589     // then do some bookkeeping, should not really be here
590 root 1.20 do_specials (); /* Routines called from time to time. */
591 root 1.56 attachable::check_mortals ();
592 root 1.5
593     ++pticks;
594 root 1.2 }
595    
596 root 1.87 #if 0
597     // used fro benchmarking (x86/amd64-specific)
598     typedef unsigned long tval;
599     typedef unsigned long long stamp64;
600    
601     extern inline tval
602     stamp (void)
603     {
604     tval tsc;
605     asm volatile ("rdtsc":"=a" (tsc)::"edx");
606    
607     return tsc;
608     }
609    
610     extern inline tval
611     measure (tval t)
612     {
613     tval tsc;
614     asm volatile ("rdtsc":"=a" (tsc)::"edx");
615    
616     if (tsc > t)
617     return tsc - t;
618     else
619     return t - tsc;
620     }
621    
622     int
623     main (int argc, char **argv)
624     {
625     rand_gen rg(0);
626     tval fastest = 0x7fffffff;
627     for (int loop = 10000; loop--; )
628     {
629     tval s = stamp ();
630     volatile int i = rg.get_int(25);
631     fastest = min (fastest, measure (s));
632     }
633    
634     //printf ("fastest %d\n", fastest);
635     for (int i = 0; i < 1024*1024*3; ++i)
636     {
637     char c = rg.get_int (256);
638     write (2, &c, 1);
639     }
640     }
641    
642     #else
643    
644     // normal main
645 root 1.20 int
646     main (int argc, char **argv)
647 elmex 1.1 {
648 root 1.6 settings.argc = argc;
649     settings.argv = argv;
650    
651     init (argc, argv);
652    
653 root 1.10 initPlugins ();
654 elmex 1.1
655 root 1.6 for (;;)
656     cfperl_main ();
657 root 1.64 }
658 root 1.87 #endif
659 root 1.4