--- deliantra/server/random_maps/layout.C 2010/07/04 01:01:42 1.21 +++ deliantra/server/random_maps/layout.C 2018/11/17 23:40:02 1.34 @@ -1,31 +1,32 @@ /* * This file is part of Deliantra, the Roguelike Realtime MMORPG. - * - * Copyright (©) 2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team - * Copyright (©) Crossfire Development Team (restored, original file without copyright notice) - * + * + * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team + * Copyright (©) 2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team + * Copyright (©) 1994-2004 Crossfire Development Team (restored, original file without copyright notice) + * * Deliantra is free software: you can redistribute it and/or modify it under * the terms of the Affero GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the Affero GNU General Public License * and the GNU General Public License along with this program. If not, see * . - * + * * The authors can be reached via e-mail to */ #include -#include +#include #include -void +ecb_noinline void layout::alloc (int w, int h) { assert (sizeof (cell) == 1); @@ -76,14 +77,23 @@ sfree ((char *)data, size); } -void +ecb_noinline void layout::fill (char fill) { //memset (data [0], fill, w * h); // only when contiguous :/ fill_rect (0, 0, w, h, fill); } -void +ecb_noinline void +layout::replace (char from, char to) +{ + for (int x = 0; x < w; ++x) + for (int y = 0; y < h; ++y) + if (data [x][y] == from) + data [x][y] = to; +} + +ecb_noinline void layout::rect (int x1, int y1, int x2, int y2, char fill) { --x2; @@ -95,32 +105,33 @@ data [x1][y1] = data [x1][y2 - 1] = fill; } -void +ecb_noinline void layout::fill_rect (int x1, int y1, int x2, int y2, char fill) { for (; x1 < x2; ++x1) memset (data [x1] + y1, fill, y2 - y1); } -void layout::border (char fill) +void +layout::border (char fill) { rect (0, 0, w, h, fill); } -void +ecb_noinline void layout::fill_rand (int percent) { percent = lerp (percent, 0, 100, 0, 256); - for (int x = w - 1; --x > 0; ) - for (int y = h - 1; --y > 0; ) + for (int x = 0; x < w; ++x) + for (int y = 0; y < h; ++y) data [x][y] = rmg_rndm (256) > percent ? 0 : '#'; } ///////////////////////////////////////////////////////////////////////////// // erode by cellular automata -void +ecb_noinline void layout::erode_1_2 (int c1, int c2, int repeat) { layout neu (w, h); @@ -196,7 +207,7 @@ typedef fixed_stack pointlist; -static void noinline +ecb_noinline static void push_flood_fill (layout &dist, pointlist &seeds, int x, int y) { if (dist [x][y]) @@ -222,7 +233,7 @@ } } -static inline void +static void inline make_tunnel (layout &dist, pointlist &seeds, int x, int y, U8 d, int perturb) { for (;;) @@ -267,7 +278,7 @@ // isolation remover, works on a "distance" map // the map must be initialised with 0 == rooms, 255 = walls -static void noinline +ecb_noinline static void isolation_remover (layout &dist, unsigned int perturb = 2) { // dist contains @@ -304,11 +315,17 @@ // phase 2, while we have seeds, if // seed is empty, floodfill, else grow + int rem_index = 0; // used to remove "somewhat ordered" + while (seeds.size) { coroapi::cede_to_tick (); - point p = seeds.remove (rmg_rndm (seeds.size)); + int i = perturb + ? rmg_rndm (max (0, seeds.size - 8), seeds.size - 1) + : rem_index ++ % seeds.size; + + point p = seeds.remove (i); x = p.x; y = p.y; @@ -360,6 +377,8 @@ { int ndoors = w * h / 60; /* reasonable number of doors. */ + coroapi::cede_to_tick (); + fixed_stack doorloc (w * h); /* make a list of possible door locations */ @@ -451,6 +470,8 @@ void layout::rotate (int rotation) { + coroapi::cede_to_tick (); + switch (rotation & 3) { case 2: /* a reflection */ @@ -515,7 +536,7 @@ * 4 match on (i+1, j+1) * and the possible combinations thereof. */ -static int noinline +ecb_noinline static int calc_pattern (char ch, layout &maze, int i, int j) { int pattern = 0; @@ -612,12 +633,14 @@ new_layout.clear (); + coroapi::cede_to_tick (); + for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) switch (data [i][j]) { - case '#': expand_wall (new_layout, i, j, *this); break; - case 'D': expand_door (new_layout, i, j, *this); break; + case '#': expand_wall (new_layout, i, j, *this); break; + case 'D': expand_door (new_layout, i, j, *this); break; default: expand_misc (new_layout, i, j, *this); break; } @@ -703,7 +726,7 @@ } int -make_wall (char **maze, int x, int y, int dir) +make_wall (layout &maze, int x, int y, int dir) { maze[x][y] = 'D'; /* mark a door */ @@ -731,6 +754,8 @@ { int tries = w * h / 30; + coroapi::cede_to_tick (); + for (int ti = 0; ti < tries; ti++) { /* starting location for looking at creating a door */ @@ -831,21 +856,14 @@ static void gen_mixed_ (layout &maze, random_map_params *RP) { - int dir; - - if (maze.w < 20 && maze.h < 20 && !rmg_rndm (3)) - dir = 2; // stop recursion randomly - else - dir = maze.w > maze.h; - - if (dir == 0 && maze.w > 16) + if (maze.w > maze.h && maze.w > 16) { int m = rmg_rndm (8, maze.w - 8); layout m1 (maze, 0, 0, m , maze.h); gen_mixed_ (m1, RP); layout m2 (maze, m, 0, maze.w, maze.h); gen_mixed_ (m2, RP); } - else if (dir == 1 && maze.h > 16) + else if (maze.h > 16) { int m = rmg_rndm (8, maze.h - 8); @@ -861,6 +879,8 @@ maze.generate (RP); } + + coroapi::cede_to_tick (); } // recursive subdivision with random sublayouts @@ -872,6 +892,11 @@ delete &rp; maze.border (); + + // exits currently do not work so well, as they + // are currently often found together, so nuke entrances + maze.replace ('<', ' '); + maze.isolation_remover (0); } @@ -991,14 +1016,15 @@ demo () { rmg_rndm.seed (time (0)); + extern void hack();hack (); for(int i=1;i<100;i++) { layout maze (40, 30); - gen_village (maze); - maze.doorify (); + maze.fill_rand (99); + maze.border (); + maze.isolation_remover (2); maze.print (); - exit(0); } exit (1);