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.8 by root, Fri Jul 2 15:43:37 2010 UTC vs.
Revision 1.12 by root, Sat Jul 3 01:49:18 2010 UTC

23 23
24#include <global.h> 24#include <global.h>
25#include <random_map.h> 25#include <random_map.h>
26#include <rproto.h> 26#include <rproto.h>
27 27
28void
28layout::layout (int w, int h) 29layout::alloc (int w, int h)
29: w(w), h(h)
30{ 30{
31 assert (sizeof (cell) == 1); 31 assert (sizeof (cell) == 1);
32
33 this->w = w;
34 this->h = h;
32 35
33 // we store the layout in a single contiguous memory layout 36 // we store the layout in a single contiguous memory layout
34 // first part consists of pointers to each column, followed 37 // first part consists of pointers to each column, followed
35 // by the actual columns (not rows!) 38 // by the actual columns (not rows!)
36 int size = (sizeof (cell *) + sizeof (cell) * h) * w; 39 int size = (sizeof (cell *) + sizeof (cell) * h) * w;
41 44
42 for (int x = w; x--; ) 45 for (int x = w; x--; )
43 data [x] = p + x * h; 46 data [x] = p + x * h;
44} 47}
45 48
49layout::layout (int w, int h)
50{
51 alloc (w, h);
52}
53
54layout::layout (layout &copy)
55{
56 alloc (copy.w, copy.h);
57
58 memcpy (data [0], copy.data [0], sizeof (cell) * h * w);
59}
60
46layout::~layout () 61layout::~layout ()
47{ 62{
48 int size = (sizeof (cell *) + sizeof (cell) * h) * w; 63 int size = (sizeof (cell *) + sizeof (cell) * h) * w;
49 64
50 sfree ((char *)data, size); 65 sfree ((char *)data, size);
56 memset (data [0], fill, w * h); 71 memset (data [0], fill, w * h);
57} 72}
58 73
59void 74void
60layout::rect (int x1, int y1, int x2, int y2, char fill) 75layout::rect (int x1, int y1, int x2, int y2, char fill)
76{
77 --x2;
78
79 memset (data [x1] + y1, fill, y2 - y1);
80 memset (data [x2] + y1, fill, y2 - y1);
81
82 while (++x1 < x2)
83 data [x1][y1] = data [x1][y2 - 1] = fill;
84}
85
86void
87layout::fill_rect (int x1, int y1, int x2, int y2, char fill)
61{ 88{
62 for (; x1 < x2; ++x1) 89 for (; x1 < x2; ++x1)
63 memset (data [x1] + y1, fill, y2 - y1); 90 memset (data [x1] + y1, fill, y2 - y1);
64} 91}
65 92
66void layout::border (char fill) 93void layout::border (char fill)
67{ 94{
68 for (int i = 0; i < w; i++) data [i][0] = data [i][h - 1] = fill; 95 rect (0, 0, w, h, fill);
69 for (int j = 0; j < h; j++) data [0][j] = data [w - 1][j] = fill;
70} 96}
71 97
72void 98void
73layout::fill_rand (int percent) 99layout::fill_rand (int percent)
74{ 100{
156///////////////////////////////////////////////////////////////////////////// 182/////////////////////////////////////////////////////////////////////////////
157// isolation remover - ensures single connected area 183// isolation remover - ensures single connected area
158 184
159typedef fixed_stack<point> pointlist; 185typedef fixed_stack<point> pointlist;
160 186
161static noinline void 187static void noinline
162push_flood_fill (layout &dist, pointlist &seeds, int x, int y) 188push_flood_fill (layout &dist, pointlist &seeds, int x, int y)
163{ 189{
164 if (dist [x][y]) 190 if (dist [x][y])
165 return; 191 return;
166 192
177 ++y; 203 ++y;
178 } 204 }
179 205
180 while (--y >= y0) 206 while (--y >= y0)
181 { 207 {
182 if (x > 0) push_flood_fill (dist, seeds, x - 1, y); 208 if (x > 0 && !dist [x - 1][y]) push_flood_fill (dist, seeds, x - 1, y);
183 if (x < dist.w - 1) push_flood_fill (dist, seeds, x + 1, y); 209 if (x < dist.w - 1 && !dist [x + 1][y]) push_flood_fill (dist, seeds, x + 1, y);
184 } 210 }
185} 211}
186 212
187static inline void 213static inline void
188make_tunnel (layout &dist, pointlist &seeds, int x, int y, U8 d) 214make_tunnel (layout &dist, pointlist &seeds, int x, int y, U8 d)
189{ 215{
190 for (;;) 216 for (;;)
191 { 217 {
218 point neigh[4];
219 int ncnt = 0;
220
192 if (x > 1 && U8 (dist [x - 1][y]) < d && dist [x - 1][y] > 1) 221 if (x > 1 && U8 (dist [x - 1][y]) <= d && dist [x - 1][y] > 1) neigh [ncnt++] = point (x - 1, y);
193 --x;
194 else if (x < dist.w - 2 && U8 (dist [x + 1][y]) < d && dist [x + 1][y] > 1) 222 if (x < dist.w - 2 && U8 (dist [x + 1][y]) <= d && dist [x + 1][y] > 1) neigh [ncnt++] = point (x + 1, y);
195 ++x;
196 else if (y > 1 && U8 (dist [x][y - 1]) < d && dist [x][y - 1] > 1) 223 if (y > 1 && U8 (dist [x][y - 1]) <= d && dist [x][y - 1] > 1) neigh [ncnt++] = point (x, y - 1);
197 --y;
198 else if (y < dist.h - 2 && U8 (dist [x][y + 1]) < d && dist [x][y + 1] > 1) 224 if (y < dist.h - 2 && U8 (dist [x][y + 1]) <= d && dist [x][y + 1] > 1) neigh [ncnt++] = point (x, y + 1);
199 ++y; 225
200 else 226 printf ("tunnel %d+%d ncnt %d\n", x, y, ncnt);//D
227
228 if (!ncnt)
201 break; 229 return;
230
231 point &p = neigh [rmg_rndm (ncnt)];
232
233 seeds.push (p);
234
235 x = p.x;
236 y = p.y;
202 237
203 d = dist [x][y]; 238 d = dist [x][y];
204 dist [x][y] = 1; 239 dist [x][y] = 1;
205 seeds.push (point (x, y));
206 } 240 }
207} 241}
208 242
209static void inline 243static void inline
210maybe_push (layout &dist, pointlist &seeds, int x, int y, U8 d) 244maybe_push (layout &dist, pointlist &seeds, int x, int y, U8 d)
217 return; 251 return;
218 252
219 seeds.push (point (x, y)); 253 seeds.push (point (x, y));
220} 254}
221 255
222void 256// isolation remover, works on a "distance" map
223layout::isolation_remover (bool dirty) 257// the map must be initialised with 0 == rooms, 255 = walls
258static void noinline
259isolation_remover (layout &dist)
224{ 260{
225 layout dist (w, h);
226
227 // dist contains 261 // dist contains
228 // 0 == invisited rooms 262 // 0 == invisited rooms
229 // 1 == visited rooms 263 // 1 == visited rooms
230 // 2+ shortest distance to random near room 264 // 2+ shortest distance to random near room
231 265
232 // phase 1, initialise dist array, find seed 266 // phase 1, find seed
233 int cnt = 0; 267 int cnt = 0;
234 int x, y; 268 int x, y;
235 269
236 for (int i = 0; i < w; ++i) 270 for (int i = 0; i < dist.w; ++i)
237 for (int j = 0; j < h; ++j) 271 for (int j = 0; j < dist.h; ++j)
238 { 272 if (!dist [i][j] && !rmg_rndm (++cnt))
239 if (data [i][j] == '#')
240 dist [i][j] = U8 (255);
241 else
242 {
243 dist [i][j] = 0;
244 if (!rmg_rndm (++cnt))
245 x = i, y = j; 273 x = i, y = j;
246 }
247 }
248 274
249 if (!cnt) 275 if (!cnt)
250 { 276 {
251 // map is completely massive, this is not good, 277 // map is completely massive, this is not good,
252 // so make it empty instead. 278 // so make it empty instead.
253 clear (); 279 dist.fill (1);
254 border (); 280 dist.border (255);
255 return; 281 return;
256 } 282 }
257 283
258 fixed_stack<point> seeds (w * h * 5); 284 fixed_stack<point> seeds (dist.w * dist.h * 5);
259 285
260 // found first free space - picking the first one gives 286 // found first free space - picking the first one gives
261 // us a slight bias for tunnels, but usually you won't 287 // us a slight bias for tunnels, but usually you won't
262 // notice that in-game 288 // notice that in-game
263 seeds.push (point (x, y)); 289 seeds.push (point (x, y));
275 y = p.y; 301 y = p.y;
276 302
277 if (!dist [x][y]) 303 if (!dist [x][y])
278 { 304 {
279 // found new isolated area, make tunnel 305 // found new isolated area, make tunnel
280 if (!dirty)
281 push_flood_fill (dist, seeds, x, y); 306 push_flood_fill (dist, seeds, x, y);
282
283 make_tunnel (dist, seeds, x, y, 255); 307 make_tunnel (dist, seeds, x, y, 255);
284
285 if (dirty)
286 push_flood_fill (dist, seeds, x, y);
287 } 308 }
288 else 309 else
289 { 310 {
290 // nothing here, continue to expand 311 // nothing here, continue to expand
291 U8 d = U8 (dist [x][y]) + 1; 312 U8 d = U8 (dist [x][y]) + 1;
292 313
293 if (x < dist.w - 1) maybe_push (dist, seeds, x + 1, y, d); 314 if (x < dist.w - 2) maybe_push (dist, seeds, x + 1, y, d);
294 if (x > 0) maybe_push (dist, seeds, x - 1, y, d); 315 if (x > 1) maybe_push (dist, seeds, x - 1, y, d);
295 if (y < dist.h - 1) maybe_push (dist, seeds, x, y + 1, d); 316 if (y < dist.h - 2) maybe_push (dist, seeds, x, y + 1, d);
296 if (y > 0) maybe_push (dist, seeds, x, y - 1, d); 317 if (y > 1) maybe_push (dist, seeds, x, y - 1, d);
297 } 318 }
298 } 319 }
320}
321
322void
323layout::isolation_remover ()
324{
325 layout dist (w, h);
326
327 for (int x = 1; x < w - 1; ++x)
328 for (int y = 1; y < h - 1; ++y)
329 dist [x][y] = data [x][y] == '#' ? U8 (255) : 0;
330
331 ::isolation_remover (dist);
299 332
300 // now copy the tunnels over 333 // now copy the tunnels over
301 for (int x = 0; x < w; ++x) 334 for (int x = 1; x < w - 1; ++x)
302 for (int y = 0; y < h; ++y) 335 for (int y = 1; y < h - 1; ++y)
303 if (data [x][y] == '#' && dist [x][y] == 1) 336 if (data [x][y] == '#' && dist [x][y] == 1)
304 data [x][y] = 0; 337 data [x][y] = 0;
305} 338}
306 339
307///////////////////////////////////////////////////////////////////////////// 340/////////////////////////////////////////////////////////////////////////////
312{ 345{
313 switch (subtype) 346 switch (subtype)
314 { 347 {
315 // a rough cave 348 // a rough cave
316 case 0: 349 case 0:
317 fill_rand (rmg_rndm (80, 95)); 350 fill_rand (rmg_rndm (85, 97));
318 break; 351 break;
319 352
320 // corridors 353 // corridors
321 case 1: 354 case 1:
322 fill_rand (rmg_rndm (5, 40)); 355 fill_rand (rmg_rndm (5, 40));
865{ 898{
866 demo () 899 demo ()
867 { 900 {
868 rmg_rndm.seed (time (0)); 901 rmg_rndm.seed (time (0));
869 902
870 for(int i=1;i<10;i) 903 for(int i=1;i<100;i++)
871 { 904 {
872 layout maze (10, 10); 905 layout maze (40, 25);
873 maze.fill_rand (90); 906 maze.fill_rand (85);
874 maze.border (); 907 maze.border ();
875 maze.isolation_remover (); 908 maze.isolation_remover ();
876 maze.doorify ();
877 maze.symmetrize (rmg_rndm (2, 4));
878 maze.rotate (rmg_rndm (4));
879 maze.expand2x ();
880 maze.print (); 909 maze.print ();
881 } 910 }
882 911
883 exit (1); 912 exit (1);
884 } 913 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines