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

Comparing deliantra/server/random_maps/layout.C (file contents):
Revision 1.2 by root, Wed Jun 30 23:03:40 2010 UTC vs.
Revision 1.4 by root, Thu Jul 1 01:27:14 2010 UTC

21 */ 21 */
22 22
23#include <global.h> 23#include <global.h>
24#include <random_map.h> 24#include <random_map.h>
25 25
26LayoutData::LayoutData (int w, int h) 26Layout::Layout (int w, int h)
27: w(w), h(h) 27: w(w), h(h)
28{ 28{
29 int size = (sizeof (char *) + sizeof (char) * h) * w; 29 int size = (sizeof (char *) + sizeof (char) * h) * w;
30 30
31 col = (char **)salloc<char> (size); 31 col = (char **)salloc<char> (size);
34 34
35 for (int x = w; x--; ) 35 for (int x = w; x--; )
36 col [x] = data + x * h; 36 col [x] = data + x * h;
37} 37}
38 38
39LayoutData::~LayoutData () 39Layout::~Layout ()
40{ 40{
41 int size = (sizeof (char *) + sizeof (char) * h) * w; 41 int size = (sizeof (char *) + sizeof (char) * h) * w;
42 42
43 sfree ((char *)col, size); 43 sfree ((char *)col, size);
44} 44}
45 45
46void 46void
47LayoutData::fill (char fill) 47Layout::fill (char fill)
48{ 48{
49 memset (col [0], fill, w * h); 49 memset (col [0], fill, w * h);
50} 50}
51 51
52void 52void
53LayoutData::rect (int x1, int y1, int x2, int y2, char fill) 53Layout::rect (int x1, int y1, int x2, int y2, char fill)
54{ 54{
55 for (; x1 < x2; ++x1) 55 for (; x1 < x2; ++x1)
56 memset (col [x1] + y1, fill, y2 - y1); 56 memset (col [x1] + y1, fill, y2 - y1);
57} 57}
58 58
59void LayoutData::border (char fill) 59void Layout::border (char fill)
60{ 60{
61 for (int i = 0; i < w; i++) col [i][0] = col [i][h - 1] = fill; 61 for (int i = 0; i < w; i++) col [i][0] = col [i][h - 1] = fill;
62 for (int j = 0; j < h; j++) col [0][j] = col [w - 1][j] = fill; 62 for (int j = 0; j < h; j++) col [0][j] = col [w - 1][j] = fill;
63} 63}
64 64
65void 65void
66LayoutData::fill_rand (int percent) 66Layout::fill_rand (int percent)
67{ 67{
68 percent = lerp (percent, 0, 100, 0, 256); 68 percent = lerp (percent, 0, 100, 0, 256);
69 69
70 for (int x = w - 1; --x > 0; ) 70 for (int x = w - 1; --x > 0; )
71 for (int y = h - 1; --y > 0; ) 71 for (int y = h - 1; --y > 0; )
74 74
75///////////////////////////////////////////////////////////////////////////// 75/////////////////////////////////////////////////////////////////////////////
76 76
77// erode by cellular automata 77// erode by cellular automata
78void 78void
79LayoutData::erode_1_2 (int c1, int c2, int repeat) 79Layout::erode_1_2 (int c1, int c2, int repeat)
80{ 80{
81 LayoutData neu (w, h); 81 Layout neu (w, h);
82 82
83 while (repeat--) 83 while (repeat--)
84 { 84 {
85 for (int x = 0; x < w; ++x) 85 for (int x = 0; x < w; ++x)
86 { 86 {
90 { 90 {
91 int n1 = 0, n2 = 0; 91 int n1 = 0, n2 = 0;
92 92
93 // a 5x5 area, dx, dy, distance (1 == <= 1, 0 <= 2) 93 // a 5x5 area, dx, dy, distance (1 == <= 1, 0 <= 2)
94 static I8 dds[][3] = { 94 static I8 dds[][3] = {
95 { -2, -1, 0 }, 95 { -2, -1, 0 }, { -2, 0, 0 }, { -2, 1, 0 },
96 { -2, 0, 0 }, 96 { -1, -2, 0 }, { -1, -1, 1 }, { -1, 0, 1 }, { -1, 1, 1 }, { -1, 2, 0 },
97 { -2, 1, 0 }, 97 { 0, -2, 0 }, { 0, -1, 1 }, { 0, 0, 1 }, { 0, 1, 1 }, { 0, 2, 0 },
98 98 { 1, -2, 0 }, { 1, -1, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 1, 2, 0 },
99 { -1, -2, 0 }, 99 { 2, -1, 0 }, { 2, 0, 0 }, { 2, 1, 0 },
100 { -1, -1, 1 },
101 { -1, 0, 1 },
102 { -1, 1, 1 },
103 { -1, 2, 0 },
104
105 { 0, -2, 0 },
106 { 0, -1, 1 },
107 { 0, 0, 1 },
108 { 0, 1, 1 },
109 { 0, 2, 0 },
110
111 { 1, -2, 0 },
112 { 1, -1, 1 },
113 { 1, 0, 1 },
114 { 1, 1, 1 },
115 { 1, 2, 0 },
116
117 { 2, -1, 0 },
118 { 2, 0, 0 },
119 { 2, 1, 0 },
120 }; 100 };
121 101
122 for (int i = array_length (dds); i--; ) 102 for (int i = array_length (dds); i--; )
123 { 103 {
124 int nx = x + dds [i][0]; 104 int nx = x + dds [i][0];
140} 120}
141 121
142///////////////////////////////////////////////////////////////////////////// 122/////////////////////////////////////////////////////////////////////////////
143 123
144void 124void
145LayoutData::print () 125Layout::print ()
146{ 126{
147 for (int y = 0; y < h; y++) 127 for (int y = 0; y < h; y++)
148 { 128 {
149 for (int x = 0; x < w; x++) 129 for (int x = 0; x < w; x++)
150 { 130 {
170// isolation remover - ensures single connected area 150// isolation remover - ensures single connected area
171 151
172typedef fixed_stack<point> pointlist; 152typedef fixed_stack<point> pointlist;
173 153
174static noinline void 154static noinline void
175push_flood_fill (LayoutData &maze, LayoutData &dist, pointlist &seeds, int x, int y) 155push_flood_fill (Layout &dist, pointlist &seeds, int x, int y)
176{ 156{
177 if (maze [x][y]) 157 if (dist [x][y])
178 return; 158 return;
179 159
180 while (y > 0 && !maze [x][y - 1]) 160 while (y > 0 && !dist [x][y - 1])
181 --y; 161 --y;
182 162
183 int y0 = y; 163 int y0 = y;
184 164
185 while (y < maze.h && !maze [x][y]) 165 while (y < dist.h && !dist [x][y])
186 { 166 {
187 seeds.push (point (x, y)); 167 seeds.push (point (x, y));
188 168
189 maze [x][y] = 1;
190 dist [x][y] = 1; 169 dist [x][y] = 1;
191 ++y; 170 ++y;
192 } 171 }
193 172
194 while (--y >= y0) 173 while (--y >= y0)
195 { 174 {
196 if (x > 0) push_flood_fill (maze, dist, seeds, x - 1, y); 175 if (x > 0) push_flood_fill (dist, seeds, x - 1, y);
197 if (x < maze.w - 1) push_flood_fill (maze, dist, seeds, x + 1, y); 176 if (x < dist.w - 1) push_flood_fill (dist, seeds, x + 1, y);
198 } 177 }
199} 178}
200 179
201static inline void 180static inline void
202make_tunnel (LayoutData &maze, LayoutData &dist, pointlist &seeds, int x, int y, U8 d) 181make_tunnel (Layout &dist, pointlist &seeds, int x, int y, U8 d)
203{ 182{
204 for (;;) 183 for (;;)
205 { 184 {
206 seeds.push (point (x, y));
207
208 maze [x][y] = 1;
209 dist [x][y] = 1;
210
211 if (x > 1 && U8 (dist [x - 1][y]) < d && dist [x - 1][y] > 1) 185 if (x > 1 && U8 (dist [x - 1][y]) < d && dist [x - 1][y] > 1)
212 --x; 186 --x;
213 else if (x < maze.w - 2 && U8 (dist [x + 1][y]) < d && dist [x + 1][y] > 1) 187 else if (x < dist.w - 2 && U8 (dist [x + 1][y]) < d && dist [x + 1][y] > 1)
214 ++x; 188 ++x;
215 else if (y > 1 && U8 (dist [x][y - 1]) < d && dist [x][y - 1] > 1) 189 else if (y > 1 && U8 (dist [x][y - 1]) < d && dist [x][y - 1] > 1)
216 --y; 190 --y;
217 else if (y < maze.h - 2 && U8 (dist [x][y + 1]) < d && dist [x][y + 1] > 1) 191 else if (y < dist.h - 2 && U8 (dist [x][y + 1]) < d && dist [x][y + 1] > 1)
218 ++y; 192 ++y;
219 else 193 else
220 break; 194 break;
221 195
222 d = dist [x][y]; 196 d = dist [x][y];
197 dist [x][y] = 1;
198 seeds.push (point (x, y));
223 } 199 }
200}
201
202static void inline
203maybe_push (Layout &dist, pointlist &seeds, int x, int y, U8 d)
204{
205 char &D = dist [x][y];
206
207 if (U8 (D) > d) // if wall and higher distance, lower distance
208 D = d;
209 else if (D) // otherwise, if it's no room, this space is uninteresting
210 return;
211
212 seeds.push (point (x, y));
224} 213}
225 214
226static void 215static void
227isolation_remover (LayoutData &maze, bool dirty) 216isolation_remover (Layout &maze, bool dirty)
228{ 217{
229 LayoutData dist (maze.w, maze.h); 218 Layout dist (maze.w, maze.h);
230 219
231 dist.fill (255); 220 // dist contains
221 // 0 == invisited rooms
222 // 1 == visited rooms
223 // 2+ shortest distance to random near room
232 224
225 // phase 1, initialise dist array, find seed
226 int cnt = 0;
227 int x, y;
228
229 for (int i = 0; i < maze.w; ++i)
230 for (int j = 0; j < maze.h; ++j)
231 {
232 if (maze [i][j] == '#')
233 dist [i][j] = U8 (255);
234 else
235 {
236 dist [i][j] = 0;
237 if (!rmg_rndm (++cnt))
238 x = i, y = j;
239 }
240 }
241
242 if (!cnt)
243 return;
244
233 fixed_stack<point> seeds (maze.w * maze.h * 4); 245 fixed_stack<point> seeds (maze.w * maze.h * 5);
234 246
235 // phase 1, find seed 247 // found first free space - picking the first one gives
236 for (int x = 1; x < maze.w; ++x) 248 // us a slight bias for tunnels, but usually you won't
237 for (int y = 1; y < maze.h; ++y) 249 // notice that in-game
250 seeds.push (point (x, y));
251
252 // phase 2, while we have seeds, if
253 // seed is empty, floodfill, else grow
254
255 while (seeds.size)
256 {
257 coroapi::cede_to_tick ();
258
259 point p = seeds.remove (rmg_rndm (seeds.size));
260
261 x = p.x;
262 y = p.y;
263
238 if (!maze [x][y]) 264 if (!dist [x][y])
239 { 265 {
240 // found first free space - picking the first one gives
241 // us a slight bias for tunnels, but usually you won't
242 // notice that in-game
243 seeds.push (point (x, y));
244
245 // phase 2, while we have seeds, if
246 // seed is empty, floodfill, else grow
247
248 while (seeds.size)
249 {
250 coroapi::cede_to_tick ();
251
252 point p = seeds.remove (rmg_rndm (seeds.size));
253
254 x = p.x;
255 y = p.y;
256
257 if (!maze [x][y])
258 {
259 // found new isolated area, make tunnel? 266 // found new isolated area, make tunnel
260 if (!dirty) 267 if (!dirty)
261 push_flood_fill (maze, dist, seeds, x, y); 268 push_flood_fill (dist, seeds, x, y);
262 269
263 make_tunnel (maze, dist, seeds, x, y, 255); 270 make_tunnel (dist, seeds, x, y, 255);
264 271
265 if (dirty) 272 if (dirty)
266 push_flood_fill (maze, dist, seeds, x, y); 273 push_flood_fill (dist, seeds, x, y);
267 }
268 else
269 {
270 U8 d = U8 (dist [x][y]) + 1;
271
272 if (x < maze.w - 1 && U8 (dist [x + 1][y]) > d)
273 {
274 dist [x + 1][y] = d;
275 seeds.push (point (x + 1, y));
276 }
277
278 if (x > 0 && U8 (dist [x - 1][y]) > d)
279 {
280 dist [x - 1][y] = d;
281 seeds.push (point (x - 1, y));
282 }
283
284 if (y < maze.h - 1 && U8 (dist [x][y + 1]) > d)
285 {
286 dist [x][y + 1] = d;
287 seeds.push (point (x, y + 1));
288 }
289
290 if (y > 0 && U8 (dist [x][y - 1]) > d)
291 {
292 dist [x][y - 1] = d;
293 seeds.push (point (x, y - 1));
294 }
295 }
296 }
297
298 goto success;
299 } 274 }
275 else
276 {
277 // nothing here, continue to expand
278 U8 d = U8 (dist [x][y]) + 1;
300 279
301success: 280 if (x < dist.w - 1) maybe_push (dist, seeds, x + 1, y, d);
281 if (x > 0) maybe_push (dist, seeds, x - 1, y, d);
282 if (y < dist.h - 1) maybe_push (dist, seeds, x, y + 1, d);
283 if (y > 0) maybe_push (dist, seeds, x, y - 1, d);
284 }
285 }
302 286
303 // we mark free but visited floors as 1, undo this here 287 // now copy the tunnels over
304 for (int x = 0; x < maze.w; ++x) 288 for (int x = 0; x < maze.w; ++x)
305 for (int y = 0; y < maze.h; ++y) 289 for (int y = 0; y < maze.h; ++y)
306 if (maze [x][y] == 1) 290 if (maze [x][y] == '#' && dist [x][y] == 1)
307 maze [x][y] = 0; 291 maze [x][y] = 0;
308} 292}
309 293
310void 294void
311LayoutData::isolation_remover (bool dirty) 295Layout::isolation_remover (bool dirty)
312{ 296{
313 ::isolation_remover (*this, dirty); 297 ::isolation_remover (*this, dirty);
314} 298}
315 299
316///////////////////////////////////////////////////////////////////////////// 300/////////////////////////////////////////////////////////////////////////////
317 301
318// inspired mostly by http://www.jimrandomh.org/misc/caves.txt 302// inspired mostly by http://www.jimrandomh.org/misc/caves.txt
319void 303void
320LayoutData::gen_cave (int subtype) 304Layout::gen_cave (int subtype)
321{ 305{
322 switch (subtype) 306 switch (subtype)
323 { 307 {
324 // a rough cave 308 // a rough cave
325 case 0: 309 case 0:
361 Layout maze (40, 25); 345 Layout maze (40, 25);
362 rmg_rndm.seed (time (0)); 346 rmg_rndm.seed (time (0));
363 347
364 for(int i=1;i<10;i) 348 for(int i=1;i<10;i)
365 { 349 {
366 maze->gen_cave (3); 350 maze.fill_rand (97);
351 maze.border ();
352 maze.isolation_remover ();
367 maze->print (); 353 maze.print ();
368 } 354 }
369 355
370 exit (1); 356 exit (1);
371 } 357 }
372} demo; 358} demo;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines