Crossfire Server, Trunk  1.75.0
utils.cpp
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 
26 #include "global.h"
27 
28 #include <assert.h>
29 #include <ctype.h>
30 #include <math.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "sproto.h"
35 
43 int random_roll(int min, int max, const object *op, int goodbad) {
44  int omin, diff, luck, base, ran;
45 
46  omin = min;
47  diff = max-min+1;
48  base = (diff > 2) ? 20 : 50; /* d2 and d3 are corner cases */
49 
50  if (max < 1 || diff < 1) {
51  LOG(llevError, "Calling random_roll with min=%d max=%d\n", min, max);
52  return(min); /* avoids a float exception */
53  }
54 
55  ran = RANDOM();
56 
57  if (op->type != PLAYER)
58  return((ran%diff)+min);
59 
60  luck = op->stats.luck;
61  if (RANDOM()%base < (unsigned int)MIN(10, abs(luck))) {
62  /* we have a winner */
63  ((luck > 0) ? (luck = 1) : (luck = -1));
64  diff -= luck;
65  if (diff < 1)
66  return(omin); /*check again*/
67  ((goodbad) ? (min += luck) : (diff));
68 
69  return(MAX(omin, MIN(max, (ran%diff)+min)));
70  }
71  return((ran%diff)+min);
72 }
73 
78 int64_t random_roll64(int64_t min, int64_t max, const object *op, int goodbad) {
79  int64_t omin, diff, ran;
80  int8_t luck;
81  int base;
82 
83  omin = min;
84  diff = max-min+1;
85  base = (diff > 2) ? 20 : 50; /* d2 and d3 are corner cases */
86 
87  if (max < 1 || diff < 1) {
88  LOG(llevError, "Calling random_roll with min=%" FMT64 " max=%" FMT64 "\n", min, max);
89  return(min); /* avoids a float exception */
90  }
91 
92  /* Don't know of a portable call to get 64 bit random values.
93  * So make a call to get two 32 bit random numbers, and just to
94  * a little byteshifting. Do make sure the first one is only
95  * 32 bit, so we don't get skewed results
96  */
97  ran = (RANDOM()&0xffffffff)|((int64_t)RANDOM()<<32);
98 
99  if (op->type != PLAYER)
100  return((ran%diff)+min);
101 
102  luck = op->stats.luck;
103  if (RANDOM()%base < (unsigned int)MIN(10, abs(luck))) {
104  /* we have a winner */
105  ((luck > 0) ? (luck = 1) : (luck = -1));
106  diff -= luck;
107  if (diff < 1)
108  return (omin); /*check again*/
109  ((goodbad) ? (min += luck) : (diff));
110 
111  return (MAX(omin, MIN(max, (ran%diff)+min)));
112  }
113  return ((ran%diff)+min);
114 }
115 
123 int die_roll(int num, int size, const object *op, int goodbad) {
124  int min, diff, luck, total, i, gotlucky, base, ran;
125 
126  diff = size;
127  min = 1;
128  luck = total = gotlucky = 0;
129  base = (diff > 2) ? 20 : 50; /* d2 and d3 are corner cases */
130  if (size < 2 || diff < 1) {
131  LOG(llevError, "Calling die_roll with num=%d size=%d\n", num, size);
132  return(num); /* avoids a float exception */
133  }
134 
135  if (op->type == PLAYER)
136  luck = op->stats.luck;
137 
138  for (i = 0; i < num; i++) {
139  if (RANDOM()%base < (unsigned int)MIN(10, abs(luck)) && !gotlucky) {
140  /* we have a winner */
141  gotlucky++;
142  ((luck > 0) ? (luck = 1) : (luck = -1));
143  diff -= luck;
144  if (diff < 1)
145  return(num); /*check again*/
146  ((goodbad) ? (min += luck) : (diff));
147  ran = RANDOM();
148  total += MAX(1, MIN(size, (ran%diff)+min));
149  } else {
150  total += RANDOM()%size+1;
151  }
152  }
153  return(total);
154 }
155 
163 int rndm(int min, int max) {
164  int diff;
165 
166  diff = max-min+1;
167  if (max < 1 || diff < 1)
168  return (min);
169 
170  return (RANDOM()%diff+min);
171 }
172 
177  int x, y, destroy;
178 
179  if (m->unique)
180  return;
181 
182  for (x = 0; x < MAP_WIDTH(m); x++)
183  for (y = 0; y < MAP_HEIGHT(m); y++)
184  FOR_MAP_PREPARE(m, x, y, op) {
185  destroy = 0;
187  break;
188  if (QUERY_FLAG(op, FLAG_IS_FLOOR)
190  || QUERY_FLAG(op, FLAG_UNIQUE)
192  || QUERY_FLAG(op, FLAG_UNPAID)
193  || IS_LIVE(op))
194  continue;
195  if (op->head)
196  /* Don't try to remove a non head part of a multipart object, object_remove() would abort(). */
197  continue;
198  /* otherwise, we decay and destroy */
199  if (IS_WEAPON(op)) {
200  op->stats.dam--;
201  if (op->stats.dam < 0)
202  destroy = 1;
203  } else if (IS_ARMOR(op)
204  || IS_SHIELD(op)
205  || op->type == GIRDLE
206  || op->type == GLOVES
207  || op->type == CLOAK) {
208  op->stats.ac--;
209  if (op->stats.ac < 0)
210  destroy = 1;
211  } else if (op->type == FOOD) {
212  op->stats.food -= rndm(5, 20);
213  if (op->stats.food < 0)
214  destroy = 1;
215  } else {
216  if (op->material&M_PAPER
217  || op->material&M_LEATHER
218  || op->material&M_WOOD
219  || op->material&M_ORGANIC
220  || op->material&M_CLOTH
221  || op->material&M_LIQUID)
222  destroy = 1;
223  if (op->material&M_IRON && rndm(1, 5) == 1)
224  destroy = 1;
225  if (op->material&M_GLASS && rndm(1, 2) == 1)
226  destroy = 1;
227  if ((op->material&M_STONE || op->material&M_ADAMANT) && rndm(1, 10) == 1)
228  destroy = 1;
229  if ((op->material&M_SOFT_METAL || op->material&M_BONE)
230  && rndm(1, 3) == 1)
231  destroy = 1;
232  //if (settings.dynamiclevel == 0) {
233  if (op->material&M_ICE && rndm(0, 100) > 70)
234  destroy = 1;
235  //} else {
236  // if (op->material & M_ICE && MAP_TEMP(m) > 32)
237  // destroy = 1;
238  //}
239  }
240  /* adjust overall chance below */
241  if (destroy && rndm(0, 1)) {
242  object_remove(op);
244  }
245  } FOR_MAP_FINISH();
246 }
247 
255  for (auto material : materials) {
256  if (strcmp(name, material->name) == 0) {
257  return material;
258  }
259  }
260  return nullptr;
261 }
262 
269 void transmute_materialname(object *op, const object *change) {
270  materialtype_t *mt;
271  int j;
272 
273  if (op->materialname == NULL)
274  return;
275 
276  if (change->materialname != NULL
277  && strcmp(op->materialname, change->materialname))
278  return;
279 
280  if (!(IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK))
281  return;
282 
283  mt = name_to_material(op->materialname);
284  if (!mt) {
285  LOG(llevError, "archetype '%s>%s' uses nonexistent material '%s'\n", op->arch->name, op->name, op->materialname);
286  return;
287  }
288 
289  for (j = 0; j < NROFATTACKS; j++)
290  if (op->resist[j] == 0 && change->resist[j] != 0) {
291  op->resist[j] += mt->mod[j];
292  if (op->resist[j] > 100)
293  op->resist[j] = 100;
294  if (op->resist[j] < -100)
295  op->resist[j] = -100;
296  }
297 }
298 
303 void set_materialname(object *op) {
304  if (op->materialname != NULL || op->material == 0)
305  return;
306 
307  for (auto material : materials) {
308  if (op->material & material->material) {
309  op->materialname = add_string(material->name);
310  return;
311  }
312  }
313 }
314 
315 #define EOL_SIZE (sizeof("\n")-1)
316 
320 void strip_endline(char *buf) {
321  if (strlen(buf) < sizeof("\n")) {
322  return;
323  }
324  if (!strcmp(buf+strlen(buf)-EOL_SIZE, "\n"))
325  buf[strlen(buf)-EOL_SIZE] = '\0';
326 }
327 
333 void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize) {
334  size_t resultlen;
335  size_t keylen;
336 
337  /* special case to prevent infinite loop if key==replacement=="" */
338  if (strcmp(key, replacement) == 0) {
339  strlcpy(result, src, resultsize);
340  return;
341  }
342 
343  keylen = strlen(key);
344 
345  resultlen = 0;
346  while (*src != '\0' && resultlen+1 < resultsize) {
347  if (strncmp(src, key, keylen) == 0) {
348  snprintf(result+resultlen, resultsize-resultlen, "%s", replacement);
349  resultlen += strlen(result+resultlen);
350  src += keylen;
351  } else {
352  result[resultlen++] = *src++;
353  }
354  }
355  result[resultlen] = '\0';
356 }
357 
374 void make_list_like(char *input) {
375  char *p, tmp[MAX_BUF];
376  int i;
377  if (!input || strlen(input) > MAX_BUF-5)
378  return;
379  /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */
380 
381  strncpy(tmp, input, MAX_BUF-5);
382  /*trim all trailing commas, spaces etc.*/
383  for (i = strlen(tmp); i >= 0 && !isalnum(tmp[i]); i--) {
384  tmp[i] = '\0';
385  }
386  strcat(tmp, ".");
387 
388  p = strrchr(tmp, ',');
389  if (p) {
390  *p = '\0';
391  strcpy(input, tmp);
392  p++;
393  strcat(input, " and");
394  strcat(input, p);
395  } else
396  strcpy(input, tmp);
397  return;
398 }
399 
406 int get_random_dir(void) {
407  return rndm(1, 8);
408 }
409 
418 int get_randomized_dir(int dir) {
419  return absdir(dir+RANDOM()%3+RANDOM()%3-2);
420 }
421 
432 int adjust_dir(int dir, int destination_dir) {
433  int diff;
434 
435  diff = (destination_dir-dir)&7;
436  if (1 <= diff && diff <= 3)
437  dir++;
438  else if (5 <= diff && diff <= 7)
439  dir--;
440  else if (rndm(0, 1) == 0)
441  dir++;
442  else
443  dir--;
444  return absdir(dir);
445 }
446 
454  char *p;
455 
456  for (p = buf; *p != '\0'; p++) {
457  if (*p < ' ') {
458  *p = ' ';
459  }
460  }
461 }
462 
479 size_t split_string(char *str, char *array[], size_t array_size, char sep) {
480  char *p;
481  size_t pos;
482 
483  if (array_size == 0)
484  return 0;
485 
486  if (*str == '\0') {
487  array[0] = str;
488  return 1;
489  }
490 
491  pos = 0;
492  p = str;
493  while (pos < array_size) {
494  array[pos++] = p;
495  while (*p != '\0' && *p != sep)
496  p++;
497  if (pos >= array_size)
498  break;
499  if (*p != sep)
500  break;
501  *p++ = '\0';
502  }
503  return pos;
504 }
505 
513 StringBuffer *describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf) {
514  assert(buf != NULL);
515 
516  if (value) {
517  int i, j = 0;
519  if (attenuation) {
520  stringbuffer_append_printf(buf, "%s: ", attenuation);
521  }
522  for (i = 0; i < NRSPELLPATHS; i++)
523  if (value&(1<<i)) {
524  if (j)
526  else
527  j = 1;
529  }
531  }
532 
533  return buf;
534 }
535 
543 StringBuffer *describe_attacktype(const char *attack, int value, StringBuffer *buf) {
544  if (buf == NULL)
545  buf = stringbuffer_new();
546 
547  if (value) {
548  int i, j = 0;
549  stringbuffer_append_printf(buf, "(%s: ", attack);
550  for (i = 0; i < NROFATTACKS; i++)
551  if (value&(1<<i)) {
552  if (j)
554  else
555  j = 1;
557  }
559  }
560 
561  return buf;
562 }
563 
567 int isqrt(int n) {
568  return (int)sqrt(n);
569 }
570 
575 int ihypot(int a, int b) {
576  a = abs(a);
577  b = abs(b);
578  if (a > b) {
579  // Swap
580  int tmp = b;
581  b = a;
582  a = tmp;
583  }
584  //assert(a <= b);
585  return ((sqrt(2) - 1) * a) + b;
586 }
587 
595 void fatal(enum fatal_error err) {
596  const char *fatalmsgs[] = {
597  "Failed to allocate memory",
598  "Failed repeatedly to load maps",
599  "Hashtable for archetypes is too small",
600  "Fatal issue in archetype file",
601  "See last error",
602  };
603 
604  if (settings.fatal_hook) {
605  settings.fatal_hook(err);
606  }
607 
608  fprintf(logfile, "Fatal error: %s\n", fatalmsgs[err]);
609  emergency_save(0);
610  clean_tmp_files();
611  fprintf(logfile, "Exiting...\n");
612  exit(err);
613 }
614 
622  if (lc->next)
623  free_charlinks(lc->next);
624  free(lc);
625 }
M_STONE
#define M_STONE
Stone.
Definition: material.h:20
PLAYER
@ PLAYER
Definition: object.h:112
global.h
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:714
emergency_save
void emergency_save(int flag)
Save all players.
Definition: main.cpp:355
llevError
@ llevError
Problems requiring server admin to fix.
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:82
GLOVES
@ GLOVES
Definition: object.h:218
materialtype_t::mod
int8_t mod[NROFATTACKS]
Modification to resistances.
Definition: material.h:37
M_PAPER
#define M_PAPER
Paper.
Definition: material.h:14
GIRDLE
@ GIRDLE
Definition: object.h:228
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
get_random_dir
int get_random_dir(void)
Returns a random direction (1..8).
Definition: utils.cpp:406
M_LEATHER
#define M_LEATHER
Leather.
Definition: material.h:17
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Perhaps not the best place for this, but needs to be in some file in the common area so that standalo...
Definition: init.cpp:233
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.cpp:79
M_ORGANIC
#define M_ORGANIC
General organic.
Definition: material.h:19
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:426
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:24
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
absdir
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3713
M_SOFT_METAL
#define M_SOFT_METAL
Soft metal.
Definition: material.h:24
MIN
#define MIN(x, y)
Definition: compat.h:21
set_materialname
void set_materialname(object *op)
Set the material name and type for an item, if not set.
Definition: utils.cpp:303
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:15
rndm
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:163
materials
std::vector< materialtype_t * > materials
Definition: init.cpp:128
Settings::fatal_hook
fatalHook fatal_hook
If not NULL then called when fatal() is called.
Definition: global.h:335
buf
StringBuffer * buf
Definition: readable.cpp:1564
name_to_material
materialtype_t * name_to_material(const char *name)
Convert materialname to materialtype_t.
Definition: utils.cpp:254
ihypot
int ihypot(int a, int b)
Rough estimate of hypot(a, b).
Definition: utils.cpp:575
MAX
#define MAX(x, y)
Definition: compat.h:24
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:353
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
linked_char
Definition: global.h:102
m
static event_registration m
Definition: citylife.cpp:424
CLOAK
@ CLOAK
Definition: object.h:209
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1558
FMT64
#define FMT64
Definition: compat.h:16
adjust_dir
int adjust_dir(int dir, int destination_dir)
Adjusts a given direction by +/-1 towards a destination direction.
Definition: utils.cpp:432
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:223
split_string
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Splits a string delimited by passed in sep value into characters into an array of strings.
Definition: utils.cpp:479
IS_LIVE
#define IS_LIVE(op)
Definition: define.h:173
describe_spellpath_attenuation
StringBuffer * describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf)
Describe the specified path attenuation.
Definition: utils.cpp:513
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
StringBuffer
std::string StringBuffer
The string buffer state.
Definition: stringbuffer.h:33
M_BONE
#define M_BONE
Bone.
Definition: material.h:25
random_roll64
int64_t random_roll64(int64_t min, int64_t max, const object *op, int goodbad)
This is a 64 bit version of random_roll() above.
Definition: utils.cpp:78
describe_attacktype
StringBuffer * describe_attacktype(const char *attack, int value, StringBuffer *buf)
Describe the specified attack type.
Definition: utils.cpp:543
isqrt
int isqrt(int n)
Compute the square root.
Definition: utils.cpp:567
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:350
object::materialname
sstring materialname
Specific material name.
Definition: object.h:358
M_GLASS
#define M_GLASS
Glass.
Definition: material.h:16
linked_char::next
struct linked_char * next
Definition: global.h:104
sproto.h
logfile
FILE * logfile
Used by server/daemon.c.
Definition: init.cpp:114
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:44
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:289
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:43
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Object is an overlay floor.
Definition: define.h:242
replace_unprintable_chars
void replace_unprintable_chars(char *buf)
Replaces any unprintable character in the given buffer with a space.
Definition: utils.cpp:453
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:595
MAP_WIDTH
#define MAP_WIDTH(m)
Map width.
Definition: map.h:76
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:225
RANDOM
#define RANDOM()
Definition: define.h:628
EOL_SIZE
#define EOL_SIZE
Definition: utils.cpp:315
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:707
replace
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Replace in string src all occurrences of key by replacement.
Definition: utils.cpp:333
decay_objects
void decay_objects(mapstruct *m)
Decay and destroy persihable items in a map.
Definition: utils.cpp:176
transmute_materialname
void transmute_materialname(object *op, const object *change)
When doing transmutation of objects, we have to recheck the resistances, as some that did not apply p...
Definition: utils.cpp:269
clean_tmp_files
void clean_tmp_files(void)
Save unique maps and clean up temporary map files unless recycling temporary maps.
Definition: main.cpp:359
object::name
sstring name
The name of the object, obviously...
Definition: object.h:321
M_LIQUID
#define M_LIQUID
Liquid.
Definition: material.h:23
M_ADAMANT
#define M_ADAMANT
Adamant.
Definition: material.h:22
M_CLOTH
#define M_CLOTH
Cloth.
Definition: material.h:21
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
attacks
const char *const attacks[NROFATTACKS]
Attack type names.
Definition: living.cpp:129
mapstruct
This is a game-map.
Definition: map.h:320
get_randomized_dir
int get_randomized_dir(int dir)
Returns a random direction (1..8) similar to a given direction.
Definition: utils.cpp:418
make_list_like
void make_list_like(char *input)
Taking a string as an argument, mutate it into a string that looks like a list.
Definition: utils.cpp:374
M_WOOD
#define M_WOOD
Wood.
Definition: material.h:18
MAP_HEIGHT
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:78
strip_endline
void strip_endline(char *buf)
Removes endline from buffer (modified in place).
Definition: utils.cpp:320
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.cpp:123
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
NEVER SET THIS.
Definition: define.h:344
FOOD
@ FOOD
Definition: object.h:117
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1832
free_charlinks
void free_charlinks(linked_char *lc)
Frees a link structure and its next items.
Definition: utils.cpp:621
a
Magical Runes Runes are magical inscriptions on the dungeon which cast a spell or detonate when something steps on them Flying objects don t detonate runes Beware ! Runes are invisible most of the time They are only visible occasionally ! There are several runes which are there are some special runes which may only be called with the invoke and people may apply it to read it Maybe useful for mazes ! This rune will not nor is it ordinarily invisible Partial Visibility of they ll be visible only part of the time They have a(your level/2) chance of being visible in any given round
M_IRON
#define M_IRON
Iron.
Definition: material.h:15
fatal_error
fatal_error
Fatal variables; used as arguments to fatal().
Definition: define.h:47
M_ICE
#define M_ICE
Ice.
Definition: material.h:26
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:486
materialtype_t
One material type.
Definition: material.h:32
destination_dir
const char * destination_dir
Root destination dir.
Definition: gridarta-types-convert.cpp:32
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:380
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:274
object::material
uint16_t material
What materials this object consist of.
Definition: object.h:359
living::luck
int8_t luck
Affects thaco and ac from time to time.
Definition: living.h:39
NRSPELLPATHS
#define NRSPELLPATHS
Number of spell paths.
Definition: spells.h:40