Crossfire Server, Trunk  1.75.0
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);
769  object_remove(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 {
848  FOR_MAP_PREPARE(map, x, y, tmp)
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) {
978  FOR_MAP_PREPARE(m, x+freearr_x[i], y+freearr_y[i], tmp) {
979  if (tmp->type == DOOR) {
980  object_remove(tmp);
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)
Gets the bottom object on a map.
Definition: map.h:170
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)
Find a random non-blocked spot in this room to drop a key.
Definition: treasure.cpp:635
global.h
random_map.h
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
MOVE_BLOCK_DEFAULT
#define MOVE_BLOCK_DEFAULT
The normal assumption is that objects are walking/flying.
Definition: define.h:409
layout
Definition: main.cpp:84
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
mapstruct::difficulty
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:333
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
retrofit_joined_wall
object * retrofit_joined_wall(mapstruct *the_map, int i, int j, int insert_flag, RMParms *RP)
this takes a map, and changes an existing wall to match what's blocked around it, counting only doors...
Definition: wall.cpp:314
free_spots_struct::room_free_spots_x
int * room_free_spots_x
Positions.
Definition: treasure.cpp:572
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:113
wall_blocked
int wall_blocked(mapstruct *m, int x, int y)
Returns true if square x,y has P_NO_PASS set, which is true for walls and doors but not monsters.
Definition: treasure.cpp:62
RICH
#define RICH
Definition: treasure.cpp:41
remove_monsters
void remove_monsters(int x, int y, mapstruct *map)
Remove living things on specified spot.
Definition: treasure.cpp:764
object::x
int16_t x
Definition: object.h:335
RMParms::Ysize
int Ysize
Definition: random_map.h:75
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
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)
object_find_first_free_spot(archetype, mapstruct, x, y) works like object_find_free_spot(),...
Definition: object.cpp:3599
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Search for the given treasurelist by name.
Definition: assets.cpp:248
find_monster_in_room
object * find_monster_in_room(mapstruct *map, int x, int y, RMParms *RP)
Find a monster in a room.
Definition: treasure.cpp:543
SPIRAL_LAYOUT
#define SPIRAL_LAYOUT
Definition: random_map.h:115
TREASURE
@ TREASURE
Definition: object.h:115
flags
static const flag_definition flags[]
Flag mapping.
Definition: gridarta-types-convert.cpp:101
find_style
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Loads and returns the map requested.
Definition: style.cpp:180
object_copy_with_inv
void object_copy_with_inv(const object *src_ob, object *dest_ob, bool update_speed)
Copy an object with an inventory, duplicate the inv too.
Definition: object.cpp:1208
RMParms::dungeon_level
int dungeon_level
Definition: random_map.h:84
find_doors_in_room
object ** find_doors_in_room(mapstruct *map, int x, int y, RMParms *RP)
Gets all doors in a room.
Definition: treasure.cpp:920
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2857
RMParms
Random map parameters.
Definition: random_map.h:14
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
DOORED
#define DOORED
Definition: treasure.cpp:38
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:422
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1560
HIDDEN
#define HIDDEN
Definition: treasure.cpp:36
free_spots_struct::number_of_free_spots_in_room
int number_of_free_spots_in_room
Number of positions.
Definition: treasure.cpp:574
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
SQUARE_SPIRAL_LAYOUT
#define SQUARE_SPIRAL_LAYOUT
Definition: random_map.h:118
PASS_DOORS
#define PASS_DOORS
Definition: treasure.cpp:47
NO_PASS_DOORS
#define NO_PASS_DOORS
Definition: treasure.cpp:46
treasurelist
treasurelist represents one logical group of items to be generated together.
Definition: treasure.h:85
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
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)
Returns the first door in this square, or NULL if there isn't a door.
Definition: treasure.cpp:846
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
object::face
const Face * face
Face with colors.
Definition: object.h:341
find_enclosed_spot
void find_enclosed_spot(mapstruct *map, int *cx, int *cy, RMParms *RP)
Searches the map for a spot with walls around it.
Definition: treasure.cpp:691
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
rproto.h
place_treasure
void place_treasure(mapstruct *map, char **layout, char *treasure_style, int treasureoptions, RMParms *RP)
Place treasures in the map.
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)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2100
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
place_chest
object * place_chest(int treasureoptions, int x, int y, mapstruct *map, int n_treasures, RMParms *RP)
Put a chest into the map, near x and y, with a chest from the styles/cheststyles map.
Definition: treasure.cpp:220
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1273
create_archetype
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
RANDOM
#define RANDOM()
Definition: define.h:638
TRAPPED
#define TRAPPED
Definition: treasure.cpp:39
free_spots_struct
Datastructure needed by find_spot_in_room() and find_spot_in_room_recursive()
Definition: treasure.cpp:571
lock_and_hide_doors
void lock_and_hide_doors(object **doorlist, mapstruct *map, int opts, RMParms *RP)
Locks and/or hides all the doors in doorlist, or does nothing if opts doesn't say to lock/hide doors.
Definition: treasure.cpp:1005
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
RMParms::difficulty
int difficulty
Definition: random_map.h:80
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
RMParms::cheststyle
char cheststyle[RM_SIZE]
Name of the chests style file, in /styles/cheststyles, can be an empty string in which case a random ...
Definition: random_map.h:53
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_.
Definition: map.cpp:300
find_monster_in_room_recursive
object * find_monster_in_room_recursive(char **layout, mapstruct *map, int x, int y, RMParms *RP)
A recursive routine which will return a monster, eventually, if there is one.
Definition: treasure.cpp:492
RMParms::total_map_hp
long unsigned int total_map_hp
Total hit points of the monsters in the map, used for treasure generation.
Definition: random_map.h:93
mapstruct
This is a game-map.
Definition: map.h:315
living::Cha
int8_t Cha
Definition: living.h:36
BC_RANDOM
#define BC_RANDOM(x)
Macro to get a strongly centered random distribution, from 0 to x, centered at x/2.
Definition: random_map.h:159
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:265
pick_random_object
object * pick_random_object(mapstruct *style)
Picks a random object from a style map.
Definition: style.cpp:289
surround_by_doors
static object ** surround_by_doors(mapstruct *map, char **layout, int x, int y, int opts)
Surrounds the point x,y by doors, so as to enclose something, like a chest.
Definition: treasure.cpp:798
KEYREQUIRED
#define KEYREQUIRED
Definition: treasure.cpp:37
RMParms::dungeon_name
char dungeon_name[RM_SIZE]
If not empty, will be used in the name of the random keys.
Definition: random_map.h:72
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)
The workhorse routine, which finds the doors in a room.
Definition: treasure.cpp:870
object::randomitems
struct treasurelist * randomitems
Items to be generated.
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)
Places keys in the map, preferably in something alive.
Definition: treasure.cpp:385
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1833
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Gets map flags.
Definition: map.h:157
DOOR
@ DOOR
Definition: object.h:131
RMParms::map_layout_style
int map_layout_style
Definition: random_map.h:91
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)
the workhorse routine, which finds the free spots in a room: a datastructure of free points is set up...
Definition: treasure.cpp:591
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
surround_flag3
int surround_flag3(mapstruct *map, int i, int j, RMParms *RP)
Check a map for blocked spots.
Definition: wall.cpp:114
remove_adjacent_doors
static void remove_adjacent_doors(object *door)
This removes any 'normal' doors around the specified door.
Definition: treasure.cpp:961
RMParms::Xsize
int Xsize
Definition: random_map.h:74
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
find_closest_monster
object * find_closest_monster(mapstruct *map, int x, int y, RMParms *RP)
finds the closest monster and returns him, regardless of doors or walls
Definition: treasure.cpp:335
free_spots_struct::room_free_spots_y
int * room_free_spots_y
Positions.
Definition: treasure.cpp:573
RMParms::symmetry_used
int symmetry_used
Definition: random_map.h:95