Atrinik Server 2.5
server/init.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00031 #define INIT_C
00032 #define EXTERN
00033 
00034 #include <global.h>
00035 
00039 struct Settings settings =
00040 {
00041     /* Logfile */
00042     "",
00043     /* Client/server port */
00044     CSPORT,
00045     llevDebug,
00046     /* dumpvalues, dumparg, daemonmode */
00047     0, NULL, 0,
00048     DATADIR,
00049     LOCALDIR,
00050     MAPDIR, PLAYERDIR, ARCHETYPES,TREASURES,
00051     UNIQUE_DIR, TMPDIR,
00052     STAT_LOSS_ON_DEATH,
00053     BALANCED_STAT_LOSS,
00054     /* This and the next 3 values are metaserver values */
00055     0,
00056     "",
00057     "",
00058     "",
00059     "",
00060     ".",
00061     "",
00062     0,
00063     0,
00064     0,
00065     0,
00066     10,
00067     1.0f,
00068     0
00069 };
00070 
00072 int world_darkness;
00073 
00075 unsigned long todtick;
00076 
00078 archetype *level_up_arch = NULL;
00079 
00081 #define ARCHETYPE_LEVEL_UP "level_up"
00082 
00083 static void usage();
00084 static void help();
00085 static void init_beforeplay();
00086 static void fatal_signal(int make_core);
00087 static void init_signals();
00088 static void dump_level_colors_table();
00089 static void init_environ();
00090 static void init_defaults();
00091 static void init_dynamic();
00092 static void init_clocks();
00093 
00096 static void init_strings()
00097 {
00098     shstr_cons.none = add_string("none");
00099     shstr_cons.NONE = add_string("NONE");
00100     shstr_cons.home = add_string("- home -");
00101     shstr_cons.force = add_string("force");
00102     shstr_cons.portal_destination_name = add_string(PORTAL_DESTINATION_NAME);
00103     shstr_cons.portal_active_name = add_string(PORTAL_ACTIVE_NAME);
00104     shstr_cons.spell_quickslot = add_string("spell_quickslot");
00105 
00106     shstr_cons.GUILD_FORCE = add_string("GUILD_FORCE");
00107     shstr_cons.guild_force = add_string("guild_force");
00108     shstr_cons.RANK_FORCE = add_string("RANK_FORCE");
00109     shstr_cons.rank_force = add_string("rank_force");
00110     shstr_cons.ALIGNMENT_FORCE = add_string("ALIGNMENT_FORCE");
00111     shstr_cons.alignment_force = add_string("alignment_force");
00112 
00113     shstr_cons.grace_limit = add_string("grace limit");
00114     shstr_cons.restore_grace = add_string("restore grace");
00115     shstr_cons.restore_hitpoints = add_string("restore hitpoints");
00116     shstr_cons.restore_spellpoints = add_string("restore spellpoints");
00117     shstr_cons.heal_spell = add_string("heal spell");
00118     shstr_cons.remove_curse = add_string("remove curse");
00119     shstr_cons.remove_damnation = add_string("remove damnation");
00120     shstr_cons.heal_depletion = add_string("heal depletion");
00121     shstr_cons.message = add_string("message");
00122     shstr_cons.enchant_weapon = add_string("enchant weapon");
00123 
00124     shstr_cons.player_info = add_string("player_info");
00125     shstr_cons.BANK_GENERAL = add_string("BANK_GENERAL");
00126     shstr_cons.of_poison = add_string("of poison");
00127     shstr_cons.of_hideous_poison = add_string("of hideous poison");
00128 }
00129 
00132 void free_strings()
00133 {
00134     int nrof_strings = sizeof(shstr_cons) / sizeof(const char *);
00135     const char **ptr = (const char **) &shstr_cons;
00136     int i = 0;
00137 
00138     LOG(llevDebug, "Freeing all string constants\n");
00139 
00140     for (i = 0; i < nrof_strings; i++)
00141     {
00142         FREE_ONLY_HASH(ptr[i]);
00143     }
00144 }
00145 
00154 void init_library()
00155 {
00156     init_environ();
00157     init_hash_table();
00158     init_globals();
00159     /* Inits the pooling memory manager and the new object system */
00160     init_mempools();
00161     init_block();
00162     LOG(llevInfo, "Atrinik Server, v%s\n", VERSION);
00163     LOG(llevInfo, "Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team.\n");
00164     read_bmap_names();
00165     init_materials();
00166     /* Must be after we read in the bitmaps */
00167     init_anim();
00168     /* Reads all archetypes from file */
00169     init_archetypes();
00170     init_dynamic();
00171     init_clocks();
00172 
00173     /* init some often used default archetypes */
00174     if (level_up_arch == NULL)
00175     {
00176         level_up_arch = find_archetype(ARCHETYPE_LEVEL_UP);
00177     }
00178 
00179     if (!level_up_arch)
00180     {
00181         LOG(llevBug, "Can't find '%s' arch\n", ARCHETYPE_LEVEL_UP);
00182     }
00183 }
00184 
00190 static void init_environ()
00191 {
00192     char *cp;
00193 
00194     cp = getenv("ATRINIK_LIBDIR");
00195 
00196     if (cp)
00197     {
00198         settings.datadir = cp;
00199     }
00200 
00201     cp = getenv("ATRINIK_LOCALDIR");
00202 
00203     if (cp)
00204     {
00205         settings.localdir = cp;
00206     }
00207 
00208     cp = getenv("ATRINIK_MAPDIR");
00209 
00210     if (cp)
00211     {
00212         settings.mapdir = cp;
00213     }
00214 
00215     cp = getenv("ATRINIK_ARCHETYPES");
00216 
00217     if (cp)
00218     {
00219         settings.archetypes = cp;
00220     }
00221 
00222     cp = getenv("ATRINIK_TREASURES");
00223 
00224     if (cp)
00225     {
00226         settings.treasures = cp;
00227     }
00228 
00229     cp = getenv("ATRINIK_UNIQUEDIR");
00230 
00231     if (cp)
00232     {
00233         settings.uniquedir = cp;
00234     }
00235 
00236     cp = getenv("ATRINIK_TMPDIR");
00237 
00238     if (cp)
00239     {
00240         settings.tmpdir = cp;
00241     }
00242 }
00243 
00247 void init_globals()
00248 {
00249     if (settings.logfilename[0] == '\0')
00250     {
00251         logfile = stderr;
00252     }
00253     else if ((logfile = fopen(settings.logfilename, "w")) == NULL)
00254     {
00255         logfile = stderr;
00256         LOG(llevBug, "Unable to open %s as the logfile - will use stderr instead\n", settings.logfilename);
00257     }
00258 
00259     /* Global round ticker */
00260     global_round_tag = 1;
00261     /* Global race counter */
00262     global_race_counter = 0;
00263 
00264     first_player = NULL;
00265     last_player = NULL;
00266     first_map = NULL;
00267     first_treasurelist = NULL;
00268     first_artifactlist = NULL;
00269     first_archetype = NULL;
00270     first_map = NULL;
00271     nroftreasures = 0;
00272     nrofartifacts = 0;
00273     nrofallowedstr = 0;
00274     init_strings();
00275     init_object_initializers();
00276     num_animations = 0;
00277     animations = NULL;
00278     animations_allocated = 0;
00279     init_defaults();
00280 }
00281 
00286 static void init_defaults()
00287 {
00288     nroferrors = 0;
00289 }
00290 
00293 static void init_dynamic()
00294 {
00295     archetype *at = first_archetype;
00296 
00297     while (at)
00298     {
00299         if (at->clone.type == MAP && EXIT_PATH(&at->clone))
00300         {
00301             strcpy(first_map_path, EXIT_PATH(&at->clone));
00302             return;
00303         }
00304 
00305         at = at->next;
00306     }
00307 
00308     LOG(llevError, "init_dynamic(): You need an archetype called 'map' and it has to contain start map.\n");
00309 }
00310 
00314 void write_todclock()
00315 {
00316     char filename[MAX_BUF];
00317     FILE *fp;
00318 
00319     snprintf(filename, sizeof(filename), "%s/clockdata", settings.localdir);
00320 
00321     if ((fp = fopen(filename, "w")) == NULL)
00322     {
00323         LOG(llevBug, "Cannot open %s for writing.\n", filename);
00324         return;
00325     }
00326 
00327     fprintf(fp, "%lu", todtick);
00328     fclose(fp);
00329 }
00330 
00335 static void init_clocks()
00336 {
00337     char filename[MAX_BUF];
00338     FILE *fp;
00339     static int has_been_done = 0;
00340 
00341     if (has_been_done)
00342     {
00343         return;
00344     }
00345     else
00346     {
00347         has_been_done = 1;
00348     }
00349 
00350     snprintf(filename, sizeof(filename), "%s/clockdata", settings.localdir);
00351     LOG(llevDebug, "Reading clockdata from %s...", filename);
00352 
00353     if ((fp = fopen(filename, "r")) == NULL)
00354     {
00355         LOG(llevDebug, "Can't open %s.\n", filename);
00356         todtick = 0;
00357         write_todclock();
00358         return;
00359     }
00360 
00361     if (fscanf(fp, "%lu", &todtick))
00362     {
00363         LOG(llevDebug, "todtick=%lu\n", todtick);
00364     }
00365 
00366     fclose(fp);
00367 }
00368 
00371 static void set_logfile(char *val)
00372 {
00373     settings.logfilename = val;
00374 }
00375 
00376 static void call_version()
00377 {
00378     version(NULL);
00379     exit(0);
00380 }
00381 
00382 static void showscores()
00383 {
00384     hiscore_display(NULL, 9999, NULL);
00385     exit(0);
00386 }
00387 
00388 static void set_debug()
00389 {
00390     settings.debug = llevDebug;
00391 }
00392 
00393 static void unset_debug()
00394 {
00395     settings.debug = llevInfo;
00396 }
00397 
00398 static void set_timestamp()
00399 {
00400     settings.timestamp = 1;
00401 }
00402 
00403 static void set_dumpmon1()
00404 {
00405     settings.dumpvalues = DUMP_VALUE_MONSTERS;
00406 }
00407 
00408 static void set_dumpmon2()
00409 {
00410     settings.dumpvalues = DUMP_VALUE_ABILITIES;
00411 }
00412 
00413 static void set_dumpmon3()
00414 {
00415     settings.dumpvalues = DUMP_VALUE_ARTIFACTS;
00416 }
00417 
00418 static void set_dumpmon4()
00419 {
00420     settings.dumpvalues = DUMP_VALUE_SPELLS;
00421 }
00422 
00423 static void set_dumpmon5()
00424 {
00425     settings.dumpvalues = DUMP_VALUE_SKILLS;
00426 }
00427 
00428 static void set_dumpmon6()
00429 {
00430     settings.dumpvalues = DUMP_VALUE_RACES;
00431 }
00432 
00433 static void set_dumpmon7()
00434 {
00435     settings.dumpvalues = DUMP_VALUE_ALCHEMY;
00436 }
00437 
00438 static void set_dumpmon8()
00439 {
00440     settings.dumpvalues = DUMP_VALUE_GODS;
00441 }
00442 
00443 static void set_dumpmon9()
00444 {
00445     settings.dumpvalues = DUMP_VALUE_ALCHEMY_COSTS;
00446 }
00447 
00448 static void set_dumpmon10()
00449 {
00450     settings.dumpvalues = DUMP_VALUE_ARCHETYPES;
00451 }
00452 
00453 static void set_dumpmon11(char *name)
00454 {
00455     settings.dumpvalues = DUMP_VALUE_MONSTER_TREASURE;
00456     settings.dumparg = name;
00457 }
00458 
00459 static void set_dumpmon12()
00460 {
00461     settings.dumpvalues = DUMP_VALUE_LEVEL_COLORS;
00462 }
00463 
00464 static void set_spell_dump(char *arg)
00465 {
00466     settings.dumpvalues = DUMP_VALUE_SPELLS;
00467     settings.dumparg = arg;
00468 }
00469 
00470 static void set_daemon()
00471 {
00472     settings.daemonmode = 1;
00473 }
00474 
00475 static void set_watchdog()
00476 {
00477     settings.watchdog = 1;
00478 }
00479 
00480 static void set_interactive()
00481 {
00482     settings.interactive = 1;
00483 }
00484 
00485 static void set_datadir(char *path)
00486 {
00487     settings.datadir = path;
00488 }
00489 
00490 static void set_localdir(char *path)
00491 {
00492     settings.localdir = path;
00493 }
00494 
00495 static void set_mapdir(char *path)
00496 {
00497     settings.mapdir = path;
00498 }
00499 
00500 static void set_archetypes(char *path)
00501 {
00502     settings.archetypes = path;
00503 }
00504 
00505 static void set_treasures(char *path)
00506 {
00507     settings.treasures = path;
00508 }
00509 
00510 static void set_uniquedir(char *path)
00511 {
00512     settings.uniquedir = path;
00513 }
00514 
00515 static void set_tmpdir(char *path)
00516 {
00517     settings.tmpdir = path;
00518 }
00519 
00520 static void showscoresparm(const char *data)
00521 {
00522     hiscore_display(NULL, 9999, data);
00523     exit(0);
00524 }
00525 
00526 static void set_csport(const char *val)
00527 {
00528     settings.csport = atoi(val);
00529 
00530 #ifndef WIN32
00531     if (settings.csport <= 0 || settings.csport > 32765 || (settings.csport < 1024 && getuid() != 0))
00532     {
00533         LOG(llevError, "%d is an invalid csport number.\n", settings.csport);
00534     }
00535 #endif
00536 }
00537 
00538 static void stat_loss_on_death_true()
00539 {
00540     settings.stat_loss_on_death = 1;
00541 }
00542 
00543 static void stat_loss_on_death_false()
00544 {
00545     settings.stat_loss_on_death = 0;
00546 }
00547 
00548 static void balanced_stat_loss_true()
00549 {
00550     settings.balanced_stat_loss = 1;
00551 }
00552 
00553 static void balanced_stat_loss_false()
00554 {
00555     settings.balanced_stat_loss = 0;
00556 }
00557 
00558 static void set_unit_tests()
00559 {
00560 #if defined(HAVE_CHECK)
00561     settings.unit_tests = 1;
00562 #else
00563     LOG(llevInfo, "The server was built without the check unit testing framework.\nIf you want to run unit tests, you must first install this framework.\n");
00564     exit(0);
00565 #endif
00566 }
00567 
00568 static void set_world_maker(const char *data)
00569 {
00570 #if defined(HAVE_WORLD_MAKER)
00571     settings.world_maker = 1;
00572 
00573     if (data)
00574     {
00575         strncpy(settings.world_maker_dir, data, sizeof(settings.world_maker_dir) - 1);
00576         settings.world_maker_dir[sizeof(settings.world_maker_dir) - 1] = '\0';
00577     }
00578 #else
00579     (void) data;
00580     LOG(llevInfo, "The server was built without the world maker module.\n");
00581     exit(0);
00582 #endif
00583 }
00584 
00588 struct Command_Line_Options
00589 {
00591     char *cmd_option;
00592 
00594     uint8 num_args;
00595 
00597     uint8 pass;
00598 
00604     void (*func)();
00605 };
00606 
00615 struct Command_Line_Options options[] =
00616 {
00617     /* Pass 1 functions - Stuff that can/should be called before we actually
00618      * initialize any data. */
00619     {"-h", 0, 1, help},
00620     /* Honor -help also, since it is somewhat common */
00621     {"-help", 0, 1, help},
00622     {"-v", 0, 1, call_version},
00623     {"-d", 0, 1, set_debug},
00624     {"+d", 0, 1, unset_debug},
00625     {"-data",1,1, set_datadir},
00626     {"-local",1,1, set_localdir},
00627     {"-maps", 1, 1, set_mapdir},
00628     {"-arch", 1, 1, set_archetypes},
00629     {"-treasures", 1, 1, set_treasures},
00630     {"-uniquedir", 1, 1, set_uniquedir},
00631     {"-tmpdir", 1, 1, set_tmpdir},
00632     {"-log", 1, 1, set_logfile},
00633     {"-ts", 0, 1, set_timestamp},
00634 
00635     /* Pass 2 functions.  Most of these could probably be in pass 1,
00636      * as they don't require much of anything to bet set up. */
00637     {"-csport", 1, 2, set_csport},
00638     {"-detach", 0, 2, set_daemon},
00639     {"-watchdog", 0, 2, set_watchdog},
00640     {"-interactive", 0, 2, set_interactive},
00641 
00642     /* Start of pass 3 information. In theory, by pass 3, all data paths
00643      * and defaults should have been set up.  */
00644     {"-o", 0, 3, compile_info},
00645 
00646     {"-m1", 0, 3, set_dumpmon1},
00647     {"-m2", 0, 3, set_dumpmon2},
00648     {"-m3", 0, 3, set_dumpmon3},
00649     {"-m4", 0, 3, set_dumpmon4},
00650     {"-m5", 0, 3, set_dumpmon5},
00651     {"-m6", 0, 3, set_dumpmon6},
00652     {"-m7", 0, 3, set_dumpmon7},
00653     {"-m8", 0, 3, set_dumpmon8},
00654     {"-m9", 0, 3, set_dumpmon9},
00655     {"-m10", 0, 3, set_dumpmon10},
00656     {"-m11", 1, 3, set_dumpmon11},
00657     {"-m12", 0, 3, set_dumpmon12},
00658     {"-spell", 1, 3, set_spell_dump},
00659 
00660     {"-tests", 0, 3, set_unit_tests},
00661     {"-world_maker", 1, 3, set_world_maker},
00662 
00663     {"-s", 0, 3, showscores},
00664     {"-score", 1, 3, showscoresparm},
00665     {"-stat_loss_on_death", 0, 3, stat_loss_on_death_true},
00666     {"+stat_loss_on_death", 0, 3, stat_loss_on_death_false},
00667     {"-balanced_stat_loss", 0, 3, balanced_stat_loss_true},
00668     {"+balanced_stat_loss", 0, 3, balanced_stat_loss_false}
00669 };
00670 
00679 static void parse_args(int argc, char *argv[], int pass)
00680 {
00681     size_t i;
00682     int on_arg = 1;
00683 
00684     while (on_arg < argc)
00685     {
00686         for (i = 0; i < sizeof(options) / sizeof(struct Command_Line_Options); i++)
00687         {
00688             if (!strcmp(options[i].cmd_option, argv[on_arg]) || (argv[on_arg][0] == '-' && !strcmp(options[i].cmd_option, argv[on_arg] + 1)))
00689             {
00690                 /* Found a matching option, but should not be processed on
00691                  * this pass.  Just skip over it */
00692                 if (options[i].pass != pass)
00693                 {
00694                     on_arg += options[i].num_args + 1;
00695                     break;
00696                 }
00697 
00698                 if (options[i].num_args)
00699                 {
00700                     if ((on_arg + options[i].num_args) >= argc)
00701                     {
00702                         LOG(llevSystem, "command line: %s requires an argument.\n", options[i].cmd_option);
00703                         exit(1);
00704                     }
00705                     else
00706                     {
00707                         if (options[i].num_args == 1)
00708                         {
00709                             options[i].func(argv[on_arg + 1]);
00710                         }
00711 
00712                         if (options[i].num_args == 2)
00713                         {
00714                             options[i].func(argv[on_arg + 1],argv[on_arg + 2]);
00715                         }
00716 
00717                         on_arg += options[i].num_args + 1;
00718                     }
00719                 }
00720                 /* takes no args */
00721                 else
00722                 {
00723                     options[i].func();
00724                     on_arg++;
00725                 }
00726 
00727                 break;
00728             }
00729         }
00730 
00731         if (i == sizeof(options) / sizeof(struct Command_Line_Options))
00732         {
00733             LOG(llevSystem, "Unknown option: %s\n", argv[on_arg]);
00734             usage();
00735             exit(1);
00736         }
00737     }
00738 }
00739 
00746 static void load_settings()
00747 {
00748     char buf[MAX_BUF], *cp;
00749     int has_val, comp;
00750     FILE *fp;
00751 
00752     snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, SETTINGS);
00753 
00754     /* We don't require a settings file at current time, but down the road,
00755      * there will probably be so many values that not having a settings file
00756      * will not be a good thing. */
00757     if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL)
00758     {
00759         LOG(llevBug, "No %s file found\n", SETTINGS);
00760         return;
00761     }
00762 
00763     while (fgets(buf, MAX_BUF-1, fp) != NULL)
00764     {
00765         if (buf[0] == '#')
00766         {
00767             continue;
00768         }
00769 
00770         /* eliminate newline */
00771         if ((cp = strrchr(buf, '\n')) != NULL)
00772         {
00773             *cp = '\0';
00774         }
00775 
00776         /* Skip over empty lines */
00777         if (buf[0] == 0)
00778         {
00779             continue;
00780         }
00781 
00782         /* Skip all the spaces and set them to nulls.  If not space,
00783          * set cp to "" to make strcpy's and the like easier down below. */
00784         if ((cp = strchr(buf, ' ')) != NULL)
00785         {
00786             while (*cp == ' ')
00787             {
00788                 *cp++ = 0;
00789             }
00790 
00791             has_val = 1;
00792         }
00793         else
00794         {
00795             cp = "";
00796             has_val = 0;
00797         }
00798 
00799         if (!strcasecmp(buf, "metaserver_notification"))
00800         {
00801             if (!strcasecmp(cp, "on") || !strcasecmp(cp, "true"))
00802             {
00803                 settings.meta_on = 1;
00804             }
00805             else if (!strcasecmp(cp, "off") || !strcasecmp(cp, "false"))
00806             {
00807                 settings.meta_on = 0;
00808             }
00809             else
00810             {
00811                 LOG(llevBug, "load_settings(): Unknown value for metaserver_notification: %s\n", cp);
00812             }
00813         }
00814         else if (!strcasecmp(buf, "metaserver_server"))
00815         {
00816             if (has_val)
00817             {
00818                 strcpy(settings.meta_server, cp);
00819             }
00820             else
00821             {
00822                 LOG(llevBug, "load_settings(): metaserver_server must have a value.\n");
00823             }
00824         }
00825         else if (!strcasecmp(buf, "metaserver_host"))
00826         {
00827             if (has_val)
00828             {
00829                 strcpy(settings.meta_host, cp);
00830             }
00831             else
00832             {
00833                 LOG(llevBug, "load_settings(): metaserver_host must have a value.\n");
00834             }
00835         }
00836         else if (!strcasecmp(buf, "metaserver_name"))
00837         {
00838             if (has_val)
00839             {
00840                 strcpy(settings.meta_name, cp);
00841             }
00842             else
00843             {
00844                 LOG(llevBug, "load_settings(): metaserver_name must have a value.\n");
00845             }
00846         }
00847         else if (!strcasecmp(buf, "metaserver_comment"))
00848         {
00849             strcpy(settings.meta_comment, cp);
00850         }
00851         else if (!strcasecmp(buf, "item_power_factor"))
00852         {
00853             float tmp = atof(cp);
00854 
00855             if (tmp < 0)
00856             {
00857                 LOG(llevError, "load_settings(): item_power_factor must be a positive number (%f < 0).\n", tmp);
00858             }
00859             else
00860             {
00861                 settings.item_power_factor = tmp;
00862             }
00863         }
00864         else if (!strcasecmp(buf, "magic_devices_level"))
00865         {
00866             settings.magic_devices_level = atoi(cp);
00867         }
00868         else if (!strcasecmp(buf, "client_maps"))
00869         {
00870             if (has_val)
00871             {
00872                 strcpy(settings.client_maps_url, cp);
00873             }
00874             else
00875             {
00876                 LOG(llevBug, "load_settings(): client_maps must have a value.\n");
00877             }
00878         }
00879         else
00880         {
00881             LOG(llevBug, "Unknown value in %s file: %s\n", SETTINGS, buf);
00882         }
00883     }
00884 
00885     close_and_delete(fp, comp);
00886 }
00887 
00894 void init(int argc, char **argv)
00895 {
00896     /* We don't want to be affected by players' umask */
00897     (void) umask(0);
00898 
00899     /* Must be done before init_signal() */
00900     init_done = 0;
00901     logfile = stderr;
00902 
00903     /* First arg pass - right now it does
00904      * nothing, but in future specifying the
00905      * LibDir in this pass would be reasonable*/
00906     parse_args(argc, argv, 1);
00907 
00908     /* Must be called early */
00909     init_library();
00910     /* Load the settings file */
00911     load_settings();
00912     init_world_darkness();
00913     parse_args(argc, argv, 2);
00914 
00915     SRANDOM(time(NULL));
00916 
00917     /* Sets up signal interceptions */
00918     init_signals();
00919     /* Sort command tables */
00920     init_commands();
00921     /* Load up the old temp map files */
00922     read_map_log();
00923     parse_args(argc, argv, 3);
00924     cftimer_init();
00925     init_regions();
00926     hiscore_init();
00927 
00928 #ifndef WIN32
00929     if (settings.daemonmode)
00930     {
00931         become_daemon(settings.logfilename[0] == '\0' ? "logfile" : settings.logfilename);
00932     }
00933 #endif
00934 
00935     init_beforeplay();
00936     init_ericserver();
00937     metaserver_init();
00938     load_bans_file();
00939     statistics_init();
00940     reset_sleep();
00941     init_done = 1;
00942 }
00943 
00946 static void usage()
00947 {
00948     LOG(llevInfo, "Usage: atrinik_server [-h] [-<flags>]...\n");
00949 }
00950 
00953 static void help()
00954 {
00955     LOG(llevInfo, "Flags:\n");
00956     LOG(llevInfo, " -csport <port> Specifies the port to use for the new client/server code.\n");
00957     LOG(llevInfo, " -d          Turns on some debugging.\n");
00958     LOG(llevInfo, " +d          Turns off debugging (useful if server compiled with debugging\n");
00959     LOG(llevInfo, "             as default).\n");
00960     LOG(llevInfo, " -detach     The server will go in the background, closing all\n");
00961     LOG(llevInfo, "             connections to the tty (UNIX only).\n");
00962     LOG(llevInfo, " -h, -help   Display this information.\n");
00963     LOG(llevInfo, " -log <file> Specifies which file to send output to.\n");
00964     LOG(llevInfo, "             Only has meaning if -detach is specified.\n");
00965     LOG(llevInfo, " -o          Prints out info on what was defined at compile time.\n");
00966     LOG(llevInfo, " -s          Display the high-score list.\n");
00967     LOG(llevInfo, " -score <name or class> Displays all high scores with matching name/class.\n");
00968     LOG(llevInfo, " -stat_loss_on_death - If set, player loses stat when they die.\n");
00969     LOG(llevInfo, " +stat_loss_on_death - If set, player does not lose a stat when they die.\n");
00970     LOG(llevInfo, " -balanced_stat_loss - If set, death stat depletion is balanced by level etc.\n");
00971     LOG(llevInfo, " +balanced_stat_loss - If set, ordinary death stat depletion is used.\n");
00972     LOG(llevInfo, " -v          Print version information.\n");
00973     LOG(llevInfo, " -data       Sets the lib dir (archetypes, treasures, etc.)\n");
00974     LOG(llevInfo, " -local      Read/write local data (hiscore, unique items, etc.)\n");
00975     LOG(llevInfo, " -maps       Sets the directory for maps.\n");
00976     LOG(llevInfo, " -arch       Sets the archetype file to use.\n");
00977     LOG(llevInfo, " -treasures  Sets the treasures file to use.\n");
00978     LOG(llevInfo, " -uniquedir  Sets the unique items/maps directory.\n");
00979     LOG(llevInfo, " -tmpdir     Sets the directory for temporary files (mostly maps.)\n");
00980     LOG(llevInfo, " -m1         Dumps out object settings for all monsters.\n");
00981     LOG(llevInfo, " -m2         Dumps out abilities for all monsters.\n");
00982     LOG(llevInfo, " -m3         Dumps out artifact information.\n");
00983     LOG(llevInfo, " -m4         Dumps out spell information.\n");
00984     LOG(llevInfo, " -m5         Dumps out skill information.\n");
00985     LOG(llevInfo, " -m6         Dumps out race information.\n");
00986     LOG(llevInfo, " -m7         Dumps out alchemy information.\n");
00987     LOG(llevInfo, " -m8         Dumps out gods information.\n");
00988     LOG(llevInfo, " -m9         Dumps out more alchemy information (formula checking).\n");
00989     LOG(llevInfo, " -m10        Dumps out all arches.\n");
00990     LOG(llevInfo, " -m11 <arch> Dumps out list of treasures for a monster.\n");
00991     LOG(llevInfo, " -m12        Dumps out level colors table.\n");
00992     LOG(llevInfo, " -spell <name> Dumps various information about the specified spell\n");
00993     LOG(llevInfo, "             (if 'all', information about all spells available). This\n");
00994     LOG(llevInfo, "             is useful when debugging/balancing spells.\n");
00995 
00996 #if defined(HAVE_CHECK)
00997     LOG(llevInfo, " -tests      Runs unit tests.\n");
00998 #endif
00999 
01000 #if defined(HAVE_WORLD_MAKER)
01001     LOG(llevInfo, " -world_maker <path> Generates region maps and stores them in the specified path.\n");
01002 #endif
01003 
01004     LOG(llevInfo, " -watchdog   Enables sending datagrams to an external watchdog program.\n");
01005     LOG(llevInfo, " -interactive Enables interactive mode. Type 'help' in console for more information.\n");
01006     LOG(llevInfo, " -ts         If enabled, all log entries will be prefixed with UNIX timestamp.\n");
01007 
01008     exit(0);
01009 }
01010 
01013 static void init_beforeplay()
01014 {
01015     init_archetypes();
01016     init_spells();
01017     race_init();
01018     init_gods();
01019     init_readable();
01020     init_archetype_pointers();
01021     init_formulae();
01022     init_new_exp_system();
01023 
01024     if (settings.dumpvalues)
01025     {
01026         switch (settings.dumpvalues)
01027         {
01028             case DUMP_VALUE_MONSTERS:
01029                 print_monsters();
01030                 break;
01031 
01032             case DUMP_VALUE_ABILITIES:
01033                 dump_abilities();
01034                 break;
01035 
01036             case DUMP_VALUE_ARTIFACTS:
01037                 dump_artifacts();
01038                 break;
01039 
01040             case DUMP_VALUE_SPELLS:
01041                 dump_spells();
01042                 break;
01043 
01044             case DUMP_VALUE_SKILLS:
01045                 dump_skills();
01046                 break;
01047 
01048             case DUMP_VALUE_RACES:
01049                 race_dump();
01050                 break;
01051 
01052             case DUMP_VALUE_ALCHEMY:
01053                 dump_alchemy();
01054                 break;
01055 
01056             case DUMP_VALUE_GODS:
01057                 dump_gods();
01058                 break;
01059 
01060             case DUMP_VALUE_ALCHEMY_COSTS:
01061                 dump_alchemy_costs();
01062                 break;
01063 
01064             case DUMP_VALUE_ARCHETYPES:
01065                 dump_all_archetypes();
01066                 break;
01067 
01068             case DUMP_VALUE_MONSTER_TREASURE:
01069                 dump_monster_treasure(settings.dumparg);
01070                 break;
01071 
01072             case DUMP_VALUE_LEVEL_COLORS:
01073                 dump_level_colors_table();
01074                 break;
01075         }
01076 
01077         exit(0);
01078     }
01079 }
01080 
01086 void compile_info()
01087 {
01088     int i = 0;
01089 
01090     LOG(llevInfo, "Setup info:\n");
01091     LOG(llevInfo, "Non-standard include files:\n");
01092 #if !defined (__STRICT_ANSI__) || defined (__sun__)
01093 #if !defined (Mips)
01094     LOG(llevInfo, "<stdlib.h>\n");
01095     i = 1;
01096 #endif
01097 
01098 #if !defined (MACH) && !defined (sony)
01099     LOG(llevInfo, "<malloc.h>\n");
01100     i = 1;
01101 #endif
01102 #endif
01103 
01104 #ifndef __STRICT_ANSI__
01105 #ifndef MACH
01106     LOG(llevInfo, "<memory.h\n");
01107     i = 1;
01108 #endif
01109 #endif
01110 
01111 #ifndef sgi
01112     LOG(llevInfo, "<sys/timeb.h>\n");
01113     i = 1;
01114 #endif
01115 
01116     if (!i)
01117     {
01118         LOG(llevInfo, "(none)\n");
01119     }
01120 
01121     LOG(llevInfo, "Datadir:\t%s\n", settings.datadir);
01122     LOG(llevInfo, "Localdir:\t%s\n", settings.localdir);
01123 
01124     LOG(llevInfo, "Save player:\t<true>\n");
01125     LOG(llevInfo, "Save mode:\t%4.4o\n", SAVE_MODE);
01126     LOG(llevInfo, "Itemsdir:\t%s/%s\n", settings.localdir, settings.uniquedir);
01127 
01128     LOG(llevInfo, "Tmpdir:\t\t%s\n", settings.tmpdir);
01129     LOG(llevInfo, "Map timeout:\t%d\n", MAP_MAXTIMEOUT);
01130 
01131     LOG(llevInfo, "Objects:\tAllocated: %d, free: %d\n", pool_object->nrof_allocated[0], pool_object->nrof_free[0]);
01132 
01133 #ifdef USE_CALLOC
01134     LOG(llevInfo, "Use_calloc:\t<true>\n");
01135 #else
01136     LOG(llevInfo, "Use_calloc:\t<false>\n");
01137 #endif
01138 
01139     LOG(llevInfo, "Max_time:\t%d\n", MAX_TIME);
01140 
01141     LOG(llevInfo, "Logfilename:\t%s (llev:%d)\n", settings.logfilename, settings.debug);
01142     LOG(llevInfo, "ObjectSize:\t%"FMT64U" (living: %"FMT64U")\n", (uint64) sizeof(object), (uint64) sizeof(living));
01143     LOG(llevInfo, "ObjectlinkSize:\t%"FMT64U"\n", (uint64) sizeof(objectlink));
01144     LOG(llevInfo, "MapStructSize:\t%"FMT64U"\n", (uint64) sizeof(mapstruct));
01145     LOG(llevInfo, "MapSpaceSize:\t%"FMT64U"\n", (uint64) sizeof(MapSpace));
01146     LOG(llevInfo, "PlayerSize:\t%"FMT64U"\n", (uint64) sizeof(player));
01147     LOG(llevInfo, "SocketSize:\t%"FMT64U"\n", (uint64) sizeof(socket_struct));
01148     LOG(llevInfo, "PartylistSize:\t%"FMT64U"\n", (uint64) sizeof(party_struct));
01149     LOG(llevInfo, "KeyValueSize:\t%"FMT64U"\n", (uint64) sizeof(key_value));
01150 
01151     LOG(llevInfo, "Setup info: Done.\n");
01152 }
01153 
01156 static void rec_sigsegv(int i)
01157 {
01158     (void) i;
01159 
01160     LOG(llevSystem, "\nSIGSEGV received.\n");
01161     fatal_signal(1);
01162 }
01163 
01164 static void rec_sigint(int i)
01165 {
01166     (void) i;
01167 
01168     LOG(llevSystem, "\nSIGINT received.\n");
01169     fatal_signal(0);
01170 }
01171 
01172 static void rec_sighup(int i)
01173 {
01174     (void) i;
01175 
01176     LOG(llevSystem, "\nSIGHUP received\n");
01177 
01178     if (init_done)
01179     {
01180         emergency_save(0);
01181         cleanup();
01182     }
01183 
01184     exit(0);
01185 }
01186 
01187 static void rec_sigquit(int i)
01188 {
01189     (void) i;
01190 
01191     LOG(llevSystem, "\nSIGQUIT received\n");
01192     fatal_signal(1);
01193 }
01194 
01195 static void rec_sigpipe(int i)
01196 {
01197     (void) i;
01198 
01199 #ifndef WIN32
01200     LOG(llevSystem, "\nSIGPIPE received, ignoring\n");
01201     signal(SIGPIPE, rec_sigpipe);
01202 #else
01203     LOG(llevSystem, "\nSIGPIPE received\n");
01204     fatal_signal(1);
01205 #endif
01206 }
01207 
01208 static void rec_sigbus(int i)
01209 {
01210     (void) i;
01211 
01212 #ifdef SIGBUS
01213     LOG(llevSystem, "\nSIGBUS received\n");
01214     fatal_signal(1);
01215 #endif
01216 }
01217 
01218 static void rec_sigterm(int i)
01219 {
01220     (void) i;
01221 
01222     LOG(llevSystem,"\nSIGTERM received\n");
01223     fatal_signal(0);
01224 }
01225 
01233 static void fatal_signal(int make_core)
01234 {
01235     if (init_done)
01236     {
01237         emergency_save(0);
01238         cleanup();
01239     }
01240 
01241     if (make_core)
01242     {
01243         abort();
01244     }
01245 
01246     exit(0);
01247 }
01248 
01251 static void init_signals()
01252 {
01253 #ifndef WIN32
01254     /* init_signals() remove signals */
01255     signal(SIGHUP, rec_sighup);
01256     signal(SIGINT, rec_sigint);
01257     signal(SIGQUIT, rec_sigquit);
01258     signal(SIGSEGV, rec_sigsegv);
01259     signal(SIGPIPE, rec_sigpipe);
01260 #   ifdef SIGBUS
01261     signal(SIGBUS, rec_sigbus);
01262 #   endif
01263     signal(SIGTERM, rec_sigterm);
01264 #endif
01265 }
01266 
01269 static void dump_level_colors_table()
01270 {
01271     int i, ii, range, tmp;
01272 
01273     uint32 vx = 0, vc = 1000000;
01274     float xc = 38;
01275 
01276     for (i = 0; i < 100; i++)
01277     {
01278         vc += 100000;
01279         vx += vc;
01280         LOG(-1, "%4.2f, ", (((float) vc) / xc) / 125.0f);
01281         xc += 2;
01282     }
01283 
01284     LOG(-1, "\n");
01285 
01286     for (i = 1; i < 201; i++)
01287     {
01288         for (ii = i; ii > 1; ii--)
01289         {
01290             if (!calc_level_difference(i, ii))
01291             {
01292                 break;
01293             }
01294         }
01295 
01296         level_color[i].yellow = i - (i / 33);
01297         level_color[i].blue = level_color[i].yellow - 1;
01298         level_color[i].orange = i + (i / 33) + 1;
01299 
01300         range = level_color[i].yellow - ii - 1;
01301 
01302         if (range < 2)
01303         {
01304             level_color[i].green = level_color[i].blue - 1;
01305             level_color[i].red = level_color[i].orange + 1;
01306             level_color[i].purple = level_color[i].orange + 2;
01307         }
01308         else
01309         {
01310             tmp = (int) ((double) range * 0.4);
01311 
01312             if (!tmp)
01313             {
01314                 tmp = 1;
01315             }
01316             else if (tmp == range)
01317             {
01318                 tmp--;
01319             }
01320 
01321             level_color[i].green = level_color[i].blue - (range - tmp);
01322 
01323             range = (int) ((double) range * 0.75);
01324 
01325             if (!range)
01326             {
01327                 range = 0;
01328             }
01329 
01330             tmp = (int) ((double) range * 0.7);
01331 
01332             if (!tmp)
01333             {
01334                 tmp = 1;
01335             }
01336             else if (tmp == range)
01337             {
01338                 tmp--;
01339             }
01340 
01341             if (tmp == range)
01342             {
01343                 range++;
01344             }
01345 
01346             level_color[i].red = level_color[i].orange + (range - tmp);
01347             level_color[i].purple = level_color[i].red + tmp;
01348         }
01349 
01350         LOG(llevSystem, "{ %d, %d, %d, %d, %d, %d},  lvl %d \n", ii + 1, level_color[i].green + 1, level_color[i].yellow, level_color[i].orange, level_color[i].red, level_color[i].purple, i);
01351     }
01352 }