ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
(Generate patch)

Comparing deliantra/server/random_maps/treasure.C (file contents):
Revision 1.1 by elmex, Sun Aug 13 17:16:03 2006 UTC vs.
Revision 1.42 by root, Thu Sep 25 04:35:50 2008 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines