Crossfire Server, Branch 1.12  R12190
init.c
Go to the documentation of this file.
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 #define EXTERN
00035 #define INIT_C
00036 #include <global.h>
00037 #include <object.h>
00038 
00039 static void init_environ(void);
00040 static void init_defaults(void);
00041 static void init_dynamic(void);
00042 static void init_clocks(void);
00043 static void init_attackmess(void);
00044 
00048 struct Settings settings = {
00049     LOGFILE,   /* Logfile */
00050     CSPORT,    /* Client/server port */
00051 
00052     /* Debug level */
00053 #ifdef DEBUG
00054     llevDebug,
00055 #else
00056     llevInfo,
00057 #endif
00058     0, NULL, 0,    /* dumpvalues, dumparg, daemonmode */
00059     0, /* argc */
00060     NULL, /* argv */
00061     CONFDIR,
00062     DATADIR,
00063     LOCALDIR,
00064     PLAYERDIR, MAPDIR, ARCHETYPES, REGIONS, TREASURES,
00065     UNIQUE_DIR, TEMPLATE_DIR,
00066     TMPDIR,
00067     STAT_LOSS_ON_DEATH,
00068     PK_LUCK_PENALTY,
00069     PERMANENT_EXPERIENCE_RATIO,
00070     DEATH_PENALTY_RATIO,
00071     DEATH_PENALTY_LEVEL,
00072     BALANCED_STAT_LOSS,
00073     NOT_PERMADETH,
00074     SIMPLE_EXP,
00075     RESET_LOCATION_TIME,
00076     SET_TITLE,
00077     RESURRECTION,
00078     SEARCH_ITEMS,
00079     SPELL_ENCUMBRANCE,
00080     SPELL_FAILURE_EFFECTS,
00081     CASTING_TIME,
00082     REAL_WIZ,
00083     RECYCLE_TMP_MAPS,
00084     EXPLORE_MODE,
00085     SPELLPOINT_LEVEL_DEPEND,
00086     SET_FRIENDLY_FIRE,
00087     "", /* Who format specifier */
00088     "", /* who wiz format specifier */
00089     MOTD,
00090     "rules",
00091     "news",
00092     "",  /* DM_MAIL */
00093     0,  /* This and the next 3 values are metaserver values */
00094     "",
00095     "",
00096     0,
00097     "",
00098     0, 0, 0, 0, 0, 0, 0,  /* worldmap settings*/
00099     EMERGENCY_MAPPATH, EMERGENCY_X, EMERGENCY_Y,
00100     0,
00101     1.0,
00102     /* Armor enchantment stuff */
00103     ARMOR_MAX_ENCHANT,
00104     ARMOR_WEIGHT_REDUCTION,
00105     ARMOR_WEIGHT_LINEAR,
00106     ARMOR_SPEED_IMPROVEMENT,
00107     ARMOR_SPEED_LINEAR,
00108     1, /* no_player_stealing */
00109     0, /* create_home_portals */
00110     1, /* personalized_blessings */
00111     5000000, /* pk_max_experience */
00112     10, /* pk_max_experience_percent */
00113     0, /* allow_denied_spells_writing */
00114     0, /* allow_broken_converters */
00115     0, /* log_timestamp */
00116     NULL, /* log_timestamp_format */
00117 };
00118 
00119 struct Statistics statistics;
00120 
00126 const char *const spellpathnames[NRSPELLPATHS] = {
00127     "Protection",
00128     "Fire",
00129     "Frost",
00130     "Electricity",
00131     "Missiles",
00132     "Self",
00133     "Summoning",
00134     "Abjuration",
00135     "Restoration",
00136     "Detonation",
00137     "Mind",
00138     "Creation",
00139     "Teleportation",
00140     "Information",
00141     "Transmutation",
00142     "Transferrence",
00143     "Turning",
00144     "Wounding",
00145     "Death",
00146     "Light"
00147 };
00148 
00149 
00161 static void init_emergency_mappath(void) {
00162     char filename[MAX_BUF], tmpbuf[MAX_BUF];
00163     FILE *fp;
00164     int online = 0;
00165 
00166     /* If this file doesn't exist, not a big deal */
00167     snprintf(filename, sizeof(filename), "%s/%s/.emergency", settings.datadir, settings.mapdir);
00168     if ((fp = fopen(filename, "r")) != NULL) {
00169         while (fgets(tmpbuf, MAX_BUF-1, fp)) {
00170             if (tmpbuf[0] == '#')
00171                 continue; /* ignore comments */
00172 
00173             if (online == 0) {
00174                 tmpbuf[strlen(tmpbuf)-1] = 0; /* kill newline */
00175                 settings.emergency_mapname = strdup_local(tmpbuf);
00176             } else if (online == 1) {
00177                 settings.emergency_x = atoi(tmpbuf);
00178             } else if (online == 2) {
00179                 settings.emergency_y = atoi(tmpbuf);
00180             }
00181             online++;
00182             if (online > 2)
00183                 break;
00184         }
00185         fclose(fp);
00186         if (online <= 2)
00187             LOG(llevError, "Online read partial data from %s\n", filename);
00188         LOG(llevDebug, "Emergency mappath reset to %s (%d, %d)\n", settings.emergency_mapname, settings.emergency_x, settings.emergency_y);
00189     }
00190 }
00191 
00192 
00201 void init_library(void) {
00202     init_environ();
00203     init_globals();
00204     init_hash_table();
00205     i18n_init();
00206     init_objects();
00207     init_vars();
00208     init_block();
00209     read_bmap_names();
00210     read_smooth();
00211     init_anim();    /* Must be after we read in the bitmaps */
00212     init_archetypes(); /* Reads all archetypes from file */
00213     init_attackmess();
00214     init_clocks();
00215     init_emergency_mappath();
00216     init_experience();
00217     init_dynamic();
00218 }
00219 
00225 static void init_environ(void) {
00226     char *cp;
00227 
00228     cp = getenv("CROSSFIRE_LIBDIR");
00229     if (cp)
00230         settings.datadir = cp;
00231     cp = getenv("CROSSFIRE_LOCALDIR");
00232     if (cp)
00233         settings.localdir = cp;
00234     cp = getenv("CROSSFIRE_PLAYERDIR");
00235     if (cp)
00236         settings.playerdir = cp;
00237     cp = getenv("CROSSFIRE_MAPDIR");
00238     if (cp)
00239         settings.mapdir = cp;
00240     cp = getenv("CROSSFIRE_ARCHETYPES");
00241     if (cp)
00242         settings.archetypes = cp;
00243     cp = getenv("CROSSFIRE_TREASURES");
00244     if (cp)
00245         settings.treasures = cp;
00246     cp = getenv("CROSSFIRE_UNIQUEDIR");
00247     if (cp)
00248         settings.uniquedir = cp;
00249     cp = getenv("CROSSFIRE_TEMPLATEDIR");
00250     if (cp)
00251         settings.templatedir = cp;
00252     cp = getenv("CROSSFIRE_TMPDIR");
00253     if (cp)
00254         settings.tmpdir = cp;
00255 }
00256 
00263 void init_globals(void) {
00264 
00265     memset(&statistics, 0, sizeof(struct Statistics));
00266     if (settings.logfilename[0] == 0) {
00267         logfile = stderr;
00268     } else if ((logfile = fopen(settings.logfilename, "a")) == NULL) {
00269         fprintf(stderr, "Unable to open %s as the logfile - will use stderr instead\n", settings.logfilename);
00270         logfile = stderr;
00271     } else {
00272         setvbuf(logfile, NULL, _IOLBF, 0);
00273     }
00274     exiting = 0;
00275     first_player = NULL;
00276     first_friendly_object = NULL;
00277     first_map = NULL;
00278     first_treasurelist = NULL;
00279     first_artifactlist = NULL;
00280     first_archetype = NULL;
00281     *first_map_ext_path = 0;
00282     warn_archetypes = 0;
00283     nroftreasures = 0;
00284     nrofartifacts = 0;
00285     nrofallowedstr = 0;
00286     ring_arch = NULL;
00287     amulet_arch = NULL;
00288     staff_arch = NULL;
00289     undead_name = add_string("undead");
00290     trying_emergency_save = 0;
00291     num_animations = 0;
00292     animations = NULL;
00293     animations_allocated = 0;
00294     init_defaults();
00295 }
00296 
00307 void free_globals(void) {
00308     int msg, attack;
00309     objectlink *friend;
00310     region *reg;
00311 
00312     FREE_AND_CLEAR_STR(undead_name);
00313     for (msg = 0; msg < NROFATTACKMESS; msg++)
00314         for (attack = 0; attack < MAXATTACKMESS; attack++) {
00315             free(attack_mess[msg][attack].buf1);
00316             free(attack_mess[msg][attack].buf2);
00317             free(attack_mess[msg][attack].buf3);
00318         }
00319 
00320     free(settings.emergency_mapname);
00321 
00322     while (first_friendly_object) {
00323         friend = first_friendly_object->next;
00324         FREE_AND_CLEAR(first_friendly_object);
00325         first_friendly_object = friend;
00326     }
00327 
00328     free_experience();
00329 
00330     while (first_region) {
00331         reg = first_region->next;
00332         FREE_AND_CLEAR(first_region->name);
00333         FREE_AND_CLEAR(first_region->parent_name);
00334         FREE_AND_CLEAR(first_region->jailmap);
00335         FREE_AND_CLEAR(first_region->msg);
00336         FREE_AND_CLEAR(first_region->longname);
00337         FREE_AND_CLEAR(first_region);
00338         first_region = reg;
00339     }
00340 }
00341 
00347 void init_objects(void) {
00348     int i;
00349     /* Initialize all objects: */
00350     objects = NULL;
00351     active_objects = NULL;
00352 
00353 #ifdef MEMORY_DEBUG
00354     free_objects = NULL;
00355 #else
00356     free_objects = objarray;
00357     objarray[0].prev = NULL,
00358     objarray[0].next = &objarray[1],
00359     SET_FLAG(&objarray[0], FLAG_REMOVED);
00360     SET_FLAG(&objarray[0], FLAG_FREED);
00361     for (i = 1; i < STARTMAX-1; i++) {
00362         objarray[i].next = &objarray[i+1];
00363         objarray[i].prev = &objarray[i-1];
00364         SET_FLAG(&objarray[i], FLAG_REMOVED);
00365         SET_FLAG(&objarray[i], FLAG_FREED);
00366     }
00367     objarray[STARTMAX-1].next = NULL;
00368     objarray[STARTMAX-1].prev = &objarray[STARTMAX-2];
00369     SET_FLAG(&objarray[STARTMAX-1], FLAG_REMOVED);
00370     SET_FLAG(&objarray[STARTMAX-1], FLAG_FREED);
00371 #endif
00372 }
00373 
00378 static void init_defaults(void) {
00379     nroferrors = 0;
00380 }
00381 
00390 static void init_dynamic(void) {
00391     archetype *at = first_archetype;
00392     while (at) {
00393         if (at->clone.type == MAP) {
00394             if (at->clone.race) {
00395                 strcpy(first_map_ext_path, at->clone.race);
00396             }
00397             if (EXIT_PATH(&at->clone)) {
00398                 mapstruct *first;
00399 
00400                 snprintf(first_map_path, sizeof(first_map_path), "%s", EXIT_PATH(&at->clone));
00401                 first = ready_map_name(first_map_path, 0);
00402                 if (!first) {
00403                     LOG(llevError, "Initial map %s can't be found! Please ensure maps are correctly installed.\n", first_map_path);
00404                     LOG(llevError, "Unable to continue without initial map.\n");
00405                     abort();
00406                 }
00407                 delete_map(first);
00408                 return;
00409             }
00410         }
00411         at = at->next;
00412     }
00413     LOG(llevError, "You need a archetype called 'map' and it have to contain start map\n");
00414     exit(-1);
00415 }
00416 
00418 unsigned long todtick;
00419 
00424 void write_todclock(void) {
00425     char filename[MAX_BUF];
00426     FILE *fp;
00427 
00428     snprintf(filename, sizeof(filename), "%s/clockdata", settings.localdir);
00429     if ((fp = fopen(filename, "w")) == NULL) {
00430         LOG(llevError, "Cannot open %s for writing\n", filename);
00431         return;
00432     }
00433     fprintf(fp, "%lu", todtick);
00434     fclose(fp);
00435 }
00436 
00441 static void init_clocks(void) {
00442     char filename[MAX_BUF];
00443     FILE *fp;
00444     static int has_been_done = 0;
00445 
00446     if (has_been_done)
00447         return;
00448     else
00449         has_been_done = 1;
00450 
00451     snprintf(filename, sizeof(filename), "%s/clockdata", settings.localdir);
00452     LOG(llevDebug, "Reading clockdata from %s...\n", filename);
00453     if ((fp = fopen(filename, "r")) == NULL) {
00454         LOG(llevError, "Can't open %s.\n", filename);
00455         todtick = 0;
00456         write_todclock();
00457         return;
00458     }
00459     fscanf(fp, "%lu", &todtick);
00460     LOG(llevDebug, "todtick=%lu\n", todtick);
00461     fclose(fp);
00462 }
00463 
00465 attackmess_t attack_mess[NROFATTACKMESS][MAXATTACKMESS];
00466 
00473 static void init_attackmess(void) {
00474     char buf[MAX_BUF];
00475     char filename[MAX_BUF];
00476     char *cp, *p;
00477     FILE *fp;
00478     static int has_been_done = 0;
00479     int mess, level, comp;
00480     int mode = 0, total = 0;
00481 
00482     if (has_been_done)
00483         return;
00484     else
00485         has_been_done = 1;
00486 
00487     snprintf(filename, sizeof(filename), "%s/attackmess", settings.datadir);
00488     LOG(llevDebug, "Reading attack messages from %s...\n", filename);
00489     if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL) {
00490         LOG(llevError, "Can't open %s.\n", filename);
00491         return;
00492     }
00493 
00494     level = 0;
00495     while (fgets(buf, MAX_BUF, fp) != NULL) {
00496         if (*buf == '#')
00497             continue;
00498         if ((cp = strchr(buf, '\n')) != NULL)
00499             *cp = '\0';
00500         cp = buf;
00501         while (*cp == ' ') /* Skip blanks */
00502             cp++;
00503 
00504         if (strncmp(cp, "TYPE:", 5) == 0) {
00505             p = strtok(buf, ":");
00506             p = strtok(NULL, ":");
00507             if (mode == 1) {
00508                 attack_mess[mess][level].level = -1;
00509                 attack_mess[mess][level].buf1 = NULL;
00510                 attack_mess[mess][level].buf2 = NULL;
00511                 attack_mess[mess][level].buf3 = NULL;
00512             }
00513             level = 0;
00514             mess = atoi(p);
00515             mode = 1;
00516             continue;
00517         }
00518         if (mode == 1) {
00519             p = strtok(buf, "=");
00520             attack_mess[mess][level].level = atoi(buf);
00521             p = strtok(NULL, "=");
00522             if (p != NULL)
00523                 attack_mess[mess][level].buf1 = strdup_local(p);
00524             else
00525                 attack_mess[mess][level].buf1 = strdup_local("");
00526             mode = 2;
00527             continue;
00528         } else if (mode == 2) {
00529             p = strtok(buf, "=");
00530             attack_mess[mess][level].level = atoi(buf);
00531             p = strtok(NULL, "=");
00532             if (p != NULL)
00533                 attack_mess[mess][level].buf2 = strdup_local(p);
00534             else
00535                 attack_mess[mess][level].buf2 = strdup_local("");
00536             mode = 3;
00537             continue;
00538         } else if (mode == 3) {
00539             p = strtok(buf, "=");
00540             attack_mess[mess][level].level = atoi(buf);
00541             p = strtok(NULL, "=");
00542             if (p != NULL)
00543                 attack_mess[mess][level].buf3 = strdup_local(p);
00544             else
00545                 attack_mess[mess][level].buf3 = strdup_local("");
00546             mode = 1;
00547             level++;
00548             total++;
00549             continue;
00550         }
00551     }
00552     LOG(llevDebug, "got %d messages in %d categories.\n", total, mess+1);
00553     close_and_delete(fp, comp);
00554 }