Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_init_c = 00003 * "$Id: init.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 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 /* Needed for strcasecmp(). */ 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 /* ***win32: set_csport: we remove csport error secure check here, do this later */ 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 /* win32 */ 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 /* Honor -help also, since it is somewhat common */ 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 /* Windows service stuff */ 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 /* Found a matching option, but should not be processed on 00312 * this pass. Just skip over it 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 { /* takes no args */ 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 == ' ') /* Skip blanks */ 00409 cp++; 00410 if (!strncmp(cp, "name", 4)) { 00411 /* clean up the previous entry */ 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 /* We don't require a settings file at current time, but down the road, 00505 * there will probably be so many values that not having a settings file 00506 * will not be a good thing. 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 /* eliminate newline */ 00516 if ((cp = strrchr(buf, '\n')) != NULL) 00517 *cp = '\0'; 00518 00519 /* Skip over empty lines */ 00520 if (buf[0] == 0) 00521 continue; 00522 00523 /* Skip all the spaces and set them to nulls. If not space, 00524 * set cp to "" to make strcpy's and the like easier down below. 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 * The who formats are defined in config to be blank. They should have been 00890 * overridden by the settings file, if there are no entries however, it will 00891 * have stayed blank. Since this probably isn't what is wanted, we will check if 00892 * new formats have been specified, and if not we will use the old defaults. 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; /* Must be done before init_signal() */ 00908 logfile = stderr; 00909 parse_args(argc, argv, 1); /* First arg pass - right now it does 00910 * nothing, but in future specifying the 00911 * LibDir in this pass would be reasonable*/ 00912 00913 init_library(); /* Must be called early */ 00914 load_settings(); /* Load the settings file */ 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(); /* Write (C), check shutdown/forbid files */ 00928 init_signals(); /* Sets up signal interceptions */ 00929 init_commands(); /* Sort command tables */ 00930 read_map_log(); /* Load up the old temp map files */ 00931 init_skills(); 00932 init_ob_methods(); 00933 cftimer_init(); 00934 00935 parse_args(argc, argv, 3); 00936 00937 #ifndef WIN32 /* ***win32: no become_daemon in windows */ 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 /* The information in usage is redundant with what is given below, so why call it? */ 00966 /* usage();*/ 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(); /* If not called before, reads all archetypes from file */ 01008 init_artifacts(); /* If not called before, reads all artifacts from file */ 01009 check_spells(); /* If not called before, links archtypes used by spells */ 01010 init_regions(); /* If not called before, reads all regions from file */ 01011 init_archetype_pointers(); /* Setup global pointers to archetypes */ 01012 init_races(); /* overwrite race designations using entries in lib/races file */ 01013 init_gods(); /* init linked list of gods from archs*/ 01014 init_readable(); /* inits useful arrays for readable texts */ 01015 init_formulae(); /* If not called before, reads formulae from file */ 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()) { /* Maybe showing highscore should be allowed? */ 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 /* ***win32 compile_info(): remove execl... */ 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 /* Signal handlers: */ 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 /* Don't call LOG(). It calls non-reentrant functions. The other 01187 * signal handlers shouldn't really call LOG() either. */ 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) /* ***win32: we don't want send SIGPIPE */ 01220 LOG(llevInfo, "\nReceived SIGPIPE, ignoring...\n"); 01221 signal(SIGPIPE, rec_sigpipe);/* hocky-pux clears signal handlers */ 01222 #else 01223 LOG(llevError, "\nSIGPIPE received, not ignoring...\n"); 01224 fatal_signal(1); /*Might consider to uncomment this line */ 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 /* init_signals() remove signals */ 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 /* win32 */ 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)) { /* set new race value */ 01333 strcpy(race, variable); 01334 } else { 01335 char *cp1; 01336 01337 /* Take out beginning spaces */ 01338 for (cp1 = cp; *cp1 == ' '; cp1++) 01339 ; 01340 /* Remove newline and trailing spaces */ 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 /* set creature race to race value */ 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 /* if the arch is a monster, add it to the race list */ 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) { /* add in a new race list */ 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 }