ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/init.C
Revision: 1.72
Committed: Thu Oct 15 21:40:42 2009 UTC (14 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82
Changes since 1.71: +1 -87 lines
Log Message:
cleanups

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.59 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 pippijn 1.34 *
4 root 1.64 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.52 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.34 *
8 root 1.71 * Deliantra is free software: you can redistribute it and/or modify it under
9     * the terms of the Affero GNU General Public License as published by the
10     * Free Software Foundation, either version 3 of the License, or (at your
11     * option) any later version.
12 pippijn 1.34 *
13 root 1.56 * 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 pippijn 1.34 *
18 root 1.71 * You should have received a copy of the Affero GNU General Public License
19     * and the GNU General Public License along with this program. If not, see
20     * <http://www.gnu.org/licenses/>.
21 root 1.52 *
22 root 1.59 * The authors can be reached via e-mail to <support@deliantra.net>
23 pippijn 1.34 */
24 elmex 1.1
25     #include <global.h>
26     #include <material.h>
27     #include <loader.h>
28 root 1.22 #include <sproto.h>
29 elmex 1.1
30 root 1.7 //TODO: make this a constructor
31 root 1.9 static materialtype_t *
32     get_empty_mat (void)
33     {
34     materialtype_t *mt;
35     int i;
36    
37     mt = new materialtype_t;
38    
39 root 1.68 mt->name = shstr_unknown;
40 root 1.67 mt->description = 0;
41    
42 root 1.9 for (i = 0; i < NROFATTACKS; i++)
43     {
44     mt->save[i] = 0;
45 root 1.67 mt->mod[i] = 0;
46 elmex 1.1 }
47 root 1.67
48     mt->chance = 0;
49     mt->difficulty = 0;
50     mt->magic = 0;
51     mt->damage = 0;
52     mt->wc = 0;
53     mt->ac = 0;
54     mt->sp = 0;
55     mt->weight = 100;
56     mt->value = 100;
57     mt->density = 1;
58     mt->next = 0;
59    
60 root 1.9 return mt;
61     }
62    
63 root 1.66 void
64 root 1.9 load_materials (void)
65     {
66 root 1.39 char filename[MAX_BUF];
67 root 1.9
68     sprintf (filename, "%s/materials", settings.datadir);
69 pippijn 1.25 LOG (llevDebug, "Reading material type data from %s...\n", filename);
70 root 1.39
71 root 1.68 //TODO: somehow free old materials, or update them in-place
72     materialt = 0;
73    
74 root 1.39 object_thawer thawer (filename);
75    
76     if (!thawer)
77 root 1.9 {
78     LOG (llevError, "Cannot open %s for reading\n", filename);
79 root 1.68 goto done;
80     }
81    
82     while (thawer.kw != KW_name)
83     {
84     thawer.next ();
85    
86     if (thawer.kw == KW_EOF)
87     goto done;
88 elmex 1.1 }
89 root 1.39
90 root 1.68 materialtype_t *mt;
91 root 1.39
92     for (;;)
93 root 1.9 {
94 root 1.51 switch (thawer.kw)
95 root 1.9 {
96 root 1.39 case KW_name:
97 root 1.68 mt = get_empty_mat ();
98     mt->next = materialt;
99     materialt = mt;
100 root 1.39
101     thawer.get (mt->name);
102 root 1.68 mt->description = mt->name;
103 root 1.39 break;
104    
105     case KW_description:
106     thawer.get (mt->description);
107     break;
108    
109     case KW_material:
110     thawer.get (mt->material);
111     break;
112    
113     case KW_saves:
114 root 1.9 {
115 root 1.39 const char *cp = thawer.get_str () - 1;
116    
117     for (int i = 0; i < NROFATTACKS; i++)
118 root 1.9 {
119 root 1.39 if (!cp)
120     {
121     mt->save[i] = 0;
122     continue;
123     }
124    
125     int value;
126     ++cp;
127     sscanf (cp, "%d", &value);
128     mt->save[i] = (sint8) value;
129     cp = strchr (cp, ',');
130 root 1.4 }
131 root 1.9 }
132 root 1.39 break;
133    
134     case KW_mods:
135 root 1.9 {
136 root 1.39 const char *cp = thawer.get_str () - 1;
137    
138     for (int i = 0; i < NROFATTACKS; i++)
139 root 1.9 {
140 root 1.39 if (!cp)
141     {
142     mt->save[i] = 0;
143     continue;
144     }
145    
146     ++cp;
147     int value;
148     sscanf (cp, "%d", &value);
149     mt->mod[i] = (sint8) value;
150     cp = strchr (cp, ',');
151 root 1.4 }
152 root 1.9 }
153 root 1.39 break;
154    
155     case KW_chance: thawer.get (mt->chance); break;
156     case KW_difficulty: // cf+ alias, not original cf
157     case KW_diff: thawer.get (mt->difficulty); break;
158     case KW_magic: thawer.get (mt->magic); break;
159     case KW_dam: // cf+ alias, not original cf
160     case KW_damage: thawer.get (mt->damage); break;
161     case KW_wc: thawer.get (mt->wc); break;
162     case KW_ac: thawer.get (mt->ac); break;
163     case KW_sp: thawer.get (mt->sp); break;
164     case KW_weight: thawer.get (mt->weight); break;
165     case KW_value: thawer.get (mt->value); break;
166     case KW_density: thawer.get (mt->density); break;
167    
168     case KW_EOF:
169     goto done;
170    
171     default:
172 root 1.41 if (!thawer.parse_error ("materials file", "materials"))
173 root 1.39 goto done;
174     break;
175 root 1.4 }
176 root 1.68
177     thawer.next ();
178 elmex 1.1 }
179 root 1.39
180     done:
181 root 1.68 if (!materialt)
182     materialt = get_empty_mat ();
183 root 1.39
184 root 1.9 LOG (llevDebug, "Done.\n");
185 elmex 1.1 }
186    
187     /* This loads the settings file. There could be debate whether this should
188     * be here or in the common directory - but since only the server needs this
189     * information, having it here probably makes more sense.
190     */
191 root 1.66 void
192 root 1.9 load_settings (void)
193 elmex 1.1 {
194 root 1.9 char buf[MAX_BUF], *cp;
195     int has_val, comp;
196     FILE *fp;
197    
198     sprintf (buf, "%s/settings", settings.confdir);
199    
200     /* We don't require a settings file at current time, but down the road,
201     * there will probably be so many values that not having a settings file
202     * will not be a good thing.
203     */
204 root 1.43 if (!(fp = open_and_uncompress (buf, 0, &comp)))
205 root 1.9 {
206 root 1.43 LOG (llevError, "Error: No settings file found\n");
207     exit (1);
208 elmex 1.1 }
209 root 1.43
210 root 1.9 while (fgets (buf, MAX_BUF - 1, fp) != NULL)
211     {
212     if (buf[0] == '#')
213     continue;
214     /* eliminate newline */
215     if ((cp = strrchr (buf, '\n')) != NULL)
216     *cp = '\0';
217    
218     /* Skip over empty lines */
219     if (buf[0] == 0)
220     continue;
221    
222     /* Skip all the spaces and set them to nulls. If not space,
223     * set cp to "" to make strcpy's and the like easier down below.
224     */
225     if ((cp = strchr (buf, ' ')) != NULL)
226     {
227     while (*cp == ' ')
228     *cp++ = 0;
229     has_val = 1;
230     }
231     else
232     {
233 root 1.44 cp = (char *)"";
234 root 1.9 has_val = 0;
235     }
236    
237 root 1.72 if (!strcasecmp (buf, "not_permadeth"))
238 root 1.9 {
239     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
240     {
241     settings.not_permadeth = TRUE;
242     }
243     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
244     {
245     settings.not_permadeth = FALSE;
246     }
247     else
248     {
249     LOG (llevError, "load_settings: Unknown value for not_permadeth" ": %s\n", cp);
250     }
251     }
252     else if (!strcasecmp (buf, "resurrection"))
253     {
254     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
255     {
256     settings.resurrection = TRUE;
257     }
258     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
259     {
260     settings.resurrection = FALSE;
261     }
262     else
263     {
264     LOG (llevError, "load_settings: Unknown value for resurrection" ": %s\n", cp);
265     }
266     }
267     else if (!strcasecmp (buf, "set_title"))
268     {
269     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
270     {
271     settings.set_title = TRUE;
272     }
273     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
274     {
275     settings.set_title = FALSE;
276     }
277     else
278     {
279     LOG (llevError, "load_settings: Unknown value for set_title" ": %s\n", cp);
280     }
281     }
282     else if (!strcasecmp (buf, "search_items"))
283     {
284     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
285     {
286     settings.search_items = TRUE;
287     }
288     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
289     {
290     settings.search_items = FALSE;
291     }
292     else
293     {
294     LOG (llevError, "load_settings: Unknown value for search_items" ": %s\n", cp);
295     }
296     }
297     else if (!strcasecmp (buf, "spell_encumbrance"))
298     {
299     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
300     {
301     settings.spell_encumbrance = TRUE;
302     }
303     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
304     {
305     settings.spell_encumbrance = FALSE;
306     }
307     else
308     {
309     LOG (llevError, "load_settings: Unknown value for " "spell_encumbrance: %s\n", cp);
310     }
311     }
312     else if (!strcasecmp (buf, "spell_failure_effects"))
313     {
314     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
315     {
316     settings.spell_failure_effects = TRUE;
317     }
318     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
319     {
320     settings.spell_failure_effects = FALSE;
321     }
322     else
323     {
324     LOG (llevError, "load_settings: Unknown value for " "spell_failure_effects: %s\n", cp);
325     }
326     }
327     else if (!strcasecmp (buf, "spellpoint_level_depend"))
328     {
329     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
330     {
331     settings.spellpoint_level_depend = TRUE;
332     }
333     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
334     {
335     settings.spellpoint_level_depend = FALSE;
336     }
337     else
338     {
339     LOG (llevError, "load_settings: Unknown value for " "spellpoint_level_depend: %s\n", cp);
340     }
341     }
342     else if (!strcasecmp (buf, "stat_loss_on_death"))
343     {
344     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
345     {
346     settings.stat_loss_on_death = TRUE;
347     }
348     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
349     {
350     settings.stat_loss_on_death = FALSE;
351     }
352     else
353     {
354     LOG (llevError, "load_settings: Unknown value for " "stat_loss_on_death: %s\n", cp);
355     }
356     }
357     else if (!strcasecmp (buf, "use_permanent_experience"))
358     {
359     LOG (llevError, "use_permanent_experience is deprecated, use" "permenent_experience_percentage instead\n");
360     }
361     else if (!strcasecmp (buf, "permanent_experience_percentage"))
362     {
363     int val = atoi (cp);
364    
365     if (val < 0 || val > 100)
366     LOG (llevError, "load_settings: permenent_experience_percentage" "must be between 0 and 100, %d is invalid\n", val);
367     else
368     settings.permanent_exp_ratio = val;
369     }
370     else if (!strcasecmp (buf, "death_penalty_percentage"))
371     {
372     int val = atoi (cp);
373    
374     if (val < 0 || val > 100)
375     LOG (llevError, "load_settings: death_penalty_percentage" "must be between 0 and 100, %d is invalid\n", val);
376     else
377     settings.death_penalty_ratio = val;
378     }
379     else if (!strcasecmp (buf, "death_penalty_levels"))
380     {
381     int val = atoi (cp);
382    
383     if (val < 0 || val > 255)
384     LOG (llevError, "load_settings: death_penalty_levels" "can not be negative, %d is invalid\n", val);
385     else
386     settings.death_penalty_level = val;
387     }
388     else if (!strcasecmp (buf, "balanced_stat_loss"))
389     {
390     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
391     {
392     settings.balanced_stat_loss = TRUE;
393     }
394     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
395     {
396     settings.balanced_stat_loss = FALSE;
397     }
398     else
399     {
400     LOG (llevError, "load_settings: Unknown value for " "balanced_stat_loss: %s\n", cp);
401     }
402     }
403     else if (!strcasecmp (buf, "simple_exp"))
404     {
405     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
406     {
407     settings.simple_exp = TRUE;
408     }
409     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
410     {
411     settings.simple_exp = FALSE;
412     }
413     else
414     {
415     LOG (llevError, "load_settings: Unknown value for simple_exp: %s\n", cp);
416     }
417     }
418     else if (!strcasecmp (buf, "item_power_factor"))
419     {
420     float tmp = atof (cp);
421    
422     if (tmp < 0)
423     LOG (llevError, "load_settings: item_power_factor must be a positive number (%f < 0)\n", tmp);
424     else
425     settings.item_power_factor = tmp;
426     }
427     else if (!strcasecmp (buf, "pk_luck_penalty"))
428     {
429     sint16 val = atoi (cp);
430    
431     if (val < -100 || val > 100)
432     LOG (llevError, "load_settings: pk_luck_penalty must be between -100 and 100" ", %d is invalid\n", val);
433     else
434     settings.pk_luck_penalty = val;
435     }
436     else if (!strcasecmp (buf, "set_friendly_fire"))
437     {
438     int val = atoi (cp);
439 elmex 1.1
440 root 1.9 if (val < 0 || val > 100)
441     LOG (llevError, "load_settings: set_friendly_fire must be between 0 an 100" ", %d is invalid\n", val);
442     else
443     settings.set_friendly_fire = val;
444     }
445     else if (!strcasecmp (buf, "armor_max_enchant"))
446     {
447     int max_e = atoi (cp);
448    
449     if (max_e <= 0)
450     LOG (llevError, "load_settings: armor_max_enchant is %d\n", max_e);
451     else
452 elmex 1.1 settings.armor_max_enchant = max_e;
453 root 1.9 }
454     else if (!strcasecmp (buf, "armor_weight_reduction"))
455     {
456     int wr = atoi (cp);
457    
458     if (wr < 0)
459     LOG (llevError, "load_settings: armor_weight_reduction is %d\n", wr);
460     else
461 elmex 1.1 settings.armor_weight_reduction = wr;
462     }
463 root 1.9 else if (!strcasecmp (buf, "armor_weight_linear"))
464     {
465     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
466     {
467     settings.armor_weight_linear = TRUE;
468     }
469     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
470     {
471     settings.armor_weight_linear = FALSE;
472     }
473     else
474     {
475     LOG (llevError, "load_settings: unknown value for armor_weight_linear: %s\n", cp);
476     }
477    
478     }
479     else if (!strcasecmp (buf, "armor_speed_improvement"))
480     {
481     int wr = atoi (cp);
482 elmex 1.1
483 root 1.9 if (wr < 0)
484     LOG (llevError, "load_settings: armor_speed_improvement is %d\n", wr);
485     else
486 elmex 1.1 settings.armor_speed_improvement = wr;
487     }
488 root 1.9 else if (!strcasecmp (buf, "armor_speed_linear"))
489     {
490     if (!strcasecmp (cp, "on") || !strcasecmp (cp, "true"))
491     {
492     settings.armor_speed_linear = TRUE;
493     }
494     else if (!strcasecmp (cp, "off") || !strcasecmp (cp, "false"))
495     {
496     settings.armor_speed_linear = FALSE;
497     }
498     else
499     {
500     LOG (llevError, "load_settings: unknown value for armor_speed_linear: %s\n", cp);
501     }
502    
503     }
504     else
505 root 1.50 LOG (llevError, "Unknown value in settings file: %s\n", buf);
506 elmex 1.1 }
507 root 1.20
508 root 1.9 close_and_delete (fp, comp);
509 elmex 1.1 }
510    
511     /*
512     * init() is called only once, when starting the program.
513     */
514 root 1.9 void
515     init (int argc, char **argv)
516     {
517 root 1.37 init_done = 0; /* Must be done before init_signal() */
518 root 1.36
519 root 1.42 init_environ ();
520 root 1.14 cfperl_init ();
521 root 1.9 init_done = 1;
522 elmex 1.1 }
523    
524 root 1.9 void
525     usage (void)
526     {
527 root 1.62 fprintf (stderr, "Usage: deliantra-server [-h] [-<flags>]...\n");
528 elmex 1.1 }
529    
530 root 1.9 void
531     help (void)
532     {
533    
534 elmex 1.1 /* The information in usage is redundant with what is given below, so why call it? */
535 root 1.9
536 elmex 1.1 /* usage();*/
537 root 1.9 printf ("Flags:\n");
538     printf (" -csport <port> Specifies the port to use for the new client/server code.\n");
539     printf (" -d Turns on some debugging.\n");
540     printf (" +d Turns off debugging (useful if server compiled with debugging\n");
541     printf (" as default).\n");
542     printf (" -detach The server will go in the background, closing all\n");
543     printf (" connections to the tty.\n");
544     printf (" -h Display this information.\n");
545     printf (" -log <file> Specifies which file to send output to.\n");
546     printf (" Only has meaning if -detach is specified.\n");
547     printf (" -mon Turns on monster debugging.\n");
548     printf (" -o Prints out info on what was defined at compile time.\n");
549     printf (" -s Display the high-score list.\n");
550     printf (" -score <name or class> Displays all high scores with matching name/class.\n");
551     printf (" -v Print version and contributors.\n");
552     printf (" -data Sets the lib dir (archetypes, treasures, etc.)\n");
553     printf (" -local Read/write local data (hiscore, unique items, etc.)\n");
554     printf (" -maps Sets the directory for maps.\n");
555     printf (" -arch Sets the archetype file to use.\n");
556     printf (" -regions Sets the regions file to use.\n");
557     printf (" -playerdir Sets the directory for the player files.\n");
558     printf (" -templatedir Sets the directory for template generate maps.\n");
559     printf (" -treasures Sets the treasures file to use.\n");
560     printf (" -uniquedir Sets the unique items/maps directory.\n");
561     printf (" -tmpdir Sets the directory for temporary files (mostly maps.)\n");
562     printf (" -m Lists out suggested experience for all monsters.\n");
563     printf (" -m2 Dumps out abilities.\n");
564     printf (" -m3 Dumps out artifact information.\n");
565     printf (" -m4 Dumps out spell information.\n");
566     printf (" -m5 Dumps out skill information.\n");
567     printf (" -m6 Dumps out race information.\n");
568     printf (" -m7 Dumps out alchemy information.\n");
569     printf (" -m8 Dumps out gods information.\n");
570     printf (" -m9 Dumps out more alchemy information (formula checking).\n");
571     printf (" -mt <name> Dumps out list of treasures for a monster.\n");
572     exit (0);
573     }
574    
575     void
576     init_beforeplay (void)
577     {
578     init_artifacts (); /* If not called before, reads all artifacts from file */
579     init_races (); /* overwrite race designations using entries in lib/races file */
580     init_gods (); /* init linked list of gods from archs */
581     init_readable (); /* inits useful arrays for readable texts */
582     init_formulae (); /* If not called before, reads formulae from file */
583 elmex 1.1 }
584    
585     /* Signal handlers: */
586    
587 root 1.48 static void
588 root 1.33 rec_sigabrt (int i)
589     {
590     signal (SIGABRT, SIG_DFL);
591    
592     LOG (llevError, "SIGABRT received.\n");
593     cleanup ("SIGABRT received", 1);
594     }
595    
596 root 1.48 static void
597 root 1.9 rec_sigsegv (int i)
598     {
599 root 1.33 signal (SIGSEGV, SIG_DFL);
600    
601 root 1.21 LOG (llevError, "SIGSEGV received.\n");
602 root 1.29 cleanup ("SIGSEGV received", 1);
603 elmex 1.1 }
604    
605 root 1.48 static void
606 root 1.9 rec_sigquit (int i)
607     {
608 root 1.33 signal (SIGQUIT, SIG_IGN);
609    
610 root 1.21 LOG (llevInfo, "SIGQUIT received\n");
611 root 1.29 cleanup ("SIGQUIT received", 1);
612 elmex 1.1 }
613    
614 root 1.48 static void
615 root 1.9 rec_sigbus (int i)
616     {
617 root 1.33 signal (SIGBUS, SIG_DFL);
618    
619 root 1.21 LOG (llevError, "SIGBUS received\n");
620 root 1.29 cleanup ("SIGBUS received", 1);
621 elmex 1.1 }
622    
623 root 1.9 void
624 root 1.48 reset_signals ()
625     {
626     signal (SIGABRT, SIG_DFL);
627     signal (SIGQUIT, SIG_DFL);
628     signal (SIGSEGV, SIG_DFL);
629     signal (SIGBUS , SIG_DFL);
630     signal (SIGINT , SIG_DFL);
631     signal (SIGTERM, SIG_DFL);
632     }
633    
634     void
635 root 1.9 init_signals (void)
636     {
637 root 1.37 // large stack, but it's important data we want to save, and it is not usually
638     // being physically allocated anyways
639     const size_t stacksize = 8 * 1024 * 1024 + SIGSTKSZ;
640    
641     stack_t ss;
642     ss.ss_sp = malloc (stacksize);
643     ss.ss_flags = 0;
644     ss.ss_size = stacksize;
645     sigaltstack (&ss, 0);
646    
647     struct sigaction sa;
648    
649     sigfillset (&sa.sa_mask);
650 root 1.49 sa.sa_flags = SA_RESTART;
651 root 1.37
652     sa.sa_handler = SIG_IGN; sigaction (SIGPIPE, &sa, 0);
653     sa.sa_handler = rec_sigabrt; sigaction (SIGABRT, &sa, 0);
654     sa.sa_handler = rec_sigquit; sigaction (SIGQUIT, &sa, 0);
655 root 1.49 sa.sa_handler = rec_sigbus; sigaction (SIGBUS, &sa, 0);
656    
657     sa.sa_flags |= SA_ONSTACK;
658 root 1.37 sa.sa_handler = rec_sigsegv; sigaction (SIGSEGV, &sa, 0);
659 elmex 1.1 }
660    
661     /* init_races() - reads the races file in the lib/ directory, then
662     * overwrites old 'race' entries. This routine allow us to quickly
663     * re-configure the 'alignment' of monsters, objects. Useful for
664     * putting together lists of creatures, etc that belong to gods.
665     */
666 root 1.9 void
667     init_races (void)
668 elmex 1.8 {
669 elmex 1.1 FILE *file;
670     char race[MAX_BUF], fname[MAX_BUF], buf[MAX_BUF], *cp, variable[MAX_BUF];
671 elmex 1.8 archetype *mon = NULL;
672     static int init_done = 0;
673 elmex 1.1
674 elmex 1.8 if (init_done)
675 elmex 1.1 return;
676 elmex 1.8 init_done = 1;
677 root 1.10 first_race = 0;
678 elmex 1.1
679 elmex 1.8 sprintf (fname, "%s/races", settings.datadir);
680 pippijn 1.25 LOG (llevDebug, "Reading races from %s...\n", fname);
681 elmex 1.8 if (!(file = fopen (fname, "r")))
682     {
683 root 1.9 LOG (llevError, "Cannot open races file %s: %s\n", fname, strerror (errno));
684 elmex 1.8 return;
685 elmex 1.1 }
686 elmex 1.8
687     while (fgets (buf, MAX_BUF, file) != NULL)
688     {
689     int set_race = 1, set_list = 1;
690 root 1.9
691 elmex 1.8 if (*buf == '#')
692     continue;
693 root 1.10
694 elmex 1.8 if ((cp = strchr (buf, '\n')) != NULL)
695     *cp = '\0';
696 root 1.10
697 elmex 1.8 cp = buf;
698     while (*cp == ' ' || *cp == '!' || *cp == '@')
699     {
700 root 1.65 if (*cp == '!') set_race = 0;
701     if (*cp == '@') set_list = 0;
702    
703 elmex 1.8 cp++;
704     }
705 root 1.10
706 elmex 1.8 if (sscanf (cp, "RACE %s", variable))
707 root 1.40 /* set new race value */
708     strcpy (race, variable);
709 elmex 1.8 else
710     {
711     char *cp1;
712 root 1.9
713 elmex 1.8 /* Take out beginning spaces */
714     for (cp1 = cp; *cp1 == ' '; cp1++)
715     ;
716     /* Remove newline and trailing spaces */
717     for (cp1 = cp + strlen (cp) - 1; *cp1 == '\n' || *cp1 == ' '; cp1--)
718     {
719     *cp1 = '\0';
720     if (cp == cp1)
721     break;
722     }
723    
724     if (cp[strlen (cp) - 1] == '\n')
725     cp[strlen (cp) - 1] = '\0';
726 root 1.10
727 elmex 1.8 /* set creature race to race value */
728 root 1.12 if ((mon = archetype::find (cp)) == NULL)
729 pippijn 1.25 LOG (llevError, "Creature %s in race file lacks archetype\n", cp);
730 elmex 1.8 else
731     {
732 root 1.70 if (set_race && (!mon->race || strcmp (&mon->race, race)))
733 elmex 1.8 {
734 root 1.54 if (mon->race)
735     LOG (llevDebug, "Resetting race to %s from %s for archetype %s\n", race, &mon->race, &mon->archname);
736 root 1.10
737 root 1.54 mon->race = race;
738 elmex 1.1 }
739 root 1.10
740 elmex 1.8 /* if the arch is a monster, add it to the race list */
741 root 1.54 if (set_list && QUERY_FLAG (mon, FLAG_MONSTER))
742     add_to_racelist (race, mon);
743 elmex 1.8 }
744 elmex 1.1 }
745     }
746 root 1.10
747 elmex 1.8 fclose (file);
748     LOG (llevDebug, "done.\n");
749 elmex 1.1 }
750    
751 root 1.9 void
752     dump_races (void)
753     {
754     racelink *list;
755     objectlink *tmp;
756    
757     for (list = first_race; list; list = list->next)
758     {
759 root 1.10 fprintf (stderr, "\nRACE %s:\t", &list->name);
760 root 1.9 for (tmp = list->member; tmp; tmp = tmp->next)
761 root 1.53 fprintf (stderr, "%s(%d), ", &tmp->ob->arch->archname, tmp->ob->level);
762 elmex 1.1 }
763 root 1.10
764 root 1.9 fprintf (stderr, "\n");
765 elmex 1.1 }
766    
767 root 1.9 void
768     add_to_racelist (const char *race_name, object *op)
769     {
770 elmex 1.1 racelink *race;
771 root 1.9
772     if (!op || !race_name)
773     return;
774 root 1.10
775 root 1.9 race = find_racelink (race_name);
776    
777     if (!race)
778     { /* add in a new race list */
779     race = get_racelist ();
780     race->next = first_race;
781     first_race = race;
782     race->name = race_name;
783     }
784    
785     if (race->member->ob)
786     {
787     objectlink *tmp = get_objectlink ();
788    
789     tmp->next = race->member;
790     race->member = tmp;
791     }
792 root 1.10
793 elmex 1.1 race->nrof++;
794     race->member->ob = op;
795     }
796    
797 root 1.9 racelink *
798     get_racelist ()
799     {
800 root 1.10 racelink *list = new racelink;
801 root 1.9
802 root 1.10 list->name = 0;
803 root 1.9 list->nrof = 0;
804 root 1.10 list->next = 0;
805 root 1.9 list->member = get_objectlink ();
806 elmex 1.1
807     return list;
808     }
809 root 1.9
810     racelink *
811     find_racelink (const char *name)
812     {
813 root 1.10 if (name)
814     for (racelink *link = first_race; link; link = link->next)
815     if (!link->name || !strcmp (name, link->name))
816     return link;
817 root 1.9
818 root 1.10 return 0;
819 elmex 1.1 }