ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/init.C
Revision: 1.56
Committed: Sun Jul 1 05:00:20 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.55: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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