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 (op->material&M_ICE && rndm(0, 100) > 70)
232  destroy = 1;
233  }
234  /* adjust overall chance below */
235  if (destroy && rndm(0, 1)) {
236  object_remove(op);
238  }
239  } FOR_MAP_FINISH();
240 }
241 
249  for (auto material : materials) {
250  if (strcmp(name, material->name) == 0) {
251  return material;
252  }
253  }
254  return nullptr;
255 }
256 
263 void transmute_materialname(object *op, const object *change) {
264  materialtype_t *mt;
265  int j;
266 
267  if (op->materialname == NULL)
268  return;
269 
270  if (change->materialname != NULL
271  && strcmp(op->materialname, change->materialname))
272  return;
273 
274  if (!(IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK))
275  return;
276 
277  mt = name_to_material(op->materialname);
278  if (!mt) {
279  LOG(llevError, "archetype '%s>%s' uses nonexistent material '%s'\n", op->arch->name, op->name, op->materialname);
280  return;
281  }
282 
283  for (j = 0; j < NROFATTACKS; j++)
284  if (op->resist[j] == 0 && change->resist[j] != 0) {
285  op->resist[j] += mt->mod[j];
286  if (op->resist[j] > 100)
287  op->resist[j] = 100;
288  if (op->resist[j] < -100)
289  op->resist[j] = -100;
290  }
291 }
292 
297 void set_materialname(object *op) {
298  if (op->materialname != NULL || op->material == 0)
299  return;
300 
301  for (auto material : materials) {
302  if (op->material & material->material) {
303  op->materialname = add_string(material->name);
304  return;
305  }
306  }
307 }
308 
309 #define EOL_SIZE (sizeof("\n")-1)
310 
314 void strip_endline(char *buf) {
315  if (strlen(buf) < sizeof("\n")) {
316  return;
317  }
318  if (!strcmp(buf+strlen(buf)-EOL_SIZE, "\n"))
319  buf[strlen(buf)-EOL_SIZE] = '\0';
320 }
321 
327 void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize) {
328  size_t resultlen;
329  size_t keylen;
330 
331  /* special case to prevent infinite loop if key==replacement=="" */
332  if (strcmp(key, replacement) == 0) {
333  strlcpy(result, src, resultsize);
334  return;
335  }
336 
337  keylen = strlen(key);
338 
339  resultlen = 0;
340  while (*src != '\0' && resultlen+1 < resultsize) {
341  if (strncmp(src, key, keylen) == 0) {
342  snprintf(result+resultlen, resultsize-resultlen, "%s", replacement);
343  resultlen += strlen(result+resultlen);
344  src += keylen;
345  } else {
346  result[resultlen++] = *src++;
347  }
348  }
349  result[resultlen] = '\0';
350 }
351 
368 void make_list_like(char *input) {
369  char *p, tmp[MAX_BUF];
370  int i;
371  if (!input || strlen(input) > MAX_BUF-5)
372  return;
373  /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */
374 
375  strncpy(tmp, input, MAX_BUF-5);
376  /*trim all trailing commas, spaces etc.*/
377  for (i = strlen(tmp); i >= 0 && !isalnum(tmp[i]); i--) {
378  tmp[i] = '\0';
379  }
380  strcat(tmp, ".");
381 
382  p = strrchr(tmp, ',');
383  if (p) {
384  *p = '\0';
385  strcpy(input, tmp);
386  p++;
387  strcat(input, " and");
388  strcat(input, p);
389  } else
390  strcpy(input, tmp);
391  return;
392 }
393 
400 int get_random_dir(void) {
401  return rndm(1, 8);
402 }
403 
412 int get_randomized_dir(int dir) {
413  return absdir(dir+RANDOM()%3+RANDOM()%3-2);
414 }
415 
426 int adjust_dir(int dir, int destination_dir) {
427  int diff;
428 
429  diff = (destination_dir-dir)&7;
430  if (1 <= diff && diff <= 3)
431  dir++;
432  else if (5 <= diff && diff <= 7)
433  dir--;
434  else if (rndm(0, 1) == 0)
435  dir++;
436  else
437  dir--;
438  return absdir(dir);
439 }
440 
448  char *p;
449 
450  for (p = buf; *p != '\0'; p++) {
451  if (*p < ' ') {
452  *p = ' ';
453  }
454  }
455 }
456 
473 size_t split_string(char *str, char *array[], size_t array_size, char sep) {
474  char *p;
475  size_t pos;
476 
477  if (array_size == 0)
478  return 0;
479 
480  if (*str == '\0') {
481  array[0] = str;
482  return 1;
483  }
484 
485  pos = 0;
486  p = str;
487  while (pos < array_size) {
488  array[pos++] = p;
489  while (*p != '\0' && *p != sep)
490  p++;
491  if (pos >= array_size)
492  break;
493  if (*p != sep)
494  break;
495  *p++ = '\0';
496  }
497  return pos;
498 }
499 
507 StringBuffer *describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf) {
508  if (buf == NULL)
509  buf = stringbuffer_new();
510 
511  if (value) {
512  int i, j = 0;
514  if (attenuation) {
515  stringbuffer_append_printf(buf, "%s: ", attenuation);
516  }
517  for (i = 0; i < NRSPELLPATHS; i++)
518  if (value&(1<<i)) {
519  if (j)
521  else
522  j = 1;
524  }
526  }
527 
528  return buf;
529 }
530 
538 StringBuffer *describe_attacktype(const char *attack, int value, StringBuffer *buf) {
539  if (buf == NULL)
540  buf = stringbuffer_new();
541 
542  if (value) {
543  int i, j = 0;
544  stringbuffer_append_printf(buf, "(%s: ", attack);
545  for (i = 0; i < NROFATTACKS; i++)
546  if (value&(1<<i)) {
547  if (j)
549  else
550  j = 1;
552  }
554  }
555 
556  return buf;
557 }
558 
562 int isqrt(int n) {
563  return (int)sqrt(n);
564 }
565 
570 int ihypot(int a, int b) {
571  a = abs(a);
572  b = abs(b);
573  if (a > b) {
574  // Swap
575  int tmp = b;
576  b = a;
577  a = tmp;
578  }
579  //assert(a <= b);
580  return ((sqrt(2) - 1) * a) + b;
581 }
582 
590 void fatal(enum fatal_error err) {
591  const char *fatalmsgs[] = {
592  "Failed to allocate memory",
593  "Failed repeatedly to load maps",
594  "Hashtable for archetypes is too small",
595  "Fatal issue in archetype file",
596  "See last error",
597  };
598 
599  if (settings.fatal_hook) {
600  settings.fatal_hook(err);
601  }
602 
603  fprintf(logfile, "Fatal error: %s\n", fatalmsgs[err]);
604  emergency_save(0);
605  clean_tmp_files();
606  fprintf(logfile, "Exiting...\n");
607  exit(err);
608 }
609 
617  if (lc->next)
618  free_charlinks(lc->next);
619  free(lc);
620 }
PLAYER
@ PLAYER
Definition: object.h:112
M_LEATHER
#define M_LEATHER
Leather.
Definition: material.h:17
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:724
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
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Object is an overlay floor.
Definition: define.h:255
GLOVES
@ GLOVES
Definition: object.h:218
materialtype_t::mod
int8_t mod[NROFATTACKS]
Modification to resistances.
Definition: material.h:37
GIRDLE
@ GIRDLE
Definition: object.h:228
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
get_random_dir
int get_random_dir(void)
Returns a random direction (1..8).
Definition: utils.cpp:400
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:236
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_WOOD
#define M_WOOD
Wood.
Definition: material.h:18
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
absdir
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3699
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:287
M_ORGANIC
#define M_ORGANIC
General organic.
Definition: material.h:19
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
NEVER SET THIS.
Definition: define.h:357
M_IRON
#define M_IRON
Iron.
Definition: material.h:15
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:297
M_STONE
#define M_STONE
Stone.
Definition: material.h:20
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
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:334
buf
StringBuffer * buf
Definition: readable.cpp:1565
name_to_material
materialtype_t * name_to_material(const char *name)
Convert materialname to materialtype_t.
Definition: utils.cpp:248
ihypot
int ihypot(int a, int b)
Rough estimate of hypot(a, b).
Definition: utils.cpp:570
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:98
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:302
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
M_LIQUID
#define M_LIQUID
Liquid.
Definition: material.h:23
M_ICE
#define M_ICE
Ice.
Definition: material.h:26
adjust_dir
int adjust_dir(int dir, int destination_dir)
Adjusts a given direction by +/-1 towards a destination direction.
Definition: utils.cpp:426
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:473
describe_spellpath_attenuation
StringBuffer * describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf)
Describe the specified path attenuation.
Definition: utils.cpp:507
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
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:538
isqrt
int isqrt(int n)
Compute the square root.
Definition: utils.cpp:562
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
object::materialname
sstring materialname
Specific material name.
Definition: object.h:356
linked_char::next
struct linked_char * next
Definition: global.h:100
sproto.h
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
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
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
replace_unprintable_chars
void replace_unprintable_chars(char *buf)
Replaces any unprintable character in the given buffer with a space.
Definition: utils.cpp:447
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
MAP_WIDTH
#define MAP_WIDTH(m)
Map width.
Definition: map.h:73
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
M_GLASS
#define M_GLASS
Glass.
Definition: material.h:16
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
RANDOM
#define RANDOM()
Definition: define.h:638
EOL_SIZE
#define EOL_SIZE
Definition: utils.cpp:309
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:717
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:327
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:263
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_CLOTH
#define M_CLOTH
Cloth.
Definition: material.h:21
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
attacks
const char *const attacks[NROFATTACKS]
Attack type names.
Definition: living.cpp:129
M_ADAMANT
#define M_ADAMANT
Adamant.
Definition: material.h:22
mapstruct
This is a game-map.
Definition: map.h:315
get_randomized_dir
int get_randomized_dir(int dir)
Returns a random direction (1..8) similar to a given direction.
Definition: utils.cpp:412
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:368
MAP_HEIGHT
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:75
strip_endline
void strip_endline(char *buf)
Removes endline from buffer (modified in place).
Definition: utils.cpp:314
M_PAPER
#define M_PAPER
Paper.
Definition: material.h:14
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
M_BONE
#define M_BONE
Bone.
Definition: material.h:25
IS_LIVE
#define IS_LIVE(op)
Definition: define.h:173
M_SOFT_METAL
#define M_SOFT_METAL
Soft metal.
Definition: material.h:24
FOOD
@ FOOD
Definition: object.h:117
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:616
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
fatal_error
fatal_error
Fatal variables; used as arguments to fatal().
Definition: define.h:47
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
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
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