Crossfire Server, Trunk
treasure.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 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 
14 /* placing treasure in maps, where appropriate. */
15 
21 #include "global.h"
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "random_map.h"
27 #include "rproto.h"
28 
35 #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */
36 #define HIDDEN 2 /* doors to treasure are hidden. */
37 #define KEYREQUIRED 4 /* chest has a key, which is placed randomly in the map. */
38 #define DOORED 8 /* treasure has doors around it. */
39 #define TRAPPED 16 /* trap dropped in same location as chest. */
40 #define SPARSE 32 /* 1/2 as much treasure as default */
41 #define RICH 64 /* 2x as much treasure as default */
42 #define FILLED 128 /* Fill/tile the entire map with treasure */
43 #define LAST_OPTION 64 /* set this to the last real option, for random */
44 
46 #define NO_PASS_DOORS 0
47 #define PASS_DOORS 1
48 
49 static object **surround_by_doors(mapstruct *map, char **layout, int x, int y, int opts);
50 
62 int wall_blocked(mapstruct *m, int x, int y)
63 {
64  int r;
65 
66  if (OUT_OF_REAL_MAP(m, x, y)) {
67  return 1;
68  }
70  return r;
71 }
72 
92 void place_treasure(mapstruct *map, char **layout, char *treasure_style, int treasureoptions, RMParms *RP)
93 {
94  int num_treasures;
95 
96  /* bail out if treasure isn't wanted. */
97  if (treasure_style)
98  if (!strcmp(treasure_style, "none")) {
99  return;
100  }
101  if (treasureoptions <= 0) {
102  treasureoptions = RANDOM()%(2*LAST_OPTION);
103  }
104 
105  /* filter out the mutually exclusive options */
106  if ((treasureoptions&RICH) && (treasureoptions&SPARSE)) {
107  if (RANDOM()%2) {
108  treasureoptions -= 1;
109  } else {
110  treasureoptions -= 2;
111  }
112  }
113 
114  /* pick the number of treasures */
115  if (treasureoptions&SPARSE) {
116  num_treasures = BC_RANDOM(RP->total_map_hp/600+RP->difficulty/2+1);
117  } else if (treasureoptions&RICH) {
118  num_treasures = BC_RANDOM(RP->total_map_hp/150+2*RP->difficulty+1);
119  } else {
120  num_treasures = BC_RANDOM(RP->total_map_hp/300+RP->difficulty+1);
121  }
122 
123  if (num_treasures <= 0) {
124  return;
125  }
126 
127  /* all the treasure at one spot in the map. */
128  if (treasureoptions&CONCENTRATED) {
129  /* map_layout_style global, and is previously set */
130  switch (RP->map_layout_style) {
131  case ONION_LAYOUT:
132  case SPIRAL_LAYOUT:
133  case SQUARE_SPIRAL_LAYOUT: {
134  int i, j;
135 
136  /* search the onion for C's or '>', and put treasure there. */
137  for (i = 0; i < RP->Xsize; i++) {
138  for (j = 0; j < RP->Ysize; j++) {
139  if (layout[i][j] == 'C' || layout[i][j] == '>') {
140  int tdiv = RP->symmetry_used;
141  object **doorlist;
142  object *chest;
143 
144  if (tdiv == 3) {
145  tdiv = 2; /* this symmetry uses a divisor of 2*/
146  }
147  /* don't put a chest on an exit. */
148  chest = place_chest(treasureoptions, i, j, map, num_treasures/tdiv, RP);
149  if (!chest) {
150  continue; /* if no chest was placed NEXT */
151  }
152  if (treasureoptions&(DOORED|HIDDEN)) {
153  doorlist = find_doors_in_room(map, i, j, RP);
154  lock_and_hide_doors(doorlist, map, treasureoptions, RP);
155  free(doorlist);
156  }
157  }
158  }
159  }
160  break;
161  }
162  default: {
163  int i, j, tries;
164  object *chest;
165  object **doorlist;
166 
167  i = j = -1;
168  tries = 0;
169  while (i == -1 && tries < 100) {
170  i = RANDOM()%(RP->Xsize-2)+1;
171  j = RANDOM()%(RP->Ysize-2)+1;
172  find_enclosed_spot(map, &i, &j, RP);
173  if (wall_blocked(map, i, j)) {
174  i = -1;
175  }
176  tries++;
177  }
178  chest = place_chest(treasureoptions, i, j, map, num_treasures, RP);
179  if (!chest) {
180  return;
181  }
182  i = chest->x;
183  j = chest->y;
184  if (treasureoptions&(DOORED|HIDDEN)) {
185  doorlist = surround_by_doors(map, layout, i, j, treasureoptions);
186  lock_and_hide_doors(doorlist, map, treasureoptions, RP);
187  free(doorlist);
188  }
189  }
190  }
191  } else { /* DIFFUSE treasure layout */
192  int ti, i, j;
193 
194  for (ti = 0; ti < num_treasures; ti++) {
195  i = RANDOM()%(RP->Xsize-2)+1;
196  j = RANDOM()%(RP->Ysize-2)+1;
197  place_chest(treasureoptions, i, j, map, 1, RP);
198  }
199  }
200 }
201 
220 object *place_chest(int treasureoptions, int x, int y, mapstruct *map, int n_treasures, RMParms *RP)
221 {
222  object *the_chest = NULL;
223  int i, xl, yl;
224  treasurelist *tlist;
225 
226  // Since we scale the stats of the mimic based on the level of the dungeon,
227  // we can have no floor to generation difficulty.
228  // It is a slim chance at any rate, so it shouldn't be a problem in any case.
229  if ((uint32_t)(RANDOM() % 1000000) < (uint32_t)(map->difficulty*map->difficulty*map->difficulty))
230  {
231  the_chest = create_archetype("mimic");
232  // Set the level for the mimic so that it can be given apporpriate stats.
233  if (the_chest)
234  the_chest->level = map->difficulty;
235  }
236  else
237  {
238  mapstruct *chests_map = find_style("/styles/cheststyles", RP->cheststyle, map->difficulty);
239  if (chests_map) {
240  object *item = pick_random_object(chests_map);
241  if (item) {
242  the_chest = object_new();
243  object_copy_with_inv(item, the_chest, true);
244  }
245  }
246  }
247  if (the_chest == NULL) {
248  return NULL;
249  }
250 
251  /* first, find a place to put the chest. */
252  i = object_find_first_free_spot(the_chest, map, x, y);
253  if (i == -1) {
254  object_free_drop_inventory(the_chest);
255  return NULL;
256  }
257  xl = x+freearr_x[i];
258  yl = y+freearr_y[i];
259 
260  /* if the placement is blocked, return a fail. */
261  if (wall_blocked(map, xl, yl)) {
262  object_free_drop_inventory(the_chest);
263  return NULL;
264  }
265 
266  // If normal, then do the old behavior.
267  if (the_chest->type == TREASURE)
268  {
269  tlist = find_treasurelist("chest");
270  the_chest->randomitems = tlist;
271  the_chest->stats.hp = n_treasures;
272  }
273  // Otherwise, do the mimic treasurelist and don't change hp
274  else if (the_chest->type == MIMIC)
275  {
276  tlist = find_treasurelist("mimic");
277  the_chest->randomitems = tlist;
278  // TODO: Make mimics on higher levels have more treasure
279  }
280  /* stick a trap in the chest if required */
281  if (treasureoptions&TRAPPED) {
282  mapstruct *trap_map = find_style("/styles/trapstyles", "traps", -1);
283  object *the_trap;
284 
285  if (trap_map) {
286  the_trap = pick_random_object(trap_map);
287  if (the_trap) {
288  object *new_trap;
289 
290  new_trap = object_new();
291  object_copy_with_inv(the_trap, new_trap, true);
292  new_trap->stats.Cha = 10+RP->difficulty;
293  new_trap->level = BC_RANDOM((3*RP->difficulty)/2);
294  if (new_trap->level == 0) {
295  new_trap->level = 1;
296  }
297  new_trap->x = x;
298  new_trap->y = y;
299  object_insert_in_ob(new_trap, the_chest);
300  }
301  }
302  }
303 
304  /* set the chest lock code, and call the keyplacer routine with
305  the lockcode. It's not worth bothering to lock the chest if
306  there's only 1 treasure....*/
307  if ((treasureoptions&KEYREQUIRED) && n_treasures > 1) {
308  char keybuf[256];
309 
310  snprintf(keybuf, sizeof(keybuf), "%d", (int)RANDOM());
311  if (keyplace(map, x, y, keybuf, PASS_DOORS, 1, RP)) {
312  the_chest->slaying = add_string(keybuf);
313  }
314  }
315 
316  /* actually place the chest. */
317  object_insert_in_map_at(the_chest, map, NULL, 0, xl, yl);
318  return the_chest;
319 }
320 
335 object *find_closest_monster(mapstruct *map, int x, int y, RMParms *RP)
336 {
337  int i;
338 
339  for (i = 0; i < SIZEOFFREE; i++) {
340  int lx, ly;
341 
342  lx = x+freearr_x[i];
343  ly = y+freearr_y[i];
344  /* boundscheck */
345  if (lx >= 0 && ly >= 0 && lx < RP->Xsize && ly < RP->Ysize)
346  /* don't bother searching this square unless the map says life exists.*/
347  if (GET_MAP_FLAGS(map, lx, ly)&P_IS_ALIVE) {
348  FOR_MAP_PREPARE(map, lx, ly, the_monster)
349  if (QUERY_FLAG(the_monster, FLAG_MONSTER)) {
350  return the_monster;
351  }
352  FOR_MAP_FINISH();
353  }
354  }
355  return NULL;
356 }
357 
385 int keyplace(mapstruct *map, int x, int y, char *keycode, int door_flag, int n_keys, RMParms *RP)
386 {
387  int i, j;
388  int kx, ky;
389  object *the_keymaster; /* the monster that gets the key. */
390  object *the_key;
391  char keybuf[256];
392  const char *keys[] = { "key2", "blue_key", "brown_key", "darkgray_key", "darkgreen_key", "gray_key", "green_key", "magenta_key", "red_key", "white_key" };
393 
394  /* get a key and set its keycode */
395  the_key = create_archetype(keys[RANDOM() % (sizeof(keys)/sizeof(*keys))]);
396  the_key->slaying = add_string(keycode);
397  free_string(the_key->name);
398  snprintf(keybuf, 256, "key from level %d of %s", RP->dungeon_level-1, RP->dungeon_name[0] != '\0' ? RP->dungeon_name : "a random map");
399  the_key->name = add_string(keybuf);
400 
401  if (door_flag == PASS_DOORS) {
402  int tries = 0;
403 
404  the_keymaster = NULL;
405  while (tries < 15 && the_keymaster == NULL) {
406  i = (RANDOM()%(RP->Xsize-2))+1;
407  j = (RANDOM()%(RP->Ysize-2))+1;
408  tries++;
409  the_keymaster = find_closest_monster(map, i, j, RP);
410  }
411  /* if we don't find a good keymaster, drop the key on the ground. */
412  if (the_keymaster == NULL) {
413  int freeindex;
414 
415  freeindex = -1;
416  for (tries = 0; tries < 15 && freeindex == -1; tries++) {
417  kx = (RANDOM()%(RP->Xsize-2))+1;
418  ky = (RANDOM()%(RP->Ysize-2))+1;
419  freeindex = object_find_first_free_spot(the_key, map, kx, ky);
420  }
421  if (freeindex != -1) {
422  kx += freearr_x[freeindex];
423  ky += freearr_y[freeindex];
424  }
425  }
426  } else { /* NO_PASS_DOORS --we have to work harder.*/
427  /* don't try to keyplace if we're sitting on a blocked square and
428  * NO_PASS_DOORS is set.
429  */
430  if (n_keys == 1) {
431  if (wall_blocked(map, x, y)) {
432  return 0;
433  }
434  the_keymaster = find_monster_in_room(map, x, y, RP);
435  if (the_keymaster == NULL) /* if fail, find a spot to drop the key. */
436  if (!find_spot_in_room(map, x, y, &kx, &ky, RP)) {
437  return 0;
438  }
439  } else {
440  /* It can happen that spots around that point are all blocked, so
441  * try to look farther away if needed
442  */
443  int sum = 0; /* count how many keys we actually place */
444  int distance = 1;
445 
446  while (distance < 5) {
447  /* I'm lazy, so just try to place in all 4 directions. */
448  sum += keyplace(map, x+distance, y, keycode, NO_PASS_DOORS, 1, RP);
449  sum += keyplace(map, x, y+distance, keycode, NO_PASS_DOORS, 1, RP);
450  sum += keyplace(map, x-distance, y, keycode, NO_PASS_DOORS, 1, RP);
451  sum += keyplace(map, x, y-distance, keycode, NO_PASS_DOORS, 1, RP);
452  if (sum < 2) { /* we might have made a disconnected map-place more keys. */
453  /* diagonally this time. */
454  keyplace(map, x+distance, y+distance, keycode, NO_PASS_DOORS, 1, RP);
455  keyplace(map, x+distance, y-distance, keycode, NO_PASS_DOORS, 1, RP);
456  keyplace(map, x-distance, y+distance, keycode, NO_PASS_DOORS, 1, RP);
457  keyplace(map, x-distance, y-distance, keycode, NO_PASS_DOORS, 1, RP);
458  }
459  if (sum > 0) {
460  return 1;
461  }
462  distance++;
463  }
464  return 0;
465  }
466  }
467 
468  if (the_keymaster == NULL) {
469  object_insert_in_map_at(the_key, map, NULL, 0, kx, ky);
470  return 1;
471  }
472 
473  object_insert_in_ob(the_key, the_keymaster);
474  return 1;
475 }
476 
492 object *find_monster_in_room_recursive(char **layout, mapstruct *map, int x, int y, RMParms *RP)
493 {
494  int i, j;
495 
496  /* bounds check x and y */
497  if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize)) {
498  return NULL;
499  }
500 
501  /* if the square is blocked or searched already, leave */
502  if (layout[x][y] != 0) {
503  return NULL;
504  }
505 
506  /* check the current square for a monster. If there is one,
507  set theMonsterToFind and return it. */
508  layout[x][y] = 1;
509  if (GET_MAP_FLAGS(map, x, y)&P_IS_ALIVE) {
510  FOR_MAP_PREPARE(map, x, y, the_monster)
511  if (QUERY_FLAG(the_monster, FLAG_ALIVE)) {
512  return HEAD(the_monster);
513  }
514  FOR_MAP_FINISH();
515  }
516 
517  /* now search all the 8 squares around recursively for a monster, in random order */
518  for (i = RANDOM()%8, j = 0; j < 8; i++, j++) {
519  object *the_monster;
520 
521  the_monster = find_monster_in_room_recursive(layout, map, x+freearr_x[i%8+1], y+freearr_y[i%8+1], RP);
522  if (the_monster != NULL) {
523  return the_monster;
524  }
525  }
526  return NULL;
527 }
528 
543 object *find_monster_in_room(mapstruct *map, int x, int y, RMParms *RP)
544 {
545  char **layout2;
546  int i, j;
547  object *theMonsterToFind;
548 
549  layout2 = (char **)calloc(sizeof(char *), RP->Xsize);
550  /* allocate and copy the layout, converting C to 0. */
551  for (i = 0; i < RP->Xsize; i++) {
552  layout2[i] = (char *)calloc(sizeof(char), RP->Ysize);
553  for (j = 0; j < RP->Ysize; j++) {
554  if (wall_blocked(map, i, j)) {
555  layout2[i][j] = '#';
556  }
557  }
558  }
559  theMonsterToFind = find_monster_in_room_recursive(layout2, map, x, y, RP);
560 
561  /* deallocate the temp. layout */
562  for (i = 0; i < RP->Xsize; i++) {
563  free(layout2[i]);
564  }
565  free(layout2);
566 
567  return theMonsterToFind;
568 }
569 
575 };
576 
591 static void find_spot_in_room_recursive(char **layout, int x, int y, RMParms *RP, free_spots_struct *spots)
592 {
593  int i, j;
594 
595  /* bounds check x and y */
596  if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize)) {
597  return;
598  }
599 
600  /* if the square is blocked or searched already, leave */
601  if (layout[x][y] != 0) {
602  return;
603  }
604 
605  /* set the current square as checked, and add it to the list.
606  check off this point */
607  layout[x][y] = 1;
611  /* now search all the 8 squares around recursively for free spots, in random order */
612  for (i = RANDOM()%8, j = 0; j < 8; i++, j++) {
613  find_spot_in_room_recursive(layout, x+freearr_x[i%8+1], y+freearr_y[i%8+1], RP, spots);
614  }
615 }
616 
635 int find_spot_in_room(mapstruct *map, int x, int y, int *kx, int *ky, RMParms *RP)
636 {
637  char **layout2;
638  int i, j;
639  free_spots_struct spots;
640 
642  spots.room_free_spots_x = (int *)calloc(sizeof(int), RP->Xsize*RP->Ysize);
643  spots.room_free_spots_y = (int *)calloc(sizeof(int), RP->Xsize*RP->Ysize);
644 
645  layout2 = (char **)calloc(sizeof(char *), RP->Xsize);
646  /* allocate and copy the layout, converting C to 0. */
647  for (i = 0; i < RP->Xsize; i++) {
648  layout2[i] = (char *)calloc(sizeof(char), RP->Ysize);
649  for (j = 0; j < RP->Ysize; j++) {
650  if (wall_blocked(map, i, j)) {
651  layout2[i][j] = '#';
652  }
653  }
654  }
655 
656  /* setup num_free_spots and room_free_spots */
657  find_spot_in_room_recursive(layout2, x, y, RP, &spots);
658 
659  if (spots.number_of_free_spots_in_room > 0) {
661  *kx = spots.room_free_spots_x[i];
662  *ky = spots.room_free_spots_y[i];
663  }
664 
665  /* deallocate the temp. layout */
666  for (i = 0; i < RP->Xsize; i++) {
667  free(layout2[i]);
668  }
669  free(layout2);
670  free(spots.room_free_spots_x);
671  free(spots.room_free_spots_y);
672 
673  if (spots.number_of_free_spots_in_room > 0) {
674  return 1;
675  }
676  return 0;
677 }
678 
691 void find_enclosed_spot(mapstruct *map, int *cx, int *cy, RMParms *RP)
692 {
693  int x, y;
694  int i;
695 
696  x = *cx;
697  y = *cy;
698 
699  for (i = 0; i <= SIZEOFFREE1; i++) {
700  int lx, ly, sindex;
701  lx = x+freearr_x[i];
702  ly = y+freearr_y[i];
703  sindex = surround_flag3(map, lx, ly, RP);
704  /* if it's blocked on 3 sides, it's enclosed */
705  if (sindex == 7 || sindex == 11 || sindex == 13 || sindex == 14) {
706  *cx = lx;
707  *cy = ly;
708  return;
709  }
710  }
711 
712  /* OK, if we got here, we're obviously someplace where there's no enclosed
713  spots--try to find someplace which is 2x enclosed. */
714  for (i = 0; i <= SIZEOFFREE1; i++) {
715  int lx, ly, sindex;
716 
717  lx = x+freearr_x[i];
718  ly = y+freearr_y[i];
719  sindex = surround_flag3(map, lx, ly, RP);
720  /* if it's blocked on 3 sides, it's enclosed */
721  if (sindex == 3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex == 10 || sindex == 12) {
722  *cx = lx;
723  *cy = ly;
724  return;
725  }
726  }
727 
728  /* settle for one surround point */
729  for (i = 0; i <= SIZEOFFREE1; i++) {
730  int lx, ly, sindex;
731 
732  lx = x+freearr_x[i];
733  ly = y+freearr_y[i];
734  sindex = surround_flag3(map, lx, ly, RP);
735  /* if it's blocked on 3 sides, it's enclosed */
736  if (sindex) {
737  *cx = lx;
738  *cy = ly;
739  return;
740  }
741  }
742 
743  /* give up and return the closest free spot. */
744  archetype *arch = find_archetype("chest");
745  if (arch != NULL) {
746  i = object_find_first_free_spot(&arch->clone, map, x, y);
747  if (i != -1 && i <= SIZEOFFREE1) {
748  *cx = x+freearr_x[i];
749  *cy = y+freearr_y[i];
750  return;
751  }
752  }
753  /* indicate failure */
754  *cx = *cy = -1;
755 }
756 
764 void remove_monsters(int x, int y, mapstruct *map)
765 {
766  FOR_MAP_PREPARE(map, x, y, tmp) {
767  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
768  tmp = HEAD(tmp);
771  tmp = GET_MAP_OB(map, x, y);
772  if (tmp == NULL) {
773  break;
774  }
775  }
776  }
777  FOR_MAP_FINISH();
778 }
779 
798 static object **surround_by_doors(mapstruct *map, char **layout, int x, int y, int opts)
799 {
800  int i;
801  const char *doors[2];
802  object **doorlist;
803  int ndoors_made = 0;
804  doorlist = (object **)calloc(9, sizeof(object *)); /* 9 doors so we can hold termination null */
805 
806  /* this is a list we pick from, for horizontal and vertical doors */
807  if (opts&DOORED) {
808  doors[0] = "locked_door2";
809  doors[1] = "locked_door1";
810  } else {
811  doors[0] = "door_1";
812  doors[1] = "door_2";
813  }
814 
815  /* place doors in all the 8 adjacent unblocked squares. */
816  for (i = 1; i < 9; i++) {
817  int x1 = x+freearr_x[i], y1 = y+freearr_y[i];
818 
819  if (!wall_blocked(map, x1, y1)
820  || layout[x1][y1] == '>') {/* place a door */
821  object *new_door = create_archetype((freearr_x[i] == 0) ? doors[1] : doors[0]);
822  int16_t nx, ny;
823 
824  nx = x+freearr_x[i];
825  ny = y+freearr_y[i];
826  remove_monsters(nx, ny, map);
827  object_insert_in_map_at(new_door, map, NULL, 0, nx, ny);
828  doorlist[ndoors_made] = new_door;
829  ndoors_made++;
830  }
831  }
832  return doorlist;
833 }
834 
846 static object *door_in_square(mapstruct *map, int x, int y)
847 {
849  if (tmp->type == DOOR || tmp->type == LOCKED_DOOR) {
850  return tmp;
851  }
852  FOR_MAP_FINISH();
853  return NULL;
854 }
855 
870 void find_doors_in_room_recursive(char **layout, mapstruct *map, int x, int y, object **doorlist, int *ndoors, RMParms *RP)
871 {
872  int i, j;
873  object *door;
874 
875  /* bounds check x and y */
876  if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize)) {
877  return;
878  }
879 
880  /* if the square is blocked or searched already, leave */
881  if (layout[x][y] == 1) {
882  return;
883  }
884 
885  /* check off this point */
886  if (layout[x][y] == '#') { /* there could be a door here */
887  layout[x][y] = 1;
888  door = door_in_square(map, x, y);
889  if (door != NULL) {
890  doorlist[*ndoors] = door;
891  if (*ndoors > 254) { /* eek! out of memory */
892  LOG(llevError, "find_doors_in_room_recursive:Too many doors for memory allocated!\n");
893  return;
894  }
895  *ndoors = *ndoors+1;
896  }
897  } else {
898  layout[x][y] = 1;
899  /* now search all the 8 squares around recursively for free spots, in random order */
900  for (i = RANDOM()%8, j = 0; j < 8; i++, j++) {
901  find_doors_in_room_recursive(layout, map, x+freearr_x[i%8+1], y+freearr_y[i%8+1], doorlist, ndoors, RP);
902  }
903  }
904 }
905 
920 object **find_doors_in_room(mapstruct *map, int x, int y, RMParms *RP)
921 {
922  char **layout2;
923  object **doorlist;
924  int i, j;
925  int ndoors = 0;
926 
927  doorlist = (object **)calloc(sizeof(*doorlist), 256);
928 
929 
930  layout2 = (char **)calloc(sizeof(char *), RP->Xsize);
931  /* allocate and copy the layout, converting C to 0. */
932  for (i = 0; i < RP->Xsize; i++) {
933  layout2[i] = (char *)calloc(sizeof(char), RP->Ysize);
934  for (j = 0; j < RP->Ysize; j++) {
935  if (wall_blocked(map, i, j)) {
936  layout2[i][j] = '#';
937  }
938  }
939  }
940 
941  /* setup num_free_spots and room_free_spots */
942  find_doors_in_room_recursive(layout2, map, x, y, doorlist, &ndoors, RP);
943 
944  /* deallocate the temp. layout */
945  for (i = 0; i < RP->Xsize; i++) {
946  free(layout2[i]);
947  }
948  free(layout2);
949  return doorlist;
950 }
951 
961 static void remove_adjacent_doors(object *door)
962 {
963  mapstruct *m = door->map;
964  int x = door->x;
965  int y = door->y;
966  int i, flags;
967 
968  for (i = 1; i <= 8; i++) {
969  flags = get_map_flags(m, NULL, x+freearr_x[i], y+freearr_y[i], NULL, NULL);
970  if (flags&P_OUT_OF_MAP) {
971  continue;
972  }
973 
974  /* Old style doors are living objects. So if P_IS_ALIVE is not
975  * set, can not be a door on this space.
976  */
977  if (flags&P_IS_ALIVE) {
979  if (tmp->type == DOOR) {
982  break;
983  }
984  }
985  FOR_MAP_FINISH();
986  }
987  }
988 }
989 
1005 void lock_and_hide_doors(object **doorlist, mapstruct *map, int opts, RMParms *RP)
1006 {
1007  object *door;
1008  int i;
1009 
1010  /* lock the doors and hide the keys. */
1011  if (opts&DOORED) {
1012  for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++) {
1013  object *new_door = create_archetype("locked_door1");
1014  char keybuf[256];
1015 
1016  door = doorlist[i];
1017  new_door->face = door->face;
1018  object_remove(door);
1020  doorlist[i] = new_door;
1021  object_insert_in_map_at(new_door, map, NULL, 0, door->x, door->y);
1022 
1023  snprintf(keybuf, 256, "%d", (int)RANDOM());
1024  if (keyplace(map, new_door->x, new_door->y, keybuf, NO_PASS_DOORS, 2, RP)) {
1025  new_door->slaying = add_string(keybuf);
1026  }
1027  }
1028  for (i = 0; doorlist[i] != NULL; i++) {
1029  remove_adjacent_doors(doorlist[i]);
1030  }
1031  }
1032 
1033  /* change the faces of the doors and surrounding walls to hide them. */
1034  if (opts&HIDDEN) {
1035  for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++) {
1036  object *wallface;
1037 
1038  door = doorlist[i];
1039  wallface = retrofit_joined_wall(map, door->x, door->y, 1, RP);
1040  if (wallface != NULL) {
1041  retrofit_joined_wall(map, door->x-1, door->y, 0, RP);
1042  retrofit_joined_wall(map, door->x+1, door->y, 0, RP);
1043  retrofit_joined_wall(map, door->x, door->y-1, 0, RP);
1044  retrofit_joined_wall(map, door->x, door->y+1, 0, RP);
1045  door->face = wallface->face;
1046  if (!QUERY_FLAG(wallface, FLAG_REMOVED)) {
1047  object_remove(wallface);
1048  }
1049  object_free_drop_inventory(wallface);
1050  }
1051  }
1052  }
1053 }
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:171
MIMIC
@ MIMIC
Definition: object.h:254
find_spot_in_room
int find_spot_in_room(mapstruct *map, int x, int y, int *kx, int *ky, RMParms *RP)
Definition: treasure.cpp:635
global.h
random_map.h
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
MOVE_BLOCK_DEFAULT
#define MOVE_BLOCK_DEFAULT
Definition: define.h:409
layout
Definition: main.cpp:84
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
retrofit_joined_wall
object * retrofit_joined_wall(mapstruct *the_map, int i, int j, int insert_flag, RMParms *RP)
Definition: wall.cpp:314
free_spots_struct::room_free_spots_x
int * room_free_spots_x
Definition: treasure.cpp:572
diamondslots.x
x
Definition: diamondslots.py:15
SIZEOFFREE1
#define SIZEOFFREE1
Definition: define.h:153
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
ONION_LAYOUT
#define ONION_LAYOUT
Definition: random_map.h:112
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
wall_blocked
int wall_blocked(mapstruct *m, int x, int y)
Definition: treasure.cpp:62
RICH
#define RICH
Definition: treasure.cpp:41
remove_monsters
void remove_monsters(int x, int y, mapstruct *map)
Definition: treasure.cpp:764
object::x
int16_t x
Definition: object.h:335
object::map
struct mapstruct * map
Definition: object.h:305
SPARSE
#define SPARSE
Definition: treasure.cpp:40
object_find_first_free_spot
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.cpp:3590
find_monster_in_room
object * find_monster_in_room(mapstruct *map, int x, int y, RMParms *RP)
Definition: treasure.cpp:543
SPIRAL_LAYOUT
#define SPIRAL_LAYOUT
Definition: random_map.h:114
TREASURE
@ TREASURE
Definition: object.h:115
hall_of_fame.keys
keys
Definition: hall_of_fame.py:43
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.cpp:101
Ice.tmp
int tmp
Definition: Ice.py:207
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Definition: assets.cpp:249
find_style
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.cpp:180
RMParms::map_layout_style
int map_layout_style
Definition: random_map.h:91
object_copy_with_inv
void object_copy_with_inv(const object *src_ob, object *dest_ob, bool update_speed)
Definition: object.cpp:1208
find_doors_in_room
object ** find_doors_in_room(mapstruct *map, int x, int y, RMParms *RP)
Definition: treasure.cpp:920
RMParms::Ysize
int Ysize
Definition: random_map.h:75
RMParms::difficulty
int difficulty
Definition: random_map.h:80
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:236
object::level
int16_t level
Definition: object.h:361
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2848
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
DOORED
#define DOORED
Definition: treasure.cpp:38
RMParms::dungeon_name
char dungeon_name[RM_SIZE]
Definition: random_map.h:72
object::y
int16_t y
Definition: object.h:335
RMParms::Xsize
int Xsize
Definition: random_map.h:74
m
static event_registration m
Definition: citylife.cpp:425
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
HIDDEN
#define HIDDEN
Definition: treasure.cpp:36
disinfect.map
map
Definition: disinfect.py:4
free_spots_struct::number_of_free_spots_in_room
int number_of_free_spots_in_room
Definition: treasure.cpp:574
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.cpp:305
SQUARE_SPIRAL_LAYOUT
#define SQUARE_SPIRAL_LAYOUT
Definition: random_map.h:117
PASS_DOORS
#define PASS_DOORS
Definition: treasure.cpp:47
NO_PASS_DOORS
#define NO_PASS_DOORS
Definition: treasure.cpp:46
RMParms
Definition: random_map.h:14
treasurelist
Definition: treasure.h:85
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
HEAD
#define HEAD(op)
Definition: object.h:598
doors
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be and may attack the nearest of your enemies Others can be in that they follow you around and help you in your quest to kill enemies and find treasure SPECIAL ITEMS There are many special items which can be found in of these the most important may be the signs all a player must do is apply the handle In the case of the player must move items over the button to hold it down Some of the larger buttons may need very large items to be moved onto before they can be activated Gates and locked doors
Definition: survival-guide.txt:69
door_in_square
static object * door_in_square(mapstruct *map, int x, int y)
Definition: treasure.cpp:846
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
object::face
const Face * face
Definition: object.h:341
find_enclosed_spot
void find_enclosed_spot(mapstruct *map, int *cx, int *cy, RMParms *RP)
Definition: treasure.cpp:691
object::type
uint8_t type
Definition: object.h:348
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:191
archetype
Definition: object.h:474
rproto.h
place_treasure
void place_treasure(mapstruct *map, char **layout, char *treasure_style, int treasureoptions, RMParms *RP)
Definition: treasure.cpp:92
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2095
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
place_chest
object * place_chest(int treasureoptions, int x, int y, mapstruct *map, int n_treasures, RMParms *RP)
Definition: treasure.cpp:220
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:248
object_new
object * object_new(void)
Definition: object.cpp:1268
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
RANDOM
#define RANDOM()
Definition: define.h:644
TRAPPED
#define TRAPPED
Definition: treasure.cpp:39
RMParms::symmetry_used
int symmetry_used
Definition: random_map.h:95
free_spots_struct
Definition: treasure.cpp:571
lock_and_hide_doors
void lock_and_hide_doors(object **doorlist, mapstruct *map, int opts, RMParms *RP)
Definition: treasure.cpp:1005
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
RMParms::cheststyle
char cheststyle[RM_SIZE]
Definition: random_map.h:53
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:216
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
object::slaying
sstring slaying
Definition: object.h:327
object::name
sstring name
Definition: object.h:319
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.cpp:299
item
Definition: item.py:1
find_monster_in_room_recursive
object * find_monster_in_room_recursive(char **layout, mapstruct *map, int x, int y, RMParms *RP)
Definition: treasure.cpp:492
mapstruct
Definition: map.h:314
living::Cha
int8_t Cha
Definition: living.h:36
BC_RANDOM
#define BC_RANDOM(x)
Definition: random_map.h:158
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
RMParms::total_map_hp
long unsigned int total_map_hp
Definition: random_map.h:93
pick_random_object
object * pick_random_object(mapstruct *style)
Definition: style.cpp:289
surround_by_doors
static object ** surround_by_doors(mapstruct *map, char **layout, int x, int y, int opts)
Definition: treasure.cpp:798
KEYREQUIRED
#define KEYREQUIRED
Definition: treasure.cpp:37
diamondslots.y
y
Definition: diamondslots.py:16
RMParms::dungeon_level
int dungeon_level
Definition: random_map.h:84
guild_entry.x1
int x1
Definition: guild_entry.py:33
find_doors_in_room_recursive
void find_doors_in_room_recursive(char **layout, mapstruct *map, int x, int y, object **doorlist, int *ndoors, RMParms *RP)
Definition: treasure.cpp:870
object::randomitems
struct treasurelist * randomitems
Definition: object.h:395
LAST_OPTION
#define LAST_OPTION
Definition: treasure.cpp:43
keyplace
int keyplace(mapstruct *map, int x, int y, char *keycode, int door_flag, int n_keys, RMParms *RP)
Definition: treasure.cpp:385
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Definition: map.h:158
DOOR
@ DOOR
Definition: object.h:131
CONCENTRATED
#define CONCENTRATED
Definition: treasure.cpp:35
find_spot_in_room_recursive
static void find_spot_in_room_recursive(char **layout, int x, int y, RMParms *RP, free_spots_struct *spots)
Definition: treasure.cpp:591
object::stats
living stats
Definition: object.h:378
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
surround_flag3
int surround_flag3(mapstruct *map, int i, int j, RMParms *RP)
Definition: wall.cpp:114
remove_adjacent_doors
static void remove_adjacent_doors(object *door)
Definition: treasure.cpp:961
guild_entry.y1
int y1
Definition: guild_entry.py:34
living::hp
int16_t hp
Definition: living.h:40
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
find_closest_monster
object * find_closest_monster(mapstruct *map, int x, int y, RMParms *RP)
Definition: treasure.cpp:335
free_spots_struct::room_free_spots_y
int * room_free_spots_y
Definition: treasure.cpp:573