00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034 #include <global.h>
00035 #include <loader.h>
00036 #include <version.h>
00037 #ifndef __CEXTRACT__
00038 #include <sproto.h>
00039 #endif
00040
00041
00042 #include <strings.h>
00043
00044 static void help(void);
00045 static void usage(void);
00046 static void init_beforeplay(void);
00047 static void init_startup(void);
00048 static void compile_info(void);
00049 static void init_signals(void);
00050 static void init_races(void);
00051 static void dump_races(void);
00052 static void add_to_racelist(const char *race_name, object *op);
00053 static racelink *get_racelist(void);
00054 static void fatal_signal(int make_core);
00055
00057 static char default_daemon_log[] = "logfile";
00058
00059 static void set_logfile(char *val) {
00060 settings.logfilename = val;
00061 }
00062
00063 static void call_version(void) {
00064 version(NULL);
00065 exit(0);
00066 }
00067
00068 static void showscores(void) {
00069 display_high_score(NULL, 9999, NULL);
00070 exit(0);
00071 }
00072
00073 static void set_debug(void) {
00074 settings.debug = llevDebug;
00075 }
00076
00077 static void unset_debug(void) {
00078 settings.debug = llevInfo;
00079 }
00080
00081 static void set_mondebug(void) {
00082 settings.debug = llevMonster;
00083 }
00084
00085 static void set_dumpmon1(void) {
00086 settings.dumpvalues = 1;
00087 }
00088
00089 static void set_dumpmon2(void) {
00090 settings.dumpvalues = 2;
00091 }
00092
00093 static void set_dumpmon3(void) {
00094 settings.dumpvalues = 3;
00095 }
00096
00097 static void set_dumpmon4(void) {
00098 settings.dumpvalues = 4;
00099 }
00100
00101 static void set_dumpmon5(void) {
00102 settings.dumpvalues = 5;
00103 }
00104
00105 static void set_dumpmon6(void) {
00106 settings.dumpvalues = 6;
00107 }
00108
00109 static void set_dumpmon7(void) {
00110 settings.dumpvalues = 7;
00111 }
00112
00113 static void set_dumpmon8(void) {
00114 settings.dumpvalues = 8;
00115 }
00116
00117 static void set_dumpmon9(void) {
00118 settings.dumpvalues = 9;
00119 }
00120
00121 static void set_dumpmont(const char *name) {
00122 settings.dumpvalues = 10;
00123 settings.dumparg = name;
00124 }
00125
00126 static void set_daemon(void) {
00127 settings.daemonmode = 1;
00128 if (settings.logfilename[0] == '\0') {
00129 settings.logfilename = default_daemon_log;
00130 }
00131 }
00132
00133 static void set_datadir(const char *path) {
00134 settings.datadir = path;
00135 }
00136
00137 static void set_confdir(const char *path) {
00138 settings.confdir = path;
00139 }
00140
00141 static void set_localdir(const char *path) {
00142 settings.localdir = path;
00143 }
00144
00145 static void set_mapdir(const char *path) {
00146 settings.mapdir = path;
00147 }
00148
00149 static void set_archetypes(const char *path) {
00150 settings.archetypes = path;
00151 }
00152
00153 static void set_regions(const char *path) {
00154 settings.regions = path;
00155 }
00156
00157 static void set_treasures(const char *path) {
00158 settings.treasures = path;
00159 }
00160
00161 static void set_uniquedir(const char *path) {
00162 settings.uniquedir = path;
00163 }
00164
00165 static void set_templatedir(const char *path) {
00166 settings.templatedir = path;
00167 }
00168
00169 static void set_playerdir(const char *path) {
00170 settings.playerdir = path;
00171 }
00172
00173 static void set_tmpdir(const char *path) {
00174 settings.tmpdir = path;
00175 }
00176
00177 static void free_races(void);
00178
00179 static void free_materials(void);
00180
00181 static void showscoresparm(const char *data) {
00182 display_high_score(NULL, 9999, data);
00183 exit(0);
00184 }
00185
00192 static void set_csport(const char *val) {
00193 settings.csport = atoi(val);
00194 #ifndef WIN32
00195 if (settings.csport <= 0
00196 || settings.csport > 32765
00197 || (settings.csport < 1024 && getuid() != 0)) {
00198 LOG(llevError, "%d is an invalid csport number.\n", settings.csport);
00199 exit(1);
00200 }
00201 #endif
00202 }
00203
00206 typedef void (*cmdlinefunc_args0)(void);
00207 typedef void (*cmdlinefunc_args1)(const char* arg1);
00208 typedef void (*cmdlinefunc_args2)(const char* arg1, const char* arg2);
00216 struct Command_Line_Options {
00217 const char *cmd_option;
00218 uint8 num_args;
00219 uint8 pass;
00220 void (*func)();
00224 };
00225
00234 static struct Command_Line_Options options[] = {
00238 { "-h", 0, 1, help },
00239
00240 { "-help", 0, 1, help },
00241 { "-v", 0, 1, call_version },
00242 { "-d", 0, 1, set_debug },
00243 { "+d", 0, 1, unset_debug },
00244 { "-mon", 0, 1, set_mondebug },
00245 { "-data", 1, 1, set_datadir },
00246 { "-conf", 1, 1, set_confdir },
00247 { "-local", 1, 1, set_localdir },
00248 { "-maps", 1, 1, set_mapdir },
00249 { "-arch", 1, 1, set_archetypes },
00250 { "-regions", 1, 1, set_regions },
00251 { "-playerdir", 1, 1, set_playerdir },
00252 { "-treasures", 1, 1, set_treasures },
00253 { "-uniquedir", 1, 1, set_uniquedir },
00254 { "-templatedir", 1, 1, set_templatedir },
00255 { "-tmpdir", 1, 1, set_tmpdir },
00256 { "-log", 1, 1, set_logfile },
00257 { "-detach", 0, 1, set_daemon },
00258
00259 #ifdef WIN32
00260
00261 { "-regsrv", 0, 1, service_register },
00262 { "-unregsrv", 0, 1, service_unregister },
00263 { "-srv", 0, 1, service_handle },
00264 #endif
00265
00269 { "-csport", 1, 2, set_csport },
00270
00274 { "-o", 0, 3, compile_info },
00275 { "-m", 0, 3, set_dumpmon1 },
00276 { "-m2", 0, 3, set_dumpmon2 },
00277 { "-m3", 0, 3, set_dumpmon3 },
00278 { "-m4", 0, 3, set_dumpmon4 },
00279 { "-m5", 0, 3, set_dumpmon5 },
00280 { "-m6", 0, 3, set_dumpmon6 },
00281 { "-m7", 0, 3, set_dumpmon7 },
00282 { "-m8", 0, 3, set_dumpmon8 },
00283 { "-m9", 0, 3, set_dumpmon9 },
00284 { "-mt", 1, 3, set_dumpmont },
00285 { "-mexp", 0, 3, dump_experience },
00286 { "-s", 0, 3, showscores },
00287 { "-score", 1, 3, showscoresparm }
00288 };
00289
00304 static void parse_args(int argc, char *argv[], int pass) {
00305 size_t i;
00306 int on_arg = 1;
00307
00308 while (on_arg < argc) {
00309 for (i = 0; i < sizeof(options)/sizeof(struct Command_Line_Options); i++) {
00310 if (!strcmp(options[i].cmd_option, argv[on_arg])) {
00311
00312
00313
00314 if (options[i].pass != pass) {
00315 on_arg += options[i].num_args+1;
00316 break;
00317 }
00318 if (options[i].num_args) {
00319 if ((on_arg+options[i].num_args) >= argc) {
00320 fprintf(stderr, "%s requires an argument.\n", options[i].cmd_option);
00321 exit(1);
00322 } else {
00323 if (options[i].num_args == 1)
00324 ((cmdlinefunc_args1)options[i].func)(argv[on_arg+1]);
00325 if (options[i].num_args == 2)
00326 ((cmdlinefunc_args2)options[i].func)(argv[on_arg+1], argv[on_arg+2]);
00327 on_arg += options[i].num_args+1;
00328 }
00329 } else {
00330 ((cmdlinefunc_args0)options[i].func)();
00331 on_arg++;
00332 }
00333 break;
00334 }
00335 }
00336 if (i == sizeof(options)/sizeof(struct Command_Line_Options)) {
00337 fprintf(stderr, "Unknown option: %s\n", argv[on_arg]);
00338 usage();
00339 exit(1);
00340 }
00341 }
00342 }
00343
00345 materialtype_t *materialt;
00346
00355 static materialtype_t *get_empty_mat(void) {
00356 materialtype_t *mt;
00357 int i;
00358
00359 mt = (materialtype_t *)malloc(sizeof(materialtype_t));
00360 if (mt == NULL)
00361 fatal(OUT_OF_MEMORY);
00362 mt->name = NULL;
00363 mt->description = NULL;
00364 for (i = 0; i < NROFATTACKS; i++) {
00365 mt->save[i] = 0;
00366 mt->mod[i] = 0;
00367 }
00368 mt->chance = 0;
00369 mt->difficulty = 0;
00370 mt->magic = 0;
00371 mt->damage = 0;
00372 mt->wc = 0;
00373 mt->ac = 0;
00374 mt->sp = 0;
00375 mt->weight = 100;
00376 mt->value = 100;
00377 mt->next = NULL;
00378 return mt;
00379 }
00380
00385 static void load_materials(void) {
00386 char buf[MAX_BUF], filename[MAX_BUF], *cp, *next;
00387 FILE *fp;
00388 materialtype_t *mt;
00389 int i, value;
00390
00391 snprintf(filename, sizeof(filename), "%s/materials", settings.datadir);
00392 LOG(llevDebug, "Reading material type data from %s...\n", filename);
00393 if ((fp = fopen(filename, "r")) == NULL) {
00394 LOG(llevError, "Cannot open %s for reading\n", filename);
00395 mt = get_empty_mat();
00396 mt->next = NULL;
00397 materialt = mt;
00398 return;
00399 }
00400 mt = get_empty_mat();
00401 materialt = mt;
00402 while (fgets(buf, MAX_BUF, fp) != NULL) {
00403 if (*buf == '#')
00404 continue;
00405 if ((cp = strchr(buf, '\n')) != NULL)
00406 *cp = '\0';
00407 cp = buf;
00408 while (*cp == ' ')
00409 cp++;
00410 if (!strncmp(cp, "name", 4)) {
00411
00412 if (mt->next != NULL) {
00413 if (mt->description == NULL)
00414 mt->description = add_string(mt->name);
00415 mt = mt->next;
00416 }
00417 mt->next = get_empty_mat();
00418 mt->name = add_string(strchr(cp, ' ')+1);
00419 } else if (!strncmp(cp, "description", 11)) {
00420 mt->description = add_string(strchr(cp, ' ')+1);
00421 } else if (sscanf(cp, "material %d", &value)) {
00422 mt->material = value;
00423 } else if (!strncmp(cp, "saves", 5)) {
00424 cp = strchr(cp, ' ')+1;
00425 for (i = 0; i < NROFATTACKS; i++) {
00426 if (cp == NULL) {
00427 mt->save[i] = 0;
00428 continue;
00429 }
00430 if ((next = strchr(cp, ',')) != NULL)
00431 *(next++) = '\0';
00432 sscanf(cp, "%d", &value);
00433 mt->save[i] = (sint8)value;
00434 cp = next;
00435 }
00436 } else if (!strncmp(cp, "mods", 4)) {
00437 cp = strchr(cp, ' ')+1;
00438 for (i = 0; i < NROFATTACKS; i++) {
00439 if (cp == NULL) {
00440 mt->save[i] = 0;
00441 continue;
00442 }
00443 if ((next = strchr(cp, ',')) != NULL)
00444 *(next++) = '\0';
00445 sscanf(cp, "%d", &value);
00446 mt->mod[i] = (sint8)value;
00447 cp = next;
00448 }
00449 } else if (sscanf(cp, "chance %d\n", &value)) {
00450 mt->chance = (sint8)value;
00451 } else if (sscanf(cp, "diff %d\n", &value)) {
00452 mt->difficulty = (sint8)value;
00453 } else if (sscanf(cp, "magic %d\n", &value)) {
00454 mt->magic = (sint8)value;
00455 } else if (sscanf(cp, "damage %d\n", &value)) {
00456 mt->damage = (sint8)value;
00457 } else if (sscanf(cp, "wc %d\n", &value)) {
00458 mt->wc = (sint8)value;
00459 } else if (sscanf(cp, "ac %d\n", &value)) {
00460 mt->ac = (sint8)value;
00461 } else if (sscanf(cp, "sp %d\n", &value)) {
00462 mt->sp = (sint8)value;
00463 } else if (sscanf(cp, "weight %d\n", &value)) {
00464 mt->weight = value;
00465 } else if (sscanf(cp, "value %d\n", &value)) {
00466 mt->value = value;
00467 }
00468 }
00469 if (mt->next) {
00470 free(mt->next);
00471 mt->next = NULL;
00472 }
00473 LOG(llevDebug, "Done.\n");
00474 fclose(fp);
00475
00476 }
00477
00481 static void free_materials(void) {
00482 materialtype_t *next;
00483
00484 while (materialt) {
00485 next = materialt->next;
00486 free(materialt);
00487 materialt = next;
00488 }
00489 materialt = NULL;
00490 }
00491
00497 static void load_settings(void) {
00498 char buf[MAX_BUF], *cp;
00499 int has_val, comp;
00500 FILE *fp;
00501
00502 snprintf(buf, sizeof(buf), "%s/settings", settings.confdir);
00503
00504
00505
00506
00507
00508 if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL) {
00509 LOG(llevError, "Warning: No settings file found\n");
00510 return;
00511 }
00512 while (fgets(buf, MAX_BUF-1, fp) != NULL) {
00513 if (buf[0] == '#')
00514 continue;
00515
00516 if ((cp = strrchr(buf, '\n')) != NULL)
00517 *cp = '\0';
00518
00519
00520 if (buf[0] == 0)
00521 continue;
00522
00523
00524
00525
00526 if ((cp = strchr(buf, ' ')) != NULL) {
00527 while (*cp == ' ')
00528 *cp++ = 0;
00529 has_val = 1;
00530 } else {
00531 cp = "";
00532 has_val = 0;
00533 }
00534
00535 if (!strcasecmp(buf, "metaserver_notification")) {
00536 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00537 settings.meta_on = TRUE;
00538 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00539 settings.meta_on = FALSE;
00540 } else {
00541 LOG(llevError, "load_settings: Unknown value for metaserver_notification: %s\n", cp);
00542 }
00543 } else if (!strcasecmp(buf, "metaserver_server")) {
00544 if (has_val)
00545 strcpy(settings.meta_server, cp);
00546 else
00547 LOG(llevError, "load_settings: metaserver_server must have a value.\n");
00548 } else if (!strcasecmp(buf, "motd")) {
00549 if (has_val)
00550 strcpy(settings.motd, cp);
00551 else
00552 LOG(llevError, "load_settings: motd must have a value.\n");
00553 } else if (!strcasecmp(buf, "dm_mail")) {
00554 if (has_val)
00555 strcpy(settings.dm_mail, cp);
00556 else
00557 LOG(llevError, "load_settings: dm_mail must have a value.\n");
00558 } else if (!strcasecmp(buf, "metaserver_host")) {
00559 if (has_val)
00560 strcpy(settings.meta_host, cp);
00561 else
00562 LOG(llevError, "load_settings: metaserver_host must have a value.\n");
00563 } else if (!strcasecmp(buf, "port")) {
00564 set_csport(cp);
00565 } else if (!strcasecmp(buf, "metaserver_port")) {
00566 int port = atoi(cp);
00567
00568 if (port < 1 || port > 65535)
00569 LOG(llevError, "load_settings: metaserver_port must be between 1 and 65535, %d is invalid\n", port);
00570 else
00571 settings.meta_port = port;
00572 } else if (!strcasecmp(buf, "metaserver_comment")) {
00573 strcpy(settings.meta_comment, cp);
00574 } else if (!strcasecmp(buf, "worldmapstartx")) {
00575 int size = atoi(cp);
00576
00577 if (size < 0)
00578 LOG(llevError, "load_settings: worldmapstartx must be at least 0, %d is invalid\n", size);
00579 else
00580 settings.worldmapstartx = size;
00581 } else if (!strcasecmp(buf, "worldmapstarty")) {
00582 int size = atoi(cp);
00583
00584 if (size < 0)
00585 LOG(llevError, "load_settings: worldmapstarty must be at least 0, %d is invalid\n", size);
00586 else
00587 settings.worldmapstarty = size;
00588 } else if (!strcasecmp(buf, "worldmaptilesx")) {
00589 int size = atoi(cp);
00590
00591 if (size < 1)
00592 LOG(llevError, "load_settings: worldmaptilesx must be greater than 1, %d is invalid\n", size);
00593 else
00594 settings.worldmaptilesx = size;
00595 } else if (!strcasecmp(buf, "worldmaptilesy")) {
00596 int size = atoi(cp);
00597
00598 if (size < 1)
00599 LOG(llevError, "load_settings: worldmaptilesy must be greater than 1, %d is invalid\n", size);
00600 else
00601 settings.worldmaptilesy = size;
00602 } else if (!strcasecmp(buf, "worldmaptilesizex")) {
00603 int size = atoi(cp);
00604
00605 if (size < 1)
00606 LOG(llevError, "load_settings: worldmaptilesizex must be greater than 1, %d is invalid\n", size);
00607 else
00608 settings.worldmaptilesizex = size;
00609 } else if (!strcasecmp(buf, "worldmaptilesizey")) {
00610 int size = atoi(cp);
00611
00612 if (size < 1)
00613 LOG(llevError, "load_settings: worldmaptilesizey must be greater than 1, %d is invalid\n", size);
00614 else
00615 settings.worldmaptilesizey = size;
00616 } else if (!strcasecmp(buf, "fastclock")) {
00617 int lev = atoi(cp);
00618
00619 if (lev < 0)
00620 LOG(llevError, "load_settings: fastclock must be at least 0, %d is invalid\n", lev);
00621 else
00622 settings.fastclock = lev;
00623 } else if (!strcasecmp(buf, "not_permadeth")) {
00624 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00625 settings.not_permadeth = TRUE;
00626 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00627 settings.not_permadeth = FALSE;
00628 } else {
00629 LOG(llevError, "load_settings: Unknown value for not_permadeth: %s\n", cp);
00630 }
00631 } else if (!strcasecmp(buf, "resurrection")) {
00632 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00633 settings.resurrection = TRUE;
00634 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00635 settings.resurrection = FALSE;
00636 } else {
00637 LOG(llevError, "load_settings: Unknown value for resurrection: %s\n", cp);
00638 }
00639 } else if (!strcasecmp(buf, "set_title")) {
00640 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00641 settings.set_title = TRUE;
00642 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00643 settings.set_title = FALSE;
00644 } else {
00645 LOG(llevError, "load_settings: Unknown value for set_title: %s\n", cp);
00646 }
00647 } else if (!strcasecmp(buf, "search_items")) {
00648 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00649 settings.search_items = TRUE;
00650 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00651 settings.search_items = FALSE;
00652 } else {
00653 LOG(llevError, "load_settings: Unknown value for search_items: %s\n", cp);
00654 }
00655 } else if (!strcasecmp(buf, "spell_encumbrance")) {
00656 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00657 settings.spell_encumbrance = TRUE;
00658 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00659 settings.spell_encumbrance = FALSE;
00660 } else {
00661 LOG(llevError, "load_settings: Unknown value for spell_encumbrance: %s\n", cp);
00662 }
00663 } else if (!strcasecmp(buf, "spell_failure_effects")) {
00664 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00665 settings.spell_failure_effects = TRUE;
00666 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00667 settings.spell_failure_effects = FALSE;
00668 } else {
00669 LOG(llevError, "load_settings: Unknown value for spell_failure_effects: %s\n", cp);
00670 }
00671 } else if (!strcasecmp(buf, "casting_time")) {
00672 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00673 settings.casting_time = TRUE;
00674 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00675 settings.casting_time = FALSE;
00676 } else {
00677 LOG(llevError, "load_settings: Unknown value for casting_time: %s\n", cp);
00678 }
00679 } else if (!strcasecmp(buf, "real_wiz")) {
00680 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00681 settings.real_wiz = TRUE;
00682 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00683 settings.real_wiz = FALSE;
00684 } else {
00685 LOG(llevError, "load_settings: Unknown value for real_wiz: %s\n", cp);
00686 }
00687 } else if (!strcasecmp(buf, "recycle_tmp_maps")) {
00688 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00689 settings.recycle_tmp_maps = TRUE;
00690 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00691 settings.recycle_tmp_maps = FALSE;
00692 } else {
00693 LOG(llevError, "load_settings: Unknown value for recycle_tmp_maps: %s\n", cp);
00694 }
00695 } else if (!strcasecmp(buf, "explore_mode")) {
00696 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00697 settings.explore_mode = TRUE;
00698 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00699 settings.explore_mode = FALSE;
00700 } else {
00701 LOG(llevError, "load_settings: Unknown value for explore_mode: %s\n", cp);
00702 }
00703 } else if (!strcasecmp(buf, "who_format")) {
00704 if (has_val)
00705 strcpy(settings.who_format, cp);
00706 } else if (!strcasecmp(buf, "who_wiz_format")) {
00707 if (has_val)
00708 strcpy(settings.who_wiz_format, cp);
00709 } else if (!strcasecmp(buf, "spellpoint_level_depend")) {
00710 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00711 settings.spellpoint_level_depend = TRUE;
00712 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00713 settings.spellpoint_level_depend = FALSE;
00714 } else {
00715 LOG(llevError, "load_settings: Unknown value for spellpoint_level_depend: %s\n", cp);
00716 }
00717 } else if (!strcasecmp(buf, "stat_loss_on_death")) {
00718 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00719 settings.stat_loss_on_death = TRUE;
00720 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00721 settings.stat_loss_on_death = FALSE;
00722 } else {
00723 LOG(llevError, "load_settings: Unknown value for stat_loss_on_death: %s\n", cp);
00724 }
00725 } else if (!strcasecmp(buf, "use_permanent_experience")) {
00726 LOG(llevError, "use_permanent_experience is deprecated, usepermenent_experience_percentage instead\n");
00727 } else if (!strcasecmp(buf, "permanent_experience_percentage")) {
00728 int val = atoi(cp);
00729 if (val < 0 || val > 100)
00730 LOG(llevError, "load_settings: permenent_experience_percentage must be between 0 and 100, %d is invalid\n", val);
00731 else
00732 settings.permanent_exp_ratio = val;
00733 } else if (!strcasecmp(buf, "death_penalty_percentage")) {
00734 int val = atoi(cp);
00735 if (val < 0 || val > 100)
00736 LOG(llevError, "load_settings: death_penalty_percentage must be between 0 and 100, %d is invalid\n", val);
00737 else
00738 settings.death_penalty_ratio = val;
00739 } else if (!strcasecmp(buf, "death_penalty_levels")) {
00740 int val = atoi(cp);
00741 if (val < 0 || val > 255)
00742 LOG(llevError, "load_settings: death_penalty_levels can not be negative, %d is invalid\n", val);
00743 else
00744 settings.death_penalty_level = val;
00745 } else if (!strcasecmp(buf, "balanced_stat_loss")) {
00746 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00747 settings.balanced_stat_loss = TRUE;
00748 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00749 settings.balanced_stat_loss = FALSE;
00750 } else {
00751 LOG(llevError, "load_settings: Unknown value for balanced_stat_loss: %s\n", cp);
00752 }
00753 } else if (!strcasecmp(buf, "simple_exp")) {
00754 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00755 settings.simple_exp = TRUE;
00756 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00757 settings.simple_exp = FALSE;
00758 } else {
00759 LOG(llevError, "load_settings: Unknown value for simple_exp: %s\n", cp);
00760 }
00761 } else if (!strcasecmp(buf, "item_power_factor")) {
00762 float tmp = atof(cp);
00763 if (tmp < 0)
00764 LOG(llevError, "load_settings: item_power_factor must be a positive number (%f < 0)\n", tmp);
00765 else
00766 settings.item_power_factor = tmp;
00767 } else if (!strcasecmp(buf, "pk_luck_penalty")) {
00768 sint16 val = atoi(cp);
00769
00770 if (val < -100 || val > 100)
00771 LOG(llevError, "load_settings: pk_luck_penalty must be between -100 and 100, %d is invalid\n", val);
00772 else
00773 settings.pk_luck_penalty = val;
00774 } else if (!strcasecmp(buf, "set_friendly_fire")) {
00775 int val = atoi(cp);
00776
00777 if (val < 1 || val > 100)
00778 LOG(llevError, "load_settings: set_friendly_fire must be between 1 an 100, %d is invalid\n", val);
00779 else
00780 settings.set_friendly_fire = val;
00781 } else if (!strcasecmp(buf, "armor_max_enchant")) {
00782 int max_e = atoi(cp);
00783 if (max_e <= 0)
00784 LOG(llevError, "load_settings: armor_max_enchant is %d\n", max_e);
00785 else
00786 settings.armor_max_enchant = max_e;
00787 } else if (!strcasecmp(buf, "armor_weight_reduction")) {
00788 int wr = atoi(cp);
00789 if (wr < 0)
00790 LOG(llevError, "load_settings: armor_weight_reduction is %d\n", wr);
00791 else
00792 settings.armor_weight_reduction = wr;
00793 } else if (!strcasecmp(buf, "armor_weight_linear")) {
00794 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00795 settings.armor_weight_linear = TRUE;
00796 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00797 settings.armor_weight_linear = FALSE;
00798 } else {
00799 LOG(llevError, "load_settings: unknown value for armor_weight_linear: %s\n", cp);
00800 }
00801
00802 } else if (!strcasecmp(buf, "armor_speed_improvement")) {
00803 int wr = atoi(cp);
00804 if (wr < 0)
00805 LOG(llevError, "load_settings: armor_speed_improvement is %d\n", wr);
00806 else
00807 settings.armor_speed_improvement = wr;
00808 } else if (!strcasecmp(buf, "armor_speed_linear")) {
00809 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00810 settings.armor_speed_linear = TRUE;
00811 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00812 settings.armor_speed_linear = FALSE;
00813 } else {
00814 LOG(llevError, "load_settings: unknown value for armor_speed_linear: %s\n", cp);
00815 }
00816
00817 } else if (!strcasecmp(buf, "no_player_stealing")) {
00818 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00819 settings.no_player_stealing = TRUE;
00820 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00821 settings.no_player_stealing = FALSE;
00822 } else {
00823 LOG(llevError, "load_settings: unknown value for no_player_stealing: %s\n", cp);
00824 }
00825
00826 } else if (!strcasecmp(buf, "create_home_portals")) {
00827 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00828 settings.create_home_portals = TRUE;
00829 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00830 settings.create_home_portals = FALSE;
00831 } else {
00832 LOG(llevError, "load_settings: unknown value for create_home_portals: %s\n", cp);
00833 }
00834 } else if (!strcasecmp(buf, "personalized_blessings")) {
00835 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00836 settings.personalized_blessings = TRUE;
00837 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00838 settings.personalized_blessings = FALSE;
00839 } else {
00840 LOG(llevError, "load_settings: unknown value for personalized_blessings: %s\n", cp);
00841 }
00842 } else if (!strcasecmp(buf, "pk_max_experience")) {
00843 sint64 pkme = atoll(cp);
00844 if (pkme < 0)
00845 pkme = -1;
00846 settings.pk_max_experience = pkme;
00847 } else if (!strcasecmp(buf, "pk_max_experience_percent")) {
00848 int pkmep = atoi(cp);
00849 if (pkmep < 0) {
00850 LOG(llevError, "load_settings: pk_max_experience_percent should be positive or zero\n", cp);
00851 } else
00852 settings.pk_max_experience_percent = pkmep;
00853 } else if (!strcasecmp(buf, "allow_denied_spells_writing")) {
00854 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00855 settings.allow_denied_spells_writing = TRUE;
00856 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00857 settings.allow_denied_spells_writing = FALSE;
00858 } else {
00859 LOG(llevError, "load_settings: unknown value for allow_denied_spells_writing: %s\n", cp);
00860 }
00861 } else if (!strcasecmp(buf, "allow_broken_converters")) {
00862 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00863 settings.allow_broken_converters = TRUE;
00864 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00865 settings.allow_broken_converters = FALSE;
00866 } else {
00867 LOG(llevError, "load_settings: unknown value for allow_broken_converters: %s\n", cp);
00868 }
00869 } else if (!strcasecmp(buf, "log_timestamp")) {
00870 if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true")) {
00871 settings.log_timestamp = TRUE;
00872 } else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false")) {
00873 settings.log_timestamp = FALSE;
00874 } else {
00875 LOG(llevError, "load_settings: unknown value for log_timestamp: %s\n", cp);
00876 }
00877 } else if (!strcasecmp(buf, "log_timestamp_format")) {
00878 free(settings.log_timestamp_format);
00879 settings.log_timestamp_format = strdup_local(cp);
00880 } else {
00881 LOG(llevError, "Unknown value in settings file: %s\n", buf);
00882 }
00883 }
00884 close_and_delete(fp, comp);
00885 if (settings.log_timestamp_format == NULL)
00886 settings.log_timestamp_format = strdup_local("%y/%m/%d %H:%M:%S");
00887
00888
00889
00890
00891
00892
00893
00894 if (!strcmp(settings.who_format, ""))
00895 strcpy(settings.who_format, "%N_%T%t%h%d%b%n<%m>");
00896 if (!strcmp(settings.who_wiz_format, ""))
00897 strcpy(settings.who_wiz_format, "%N_%T%t%h%d%b%nLevel %l <%m>(@%i)(%c)");
00898 }
00899
00905 void init(int argc, char **argv) {
00906
00907 init_done = 0;
00908 logfile = stderr;
00909 parse_args(argc, argv, 1);
00910
00911
00912
00913 init_library();
00914 load_settings();
00915 load_materials();
00916 parse_args(argc, argv, 2);
00917 fprintf(logfile, "Welcome to CrossFire, v%s\n", FULL_VERSION);
00918 fprintf(logfile, "Copyright (C) 1994 Mark Wedel.\n");
00919 fprintf(logfile, "Copyright (C) 1992 Frank Tore Johansen.\n");
00920
00921 if (strcmp(settings.dm_mail, "") != 0) {
00922 fprintf(logfile, "Maintained locally by: %s\n", settings.dm_mail);
00923 fprintf(logfile, "Questions and bugs should be mailed to above address.\n");
00924 }
00925 SRANDOM(time(NULL));
00926
00927 init_startup();
00928 init_signals();
00929 init_commands();
00930 read_map_log();
00931 init_skills();
00932 init_ob_methods();
00933 cftimer_init();
00934
00935 parse_args(argc, argv, 3);
00936
00937 #ifndef WIN32
00938 if (settings.daemonmode)
00939 become_daemon();
00940 #endif
00941
00942 init_beforeplay();
00943 init_server();
00944 metaserver_init();
00945 metaserver2_init();
00946 reset_sleep();
00947 init_done = 1;
00948 }
00949
00955 void free_server(void) {
00956 free_materials();
00957 free_races();
00958 }
00959
00960 static void usage(void) {
00961 (void)fprintf(logfile, "Usage: crossfire [-h] [-<flags>]...\n");
00962 }
00963
00964 static void help(void) {
00965
00966
00967 printf("Flags:\n");
00968 printf(" -csport <port> Specifies the port to use for the new client/server code.\n");
00969 printf(" -d Turns on some debugging.\n");
00970 printf(" +d Turns off debugging (useful if server compiled with debugging\n");
00971 printf(" as default).\n");
00972 printf(" -detach The server will go in the background, closing all\n");
00973 printf(" connections to the tty.\n");
00974 printf(" -h Display this information.\n");
00975 printf(" -log <file> Specifies which file to send output to.\n");
00976 printf(" Only has meaning if -detach is specified.\n");
00977 printf(" -mon Turns on monster debugging.\n");
00978 printf(" -o Prints out info on what was defined at compile time.\n");
00979 printf(" -s Display the high-score list.\n");
00980 printf(" -score <name or class> Displays all high scores with matching name/class.\n");
00981 printf(" -v Print version and contributors.\n");
00982 printf(" -conf Sets the configuration dir (settings, motd, etc.)\n");
00983 printf(" -data Sets the lib dir (archetypes, treasures, etc.)\n");
00984 printf(" -local Read/write local data (hiscore, unique items, etc.)\n");
00985 printf(" -maps Sets the directory for maps.\n");
00986 printf(" -arch Sets the archetype file to use.\n");
00987 printf(" -regions Sets the regions file to use.\n");
00988 printf(" -playerdir Sets the directory for the player files.\n");
00989 printf(" -templatedir Sets the directory for template generate maps.\n");
00990 printf(" -treasures Sets the treasures file to use.\n");
00991 printf(" -uniquedir Sets the unique items/maps directory.\n");
00992 printf(" -tmpdir Sets the directory for temporary files (mostly maps.)\n");
00993 printf(" -m Lists out suggested experience for all monsters.\n");
00994 printf(" -m2 Dumps out abilities.\n");
00995 printf(" -m3 Dumps out artifact information.\n");
00996 printf(" -m4 Dumps out spell information.\n");
00997 printf(" -m5 Dumps out skill information.\n");
00998 printf(" -m6 Dumps out race information.\n");
00999 printf(" -m7 Dumps out alchemy information.\n");
01000 printf(" -m8 Dumps out gods information.\n");
01001 printf(" -m9 Dumps out more alchemy information (formula checking).\n");
01002 printf(" -mt <name> Dumps out list of treasures for a monster.\n");
01003 exit(0);
01004 }
01005
01006 static void init_beforeplay(void) {
01007 init_archetypes();
01008 init_artifacts();
01009 check_spells();
01010 init_regions();
01011 init_archetype_pointers();
01012 init_races();
01013 init_gods();
01014 init_readable();
01015 init_formulae();
01016
01017 switch (settings.dumpvalues) {
01018 case 1:
01019 print_monsters();
01020 cleanup();
01021
01022 case 2:
01023 dump_abilities();
01024 cleanup();
01025
01026 case 3:
01027 dump_artifacts();
01028 cleanup();
01029
01030 case 4:
01031 dump_spells();
01032 cleanup();
01033
01034 case 5:
01035 cleanup();
01036
01037 case 6:
01038 dump_races();
01039 cleanup();
01040
01041 case 7:
01042 dump_alchemy();
01043 cleanup();
01044
01045 case 8:
01046 dump_gods();
01047 cleanup();
01048
01049 case 9:
01050 dump_alchemy_costs();
01051 cleanup();
01052
01053 case 10:
01054 dump_monster_treasure(settings.dumparg);
01055 cleanup();
01056 }
01057 }
01058
01064 static void init_startup(void) {
01065 char buf[MAX_BUF];
01066 FILE *fp;
01067 int comp;
01068
01069 #ifdef SHUTDOWN_FILE
01070 snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, SHUTDOWN_FILE);
01071 if ((fp = open_and_uncompress(buf, 0, &comp)) != NULL) {
01072 while (fgets(buf, MAX_BUF-1, fp) != NULL)
01073 printf("%s", buf);
01074 close_and_delete(fp, comp);
01075 exit(1);
01076 }
01077 #endif
01078
01079 if (forbid_play()) {
01080 LOG(llevError, "CrossFire: Playing not allowed.\n");
01081 exit(-1);
01082 }
01083 }
01084
01091 static void compile_info(void) {
01092 int i = 0;
01093 char err[MAX_BUF];
01094
01095 printf("Non-standard include files:\n");
01096 #if !defined(__STRICT_ANSI__) || defined(__sun__)
01097 #if !defined(Mips)
01098 printf("<stdlib.h>\n");
01099 i = 1;
01100 #endif
01101 #if !defined(MACH) && !defined(sony)
01102 printf("<malloc.h>\n");
01103 i = 1;
01104 #endif
01105 #endif
01106 #ifndef __STRICT_ANSI__
01107 #ifndef MACH
01108 printf("<memory.h\n");
01109 i = 1;
01110 #endif
01111 #endif
01112 #ifndef sgi
01113 printf("<sys/timeb.h>\n");
01114 i = 1;
01115 #endif
01116 if (!i)
01117 printf("(none)\n");
01118 printf("Datadir:\t\t%s\n", settings.datadir);
01119 printf("Localdir:\t\t%s\n", settings.localdir);
01120 #ifdef PERM_FILE
01121 printf("Perm file:\t<ETC>/%s\n", PERM_FILE);
01122 #endif
01123 #ifdef SHUTDOWN_FILE
01124 printf("Shutdown file:\t<ETC>/%s\n", SHUTDOWN_FILE);
01125 #endif
01126 printf("Save player:\t<true>\n");
01127 printf("Save mode:\t%4.4o\n", SAVE_MODE);
01128 printf("Playerdir:\t<VAR>/%s\n", settings.playerdir);
01129 printf("Itemsdir:\t<VAR>/%s\n", settings.uniquedir);
01130 printf("Tmpdir:\t\t%s\n", settings.tmpdir);
01131 printf("Map max timeout:\t%d\n", MAP_MAXTIMEOUT);
01132 printf("Max objects:\t%d\n", MAX_OBJECTS);
01133 #ifdef USE_CALLOC
01134 printf("Use_calloc:\t<true>\n");
01135 #else
01136 printf("Use_calloc:\t<false>\n");
01137 #endif
01138
01139 printf("Max_time:\t%d\n", MAX_TIME);
01140
01141 #ifdef WIN32
01142 printf("Logfilename:\t%s\n", settings.logfilename);
01143 exit(0);
01144 #else
01145 execl("/bin/uname", "uname", "-a", NULL);
01146 LOG(llevError, "Oops, shouldn't have gotten here: execl(/bin/uname) failed: %s\n", strerror_local(errno, err, sizeof(err)));
01147 exit(-1);
01148 #endif
01149 }
01150
01151
01152
01158 static void rec_sigsegv(int i) {
01159 LOG(llevError, "\nSIGSEGV received.\n");
01160 fatal_signal(1);
01161 }
01162
01168 static void rec_sigint(int i) {
01169 LOG(llevInfo, "\nSIGINT received.\n");
01170 fatal_signal(0);
01171 }
01172
01185 static void rec_sighup(int i) {
01186
01187
01188 if (logfile != stderr) {
01189 reopen_logfile = 1;
01190 }
01191 }
01192
01199 static void rec_sigquit(int i) {
01200 LOG(llevInfo, "\nSIGQUIT received\n");
01201 fatal_signal(1);
01202 }
01203
01217 static void rec_sigpipe(int i) {
01218 LOG(llevError, "\nSIGPIPE--------------\n------------\n--------\n---\n");
01219 #if 1 && !defined(WIN32)
01220 LOG(llevInfo, "\nReceived SIGPIPE, ignoring...\n");
01221 signal(SIGPIPE, rec_sigpipe);
01222 #else
01223 LOG(llevError, "\nSIGPIPE received, not ignoring...\n");
01224 fatal_signal(1);
01225 #endif
01226 }
01227
01234 static void rec_sigbus(int i) {
01235 #ifdef SIGBUS
01236 LOG(llevError, "\nSIGBUS received\n");
01237 fatal_signal(1);
01238 #endif
01239 }
01240
01247 static void rec_sigterm(int i) {
01248 LOG(llevInfo, "\nSIGTERM received\n");
01249 fatal_signal(0);
01250 }
01251
01258 static void fatal_signal(int make_core) {
01259 if (init_done) {
01260 emergency_save(0);
01261 clean_tmp_files();
01262 }
01263 if (make_core)
01264 abort();
01265 exit(0);
01266 }
01267
01271 static void init_signals(void) {
01272 #ifndef WIN32
01273 struct sigaction sa;
01274
01275 sa.sa_sigaction = NULL;
01276 sigemptyset(&sa.sa_mask);
01277 sa.sa_flags = 0;
01278 sa.sa_handler = rec_sighup;
01279 sigaction(SIGHUP, &sa, NULL);
01280 signal(SIGINT, rec_sigint);
01281 #ifndef DEBUG
01282 signal(SIGQUIT, rec_sigquit);
01283 signal(SIGSEGV, rec_sigsegv);
01284 LOG(llevInfo, "\n---------registering SIGPIPE\n");
01285 signal(SIGPIPE, rec_sigpipe);
01286 #ifdef SIGBUS
01287 signal(SIGBUS, rec_sigbus);
01288 #endif
01289 signal(SIGTERM, rec_sigterm);
01290 #endif
01291 #endif
01292 }
01293
01300 static void init_races(void) {
01301 FILE *file;
01302 char race[MAX_BUF], fname[MAX_BUF], buf[MAX_BUF], *cp, variable[MAX_BUF];
01303 archetype *mon = NULL;
01304 static int init_done = 0;
01305
01306 if (init_done)
01307 return;
01308 init_done = 1;
01309 first_race = NULL;
01310
01311 snprintf(fname, sizeof(fname), "%s/races", settings.datadir);
01312 LOG(llevDebug, "Reading races from %s...\n", fname);
01313 if (!(file = fopen(fname, "r"))) {
01314 LOG(llevError, "Cannot open races file %s: %s\n", fname, strerror_local(errno, buf, sizeof(buf)));
01315 return;
01316 }
01317
01318 while (fgets(buf, MAX_BUF, file) != NULL) {
01319 int set_race = 1, set_list = 1;
01320 if (*buf == '#')
01321 continue;
01322 if ((cp = strchr(buf, '\n')) != NULL)
01323 *cp = '\0';
01324 cp = buf;
01325 while (*cp == ' ' || *cp == '!' || *cp == '@') {
01326 if (*cp == '!')
01327 set_race = 0;
01328 if (*cp == '@')
01329 set_list = 0;
01330 cp++;
01331 }
01332 if (sscanf(cp, "RACE %s", variable)) {
01333 strcpy(race, variable);
01334 } else {
01335 char *cp1;
01336
01337
01338 for (cp1 = cp; *cp1 == ' '; cp1++)
01339 ;
01340
01341 for (cp1 = cp+strlen(cp)-1; *cp1 == '\n' || *cp1 == ' '; cp1--) {
01342 *cp1 = '\0';
01343 if (cp == cp1)
01344 break;
01345 }
01346
01347 if (cp[strlen(cp)-1] == '\n')
01348 cp[strlen(cp)-1] = '\0';
01349
01350 if ((mon = find_archetype(cp)) == NULL)
01351 LOG(llevError, "Creature %s in race file lacks archetype\n", cp);
01352 else {
01353 if (set_race && (!mon->clone.race || strcmp(mon->clone.race, race))) {
01354 if (mon->clone.race) {
01355 LOG(llevDebug, " Resetting race to %s from %s for archetype %s\n", race, mon->clone.race, mon->name);
01356 free_string(mon->clone.race);
01357 }
01358 mon->clone.race = add_string(race);
01359 }
01360
01361 if (set_list && QUERY_FLAG(&mon->clone, FLAG_MONSTER))
01362 add_to_racelist(race, &mon->clone);
01363 }
01364 }
01365 }
01366 fclose(file);
01367 LOG(llevDebug, "done races.\n");
01368 }
01369
01373 static void dump_races(void) {
01374 racelink *list;
01375 objectlink *tmp;
01376
01377 for (list = first_race; list; list = list->next) {
01378 fprintf(stderr, "\nRACE %s:\t", list->name);
01379 for (tmp = list->member; tmp; tmp = tmp->next)
01380 fprintf(stderr, "%s(%d), ", tmp->ob->arch->name, tmp->ob->level);
01381 }
01382 fprintf(stderr, "\n");
01383 }
01384
01388 static void free_races(void) {
01389 racelink *race;
01390 objectlink *link;
01391
01392 LOG(llevDebug, "Freeing race information.\n");
01393 while (first_race) {
01394 race = first_race->next;
01395 while (first_race->member) {
01396 link = first_race->member->next;
01397 free(first_race->member);
01398 first_race->member = link;
01399 }
01400 free_string(first_race->name);
01401 free(first_race);
01402 first_race = race;
01403 }
01404 }
01405
01414 static void add_to_racelist(const char *race_name, object *op) {
01415 racelink *race;
01416
01417 if (!op || !race_name)
01418 return;
01419 race = find_racelink(race_name);
01420
01421 if (!race) {
01422 race = get_racelist();
01423 race->next = first_race;
01424 first_race = race;
01425 race->name = add_string(race_name);
01426 }
01427
01428 if (race->member->ob) {
01429 objectlink *tmp = get_objectlink();
01430
01431 tmp->next = race->member;
01432 race->member = tmp;
01433 }
01434 race->nrof++;
01435 race->member->ob = op;
01436 }
01437
01446 static racelink *get_racelist(void) {
01447 racelink *list;
01448
01449 list = (racelink *)malloc(sizeof(racelink));
01450 if (!list)
01451 fatal(OUT_OF_MEMORY);
01452 list->name = NULL;
01453 list->nrof = 0;
01454 list->member = get_objectlink();
01455 list->next = NULL;
01456
01457 return list;
01458 }
01459
01468 racelink *find_racelink(const char *name) {
01469 racelink *test = NULL;
01470
01471 if (name && first_race)
01472 for (test = first_race; test && test != test->next; test = test->next)
01473 if (!test->name || !strcmp(name, test->name))
01474 break;
01475
01476 return test;
01477 }