ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.37
Committed: Fri May 2 21:01:53 2008 UTC (16 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.36: +5 -5 lines
Log Message:
remove all easy cases of copy_to, mostly replace by clone or instance

File Contents

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