/* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * Copyright (©) 2002 Mark Wedel & Crossfire Development Team * Copyright (©) 1992 Frank Tore Johansen * * Deliantra is free software: you can redistribute it and/or modify it under * the terms of the Affero GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the Affero GNU General Public License * and the GNU General Public License along with this program. If not, see * . * * The authors can be reached via e-mail to */ #include #include #include /* This loads the settings file. There could be debate whether this should * be here or in the common directory - but since only the server needs this * information, having it here probably makes more sense. */ void load_settings () { object_thawer thawer (settings.confdir, "settings"); if (!thawer) { LOG (llevError, "Error: No settings file found\n"); exit (1); } while (thawer.kw) { const char *buf = thawer.kw_str; const char *cp = thawer.value_nn; if (!strcmp (buf, "not_permadeth")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.not_permadeth = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.not_permadeth = FALSE; } else { LOG (llevError, "load_settings: Unknown value for not_permadeth" ": %s\n", cp); } } else if (!strcmp (buf, "resurrection")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.resurrection = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.resurrection = FALSE; } else { LOG (llevError, "load_settings: Unknown value for resurrection" ": %s\n", cp); } } else if (!strcmp (buf, "set_title")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.set_title = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.set_title = FALSE; } else { LOG (llevError, "load_settings: Unknown value for set_title" ": %s\n", cp); } } else if (!strcmp (buf, "search_items")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.search_items = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.search_items = FALSE; } else { LOG (llevError, "load_settings: Unknown value for search_items" ": %s\n", cp); } } else if (!strcmp (buf, "spell_encumbrance")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.spell_encumbrance = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.spell_encumbrance = FALSE; } else { LOG (llevError, "load_settings: Unknown value for " "spell_encumbrance: %s\n", cp); } } else if (!strcmp (buf, "spell_failure_effects")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.spell_failure_effects = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.spell_failure_effects = FALSE; } else { LOG (llevError, "load_settings: Unknown value for " "spell_failure_effects: %s\n", cp); } } else if (!strcmp (buf, "spellpoint_level_depend")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.spellpoint_level_depend = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.spellpoint_level_depend = FALSE; } else { LOG (llevError, "load_settings: Unknown value for " "spellpoint_level_depend: %s\n", cp); } } else if (!strcmp (buf, "stat_loss_on_death")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.stat_loss_on_death = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.stat_loss_on_death = FALSE; } else { LOG (llevError, "load_settings: Unknown value for " "stat_loss_on_death: %s\n", cp); } } else if (!strcmp (buf, "use_permanent_experience")) { LOG (llevError, "use_permanent_experience is deprecated, use" "permenent_experience_percentage instead\n"); } else if (!strcmp (buf, "permanent_experience_percentage")) { int val = atoi (cp); if (val < 0 || val > 100) LOG (llevError, "load_settings: permenent_experience_percentage" "must be between 0 and 100, %d is invalid\n", val); else settings.permanent_exp_ratio = val; } else if (!strcmp (buf, "death_penalty_percentage")) { int val = atoi (cp); if (val < 0 || val > 100) LOG (llevError, "load_settings: death_penalty_percentage" "must be between 0 and 100, %d is invalid\n", val); else settings.death_penalty_ratio = val; } else if (!strcmp (buf, "death_penalty_levels")) { int val = atoi (cp); if (val < 0 || val > 255) LOG (llevError, "load_settings: death_penalty_levels" "can not be negative, %d is invalid\n", val); else settings.death_penalty_level = val; } else if (!strcmp (buf, "balanced_stat_loss")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.balanced_stat_loss = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.balanced_stat_loss = FALSE; } else { LOG (llevError, "load_settings: Unknown value for " "balanced_stat_loss: %s\n", cp); } } else if (!strcmp (buf, "simple_exp")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.simple_exp = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.simple_exp = FALSE; } else { LOG (llevError, "load_settings: Unknown value for simple_exp: %s\n", cp); } } else if (!strcmp (buf, "item_power_factor")) { float tmp = atof (cp); if (tmp < 0) LOG (llevError, "load_settings: item_power_factor must be a positive number (%f < 0)\n", tmp); else settings.item_power_factor = tmp; } else if (!strcmp (buf, "pk_luck_penalty")) { sint16 val = atoi (cp); if (val < -100 || val > 100) LOG (llevError, "load_settings: pk_luck_penalty must be between -100 and 100" ", %d is invalid\n", val); else settings.pk_luck_penalty = val; } else if (!strcmp (buf, "set_friendly_fire")) { int val = atoi (cp); if (val < 0 || val > 100) LOG (llevError, "load_settings: set_friendly_fire must be between 0 an 100" ", %d is invalid\n", val); else settings.set_friendly_fire = val; } else if (!strcmp (buf, "armor_max_enchant")) { int max_e = atoi (cp); if (max_e <= 0) LOG (llevError, "load_settings: armor_max_enchant is %d\n", max_e); else settings.armor_max_enchant = max_e; } else if (!strcmp (buf, "armor_weight_reduction")) { int wr = atoi (cp); if (wr < 0) LOG (llevError, "load_settings: armor_weight_reduction is %d\n", wr); else settings.armor_weight_reduction = wr; } else if (!strcmp (buf, "armor_weight_linear")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.armor_weight_linear = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.armor_weight_linear = FALSE; } else { LOG (llevError, "load_settings: unknown value for armor_weight_linear: %s\n", cp); } } else if (!strcmp (buf, "armor_speed_improvement")) { int wr = atoi (cp); if (wr < 0) LOG (llevError, "load_settings: armor_speed_improvement is %d\n", wr); else settings.armor_speed_improvement = wr; } else if (!strcmp (buf, "armor_speed_linear")) { if (!strcmp (cp, "on") || !strcmp (cp, "true")) { settings.armor_speed_linear = TRUE; } else if (!strcmp (cp, "off") || !strcmp (cp, "false")) { settings.armor_speed_linear = FALSE; } else { LOG (llevError, "load_settings: unknown value for armor_speed_linear: %s\n", cp); } } else thawer.parse_error ("settings file"); thawer.next (); } } /* * init() is called only once, when starting the program. */ void init (int argc, char **argv) { init_done = 0; /* Must be done before init_signal() */ init_environ (); cfperl_init (); init_done = 1; } /* Signal handlers: */ static void rec_sigabrt (int i) { signal (SIGABRT, SIG_DFL); LOG (llevError, "SIGABRT received.\n"); cleanup ("SIGABRT received", 1); } static void rec_sigsegv (int i) { signal (SIGSEGV, SIG_DFL); LOG (llevError, "SIGSEGV received.\n"); cleanup ("SIGSEGV received", 1); } static void rec_sigquit (int i) { signal (SIGQUIT, SIG_IGN); LOG (llevInfo, "SIGQUIT received\n"); cleanup ("SIGQUIT received", 1); } static void rec_sigbus (int i) { signal (SIGBUS, SIG_DFL); LOG (llevError, "SIGBUS received\n"); cleanup ("SIGBUS received", 1); } void reset_signals () { signal (SIGABRT, SIG_DFL); signal (SIGQUIT, SIG_DFL); signal (SIGSEGV, SIG_DFL); signal (SIGBUS , SIG_DFL); signal (SIGINT , SIG_DFL); signal (SIGTERM, SIG_DFL); } void init_signals () { // large stack, but it's important data we want to save, and it is not usually // being physically allocated anyways const size_t stacksize = 8 * 1024 * 1024 + SIGSTKSZ; stack_t ss; ss.ss_sp = malloc (stacksize); ss.ss_flags = 0; ss.ss_size = stacksize; sigaltstack (&ss, 0); struct sigaction sa; sigfillset (&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = SIG_IGN; sigaction (SIGPIPE, &sa, 0); sa.sa_handler = rec_sigabrt; sigaction (SIGABRT, &sa, 0); sa.sa_handler = rec_sigquit; sigaction (SIGQUIT, &sa, 0); sa.sa_handler = rec_sigbus; sigaction (SIGBUS, &sa, 0); sa.sa_flags |= SA_ONSTACK; sa.sa_handler = rec_sigsegv; sigaction (SIGSEGV, &sa, 0); } static racelink * get_racelist () { racelink *list = new racelink; list->name = 0; list->nrof = 0; list->next = 0; list->member = get_objectlink (); return list; } racelink * find_racelink (const char *name) { if (name) for (racelink *link = first_race; link; link = link->next) if (!link->name || !strcmp (name, link->name)) return link; return 0; } static void add_to_racelist (const char *race_name, object *op) { racelink *race; if (!op || !race_name) return; race = find_racelink (race_name); if (!race) { /* add in a new race list */ race = get_racelist (); race->next = first_race; first_race = race; race->name = race_name; } if (race->member->ob) { objectlink *tmp = get_objectlink (); tmp->next = race->member; race->member = tmp; } race->nrof++; race->member->ob = op; } /* init_races() - reads the races file in the lib/ directory, then * overwrites old 'race' entries. This routine allow us to quickly * re-configure the 'alignment' of monsters, objects. Useful for * putting together lists of creatures, etc that belong to gods. */ static void init_races () { FILE *file; char race[MAX_BUF], fname[MAX_BUF], buf[MAX_BUF], *cp, variable[MAX_BUF]; archetype *mon = NULL; static int init_done = 0; if (init_done) return; init_done = 1; first_race = 0; sprintf (fname, "%s/races", settings.datadir); LOG (llevDebug, "Reading races from %s...\n", fname); if (!(file = fopen (fname, "r"))) { LOG (llevError, "Cannot open races file %s: %s\n", fname, strerror (errno)); return; } while (fgets (buf, MAX_BUF, file) != NULL) { int set_race = 1, set_list = 1; if (*buf == '#') continue; if ((cp = strchr (buf, '\n')) != NULL) *cp = '\0'; cp = buf; while (*cp == ' ' || *cp == '!' || *cp == '@') { if (*cp == '!') set_race = 0; if (*cp == '@') set_list = 0; cp++; } if (sscanf (cp, "RACE %s", variable)) /* set new race value */ strcpy (race, variable); else { char *cp1; /* Take out beginning spaces */ for (cp1 = cp; *cp1 == ' '; cp1++) ; /* Remove newline and trailing spaces */ for (cp1 = cp + strlen (cp) - 1; *cp1 == '\n' || *cp1 == ' '; cp1--) { *cp1 = '\0'; if (cp == cp1) break; } if (cp[strlen (cp) - 1] == '\n') cp[strlen (cp) - 1] = '\0'; /* set creature race to race value */ if ((mon = archetype::find (cp)) == NULL) LOG (llevError, "Creature %s in race file lacks archetype\n", cp); else { if (set_race && (!mon->race || strcmp (&mon->race, race))) { if (mon->race) LOG (llevDebug, "Resetting race to %s from %s for archetype %s\n", race, &mon->race, &mon->archname); mon->race = race; } /* if the arch is a monster, add it to the race list */ if (set_list && mon->flag [FLAG_MONSTER]) add_to_racelist (race, mon); } } } fclose (file); LOG (llevDebug, "done.\n"); } void init_beforeplay () { init_artifacts (); /* If not called before, reads all artifacts from file */ init_races (); /* overwrite race designations using entries in lib/races file */ init_gods (); /* init linked list of gods from archs */ init_readable (); /* inits useful arrays for readable texts */ init_formulae (); /* If not called before, reads formulae from file */ }