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;
513  stringbuffer_append_printf(buf, "(%s: ", attenuation);
514  for (i = 0; i < NRSPELLPATHS; i++)
515  if (value&(1<<i)) {
516  if (j)
518  else
519  j = 1;
521  }
523  }
524 
525  return buf;
526 }
527 
536  if (buf == NULL)
537  buf = stringbuffer_new();
538 
539  if (value) {
540  int i, j = 0;
541  stringbuffer_append_printf(buf, "(%s: ", attack);
542  for (i = 0; i < NROFATTACKS; i++)
543  if (value&(1<<i)) {
544  if (j)
546  else
547  j = 1;
549  }
551  }
552 
553  return buf;
554 }
555 
559 int isqrt(int n) {
560  return (int)sqrt(n);
561 }
562 
570 void fatal(enum fatal_error err) {
571  const char *fatalmsgs[] = {
572  "Failed to allocate memory",
573  "Failed repeatedly to load maps",
574  "Hashtable for archetypes is too small",
575  "Fatal issue in archetype file",
576  "See last error",
577  };
578 
579  if (settings.fatal_hook) {
580  settings.fatal_hook(err);
581  }
582 
583  fprintf(logfile, "Fatal error: %s\n", fatalmsgs[err]);
584  emergency_save(0);
585  clean_tmp_files();
586  fprintf(logfile, "Exiting...\n");
587  exit(err);
588 }
589 
597  if (lc->next)
598  free_charlinks(lc->next);
599  free(lc);
600 }
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
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.cpp:412
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
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
n
based on the size of the this randomly makes land number of spaces randomly lower or higher The default is Note that this is run also based on the the altitude amount will likely be less So if you do something like l and n
Definition: land.6.txt:25
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.cpp:239
name_to_material
materialtype_t * name_to_material(const char *name)
Definition: utils.cpp:248
adjust_dir
int adjust_dir(int dir, int destination_dir)
Definition: utils.cpp:426
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
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
absdir
int absdir(int d)
Definition: object.cpp:3705
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
get_random_dir
int get_random_dir(void)
Definition: utils.cpp:400
mail_login.total
total
Definition: mail_login.py:30
MIN
#define MIN(x, y)
Definition: compat.h:21
replace
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.cpp:327
Ice.tmp
int tmp
Definition: Ice.py:207
M_STONE
#define M_STONE
Definition: material.h:20
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
materials
std::vector< materialtype_t * > materials
Definition: init.cpp:128
buf
StringBuffer * buf
Definition: readable.cpp:1552
Settings::fatal_hook
fatalHook fatal_hook
Definition: global.h:337
MAX
#define MAX(x, y)
Definition: compat.h:24
describe_attacktype
StringBuffer * describe_attacktype(const char *attack, int value, StringBuffer *buf)
Definition: utils.cpp:535
object::resist
int16_t resist[NROFATTACKS]
Definition: object.h:351
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
linked_char
Definition: global.h:96
m
static event_registration m
Definition: citylife.cpp:425
transmute_materialname
void transmute_materialname(object *op, const object *change)
Definition: utils.cpp:263
CLOAK
@ CLOAK
Definition: object.h:209
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
FMT64
#define FMT64
Definition: compat.h:16
M_LIQUID
#define M_LIQUID
Definition: material.h:23
decay_objects
void decay_objects(mapstruct *m)
Definition: utils.cpp:175
M_ICE
#define M_ICE
Definition: material.h:26
rotate-tower.result
bool result
Definition: rotate-tower.py:13
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
isqrt
int isqrt(int n)
Definition: utils.cpp:559
make_face_from_files.str
str
Definition: make_face_from_files.py:30
object::materialname
sstring materialname
Definition: object.h:356
linked_char::next
struct linked_char * next
Definition: global.h:98
free_charlinks
void free_charlinks(linked_char *lc)
Definition: utils.cpp:596
say.max
dictionary max
Definition: say.py:148
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.cpp:122
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
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:74
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
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
describe_spellpath_attenuation
StringBuffer * describe_spellpath_attenuation(const char *attenuation, int value, StringBuffer *buf)
Definition: utils.cpp:507
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:570
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:314
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
set_materialname
void set_materialname(object *op)
Definition: utils.cpp:297
exit
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
diamondslots.y
y
Definition: diamondslots.py:16
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.cpp:42
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:76
M_PAPER
#define M_PAPER
Definition: material.h:14
split_string
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Definition: utils.cpp:473
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
strip_endline
void strip_endline(char *buf)
Definition: utils.cpp:314
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
EOL_SIZE
#define EOL_SIZE
Definition: utils.cpp:309
fatal_error
fatal_error
Definition: define.h:47
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
rndm
int rndm(int min, int max)
Definition: utils.cpp:162
materialtype_t
Definition: material.h:32
destination_dir
const char * destination_dir
Definition: gridarta-types-convert.cpp:32
make_list_like
void make_list_like(char *input)
Definition: utils.cpp:368
StringBuffer
Definition: stringbuffer.cpp:25
random_roll64
int64_t random_roll64(int64_t min, int64_t max, const object *op, int goodbad)
Definition: utils.cpp:77
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
replace_unprintable_chars
void replace_unprintable_chars(char *buf)
Definition: utils.cpp:447