Crossfire Server, Trunk  R22047
init.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #define EXTERN
20 #define INIT_C
21 
22 #include "global.h"
23 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "object.h"
28 #include "output_file.h"
29 #include "assets.h"
30 
31 static void init_environ(void);
32 static void init_defaults(void);
33 static void init_dynamic(void);
34 static void init_clocks(void);
35 
36 /*
37  * Anything with non-zero defaults in include/global.h must be set here.
38  */
39 struct Settings settings = {
40  .csport = CSPORT,
41  .debug = llevInfo,
42  .confdir = CONFDIR,
43  .datadir = DATADIR,
44  .localdir = LOCALDIR,
45  .playerdir = PLAYERDIR,
46  .mapdir = MAPDIR,
47  .archetypes = ARCHETYPES,
48  .regions = REGIONS,
49  .treasures = TREASURES,
50  .uniquedir = UNIQUE_DIR,
51  .templatedir = TEMPLATE_DIR,
52  .tmpdir = TMPDIR,
53  .stat_loss_on_death = STAT_LOSS_ON_DEATH,
54  .pk_luck_penalty = PK_LUCK_PENALTY,
55  .permanent_exp_ratio = PERMANENT_EXPERIENCE_RATIO,
56  .death_penalty_ratio = DEATH_PENALTY_RATIO,
57  .death_penalty_level = DEATH_PENALTY_LEVEL,
58  .balanced_stat_loss = BALANCED_STAT_LOSS,
59  .not_permadeth = NOT_PERMADETH,
60  .simple_exp = SIMPLE_EXP,
61  .reset_loc_time = RESET_LOCATION_TIME,
62  .set_title = SET_TITLE,
63  .resurrection = RESURRECTION,
64  .search_items = SEARCH_ITEMS,
65  .spell_encumbrance = SPELL_ENCUMBRANCE,
66  .spell_failure_effects = SPELL_FAILURE_EFFECTS,
67  .casting_time = CASTING_TIME,
68  .real_wiz = REAL_WIZ,
69  .recycle_tmp_maps = RECYCLE_TMP_MAPS,
70  .always_show_hp = ALWAYS_SHOW_HP,
71  .spellpoint_level_depend = SPELLPOINT_LEVEL_DEPEND,
72  .set_friendly_fire = SET_FRIENDLY_FIRE,
73  .motd = MOTD,
74  .rules = "rules",
75  .news = "news",
76  .emergency_x = EMERGENCY_X,
77  .emergency_y = EMERGENCY_Y,
78  .item_power_factor = 1.0,
79  /* Armor enchantment stuff */
80  .armor_max_enchant = ARMOR_MAX_ENCHANT,
81  .armor_weight_reduction = ARMOR_WEIGHT_REDUCTION,
82  .armor_weight_linear = ARMOR_WEIGHT_LINEAR,
83  .armor_speed_improvement = ARMOR_SPEED_IMPROVEMENT,
84  .armor_speed_linear = ARMOR_SPEED_LINEAR,
85  .no_player_stealing = 1,
86  .create_home_portals = 0,
87  .personalized_blessings = 1,
88  .pk_max_experience = 5000000,
89  .pk_max_experience_percent = 10,
90  .starting_stat_min = 3,
91  .starting_stat_max = 18,
92  .starting_stat_points = 85,
93  .roll_stat_points = 115,
94  .max_stat = 0, /* max_stat - will be loaded from stats file */
95  .special_break_map = 1, /* special_break_map, 1 for historical reasons */
96  .hooks_count = 0,
97  .ignore_assets_errors = 0,
98  .archetypes_tracker = NULL,
99 };
100 
102 
108 const char *const spellpathnames[NRSPELLPATHS] = {
109  "Protection",
110  "Fire",
111  "Frost",
112  "Electricity",
113  "Missiles",
114  "Self",
115  "Summoning",
116  "Abjuration",
117  "Restoration",
118  "Detonation",
119  "Mind",
120  "Creation",
121  "Teleportation",
122  "Information",
123  "Transmutation",
124  "Transferrence",
125  "Turning",
126  "Wounding",
127  "Death",
128  "Light"
129 };
130 
131 
143 static void init_emergency_mappath(void) {
144  char filename[MAX_BUF], tmpbuf[MAX_BUF];
145  FILE *fp;
146  int online = 0;
147 
149 
150  /* If this file doesn't exist, not a big deal */
151  snprintf(filename, sizeof(filename), "%s/%s/.emergency", settings.datadir, settings.mapdir);
152  fp = fopen(filename, "r");
153  if (fp != NULL) {
154  while (fgets(tmpbuf, MAX_BUF-1, fp)) {
155  if (tmpbuf[0] == '#')
156  continue; /* ignore comments */
157 
158  if (online == 0) {
159  tmpbuf[strlen(tmpbuf)-1] = 0; /* kill newline */
160  free(settings.emergency_mapname);
161  settings.emergency_mapname = strdup_local(tmpbuf);
162  } else if (online == 1) {
163  settings.emergency_x = atoi(tmpbuf);
164  } else if (online == 2) {
165  settings.emergency_y = atoi(tmpbuf);
166  }
167  online++;
168  if (online > 2)
169  break;
170  }
171  fclose(fp);
172  if (online <= 2)
173  LOG(llevError, "Online read partial data from %s\n", filename);
174  LOG(llevDebug, "emergency map set to %s (%d, %d)\n",
175  settings.emergency_mapname,
176  settings.emergency_x, settings.emergency_y);
177  }
178 }
179 
180 
189 void init_library(void) {
190  init_environ();
191  init_globals();
192  init_stats(FALSE); /* Needs to be fairly early, since the loader will check
193  * against the settings.max_stat value
194  */
195 
196  for (int mess = 0; mess < MAXATTACKMESS; mess++) {
197  for (int level = 0; level < MAXATTACKMESS; level++) {
198  attack_mess[mess][level].level = -1;
199  attack_mess[mess][level].buf1 = NULL;
200  attack_mess[mess][level].buf2 = NULL;
201  attack_mess[mess][level].buf3 = NULL;
202  }
203  }
204 
205  assets_init();
206  init_hash_table();
207  i18n_init();
208  init_objects();
209  init_block();
210 
211  assets_collect(settings.datadir);
212  assets_end_load();
213 
214  check_formulae();
215 
216 
217  init_clocks();
219  init_experience();
220 
221  if (assets_dump_undefined() > 0 && !settings.ignore_assets_errors) {
222  LOG(llevError, "Assets errors, please fix and restart.\n");
223  exit(EXIT_FAILURE);
224  }
225 
226  /* init_dynamic() loads a map, so needs a region */
227  if (init_regions() != 0) {
228  LOG(llevError, "Please check that your maps are correctly installed.\n");
229  exit(EXIT_FAILURE);
230  }
231 
232  init_dynamic();
233 }
234 
240 static void init_environ(void) {
241  char *cp;
242 
243  cp = getenv("CROSSFIRE_LIBDIR");
244  if (cp)
245  settings.datadir = cp;
246  cp = getenv("CROSSFIRE_LOCALDIR");
247  if (cp)
248  settings.localdir = cp;
249  cp = getenv("CROSSFIRE_PLAYERDIR");
250  if (cp)
251  settings.playerdir = cp;
252  cp = getenv("CROSSFIRE_MAPDIR");
253  if (cp)
254  settings.mapdir = cp;
255  cp = getenv("CROSSFIRE_ARCHETYPES");
256  if (cp)
257  settings.archetypes = cp;
258  cp = getenv("CROSSFIRE_TREASURES");
259  if (cp)
260  settings.treasures = cp;
261  cp = getenv("CROSSFIRE_UNIQUEDIR");
262  if (cp)
263  settings.uniquedir = cp;
264  cp = getenv("CROSSFIRE_TEMPLATEDIR");
265  if (cp)
266  settings.templatedir = cp;
267  cp = getenv("CROSSFIRE_TMPDIR");
268  if (cp)
269  settings.tmpdir = cp;
270 }
271 
278 void init_globals(void) {
279  memset(&statistics, 0, sizeof(struct Statistics));
280 
281  /* Log to stderr by default. */
282  logfile = stderr;
283 
284  /* Try to open the log file specified on the command-line. */
285  if (settings.logfilename != NULL) {
286  logfile = fopen(settings.logfilename, "a");
287 
288  /* If writable, set buffer mode to per-line. */
289  if (logfile != NULL) {
290  setvbuf(logfile, NULL, _IOLBF, 0);
291  } else {
292  logfile = stderr;
293 
294  LOG(llevError, "Could not open '%s' for logging.\n",
295  settings.logfilename);
296  }
297  }
298 
299  exiting = 0;
300  first_player = NULL;
301  first_friendly_object = NULL;
302  first_map = NULL;
303  first_artifactlist = NULL;
304  *first_map_ext_path = 0;
305  nrofartifacts = 0;
306  nrofallowedstr = 0;
307  ring_arch = NULL;
308  amulet_arch = NULL;
309  undead_name = add_string("undead");
311  init_defaults();
312 }
313 
324 void free_globals(void) {
325  int msg, attack;
326  objectlink *friend;
327  region *reg;
328 
330  for (msg = 0; msg < NROFATTACKMESS; msg++)
331  for (attack = 0; attack < MAXATTACKMESS; attack++) {
332  free(attack_mess[msg][attack].buf1);
333  free(attack_mess[msg][attack].buf2);
334  free(attack_mess[msg][attack].buf3);
335  }
336 
337  free(settings.emergency_mapname);
338 
339  while (first_friendly_object) {
340  friend = first_friendly_object->next;
342  first_friendly_object = friend;
343  }
344 
345  free_experience();
346 
347  while (first_region) {
348  reg = first_region->next;
355  first_region = reg;
356  }
357 
358  assets_free();
359 }
360 
365 static void init_defaults(void) {
366  nroferrors = 0;
367 }
368 
369 static int found_map = 0;
370 
371 static void do_dynamic(archetype *at) {
372  if (found_map) {
373  return;
374  }
375 
376  if (at->clone.type == MAP && at->clone.subtype == MAP_TYPE_LEGACY) {
377  if (at->clone.race) {
378  safe_strncpy(first_map_ext_path, at->clone.race,
379  sizeof(first_map_ext_path));
380  }
381  if (EXIT_PATH(&at->clone)) {
382  mapstruct *first;
383 
384  strlcpy(first_map_path, EXIT_PATH(&at->clone), sizeof(first_map_path));
385  first = ready_map_name(first_map_path, 0);
386  if (!first) {
387  LOG(llevError, "Initial map %s can't be found! Please ensure maps are correctly installed.\n", first_map_path);
388  LOG(llevError, "Unable to continue without initial map.\n");
389  abort();
390  }
391  delete_map(first);
392  found_map = 1;
393  }
394  }
395 }
396 
405 static void init_dynamic(void) {
407 
408  if (found_map) {
409  return;
410  }
411 
412  LOG(llevError, "You need a archetype called 'map' and it have to contain start map\n");
413  exit(-1);
414 }
415 
417 unsigned long todtick;
418 
423 void write_todclock(void) {
424  char filename[MAX_BUF];
425  FILE *fp;
426  OutputFile of;
427 
428  snprintf(filename, sizeof(filename), "%s/clockdata", settings.localdir);
429  fp = of_open(&of, filename);
430  if (fp == NULL)
431  return;
432  fprintf(fp, "%lu", todtick);
433  of_close(&of);
434 }
435 
440 static void init_clocks(void) {
441  char filename[MAX_BUF];
442  FILE *fp;
443  static int has_been_done = 0;
444 
445  if (has_been_done)
446  return;
447  else
448  has_been_done = 1;
449 
450  snprintf(filename, sizeof(filename), "%s/clockdata", settings.localdir);
451  fp = fopen(filename, "r");
452  if (fp == NULL) {
453  LOG(llevError, "Can't open %s.\n", filename);
454  todtick = 0;
455  write_todclock();
456  return;
457  }
458  /* Read TOD and default to 0 on failure. */
459  if (fscanf(fp, "%lu", &todtick) == 1) {
460  LOG(llevDebug, "clockdata: todtick is %lu\n", todtick);
461  fclose(fp);
462  } else {
463  LOG(llevError, "Couldn't parse todtick, using default value 0\n");
464  todtick = 0;
465  fclose(fp);
466  write_todclock();
467  }
468 }
469 
476 void init_attackmess(BufferReader *reader, const char *filename) {
477  char *buf;
478  char *cp, *p;
479  int mess = -1, level;
480  int mode = 0, total = 0;
481 
482  level = 0;
483  while ((buf = bufferreader_next_line(reader)) != NULL) {
484  if (*buf == '#')
485  continue;
486  /*
487  * Skip blanks -- strspn is slightly faster than a loop w/ optimization on
488  * Also, note we go from the beginning of the line again, since cp was at the end.
489  * While here, also skip tabs for more complete whitespace handling.
490  *
491  * SilverNexus 2018-01-21
492  */
493  cp = buf + strspn(buf, " \t");
494 
495  if (strncmp(cp, "TYPE:", 5) == 0) {
496  p = strtok(buf, ":");
497  p = strtok(NULL, ":");
498  if (mode == 1) {
499  attack_mess[mess][level].level = -1;
500  free(attack_mess[mess][level].buf1);
501  free(attack_mess[mess][level].buf2);
502  free(attack_mess[mess][level].buf3);
503  attack_mess[mess][level].buf1 = NULL;
504  attack_mess[mess][level].buf2 = NULL;
505  attack_mess[mess][level].buf3 = NULL;
506  }
507  level = 0;
508  mess = atoi(p);
509  mode = 1;
510  continue;
511  }
512  if (mode == 1) {
513  p = strtok(buf, "=");
514  attack_mess[mess][level].level = atoi(buf);
515  p = strtok(NULL, "=");
516  free(attack_mess[mess][level].buf1);
517  if (p != NULL)
518  attack_mess[mess][level].buf1 = strdup_local(p);
519  else
520  attack_mess[mess][level].buf1 = strdup_local("");
521  mode = 2;
522  continue;
523  } else if (mode == 2) {
524  p = strtok(buf, "=");
525  attack_mess[mess][level].level = atoi(buf);
526  p = strtok(NULL, "=");
527  free(attack_mess[mess][level].buf2);
528  if (p != NULL)
529  attack_mess[mess][level].buf2 = strdup_local(p);
530  else
531  attack_mess[mess][level].buf2 = strdup_local("");
532  mode = 3;
533  continue;
534  } else if (mode == 3) {
535  p = strtok(buf, "=");
536  attack_mess[mess][level].level = atoi(buf);
537  p = strtok(NULL, "=");
538  free(attack_mess[mess][level].buf3);
539  if (p != NULL)
540  attack_mess[mess][level].buf3 = strdup_local(p);
541  else
542  attack_mess[mess][level].buf3 = strdup_local("");
543  mode = 1;
544  level++;
545  total++;
546  continue;
547  }
548  }
549  LOG(llevDebug, "attackmsg %s: %d messages in %d categories\n", filename, total, mess+1);
550 }
EXTERN FILE * logfile
Definition: global.h:137
#define RESURRECTION
Definition: config.h:161
#define STAT_LOSS_ON_DEATH
Definition: config.h:164
static int found_map
Definition: init.c:369
int ignore_assets_errors
Definition: global.h:335
#define SPELL_FAILURE_EFFECTS
Definition: config.h:157
#define BALANCED_STAT_LOSS
Definition: config.h:149
#define SPELLPOINT_LEVEL_DEPEND
Definition: config.h:155
int init_regions(void)
Definition: region.c:292
struct Statistics statistics
Definition: init.c:101
void init_block(void)
Definition: los.c:88
#define TEMPLATE_DIR
Definition: config.h:515
void init_attackmess(BufferReader *reader, const char *filename)
Definition: init.c:476
#define DEATH_PENALTY_RATIO
Definition: config.h:151
int level
Definition: attack.h:119
StringBuffer * buf
Definition: readable.c:1591
#define SEARCH_ITEMS
Definition: config.h:162
#define strdup_local
Definition: compat.h:25
EXTERN objectlink * first_friendly_object
Definition: global.h:119
#define PERMANENT_EXPERIENCE_RATIO
Definition: config.h:150
#define ARMOR_SPEED_IMPROVEMENT
Definition: config.h:171
char * buf1
Definition: attack.h:120
#define PK_LUCK_PENALTY
Definition: config.h:165
void init_objects(void)
Definition: object.c:93
void archetypes_for_each(arch_op op)
Definition: assets.cpp:300
uint16_t csport
Definition: global.h:240
static void do_dynamic(archetype *at)
Definition: init.c:371
#define EMERGENCY_MAPPATH
Definition: config.h:505
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.c:1797
const char * playerdir
Definition: global.h:247
#define TMPDIR
Definition: config.h:487
void init_globals(void)
Definition: init.c:278
#define ARMOR_SPEED_LINEAR
Definition: config.h:172
void assets_init()
Definition: assets.cpp:67
#define NOT_PERMADETH
Definition: config.h:163
#define ARMOR_MAX_ENCHANT
Definition: config.h:168
void init_library(void)
Definition: init.c:189
void init_experience(void)
Definition: exp.c:167
#define FALSE
Definition: compat.h:11
#define MAP_TYPE_LEGACY
Definition: map.h:57
#define SPELL_ENCUMBRANCE
Definition: config.h:156
EXTERN char first_map_ext_path[MAX_BUF]
Definition: global.h:146
#define DEATH_PENALTY_LEVEL
Definition: config.h:152
#define safe_strncpy
Definition: compat.h:23
const char * treasures
Definition: global.h:251
const char * logfilename
Definition: global.h:239
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:108
uint16_t emergency_y
Definition: global.h:300
EXTERN archetype * amulet_arch
Definition: global.h:154
char * name
Definition: map.h:279
void init_hash_table(void)
Definition: shstr.c:55
void i18n_init(void)
Definition: languages.c:154
#define ARMOR_WEIGHT_LINEAR
Definition: config.h:170
void write_todclock(void)
Definition: init.c:423
static void init_emergency_mappath(void)
Definition: init.c:143
static void init_defaults(void)
Definition: init.c:365
static void init_environ(void)
Definition: init.c:240
EXTERN const char * undead_name
Definition: global.h:155
const char * tmpdir
Definition: global.h:254
#define ALWAYS_SHOW_HP
Definition: config.h:160
#define EMERGENCY_Y
Definition: config.h:508
struct regiondef * next
Definition: map.h:278
Definition: map.h:277
#define EMERGENCY_X
Definition: config.h:507
#define snprintf
Definition: win32.h:46
#define MAXATTACKMESS
Definition: attack.h:19
#define RESET_LOCATION_TIME
Definition: config.h:632
int of_close(OutputFile *of)
Definition: output_file.c:61
#define SIMPLE_EXP
Definition: config.h:154
char * parent_name
Definition: map.h:280
#define EXIT_PATH(xyz)
Definition: define.h:454
EXTERN long nroferrors
Definition: global.h:129
uint16_t emergency_x
Definition: global.h:300
#define REGIONS
Definition: config.h:517
static void init_dynamic(void)
Definition: init.c:405
#define NROFATTACKMESS
Definition: attack.h:18
#define LOCALDIR
Definition: win32.h:103
char * bufferreader_next_line(BufferReader *br)
Definition: bufferreader.c:81
#define PLAYERDIR
Definition: config.h:552
const char * templatedir
Definition: global.h:253
void free_experience(void)
Definition: exp.c:262
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:198
const char * archetypes
Definition: global.h:249
void free_globals(void)
Definition: init.c:324
EXTERN artifactlist * first_artifactlist
Definition: global.h:118
#define MAX_BUF
Definition: define.h:35
#define NRSPELLPATHS
Definition: spells.h:40
#define ARCHETYPES
Definition: config.h:516
#define RECYCLE_TMP_MAPS
Definition: config.h:159
void check_formulae(void)
Definition: recipe.c:251
void assets_end_load()
Definition: assets.cpp:209
const char * uniquedir
Definition: global.h:252
#define CSPORT
Definition: config.h:361
EXTERN long nrofartifacts
Definition: global.h:140
const char * datadir
Definition: global.h:245
#define TREASURES
Definition: config.h:520
EXTERN long nrofallowedstr
Definition: global.h:141
EXTERN attackmess_t attack_mess[NROFATTACKMESS][MAXATTACKMESS]
Definition: attack.h:131
const char * localdir
Definition: global.h:246
#define DATADIR
Definition: win32.h:98
char * jailmap
Definition: map.h:298
void init_stats(int reload)
Definition: living.c:2592
const char * mapdir
Definition: global.h:248
EXTERN int exiting
Definition: global.h:139
struct Settings settings
Definition: init.c:39
EXTERN long trying_emergency_save
Definition: global.h:128
FILE * of_open(OutputFile *of, const char *fname)
Definition: output_file.c:30
void delete_map(mapstruct *m)
Definition: map.c:1735
EXTERN char first_map_path[MAX_BUF]
Definition: global.h:145
#define MAPDIR
Definition: config.h:514
#define UNIQUE_DIR
Definition: config.h:495
sstring add_string(const char *str)
Definition: shstr.c:124
EXTERN player * first_player
Definition: global.h:115
#define ARMOR_WEIGHT_REDUCTION
Definition: config.h:169
#define MOTD
Definition: config.h:447
#define CASTING_TIME
Definition: config.h:166
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
char * msg
Definition: map.h:294
EXTERN archetype * ring_arch
Definition: global.h:154
EXTERN region * first_region
Definition: global.h:117
static void init_clocks(void)
Definition: init.c:440
char * buf3
Definition: attack.h:122
unsigned long todtick
Definition: init.c:417
char * emergency_mapname
Definition: global.h:299
Definition: map.h:326
char * buf2
Definition: attack.h:121
#define REAL_WIZ
Definition: config.h:158
#define FREE_AND_CLEAR(xyz)
Definition: global.h:193
#define SET_TITLE
Definition: config.h:153
#define SET_FRIENDLY_FIRE
Definition: config.h:167
void assets_collect(const char *datadir)
Definition: assets.cpp:114
EXTERN mapstruct * first_map
Definition: global.h:116
char * longname
Definition: map.h:292
int level
Definition: readable.c:1589
#define CONFDIR
Definition: win32.h:100
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:370
void assets_free()
Definition: assets.cpp:74
size_t assets_dump_undefined()
Definition: assets.cpp:202