Crossfire Server, Trunk
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;
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)
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 
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 
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
Definition: material.h:17
global.h
settings
struct Settings settings
Definition: init.cpp:139
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
emergency_save
void emergency_save(int flag)
Definition: main.cpp:347
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Definition: define.h:255
GLOVES
@ GLOVES
Definition: object.h:218
materialtype_t::mod
int8_t mod[NROFATTACKS]
Definition: material.h:37
GIRDLE
@ GIRDLE
Definition: object.h:228
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
get_random_dir
int get_random_dir(void)
Definition: utils.cpp:400
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.cpp:240
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.cpp:138
M_WOOD
#define M_WOOD
Definition: material.h:18
disinfect.a
a
Definition: disinfect.py:13
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
absdir
int absdir(int d)
Definition: object.cpp:3710
FLAG_UNIQUE
#define FLAG_UNIQUE
Definition: define.h:287
M_ORGANIC
#define M_ORGANIC
Definition: material.h:19
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
Definition: define.h:357
M_IRON
#define M_IRON
Definition: material.h:15
mail_login.total
total
Definition: mail_login.py:30
MIN
#define MIN(x, y)
Definition: compat.h:21
set_materialname
void set_materialname(object *op)
Definition: utils.cpp:297
M_STONE
#define M_STONE
Definition: material.h:20
Ice.tmp
int tmp
Definition: Ice.py:207
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
rndm
int rndm(int min, int max)
Definition: utils.cpp:162
materials
std::vector< materialtype_t * > materials
Definition: init.cpp:128
Settings::fatal_hook
fatalHook fatal_hook
Definition: global.h:337
buf
StringBuffer * buf
Definition: readable.cpp:1565
name_to_material
materialtype_t * name_to_material(const char *name)
Definition: utils.cpp:248
ihypot
int ihypot(int a, int b)
Definition: utils.cpp:570
MAX
#define MAX(x, y)
Definition: compat.h:24
object::resist
int16_t resist[NROFATTACKS]
Definition: object.h:351
linked_char
Definition: global.h:96
m
static event_registration m
Definition: citylife.cpp:425
CLOAK
@ CLOAK
Definition: object.h:209
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
FMT64
#define FMT64
Definition: compat.h:16
M_LIQUID
#define M_LIQUID
Definition: material.h:23
M_ICE
#define M_ICE
Definition: material.h:26
adjust_dir
int adjust_dir(int dir, int destination_dir)
Definition: utils.cpp:426
rotate-tower.result
bool result
Definition: rotate-tower.py:13
split_string
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Definition: utils.cpp:473
describe_spellpath_attenuation
StringBuffer * describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf)
Definition: utils.cpp:507
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
make_face_from_files.str
str
Definition: make_face_from_files.py:30
random_roll64
int64_t random_roll64(int64_t min, int64_t max, const object *op, int goodbad)
Definition: utils.cpp:77
describe_attacktype
StringBuffer * describe_attacktype(const char *attack, int value, StringBuffer *buf)
Definition: utils.cpp:538
isqrt
int isqrt(int n)
Definition: utils.cpp:562
Ice.b
b
Definition: Ice.py:48
object::materialname
sstring materialname
Definition: object.h:356
linked_char::next
struct linked_char * next
Definition: global.h:98
say.max
dictionary max
Definition: say.py:148
sproto.h
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
logfile
FILE * logfile
Definition: init.cpp:114
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.cpp:95
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.cpp:42
replace_unprintable_chars
void replace_unprintable_chars(char *buf)
Definition: utils.cpp:447
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:590
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:73
MAX_BUF
#define MAX_BUF
Definition: define.h:35
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
M_GLASS
#define M_GLASS
Definition: material.h:16
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
RANDOM
#define RANDOM()
Definition: define.h:644
EOL_SIZE
#define EOL_SIZE
Definition: utils.cpp:309
StringBuffer
Definition: stringbuffer.cpp:25
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
replace
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.cpp:327
decay_objects
void decay_objects(mapstruct *m)
Definition: utils.cpp:175
transmute_materialname
void transmute_materialname(object *op, const object *change)
Definition: utils.cpp:263
clean_tmp_files
void clean_tmp_files(void)
Definition: main.cpp:351
M_CLOTH
#define M_CLOTH
Definition: material.h:21
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
attacks
const char *const attacks[NROFATTACKS]
Definition: living.cpp:129
M_ADAMANT
#define M_ADAMANT
Definition: material.h:22
mapstruct
Definition: map.h:313
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.cpp:412
make_list_like
void make_list_like(char *input)
Definition: utils.cpp:368
diamondslots.y
y
Definition: diamondslots.py:16
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:75
strip_endline
void strip_endline(char *buf)
Definition: utils.cpp:314
M_PAPER
#define M_PAPER
Definition: material.h:14
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.cpp:122
M_BONE
#define M_BONE
Definition: material.h:25
castle_read.key
key
Definition: castle_read.py:64
make_face_from_files.int
int
Definition: make_face_from_files.py:32
IS_LIVE
#define IS_LIVE(op)
Definition: define.h:173
M_SOFT_METAL
#define M_SOFT_METAL
Definition: material.h:24
FOOD
@ FOOD
Definition: object.h:117
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
free_charlinks
void free_charlinks(linked_char *lc)
Definition: utils.cpp:616
fatal_error
fatal_error
Definition: define.h:47
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
materialtype_t
Definition: material.h:32
destination_dir
const char * destination_dir
Definition: gridarta-types-convert.cpp:32
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
give.name
name
Definition: give.py:27