ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.4
Committed: Sun Sep 10 16:06:37 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +605 -442 lines
Log Message:
indent

File Contents

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