ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.18
Committed: Mon Jan 15 21:06:19 2007 UTC (17 years, 4 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.17: +22 -23 lines
Log Message:
comments

File Contents

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