ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/main.C
Revision: 1.100
Committed: Mon Apr 30 04:25:30 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.99: +1 -1 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

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.99 if (type == PLAYER)
209 root 1.100 if (object *golem = contr->golem)
210 root 1.99 {
211     int i = find_free_spot (golem, newmap, x, y, 1, SIZEOFFREE);
212    
213     if (i < 0)
214     golem->destroy ();
215     else
216     {
217     newmap->insert (golem, x + freearr_x[i], y + freearr_y[i]);
218     golem->direction = find_dir_2 (x - golem->x, y - golem->y);
219     }
220     }
221 root 1.31
222 root 1.20 /* since the players map is already loaded, we don't need to worry
223     * about pending objects.
224     */
225     remove_all_pets (newmap);
226 elmex 1.1 }
227    
228     /* process_players1 and process_players2 do all the player related stuff.
229     * I moved it out of process events and process_map. This was to some
230     * extent for debugging as well as to get a better idea of the time used
231     * by the various functions. process_players1() does the processing before
232     * objects have been updated, process_players2() does the processing that
233     * is needed after the players have been updated.
234     */
235 root 1.46 static void
236     process_players1 ()
237 elmex 1.1 {
238 root 1.20 /* Basically, we keep looping until all the players have done their actions. */
239 root 1.94 for (int flag = 1; flag != 0;)
240 root 1.20 {
241     flag = 0;
242 root 1.56 for_all_players (pl)
243 root 1.20 {
244 root 1.56 pl->refcnt_chk ();
245 elmex 1.1
246 root 1.81 if (!pl->ob || !pl->ns || !pl->ob->active)
247 root 1.20 continue;
248    
249 root 1.89 if (pl->ob->speed_left > 0 && pl->ns)
250 root 1.56 if (handle_newcs_player (pl->ob))
251     flag = 1;
252 root 1.20
253     /* If the player is not actively playing, don't make a
254     * backup save - nothing to save anyway. Plus, the
255     * map may not longer be valid. This can happen when the
256     * player quits - they exist for purposes of tracking on the map,
257     * but don't actually reside on any actual map.
258     */
259     if (QUERY_FLAG (pl->ob, FLAG_REMOVED))
260     continue;
261     } /* end of for loop for all the players */
262     } /* for flag */
263 root 1.46
264 root 1.55 for_all_players (pl)
265 root 1.20 {
266 root 1.81 if (!pl->ob || !pl->ns || !pl->ob->active)
267 root 1.56 continue;
268    
269 root 1.46 if (settings.casting_time)
270 root 1.20 {
271     if (pl->ob->casting_time > 0)
272     {
273     pl->ob->casting_time--;
274     pl->ob->start_holding = 1;
275 root 1.14 }
276 root 1.46
277 root 1.20 /* set spell_state so we can update the range in stats field */
278     if ((pl->ob->casting_time == 0) && (pl->ob->start_holding == 1))
279 root 1.46 pl->ob->start_holding = 0;
280 root 1.14 }
281 root 1.46
282 root 1.20 do_some_living (pl->ob);
283 elmex 1.1 }
284     }
285    
286 root 1.46 static void
287     process_players2 ()
288 elmex 1.1 {
289 root 1.20 /* Then check if any players should use weapon-speed instead of speed */
290 root 1.55 for_all_players (pl)
291 root 1.20 {
292     /* The code that did weapon_sp handling here was out of place -
293     * this isn't called until after the player has finished there
294     * actions, and is thus out of place. All we do here is bounds
295     * checking.
296     */
297     if (pl->has_hit)
298     {
299     if (pl->ob->speed_left > pl->weapon_sp)
300     pl->ob->speed_left = pl->weapon_sp;
301 root 1.14
302 root 1.20 /* This needs to be here - if the player is running, we need to
303     * clear this each tick, but new commands are not being received
304     * so execute_newserver_command() is never called
305     */
306     pl->has_hit = 0;
307     }
308     else if (pl->ob->speed_left > pl->ob->speed)
309     pl->ob->speed_left = pl->ob->speed;
310 elmex 1.1 }
311     }
312    
313 root 1.20 void
314 root 1.46 process_events ()
315 root 1.20 {
316 root 1.46 process_players1 ();
317 elmex 1.1
318 root 1.81 for_all_actives (op)
319 root 1.20 {
320     /* Now process op */
321     if (QUERY_FLAG (op, FLAG_FREED))
322     {
323     LOG (llevError, "BUG: process_events(): Free object on list\n");
324 root 1.59 op->set_speed (0);
325 root 1.20 continue;
326     }
327    
328 elmex 1.66 if (!op->has_active_speed ())
329 root 1.20 {
330 elmex 1.66 LOG (llevError, "BUG: process_events(): Object %s has no speed (%f), "
331     "but is on active list\n", op->debug_desc (), op->speed);
332 root 1.59 op->set_speed (0);
333 root 1.20 continue;
334 root 1.14 }
335    
336 root 1.96 if (op->flag [FLAG_REMOVED])
337 root 1.20 {
338 root 1.96 LOG (llevError, "BUG: process_events(): removed object is on active list: %s\n",
339     op->debug_desc ());
340 root 1.59 op->set_speed (0);
341 root 1.20 continue;
342 root 1.14 }
343    
344 root 1.46 /* Animate the object. Bug or feature that anim_speed
345 root 1.20 * is based on ticks, and not the creatures speed?
346     */
347     if (op->anim_speed && op->last_anim >= op->anim_speed)
348     {
349 root 1.90 animate_object (op, op->type == PLAYER ? op->facing : op->direction);
350 root 1.14
351 root 1.20 op->last_anim = 1;
352     }
353     else
354     op->last_anim++;
355 elmex 1.1
356 root 1.20 if (op->speed_left > 0)
357     {
358 elmex 1.1 #if 0
359 root 1.20 /* I've seen occasional crashes in move_symptom() with it
360     * crashing because op is removed - add some debugging to
361     * track if it is removed at this point.
362     * This unfortunately is a bit too verbose it seems - not sure
363     * why - I think what happens is a map is freed or something and
364     * some objects get 'lost' - removed never to be reclaimed.
365     * removed objects generally shouldn't exist.
366     */
367     if (QUERY_FLAG (op, FLAG_REMOVED))
368     {
369     LOG (llevDebug, "process_events: calling process_object with removed object %s\n", op->name ? op->name : "null");
370 root 1.14 }
371 elmex 1.1 #endif
372 root 1.20 --op->speed_left;
373     process_object (op);
374 root 1.28
375     if (op->destroyed ())
376 root 1.20 continue;
377 root 1.14 }
378 root 1.28
379 root 1.20 if (settings.casting_time == TRUE && op->casting_time > 0)
380     op->casting_time--;
381 root 1.28
382 root 1.20 if (op->speed_left <= 0)
383     op->speed_left += FABS (op->speed);
384 elmex 1.1 }
385    
386 root 1.46 process_players2 ();
387 elmex 1.1 }
388    
389 root 1.62 /* clean up everything before exiting */
390 root 1.20 void
391 root 1.62 emergency_save ()
392 root 1.20 {
393 root 1.62 LOG (llevDebug, "emergency save begin.\n");
394 elmex 1.1
395 root 1.83 cfperl_emergency_save ();
396 root 1.62
397     LOG (llevDebug, "saving book archive.\n");
398     write_book_archive ();
399 root 1.47
400 root 1.62 LOG (llevDebug, "emergency save done.\n");
401 elmex 1.1 }
402    
403 root 1.79 // send all clients some informational text
404     static void
405     cleanup_inform (const char *cause, bool make_core)
406     {
407 root 1.83 int flags = NDI_UNIQUE | NDI_ALL | (make_core ? NDI_RED : NDI_GREEN);
408    
409     new_draw_info_format (flags, 0, 0, "The server will now shutdown.\n");
410 root 1.86 new_draw_info_format (flags, 0, 0, "Cause for this shutdown: %s\n", cause);
411 root 1.79
412     if (make_core)
413 root 1.86 new_draw_info_format (flags, 0, 0, "This is considered a crash, but all maps and players have been saved.\n");
414 root 1.79 else
415 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");
416 root 1.79
417 root 1.83 new_draw_info_format (flags, 0, 0, "%s\n", CLEANUP_MESSAGE);
418 root 1.79
419     flush_sockets ();
420     }
421    
422 elmex 1.1 /* clean up everything before exiting */
423 root 1.20 void
424 root 1.79 cleanup (const char *cause, bool make_core)
425 elmex 1.1 {
426 root 1.84 if (make_core)
427 root 1.85 fork_abort (cause);
428 root 1.84
429 root 1.79 LOG (llevError, "cleanup cause: %s\n", cause);
430    
431     if (!make_core)
432     cleanup_inform (cause, make_core);
433    
434 root 1.62 LOG (llevDebug, "cleanup begin.\n");
435    
436 root 1.65 if (init_done && !in_cleanup)
437 root 1.67 {
438     in_cleanup = true;
439     emergency_save ();
440     }
441     else
442     in_cleanup = true;
443 root 1.29
444 root 1.62 LOG (llevDebug, "running cleanup handlers.\n");
445     INVOKE_GLOBAL (CLEANUP);
446 root 1.23
447 root 1.62 LOG (llevDebug, "cleanup done.\n");
448 root 1.25
449 root 1.49 if (make_core)
450 root 1.79 {
451     cleanup_inform (cause, make_core);
452 root 1.91 cfperl_cleanup (make_core);
453 root 1.84 _exit (1);
454 root 1.79 }
455 root 1.49 else
456 root 1.88 {
457     new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_GREEN, 0, 0, "Maps and players successfully saved, exiting.\n");
458     new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_GREEN, 0, 0, "And again: " CLEANUP_MESSAGE "\n");
459     flush_sockets ();
460 root 1.91 cfperl_cleanup (make_core);
461 root 1.88 _exit (0);
462     }
463 elmex 1.1 }
464    
465 root 1.20 int
466     forbid_play (void)
467 elmex 1.1 {
468     #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
469 root 1.20 char buf[MAX_BUF], day[MAX_BUF];
470     FILE *fp;
471     time_t clock;
472     struct tm *tm;
473     int i, start, stop, forbit = 0, comp;
474    
475     clock = time (NULL);
476     tm = (struct tm *) localtime (&clock);
477 root 1.14
478 root 1.20 sprintf (buf, "%s/%s", settings.confdir, PERM_FILE);
479     if ((fp = open_and_uncompress (buf, 0, &comp)) == NULL)
480     return 0;
481    
482     while (fgets (buf, MAX_BUF, fp))
483     {
484     if (buf[0] == '#')
485     continue;
486 root 1.73
487 root 1.20 if (!strncmp (buf, "msg", 3))
488     {
489     if (forbit)
490     while (fgets (buf, MAX_BUF, fp)) /* print message */
491     fputs (buf, logfile);
492     break;
493     }
494     else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3)
495     {
496     LOG (llevDebug, "Warning: Incomplete line in permission file ignored.\n");
497     continue;
498 root 1.14 }
499    
500 root 1.20 for (i = 0; i < 7; i++)
501     {
502     if (!strncmp (buf, days[i], 3) && (tm->tm_wday == i) && (tm->tm_hour >= start) && (tm->tm_hour < stop))
503     forbit = 1;
504 root 1.14 }
505 elmex 1.1 }
506    
507 root 1.20 close_and_delete (fp, comp);
508 elmex 1.1
509 root 1.20 return forbit;
510 elmex 1.1 #else
511 root 1.20 return 0;
512 elmex 1.1 #endif
513     }
514    
515     /*
516 root 1.73 * do_specials() is a collection of functions to call from time to time.
517 elmex 1.1 * Modified 2000-1-14 MSW to use the global pticks count to determine how
518     * often to do things. This will allow us to spred them out more often.
519     * I use prime numbers for the factor count - in that way, it is less likely
520     * these actions will fall on the same tick (compared to say using 500/2500/15000
521     * which would mean on that 15,000 tick count a whole bunch of stuff gets
522     * done). Of course, there can still be times where multiple specials are
523     * done on the same tick, but that will happen very infrequently
524     *
525     * I also think this code makes it easier to see how often we really are
526     * doing the various things.
527     */
528 root 1.20 void
529     do_specials (void)
530     {
531 root 1.95 if (!(pticks % TICKS_PER_HOUR))
532     adjust_daylight ();
533 elmex 1.1
534 root 1.20 if (!(pticks % 7))
535     shstr::gc ();
536 root 1.18
537 root 1.20 if (!(pticks % 2503))
538     fix_weight (); /* Hack to fix weightproblems caused by bugs */
539 elmex 1.1
540 root 1.20 if (!(pticks % 5003))
541     write_book_archive ();
542 elmex 1.1
543 root 1.20 if (!(pticks % 5009))
544     clean_friendly_list ();
545 elmex 1.1
546 root 1.20 if (!(pticks % 5011))
547     obsolete_parties ();
548 elmex 1.1
549 root 1.20 if (!(pticks % 12503))
550     fix_luck ();
551 elmex 1.1 }
552    
553 root 1.20 void
554     server_tick ()
555 root 1.2 {
556 root 1.44 // first do the user visible stuff
557 root 1.20 doeric_server ();
558 root 1.12 INVOKE_GLOBAL (CLOCK);
559 root 1.46 process_events (); /* "do" something with objects with speed */
560 root 1.20 flush_sockets ();
561 root 1.44
562     // then do some bookkeeping, should not really be here
563 root 1.20 do_specials (); /* Routines called from time to time. */
564 root 1.56 attachable::check_mortals ();
565 root 1.5
566     ++pticks;
567 root 1.2 }
568    
569 root 1.87 #if 0
570     // used fro benchmarking (x86/amd64-specific)
571     typedef unsigned long tval;
572     typedef unsigned long long stamp64;
573    
574     extern inline tval
575     stamp (void)
576     {
577     tval tsc;
578     asm volatile ("rdtsc":"=a" (tsc)::"edx");
579    
580     return tsc;
581     }
582    
583     extern inline tval
584     measure (tval t)
585     {
586     tval tsc;
587     asm volatile ("rdtsc":"=a" (tsc)::"edx");
588    
589     if (tsc > t)
590     return tsc - t;
591     else
592     return t - tsc;
593     }
594    
595     int
596     main (int argc, char **argv)
597     {
598     rand_gen rg(0);
599     tval fastest = 0x7fffffff;
600     for (int loop = 10000; loop--; )
601     {
602     tval s = stamp ();
603     volatile int i = rg.get_int(25);
604     fastest = min (fastest, measure (s));
605     }
606    
607     //printf ("fastest %d\n", fastest);
608     for (int i = 0; i < 1024*1024*3; ++i)
609     {
610     char c = rg.get_int (256);
611     write (2, &c, 1);
612     }
613     }
614    
615     #else
616    
617     // normal main
618 root 1.20 int
619     main (int argc, char **argv)
620 elmex 1.1 {
621 root 1.6 settings.argc = argc;
622     settings.argv = argv;
623    
624     init (argc, argv);
625    
626 root 1.10 initPlugins ();
627 elmex 1.1
628 root 1.6 for (;;)
629     cfperl_main ();
630 root 1.64 }
631 root 1.87 #endif
632 root 1.4