ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/init.C
Revision: 1.15
Committed: Mon Oct 2 15:28:36 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.14: +1 -44 lines
Log Message:
nuke metaserver code

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5     Copyright (C) 1992 Frank Tore Johansen
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 root 1.13 The authors can be reached via e-mail at <crossfire@schmorp.de>
22 elmex 1.1 */
23    
24     #include <global.h>
25     #include <material.h>
26     #include <loader.h>
27     #ifndef __CEXTRACT__
28 root 1.9 # include <sproto.h>
29 elmex 1.1 #endif
30    
31     /* global weathermap */
32     weathermap_t **weathermap;
33    
34 root 1.9 void
35     set_logfile (char *val)
36     {
37     settings.logfilename = val;
38     }
39    
40     void
41     call_version (void)
42     {
43     version (NULL);
44     exit (0);
45     }
46    
47     void
48     showscores (void)
49     {
50     display_high_score (NULL, 9999, NULL);
51     exit (0);
52     }
53    
54     void
55     set_debug (void)
56     {
57     settings.debug = llevDebug;
58     }
59    
60     void
61     unset_debug (void)
62     {
63     settings.debug = llevInfo;
64     }
65    
66     void
67     set_mondebug (void)
68     {
69     settings.debug = llevMonster;
70     }
71    
72     void
73     set_dumpmon1 (void)
74     {
75     settings.dumpvalues = 1;
76     }
77    
78     void
79     set_dumpmon2 (void)
80     {
81     settings.dumpvalues = 2;
82     }
83    
84     void
85     set_dumpmon3 (void)
86     {
87     settings.dumpvalues = 3;
88     }
89    
90     void
91     set_dumpmon4 (void)
92     {
93     settings.dumpvalues = 4;
94     }
95    
96     void
97     set_dumpmon5 (void)
98     {
99     settings.dumpvalues = 5;
100     }
101    
102     void
103     set_dumpmon6 (void)
104     {
105     settings.dumpvalues = 6;
106     }
107    
108     void
109     set_dumpmon7 (void)
110     {
111     settings.dumpvalues = 7;
112     }
113    
114     void
115     set_dumpmon8 (void)
116     {
117     settings.dumpvalues = 8;
118     }
119    
120     void
121     set_dumpmon9 (void)
122     {
123     settings.dumpvalues = 9;
124     }
125    
126     void
127     set_dumpmont (char *name)
128     {
129     settings.dumpvalues = 10;
130     settings.dumparg = name;
131     }
132    
133     void
134     set_daemon (void)
135     {
136     settings.daemonmode = 1;
137     }
138    
139     void
140     set_datadir (char *path)
141     {
142     settings.datadir = path;
143     }
144    
145     void
146     set_confdir (char *path)
147     {
148     settings.confdir = path;
149     }
150    
151     void
152     set_localdir (char *path)
153     {
154     settings.localdir = path;
155     }
156    
157     void
158     set_mapdir (char *path)
159     {
160     settings.mapdir = path;
161     }
162    
163     void
164     set_archetypes (char *path)
165     {
166     settings.archetypes = path;
167     }
168    
169     void
170     set_regions (char *path)
171     {
172     settings.regions = path;
173     }
174    
175     void
176     set_treasures (char *path)
177     {
178     settings.treasures = path;
179     }
180    
181     void
182     set_uniquedir (char *path)
183     {
184     settings.uniquedir = path;
185     }
186    
187     void
188     set_templatedir (char *path)
189     {
190     settings.templatedir = path;
191     }
192    
193     void
194     set_playerdir (char *path)
195     {
196     settings.playerdir = path;
197     }
198    
199     void
200     set_tmpdir (char *path)
201     {
202     settings.tmpdir = path;
203     }
204    
205     void
206     showscoresparm (char *data)
207     {
208     display_high_score (NULL, 9999, data);
209     exit (0);
210     }
211    
212     void
213     set_csport (char *val)
214     {
215     settings.csport = atoi (val);
216     #ifndef WIN32 /* ***win32: set_csport: we remove csport error secure check here, do this later */
217     if (settings.csport <= 0 || settings.csport > 32765 || (settings.csport < 1024 && getuid () != 0))
218     {
219     LOG (llevError, "%d is an invalid csport number.\n", settings.csport);
220     exit (1);
221 elmex 1.1 }
222     #endif /* win32 */
223     }
224    
225     /* Most of this is shamelessly stolen from XSysStats. But since that is
226     * also my program, no problem.
227     */
228 root 1.9 struct Command_Line_Options
229     {
230     const char *cmd_option; /* how it is called on the command line */
231     uint8 num_args; /* Number or args it takes */
232     uint8 pass; /* What pass this should be processed on. */
233     void (*func) (); /* function to call when we match this.
234     * if num_args is true, than that gets passed
235     * to the function, otherwise nothing is passed
236     */
237 elmex 1.1 };
238    
239     /* The way this system works is pretty simple - parse_args takes
240     * the options passed to the program and a pass number. If an option
241     * matches both in name and in pass (and we have enough options),
242     * we call the associated function. This makes writing a multi
243     * pass system very easy, and it is very easy to add in new options.
244     */
245     struct Command_Line_Options options[] = {
246    
247     /* Pass 1 functions - STuff that can/should be called before we actually
248     * initialize any data.
249     */
250 root 1.9 {"-h", 0, 1, help},
251    
252 elmex 1.1 /* Honor -help also, since it is somewhat common */
253 root 1.9 {"-help", 0, 1, help},
254     {"-v", 0, 1, call_version},
255     {"-d", 0, 1, set_debug},
256     {"+d", 0, 1, unset_debug},
257     {"-mon", 0, 1, set_mondebug},
258     {"-data", 1, 1, (void (*)()) set_datadir},
259     {"-conf", 1, 1, (void (*)()) set_confdir},
260     {"-local", 1, 1, (void (*)()) set_localdir},
261     {"-maps", 1, 1, (void (*)()) set_mapdir},
262     {"-arch", 1, 1, (void (*)()) set_archetypes},
263     {"-regions", 1, 1, (void (*)()) set_regions},
264     {"-playerdir", 1, 1, (void (*)()) set_playerdir},
265     {"-treasures", 1, 1, (void (*)()) set_treasures},
266     {"-uniquedir", 1, 1, (void (*)()) set_uniquedir},
267     {"-templatedir", 1, 1, (void (*)()) set_templatedir},
268     {"-tmpdir", 1, 1, (void (*)()) set_tmpdir},
269     {"-log", 1, 1, (void (*)()) set_logfile},
270 elmex 1.1
271     #ifdef WIN32
272 root 1.9
273 elmex 1.1 /* Windows service stuff */
274 root 1.9 {"-regsrv", 0, 1, service_register},
275     {"-unregsrv", 0, 1, service_unregister},
276     {"-srv", 0, 1, service_handle},
277 elmex 1.1 #endif
278    
279     /* Pass 2 functions. Most of these could probably be in pass 1,
280     * as they don't require much of anything to bet set up.
281     */
282 root 1.9 {"-csport", 1, 2, (void (*)()) set_csport},
283     {"-detach", 0, 2, set_daemon},
284 elmex 1.1
285     /* Start of pass 3 information. In theory, by pass 3, all data paths
286     * and defaults should have been set up.
287     */
288 root 1.9 {"-o", 0, 3, compile_info},
289     {"-m", 0, 3, set_dumpmon1},
290     {"-m2", 0, 3, set_dumpmon2},
291     {"-m3", 0, 3, set_dumpmon3},
292     {"-m4", 0, 3, set_dumpmon4},
293     {"-m5", 0, 3, set_dumpmon5},
294     {"-m6", 0, 3, set_dumpmon6},
295     {"-m7", 0, 3, set_dumpmon7},
296     {"-m8", 0, 3, set_dumpmon8},
297     {"-m9", 0, 3, set_dumpmon9},
298     {"-mt", 1, 3, (void (*)()) set_dumpmont},
299     {"-mexp", 0, 3, dump_experience},
300     {"-s", 0, 3, showscores},
301     {"-score", 1, 3, (void (*)()) showscoresparm}
302 elmex 1.1 };
303    
304    
305     /* Note since this may be called before the library has been set up,
306     * we don't use any of crossfires built in logging functions.
307     */
308 root 1.9 static void
309     parse_args (int argc, char *argv[], int pass)
310 elmex 1.1 {
311 root 1.9 size_t i;
312     int on_arg = 1;
313 elmex 1.1
314 root 1.9 while (on_arg < argc)
315     {
316     for (i = 0; i < sizeof (options) / sizeof (struct Command_Line_Options); i++)
317     {
318     if (!strcmp (options[i].cmd_option, argv[on_arg]))
319     {
320     /* Found a matching option, but should not be processed on
321     * this pass. Just skip over it
322     */
323     if (options[i].pass != pass)
324     {
325     on_arg += options[i].num_args + 1;
326     break;
327 root 1.4 }
328 root 1.9 if (options[i].num_args)
329     {
330     if ((on_arg + options[i].num_args) >= argc)
331     {
332     fprintf (stderr, "%s requires an argument.\n", options[i].cmd_option);
333     exit (1);
334 root 1.4 }
335 root 1.9 else
336     {
337     if (options[i].num_args == 1)
338     ((void (*)(char *)) options[i].func) (argv[on_arg + 1]);
339     if (options[i].num_args == 2)
340     ((void (*)(char *, char *)) options[i].func) (argv[on_arg + 1], argv[on_arg + 2]);
341     on_arg += options[i].num_args + 1;
342 root 1.4 }
343     }
344 root 1.9 else
345     { /* takes no args */
346     options[i].func ();
347     on_arg++;
348 root 1.4 }
349 root 1.9 break;
350 root 1.4 }
351     }
352 root 1.9 if (i == sizeof (options) / sizeof (struct Command_Line_Options))
353     {
354     fprintf (stderr, "Unknown option: %s\n", argv[on_arg]);
355     usage ();
356     exit (1);
357 root 1.4 }
358 elmex 1.1 }
359     }
360    
361 root 1.7 //TODO: make this a constructor
362 root 1.9 static materialtype_t *
363     get_empty_mat (void)
364     {
365     materialtype_t *mt;
366     int i;
367    
368     mt = new materialtype_t;
369    
370     mt->name = NULL;
371     mt->description = NULL;
372     for (i = 0; i < NROFATTACKS; i++)
373     {
374     mt->save[i] = 0;
375     mt->mod[i] = 0;
376 elmex 1.1 }
377 root 1.9 mt->chance = 0;
378     mt->difficulty = 0;
379     mt->magic = 0;
380     mt->damage = 0;
381     mt->wc = 0;
382     mt->ac = 0;
383     mt->sp = 0;
384     mt->weight = 100;
385     mt->value = 100;
386     mt->next = NULL;
387     return mt;
388     }
389    
390     static void
391     load_materials (void)
392     {
393     char buf[MAX_BUF], filename[MAX_BUF], *cp, *next;
394     FILE *fp;
395     materialtype_t *mt;
396     int i, value;
397    
398     sprintf (filename, "%s/materials", settings.datadir);
399     LOG (llevDebug, "Reading material type data from %s...", filename);
400     if ((fp = fopen (filename, "r")) == NULL)
401     {
402     LOG (llevError, "Cannot open %s for reading\n", filename);
403     mt = get_empty_mat ();
404     mt->next = NULL;
405     materialt = mt;
406     return;
407 elmex 1.1 }
408 root 1.9 mt = get_empty_mat ();
409     materialt = mt;
410     while (fgets (buf, MAX_BUF, fp) != NULL)
411     {
412     if (*buf == '#')
413     continue;
414     if ((cp = strchr (buf, '\n')) != NULL)
415     *cp = '\0';
416     cp = buf;
417     while (*cp == ' ') /* Skip blanks */
418     cp++;
419     if (!strncmp (cp, "name", 4))
420     {
421     /* clean up the previous entry */
422     if (mt->next != NULL)
423     {
424     if (mt->description == NULL)
425     mt->description = mt->name;
426     mt = mt->next;
427     }
428     mt->next = get_empty_mat ();
429     mt->name = strchr (cp, ' ') + 1;
430     }
431     else if (!strncmp (cp, "description", 11))
432     {
433     mt->description = strchr (cp, ' ') + 1;
434     }
435     else if (sscanf (cp, "material %d", &value))
436     {
437     mt->material = value;
438     }
439     else if (!strncmp (cp, "saves", 5))
440     {
441     cp = strchr (cp, ' ') + 1;
442     for (i = 0; i < NROFATTACKS; i++)
443     {
444     if (cp == NULL)
445     {
446     mt->save[i] = 0;
447     continue;
448 root 1.4 }
449 root 1.9 if ((next = strchr (cp, ',')) != NULL)
450     *(next++) = '\0';
451     sscanf (cp, "%d", &value);
452     mt->save[i] = (sint8) value;
453     cp = next;
454     }
455     }
456     else if (!strncmp (cp, "mods", 4))
457     {
458     cp = strchr (cp, ' ') + 1;
459     for (i = 0; i < NROFATTACKS; i++)
460     {
461     if (cp == NULL)
462     {
463     mt->save[i] = 0;
464     continue;
465 root 1.4 }
466 root 1.9 if ((next = strchr (cp, ',')) != NULL)
467     *(next++) = '\0';
468     sscanf (cp, "%d", &value);
469     mt->mod[i] = (sint8) value;
470     cp = next;
471     }
472     }
473     else if (sscanf (cp, "chance %d\n", &value))
474     {
475     mt->chance = (sint8) value;
476     }
477     else if (sscanf (cp, "diff %d\n", &value))
478     {
479     mt->difficulty = (sint8) value;
480     }
481     else if (sscanf (cp, "magic %d\n", &value))
482     {
483     mt->magic = (sint8) value;
484     }
485     else if (sscanf (cp, "damage %d\n", &value))
486     {
487     mt->damage = (sint8) value;
488     }
489     else if (sscanf (cp, "wc %d\n", &value))
490     {
491     mt->wc = (sint8) value;
492     }
493     else if (sscanf (cp, "ac %d\n", &value))
494     {
495     mt->ac = (sint8) value;
496     }
497     else if (sscanf (cp, "sp %d\n", &value))
498     {
499     mt->sp = (sint8) value;
500     }
501     else if (sscanf (cp, "weight %d\n", &value))
502     {
503     mt->weight = value;
504     }
505     else if (sscanf (cp, "value %d\n", &value))
506     {
507     mt->value = value;
508 root 1.4 }
509 elmex 1.1 }
510 root 1.9 if (mt->next)
511 elmex 1.1 {
512 root 1.9 delete mt->next;
513    
514     mt->next = NULL;
515 elmex 1.1 }
516 root 1.9 LOG (llevDebug, "Done.\n");
517     fclose (fp);
518 elmex 1.1 }
519    
520     /* This loads the settings file. There could be debate whether this should
521     * be here or in the common directory - but since only the server needs this
522     * information, having it here probably makes more sense.
523     */
524 root 1.9 static void
525     load_settings (void)
526 elmex 1.1 {
527 root 1.9 char buf[MAX_BUF], *cp;
528     int has_val, comp;
529     FILE *fp;
530    
531     sprintf (buf, "%s/settings", settings.confdir);
532    
533     /* We don't require a settings file at current time, but down the road,
534     * there will probably be so many values that not having a settings file
535     * will not be a good thing.
536     */
537     if ((fp = open_and_uncompress (buf, 0, &comp)) == NULL)
538     {
539     LOG (llevError, "Warning: No settings file found\n");
540     return;
541 elmex 1.1 }
542 root 1.9 while (fgets (buf, MAX_BUF - 1, fp) != NULL)
543     {
544     if (buf[0] == '#')
545     continue;
546     /* eliminate newline */
547     if ((cp = strrchr (buf, '\n')) != NULL)
548     *cp = '\0';
549    
550     /* Skip over empty lines */
551     if (buf[0] == 0)
552     continue;
553    
554     /* Skip all the spaces and set them to nulls. If not space,
555     * set cp to "" to make strcpy's and the like easier down below.
556     */
557     if ((cp = strchr (buf, ' ')) != NULL)
558     {
559     while (*cp == ' ')
560     *cp++ = 0;
561     has_val = 1;
562     }
563     else
564     {
565     cp = "";
566     has_val = 0;
567     }
568    
569 root 1.15 if (!strcasecmp (buf, "motd"))
570 root 1.9 {
571     if (has_val)
572     strcpy (settings.motd, cp);
573     else
574     LOG (llevError, "load_settings: motd must have a value.\n");
575     }
576     else if (!strcasecmp (buf, "dm_mail"))
577     {
578     if (has_val)
579     strcpy (settings.dm_mail, cp);
580     else
581     LOG (llevError, "load_settings: dm_mail must have a value.\n");
582     }
583     else if (!strcasecmp (buf, "worldmapstartx"))
584     {
585     int size = atoi (cp);
586    
587     if (size < 0)
588     LOG (llevError, "load_settings: worldmapstartx must be at least " "0, %d is invalid\n", size);
589     else
590     settings.worldmapstartx = size;
591     }
592     else if (!strcasecmp (buf, "worldmapstarty"))
593     {
594     int size = atoi (cp);
595    
596     if (size < 0)
597     LOG (llevError, "load_settings: worldmapstarty must be at least " "0, %d is invalid\n", size);
598     else
599     settings.worldmapstarty = size;
600     }
601     else if (!strcasecmp (buf, "worldmaptilesx"))
602     {
603     int size = atoi (cp);
604    
605     if (size < 1)
606     LOG (llevError, "load_settings: worldmaptilesx must be greater " "than 1, %d is invalid\n", size);
607     else
608     settings.worldmaptilesx = size;
609     }
610     else if (!strcasecmp (buf, "worldmaptilesy"))
611     {
612     int size = atoi (cp);
613    
614     if (size < 1)
615     LOG (llevError, "load_settings: worldmaptilesy must be greater " "than 1, %d is invalid\n", size);
616     else
617     settings.worldmaptilesy = size;
618     }
619     else if (!strcasecmp (buf, "worldmaptilesizex"))
620     {
621     int size = atoi (cp);
622    
623     if (size < 1)
624     LOG (llevError, "load_settings: worldmaptilesizex must be " "greater than 1, %d is invalid\n", size);
625     else
626     settings.worldmaptilesizex = size;
627     }
628     else if (!strcasecmp (buf, "worldmaptilesizey"))
629     {
630     int size = atoi (cp);
631    
632     if (size < 1)
633     LOG (llevError, "load_settings: worldmaptilesizey must be " "greater than 1, %d is invalid\n", size);
634     else
635     settings.worldmaptilesizey = size;
636     }
637     else if (!strcasecmp (buf, "dynamiclevel"))
638     {
639     int lev = atoi (cp);
640    
641     if (lev < 0)
642     LOG (llevError, "load_settings: dynamiclevel must be " "at least 0, %d is invalid\n", lev);
643     else
644     settings.dynamiclevel = lev;
645     }
646     else if (!strcasecmp (buf, "fastclock"))
647     {
648     int lev = atoi (cp);
649    
650     if (lev < 0)
651     LOG (llevError, "load_settings: fastclock must be at least 0" ", %d is invalid\n", lev);
652     else
653     settings.fastclock = lev;
654     }
655     else if (!strcasecmp (buf, "not_permadeth"))
656     {
657     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
658     {
659     settings.not_permadeth = TRUE;
660     }
661     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
662     {
663     settings.not_permadeth = FALSE;
664     }
665     else
666     {
667     LOG (llevError, "load_settings: Unknown value for not_permadeth" ": %s\n", cp);
668     }
669     }
670     else if (!strcasecmp (buf, "resurrection"))
671     {
672     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
673     {
674     settings.resurrection = TRUE;
675     }
676     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
677     {
678     settings.resurrection = FALSE;
679     }
680     else
681     {
682     LOG (llevError, "load_settings: Unknown value for resurrection" ": %s\n", cp);
683     }
684     }
685     else if (!strcasecmp (buf, "set_title"))
686     {
687     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
688     {
689     settings.set_title = TRUE;
690     }
691     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
692     {
693     settings.set_title = FALSE;
694     }
695     else
696     {
697     LOG (llevError, "load_settings: Unknown value for set_title" ": %s\n", cp);
698     }
699     }
700     else if (!strcasecmp (buf, "search_items"))
701     {
702     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
703     {
704     settings.search_items = TRUE;
705     }
706     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
707     {
708     settings.search_items = FALSE;
709     }
710     else
711     {
712     LOG (llevError, "load_settings: Unknown value for search_items" ": %s\n", cp);
713     }
714     }
715     else if (!strcasecmp (buf, "spell_encumbrance"))
716     {
717     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
718     {
719     settings.spell_encumbrance = TRUE;
720     }
721     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
722     {
723     settings.spell_encumbrance = FALSE;
724     }
725     else
726     {
727     LOG (llevError, "load_settings: Unknown value for " "spell_encumbrance: %s\n", cp);
728     }
729     }
730     else if (!strcasecmp (buf, "spell_failure_effects"))
731     {
732     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
733     {
734     settings.spell_failure_effects = TRUE;
735     }
736     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
737     {
738     settings.spell_failure_effects = FALSE;
739     }
740     else
741     {
742     LOG (llevError, "load_settings: Unknown value for " "spell_failure_effects: %s\n", cp);
743     }
744     }
745     else if (!strcasecmp (buf, "casting_time"))
746     {
747     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
748     {
749     settings.casting_time = TRUE;
750     }
751     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
752     {
753     settings.casting_time = FALSE;
754     }
755     else
756     {
757     LOG (llevError, "load_settings: Unknown value for " "casting_time: %s\n", cp);
758     }
759     }
760     else if (!strcasecmp (buf, "real_wiz"))
761     {
762     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
763     {
764     settings.real_wiz = TRUE;
765     }
766     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
767     {
768     settings.real_wiz = FALSE;
769     }
770     else
771     {
772     LOG (llevError, "load_settings: Unknown value for " "real_wiz: %s\n", cp);
773     }
774     }
775     else if (!strcasecmp (buf, "recycle_tmp_maps"))
776     {
777     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
778     {
779     settings.recycle_tmp_maps = TRUE;
780     }
781     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
782     {
783     settings.recycle_tmp_maps = FALSE;
784     }
785     else
786     {
787     LOG (llevError, "load_settings: Unknown value for " "recycle_tmp_maps: %s\n", cp);
788     }
789     }
790     else if (!strcasecmp (buf, "explore_mode"))
791     {
792     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
793     {
794     settings.explore_mode = TRUE;
795     }
796     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
797     {
798     settings.explore_mode = FALSE;
799     }
800     else
801     {
802     LOG (llevError, "load_settings: Unknown value for " "explore_mode: %s\n", cp);
803     }
804     }
805     else if (!strcasecmp (buf, "who_format"))
806     {
807     if (has_val)
808     strcpy (settings.who_format, cp);
809     }
810     else if (!strcasecmp (buf, "who_wiz_format"))
811     {
812     if (has_val)
813     strcpy (settings.who_wiz_format, cp);
814     }
815     else if (!strcasecmp (buf, "spellpoint_level_depend"))
816     {
817     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
818     {
819     settings.spellpoint_level_depend = TRUE;
820     }
821     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
822     {
823     settings.spellpoint_level_depend = FALSE;
824     }
825     else
826     {
827     LOG (llevError, "load_settings: Unknown value for " "spellpoint_level_depend: %s\n", cp);
828     }
829     }
830     else if (!strcasecmp (buf, "stat_loss_on_death"))
831     {
832     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
833     {
834     settings.stat_loss_on_death = TRUE;
835     }
836     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
837     {
838     settings.stat_loss_on_death = FALSE;
839     }
840     else
841     {
842     LOG (llevError, "load_settings: Unknown value for " "stat_loss_on_death: %s\n", cp);
843     }
844     }
845     else if (!strcasecmp (buf, "use_permanent_experience"))
846     {
847     LOG (llevError, "use_permanent_experience is deprecated, use" "permenent_experience_percentage instead\n");
848     }
849     else if (!strcasecmp (buf, "permanent_experience_percentage"))
850     {
851     int val = atoi (cp);
852    
853     if (val < 0 || val > 100)
854     LOG (llevError, "load_settings: permenent_experience_percentage" "must be between 0 and 100, %d is invalid\n", val);
855     else
856     settings.permanent_exp_ratio = val;
857     }
858     else if (!strcasecmp (buf, "death_penalty_percentage"))
859     {
860     int val = atoi (cp);
861    
862     if (val < 0 || val > 100)
863     LOG (llevError, "load_settings: death_penalty_percentage" "must be between 0 and 100, %d is invalid\n", val);
864     else
865     settings.death_penalty_ratio = val;
866     }
867     else if (!strcasecmp (buf, "death_penalty_levels"))
868     {
869     int val = atoi (cp);
870    
871     if (val < 0 || val > 255)
872     LOG (llevError, "load_settings: death_penalty_levels" "can not be negative, %d is invalid\n", val);
873     else
874     settings.death_penalty_level = val;
875     }
876     else if (!strcasecmp (buf, "balanced_stat_loss"))
877     {
878     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
879     {
880     settings.balanced_stat_loss = TRUE;
881     }
882     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
883     {
884     settings.balanced_stat_loss = FALSE;
885     }
886     else
887     {
888     LOG (llevError, "load_settings: Unknown value for " "balanced_stat_loss: %s\n", cp);
889     }
890     }
891     else if (!strcasecmp (buf, "simple_exp"))
892     {
893     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
894     {
895     settings.simple_exp = TRUE;
896     }
897     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
898     {
899     settings.simple_exp = FALSE;
900     }
901     else
902     {
903     LOG (llevError, "load_settings: Unknown value for simple_exp: %s\n", cp);
904     }
905     }
906     else if (!strcasecmp (buf, "item_power_factor"))
907     {
908     float tmp = atof (cp);
909    
910     if (tmp < 0)
911     LOG (llevError, "load_settings: item_power_factor must be a positive number (%f < 0)\n", tmp);
912     else
913     settings.item_power_factor = tmp;
914     }
915     else if (!strcasecmp (buf, "pk_luck_penalty"))
916     {
917     sint16 val = atoi (cp);
918    
919     if (val < -100 || val > 100)
920     LOG (llevError, "load_settings: pk_luck_penalty must be between -100 and 100" ", %d is invalid\n", val);
921     else
922     settings.pk_luck_penalty = val;
923     }
924     else if (!strcasecmp (buf, "set_friendly_fire"))
925     {
926     int val = atoi (cp);
927 elmex 1.1
928     #if COZY_SERVER
929 root 1.9 if (val < 0 || val > 100)
930     LOG (llevError, "load_settings: set_friendly_fire must be between 0 an 100" ", %d is invalid\n", val);
931 elmex 1.1 #else
932 root 1.9 if (val < 1 || val > 100)
933     LOG (llevError, "load_settings: set_friendly_fire must be between 1 an 100" ", %d is invalid\n", val);
934 elmex 1.1 #endif
935 root 1.9 else
936     settings.set_friendly_fire = val;
937     }
938     else if (!strcasecmp (buf, "armor_max_enchant"))
939     {
940     int max_e = atoi (cp);
941    
942     if (max_e <= 0)
943     LOG (llevError, "load_settings: armor_max_enchant is %d\n", max_e);
944     else
945 elmex 1.1 settings.armor_max_enchant = max_e;
946 root 1.9 }
947     else if (!strcasecmp (buf, "armor_weight_reduction"))
948     {
949     int wr = atoi (cp);
950    
951     if (wr < 0)
952     LOG (llevError, "load_settings: armor_weight_reduction is %d\n", wr);
953     else
954 elmex 1.1 settings.armor_weight_reduction = wr;
955     }
956 root 1.9 else if (!strcasecmp (buf, "armor_weight_linear"))
957     {
958     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
959     {
960     settings.armor_weight_linear = TRUE;
961     }
962     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
963     {
964     settings.armor_weight_linear = FALSE;
965     }
966     else
967     {
968     LOG (llevError, "load_settings: unknown value for armor_weight_linear: %s\n", cp);
969     }
970    
971     }
972     else if (!strcasecmp (buf, "armor_speed_improvement"))
973     {
974     int wr = atoi (cp);
975 elmex 1.1
976 root 1.9 if (wr < 0)
977     LOG (llevError, "load_settings: armor_speed_improvement is %d\n", wr);
978     else
979 elmex 1.1 settings.armor_speed_improvement = wr;
980     }
981 root 1.9 else if (!strcasecmp (buf, "armor_speed_linear"))
982     {
983     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
984     {
985     settings.armor_speed_linear = TRUE;
986     }
987     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
988     {
989     settings.armor_speed_linear = FALSE;
990     }
991     else
992     {
993     LOG (llevError, "load_settings: unknown value for armor_speed_linear: %s\n", cp);
994     }
995    
996     }
997     else if (!strcasecmp (buf, "no_player_stealing"))
998     {
999     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
1000     {
1001     settings.no_player_stealing = TRUE;
1002     }
1003     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
1004     {
1005     settings.no_player_stealing = FALSE;
1006     }
1007     else
1008     {
1009     LOG (llevError, "load_settings: unknown value for no_player_stealing: %s\n", cp);
1010     }
1011 elmex 1.1
1012 root 1.9 }
1013     else if (!strcasecmp (buf, "create_home_portals"))
1014     {
1015     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
1016     {
1017     settings.create_home_portals = TRUE;
1018     }
1019     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
1020     {
1021     settings.create_home_portals = FALSE;
1022     }
1023     else
1024     {
1025     LOG (llevError, "load_settings: Unknown value for create_home_portals: %s\n", cp);
1026     }
1027    
1028     }
1029     else
1030     {
1031     LOG (llevError, "Unknown value in settings file: %s\n", buf);
1032 root 1.4 }
1033 elmex 1.1 }
1034 root 1.9 close_and_delete (fp, comp);
1035 elmex 1.1 }
1036    
1037    
1038     /*
1039     * init() is called only once, when starting the program.
1040     */
1041    
1042 root 1.9 void
1043     init (int argc, char **argv)
1044     {
1045     init_done = 0; /* Must be done before init_signal() */
1046     logfile = stderr;
1047     parse_args (argc, argv, 1); /* First arg pass - right now it does
1048 root 1.4 * nothing, but in future specifying the
1049     * LibDir in this pass would be reasonable*/
1050 elmex 1.1
1051 root 1.14 cfperl_init ();
1052 root 1.9 init_library (); /* Must be called early */
1053     load_settings (); /* Load the settings file */
1054     init_weather ();
1055     load_materials ();
1056     parse_args (argc, argv, 2);
1057     fprintf (logfile, "Welcome to CrossFire, v%s\n", VERSION);
1058     fprintf (logfile, "Copyright (C) 1994 Mark Wedel.\n");
1059     fprintf (logfile, "Copyright (C) 1992 Frank Tore Johansen.\n");
1060    
1061     if (strcmp (settings.dm_mail, "") != 0)
1062     {
1063     fprintf (logfile, "Maintained locally by: %s\n", settings.dm_mail);
1064     fprintf (logfile, "Questions and bugs should be mailed to above address.\n");
1065 elmex 1.1 }
1066 root 1.11
1067 root 1.9 SRANDOM (time (NULL));
1068 elmex 1.1
1069 root 1.9 init_startup (); /* Write (C), check shutdown/forbid files */
1070 root 1.11 init_uuid ();
1071 root 1.9 init_signals (); /* Sets up signal interceptions */
1072     init_commands (); /* Sort command tables */
1073     read_map_log (); /* Load up the old temp map files */
1074     init_skills ();
1075    
1076     parse_args (argc, argv, 3);
1077    
1078     #ifndef WIN32 /* ***win32: no BecomeDaemon in windows */
1079     if (settings.daemonmode)
1080     logfile = BecomeDaemon (settings.logfilename[0] == '\0' ? "logfile" : settings.logfilename);
1081 elmex 1.1 #endif
1082    
1083 root 1.9 init_beforeplay ();
1084     init_ericserver ();
1085     init_done = 1;
1086 elmex 1.1 }
1087    
1088 root 1.9 void
1089     usage (void)
1090     {
1091     (void) fprintf (logfile, "Usage: crossfire [-h] [-<flags>]...\n");
1092 elmex 1.1 }
1093    
1094 root 1.9 void
1095     help (void)
1096     {
1097    
1098 elmex 1.1 /* The information in usage is redundant with what is given below, so why call it? */
1099 root 1.9
1100 elmex 1.1 /* usage();*/
1101 root 1.9 printf ("Flags:\n");
1102     printf (" -csport <port> Specifies the port to use for the new client/server code.\n");
1103     printf (" -d Turns on some debugging.\n");
1104     printf (" +d Turns off debugging (useful if server compiled with debugging\n");
1105     printf (" as default).\n");
1106     printf (" -detach The server will go in the background, closing all\n");
1107     printf (" connections to the tty.\n");
1108     printf (" -h Display this information.\n");
1109     printf (" -log <file> Specifies which file to send output to.\n");
1110     printf (" Only has meaning if -detach is specified.\n");
1111     printf (" -mon Turns on monster debugging.\n");
1112     printf (" -o Prints out info on what was defined at compile time.\n");
1113     printf (" -s Display the high-score list.\n");
1114     printf (" -score <name or class> Displays all high scores with matching name/class.\n");
1115     printf (" -v Print version and contributors.\n");
1116     printf (" -data Sets the lib dir (archetypes, treasures, etc.)\n");
1117     printf (" -local Read/write local data (hiscore, unique items, etc.)\n");
1118     printf (" -maps Sets the directory for maps.\n");
1119     printf (" -arch Sets the archetype file to use.\n");
1120     printf (" -regions Sets the regions file to use.\n");
1121     printf (" -playerdir Sets the directory for the player files.\n");
1122     printf (" -templatedir Sets the directory for template generate maps.\n");
1123     printf (" -treasures Sets the treasures file to use.\n");
1124     printf (" -uniquedir Sets the unique items/maps directory.\n");
1125     printf (" -tmpdir Sets the directory for temporary files (mostly maps.)\n");
1126     printf (" -m Lists out suggested experience for all monsters.\n");
1127     printf (" -m2 Dumps out abilities.\n");
1128     printf (" -m3 Dumps out artifact information.\n");
1129     printf (" -m4 Dumps out spell information.\n");
1130     printf (" -m5 Dumps out skill information.\n");
1131     printf (" -m6 Dumps out race information.\n");
1132     printf (" -m7 Dumps out alchemy information.\n");
1133     printf (" -m8 Dumps out gods information.\n");
1134     printf (" -m9 Dumps out more alchemy information (formula checking).\n");
1135     printf (" -mt <name> Dumps out list of treasures for a monster.\n");
1136     exit (0);
1137     }
1138    
1139     void
1140     init_beforeplay (void)
1141     {
1142     init_archetypes (); /* If not called before, reads all archetypes from file */
1143     init_artifacts (); /* If not called before, reads all artifacts from file */
1144     init_spells (); /* If not called before, links archtypes used by spells */
1145     init_regions (); /* If not called before, reads all regions from file */
1146     init_archetype_pointers (); /* Setup global pointers to archetypes */
1147     init_races (); /* overwrite race designations using entries in lib/races file */
1148     init_gods (); /* init linked list of gods from archs */
1149     init_readable (); /* inits useful arrays for readable texts */
1150     init_formulae (); /* If not called before, reads formulae from file */
1151    
1152     switch (settings.dumpvalues)
1153     {
1154 root 1.10 case 1:
1155     print_monsters ();
1156     exit (0);
1157     case 2:
1158     dump_abilities ();
1159     exit (0);
1160     case 3:
1161     dump_artifacts ();
1162     exit (0);
1163     case 4:
1164     dump_spells ();
1165     exit (0);
1166     case 5:
1167     exit (0);
1168     case 6:
1169     dump_races ();
1170     exit (0);
1171     case 7:
1172     dump_alchemy ();
1173     exit (0);
1174     case 9:
1175     dump_alchemy_costs ();
1176     exit (0);
1177     case 10:
1178     dump_monster_treasure (settings.dumparg);
1179     exit (0);
1180 root 1.9 }
1181 elmex 1.1 }
1182    
1183 root 1.9 void
1184     init_startup (void)
1185     {
1186 elmex 1.1 char buf[MAX_BUF];
1187     FILE *fp;
1188     int comp;
1189    
1190     #ifdef SHUTDOWN_FILE
1191 root 1.9 sprintf (buf, "%s/%s", settings.confdir, SHUTDOWN_FILE);
1192     if ((fp = open_and_uncompress (buf, 0, &comp)) != NULL)
1193     {
1194     while (fgets (buf, MAX_BUF - 1, fp) != NULL)
1195     printf ("%s", buf);
1196     close_and_delete (fp, comp);
1197     exit (1);
1198     }
1199 elmex 1.1 #endif
1200    
1201 root 1.9 if (forbid_play ())
1202     { /* Maybe showing highscore should be allowed? */
1203     LOG (llevError, "CrossFire: Playing not allowed.\n");
1204     exit (-1);
1205     }
1206 elmex 1.1 }
1207    
1208     /*
1209     * compile_info(): activated with the -o flag.
1210     * It writes out information on how Imakefile and config.h was configured
1211     * at compile time.
1212     */
1213    
1214 root 1.9 void
1215     compile_info (void)
1216     {
1217     int i = 0;
1218    
1219     printf ("Non-standard include files:\n");
1220 elmex 1.1 #if !defined (__STRICT_ANSI__) || defined (__sun__)
1221 root 1.9 # if !defined (Mips)
1222     printf ("<stdlib.h>\n");
1223     i = 1;
1224     # endif
1225     # if !defined (MACH) && !defined (sony)
1226     printf ("<malloc.h>\n");
1227     i = 1;
1228     # endif
1229 elmex 1.1 #endif
1230     #ifndef __STRICT_ANSI__
1231 root 1.9 # ifndef MACH
1232     printf ("<memory.h\n");
1233     i = 1;
1234     # endif
1235 elmex 1.1 #endif
1236     #ifndef sgi
1237 root 1.9 printf ("<sys/timeb.h>\n");
1238     i = 1;
1239 elmex 1.1 #endif
1240 root 1.9 if (!i)
1241     printf ("(none)\n");
1242     printf ("Datadir:\t\t%s\n", settings.datadir);
1243     printf ("Localdir:\t\t%s\n", settings.localdir);
1244 elmex 1.1 #ifdef PERM_FILE
1245 root 1.9 printf ("Perm file:\t<ETC>/%s\n", PERM_FILE);
1246 elmex 1.1 #endif
1247     #ifdef SHUTDOWN_FILE
1248 root 1.9 printf ("Shutdown file:\t<ETC>/%s\n", SHUTDOWN_FILE);
1249 elmex 1.1 #endif
1250 root 1.9 printf ("Save player:\t<true>\n");
1251     printf ("Save mode:\t%4.4o\n", SAVE_MODE);
1252     printf ("Playerdir:\t<VAR>/%s\n", settings.playerdir);
1253     printf ("Itemsdir:\t<VAR>/%s\n", settings.uniquedir);
1254     printf ("Tmpdir:\t\t%s\n", settings.tmpdir);
1255     printf ("Map max timeout:\t%d\n", MAP_MAXTIMEOUT);
1256     printf ("Max objects:\t%d\n", MAX_OBJECTS);
1257 elmex 1.1 #ifdef USE_CALLOC
1258 root 1.9 printf ("Use_calloc:\t<true>\n");
1259 elmex 1.1 #else
1260 root 1.9 printf ("Use_calloc:\t<false>\n");
1261 elmex 1.1 #endif
1262    
1263     #ifdef X_EDITOR
1264 root 1.9 printf ("Editor:\t\t%s\n", X_EDITOR);
1265 elmex 1.1 #endif
1266    
1267 root 1.9 printf ("Max_time:\t%d\n", MAX_TIME);
1268 elmex 1.1
1269 root 1.9 #ifdef WIN32 /* ***win32 compile_info(): remove execl... */
1270     printf ("Logfilename:\t%s\n", settings.logfilename);
1271     exit (0);
1272 elmex 1.1 #else
1273 root 1.9 execl ("/bin/uname", "uname", "-a", NULL);
1274     LOG (llevError, "Oops, shouldn't have gotten here: execl(/bin/uname) failed: %s\n", strerror (errno));
1275     exit (-1);
1276 elmex 1.1 #endif
1277     }
1278    
1279     /* Signal handlers: */
1280    
1281 root 1.9 void
1282     rec_sigsegv (int i)
1283     {
1284     LOG (llevError, "\nSIGSEGV received.\n");
1285     fatal_signal (1, 1);
1286 elmex 1.1 }
1287    
1288 root 1.9 void
1289     rec_sigint (int i)
1290     {
1291     LOG (llevInfo, "\nSIGINT received.\n");
1292     fatal_signal (0, 1);
1293 elmex 1.1 }
1294    
1295 root 1.9 void
1296     rec_sighup (int i)
1297     {
1298     LOG (llevInfo, "\nSIGHUP received\n");
1299     if (init_done)
1300     {
1301     emergency_save (0);
1302     cleanup ();
1303     }
1304     exit (0);
1305 elmex 1.1 }
1306    
1307 root 1.9 void
1308     rec_sigquit (int i)
1309     {
1310     LOG (llevInfo, "\nSIGQUIT received\n");
1311     fatal_signal (1, 1);
1312 elmex 1.1 }
1313    
1314 root 1.9 void
1315     rec_sigbus (int i)
1316     {
1317 elmex 1.1 #ifdef SIGBUS
1318 root 1.9 LOG (llevError, "\nSIGBUS received\n");
1319     fatal_signal (1, 1);
1320 elmex 1.1 #endif
1321     }
1322    
1323 root 1.9 void
1324     rec_sigterm (int i)
1325     {
1326     LOG (llevInfo, "\nSIGTERM received\n");
1327     fatal_signal (0, 1);
1328     }
1329    
1330     void
1331     fatal_signal (int make_core, int close_sockets)
1332     {
1333     if (init_done)
1334     {
1335     emergency_save (0);
1336     clean_tmp_files ();
1337     }
1338     if (make_core)
1339     abort ();
1340     exit (0);
1341     }
1342    
1343     void
1344     init_signals (void)
1345     {
1346     #ifndef WIN32 /* init_signals() remove signals */
1347     signal (SIGHUP, rec_sighup);
1348     signal (SIGINT, rec_sigint);
1349     signal (SIGQUIT, rec_sigquit);
1350     signal (SIGSEGV, rec_sigsegv);
1351     signal (SIGPIPE, SIG_IGN);
1352     # ifdef SIGBUS
1353     signal (SIGBUS, rec_sigbus);
1354     # endif
1355     signal (SIGTERM, rec_sigterm);
1356 elmex 1.1 #endif
1357     }
1358    
1359     /* init_races() - reads the races file in the lib/ directory, then
1360     * overwrites old 'race' entries. This routine allow us to quickly
1361     * re-configure the 'alignment' of monsters, objects. Useful for
1362     * putting together lists of creatures, etc that belong to gods.
1363     */
1364 root 1.9
1365     void
1366     init_races (void)
1367 elmex 1.8 {
1368 elmex 1.1 FILE *file;
1369     char race[MAX_BUF], fname[MAX_BUF], buf[MAX_BUF], *cp, variable[MAX_BUF];
1370 elmex 1.8 archetype *mon = NULL;
1371     static int init_done = 0;
1372 elmex 1.1
1373 elmex 1.8 if (init_done)
1374 elmex 1.1 return;
1375 elmex 1.8 init_done = 1;
1376 root 1.10 first_race = 0;
1377 elmex 1.1
1378 elmex 1.8 sprintf (fname, "%s/races", settings.datadir);
1379     LOG (llevDebug, "Reading races from %s...", fname);
1380     if (!(file = fopen (fname, "r")))
1381     {
1382 root 1.9 LOG (llevError, "Cannot open races file %s: %s\n", fname, strerror (errno));
1383 elmex 1.8 return;
1384 elmex 1.1 }
1385 elmex 1.8
1386     while (fgets (buf, MAX_BUF, file) != NULL)
1387     {
1388     int set_race = 1, set_list = 1;
1389 root 1.9
1390 elmex 1.8 if (*buf == '#')
1391     continue;
1392 root 1.10
1393 elmex 1.8 if ((cp = strchr (buf, '\n')) != NULL)
1394     *cp = '\0';
1395 root 1.10
1396 elmex 1.8 cp = buf;
1397     while (*cp == ' ' || *cp == '!' || *cp == '@')
1398     {
1399     if (*cp == '!')
1400     set_race = 0;
1401     if (*cp == '@')
1402     set_list = 0;
1403     cp++;
1404     }
1405 root 1.10
1406 elmex 1.8 if (sscanf (cp, "RACE %s", variable))
1407     { /* set new race value */
1408     strcpy (race, variable);
1409 root 1.4 }
1410 elmex 1.8 else
1411     {
1412     char *cp1;
1413 root 1.9
1414 elmex 1.8 /* Take out beginning spaces */
1415     for (cp1 = cp; *cp1 == ' '; cp1++)
1416     ;
1417     /* Remove newline and trailing spaces */
1418     for (cp1 = cp + strlen (cp) - 1; *cp1 == '\n' || *cp1 == ' '; cp1--)
1419     {
1420     *cp1 = '\0';
1421     if (cp == cp1)
1422     break;
1423     }
1424    
1425     if (cp[strlen (cp) - 1] == '\n')
1426     cp[strlen (cp) - 1] = '\0';
1427 root 1.10
1428 elmex 1.8 /* set creature race to race value */
1429 root 1.12 if ((mon = archetype::find (cp)) == NULL)
1430 elmex 1.8 LOG (llevError, "\nCreature %s in race file lacks archetype", cp);
1431     else
1432     {
1433 root 1.9 if (set_race && (!mon->clone.race || strcmp (mon->clone.race, race)))
1434 elmex 1.8 {
1435     if (mon->clone.race)
1436 root 1.10 LOG (llevDebug, "\n Resetting race to %s from %s for archetype %s", race, &mon->clone.race, &mon->name);
1437    
1438 elmex 1.8 mon->clone.race = race;
1439 elmex 1.1 }
1440 root 1.10
1441 elmex 1.8 /* if the arch is a monster, add it to the race list */
1442     if (set_list && QUERY_FLAG (&mon->clone, FLAG_MONSTER))
1443     add_to_racelist (race, &mon->clone);
1444     }
1445 elmex 1.1 }
1446     }
1447 root 1.10
1448 elmex 1.8 fclose (file);
1449     LOG (llevDebug, "done.\n");
1450 elmex 1.1 }
1451    
1452 root 1.9 void
1453     dump_races (void)
1454     {
1455     racelink *list;
1456     objectlink *tmp;
1457    
1458     for (list = first_race; list; list = list->next)
1459     {
1460 root 1.10 fprintf (stderr, "\nRACE %s:\t", &list->name);
1461 root 1.9 for (tmp = list->member; tmp; tmp = tmp->next)
1462     fprintf (stderr, "%s(%d), ", &tmp->ob->arch->name, tmp->ob->level);
1463 elmex 1.1 }
1464 root 1.10
1465 root 1.9 fprintf (stderr, "\n");
1466 elmex 1.1 }
1467    
1468 root 1.9 void
1469     add_to_racelist (const char *race_name, object *op)
1470     {
1471 elmex 1.1 racelink *race;
1472 root 1.9
1473     if (!op || !race_name)
1474     return;
1475 root 1.10
1476 root 1.9 race = find_racelink (race_name);
1477    
1478     if (!race)
1479     { /* add in a new race list */
1480     race = get_racelist ();
1481     race->next = first_race;
1482     first_race = race;
1483     race->name = race_name;
1484     }
1485    
1486     if (race->member->ob)
1487     {
1488     objectlink *tmp = get_objectlink ();
1489    
1490     tmp->next = race->member;
1491     race->member = tmp;
1492     }
1493 root 1.10
1494 elmex 1.1 race->nrof++;
1495     race->member->ob = op;
1496     }
1497    
1498 root 1.9 racelink *
1499     get_racelist ()
1500     {
1501 root 1.10 racelink *list = new racelink;
1502 root 1.9
1503 root 1.10 list->name = 0;
1504 root 1.9 list->nrof = 0;
1505 root 1.10 list->next = 0;
1506 root 1.9 list->member = get_objectlink ();
1507 elmex 1.1
1508     return list;
1509     }
1510 root 1.9
1511     racelink *
1512     find_racelink (const char *name)
1513     {
1514 root 1.10 if (name)
1515     for (racelink *link = first_race; link; link = link->next)
1516     if (!link->name || !strcmp (name, link->name))
1517     return link;
1518 root 1.9
1519 root 1.10 return 0;
1520 elmex 1.1 }