Crossfire Server, Trunk  R21041
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  ((diff > 2) ? (base = 20) : (base = 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  ((diff > 2) ? (base = 20) : (base = 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  ((diff > 2) ? (base = 20) : (base = 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 
248 materialtype_t *name_to_material(const char *name) {
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 
325 const char *strrstr(const char *haystack, const char *needle) {
326  const char *lastneedle;
327 
328  lastneedle = NULL;
329  while ((haystack = strstr(haystack, needle)) != NULL) {
330  lastneedle = haystack;
331  haystack++;
332  }
333  return lastneedle;
334 }
335 
336 #define EOL_SIZE (sizeof("\n")-1)
337 
341 void strip_endline(char *buf) {
342  if (strlen(buf) < sizeof("\n")) {
343  return;
344  }
345  if (!strcmp(buf+strlen(buf)-EOL_SIZE, "\n"))
346  buf[strlen(buf)-EOL_SIZE] = '\0';
347 }
348 
354 void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize) {
355  size_t resultlen;
356  size_t keylen;
357 
358  /* special case to prevent infinite loop if key==replacement=="" */
359  if (strcmp(key, replacement) == 0) {
360  snprintf(result, resultsize, "%s", src);
361  return;
362  }
363 
364  keylen = strlen(key);
365 
366  resultlen = 0;
367  while (*src != '\0' && resultlen+1 < resultsize) {
368  if (strncmp(src, key, keylen) == 0) {
369  snprintf(result+resultlen, resultsize-resultlen, "%s", replacement);
370  resultlen += strlen(result+resultlen);
371  src += keylen;
372  } else {
373  result[resultlen++] = *src++;
374  }
375  }
376  result[resultlen] = '\0';
377 }
378 
395 void make_list_like(char *input) {
396  char *p, tmp[MAX_BUF];
397  int i;
398  if (!input || strlen(input) > MAX_BUF-5)
399  return;
400  /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */
401 
402  strncpy(tmp, input, MAX_BUF-5);
403  /*trim all trailing commas, spaces etc.*/
404  for (i = strlen(tmp); i >= 0 && !isalnum(tmp[i]); i--) {
405  tmp[i] = '\0';
406  }
407  strcat(tmp, ".");
408 
409  p = strrchr(tmp, ',');
410  if (p) {
411  *p = '\0';
412  strcpy(input, tmp);
413  p++;
414  strcat(input, " and");
415  strcat(input, p);
416  } else
417  strcpy(input, tmp);
418  return;
419 }
420 
427 int get_random_dir(void) {
428  return rndm(1, 8);
429 }
430 
439 int get_randomized_dir(int dir) {
440  return absdir(dir+RANDOM()%3+RANDOM()%3-2);
441 }
442 
453 int adjust_dir(int dir, int destination_dir) {
454  int diff;
455 
456  diff = (destination_dir-dir)&7;
457  if (1 <= diff && diff <= 3)
458  dir++;
459  else if (5 <= diff && diff <= 7)
460  dir--;
461  else if (rndm(0, 1) == 0)
462  dir++;
463  else
464  dir--;
465  return absdir(dir);
466 }
467 
474 void replace_unprintable_chars(char *buf) {
475  char *p;
476 
477  for (p = buf; *p != '\0'; p++) {
478  if (*p < ' ') {
479  *p = ' ';
480  }
481  }
482 }
483 
500 size_t split_string(char *str, char *array[], size_t array_size, char sep) {
501  char *p;
502  size_t pos;
503 
504  if (array_size <= 0)
505  return 0;
506 
507  if (*str == '\0') {
508  array[0] = str;
509  return 1;
510  }
511 
512  pos = 0;
513  p = str;
514  while (pos < array_size) {
515  array[pos++] = p;
516  while (*p != '\0' && *p != sep)
517  p++;
518  if (pos >= array_size)
519  break;
520  if (*p != sep)
521  break;
522  *p++ = '\0';
523  }
524  return pos;
525 }
526 
534 StringBuffer *describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf) {
535  if (buf == NULL)
536  buf = stringbuffer_new();
537 
538  if (value) {
539  int i, j = 0;
540  stringbuffer_append_printf(buf, "(%s: ", attenuation);
541  for (i = 0; i < NRSPELLPATHS; i++)
542  if (value&(1<<i)) {
543  if (j)
544  stringbuffer_append_string(buf, ", ");
545  else
546  j = 1;
548  }
549  stringbuffer_append_string(buf, ")");
550  }
551 
552  return buf;
553 }
554 
562 StringBuffer *describe_attacktype(const char *attack, int value, StringBuffer *buf) {
563  if (buf == NULL)
564  buf = stringbuffer_new();
565 
566  if (value) {
567  int i, j = 0;
568  stringbuffer_append_printf(buf, "(%s: ", attack);
569  for (i = 0; i < NROFATTACKS; i++)
570  if (value&(1<<i)) {
571  if (j)
572  stringbuffer_append_string(buf, ", ");
573  else
574  j = 1;
576  }
577  stringbuffer_append_string(buf, ")");
578  }
579 
580  return buf;
581 }
582 
586 int isqrt(int n) {
587  return (int)sqrt(n);
588 }
589 
597 void fatal(enum fatal_error err) {
598  const char *fatalmsgs[] = {
599  "Failed to allocate memory",
600  "Failed repeatedly to load maps",
601  "Hashtable for archetypes is too small",
602  "Fatal issue in archetype file",
603  "See last error",
604  };
605 
606  fprintf(logfile, "Fatal error: %s\n", fatalmsgs[err]);
607  emergency_save(0);
608  clean_tmp_files();
609  fprintf(logfile, "Exiting...\n");
610  exit(err);
611 }
int64_t random_roll64(int64_t min, int64_t max, const object *op, int goodbad)
Definition: utils.c:77
#define M_BONE
Definition: material.h:25
EXTERN FILE * logfile
Definition: global.h:142
void clean_tmp_files(void)
Definition: main.c:336
#define M_ICE
Definition: material.h:26
#define M_STONE
Definition: material.h:20
#define FLAG_IS_FLOOR
Definition: define.h:303
#define FLAG_UNPAID
Definition: define.h:236
int8_t mod[NROFATTACKS]
Definition: material.h:38
const char * strrstr(const char *haystack, const char *needle)
Definition: utils.c:325
materialtype_t * name_to_material(const char *name)
Definition: utils.c:248
const char * name
Definition: material.h:34
EXTERN materialtype_t * materialt
Definition: material.h:43
uint16_t material
Definition: object.h:347
Definition: object.h:204
Definition: object.h:112
void fatal(enum fatal_error err)
Definition: utils.c:597
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
#define MAP_HEIGHT(m)
Definition: map.h:80
int isqrt(int n)
Definition: utils.c:586
#define IS_WEAPON(op)
Definition: define.h:162
#define M_ADAMANT
Definition: material.h:22
void decay_objects(mapstruct *m)
Definition: utils.c:175
#define M_CLOTH
Definition: material.h:21
int material
Definition: material.h:36
Definition: object.h:223
#define MAX(x, y)
Definition: compat.h:20
void strip_endline(char *buf)
Definition: utils.c:341
int absdir(int d)
Definition: object.c:3652
void transmute_materialname(object *op, const object *change)
Definition: utils.c:267
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:122
#define MIN(x, y)
Definition: compat.h:17
int adjust_dir(int dir, int destination_dir)
Definition: utils.c:453
#define M_SOFT_METAL
Definition: material.h:24
int rndm(int min, int max)
Definition: utils.c:162
void make_list_like(char *input)
Definition: utils.c:395
const char * destination_dir
void object_free_drop_inventory(object *ob)
Definition: object.c:1389
#define EOL_SIZE
Definition: utils.c:336
int get_randomized_dir(int dir)
Definition: utils.c:439
#define FLAG_OBJ_ORIGINAL
Definition: define.h:365
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
#define M_LIQUID
Definition: material.h:23
const char * materialname
Definition: object.h:346
uint32_t unique
Definition: map.h:337
#define snprintf
Definition: win32.h:46
#define FMT64
Definition: compat.h:12
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:122
const char * name
Definition: object.h:311
#define M_GLASS
Definition: material.h:16
#define FLAG_OVERLAY_FLOOR
Definition: define.h:255
int get_random_dir(void)
Definition: utils.c:427
#define M_ORGANIC
Definition: material.h:19
int8_t luck
Definition: living.h:39
#define IS_LIVE(op)
Definition: define.h:172
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
void emergency_save(int flag)
Definition: main.c:333
#define MAX_BUF
Definition: define.h:35
#define NRSPELLPATHS
Definition: spells.h:40
#define IS_SHIELD(op)
Definition: define.h:169
StringBuffer * describe_attacktype(const char *attack, int value, StringBuffer *buf)
Definition: utils.c:562
void replace_unprintable_chars(char *buf)
Definition: utils.c:474
#define M_IRON
Definition: material.h:15
signed __int64 int64_t
Definition: win32.h:168
#define FOR_MAP_FINISH()
Definition: define.h:767
int16_t resist[NROFATTACKS]
Definition: object.h:341
Definition: object.h:107
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.c:354
#define RANDOM()
Definition: define.h:681
signed char int8_t
Definition: win32.h:158
living stats
Definition: object.h:368
struct archt * arch
Definition: object.h:412
#define MAP_WIDTH(m)
Definition: map.h:78
uint8_t type
Definition: object.h:338
#define NROFATTACKS
Definition: attack.h:17
sstring add_string(const char *str)
Definition: shstr.c:124
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.c:104
StringBuffer * describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf)
Definition: utils.c:534
#define M_PAPER
Definition: material.h:14
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Definition: utils.c:500
#define M_LEATHER
Definition: material.h:17
Definition: object.h:213
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
struct _materialtype * next
Definition: material.h:39
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:760
#define IS_ARMOR(op)
Definition: define.h:165
void set_materialname(object *op)
Definition: utils.c:301
Definition: map.h:325
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
#define FLAG_UNIQUE
Definition: define.h:288
#define M_WOOD
Definition: material.h:18
fatal_error
Definition: define.h:47
const char * name
Definition: object.h:466
void object_remove(object *op)
Definition: object.c:1669
const char *const attacks[NROFATTACKS]
Definition: living.c:129