Crossfire Server, Trunk
utils.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 
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  materialtype_t *mt, *nmt;
250 
251  mt = NULL;
252  for (nmt = materialt; nmt != NULL && nmt->next != NULL; nmt = nmt->next) {
253  if (strcmp(name, nmt->name) == 0) {
254  mt = nmt;
255  break;
256  }
257  }
258  return mt;
259 }
260 
267 void transmute_materialname(object *op, const object *change) {
268  materialtype_t *mt;
269  int j;
270 
271  if (op->materialname == NULL)
272  return;
273 
274  if (change->materialname != NULL
275  && strcmp(op->materialname, change->materialname))
276  return;
277 
278  if (!(IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK))
279  return;
280 
281  mt = name_to_material(op->materialname);
282  if (!mt) {
283  LOG(llevError, "archetype '%s>%s' uses nonexistent material '%s'\n", op->arch->name, op->name, op->materialname);
284  return;
285  }
286 
287  for (j = 0; j < NROFATTACKS; j++)
288  if (op->resist[j] == 0 && change->resist[j] != 0) {
289  op->resist[j] += mt->mod[j];
290  if (op->resist[j] > 100)
291  op->resist[j] = 100;
292  if (op->resist[j] < -100)
293  op->resist[j] = -100;
294  }
295 }
296 
301 void set_materialname(object *op) {
302  materialtype_t *mt;
303 
304  if (op->materialname != NULL)
305  return;
306 
307  for (mt = materialt; mt != NULL; mt = mt->next) {
308  if (op->material&mt->material) {
309  break;
310  }
311  }
312 
313  if (mt != NULL) {
314  op->materialname = add_string(mt->name);
315  return;
316  }
317 }
318 
319 #define EOL_SIZE (sizeof("\n")-1)
320 
324 void strip_endline(char *buf) {
325  if (strlen(buf) < sizeof("\n")) {
326  return;
327  }
328  if (!strcmp(buf+strlen(buf)-EOL_SIZE, "\n"))
329  buf[strlen(buf)-EOL_SIZE] = '\0';
330 }
331 
337 void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize) {
338  size_t resultlen;
339  size_t keylen;
340 
341  /* special case to prevent infinite loop if key==replacement=="" */
342  if (strcmp(key, replacement) == 0) {
343  strlcpy(result, src, resultsize);
344  return;
345  }
346 
347  keylen = strlen(key);
348 
349  resultlen = 0;
350  while (*src != '\0' && resultlen+1 < resultsize) {
351  if (strncmp(src, key, keylen) == 0) {
352  snprintf(result+resultlen, resultsize-resultlen, "%s", replacement);
353  resultlen += strlen(result+resultlen);
354  src += keylen;
355  } else {
356  result[resultlen++] = *src++;
357  }
358  }
359  result[resultlen] = '\0';
360 }
361 
378 void make_list_like(char *input) {
379  char *p, tmp[MAX_BUF];
380  int i;
381  if (!input || strlen(input) > MAX_BUF-5)
382  return;
383  /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */
384 
385  strncpy(tmp, input, MAX_BUF-5);
386  /*trim all trailing commas, spaces etc.*/
387  for (i = strlen(tmp); i >= 0 && !isalnum(tmp[i]); i--) {
388  tmp[i] = '\0';
389  }
390  strcat(tmp, ".");
391 
392  p = strrchr(tmp, ',');
393  if (p) {
394  *p = '\0';
395  strcpy(input, tmp);
396  p++;
397  strcat(input, " and");
398  strcat(input, p);
399  } else
400  strcpy(input, tmp);
401  return;
402 }
403 
410 int get_random_dir(void) {
411  return rndm(1, 8);
412 }
413 
422 int get_randomized_dir(int dir) {
423  return absdir(dir+RANDOM()%3+RANDOM()%3-2);
424 }
425 
436 int adjust_dir(int dir, int destination_dir) {
437  int diff;
438 
439  diff = (destination_dir-dir)&7;
440  if (1 <= diff && diff <= 3)
441  dir++;
442  else if (5 <= diff && diff <= 7)
443  dir--;
444  else if (rndm(0, 1) == 0)
445  dir++;
446  else
447  dir--;
448  return absdir(dir);
449 }
450 
458  char *p;
459 
460  for (p = buf; *p != '\0'; p++) {
461  if (*p < ' ') {
462  *p = ' ';
463  }
464  }
465 }
466 
483 size_t split_string(char *str, char *array[], size_t array_size, char sep) {
484  char *p;
485  size_t pos;
486 
487  if (array_size == 0)
488  return 0;
489 
490  if (*str == '\0') {
491  array[0] = str;
492  return 1;
493  }
494 
495  pos = 0;
496  p = str;
497  while (pos < array_size) {
498  array[pos++] = p;
499  while (*p != '\0' && *p != sep)
500  p++;
501  if (pos >= array_size)
502  break;
503  if (*p != sep)
504  break;
505  *p++ = '\0';
506  }
507  return pos;
508 }
509 
518  if (buf == NULL)
519  buf = stringbuffer_new();
520 
521  if (value) {
522  int i, j = 0;
523  stringbuffer_append_printf(buf, "(%s: ", attenuation);
524  for (i = 0; i < NRSPELLPATHS; i++)
525  if (value&(1<<i)) {
526  if (j)
528  else
529  j = 1;
531  }
533  }
534 
535  return buf;
536 }
537 
546  if (buf == NULL)
547  buf = stringbuffer_new();
548 
549  if (value) {
550  int i, j = 0;
551  stringbuffer_append_printf(buf, "(%s: ", attack);
552  for (i = 0; i < NROFATTACKS; i++)
553  if (value&(1<<i)) {
554  if (j)
556  else
557  j = 1;
559  }
561  }
562 
563  return buf;
564 }
565 
569 int isqrt(int n) {
570  return (int)sqrt(n);
571 }
572 
580 void fatal(enum fatal_error err) {
581  const char *fatalmsgs[] = {
582  "Failed to allocate memory",
583  "Failed repeatedly to load maps",
584  "Hashtable for archetypes is too small",
585  "Fatal issue in archetype file",
586  "See last error",
587  };
588 
589  if (settings.fatal_hook) {
590  settings.fatal_hook(err);
591  }
592 
593  fprintf(logfile, "Fatal error: %s\n", fatalmsgs[err]);
594  emergency_save(0);
595  clean_tmp_files();
596  fprintf(logfile, "Exiting...\n");
597  exit(err);
598 }
599 
607  if (lc->next)
608  free_charlinks(lc->next);
609  free(lc);
610 }
PLAYER
@ PLAYER
Definition: object.h:107
M_LEATHER
#define M_LEATHER
Definition: material.h:17
global.h
_materialtype::mod
int8_t mod[NROFATTACKS]
Definition: material.h:37
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
object_remove
void object_remove(object *op)
Definition: object.c:1819
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
adjust_dir
int adjust_dir(int dir, int destination_dir)
Definition: utils.c:436
emergency_save
void emergency_save(int flag)
Definition: main.c:348
llevError
@ llevError
Definition: logger.h:11
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Definition: define.h:255
GLOVES
@ GLOVES
Definition: object.h:213
GIRDLE
@ GIRDLE
Definition: object.h:223
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
decay_objects
void decay_objects(mapstruct *m)
Definition: utils.c:175
M_WOOD
#define M_WOOD
Definition: material.h:18
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
set_materialname
void set_materialname(object *op)
Definition: utils.c:301
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
M_STONE
#define M_STONE
Definition: material.h:20
Ice.tmp
int tmp
Definition: Ice.py:207
materialt
EXTERN materialtype_t * materialt
Definition: material.h:42
make_list_like
void make_list_like(char *input)
Definition: utils.c:378
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
random_roll64
int64_t random_roll64(int64_t min, int64_t max, const object *op, int goodbad)
Definition: utils.c:77
Settings::fatal_hook
fatalHook fatal_hook
Definition: global.h:332
isqrt
int isqrt(int n)
Definition: utils.c:569
MAX
#define MAX(x, y)
Definition: compat.h:24
linked_char
Definition: global.h:86
settings
struct Settings settings
Definition: init.c:39
_materialtype::material
int material
Definition: material.h:35
m
static event_registration m
Definition: citylife.cpp:427
CLOAK
@ CLOAK
Definition: object.h:204
name_to_material
materialtype_t * name_to_material(const char *name)
Definition: utils.c:248
EOL_SIZE
#define EOL_SIZE
Definition: utils.c:319
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
strip_endline
void strip_endline(char *buf)
Definition: utils.c:324
rotate-tower.result
bool result
Definition: rotate-tower.py:13
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.c:422
_materialtype::next
struct _materialtype * next
Definition: material.h:38
fatal
void fatal(enum fatal_error err)
Definition: utils.c:580
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
make_face_from_files.str
str
Definition: make_face_from_files.py:24
absdir
int absdir(int d)
Definition: object.c:3685
transmute_materialname
void transmute_materialname(object *op, const object *change)
Definition: utils.c:267
_materialtype
Definition: material.h:32
linked_char::next
struct linked_char * next
Definition: global.h:88
rndm
int rndm(int min, int max)
Definition: utils.c:162
say.max
dictionary max
Definition: say.py:148
sproto.h
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
replace_unprintable_chars
void replace_unprintable_chars(char *buf)
Definition: utils.c:457
mapdef
Definition: map.h:317
logfile
EXTERN FILE * logfile
Definition: global.h:134
describe_spellpath_attenuation
StringBuffer * describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf)
Definition: utils.c:517
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:78
free_charlinks
void free_charlinks(linked_char *lc)
Definition: utils.c:606
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:220
MAX_BUF
#define MAX_BUF
Definition: define.h:35
split_string
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Definition: utils.c:483
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
StringBuffer
Definition: stringbuffer.c:25
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
attacks
const char *const attacks[NROFATTACKS]
Definition: living.c:130
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:122
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:107
clean_tmp_files
void clean_tmp_files(void)
Definition: main.c:352
M_CLOTH
#define M_CLOTH
Definition: material.h:21
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
M_ADAMANT
#define M_ADAMANT
Definition: material.h:22
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
diamondslots.y
y
Definition: diamondslots.py:16
buf
StringBuffer * buf
Definition: readable.c:1610
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.c:138
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:80
M_PAPER
#define M_PAPER
Definition: material.h:14
obj::materialname
sstring materialname
Definition: object.h:351
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:26
IS_LIVE
#define IS_LIVE(op)
Definition: define.h:173
replace
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.c:337
M_SOFT_METAL
#define M_SOFT_METAL
Definition: material.h:24
describe_attacktype
StringBuffer * describe_attacktype(const char *attack, int value, StringBuffer *buf)
Definition: utils.c:545
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
FOOD
@ FOOD
Definition: object.h:112
_materialtype::name
const char * name
Definition: material.h:33
fatal_error
fatal_error
Definition: define.h:47
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
get_random_dir
int get_random_dir(void)
Definition: utils.c:410
destination_dir
const char * destination_dir
Definition: gridarta-types-convert.c:32
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:346
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