Crossfire Server, Branches 1.12  R18729
check_1727944.c
Go to the documentation of this file.
1 /*
2  * CrossFire, A Multiplayer game for X-windows
3  *
4  * Copyright (C) 2007 Crossfire Development Team
5  * Copyright (C) 1992 Frank Tore Johansen
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * The authors can be reached via e-mail at crossfire-devel@real-time.com
22  */
23 
34 #include <stdlib.h>
35 #include <check.h>
36 #include <global.h>
37 
38 void setup(void) {
39  /* put any initialisation steps here, they will be run before each testcase */
40 }
41 
42 void teardown(void) {
43  /* put any cleanup steps here, they will be run after each testcase */
44 }
45 
46 #if 0
47 static mapstruct *get_random_map(mapstruct *map) {
48  object *exit_ob;
49  mapstruct *random;
50  RMParms rp;
51  char newmap_name[HUGE_BUF], *cp;
52  static int reference_number = 0;
53  int x, y;
54 
55  exit_ob = NULL;
56  for (x = 0; x < MAP_WIDTH(map) && exit_ob == NULL; x++) {
57  for (y = 0; y < MAP_HEIGHT(map) && exit_ob == NULL; y++) {
58  for (exit_ob = GET_MAP_OB(map, x, y); exit_ob != NULL; exit_ob = exit_ob->above)
59  if (exit_ob->type == EXIT && exit_ob->msg != NULL)
60  break;
61  }
62  }
63 
64  if (!exit_ob)
65  /* this means we reached the end of the random part. */
66  return NULL;
67 
68  /* copied from server/server.c:enter_random_map(). */
69  memset(&rp, 0, sizeof(RMParms));
70  rp.Xsize = -1;
71  rp.Ysize = -1;
72  rp.region = get_region_by_map(exit_ob->map);
73  if (exit_ob->msg)
74  set_random_map_variable(&rp, exit_ob->msg);
75  rp.origin_x = exit_ob->x;
76  rp.origin_y = exit_ob->y;
77  strcpy(rp.origin_map, map->path);
78 
79  /* If we have a final_map, use it as a base name to give some clue
80  * as where the player is. Otherwise, use the origin map.
81  * Take the last component (after the last slash) to give
82  * shorter names without bogus slashes.
83  */
84  if (rp.final_map[0]) {
85  cp = strrchr(rp.final_map, '/');
86  if (!cp)
87  cp = rp.final_map;
88  } else {
89  char buf[HUGE_BUF];
90 
91  cp = strrchr(rp.origin_map, '/');
92  if (!cp)
93  cp = rp.origin_map;
94  /* Need to strip of any trailing digits, if it has them */
95  snprintf(buf, sizeof(buf), "%s", cp);
96  while (isdigit(buf[strlen(buf)-1]))
97  buf[strlen(buf)-1] = 0;
98  cp = buf;
99  }
100  snprintf(newmap_name, sizeof(newmap_name), "/random/%s%04d", cp+1, reference_number++);
101  /* now to generate the actual map. */
102  return generate_random_map(newmap_name, &rp, NULL);
103 }
104 
105 static void do_run() {
106  mapstruct *worldmap;
107  mapstruct *random;
108  mapstruct *old;
109  int iteration, x, y, map;
110  object *check;
111  char path[150];
112 
113  for (map = 1; map <= 3; map++) {
114  snprintf(path, sizeof(path), "/whalingoutpost/underwaterdungeon/level%d", map);
115  worldmap = ready_map_name(path, 0);
116  fail_unless(worldmap != NULL, "Can't load %s", path);
117 
118  random = worldmap;
119  old = NULL;
120  iteration = 0;
121  while (random != NULL) {
122  random = get_random_map(random);
123  if (!random)
124  break;
125  if (old)
126  delete_map(old);
127  old = random;
128  iteration++;
129  for (x = 0; x < MAP_WIDTH(random); x++) {
130  for (y = 0; y < MAP_HEIGHT(random); y++) {
131  for (check = GET_MAP_OB(random, x, y); check; check = check->above) {
132  if (check->type == HORN && check->title && strcmp(check->title, "of Plenty") == 0)
133  fail_unless(check->inv != NULL, "Horn has empty inventory!");
134  }
135  }
136  }
137  }
138  fail_unless(iteration != 0, "did %d iterations", iteration);
139  if (old)
140  delete_map(old);
141  }
142 }
143 #endif
144 
145 #if 0
146 static void do_run() {
147  mapstruct *map, *overlay;
148  int x, y, found = 0, test = 0;
149  object *check;
150 
151  overlay = ready_map_name("../../rsc/bug_1727944_unique", MAP_PLAYER_UNIQUE);
152  fail_unless(overlay != NULL, "Couldn't load unique map ../../rsc/bug_1727944_unique");
153 
154  while (found == 0 && test < 10) {
155  map = ready_map_name("../../rsc/bug_1727944", MAP_PLAYER_UNIQUE);
156  fail_unless(map != NULL, "couldn't load map ../../rsc/bug_1727944");
157 
158  for (x = 0; x < MAP_WIDTH(map); x++) {
159  for (y = 0; y < MAP_HEIGHT(map); y++) {
160  for (check = GET_MAP_OB(map, x, y); check; check = check->above) {
161  if (check->type == HORN) {
162  fail_unless(check->inv != NULL, "Horn has empty inventory!");
163  fail_unless(check->inv->below == NULL, "Horn has 2 items in inventory!");
164  if (check->title && strcmp(check->title, "of Plenty") == 0) {
165  remove_ob(check);
166  insert_ob_in_map_at(check, overlay, NULL, 0, 2, 3);
167  found++;
168  break;
169  }
170  }
171  }
172  }
173  }
174  delete_map(map);
175  test++;
176  }
177  save_map(overlay, SAVE_MODE_OVERLAY);
178  delete_map(overlay);
179 }
180 #endif
181 
182 extern int artifact_init;
183 extern int arch_init;
184 
185 /* Copied from loader.l */
186 extern const char *const spell_mapping[];
187 
188 static void local_check_loaded_object(object *op) {
189  int ip;
190 
191  if (artifact_init)
192  /* Artifacts are special beasts, let's not check them. */
193  return;
194 
195  /* We do some specialized handling to handle legacy cases of name_pl.
196  * If the object doesn't have a name_pl, we just use the object name -
197  * this isn't perfect (things won't be properly pluralized), but works to
198  * that degree (5 heart is still quite understandable). But the case we
199  * also have to catch is if this object is not using the normal name for
200  * the object. In that case, we also want to use the loaded name.
201  * Otherwise, what happens is that the the plural name will lose
202  * information (appear as just 'hearts' and not 'goblins heart')
203  */
204  if (op->arch && op->name != op->arch->clone.name && op->name_pl == op->arch->clone.name_pl) {
205  if (op->name_pl)
206  free_string(op->name_pl);
207  op->name_pl = NULL;
208  }
209  if (!op->name_pl && op->name)
210  op->name_pl = add_string(op->name);
211 
212  /* objects now have a materialname. try to patch it in */
213  if (!(IS_WEAPON(op) && op->level > 0)) {
214  if (op->map != NULL)
215  set_materialname(op, op->map->difficulty, NULL);
216  else
217  set_materialname(op, 5, NULL);
218  }
219  /* only do these when program is first run - a bit
220  * excessive to do this at every run - most of this is
221  * really just to catch any errors - program will still run, but
222  * not in the ideal fashion.
223  */
224  if ((op->type == WEAPON || op->type == BOW) && arch_init) {
225  if (!op->skill) {
226  LOG(llevError, "Weapon %s lacks a skill.\n", op->name);
227  } else if ((!strcmp(op->skill, "one handed weapons") && op->body_info[1] != -1)
228  || (!strcmp(op->skill, "two handed weapons") && op->body_info[1] != -2)) {
229  LOG(llevError, "weapon %s arm usage does not match skill: %d, %s\n",
230  op->name, op->body_info[1], op->skill);
231  }
232  }
233 
234  /* We changed last_heal to gen_sp_armour, which is what it
235  * really does for many objects. Need to catch any in maps
236  * that may have an old value.
237  */
238  if ((op->type == WEAPON)
239  || (op->type == ARMOUR)
240  || (op->type == HELMET)
241  || (op->type == SHIELD)
242  || (op->type == RING)
243  || (op->type == BOOTS)
244  || (op->type == GLOVES)
245  || (op->type == AMULET)
246  || (op->type == GIRDLE)
247  || (op->type == BRACERS)
248  || (op->type == CLOAK)) {
249  if (op->last_heal) {
250  LOG(llevDebug, "Object %s still has last_heal set, not gen_sp_armour\n", op->name ? op->name : "NULL");
251  op->gen_sp_armour = op->last_heal;
252  op->last_heal = 0;
253  }
254  ip = calc_item_power(op, 0);
255  /* Legacy objects from before item power was in the game */
256  if (!op->item_power && ip) {
257  if (ip > 3) {
258  LOG(llevDebug, "Object %s had no item power, using %d\n", op->name ? op->name : "NULL", ip);
259  }
260  op->item_power = ip;
261  }
262  /* Check for possibly bogus values. Has to meet both these criteria -
263  * something that has item_power 1 is probably just fine if our calculated
264  * value is 1 or 2 - these values are small enough that hard to be precise.
265  * similarly, it item_power is 0, the first check will always pass,
266  * but not the second one.
267  */
268  if (ip > 2*op->item_power && ip > (op->item_power+3)) {
269  LOG(llevDebug, "Object %s seems to have too low item power? %d > %d\n", op->name ? op->name : "NULL", ip, op->item_power);
270  }
271  }
272  /* Old spellcasting object - need to load in the appropiate object */
273  if ((op->type == ROD || op->type == WAND || op->type == SCROLL || op->type == HORN || op->type == FIREWALL || /* POTIONS and ALTARS don't always cast spells, but if they do, update them */ ((op->type == POTION || op->type == ALTAR) && op->stats.sp))
274  && !op->inv
275  && !arch_init) {
276  object *tmp;
277 
278  /* Fireall is bizarre in that spell type was stored in dam. Rest are 'normal'
279  * in that spell was stored in sp.
280  */
281  tmp = create_archetype(spell_mapping[op->type == FIREWALL ? op->stats.dam : op->stats.sp]);
282  insert_ob_in_ob(tmp, op);
283  op->randomitems = NULL; /* So another spell isn't created for this object */
284  }
285 
286  /* spellbooks & runes use slaying. But not to arch name, but to spell name */
287  if ((op->type == SPELLBOOK || op->type == RUNE) && op->slaying && !op->inv && !arch_init) {
288  object *tmp;
289 
291  insert_ob_in_ob(tmp, op);
292  op->randomitems = NULL; /* So another spell isn't created for this object */
293  /* without this, value is all screwed up */
294  op->value = op->arch->clone.value*op->inv->value;
295  }
296 
297  if (QUERY_FLAG(op, FLAG_MONSTER)) {
298  if (op->stats.hp > op->stats.maxhp)
299  LOG(llevDebug, "Monster %s has hp set higher than maxhp (%d>%d)\n", op->name, op->stats.hp, op->stats.maxhp);
300  }
302  || op->type == CREATOR
303  || op->type == CONVERTER) {
304  /* Object will duplicate it's content as part of the
305  * generation process. To do this, we must flag inventory
306  * so it remains unevaluated concerning the randomitems and
307  * the living (a demonlord shouldn't cast from inside generator!)
308  */
310  }
311 
312  /* Here we'll handle custom monsters. In order to handle them correctly, especially in the fix_object
313  * method, we'll create a new temporary archetype containing defined values.
314  * Of course this doesn't apply when loading archetypes or artifacts.
315  */
316  if (arch_init == 0 && artifact_init == 0 && QUERY_FLAG(op, FLAG_MONSTER) && op->arch && !can_merge(op, &op->arch->clone)) {
318 
319  temp->reference_count++;
320  temp->name = add_string(op->arch->name);
321  temp->tail_x = op->arch->tail_x;
322  temp->tail_y = op->arch->tail_y;
323  copy_object(op, &temp->clone);
324  temp->clone.inv = NULL;
325  temp->clone.env = NULL;
326  temp->clone.x = 0;
327  temp->clone.y = 0;
328  temp->clone.map = NULL;
329  if (FABS(temp->clone.speed) > MIN_ACTIVE_SPEED) {
330  /* Clone has a speed, so need to clear that because it isn't on a map.
331  * But we need to keep the value, because otherwise the customized object
332  * will have no speed (fix_player() will use the 0 value). So set it
333  * to zero, call update_ob_speed() to remove it from active list, then
334  * set its speed back to the original.
335  */
336  temp->clone.speed = 0;
337  update_ob_speed(&temp->clone);
338  temp->clone.speed = op->speed;
339  }
340 
341  temp->more = op->arch->more;
342  op->arch = temp;
343  /* LOG(llevDebug, "created temporary archetype for %s at %d,%d\n", op->name, op->x, op->y); */
344  }
345 }
346 
347 START_TEST(test_randommaps) {
348 #if 0
349  int test;
350  mapstruct *overlay;
351  object *check;
352 
353  for (test = 0; test < 50; test++)
354  do_run();
355 
356  for (test = 0; test < 50; test++) {
357  overlay = ready_map_name("../../rsc/bug_1727944_unique", MAP_PLAYER_UNIQUE);
358  fail_unless(overlay != NULL, "Couldn't load unique map ../../rsc/bug_1727944_unique");
359  fail_unless(GET_MAP_OB(overlay, 2, 3) != NULL, "No item on spot 2,3?");
360 
361  for (check = GET_MAP_OB(overlay, 2, 3)->above; check != NULL; check = check->above) {
362  fail_unless(check->type == HORN, "Found a non horn?");
363  fail_unless(check->inv != NULL, "Horn without a spell!");
364  fail_unless(check->inv->below == NULL, "Horn with 2 items in inventory.");
365  }
366  save_map(overlay, SAVE_MODE_OVERLAY);
367  delete_map(overlay);
368  }
369 #endif
370 
371 #if 0
372  int test;
373  archetype *horn = find_archetype("horn");
374  fail_unless(horn != NULL, "couldn't find archetype horn.");
375  archetype *horn2 = find_archetype("horn2");
376  fail_unless(horn2 != NULL, "couldn't find archetype horn2.");
377 
378  for (test = 0; test < 100000; test++) {
379  object *check = arch_to_object(RANDOM()%2 ? horn : horn2);
380 
381  generate_artifact(check, RANDOM()%100);
382  fail_unless(check->inv != NULL, "horn without inventory!");
383  }
384 #endif
385 
386  int test, level, found = 0;
387  object *the_chest, *check;
388  mapstruct *map;
389  treasurelist *tlist = find_treasurelist("uncommon_items");
390  fail_unless(tlist != NULL, "couldn't find treasure list uncommon_items");
391 
392  for (test = 0; test < 10; test++) {
393  for (level = 1; level < 120; level++) {
394  map = get_empty_map(1, 1);
395  fail_unless(map != NULL, "failed to get empty map");
396  map->difficulty = level;
397 
398  the_chest = create_archetype("chest"); /* was "chest_2" */
399  fail_unless(the_chest != NULL, "failed to get chest");
400  the_chest->randomitems = tlist;
401  the_chest->stats.hp = RANDOM()%100;
402  insert_ob_in_map_at(the_chest, map, NULL, 0, 0, 0);
403  fix_auto_apply(map);
404  the_chest = GET_MAP_OB(map, 0, 0);
405  fail_unless(the_chest != NULL, "failed to recover chest?");
406  for (check = the_chest->inv; check; check = check->below) {
407  if (check->type != HORN)
408  continue;
410  fail_unless(check->inv != NULL, "horn without inventory");
411  fail_unless(check->inv->below == NULL, "horn with 2 items");
412  fail_unless(check->randomitems == NULL, "horn with randomitems set");
413  found++;
414  }
415  delete_map(map);
416  }
417  }
418  fail_unless(found > 100, "didn't find 100 horn but %d??", found);
419 
420 }
421 END_TEST
422 
423 Suite *bug_suite(void) {
424  Suite *s = suite_create("bug");
425  TCase *tc_core = tcase_create("Core");
426 
427  /*setup and teardown will be called before each test in testcase 'tc_core' */
428  tcase_add_checked_fixture(tc_core, setup, teardown);
429 
430  suite_add_tcase(s, tc_core);
431  tcase_add_test(tc_core, test_randommaps);
432  tcase_set_timeout(tc_core, 0);
433 
434  return s;
435 }
436 
437 int main(void) {
438  int nf;
439  Suite *s = bug_suite();
440  SRunner *sr = srunner_create(s);
441 
442  srunner_set_fork_status(sr, CK_NOFORK);
443  init(0, NULL);
444 
445  srunner_set_xml(sr, LOGDIR "/bugs/bugtrack/1727944.xml");
446  srunner_set_log(sr, LOGDIR "/bugs/bugtrack/1727944.out");
447  srunner_run_all(sr, CK_ENV); /*verbosity from env variable*/
448  nf = srunner_ntests_failed(sr);
449  srunner_free(sr);
450  return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
451 }
char path[HUGE_BUF]
Definition: map.h:384
int reference_count
Definition: object.h:329
#define RING
Definition: define.h:232
void teardown(void)
Definition: check_1727944.c:42
archetype * find_archetype(const char *name)
Definition: arch.c:700
int main(void)
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.c:884
#define FABS(x)
Definition: define.h:61
mapstruct * generate_random_map(const char *OutFileName, RMParms *RP, char **use_layout)
Definition: random_map.c:80
#define WAND
Definition: define.h:291
object * insert_ob_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1761
char final_map[RM_SIZE]
Definition: random_map.h:52
treasurelist * find_treasurelist(const char *name)
Definition: treasure.c:295
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.c:1809
sint32 last_heal
Definition: object.h:208
void free_string(sstring str)
Definition: shstr.c:272
#define HUGE_BUF
Definition: define.h:83
struct treasureliststruct * randomitems
Definition: object.h:236
#define MAP_HEIGHT(m)
Definition: map.h:99
object clone
Definition: object.h:326
void flag_inv(object *op, int flag)
Definition: object.c:2876
#define POTION
Definition: define.h:117
const char * slaying
Definition: object.h:172
region * get_region_by_map(mapstruct *m)
Definition: region.c:85
#define IS_WEAPON(op)
Definition: define.h:449
#define SCROLL
Definition: define.h:293
#define RUNE
Definition: define.h:325
struct obj * above
Definition: object.h:146
#define BOOTS
Definition: define.h:281
object * create_archetype_by_object_name(const char *name)
Definition: arch.c:173
#define CLOAK
Definition: define.h:268
sint16 x
Definition: object.h:179
#define GIRDLE
Definition: define.h:295
sint16 sp
Definition: living.h:83
#define ARMOUR
Definition: define.h:128
Definition: object.h:321
sint16 hp
Definition: living.h:81
int artifact_init
Definition: treasure.c:61
void set_materialname(object *op, int difficulty, materialtype_t *nmt)
Definition: utils.c:314
#define AMULET
Definition: define.h:153
const char * title
Definition: object.h:170
void remove_ob(object *op)
Definition: object.c:1515
sint16 maxhp
Definition: living.h:82
void fix_auto_apply(mapstruct *m)
Definition: standalone.c:130
#define CREATOR
Definition: define.h:156
const char * name_pl
Definition: object.h:168
object * create_archetype(const char *name)
Definition: arch.c:625
END_TEST Suite * bug_suite(void)
int arch_init
Definition: arch.c:54
struct mapdef * map
Definition: object.h:155
static void local_check_loaded_object(object *op)
#define HORN
Definition: define.h:147
sint16 dam
Definition: living.h:87
const char * name
Definition: object.h:167
struct obj * env
Definition: object.h:151
int can_merge(object *ob1, object *ob2)
Definition: object.c:178
struct obj * below
Definition: object.h:145
struct archt * more
Definition: object.h:325
uint16 difficulty
Definition: map.h:364
void generate_artifact(object *op, int difficulty)
Definition: treasure.c:1906
#define FLAG_IS_A_TEMPLATE
Definition: define.h:671
sint16 y
Definition: object.h:179
sint8 item_power
Definition: object.h:213
#define WEAPON
Definition: define.h:127
sint8 tail_y
Definition: object.h:327
float speed
Definition: object.h:181
void init(int argc, char **argv)
Definition: init.c:905
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define EXIT
Definition: define.h:228
object * insert_ob_in_ob(object *op, object *where)
Definition: object.c:2510
#define GLOVES
Definition: define.h:282
#define BRACERS
Definition: define.h:286
const char * skill
Definition: object.h:174
int Ysize
Definition: random_map.h:60
int Xsize
Definition: random_map.h:59
int save_map(mapstruct *m, int flag)
Definition: map.c:1453
char origin_map[RM_SIZE]
Definition: random_map.h:51
sint8 body_info[NUM_BODY_LOCATIONS]
Definition: object.h:223
#define SHIELD
Definition: define.h:145
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
START_TEST(test_randommaps)
#define ALTAR
Definition: define.h:130
#define FLAG_GENERATOR
Definition: define.h:544
int set_random_map_variable(RMParms *rp, const char *buf)
const char *const spell_mapping[]
#define FIREWALL
Definition: define.h:204
#define MAP_PLAYER_UNIQUE
Definition: map.h:117
int origin_y
Definition: random_map.h:73
living stats
Definition: object.h:219
struct archt * arch
Definition: object.h:263
#define MAP_WIDTH(m)
Definition: map.h:97
struct regiondef * region
Definition: random_map.h:80
void delete_map(mapstruct *m)
Definition: map.c:1745
void update_ob_speed(object *op)
Definition: object.c:1008
#define BOW
Definition: define.h:126
sstring add_string(const char *str)
Definition: shstr.c:116
#define MIN_ACTIVE_SPEED
Definition: define.h:1063
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
#define FLAG_MONSTER
Definition: define.h:541
struct obj * inv
Definition: object.h:148
#define HELMET
Definition: define.h:146
#define SPELLBOOK
Definition: define.h:266
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
#define ROD
Definition: define.h:115
void copy_object(object *op2, object *op)
Definition: object.c:758
int calc_item_power(const object *op, int flag)
Definition: item.c:264
void setup(void)
Definition: check_1727944.c:38
sint8 tail_x
Definition: object.h:327
Definition: map.h:346
int origin_x
Definition: random_map.h:74
sint16 level
Definition: object.h:202
object * arch_to_object(archetype *at)
Definition: arch.c:576
#define FLAG_CONTENT_ON_GEN
Definition: define.h:670
sint32 value
Definition: object.h:201
#define CONVERTER
Definition: define.h:285
archetype * get_archetype_struct(void)
Definition: arch.c:323
const char * name
Definition: object.h:322
#define SAVE_MODE_OVERLAY
Definition: map.h:143
uint8 type
Definition: object.h:189
sint8 gen_sp_armour
Definition: object.h:214