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

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
4 * 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 *
8 * 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 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 */
23
24 #include <global.h>
25 #include <material.h>
26 #include <loader.h>
27 #include <sproto.h>
28
29 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 }
216 }
217
218 /* Most of this is shamelessly stolen from XSysStats. But since that is
219 * also my program, no problem.
220 */
221 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 };
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 * initialise any data.
242 */
243 {"-h", 0, 1, help},
244
245 /* Honor -help also, since it is somewhat common */
246 {"-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
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 {"-csport", 1, 2, (void (*)()) set_csport},
268 {"-detach", 0, 2, set_daemon},
269
270 /* Start of pass 3 information. In theory, by pass 3, all data paths
271 * and defaults should have been set up.
272 */
273 {"-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 };
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 static void
294 parse_args (int argc, char *argv[], int pass)
295 {
296 size_t i;
297 int on_arg = 1;
298
299 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 }
313 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 }
320 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 }
328 }
329 else
330 { /* takes no args */
331 options[i].func ();
332 on_arg++;
333 }
334 break;
335 }
336 }
337 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 }
343 }
344 }
345
346 //TODO: make this a constructor
347 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 }
362 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 char filename[MAX_BUF];
379 materialtype_t *mt;
380
381 sprintf (filename, "%s/materials", settings.datadir);
382 LOG (llevDebug, "Reading material type data from %s...\n", filename);
383
384 object_thawer thawer (filename);
385
386 if (!thawer)
387 {
388 LOG (llevError, "Cannot open %s for reading\n", filename);
389 mt = get_empty_mat ();
390 mt->next = 0;
391 materialt = mt;
392 return;
393 }
394
395 mt = get_empty_mat ();
396 materialt = mt;
397
398 for (;;)
399 {
400 thawer.next ();
401
402 switch (thawer.kw)
403 {
404 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 {
428 const char *cp = thawer.get_str () - 1;
429
430 for (int i = 0; i < NROFATTACKS; i++)
431 {
432 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 }
444 }
445 break;
446
447 case KW_mods:
448 {
449 const char *cp = thawer.get_str () - 1;
450
451 for (int i = 0; i < NROFATTACKS; i++)
452 {
453 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 }
465 }
466 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 if (!thawer.parse_error ("materials file", "materials"))
486 goto done;
487 break;
488 }
489 }
490
491 done:
492 if (mt->next)
493 {
494 delete mt->next;
495
496 mt->next = 0;
497 }
498
499 LOG (llevDebug, "Done.\n");
500 }
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 static void
507 load_settings (void)
508 {
509 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 if (!(fp = open_and_uncompress (buf, 0, &comp)))
520 {
521 LOG (llevError, "Error: No settings file found\n");
522 exit (1);
523 }
524
525 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 cp = (char *)"";
549 has_val = 0;
550 }
551
552 if (!strcasecmp (buf, "motd"))
553 {
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
841 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 settings.armor_max_enchant = max_e;
854 }
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 settings.armor_weight_reduction = wr;
863 }
864 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
884 if (wr < 0)
885 LOG (llevError, "load_settings: armor_speed_improvement is %d\n", wr);
886 else
887 settings.armor_speed_improvement = wr;
888 }
889 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 LOG (llevError, "Unknown value in settings file: %s\n", buf);
907 }
908
909 close_and_delete (fp, comp);
910 }
911
912 /*
913 * init() is called only once, when starting the program.
914 */
915 void
916 init (int argc, char **argv)
917 {
918 init_done = 0; /* Must be done before init_signal() */
919 rndm.seed (time (0));
920
921 logfile = stderr;
922 init_environ ();
923 parse_args (argc, argv, 1); /* First arg pass - right now it does
924 * nothing, but in future specifying the
925 * LibDir in this pass would be reasonable*/
926
927 init_anim (); // Must be called before perl
928 cfperl_init ();
929 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 fprintf (logfile, "Copyright (C) 2005, 2006, 2007 Marc Lehmann.\n");
935 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 }
943
944 init_startup (); /* Write (C), check shutdown/forbid files */
945 init_uuid ();
946 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 }
955
956 void
957 usage (void)
958 {
959 (void) fprintf (logfile, "Usage: crossfire [-h] [-<flags>]...\n");
960 }
961
962 void
963 help (void)
964 {
965
966 /* The information in usage is redundant with what is given below, so why call it? */
967
968 /* usage();*/
969 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 }
1018
1019 void
1020 init_startup (void)
1021 {
1022 char buf[MAX_BUF];
1023 FILE *fp;
1024 int comp;
1025
1026 #ifdef SHUTDOWN_FILE
1027 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 #endif
1036
1037 if (forbid_play ())
1038 { /* Maybe showing highscore should be allowed? */
1039 LOG (llevError, "CrossFire: Playing not allowed.\n");
1040 exit (-1);
1041 }
1042 }
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 void
1051 compile_info (void)
1052 {
1053 int i = 0;
1054
1055 printf ("Non-standard include files:\n");
1056 #if !defined (__STRICT_ANSI__) || defined (__sun__)
1057 # 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 #endif
1066 #ifndef __STRICT_ANSI__
1067 # ifndef MACH
1068 printf ("<memory.h\n");
1069 i = 1;
1070 # endif
1071 #endif
1072 #ifndef sgi
1073 printf ("<sys/timeb.h>\n");
1074 i = 1;
1075 #endif
1076 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 #ifdef PERM_FILE
1081 printf ("Perm file:\t<ETC>/%s\n", PERM_FILE);
1082 #endif
1083 #ifdef SHUTDOWN_FILE
1084 printf ("Shutdown file:\t<ETC>/%s\n", SHUTDOWN_FILE);
1085 #endif
1086 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 #ifdef USE_CALLOC
1092 printf ("Use_calloc:\t<true>\n");
1093 #else
1094 printf ("Use_calloc:\t<false>\n");
1095 #endif
1096
1097 #ifdef X_EDITOR
1098 printf ("Editor:\t\t%s\n", X_EDITOR);
1099 #endif
1100
1101 printf ("Max_time:\t%d\n", MAX_TIME);
1102
1103 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 }
1107
1108 /* Signal handlers: */
1109
1110 static void
1111 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 static void
1120 rec_sigsegv (int i)
1121 {
1122 signal (SIGSEGV, SIG_DFL);
1123
1124 LOG (llevError, "SIGSEGV received.\n");
1125 cleanup ("SIGSEGV received", 1);
1126 }
1127
1128 static void
1129 rec_sigquit (int i)
1130 {
1131 signal (SIGQUIT, SIG_IGN);
1132
1133 LOG (llevInfo, "SIGQUIT received\n");
1134 cleanup ("SIGQUIT received", 1);
1135 }
1136
1137 static void
1138 rec_sigbus (int i)
1139 {
1140 signal (SIGBUS, SIG_DFL);
1141
1142 LOG (llevError, "SIGBUS received\n");
1143 cleanup ("SIGBUS received", 1);
1144 }
1145
1146 void
1147 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 init_signals (void)
1159 {
1160 // 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 sa.sa_flags = SA_RESTART;
1174
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 sa.sa_handler = rec_sigbus; sigaction (SIGBUS, &sa, 0);
1179
1180 sa.sa_flags |= SA_ONSTACK;
1181 sa.sa_handler = rec_sigsegv; sigaction (SIGSEGV, &sa, 0);
1182 }
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 void
1190 init_races (void)
1191 {
1192 FILE *file;
1193 char race[MAX_BUF], fname[MAX_BUF], buf[MAX_BUF], *cp, variable[MAX_BUF];
1194 archetype *mon = NULL;
1195 static int init_done = 0;
1196
1197 if (init_done)
1198 return;
1199 init_done = 1;
1200 first_race = 0;
1201
1202 sprintf (fname, "%s/races", settings.datadir);
1203 LOG (llevDebug, "Reading races from %s...\n", fname);
1204 if (!(file = fopen (fname, "r")))
1205 {
1206 LOG (llevError, "Cannot open races file %s: %s\n", fname, strerror (errno));
1207 return;
1208 }
1209
1210 while (fgets (buf, MAX_BUF, file) != NULL)
1211 {
1212 int set_race = 1, set_list = 1;
1213
1214 if (*buf == '#')
1215 continue;
1216
1217 if ((cp = strchr (buf, '\n')) != NULL)
1218 *cp = '\0';
1219
1220 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
1230 if (sscanf (cp, "RACE %s", variable))
1231 /* set new race value */
1232 strcpy (race, variable);
1233 else
1234 {
1235 char *cp1;
1236
1237 /* 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
1251 /* set creature race to race value */
1252 if ((mon = archetype::find (cp)) == NULL)
1253 LOG (llevError, "Creature %s in race file lacks archetype\n", cp);
1254 else
1255 {
1256 if (set_race && (!mon->race || strcmp (mon->race, race)))
1257 {
1258 if (mon->race)
1259 LOG (llevDebug, "Resetting race to %s from %s for archetype %s\n", race, &mon->race, &mon->archname);
1260
1261 mon->race = race;
1262 }
1263
1264 /* if the arch is a monster, add it to the race list */
1265 if (set_list && QUERY_FLAG (mon, FLAG_MONSTER))
1266 add_to_racelist (race, mon);
1267 }
1268 }
1269 }
1270
1271 fclose (file);
1272 LOG (llevDebug, "done.\n");
1273 }
1274
1275 void
1276 dump_races (void)
1277 {
1278 racelink *list;
1279 objectlink *tmp;
1280
1281 for (list = first_race; list; list = list->next)
1282 {
1283 fprintf (stderr, "\nRACE %s:\t", &list->name);
1284 for (tmp = list->member; tmp; tmp = tmp->next)
1285 fprintf (stderr, "%s(%d), ", &tmp->ob->arch->archname, tmp->ob->level);
1286 }
1287
1288 fprintf (stderr, "\n");
1289 }
1290
1291 void
1292 add_to_racelist (const char *race_name, object *op)
1293 {
1294 racelink *race;
1295
1296 if (!op || !race_name)
1297 return;
1298
1299 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
1317 race->nrof++;
1318 race->member->ob = op;
1319 }
1320
1321 racelink *
1322 get_racelist ()
1323 {
1324 racelink *list = new racelink;
1325
1326 list->name = 0;
1327 list->nrof = 0;
1328 list->next = 0;
1329 list->member = get_objectlink ();
1330
1331 return list;
1332 }
1333
1334 racelink *
1335 find_racelink (const char *name)
1336 {
1337 if (name)
1338 for (racelink *link = first_race; link; link = link->next)
1339 if (!link->name || !strcmp (name, link->name))
1340 return link;
1341
1342 return 0;
1343 }