Crossfire Server, Branches 1.12  R18729
utils.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_utils_c =
3  * "$Id: utils.c 11869 2009-06-14 14:32:45Z akirschbaum $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
41 #include <stdlib.h>
42 #include <global.h>
43 
51 int random_roll(int min, int max, const object *op, int goodbad) {
52  int omin, diff, luck, base, ran;
53 
54  omin = min;
55  diff = max-min+1;
56  ((diff > 2) ? (base = 20) : (base = 50)); /* d2 and d3 are corner cases */
57 
58  if (max < 1 || diff < 1) {
59  LOG(llevError, "Calling random_roll with min=%d max=%d\n", min, max);
60  return(min); /* avoids a float exception */
61  }
62 
63  ran = RANDOM();
64 
65  if (op->type != PLAYER)
66  return((ran%diff)+min);
67 
68  luck = op->stats.luck;
69  if (RANDOM()%base < MIN(10, abs(luck))) {
70  /* we have a winner */
71  ((luck > 0) ? (luck = 1) : (luck = -1));
72  diff -= luck;
73  if (diff < 1)
74  return(omin); /*check again*/
75  ((goodbad) ? (min += luck) : (diff));
76 
77  return(MAX(omin, MIN(max, (ran%diff)+min)));
78  }
79  return((ran%diff)+min);
80 }
81 
86 sint64 random_roll64(sint64 min, sint64 max, const object *op, int goodbad) {
87  sint64 omin, diff, luck, ran;
88  int base;
89 
90  omin = min;
91  diff = max-min+1;
92  ((diff > 2) ? (base = 20) : (base = 50)); /* d2 and d3 are corner cases */
93 
94  if (max < 1 || diff < 1) {
95 #ifndef WIN32
96  LOG(llevError, "Calling random_roll with min=%lld max=%lld\n", min, max);
97 #else
98  LOG(llevError, "Calling random_roll with min=%I64d max=%I64d\n", min, max);
99 #endif
100  return(min); /* avoids a float exception */
101  }
102 
103  /* Don't know of a portable call to get 64 bit random values.
104  * So make a call to get two 32 bit random numbers, and just to
105  * a little byteshifting. Do make sure the first one is only
106  * 32 bit, so we don't get skewed results
107  */
108  ran = (RANDOM()&0xffffffff)|((sint64)RANDOM()<<32);
109 
110  if (op->type != PLAYER)
111  return((ran%diff)+min);
112 
113  luck = op->stats.luck;
114  if (RANDOM()%base < MIN(10, abs(luck))) {
115  /* we have a winner */
116  ((luck > 0) ? (luck = 1) : (luck = -1));
117  diff -= luck;
118  if (diff < 1)
119  return (omin); /*check again*/
120  ((goodbad) ? (min += luck) : (diff));
121 
122  return (MAX(omin, MIN(max, (ran%diff)+min)));
123  }
124  return ((ran%diff)+min);
125 }
126 
134 int die_roll(int num, int size, const object *op, int goodbad) {
135  int min, diff, luck, total, i, gotlucky, base, ran;
136 
137  diff = size;
138  min = 1;
139  luck = total = gotlucky = 0;
140  ((diff > 2) ? (base = 20) : (base = 50)); /* d2 and d3 are corner cases */
141  if (size < 2 || diff < 1) {
142  LOG(llevError, "Calling die_roll with num=%d size=%d\n", num, size);
143  return(num); /* avoids a float exception */
144  }
145 
146  if (op->type == PLAYER)
147  luck = op->stats.luck;
148 
149  for (i = 0; i < num; i++) {
150  if (RANDOM()%base < MIN(10, abs(luck)) && !gotlucky) {
151  /* we have a winner */
152  gotlucky++;
153  ((luck > 0) ? (luck = 1) : (luck = -1));
154  diff -= luck;
155  if (diff < 1)
156  return(num); /*check again*/
157  ((goodbad) ? (min += luck) : (diff));
158  ran = RANDOM();
159  total += MAX(1, MIN(size, (ran%diff)+min));
160  } else {
161  total += RANDOM()%size+1;
162  }
163  }
164  return(total);
165 }
166 
174 int rndm(int min, int max) {
175  int diff;
176 
177  diff = max-min+1;
178  if (max < 1 || diff < 1)
179  return (min);
180 
181  return (RANDOM()%diff+min);
182 }
183 
188  int x, y, destroy;
189  object *op, *otmp;
190 
191  if (m->unique)
192  return;
193 
194  for (x = 0; x < MAP_WIDTH(m); x++)
195  for (y = 0; y < MAP_HEIGHT(m); y++)
196  for (op = GET_MAP_OB(m, x, y); op; op = otmp) {
197  destroy = 0;
198  otmp = op->above;
200  break;
201  if (QUERY_FLAG(op, FLAG_IS_FLOOR)
203  || QUERY_FLAG(op, FLAG_UNIQUE)
205  || QUERY_FLAG(op, FLAG_UNPAID)
206  || IS_LIVE(op))
207  continue;
208  if (op->head)
209  /* Don't try to remove a non head part of a multipart object, remove_ob() would abort(). */
210  continue;
211  /* otherwise, we decay and destroy */
212  if (IS_WEAPON(op)) {
213  op->stats.dam--;
214  if (op->stats.dam < 0)
215  destroy = 1;
216  } else if (IS_ARMOR(op)
217  || IS_SHIELD(op)
218  || op->type == GIRDLE
219  || op->type == GLOVES
220  || op->type == CLOAK) {
221  op->stats.ac--;
222  if (op->stats.ac < 0)
223  destroy = 1;
224  } else if (op->type == FOOD) {
225  op->stats.food -= rndm(5, 20);
226  if (op->stats.food < 0)
227  destroy = 1;
228  } else {
229  if (op->material&M_PAPER
230  || op->material&M_LEATHER
231  || op->material&M_WOOD
232  || op->material&M_ORGANIC
233  || op->material&M_CLOTH
234  || op->material&M_LIQUID)
235  destroy = 1;
236  if (op->material&M_IRON && rndm(1, 5) == 1)
237  destroy = 1;
238  if (op->material&M_GLASS && rndm(1, 2) == 1)
239  destroy = 1;
240  if ((op->material&M_STONE || op->material&M_ADAMANT) && rndm(1, 10) == 1)
241  destroy = 1;
242  if ((op->material&M_SOFT_METAL || op->material&M_BONE)
243  && rndm(1, 3) == 1)
244  destroy = 1;
245  if (op->material&M_ICE && rndm(0, 100) > 70)
246  destroy = 1;
247  }
248  /* adjust overall chance below */
249  if (destroy && rndm(0, 1)) {
250  remove_ob(op);
251  free_object(op);
252  }
253  }
254 }
255 
262 materialtype_t *name_to_material(const char *name) {
263  materialtype_t *mt, *nmt;
264 
265  mt = NULL;
266  for (nmt = materialt; nmt != NULL && nmt->next != NULL; nmt = nmt->next) {
267  if (strcmp(name, nmt->name) == 0) {
268  mt = nmt;
269  break;
270  }
271  }
272  return mt;
273 }
274 
281 void transmute_materialname(object *op, const object *change) {
282  materialtype_t *mt;
283  int j;
284 
285  if (op->materialname == NULL)
286  return;
287 
288  if (change->materialname != NULL
289  && strcmp(op->materialname, change->materialname))
290  return;
291 
292  if (!(IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK))
293  return;
294 
295  mt = name_to_material(op->materialname);
296  if (!mt) {
297  LOG(llevError, "archetype '%s>%s' uses nonexistent material '%s'\n", op->arch->name, op->name, op->materialname);
298  return;
299  }
300 
301  for (j = 0; j < NROFATTACKS; j++)
302  if (op->resist[j] == 0 && change->resist[j] != 0) {
303  op->resist[j] += mt->mod[j];
304  if (op->resist[j] > 100)
305  op->resist[j] = 100;
306  if (op->resist[j] < -100)
307  op->resist[j] = -100;
308  }
309 }
310 
314 void set_materialname(object *op, int difficulty, materialtype_t *nmt) {
315  materialtype_t *mt, *lmt;
316 
317  if (op->materialname != NULL)
318  return;
319 
320  if (nmt == NULL) {
321  lmt = NULL;
322 #ifndef NEW_MATERIAL_CODE
323  for (mt = materialt; mt != NULL && mt->next != NULL; mt = mt->next) {
324  if (op->material&mt->material) {
325  lmt = mt;
326  break;
327  }
328  }
329 #else
330  for (mt = materialt; mt != NULL && mt->next != NULL; mt = mt->next) {
331  if (op->material&mt->material
332  && rndm(1, 100) <= mt->chance
333  && difficulty >= mt->difficulty
334  && (op->magic >= mt->magic || mt->magic == 0)) {
335  lmt = mt;
336  if (!(IS_WEAPON(op) || IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK))
337  break;
338  }
339  }
340 #endif
341  } else {
342  lmt = nmt;
343  }
344 
345  if (lmt != NULL) {
346 #ifndef NEW_MATERIAL_CODE
347  op->materialname = add_string(lmt->name);
348  return;
349 #else
350 
351  if (op->stats.dam && IS_WEAPON(op)) {
352  op->stats.dam += lmt->damage;
353  if (op->stats.dam < 1)
354  op->stats.dam = 1;
355  }
356  if (op->stats.sp && op->type == BOW)
357  op->stats.sp += lmt->sp;
358  if (op->stats.wc && IS_WEAPON(op))
359  op->stats.wc += lmt->wc;
360  if (IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK) {
361  int j;
362 
363  if (op->stats.ac)
364  op->stats.ac += lmt->ac;
365  for (j = 0; j < NROFATTACKS; j++)
366  if (op->resist[j] != 0) {
367  op->resist[j] += lmt->mod[j];
368  if (op->resist[j] > 100)
369  op->resist[j] = 100;
370  if (op->resist[j] < -100)
371  op->resist[j] = -100;
372  }
373  }
374  op->materialname = add_string(lmt->name);
375  /* dont make it unstackable if it doesn't need to be */
376  if (IS_WEAPON(op) || IS_ARMOR(op) || IS_SHIELD(op) || op->type == GIRDLE || op->type == GLOVES || op->type == CLOAK) {
377  op->weight = (op->weight*lmt->weight)/100;
378  op->value = (op->value*lmt->value)/100;
379  }
380 #endif
381  }
382 }
383 
388 void strip_media_tag(char *message) {
389  int in_tag = 0;
390  char *dest;
391  char *src;
392  src = dest = message;
393 
394  while (*src != '\0') {
395  if (*src == '[') {
396  in_tag = 1;
397  } else if (in_tag && (*src == ']'))
398  in_tag = 0;
399  else if (!in_tag) {
400  *dest = *src;
401  dest++;
402  }
403  src++;
404  }
405  *dest = '\0';
406 }
407 
414 const char *strrstr(const char *haystack, const char *needle) {
415  const char *lastneedle;
416 
417  lastneedle = NULL;
418  while ((haystack = strstr(haystack, needle)) != NULL) {
419  lastneedle = haystack;
420  haystack++;
421  }
422  return lastneedle;
423 
424 }
425 
426 #define EOL_SIZE (sizeof("\n")-1)
427 
431 void strip_endline(char *buf) {
432  if (strlen(buf) < sizeof("\n")) {
433  return;
434  }
435  if (!strcmp(buf+strlen(buf)-EOL_SIZE, "\n"))
436  buf[strlen(buf)-EOL_SIZE] = '\0';
437 }
438 
444 void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize) {
445  size_t resultlen;
446  size_t keylen;
447 
448  /* special case to prevent infinite loop if key==replacement=="" */
449  if (strcmp(key, replacement) == 0) {
450  snprintf(result, resultsize, "%s", src);
451  return;
452  }
453 
454  keylen = strlen(key);
455 
456  resultlen = 0;
457  while (*src != '\0' && resultlen+1 < resultsize) {
458  if (strncmp(src, key, keylen) == 0) {
459  snprintf(result+resultlen, resultsize-resultlen, "%s", replacement);
460  resultlen += strlen(result+resultlen);
461  src += keylen;
462  } else {
463  result[resultlen++] = *src++;
464  }
465  }
466  result[resultlen] = '\0';
467 }
468 
485 void make_list_like(char *input) {
486  char *p, tmp[MAX_BUF];
487  int i;
488  if (!input || strlen(input) > MAX_BUF-5)
489  return;
490  /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */
491 
492  strncpy(tmp, input, MAX_BUF-5);
493  /*trim all trailing commas, spaces etc.*/
494  for (i = strlen(tmp); !isalnum(tmp[i]) && i >= 0; i--)
495  tmp[i] = '\0';
496  strcat(tmp, ".");
497 
498  p = strrchr(tmp, ',');
499  if (p) {
500  *p = '\0';
501  strcpy(input, tmp);
502  p++;
503  strcat(input, " and");
504  strcat(input, p);
505  } else
506  strcpy(input, tmp);
507  return;
508 }
509 
516 void replace_unprintable_chars(char *buf) {
517  char *p;
518 
519  for (p = buf; *p != '\0'; p++) {
520  if (*p < ' ') {
521  *p = ' ';
522  }
523  }
524 }
#define M_BONE
Definition: material.h:55
#define FOOD
Definition: define.h:118
#define M_ICE
Definition: material.h:56
#define M_STONE
Definition: material.h:50
#define FLAG_IS_FLOOR
Definition: define.h:599
#define FLAG_UNPAID
Definition: define.h:532
sint8 ac
Definition: living.h:79
void strip_media_tag(char *message)
Definition: utils.c:388
const char * strrstr(const char *haystack, const char *needle)
Definition: utils.c:414
materialtype_t * name_to_material(const char *name)
Definition: utils.c:262
const char * name
Definition: material.h:63
EXTERN materialtype_t * materialt
Definition: material.h:80
uint16 material
Definition: object.h:198
#define MAP_HEIGHT(m)
Definition: map.h:99
#define IS_WEAPON(op)
Definition: define.h:449
#define M_ADAMANT
Definition: material.h:52
void decay_objects(mapstruct *m)
Definition: utils.c:187
#define M_CLOTH
Definition: material.h:51
struct obj * above
Definition: object.h:146
int material
Definition: material.h:65
#define CLOAK
Definition: define.h:268
#define GIRDLE
Definition: define.h:295
sint16 sp
Definition: living.h:83
void strip_endline(char *buf)
Definition: utils.c:431
void transmute_materialname(object *op, const object *change)
Definition: utils.c:281
#define PLAYER
Definition: define.h:113
sint8 magic
Definition: material.h:70
#define M_SOFT_METAL
Definition: material.h:54
void set_materialname(object *op, int difficulty, materialtype_t *nmt)
Definition: utils.c:314
int rndm(int min, int max)
Definition: utils.c:174
void make_list_like(char *input)
Definition: utils.c:485
#define EOL_SIZE
Definition: utils.c:426
void remove_ob(object *op)
Definition: object.c:1515
#define FLAG_OBJ_ORIGINAL
Definition: define.h:661
#define M_LIQUID
Definition: material.h:53
const char * materialname
Definition: object.h:197
sint32 weight
Definition: object.h:216
sint16 dam
Definition: living.h:87
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:134
const char * name
Definition: object.h:167
#define M_GLASS
Definition: material.h:46
#define FLAG_OVERLAY_FLOOR
Definition: define.h:551
#define M_ORGANIC
Definition: material.h:49
#define MAX(x, y)
Definition: define.h:70
sint8 luck
Definition: living.h:80
#define IS_LIVE(op)
Definition: define.h:459
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define MAX_BUF
Definition: define.h:81
#define GLOVES
Definition: define.h:282
#define IS_SHIELD(op)
Definition: define.h:456
void replace_unprintable_chars(char *buf)
Definition: utils.c:516
sint8 wc
Definition: living.h:79
sint8 difficulty
Definition: material.h:69
#define M_IRON
Definition: material.h:45
#define MIN(x, y)
Definition: define.h:67
sint16 resist[NROFATTACKS]
Definition: object.h:192
uint32 unique
Definition: map.h:358
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.c:444
sint8 wc
Definition: material.h:72
sint8 ac
Definition: material.h:73
living stats
Definition: object.h:219
struct archt * arch
Definition: object.h:263
#define MAP_WIDTH(m)
Definition: map.h:97
sint8 mod[NROFATTACKS]
Definition: material.h:67
#define NROFATTACKS
Definition: attack.h:45
#define BOW
Definition: define.h:126
sstring add_string(const char *str)
Definition: shstr.c:116
#define M_PAPER
Definition: material.h:44
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
#define M_LEATHER
Definition: material.h:47
struct obj * head
Definition: object.h:154
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
struct _materialtype * next
Definition: material.h:77
#define IS_ARMOR(op)
Definition: define.h:452
sint8 chance
Definition: material.h:68
void free_object(object *ob)
Definition: object.c:1238
Definition: map.h:346
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:51
sint64 random_roll64(sint64 min, sint64 max, const object *op, int goodbad)
Definition: utils.c:86
#define FLAG_UNIQUE
Definition: define.h:584
#define M_WOOD
Definition: material.h:48
sint8 damage
Definition: material.h:71
sint32 value
Definition: object.h:201
sint8 magic
Definition: object.h:199
const char * name
Definition: object.h:322
sint8 sp
Definition: material.h:74
uint8 type
Definition: object.h:189
sint32 food
Definition: living.h:89