ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.14
Committed: Sat Jan 6 14:42:30 2007 UTC (17 years, 4 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.13: +1 -0 lines
Log Message:
added some copyrights

File Contents

# User Rev Content
1 root 1.12
2 elmex 1.1 /*
3     CrossFire, A Multiplayer game for X-windows
4    
5 pippijn 1.14 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
6 elmex 1.1 Copyright (C) 2001 Mark Wedel & Crossfire Development Team
7     Copyright (C) 1992 Frank Tore Johansen
8    
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13    
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     GNU General Public License for more details.
18    
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23 root 1.6 The authors can be reached via e-mail at <crossfire@schmorp.de>
24 elmex 1.1 */
25    
26     /* placing treasure in maps, where appropriate. */
27    
28    
29    
30     #include <global.h>
31     #include <random_map.h>
32     #include <rproto.h>
33    
34     /* some defines for various options which can be set. */
35    
36 root 1.4 #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */
37     #define HIDDEN 2 /* doors to treasure are hidden. */
38     #define KEYREQUIRED 4 /* chest has a key, which is placed randomly in the map. */
39     #define DOORED 8 /* treasure has doors around it. */
40     #define TRAPPED 16 /* trap dropped in same location as chest. */
41     #define SPARSE 32 /* 1/2 as much treasure as default */
42     #define RICH 64 /* 2x as much treasure as default */
43     #define FILLED 128 /* Fill/tile the entire map with treasure */
44     #define LAST_OPTION 64 /* set this to the last real option, for random */
45 elmex 1.1
46     #define NO_PASS_DOORS 0
47     #define PASS_DOORS 1
48    
49    
50     /* returns true if square x,y has P_NO_PASS set, which is true for walls
51     * and doors but not monsters.
52     * This function is not map tile aware.
53     */
54    
55 root 1.4 int
56 root 1.7 wall_blocked (maptile *m, int x, int y)
57 root 1.4 {
58     int r;
59 elmex 1.1
60 root 1.4 if (OUT_OF_REAL_MAP (m, x, y))
61     return 1;
62     r = GET_MAP_MOVE_BLOCK (m, x, y) & ~MOVE_BLOCK_DEFAULT;
63     return r;
64 elmex 1.1 }
65    
66     /* place treasures in the map, given the
67     map, (required)
68     layout, (required)
69     treasure style (may be empty or NULL, or "none" to cause no treasure.)
70     treasureoptions (may be 0 for random choices or positive)
71     */
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     if (treasureoptions <= 0)
86     treasureoptions = RANDOM () % (2 * LAST_OPTION);
87 elmex 1.1
88     /* filter out the mutually exclusive options */
89 root 1.4 if ((treasureoptions & RICH) && (treasureoptions & SPARSE))
90     {
91     if (RANDOM () % 2)
92     treasureoptions -= 1;
93     else
94     treasureoptions -= 2;
95     }
96 elmex 1.1
97     /* pick the number of treasures */
98 root 1.4 if (treasureoptions & SPARSE)
99     num_treasures = BC_RANDOM (RP->total_map_hp / 600 + RP->difficulty / 2 + 1);
100     else if (treasureoptions & RICH)
101     num_treasures = BC_RANDOM (RP->total_map_hp / 150 + 2 * RP->difficulty + 1);
102     else
103     num_treasures = BC_RANDOM (RP->total_map_hp / 300 + RP->difficulty + 1);
104    
105     if (num_treasures <= 0)
106     return;
107 elmex 1.1
108     /* get the style map */
109 root 1.4 sprintf (styledirname, "%s", "/styles/treasurestyles");
110     sprintf (stylefilepath, "%s/%s", styledirname, treasure_style);
111     style_map = find_style (styledirname, treasure_style, -1);
112 elmex 1.1
113     /* all the treasure at one spot in the map. */
114 root 1.4 if (treasureoptions & CONCENTRATED)
115     {
116 elmex 1.1
117 root 1.4 /* map_layout_style global, and is previously set */
118     switch (RP->map_layout_style)
119     {
120 root 1.12 case LAYOUT_ONION:
121     case LAYOUT_SPIRAL:
122     case LAYOUT_SQUARE_SPIRAL:
123     {
124     int i, j;
125    
126     /* search the onion for C's or '>', and put treasure there. */
127     for (i = 0; i < RP->Xsize; i++)
128     {
129     for (j = 0; j < RP->Ysize; j++)
130     {
131     if (layout[i][j] == 'C' || layout[i][j] == '>')
132     {
133     int tdiv = RP->symmetry_used;
134     object **doorlist;
135     object *chest;
136    
137     if (tdiv == 3)
138     tdiv = 2; /* this symmetry uses a divisor of 2 */
139     /* don't put a chest on an exit. */
140     chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures / tdiv, RP);
141     if (!chest)
142     continue; /* if no chest was placed NEXT */
143     if (treasureoptions & (DOORED | HIDDEN))
144     {
145     doorlist = find_doors_in_room (map, i, j, RP);
146     lock_and_hide_doors (doorlist, map, treasureoptions, RP);
147     free (doorlist);
148     }
149     }
150     }
151     }
152     break;
153     }
154     default:
155     {
156     int i, j, tries;
157     object *chest;
158     object **doorlist;
159    
160     i = j = -1;
161     tries = 0;
162     while (i == -1 && tries < 100)
163     {
164     i = RANDOM () % (RP->Xsize - 2) + 1;
165     j = RANDOM () % (RP->Ysize - 2) + 1;
166     find_enclosed_spot (map, &i, &j, RP);
167     if (wall_blocked (map, i, j))
168     i = -1;
169     tries++;
170     }
171     chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures, RP);
172     if (!chest)
173     return;
174     i = chest->x;
175     j = chest->y;
176     if (treasureoptions & (DOORED | HIDDEN))
177     {
178     doorlist = surround_by_doors (map, layout, i, j, treasureoptions);
179     lock_and_hide_doors (doorlist, map, treasureoptions, RP);
180     free (doorlist);
181     }
182     }
183 elmex 1.1 }
184 root 1.4 }
185     else
186     { /* DIFFUSE treasure layout */
187     int ti, i, j;
188    
189     for (ti = 0; ti < num_treasures; ti++)
190     {
191     i = RANDOM () % (RP->Xsize - 2) + 1;
192     j = RANDOM () % (RP->Ysize - 2) + 1;
193     place_chest (treasureoptions, i, j, map, style_map, 1, RP);
194 elmex 1.1 }
195     }
196     }
197    
198     /* put a chest into the map, near x and y, with the treasure style
199 root 1.2 determined (may be null, or may be a treasure list from lib/treasures,
200     if the global variable "treasurestyle" is set to that treasure list's name */
201 elmex 1.1
202 root 1.4 object *
203 root 1.12 place_chest (int treasureoptions, int x, int y, maptile *map, maptile *style_map, int n_treasures, random_map_params *RP)
204 root 1.4 {
205 elmex 1.1 object *the_chest;
206 root 1.4 int i, xl, yl;
207 elmex 1.1
208 root 1.4 the_chest = get_archetype ("chest"); /* was "chest_2" */
209 elmex 1.1
210     /* first, find a place to put the chest. */
211 root 1.4 i = find_first_free_spot (the_chest, map, x, y);
212     if (i == -1)
213     {
214 root 1.9 the_chest->destroy ();
215 root 1.4 return NULL;
216     }
217     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     freeindex = find_first_free_spot (the_key, map, kx, ky);
373     }
374     if (freeindex != -1)
375     {
376     kx += freearr_x[freeindex];
377     ky += freearr_y[freeindex];
378     }
379     }
380 elmex 1.1 }
381 root 1.4 else
382     { /* NO_PASS_DOORS --we have to work harder. */
383     /* don't try to keyplace if we're sitting on a blocked square and
384     NO_PASS_DOORS is set. */
385     if (n_keys == 1)
386     {
387     if (wall_blocked (map, x, y))
388     return 0;
389     the_keymaster = find_monster_in_room (map, x, y, RP);
390     if (the_keymaster == NULL) /* if fail, find a spot to drop the key. */
391     find_spot_in_room (map, x, y, &kx, &ky, RP);
392     }
393     else
394     {
395     int sum = 0; /* count how many keys we actually place */
396    
397     /* I'm lazy, so just try to place in all 4 directions. */
398     sum += keyplace (map, x + 1, y, keycode, NO_PASS_DOORS, 1, RP);
399     sum += keyplace (map, x, y + 1, keycode, NO_PASS_DOORS, 1, RP);
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     if (sum < 2) /* we might have made a disconnected map-place more keys. */
403     { /* diagnoally this time. */
404     keyplace (map, x + 1, y + 1, keycode, NO_PASS_DOORS, 1, RP);
405     keyplace (map, x + 1, y - 1, keycode, NO_PASS_DOORS, 1, RP);
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     }
409     return 1;
410 elmex 1.1 }
411 root 1.4 }
412    
413     if (the_keymaster == NULL)
414     {
415     the_key->x = kx;
416     the_key->y = ky;
417     insert_ob_in_map (the_key, map, NULL, 0);
418 elmex 1.1 return 1;
419 root 1.4 }
420 elmex 1.1
421 root 1.4 insert_ob_in_ob (the_key, the_keymaster);
422 elmex 1.1 return 1;
423 root 1.4 }
424 elmex 1.1
425    
426    
427 root 1.4 /* both find_monster_in_room routines need to have access to this. */
428 elmex 1.1
429     object *theMonsterToFind;
430    
431     /* a recursive routine which will return a monster, eventually,if there is one.
432 root 1.4 it does a check-off on the layout, converting 0's to 1's */
433    
434     object *
435 root 1.12 find_monster_in_room_recursive (char **layout, maptile *map, int x, int y, random_map_params *RP)
436 root 1.4 {
437     int i, j;
438 elmex 1.1
439     /* if we've found a monster already, leave */
440 root 1.4 if (theMonsterToFind != NULL)
441     return theMonsterToFind;
442 elmex 1.1
443     /* bounds check x and y */
444 root 1.4 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
445     return theMonsterToFind;
446 elmex 1.1
447     /* if the square is blocked or searched already, leave */
448 root 1.4 if (layout[x][y] != 0)
449     return theMonsterToFind; /* might be NULL, that's fine. */
450 elmex 1.1
451     /* check the current square for a monster. If there is one,
452     set theMonsterToFind and return it. */
453 root 1.4 layout[x][y] = 1;
454     if (GET_MAP_FLAGS (map, x, y) & P_IS_ALIVE)
455     {
456 root 1.10 object *the_monster = GET_MAP_OB (map, x, y);
457 root 1.4
458     /* check off this point */
459     for (; the_monster != NULL && (!QUERY_FLAG (the_monster, FLAG_ALIVE)); the_monster = the_monster->above);
460     if (the_monster && QUERY_FLAG (the_monster, FLAG_ALIVE))
461     {
462     theMonsterToFind = the_monster;
463     return theMonsterToFind;
464     }
465 elmex 1.1 }
466 root 1.4
467 elmex 1.1 /* now search all the 8 squares around recursively for a monster,in random order */
468 root 1.4 for (i = RANDOM () % 8, j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
469     {
470     theMonsterToFind = find_monster_in_room_recursive (layout, map, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], RP);
471     if (theMonsterToFind != NULL)
472     return theMonsterToFind;
473     }
474 elmex 1.1 return theMonsterToFind;
475     }
476    
477    
478     /* sets up some data structures: the _recursive form does the
479     real work. */
480    
481 root 1.4 object *
482 root 1.12 find_monster_in_room (maptile *map, int x, int y, random_map_params *RP)
483 root 1.4 {
484 elmex 1.1 char **layout2;
485 root 1.4 int i, j;
486    
487     theMonsterToFind = 0;
488     layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
489 elmex 1.1 /* allocate and copy the layout, converting C to 0. */
490 root 1.4 for (i = 0; i < RP->Xsize; i++)
491     {
492     layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
493     for (j = 0; j < RP->Ysize; j++)
494     {
495     if (wall_blocked (map, i, j))
496     layout2[i][j] = '#';
497     }
498 elmex 1.1 }
499 root 1.4 theMonsterToFind = find_monster_in_room_recursive (layout2, map, x, y, RP);
500    
501 elmex 1.1 /* deallocate the temp. layout */
502 root 1.4 for (i = 0; i < RP->Xsize; i++)
503     {
504     free (layout2[i]);
505     }
506     free (layout2);
507 elmex 1.1
508     return theMonsterToFind;
509     }
510    
511    
512 root 1.4
513    
514     /* a datastructure needed by find_spot_in_room and find_spot_in_room_recursive */
515 elmex 1.1 int *room_free_spots_x;
516     int *room_free_spots_y;
517 root 1.4 int number_of_free_spots_in_room;
518 elmex 1.1
519     /* the workhorse routine, which finds the free spots in a room:
520     a datastructure of free points is set up, and a position chosen from
521     that datastructure. */
522    
523 root 1.4 void
524 root 1.12 find_spot_in_room_recursive (char **layout, int x, int y, random_map_params *RP)
525 root 1.4 {
526     int i, j;
527 elmex 1.1
528     /* bounds check x and y */
529 root 1.4 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
530     return;
531 elmex 1.1
532     /* if the square is blocked or searched already, leave */
533 root 1.4 if (layout[x][y] != 0)
534     return;
535 elmex 1.1
536     /* set the current square as checked, and add it to the list.
537     set theMonsterToFind and return it. */
538     /* check off this point */
539 root 1.4 layout[x][y] = 1;
540     room_free_spots_x[number_of_free_spots_in_room] = x;
541     room_free_spots_y[number_of_free_spots_in_room] = y;
542 elmex 1.1 number_of_free_spots_in_room++;
543     /* now search all the 8 squares around recursively for free spots,in random order */
544 root 1.4 for (i = RANDOM () % 8, j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
545     {
546     find_spot_in_room_recursive (layout, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], RP);
547     }
548 elmex 1.1
549     }
550    
551     /* find a random non-blocked spot in this room to drop a key. */
552 root 1.4 void
553 root 1.12 find_spot_in_room (maptile *map, int x, int y, int *kx, int *ky, random_map_params *RP)
554 root 1.4 {
555 elmex 1.1 char **layout2;
556 root 1.4 int i, j;
557 elmex 1.1
558 root 1.4 number_of_free_spots_in_room = 0;
559     room_free_spots_x = (int *) calloc (sizeof (int), RP->Xsize * RP->Ysize);
560     room_free_spots_y = (int *) calloc (sizeof (int), RP->Xsize * RP->Ysize);
561    
562     layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
563 elmex 1.1 /* allocate and copy the layout, converting C to 0. */
564 root 1.4 for (i = 0; i < RP->Xsize; i++)
565     {
566     layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
567     for (j = 0; j < RP->Ysize; j++)
568     {
569     if (wall_blocked (map, i, j))
570     layout2[i][j] = '#';
571     }
572     }
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     i = RANDOM () % number_of_free_spots_in_room;
580     *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     {
587     free (layout2[i]);
588     }
589     free (layout2);
590     free (room_free_spots_x);
591     free (room_free_spots_y);
592 elmex 1.1 }
593    
594    
595     /* searches the map for a spot with walls around it. The more
596 root 1.2 walls the better, but it'll settle for 1 wall, or even 0, but
597     it'll return 0 if no FREE spots are found.*/
598 elmex 1.1
599 root 1.4 void
600 root 1.12 find_enclosed_spot (maptile *map, int *cx, int *cy, random_map_params *RP)
601 root 1.4 {
602     int x, y;
603 elmex 1.1 int i;
604    
605 root 1.4 x = *cx;
606     y = *cy;
607    
608     for (i = 0; i <= SIZEOFFREE1; i++)
609     {
610     int lx, ly, sindex;
611    
612     lx = x + freearr_x[i];
613     ly = y + freearr_y[i];
614     sindex = surround_flag3 (map, lx, ly, RP);
615     /* if it's blocked on 3 sides, it's enclosed */
616     if (sindex == 7 || sindex == 11 || sindex == 13 || sindex == 14)
617     {
618     *cx = lx;
619     *cy = ly;
620     return;
621     }
622 elmex 1.1 }
623    
624     /* OK, if we got here, we're obviously someplace where there's no enclosed
625     spots--try to find someplace which is 2x enclosed. */
626 root 1.4 for (i = 0; i <= SIZEOFFREE1; i++)
627     {
628     int lx, ly, sindex;
629    
630     lx = x + freearr_x[i];
631     ly = y + freearr_y[i];
632     sindex = surround_flag3 (map, lx, ly, RP);
633     /* if it's blocked on 3 sides, it's enclosed */
634     if (sindex == 3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex == 10 || sindex == 12)
635     {
636     *cx = lx;
637     *cy = ly;
638     return;
639     }
640 elmex 1.1 }
641    
642     /* settle for one surround point */
643 root 1.4 for (i = 0; i <= SIZEOFFREE1; i++)
644     {
645     int lx, ly, sindex;
646    
647     lx = x + freearr_x[i];
648     ly = y + freearr_y[i];
649     sindex = surround_flag3 (map, lx, ly, RP);
650     /* if it's blocked on 3 sides, it's enclosed */
651     if (sindex)
652     {
653     *cx = lx;
654     *cy = ly;
655     return;
656     }
657     }
658     /* give up and return the closest free spot. */
659 root 1.5 i = find_first_free_spot (&archetype::find ("chest")->clone, map, x, y);
660 root 1.4 if (i != -1 && i <= SIZEOFFREE1)
661     {
662     *cx = x + freearr_x[i];
663     *cy = y + freearr_y[i];
664 elmex 1.1 return;
665     }
666     /* indicate failure */
667 root 1.4 *cx = *cy = -1;
668 elmex 1.1 }
669    
670    
671 root 1.4 void
672 root 1.7 remove_monsters (int x, int y, maptile *map)
673 root 1.4 {
674 elmex 1.1 object *tmp;
675    
676 root 1.10 for (tmp = GET_MAP_OB (map, x, y); tmp != NULL; tmp = tmp->above)
677 root 1.4 if (QUERY_FLAG (tmp, FLAG_ALIVE))
678     {
679     if (tmp->head)
680     tmp = tmp->head;
681 root 1.8 tmp->remove ();
682 root 1.9 tmp->destroy ();
683 root 1.10 tmp = GET_MAP_OB (map, x, y);
684 root 1.4 if (tmp == NULL)
685     break;
686     };
687 elmex 1.1 }
688    
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 elmex 1.1
694 root 1.4 object **
695 root 1.7 surround_by_doors (maptile *map, char **layout, int x, int y, int opts)
696 root 1.4 {
697 elmex 1.1 int i;
698     char *doors[2];
699     object **doorlist;
700 root 1.4 int ndoors_made = 0;
701     doorlist = (object **) calloc (9, sizeof (object *)); /* 9 doors so we can hold termination null */
702 elmex 1.1
703     /* this is a list we pick from, for horizontal and vertical doors */
704 root 1.4 if (opts & DOORED)
705     {
706     doors[0] = "locked_door2";
707     doors[1] = "locked_door1";
708     }
709     else
710     {
711     doors[0] = "door_1";
712     doors[1] = "door_2";
713     }
714 elmex 1.1
715     /* place doors in all the 8 adjacent unblocked squares. */
716 root 1.4 for (i = 1; i < 9; i++)
717     {
718     int x1 = x + freearr_x[i], y1 = y + freearr_y[i];
719    
720     if (!wall_blocked (map, x1, y1) || layout[x1][y1] == '>')
721     { /* place a door */
722     object *new_door = get_archetype ((freearr_x[i] == 0) ? doors[1] : doors[0]);
723    
724     new_door->x = x + freearr_x[i];
725     new_door->y = y + freearr_y[i];
726     remove_monsters (new_door->x, new_door->y, map);
727     insert_ob_in_map (new_door, map, NULL, 0);
728     doorlist[ndoors_made] = new_door;
729     ndoors_made++;
730     }
731 elmex 1.1 }
732     return doorlist;
733     }
734    
735    
736     /* returns the first door in this square, or NULL if there isn't a door. */
737 root 1.4 object *
738 root 1.7 door_in_square (maptile *map, int x, int y)
739 root 1.4 {
740 elmex 1.1 object *tmp;
741 root 1.4
742 root 1.10 for (tmp = GET_MAP_OB (map, x, y); tmp != NULL; tmp = tmp->above)
743 root 1.4 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
744     return tmp;
745 elmex 1.1 return NULL;
746     }
747 root 1.4
748 elmex 1.1
749     /* the workhorse routine, which finds the doors in a room */
750 root 1.4 void
751 root 1.12 find_doors_in_room_recursive (char **layout, maptile *map, int x, int y, object **doorlist, int *ndoors, random_map_params *RP)
752 root 1.4 {
753     int i, j;
754 elmex 1.1 object *door;
755    
756     /* bounds check x and y */
757 root 1.4 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
758     return;
759 elmex 1.1
760     /* if the square is blocked or searched already, leave */
761 root 1.4 if (layout[x][y] == 1)
762     return;
763 elmex 1.1
764     /* check off this point */
765 root 1.4 if (layout[x][y] == '#')
766     { /* there could be a door here */
767     layout[x][y] = 1;
768     door = door_in_square (map, x, y);
769 root 1.13 if (door)
770 elmex 1.1 {
771 root 1.4 doorlist[*ndoors] = door;
772 root 1.13 if (*ndoors > 1022) /* eek! out of memory */
773 root 1.4 {
774     LOG (llevError, "find_doors_in_room_recursive:Too many doors for memory allocated!\n");
775     return;
776     }
777 root 1.13
778 root 1.4 *ndoors = *ndoors + 1;
779 elmex 1.1 }
780     }
781 root 1.4 else
782     {
783     layout[x][y] = 1;
784     /* now search all the 8 squares around recursively for free spots,in random order */
785     for (i = RANDOM () % 8, j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
786 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);
787 elmex 1.1 }
788     }
789    
790     /* find a random non-blocked spot in this room to drop a key. */
791 root 1.4 object **
792 root 1.12 find_doors_in_room (maptile *map, int x, int y, random_map_params *RP)
793 root 1.4 {
794 elmex 1.1 char **layout2;
795     object **doorlist;
796 root 1.4 int i, j;
797     int ndoors = 0;
798 elmex 1.1
799 root 1.13 doorlist = (object **) calloc (sizeof (int), 1024);
800 elmex 1.1
801 root 1.4 layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
802 elmex 1.1 /* allocate and copy the layout, converting C to 0. */
803 root 1.4 for (i = 0; i < RP->Xsize; i++)
804     {
805     layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
806     for (j = 0; j < RP->Ysize; j++)
807     {
808     if (wall_blocked (map, i, j))
809     layout2[i][j] = '#';
810     }
811 elmex 1.1 }
812 root 1.4
813     /* setup num_free_spots and room_free_spots */
814     find_doors_in_room_recursive (layout2, map, x, y, doorlist, &ndoors, RP);
815 elmex 1.1
816     /* deallocate the temp. layout */
817 root 1.4 for (i = 0; i < RP->Xsize; i++)
818 root 1.13 free (layout2[i]);
819    
820 root 1.4 free (layout2);
821 elmex 1.1 return doorlist;
822     }
823    
824    
825    
826     /* locks and/or hides all the doors in doorlist, or does nothing if
827 root 1.2 opts doesn't say to lock/hide doors. */
828 elmex 1.1
829 root 1.4 void
830 root 1.12 lock_and_hide_doors (object **doorlist, maptile *map, int opts, random_map_params *RP)
831 root 1.4 {
832 elmex 1.1 object *door;
833     int i;
834 root 1.4
835 elmex 1.1 /* lock the doors and hide the keys. */
836 root 1.4
837     if (opts & DOORED)
838     {
839     for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
840     {
841     object *new_door = get_archetype ("locked_door1");
842 root 1.13 char keybuf[1024];
843 root 1.4
844     door = doorlist[i];
845     new_door->face = door->face;
846     new_door->x = door->x;
847     new_door->y = door->y;
848 root 1.8 door->remove ();
849 root 1.9 door->destroy ();
850 root 1.4 doorlist[i] = new_door;
851     insert_ob_in_map (new_door, map, NULL, 0);
852     sprintf (keybuf, "%d", (int) RANDOM ());
853     new_door->slaying = keybuf;
854     keyplace (map, new_door->x, new_door->y, keybuf, NO_PASS_DOORS, 2, RP);
855     }
856 elmex 1.1 }
857    
858     /* change the faces of the doors and surrounding walls to hide them. */
859 root 1.4 if (opts & HIDDEN)
860     {
861     for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
862     {
863     object *wallface;
864    
865     door = doorlist[i];
866     wallface = retrofit_joined_wall (map, door->x, door->y, 1, RP);
867     if (wallface != NULL)
868     {
869     retrofit_joined_wall (map, door->x - 1, door->y, 0, RP);
870     retrofit_joined_wall (map, door->x + 1, door->y, 0, RP);
871     retrofit_joined_wall (map, door->x, door->y - 1, 0, RP);
872     retrofit_joined_wall (map, door->x, door->y + 1, 0, RP);
873     door->face = wallface->face;
874     if (!QUERY_FLAG (wallface, FLAG_REMOVED))
875 root 1.8 wallface->remove ();
876 root 1.9 wallface->destroy ();
877 root 1.4 }
878     }
879 elmex 1.1 }
880     }