ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.30
Committed: Sun Jul 1 05:00:19 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.29: +14 -15 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.30 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3     *
4     * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7     *
8     * Crossfire TRT is free software: you can redistribute it and/or modify
9 root 1.19 * it under the terms of the GNU General Public License as published by
10 root 1.30 * the Free Software Foundation, either version 3 of the License, or
11 root 1.19 * (at your option) any later version.
12 root 1.30 *
13 root 1.19 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 root 1.30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 root 1.19 * GNU General Public License for more details.
17 root 1.30 *
18 root 1.19 * You should have received a copy of the GNU General Public License
19 root 1.30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20     *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 root 1.19 */
23 elmex 1.1
24     /* placing treasure in maps, where appropriate. */
25    
26     #include <global.h>
27     #include <random_map.h>
28     #include <rproto.h>
29    
30     /* some defines for various options which can be set. */
31    
32 root 1.4 #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */
33     #define HIDDEN 2 /* doors to treasure are hidden. */
34     #define KEYREQUIRED 4 /* chest has a key, which is placed randomly in the map. */
35     #define DOORED 8 /* treasure has doors around it. */
36     #define TRAPPED 16 /* trap dropped in same location as chest. */
37     #define SPARSE 32 /* 1/2 as much treasure as default */
38     #define RICH 64 /* 2x as much treasure as default */
39     #define FILLED 128 /* Fill/tile the entire map with treasure */
40     #define LAST_OPTION 64 /* set this to the last real option, for random */
41 elmex 1.1
42     #define NO_PASS_DOORS 0
43     #define PASS_DOORS 1
44    
45 root 1.24 /* a macro to get a strongly centered random distribution,
46     from 0 to x, centered at x/2 */
47     static int
48     bc_random (int x)
49     {
50     return (rndm (x) + rndm (x) + rndm (x)) / 3;
51     }
52 elmex 1.1
53     /* returns true if square x,y has P_NO_PASS set, which is true for walls
54     * and doors but not monsters.
55     * This function is not map tile aware.
56     */
57 root 1.4 int
58 root 1.7 wall_blocked (maptile *m, int x, int y)
59 root 1.4 {
60     if (OUT_OF_REAL_MAP (m, x, y))
61     return 1;
62 root 1.19
63 elmex 1.27 m->at (x, y).update ();
64     return GET_MAP_MOVE_BLOCK (m, x, y) & MOVE_WALK;
65 elmex 1.1 }
66    
67     /* place treasures in the map, given the
68     map, (required)
69     layout, (required)
70     treasure style (may be empty or NULL, or "none" to cause no treasure.)
71     treasureoptions (may be 0 for random choices or positive)
72     */
73 root 1.4 void
74 root 1.12 place_treasure (maptile *map, char **layout, char *treasure_style, int treasureoptions, random_map_params *RP)
75 root 1.4 {
76 root 1.13 char styledirname[1024];
77     char stylefilepath[1024];
78 root 1.7 maptile *style_map = 0;
79 elmex 1.1 int num_treasures;
80    
81     /* bail out if treasure isn't wanted. */
82 root 1.4 if (treasure_style)
83     if (!strcmp (treasure_style, "none"))
84     return;
85 root 1.22
86 root 1.4 if (treasureoptions <= 0)
87 root 1.24 treasureoptions = rndm (2 * LAST_OPTION);
88 elmex 1.1
89     /* filter out the mutually exclusive options */
90 root 1.4 if ((treasureoptions & RICH) && (treasureoptions & SPARSE))
91     {
92 root 1.21 if (rndm (2))
93 root 1.4 treasureoptions -= 1;
94     else
95     treasureoptions -= 2;
96     }
97 elmex 1.1
98     /* pick the number of treasures */
99 root 1.4 if (treasureoptions & SPARSE)
100 root 1.24 num_treasures = bc_random (RP->total_map_hp / 600 + RP->difficulty / 2 + 1);
101 root 1.4 else if (treasureoptions & RICH)
102 root 1.24 num_treasures = bc_random (RP->total_map_hp / 150 + 2 * RP->difficulty + 1);
103 root 1.4 else
104 root 1.24 num_treasures = bc_random (RP->total_map_hp / 300 + RP->difficulty + 1);
105 root 1.4
106     if (num_treasures <= 0)
107     return;
108 elmex 1.1
109     /* get the style map */
110 root 1.4 sprintf (styledirname, "%s", "/styles/treasurestyles");
111     sprintf (stylefilepath, "%s/%s", styledirname, treasure_style);
112     style_map = find_style (styledirname, treasure_style, -1);
113 elmex 1.1
114 root 1.23 if (!style_map)
115     {
116     LOG (llevError, "unable to load style map %s %s.\n", styledirname, treasure_style);
117     return;
118     }
119    
120 elmex 1.1 /* all the treasure at one spot in the map. */
121 root 1.4 if (treasureoptions & CONCENTRATED)
122     {
123 elmex 1.1
124 root 1.4 /* map_layout_style global, and is previously set */
125     switch (RP->map_layout_style)
126     {
127 root 1.12 case LAYOUT_ONION:
128     case LAYOUT_SPIRAL:
129     case LAYOUT_SQUARE_SPIRAL:
130     {
131     int i, j;
132    
133     /* search the onion for C's or '>', and put treasure there. */
134     for (i = 0; i < RP->Xsize; i++)
135     {
136     for (j = 0; j < RP->Ysize; j++)
137     {
138     if (layout[i][j] == 'C' || layout[i][j] == '>')
139     {
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     /* don't put a chest on an exit. */
147     chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures / tdiv, RP);
148     if (!chest)
149     continue; /* if no chest was placed NEXT */
150     if (treasureoptions & (DOORED | HIDDEN))
151     {
152     doorlist = find_doors_in_room (map, i, j, RP);
153     lock_and_hide_doors (doorlist, map, treasureoptions, RP);
154     free (doorlist);
155     }
156     }
157     }
158     }
159     break;
160     }
161     default:
162     {
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     {
171 root 1.24 i = rndm (RP->Xsize - 2) + 1;
172     j = rndm (RP->Ysize - 2) + 1;
173 root 1.12 find_enclosed_spot (map, &i, &j, RP);
174     if (wall_blocked (map, i, j))
175     i = -1;
176     tries++;
177     }
178     chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures, RP);
179     if (!chest)
180     return;
181     i = chest->x;
182     j = chest->y;
183     if (treasureoptions & (DOORED | HIDDEN))
184     {
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 elmex 1.1 }
191 root 1.4 }
192     else
193     { /* DIFFUSE treasure layout */
194     int ti, i, j;
195    
196     for (ti = 0; ti < num_treasures; ti++)
197     {
198 root 1.24 i = rndm (RP->Xsize - 2) + 1;
199     j = rndm (RP->Ysize - 2) + 1;
200 root 1.4 place_chest (treasureoptions, i, j, map, style_map, 1, RP);
201 elmex 1.1 }
202     }
203     }
204    
205     /* put a chest into the map, near x and y, with the treasure style
206 root 1.2 determined (may be null, or may be a treasure list from lib/treasures,
207     if the global variable "treasurestyle" is set to that treasure list's name */
208 elmex 1.1
209 root 1.4 object *
210 root 1.12 place_chest (int treasureoptions, int x, int y, maptile *map, maptile *style_map, int n_treasures, random_map_params *RP)
211 root 1.4 {
212 elmex 1.1 object *the_chest;
213 root 1.4 int i, xl, yl;
214 elmex 1.1
215 root 1.4 the_chest = get_archetype ("chest"); /* was "chest_2" */
216 elmex 1.1
217     /* first, find a place to put the chest. */
218 root 1.4 i = find_first_free_spot (the_chest, map, x, y);
219     if (i == -1)
220     {
221 root 1.9 the_chest->destroy ();
222 root 1.4 return NULL;
223     }
224 root 1.17
225 root 1.4 xl = x + freearr_x[i];
226     yl = y + freearr_y[i];
227 elmex 1.1
228     /* if the placement is blocked, return a fail. */
229 root 1.4 if (wall_blocked (map, xl, yl))
230     return 0;
231    
232 elmex 1.1 /* put the treasures in the chest. */
233     /* if(style_map) { */
234 root 1.4 #if 0 /* don't use treasure style maps for now! */
235 elmex 1.1 int ti;
236 root 1.4
237 elmex 1.1 /* if treasurestyle lists a treasure list, use it. */
238 root 1.4 treasurelist *tlist = find_treasurelist (RP->treasurestyle);
239    
240     if (tlist != NULL)
241     for (ti = 0; ti < n_treasures; ti++)
242     { /* use the treasure list */
243 root 1.25 object *new_treasure = style_map->pick_random_object ();
244 root 1.4
245     insert_ob_in_ob (arch_to_object (new_treasure->arch), the_chest);
246     }
247     else
248     { /* use the style map */
249     the_chest->randomitems = tlist;
250     the_chest->stats.hp = n_treasures;
251 elmex 1.1 }
252     #endif
253 root 1.4 { /* neither style_map no treasure list given */
254 root 1.28 treasurelist *tlist = treasurelist::find ("chest");
255 root 1.4
256     the_chest->randomitems = tlist;
257 elmex 1.1 the_chest->stats.hp = n_treasures;
258     }
259    
260     /* stick a trap in the chest if required */
261 root 1.4 if (treasureoptions & TRAPPED)
262     {
263 root 1.7 maptile *trap_map = find_style ("/styles/trapstyles", "traps", -1);
264 root 1.4 object *the_trap;
265    
266     if (trap_map)
267     {
268 root 1.25 the_trap = trap_map->pick_random_object ();
269 root 1.4 the_trap->stats.Cha = 10 + RP->difficulty;
270 root 1.24 the_trap->level = bc_random ((3 * RP->difficulty) / 2);
271 root 1.4 if (the_trap)
272     {
273     object *new_trap;
274    
275     new_trap = arch_to_object (the_trap->arch);
276 root 1.9 new_trap->copy_to (the_trap);
277 root 1.4 new_trap->x = x;
278     new_trap->y = y;
279     insert_ob_in_ob (new_trap, the_chest);
280     }
281     }
282 elmex 1.1 }
283    
284     /* set the chest lock code, and call the keyplacer routine with
285     the lockcode. It's not worth bothering to lock the chest if
286 root 1.4 there's only 1 treasure.... */
287     if ((treasureoptions & KEYREQUIRED) && n_treasures > 1)
288     {
289 root 1.13 char keybuf[1024];
290 root 1.4
291 root 1.24 sprintf (keybuf, "%d", rndm (1000000000));
292 root 1.4 the_chest->slaying = keybuf;
293     keyplace (map, x, y, keybuf, PASS_DOORS, 1, RP);
294     }
295 elmex 1.1
296     /* actually place the chest. */
297 root 1.4 the_chest->x = xl;
298     the_chest->y = yl;
299     insert_ob_in_map (the_chest, map, NULL, 0);
300 elmex 1.1 return the_chest;
301     }
302    
303    
304     /* finds the closest monster and returns him, regardless of doors
305 root 1.2 or walls */
306 root 1.4 object *
307 root 1.12 find_closest_monster (maptile *map, int x, int y, random_map_params *RP)
308 root 1.4 {
309 elmex 1.1 int i;
310 root 1.4
311     for (i = 0; i < SIZEOFFREE; i++)
312     {
313     int lx, ly;
314    
315     lx = x + freearr_x[i];
316     ly = y + freearr_y[i];
317     /* boundscheck */
318     if (lx >= 0 && ly >= 0 && lx < RP->Xsize && ly < RP->Ysize)
319     /* don't bother searching this square unless the map says life exists. */
320     if (GET_MAP_FLAGS (map, lx, ly) & P_IS_ALIVE)
321     {
322 root 1.10 object *the_monster = GET_MAP_OB (map, lx, ly);
323 root 1.4
324     for (; the_monster != NULL && (!QUERY_FLAG (the_monster, FLAG_MONSTER)); the_monster = the_monster->above);
325     if (the_monster && QUERY_FLAG (the_monster, FLAG_MONSTER))
326     return the_monster;
327     }
328     }
329 elmex 1.1 return NULL;
330     }
331 root 1.4
332 elmex 1.1
333    
334     /* places keys in the map, preferably in something alive.
335 root 1.2 keycode is the key's code,
336     door_flag is either PASS_DOORS or NO_PASS_DOORS.
337     NO_PASS_DOORS won't cross doors or walls to keyplace, PASS_DOORS will.
338     if n_keys is 1, it will place 1 key. if n_keys >1, it will place 2-4 keys:
339     it will place 2-4 keys regardless of what nkeys is provided nkeys > 1.
340 elmex 1.1
341 root 1.2 The idea is that you call keyplace on x,y where a door is, and it'll make
342     sure a key is placed on both sides of the door.
343 elmex 1.1 */
344 root 1.4 int
345 root 1.12 keyplace (maptile *map, int x, int y, char *keycode, int door_flag, int n_keys, random_map_params *RP)
346 root 1.4 {
347     int i, j;
348 root 1.19 int kx = 0, ky = 0;
349 root 1.4 object *the_keymaster; /* the monster that gets the key. */
350 elmex 1.1 object *the_key;
351    
352     /* get a key and set its keycode */
353 root 1.4 the_key = get_archetype ("key2");
354 root 1.3 the_key->slaying = keycode;
355 elmex 1.1
356 root 1.4 if (door_flag == PASS_DOORS)
357     {
358     int tries = 0;
359    
360 root 1.19 the_keymaster = 0;
361     while (tries < 15 && !the_keymaster)
362 root 1.4 {
363 root 1.24 i = rndm (RP->Xsize - 2) + 1;
364     j = rndm (RP->Ysize - 2) + 1;
365 root 1.4 tries++;
366     the_keymaster = find_closest_monster (map, i, j, RP);
367     }
368 root 1.19
369 root 1.4 /* if we don't find a good keymaster, drop the key on the ground. */
370 root 1.19 if (!the_keymaster)
371 root 1.4 {
372     int freeindex;
373    
374     freeindex = -1;
375     for (tries = 0; tries < 15 && freeindex == -1; tries++)
376     {
377 root 1.24 kx = rndm (RP->Xsize - 2) + 1;
378     ky = rndm (RP->Ysize - 2) + 1;
379 root 1.16 freeindex = find_free_spot (the_key, map, kx, ky, 1, SIZEOFFREE1 + 1);
380 root 1.4 }
381 root 1.15
382 root 1.19 // can freeindex ever be < 0?
383     if (freeindex >= 0)
384 root 1.4 {
385 root 1.19 kx += freearr_x [freeindex];
386     ky += freearr_y [freeindex];
387 root 1.4 }
388     }
389 elmex 1.1 }
390 root 1.4 else
391     { /* NO_PASS_DOORS --we have to work harder. */
392     /* don't try to keyplace if we're sitting on a blocked square and
393     NO_PASS_DOORS is set. */
394     if (n_keys == 1)
395     {
396     if (wall_blocked (map, x, y))
397     return 0;
398 root 1.15
399 root 1.4 the_keymaster = find_monster_in_room (map, x, y, RP);
400 root 1.19 if (!the_keymaster) /* if fail, find a spot to drop the key. */
401 root 1.4 find_spot_in_room (map, x, y, &kx, &ky, RP);
402     }
403     else
404     {
405     int sum = 0; /* count how many keys we actually place */
406    
407     /* I'm lazy, so just try to place in all 4 directions. */
408     sum += keyplace (map, x + 1, y, keycode, NO_PASS_DOORS, 1, RP);
409     sum += keyplace (map, x, y + 1, keycode, NO_PASS_DOORS, 1, RP);
410     sum += keyplace (map, x - 1, y, keycode, NO_PASS_DOORS, 1, RP);
411     sum += keyplace (map, x, y - 1, keycode, NO_PASS_DOORS, 1, RP);
412 root 1.19
413 root 1.4 if (sum < 2) /* we might have made a disconnected map-place more keys. */
414 root 1.19 { /* diagonally this time. */
415 root 1.4 keyplace (map, x + 1, y + 1, keycode, NO_PASS_DOORS, 1, RP);
416     keyplace (map, x + 1, y - 1, keycode, NO_PASS_DOORS, 1, RP);
417     keyplace (map, x - 1, y + 1, keycode, NO_PASS_DOORS, 1, RP);
418     keyplace (map, x - 1, y - 1, keycode, NO_PASS_DOORS, 1, RP);
419     }
420 root 1.19
421 root 1.4 return 1;
422 elmex 1.1 }
423 root 1.4 }
424    
425 root 1.19 if (!the_keymaster)
426 root 1.4 {
427     the_key->x = kx;
428     the_key->y = ky;
429     insert_ob_in_map (the_key, map, NULL, 0);
430 elmex 1.1 return 1;
431 root 1.4 }
432 elmex 1.1
433 root 1.4 insert_ob_in_ob (the_key, the_keymaster);
434 elmex 1.1 return 1;
435 root 1.4 }
436 elmex 1.1
437    
438    
439 root 1.4 /* both find_monster_in_room routines need to have access to this. */
440 elmex 1.1
441     object *theMonsterToFind;
442    
443     /* a recursive routine which will return a monster, eventually,if there is one.
444 root 1.4 it does a check-off on the layout, converting 0's to 1's */
445    
446     object *
447 root 1.12 find_monster_in_room_recursive (char **layout, maptile *map, int x, int y, random_map_params *RP)
448 root 1.4 {
449     int i, j;
450 elmex 1.1
451     /* if we've found a monster already, leave */
452 root 1.4 if (theMonsterToFind != NULL)
453     return theMonsterToFind;
454 elmex 1.1
455     /* bounds check x and y */
456 root 1.4 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
457     return theMonsterToFind;
458 elmex 1.1
459     /* if the square is blocked or searched already, leave */
460 root 1.4 if (layout[x][y] != 0)
461     return theMonsterToFind; /* might be NULL, that's fine. */
462 elmex 1.1
463     /* check the current square for a monster. If there is one,
464     set theMonsterToFind and return it. */
465 root 1.4 layout[x][y] = 1;
466     if (GET_MAP_FLAGS (map, x, y) & P_IS_ALIVE)
467     {
468 root 1.10 object *the_monster = GET_MAP_OB (map, x, y);
469 root 1.4
470     /* check off this point */
471     for (; the_monster != NULL && (!QUERY_FLAG (the_monster, FLAG_ALIVE)); the_monster = the_monster->above);
472     if (the_monster && QUERY_FLAG (the_monster, FLAG_ALIVE))
473     {
474     theMonsterToFind = the_monster;
475     return theMonsterToFind;
476     }
477 elmex 1.1 }
478 root 1.4
479 elmex 1.1 /* now search all the 8 squares around recursively for a monster,in random order */
480 root 1.21 for (i = rndm (8), j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
481 root 1.4 {
482     theMonsterToFind = find_monster_in_room_recursive (layout, map, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], RP);
483     if (theMonsterToFind != NULL)
484     return theMonsterToFind;
485     }
486 elmex 1.1 return theMonsterToFind;
487     }
488    
489    
490     /* sets up some data structures: the _recursive form does the
491     real work. */
492    
493 root 1.4 object *
494 root 1.12 find_monster_in_room (maptile *map, int x, int y, random_map_params *RP)
495 root 1.4 {
496 elmex 1.1 char **layout2;
497 root 1.4 int i, j;
498    
499     theMonsterToFind = 0;
500     layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
501 elmex 1.1 /* allocate and copy the layout, converting C to 0. */
502 root 1.4 for (i = 0; i < RP->Xsize; i++)
503     {
504     layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
505     for (j = 0; j < RP->Ysize; j++)
506     {
507     if (wall_blocked (map, i, j))
508     layout2[i][j] = '#';
509     }
510 elmex 1.1 }
511 root 1.4 theMonsterToFind = find_monster_in_room_recursive (layout2, map, x, y, RP);
512    
513 elmex 1.1 /* deallocate the temp. layout */
514 root 1.4 for (i = 0; i < RP->Xsize; i++)
515     {
516     free (layout2[i]);
517     }
518     free (layout2);
519 elmex 1.1
520     return theMonsterToFind;
521     }
522    
523 root 1.4 /* a datastructure needed by find_spot_in_room and find_spot_in_room_recursive */
524 elmex 1.1 int *room_free_spots_x;
525     int *room_free_spots_y;
526 root 1.4 int number_of_free_spots_in_room;
527 elmex 1.1
528     /* the workhorse routine, which finds the free spots in a room:
529     a datastructure of free points is set up, and a position chosen from
530     that datastructure. */
531 root 1.4 void
532 root 1.12 find_spot_in_room_recursive (char **layout, int x, int y, random_map_params *RP)
533 root 1.4 {
534     int i, j;
535 elmex 1.1
536     /* bounds check x and y */
537 root 1.4 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
538     return;
539 elmex 1.1
540     /* if the square is blocked or searched already, leave */
541 root 1.4 if (layout[x][y] != 0)
542     return;
543 elmex 1.1
544     /* set the current square as checked, and add it to the list.
545     set theMonsterToFind and return it. */
546     /* check off this point */
547 root 1.4 layout[x][y] = 1;
548     room_free_spots_x[number_of_free_spots_in_room] = x;
549     room_free_spots_y[number_of_free_spots_in_room] = y;
550 elmex 1.1 number_of_free_spots_in_room++;
551 root 1.19
552 elmex 1.1 /* now search all the 8 squares around recursively for free spots,in random order */
553 root 1.21 for (i = rndm (8), j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
554 root 1.19 find_spot_in_room_recursive (layout, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], RP);
555 elmex 1.1
556     }
557    
558     /* find a random non-blocked spot in this room to drop a key. */
559 root 1.4 void
560 root 1.12 find_spot_in_room (maptile *map, int x, int y, int *kx, int *ky, random_map_params *RP)
561 root 1.4 {
562 elmex 1.1 char **layout2;
563 root 1.4 int i, j;
564 elmex 1.1
565 root 1.4 number_of_free_spots_in_room = 0;
566     room_free_spots_x = (int *) calloc (sizeof (int), RP->Xsize * RP->Ysize);
567     room_free_spots_y = (int *) calloc (sizeof (int), RP->Xsize * RP->Ysize);
568    
569     layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
570 elmex 1.1 /* allocate and copy the layout, converting C to 0. */
571 root 1.4 for (i = 0; i < RP->Xsize; i++)
572     {
573     layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
574     for (j = 0; j < RP->Ysize; j++)
575 root 1.19 if (wall_blocked (map, i, j))
576     layout2[i][j] = '#';
577 root 1.4 }
578    
579     /* setup num_free_spots and room_free_spots */
580     find_spot_in_room_recursive (layout2, x, y, RP);
581    
582     if (number_of_free_spots_in_room > 0)
583     {
584 root 1.24 i = rndm (number_of_free_spots_in_room);
585 root 1.4 *kx = room_free_spots_x[i];
586     *ky = room_free_spots_y[i];
587 elmex 1.1 }
588    
589     /* deallocate the temp. layout */
590 root 1.4 for (i = 0; i < RP->Xsize; i++)
591 root 1.19 free (layout2[i]);
592    
593 root 1.4 free (layout2);
594     free (room_free_spots_x);
595     free (room_free_spots_y);
596 elmex 1.1 }
597    
598    
599     /* searches the map for a spot with walls around it. The more
600 root 1.2 walls the better, but it'll settle for 1 wall, or even 0, but
601     it'll return 0 if no FREE spots are found.*/
602 root 1.4 void
603 root 1.12 find_enclosed_spot (maptile *map, int *cx, int *cy, random_map_params *RP)
604 root 1.4 {
605     int x, y;
606 elmex 1.1 int i;
607    
608 root 1.4 x = *cx;
609     y = *cy;
610    
611     for (i = 0; i <= SIZEOFFREE1; i++)
612     {
613     int lx, ly, sindex;
614    
615     lx = x + freearr_x[i];
616     ly = y + freearr_y[i];
617     sindex = surround_flag3 (map, lx, ly, RP);
618     /* if it's blocked on 3 sides, it's enclosed */
619     if (sindex == 7 || sindex == 11 || sindex == 13 || sindex == 14)
620     {
621     *cx = lx;
622     *cy = ly;
623     return;
624     }
625 elmex 1.1 }
626    
627     /* OK, if we got here, we're obviously someplace where there's no enclosed
628     spots--try to find someplace which is 2x enclosed. */
629 root 1.4 for (i = 0; i <= SIZEOFFREE1; i++)
630     {
631     int lx, ly, sindex;
632    
633     lx = x + freearr_x[i];
634     ly = y + freearr_y[i];
635     sindex = surround_flag3 (map, lx, ly, RP);
636     /* if it's blocked on 3 sides, it's enclosed */
637     if (sindex == 3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex == 10 || sindex == 12)
638     {
639     *cx = lx;
640     *cy = ly;
641     return;
642     }
643 elmex 1.1 }
644    
645     /* settle for one surround point */
646 root 1.4 for (i = 0; i <= SIZEOFFREE1; i++)
647     {
648     int lx, ly, sindex;
649    
650     lx = x + freearr_x[i];
651     ly = y + freearr_y[i];
652     sindex = surround_flag3 (map, lx, ly, RP);
653     /* if it's blocked on 3 sides, it's enclosed */
654     if (sindex)
655     {
656     *cx = lx;
657     *cy = ly;
658     return;
659     }
660     }
661     /* give up and return the closest free spot. */
662 root 1.29 i = find_free_spot (archetype::find ("chest"), map, x, y, 1, SIZEOFFREE1 + 1);
663 root 1.17
664     if (i != -1)
665 root 1.4 {
666     *cx = x + freearr_x[i];
667     *cy = y + freearr_y[i];
668 elmex 1.1 }
669 root 1.17 else
670     {
671     /* indicate failure */
672     *cx = -1;
673     *cy = -1;
674     }
675 elmex 1.1 }
676    
677 root 1.4 void
678 root 1.7 remove_monsters (int x, int y, maptile *map)
679 root 1.4 {
680 elmex 1.1 object *tmp;
681    
682 root 1.22 for (tmp = GET_MAP_OB (map, x, y); tmp; tmp = tmp->above)
683 root 1.4 if (QUERY_FLAG (tmp, FLAG_ALIVE))
684     {
685     if (tmp->head)
686     tmp = tmp->head;
687 root 1.8 tmp->remove ();
688 root 1.9 tmp->destroy ();
689 root 1.10 tmp = GET_MAP_OB (map, x, y);
690 root 1.4 if (tmp == NULL)
691     break;
692     };
693 elmex 1.1 }
694    
695     /* surrounds the point x,y by doors, so as to enclose something, like
696 root 1.2 a chest. It only goes as far as the 8 squares surrounding, and
697     it'll remove any monsters it finds.*/
698 root 1.4 object **
699 root 1.7 surround_by_doors (maptile *map, char **layout, int x, int y, int opts)
700 root 1.4 {
701 elmex 1.1 int i;
702 root 1.26 const char *doors[2];
703 elmex 1.1 object **doorlist;
704 root 1.4 int ndoors_made = 0;
705     doorlist = (object **) calloc (9, sizeof (object *)); /* 9 doors so we can hold termination null */
706 elmex 1.1
707     /* this is a list we pick from, for horizontal and vertical doors */
708 root 1.4 if (opts & DOORED)
709     {
710     doors[0] = "locked_door2";
711     doors[1] = "locked_door1";
712     }
713     else
714     {
715     doors[0] = "door_1";
716     doors[1] = "door_2";
717     }
718 elmex 1.1
719     /* place doors in all the 8 adjacent unblocked squares. */
720 root 1.4 for (i = 1; i < 9; i++)
721     {
722     int x1 = x + freearr_x[i], y1 = y + freearr_y[i];
723    
724 root 1.22 if (!wall_blocked (map, x1, y1) && layout[x1][y1] == '>')
725 root 1.4 { /* place a door */
726 root 1.22 remove_monsters (x1, y1, map);
727 root 1.4
728 root 1.22 object *new_door = get_archetype (freearr_x[i] == 0 ? doors[1] : doors[0]);
729     map->insert (new_door, x1, y1);
730 root 1.4 doorlist[ndoors_made] = new_door;
731     ndoors_made++;
732     }
733 elmex 1.1 }
734 root 1.22
735 elmex 1.1 return doorlist;
736     }
737    
738    
739     /* returns the first door in this square, or NULL if there isn't a door. */
740 root 1.4 object *
741 root 1.7 door_in_square (maptile *map, int x, int y)
742 root 1.4 {
743 elmex 1.1 object *tmp;
744 root 1.4
745 root 1.10 for (tmp = GET_MAP_OB (map, x, y); tmp != NULL; tmp = tmp->above)
746 root 1.4 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
747     return tmp;
748 elmex 1.1 return NULL;
749     }
750 root 1.4
751 elmex 1.1
752     /* the workhorse routine, which finds the doors in a room */
753 root 1.4 void
754 root 1.12 find_doors_in_room_recursive (char **layout, maptile *map, int x, int y, object **doorlist, int *ndoors, random_map_params *RP)
755 root 1.4 {
756     int i, j;
757 elmex 1.1 object *door;
758    
759     /* bounds check x and y */
760 root 1.4 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
761     return;
762 elmex 1.1
763     /* if the square is blocked or searched already, leave */
764 root 1.4 if (layout[x][y] == 1)
765     return;
766 elmex 1.1
767     /* check off this point */
768 root 1.4 if (layout[x][y] == '#')
769     { /* there could be a door here */
770     layout[x][y] = 1;
771     door = door_in_square (map, x, y);
772 root 1.13 if (door)
773 elmex 1.1 {
774 root 1.4 doorlist[*ndoors] = door;
775 root 1.13 if (*ndoors > 1022) /* eek! out of memory */
776 root 1.4 {
777     LOG (llevError, "find_doors_in_room_recursive:Too many doors for memory allocated!\n");
778     return;
779     }
780 root 1.13
781 root 1.4 *ndoors = *ndoors + 1;
782 elmex 1.1 }
783     }
784 root 1.4 else
785     {
786     layout[x][y] = 1;
787 root 1.24
788 root 1.4 /* now search all the 8 squares around recursively for free spots,in random order */
789 root 1.24 for (i = rndm (8), j = 0; j < 8 && !theMonsterToFind; i++, j++)
790     find_doors_in_room_recursive (layout, map,
791     x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1],
792     doorlist, ndoors, RP);
793 elmex 1.1 }
794     }
795    
796     /* find a random non-blocked spot in this room to drop a key. */
797 root 1.4 object **
798 root 1.12 find_doors_in_room (maptile *map, int x, int y, random_map_params *RP)
799 root 1.4 {
800 elmex 1.1 char **layout2;
801     object **doorlist;
802 root 1.4 int i, j;
803     int ndoors = 0;
804 elmex 1.1
805 root 1.13 doorlist = (object **) calloc (sizeof (int), 1024);
806 elmex 1.1
807 root 1.4 layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
808 elmex 1.1 /* allocate and copy the layout, converting C to 0. */
809 root 1.4 for (i = 0; i < RP->Xsize; i++)
810     {
811     layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
812     for (j = 0; j < RP->Ysize; j++)
813     {
814     if (wall_blocked (map, i, j))
815     layout2[i][j] = '#';
816     }
817 elmex 1.1 }
818 root 1.4
819     /* setup num_free_spots and room_free_spots */
820     find_doors_in_room_recursive (layout2, map, x, y, doorlist, &ndoors, RP);
821 elmex 1.1
822     /* deallocate the temp. layout */
823 root 1.4 for (i = 0; i < RP->Xsize; i++)
824 root 1.13 free (layout2[i]);
825    
826 root 1.4 free (layout2);
827 elmex 1.1 return doorlist;
828     }
829    
830    
831    
832     /* locks and/or hides all the doors in doorlist, or does nothing if
833 root 1.2 opts doesn't say to lock/hide doors. */
834 elmex 1.1
835 root 1.4 void
836 root 1.12 lock_and_hide_doors (object **doorlist, maptile *map, int opts, random_map_params *RP)
837 root 1.4 {
838 elmex 1.1 object *door;
839     int i;
840 root 1.4
841 elmex 1.1 /* lock the doors and hide the keys. */
842 root 1.4
843     if (opts & DOORED)
844     {
845     for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
846     {
847     object *new_door = get_archetype ("locked_door1");
848 root 1.13 char keybuf[1024];
849 root 1.4
850     door = doorlist[i];
851     new_door->face = door->face;
852     new_door->x = door->x;
853     new_door->y = door->y;
854 root 1.8 door->remove ();
855 root 1.9 door->destroy ();
856 root 1.4 doorlist[i] = new_door;
857     insert_ob_in_map (new_door, map, NULL, 0);
858 root 1.24 sprintf (keybuf, "%d", rndm (1000000000));
859 root 1.4 new_door->slaying = keybuf;
860     keyplace (map, new_door->x, new_door->y, keybuf, NO_PASS_DOORS, 2, RP);
861     }
862 elmex 1.1 }
863    
864     /* change the faces of the doors and surrounding walls to hide them. */
865 root 1.4 if (opts & HIDDEN)
866     {
867     for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
868     {
869     object *wallface;
870    
871     door = doorlist[i];
872     wallface = retrofit_joined_wall (map, door->x, door->y, 1, RP);
873     if (wallface != NULL)
874     {
875     retrofit_joined_wall (map, door->x - 1, door->y, 0, RP);
876     retrofit_joined_wall (map, door->x + 1, door->y, 0, RP);
877     retrofit_joined_wall (map, door->x, door->y - 1, 0, RP);
878     retrofit_joined_wall (map, door->x, door->y + 1, 0, RP);
879     door->face = wallface->face;
880     if (!QUERY_FLAG (wallface, FLAG_REMOVED))
881 root 1.8 wallface->remove ();
882 root 1.9 wallface->destroy ();
883 root 1.4 }
884     }
885 elmex 1.1 }
886     }