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 <ctype.h>
29 #include <math.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "sproto.h"
34 
42 int random_roll(int min, int max, const object *op, int goodbad) {
43  int omin, diff, luck, base, ran;
44 
45  omin = min;
46  diff = max-min+1;
47  base = (diff > 2) ? 20 : 50; /* d2 and d3 are corner cases */
48 
49  if (max < 1 || diff < 1) {
50  LOG(llevError, "Calling random_roll with min=%d max=%d\n", min, max);
51  return(min); /* avoids a float exception */
52  }
53 
54  ran = RANDOM();
55 
56  if (op->type != PLAYER)
57  return((ran%diff)+min);
58 
59  luck = op->stats.luck;
60  if (RANDOM()%base < (unsigned int)MIN(10, abs(luck))) {
61  /* we have a winner */
62  ((luck > 0) ? (luck = 1) : (luck = -1));
63  diff -= luck;
64  if (diff < 1)
65  return(omin); /*check again*/
66  ((goodbad) ? (min += luck) : (diff));
67 
68  return(MAX(omin, MIN(max, (ran%diff)+min)));
69  }
70  return((ran%diff)+min);
71 }
72 
77 int64_t random_roll64(int64_t min, int64_t max, const object *op, int goodbad) {
78  int64_t omin, diff, ran;
79  int8_t luck;
80  int base;
81 
82  omin = min;
83  diff = max-min+1;
84  base = (diff > 2) ? 20 : 50; /* d2 and d3 are corner cases */
85 
86  if (max < 1 || diff < 1) {
87  LOG(llevError, "Calling random_roll with min=%" FMT64 " max=%" FMT64 "\n", min, max);
88  return(min); /* avoids a float exception */
89  }
90 
91  /* Don't know of a portable call to get 64 bit random values.
92  * So make a call to get two 32 bit random numbers, and just to
93  * a little byteshifting. Do make sure the first one is only
94  * 32 bit, so we don't get skewed results
95  */
96  ran = (RANDOM()&0xffffffff)|((int64_t)RANDOM()<<32);
97 
98  if (op->type != PLAYER)
99  return((ran%diff)+min);
100 
101  luck = op->stats.luck;
102  if (RANDOM()%base < (unsigned int)MIN(10, abs(luck))) {
103  /* we have a winner */
104  ((luck > 0) ? (luck = 1) : (luck = -1));
105  diff -= luck;
106  if (diff < 1)
107  return (omin); /*check again*/
108  ((goodbad) ? (min += luck) : (diff));
109 
110  return (MAX(omin, MIN(max, (ran%diff)+min)));
111  }
112  return ((ran%diff)+min);
113 }
114 
122 int die_roll(int num, int size, const object *op, int goodbad) {
123  int min, diff, luck, total, i, gotlucky, base, ran;
124 
125  diff = size;
126  min = 1;
127  luck = total = gotlucky = 0;
128  base = (diff > 2) ? 20 : 50; /* d2 and d3 are corner cases */
129  if (size < 2 || diff < 1) {
130  LOG(llevError, "Calling die_roll with num=%d size=%d\n", num, size);
131  return(num); /* avoids a float exception */
132  }
133 
134  if (op->type == PLAYER)
135  luck = op->stats.luck;
136 
137  for (i = 0; i < num; i++) {
138  if (RANDOM()%base < (unsigned int)MIN(10, abs(luck)) && !gotlucky) {
139  /* we have a winner */
140  gotlucky++;
141  ((luck > 0) ? (luck = 1) : (luck = -1));
142  diff -= luck;
143  if (diff < 1)
144  return(num); /*check again*/
145  ((goodbad) ? (min += luck) : (diff));
146  ran = RANDOM();
147  total += MAX(1, MIN(size, (ran%diff)+min));
148  } else {
149  total += RANDOM()%size+1;
150  }
151  }
152  return(total);
153 }
154 
162 int rndm(int min, int max) {
163  int diff;
164 
165  diff = max-min+1;
166  if (max < 1 || diff < 1)
167  return (min);
168 
169  return (RANDOM()%diff+min);
170 }
171 
176  int x, y, destroy;
177 
178  if (m->unique)
179  return;
180 
181  for (x = 0; x < MAP_WIDTH(m); x++)
182  for (y = 0; y < MAP_HEIGHT(m); y++)
183  FOR_MAP_PREPARE(m, x, y, op) {
184  destroy = 0;
186  break;
187  if (QUERY_FLAG(op, FLAG_IS_FLOOR)
189  || QUERY_FLAG(op, FLAG_UNIQUE)
191  || QUERY_FLAG(op, FLAG_UNPAID)
192  || IS_LIVE(op))
193  continue;
194  if (op->head)
195  /* Don't try to remove a non head part of a multipart object, object_remove() would abort(). */
196  continue;
197  /* otherwise, we decay and destroy */
198  if (IS_WEAPON(op)) {
199  op->stats.dam--;
200  if (op->stats.dam < 0)
201  destroy = 1;
202  } else if (IS_ARMOR(op)
203  || IS_SHIELD(op)
204  || op->type == GIRDLE
205  || op->type == GLOVES
206  || op->type == CLOAK) {
207  op->stats.ac--;
208  if (op->stats.ac < 0)
209  destroy = 1;
210  } else if (op->type == FOOD) {
211  op->stats.food -= rndm(5, 20);
212  if (op->stats.food < 0)
213  destroy = 1;
214  } else {
215  if (op->material&M_PAPER
216  || op->material&M_LEATHER
217  || op->material&M_WOOD
218  || op->material&M_ORGANIC
219  || op->material&M_CLOTH
220  || op->material&M_LIQUID)
221  destroy = 1;
222  if (op->material&M_IRON && rndm(1, 5) == 1)
223  destroy = 1;
224  if (op->material&M_GLASS && rndm(1, 2) == 1)
225  destroy = 1;
226  if ((op->material&M_STONE || op->material&M_ADAMANT) && rndm(1, 10) == 1)
227  destroy = 1;
228  if ((op->material&M_SOFT_METAL || op->material&M_BONE)
229  && rndm(1, 3) == 1)
230  destroy = 1;
231  //if (settings.dynamiclevel == 0) {
232  if (op->material&M_ICE && rndm(0, 100) > 70)
233  destroy = 1;
234  //} else {
235  // if (op->material & M_ICE && MAP_TEMP(m) > 32)
236  // destroy = 1;
237  //}
238  }
239  /* adjust overall chance below */
240  if (destroy && rndm(0, 1)) {
241  object_remove(op);
243  }
244  } FOR_MAP_FINISH();
245 }
246 
254  for (auto material : materials) {
255  if (strcmp(name, material->name) == 0) {
256  return material;
257  }
258  }
259  return nullptr;
260 }
261 
268 void transmute_materialname(object *op, const object *change) {
269  materialtype_t *mt;
270  int j;
271 
272  if (op->materialname == NULL)
273  return;
274 
275  if (change->materialname != NULL
276  && strcmp(op->materialname, change->materialname))
277  return;
278 
279  if (!(IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK))
280  return;
281 
282  mt = name_to_material(op->materialname);
283  if (!mt) {
284  LOG(llevError, "archetype '%s>%s' uses nonexistent material '%s'\n", op->arch->name, op->name, op->materialname);
285  return;
286  }
287 
288  for (j = 0; j < NROFATTACKS; j++)
289  if (op->resist[j] == 0 && change->resist[j] != 0) {
290  op->resist[j] += mt->mod[j];
291  if (op->resist[j] > 100)
292  op->resist[j] = 100;
293  if (op->resist[j] < -100)
294  op->resist[j] = -100;
295  }
296 }
297 
302 void set_materialname(object *op) {
303  if (op->materialname != NULL || op->material == 0)
304  return;
305 
306  for (auto material : materials) {
307  if (op->material & material->material) {
308  op->materialname = add_string(material->name);
309  return;
310  }
311  }
312 }
313 
314 #define EOL_SIZE (sizeof("\n")-1)
315 
319 void strip_endline(char *buf) {
320  if (strlen(buf) < sizeof("\n")) {
321  return;
322  }
323  if (!strcmp(buf+strlen(buf)-EOL_SIZE, "\n"))
324  buf[strlen(buf)-EOL_SIZE] = '\0';
325 }
326 
332 void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize) {
333  size_t resultlen;
334  size_t keylen;
335 
336  /* special case to prevent infinite loop if key==replacement=="" */
337  if (strcmp(key, replacement) == 0) {
338  strlcpy(result, src, resultsize);
339  return;
340  }
341 
342  keylen = strlen(key);
343 
344  resultlen = 0;
345  while (*src != '\0' && resultlen+1 < resultsize) {
346  if (strncmp(src, key, keylen) == 0) {
347  snprintf(result+resultlen, resultsize-resultlen, "%s", replacement);
348  resultlen += strlen(result+resultlen);
349  src += keylen;
350  } else {
351  result[resultlen++] = *src++;
352  }
353  }
354  result[resultlen] = '\0';
355 }
356 
373 void make_list_like(char *input) {
374  char *p, tmp[MAX_BUF];
375  int i;
376  if (!input || strlen(input) > MAX_BUF-5)
377  return;
378  /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */
379 
380  strncpy(tmp, input, MAX_BUF-5);
381  /*trim all trailing commas, spaces etc.*/
382  for (i = strlen(tmp); i >= 0 && !isalnum(tmp[i]); i--) {
383  tmp[i] = '\0';
384  }
385  strcat(tmp, ".");
386 
387  p = strrchr(tmp, ',');
388  if (p) {
389  *p = '\0';
390  strcpy(input, tmp);
391  p++;
392  strcat(input, " and");
393  strcat(input, p);
394  } else
395  strcpy(input, tmp);
396  return;
397 }
398 
405 int get_random_dir(void) {
406  return rndm(1, 8);
407 }
408 
417 int get_randomized_dir(int dir) {
418  return absdir(dir+RANDOM()%3+RANDOM()%3-2);
419 }
420 
431 int adjust_dir(int dir, int destination_dir) {
432  int diff;
433 
434  diff = (destination_dir-dir)&7;
435  if (1 <= diff && diff <= 3)
436  dir++;
437  else if (5 <= diff && diff <= 7)
438  dir--;
439  else if (rndm(0, 1) == 0)
440  dir++;
441  else
442  dir--;
443  return absdir(dir);
444 }
445 
453  char *p;
454 
455  for (p = buf; *p != '\0'; p++) {
456  if (*p < ' ') {
457  *p = ' ';
458  }
459  }
460 }
461 
478 size_t split_string(char *str, char *array[], size_t array_size, char sep) {
479  char *p;
480  size_t pos;
481 
482  if (array_size == 0)
483  return 0;
484 
485  if (*str == '\0') {
486  array[0] = str;
487  return 1;
488  }
489 
490  pos = 0;
491  p = str;
492  while (pos < array_size) {
493  array[pos++] = p;
494  while (*p != '\0' && *p != sep)
495  p++;
496  if (pos >= array_size)
497  break;
498  if (*p != sep)
499  break;
500  *p++ = '\0';
501  }
502  return pos;
503 }
504 
512 StringBuffer *describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf) {
513  if (buf == NULL)
514  buf = stringbuffer_new();
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:347
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
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:405
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:234
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.cpp:138
M_ORGANIC
#define M_ORGANIC
General organic.
Definition: material.h:19
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
absdir
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3699
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:302
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:15
rndm
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:162
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:336
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:253
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:351
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:1545
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:431
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:478
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:512
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
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:77
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:348
object::materialname
sstring materialname
Specific material name.
Definition: object.h:356
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:95
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:42
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:452
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:222
RANDOM
#define RANDOM()
Definition: define.h:628
EOL_SIZE
#define EOL_SIZE
Definition: utils.cpp:314
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
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:332
decay_objects
void decay_objects(mapstruct *m)
Decay and destroy persihable items in a map.
Definition: utils.cpp:175
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:268
clean_tmp_files
void clean_tmp_files(void)
Save unique maps and clean up temporary map files unless recycling temporary maps.
Definition: main.cpp:351
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
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:417
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:373
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:319
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.cpp:122
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:1818
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:484
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:378
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:357
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