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

Comparing deliantra/server/random_maps/random_map.C (file contents):
Revision 1.59 by root, Thu Jul 1 01:22:44 2010 UTC vs.
Revision 1.60 by root, Fri Jul 2 03:40:14 2010 UTC

28#include <random_map.h> 28#include <random_map.h>
29#include <rproto.h> 29#include <rproto.h>
30#include <sproto.h> 30#include <sproto.h>
31 31
32#define CEDE coroapi::cede_to_tick () 32#define CEDE coroapi::cede_to_tick ()
33
34static void symmetrize_layout (Layout &maze, random_map_params *RP);
35static void rotate_layout (Layout &maze, int rotation);
36 33
37noinline SV * 34noinline SV *
38random_map_params::get_sv (const char *option) const 35random_map_params::get_sv (const char *option) const
39{ 36{
40 SV **he = hv_fetch (hv, option, strlen (option), 0); 37 SV **he = hv_fetch (hv, option, strlen (option), 0);
169random_map_params::~random_map_params () 166random_map_params::~random_map_params ()
170{ 167{
171 SvREFCNT_dec (hv); 168 SvREFCNT_dec (hv);
172} 169}
173 170
174/* takes a map and makes it symmetric: adjusts Xsize and
175 * Ysize to produce a symmetric map.
176 */
177static void
178symmetrize_layout (Layout &layout, random_map_params *RP)
179{
180 if (RP->symmetry_used == SYMMETRY_NONE)
181 return;
182
183 Layout sym_layout (
184 RP->symmetry_used == SYMMETRY_X || RP->symmetry_used == SYMMETRY_XY ? layout.w * 2 - 3 : layout.w,
185 RP->symmetry_used == SYMMETRY_Y || RP->symmetry_used == SYMMETRY_XY ? layout.h * 2 - 3 : layout.h
186 );
187
188 if (RP->symmetry_used == SYMMETRY_X)
189 for (int i = 0; i < sym_layout.w / 2 + 1; i++)
190 for (int j = 0; j < sym_layout.h; j++)
191 {
192 sym_layout[i ][j] =
193 sym_layout[sym_layout.w - i - 1][j] = layout[i][j];
194 }
195
196 if (RP->symmetry_used == SYMMETRY_Y)
197 for (int i = 0; i < sym_layout.w; i++)
198 for (int j = 0; j < sym_layout.h / 2 + 1; j++)
199 {
200 sym_layout[i][j ] =
201 sym_layout[i][sym_layout.h - j - 1] = layout[i][j];
202 }
203
204 if (RP->symmetry_used == SYMMETRY_XY)
205 for (int i = 0; i < sym_layout.w / 2 + 1; i++)
206 for (int j = 0; j < sym_layout.h / 2 + 1; j++)
207 {
208 sym_layout[i ][j ] =
209 sym_layout[i ][sym_layout.h - j - 1] =
210 sym_layout[sym_layout.w - i - 1][j ] =
211 sym_layout[sym_layout.w - i - 1][sym_layout.h - j - 1] = layout[i][j];
212 }
213
214 /* need to run the isolation remover for some layouts */
215 switch (RP->map_layout_style)
216 {
217 case LAYOUT_ONION:
218 case LAYOUT_SNAKE:
219 case LAYOUT_SQUARE_SPIRAL:
220 // safe
221 break;
222
223 default:
224 sym_layout.isolation_remover ();
225 break;
226 }
227
228 layout.swap (sym_layout);
229}
230
231/* takes a map and rotates it. This completes the
232 onion layouts, making them possibly centered on any wall.
233 It'll modify Xsize and Ysize if they're swapped.
234*/
235static void
236rotate_layout (Layout &layout, int rotation)
237{
238 int w = layout.w;
239 int h = layout.h;
240
241 switch (rotation)
242 {
243 case 2: /* a reflection */
244 {
245 Layout new_layout (w, h);
246
247 for (int i = 0; i < w; i++) /* copy a reflection back */
248 for (int j = 0; j < h; j++)
249 new_layout[i][j] = layout[w - i - 1][h - j - 1];
250
251 layout.swap (new_layout);
252 }
253 break;
254
255 case 1:
256 case 3:
257 {
258 Layout new_layout (h, w);
259
260 if (rotation == 1) /* swap x and y */
261 for (int i = 0; i < w; i++)
262 for (int j = 0; j < h; j++)
263 new_layout[j][i] = layout[i][j];
264
265 if (rotation == 3) /* swap x and y */
266 for (int i = 0; i < w; i++)
267 for (int j = 0; j < h; j++)
268 new_layout[j][i] = layout[w - i - 1][h - j - 1];
269
270 layout.swap (new_layout);
271 }
272 break;
273 }
274}
275
276/* checks the layout to see if I can stick a horizontal(dir = 0) wall
277 (or vertical, dir == 1)
278 here which ends up on other walls sensibly. */
279static int
280can_make_wall (char **maze, int dx, int dy, int dir, random_map_params *RP)
281{
282 int i1;
283 int length = 0;
284
285 /* dont make walls if we're on the edge. */
286 if (dx == 0 || dx == (RP->Xsize - 1) || dy == 0 || dy == (RP->Ysize - 1))
287 return -1;
288
289 /* don't make walls if we're ON a wall. */
290 if (maze[dx][dy] != 0)
291 return -1;
292
293 if (dir == 0) /* horizontal */
294 {
295 int y = dy;
296
297 for (i1 = dx - 1; i1 > 0; i1--)
298 {
299 int sindex = surround_flag2 (maze, i1, y, RP);
300
301 if (sindex == 1)
302 break;
303 if (sindex != 0)
304 return -1; /* can't make horiz. wall here */
305 if (maze[i1][y] != 0)
306 return -1; /* can't make horiz. wall here */
307 length++;
308 }
309
310 for (i1 = dx + 1; i1 < RP->Xsize - 1; i1++)
311 {
312 int sindex = surround_flag2 (maze, i1, y, RP);
313
314 if (sindex == 2)
315 break;
316 if (sindex != 0)
317 return -1; /* can't make horiz. wall here */
318 if (maze[i1][y] != 0)
319 return -1; /* can't make horiz. wall here */
320 length++;
321 }
322 return length;
323 }
324 else
325 { /* vertical */
326 int x = dx;
327
328 for (i1 = dy - 1; i1 > 0; i1--)
329 {
330 int sindex = surround_flag2 (maze, x, i1, RP);
331
332 if (sindex == 4)
333 break;
334 if (sindex != 0)
335 return -1; /* can't make vert. wall here */
336 if (maze[x][i1] != 0)
337 return -1; /* can't make horiz. wall here */
338 length++;
339 }
340
341 for (i1 = dy + 1; i1 < RP->Ysize - 1; i1++)
342 {
343 int sindex = surround_flag2 (maze, x, i1, RP);
344
345 if (sindex == 8)
346 break;
347 if (sindex != 0)
348 return -1; /* can't make verti. wall here */
349 if (maze[x][i1] != 0)
350 return -1; /* can't make horiz. wall here */
351 length++;
352 }
353
354 return length;
355 }
356
357 return -1;
358}
359
360/* take a layout and make some rooms in it.
361 --works best on onions.*/
362static void
363roomify_layout (char **maze, random_map_params *RP)
364{
365 int tries = RP->Xsize * RP->Ysize / 30;
366
367 for (int ti = 0; ti < tries; ti++)
368 {
369 /* starting location for looking at creating a door */
370 int dx = rmg_rndm (RP->Xsize);
371 int dy = rmg_rndm (RP->Ysize);
372
373 /* results of checking on creating walls. */
374 int cx = can_make_wall (maze, dx, dy, 0, RP); /* horizontal */
375 int cy = can_make_wall (maze, dx, dy, 1, RP); /* vertical */
376
377 if (cx == -1)
378 {
379 if (cy != -1)
380 make_wall (maze, dx, dy, 1);
381
382 continue;
383 }
384
385 if (cy == -1)
386 {
387 make_wall (maze, dx, dy, 0);
388 continue;
389 }
390
391 if (cx < cy)
392 make_wall (maze, dx, dy, 0);
393 else
394 make_wall (maze, dx, dy, 1);
395 }
396}
397
398int
399make_wall (char **maze, int x, int y, int dir)
400{
401 maze[x][y] = 'D'; /* mark a door */
402
403 switch (dir)
404 {
405 case 0: /* horizontal */
406 {
407 for (int i1 = x - 1; maze[i1][y] == 0; --i1) maze[i1][y] = '#';
408 for (int i1 = x + 1; maze[i1][y] == 0; ++i1) maze[i1][y] = '#';
409 break;
410 }
411 case 1: /* vertical */
412 {
413 for (int i1 = y - 1; maze[x][i1] == 0; --i1) maze[x][i1] = '#';
414 for (int i1 = y + 1; maze[x][i1] == 0; ++i1) maze[x][i1] = '#';
415 break;
416 }
417 }
418
419 return 0;
420}
421
422/* puts doors at appropriate locations in a layout. */
423static void
424doorify_layout (char **maze, random_map_params *RP)
425{
426 int ndoors = RP->Xsize * RP->Ysize / 60; /* reasonable number of doors. */
427 int doorlocs = 0; /* # of available doorlocations */
428
429 uint16 *doorlist_x = salloc<uint16> (RP->Xsize * RP->Ysize);
430 uint16 *doorlist_y = salloc<uint16> (RP->Xsize * RP->Ysize);
431
432 /* make a list of possible door locations */
433 for (int i = 1; i < RP->Xsize - 1; i++)
434 for (int j = 1; j < RP->Ysize - 1; j++)
435 {
436 int sindex = surround_flag (maze, i, j, RP);
437
438 if (sindex == 3 || sindex == 12) /* these are possible door sindex */
439 {
440 doorlist_x[doorlocs] = i;
441 doorlist_y[doorlocs] = j;
442 doorlocs++;
443 }
444 }
445
446 while (ndoors > 0 && doorlocs > 0)
447 {
448 int di = rmg_rndm (doorlocs);
449 int i = doorlist_x[di];
450 int j = doorlist_y[di];
451 int sindex = surround_flag (maze, i, j, RP);
452
453 if (sindex == 3 || sindex == 12) /* these are possible door sindex */
454 {
455 maze[i][j] = 'D';
456 ndoors--;
457 }
458
459 /* reduce the size of the list */
460 doorlocs--;
461 doorlist_x[di] = doorlist_x[doorlocs];
462 doorlist_y[di] = doorlist_y[doorlocs];
463 }
464
465 sfree (doorlist_x, RP->Xsize * RP->Ysize);
466 sfree (doorlist_y, RP->Xsize * RP->Ysize);
467}
468
469/* function selects the layout function and gives it whatever
470 arguments it needs. */
471void
472Layout::generate (random_map_params *RP)
473{
474 switch (RP->map_layout_style)
475 {
476 case LAYOUT_ONION:
477 map_gen_onion (*this, RP->layoutoptions1, RP->layoutoptions2);
478
479 if (!(rmg_rndm (3)) && !(RP->layoutoptions1 & (RMOPT_WALLS_ONLY | RMOPT_WALL_OFF)))
480 roomify_layout (*this, RP);
481
482 break;
483
484 case LAYOUT_MAZE:
485 maze_gen (*this, RP->get_iv ("maze_type", rmg_rndm (4)));
486
487 if (!(rmg_rndm (2)))
488 doorify_layout (*this, RP);
489
490 break;
491
492 case LAYOUT_SPIRAL:
493 map_gen_spiral (*this, RP->layoutoptions1);
494
495 if (!(rmg_rndm (2)))
496 doorify_layout (*this, RP);
497
498 break;
499
500 case LAYOUT_ROGUELIKE:
501 /* Don't put symmetry in rogue maps. There isn't much reason to
502 * do so in the first place (doesn't make it any more interesting),
503 * but more importantly, the symmetry code presumes we are symmetrizing
504 * spirals, or maps with lots of passages - making a symmetric rogue
505 * map fails because its likely that the passages the symmetry process
506 * creates may not connect the rooms.
507 */
508 RP->symmetry_used = SYMMETRY_NONE;
509 roguelike_layout_gen (*this, RP->layoutoptions1);
510 /* no doorifying... done already */
511 break;
512
513 case LAYOUT_SNAKE:
514 make_snake_layout (*this, RP->layoutoptions1);
515
516 if (rmg_rndm (2))
517 roomify_layout (*this, RP);
518
519 break;
520
521 case LAYOUT_SQUARE_SPIRAL:
522 make_square_spiral_layout (*this, RP->layoutoptions1);
523
524 if (rmg_rndm (2))
525 roomify_layout (*this, RP);
526
527 break;
528
529 case LAYOUT_CAVE:
530 gen_cave (RP->get_iv ("cave_type", rmg_rndm (4)));
531
532 if (!(rmg_rndm (2)))
533 doorify_layout (*this, RP);
534
535 break;
536
537 default:
538 abort ();
539 }
540
541 /* rotate the layout randomly */
542 rotate_layout (*this, rmg_rndm (4));
543
544 symmetrize_layout (*this, RP);
545
546#if 0
547 print ();//D
548#endif
549
550 if (RP->expand2x)
551 expand2x (*this);
552}
553
554bool 171bool
555maptile::generate_random_map (random_map_params *RP) 172maptile::generate_random_map (random_map_params *RP)
556{ 173{
557 RP->Xsize = RP->xsize; 174 RP->Xsize = RP->xsize;
558 RP->Ysize = RP->ysize; 175 RP->Ysize = RP->ysize;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines