ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.19
Committed: Wed Jan 17 12:36:31 2007 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.18: +47 -33 lines
Log Message:
fix possibly uninitialised kx,ky because find_free_spot does not seem to guarentee a result

File Contents

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