Crossfire Server, Branches 1.12  R18729
rogue_layout.c
Go to the documentation of this file.
1 
6 #include <global.h>
7 #include <random_map.h>
8 #include <math.h>
9 
10 typedef struct {
11  int x;
12  int y; /* coordinates of room centers */
13 
14  int sx;
15  int sy; /* sizes */
16  int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */
17 
18  int rtype; /* circle or rectangular */
19 } Room;
20 
21 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms);
22 static void roguelike_make_rooms(Room *Rooms, char **maze, int options);
23 static void roguelike_link_rooms(Room *Rooms, char **maze, int xsize, int ysize);
24 
44 int surround_check(char **layout, int i, int j, int Xsize, int Ysize) {
45  int surround_index = 0;
46 
47  if ((i > 0) && (layout[i-1][j] != 0 && layout[i-1][j] != '.'))
48  surround_index += 1;
49  if ((i < Xsize-1) && (layout[i+1][j] != 0 && layout[i+1][j] != '.'))
50  surround_index += 2;
51  if ((j > 0) && (layout[i][j-1] != 0 && layout[i][j-1] != '.'))
52  surround_index += 4;
53  if ((j < Ysize-1) && (layout[i][j+1] != 0 && layout[i][j+1] != '.'))
54  surround_index += 8;
55  return surround_index;
56 }
57 
69 char **roguelike_layout_gen(int xsize, int ysize, int options) {
70  int i, j;
71  Room *Rooms = NULL;
72  Room *walk;
73  int nrooms = 0;
74  int tries = 0;
75 
76  /* allocate that array, write walls everywhere up */
77  char **maze = (char **)malloc(sizeof(char *)*xsize);
78  for (i = 0; i < xsize; i++) {
79  maze[i] = (char *)malloc(sizeof(char)*ysize);
80  for (j = 0; j < ysize; j++)
81  maze[i][j] = '#';
82  }
83 
84  /* minimum room size is basically 5x5: if xsize/ysize is
85  less than 3x that then hollow things out, stick in
86  a stairsup and stairs down, and exit */
87 
88  if (xsize < 11 || ysize < 11) {
89  for (i = 1; i < xsize-1; i++)
90  for (j = 1; j < ysize-1; j++)
91  maze[i][j] = 0;
92  maze[(xsize-1)/2][(ysize-1)/2] = '>';
93  maze[(xsize-1)/2][(ysize-1)/2+1] = '<';
94  return maze;
95  }
96 
97  /* decide on the number of rooms */
98  nrooms = RANDOM()%10+6;
99  Rooms = (Room *)calloc(nrooms+1, sizeof(Room));
100 
101  /* actually place the rooms */
102  i = 0;
103  while (tries < 450 && i < nrooms) {
104  /* try to place the room */
105  if (!roguelike_place_room(Rooms, xsize, ysize, nrooms))
106  tries++;
107  else
108  i++;
109  }
110 
111  if (i == 0) { /* no can do! */
112  for (i = 1; i < xsize-1; i++)
113  for (j = 1; j < ysize-1; j++)
114  maze[i][j] = 0;
115  maze[(xsize-1)/2][(ysize-1)/2] = '>';
116  maze[(xsize-1)/2][(ysize-1)/2+1] = '<';
117  free(Rooms);
118  return maze;
119  }
120 
121  /* erase the areas occupied by the rooms */
122  roguelike_make_rooms(Rooms, maze, options);
123 
124  roguelike_link_rooms(Rooms, maze, xsize, ysize);
125 
126  /* put in the stairs */
127 
128  maze[Rooms->x][Rooms->y] = '<';
129  /* get the last one */
130  for (walk = Rooms; walk->x != 0; walk++)
131  ;
132  /* back up one */
133  walk--;
134  if (walk == Rooms) {
135  /* In this case, there is only a single room. We don't want to
136  * clobber are up exit (above) with a down exit, so put the
137  * other exit one space up/down, depending which is a space
138  * and not a wall.
139  */
140  if (maze[walk->x][walk->y+1] == '.')
141  maze[walk->x][walk->y+1] = '>';
142  else
143  maze[walk->x][walk->y-1] = '>';
144  } else
145  maze[walk->x][walk->y] = '>';
146 
147  /* convert all the '.' to 0, we're through with the '.' */
148  for (i = 0; i < xsize; i++)
149  for (j = 0; j < ysize; j++) {
150  if (maze[i][j] == '.')
151  maze[i][j] = 0;
152  if (maze[i][j] == 'D') { /* remove bad door. */
153  int si = surround_check(maze, i, j, xsize, ysize);
154 
155  if (si != 3 && si != 12) {
156  maze[i][j] = 0;
157  /* back up and recheck any nearby doors */
158  i = 0;
159  j = 0;
160  }
161  }
162  }
163 
164  free(Rooms);
165  return maze;
166 }
167 
180 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms) {
181  int tx, ty; /* trial center locations */
182  int sx, sy; /* trial sizes */
183  int ax, ay; /* min coords of rect */
184  int zx, zy; /* max coords of rect */
185  int x_basesize;
186  int y_basesize;
187  Room *walk;
188 
189  /* decide on the base x and y sizes */
190 
191  x_basesize = xsize/isqrt(nrooms);
192  y_basesize = ysize/isqrt(nrooms);
193 
194 
195  tx = RANDOM()%xsize;
196  ty = RANDOM()%ysize;
197 
198  /* generate a distribution of sizes centered about basesize */
199  sx = (RANDOM()%x_basesize)+(RANDOM()%x_basesize)+(RANDOM()%x_basesize);
200  sy = (RANDOM()%y_basesize)+(RANDOM()%y_basesize)+(RANDOM()%y_basesize);
201  sy = (int)(sy*.5); /* renormalize */
202 
203  /* find the corners */
204  ax = tx-sx/2;
205  zx = tx+sx/2+sx%2;
206 
207  ay = ty-sy/2;
208  zy = ty+sy/2+sy%2;
209 
210  /* check to see if it's in the map */
211  if (zx > xsize-1 || ax < 1)
212  return 0;
213  if (zy > ysize-1 || ay < 1)
214  return 0;
215 
216  /* no small fish */
217  if (sx < 3 || sy < 3)
218  return 0;
219 
220  /* check overlap with existing rooms */
221  for (walk = Rooms; walk->x != 0; walk++) {
222  int dx = abs(tx-walk->x);
223  int dy = abs(ty-walk->y);
224 
225  if ((dx < (walk->sx+sx)/2+2) && (dy < (walk->sy+sy)/2+2))
226  return 0;
227  }
228 
229  /* if we've got here, presumably the room is OK. */
230 
231  /* get a pointer to the first free room */
232  for (walk = Rooms; walk->x != 0; walk++)
233  ;
234  walk->x = tx;
235  walk->y = ty;
236  walk->sx = sx;
237  walk->sy = sy;
238  walk->ax = ax;
239  walk->ay = ay;
240  walk->zx = zx;
241  walk->zy = zy;
242  return 1; /* success */
243 }
244 
254 static void roguelike_make_rooms(Room *Rooms, char **maze, int options) {
255  int making_circle = 0;
256  int i, j;
257  int R;
258  Room *walk;
259 
260  for (walk = Rooms; walk->x != 0; walk++) {
261  /* first decide what shape to make */
262  switch (options) {
263  case 1:
264  making_circle = 0;
265  break;
266 
267  case 2:
268  making_circle = 1;
269  break;
270 
271  default:
272  making_circle = ((RANDOM()%3 == 0) ? 1 : 0);
273  break;
274  }
275 
276  if (walk->sx < walk->sy)
277  R = walk->sx/2;
278  else
279  R = walk->sy/2;
280 
281  /* enscribe a rectangle or a circle */
282  for (i = walk->ax; i < walk->zx; i++)
283  for (j = walk->ay; j < walk->zy; j++) {
284  if (!making_circle || ((int)(0.5+hypot(walk->x-i, walk->y-j))) <= R)
285  maze[i][j] = '.';
286  }
287  }
288 }
289 
300 static void roguelike_link_rooms(Room *Rooms, char **maze, int xsize, int ysize) {
301  Room *walk;
302  int i, j;
303 
304  /* link each room to the previous room */
305  if (Rooms[1].x == 0)
306  return; /* only 1 room */
307 
308  for (walk = Rooms+1; walk->x != 0; walk++) {
309  int x1 = walk->x;
310  int y1 = walk->y;
311  int x2 = (walk-1)->x;
312  int y2 = (walk-1)->y;
313  int in_wall = 0;
314 
315  if (RANDOM()%2) { /* connect in x direction first */
316  /* horizontal connect */
317  /* swap (x1,y1) (x2,y2) if necessary */
318 
319  if (x2 < x1) {
320  int tx = x2, ty = y2;
321  x2 = x1;
322  y2 = y1;
323  x1 = tx;
324  y1 = ty;
325  }
326 
327  j = y1;
328  for (i = x1; i < x2; i++) {
329  if (in_wall == 0 && maze[i][j] == '#') {
330  in_wall = 1;
331  maze[i][j] = 'D';
332  } else if (in_wall && maze[i][j] == '.') {
333  in_wall = 0;
334  maze[i-1][j] = 'D';
335  } else if (maze[i][j] != 'D' && maze[i][j] != '.')
336  maze[i][j] = 0;
337  }
338  j = MIN(y1, y2);
339  if (maze[i][j] == '.')
340  in_wall = 0;
341  if (maze[i][j] == 0 || maze[i][j] == '#')
342  in_wall = 1;
343  for (/* j set already */; j < MAX(y1, y2); j++) {
344  if (in_wall == 0 && maze[i][j] == '#') {
345  in_wall = 1;
346  maze[i][j] = 'D';
347  } else if (in_wall && maze[i][j] == '.') {
348  in_wall = 0;
349  maze[i][j-1] = 'D';
350  } else if (maze[i][j] != 'D' && maze[i][j] != '.')
351  maze[i][j] = 0;
352  }
353  } else { /* connect in y direction first */
354  in_wall = 0;
355  /* swap if necessary */
356  if (y2 < y1) {
357  int tx = x2, ty = y2;
358  x2 = x1;
359  y2 = y1;
360  x1 = tx;
361  y1 = ty;
362  }
363  i = x1;
364  /* vertical connect */
365  for (j = y1; j < y2; j++) {
366  if (in_wall == 0 && maze[i][j] == '#') {
367  in_wall = 1;
368  maze[i][j] = 'D';
369  } else if (in_wall && maze[i][j] == '.') {
370  in_wall = 0;
371  maze[i][j-1] = 'D';
372  } else if (maze[i][j] != 'D' && maze[i][j] != '.')
373  maze[i][j] = 0;
374  }
375 
376  i = MIN(x1, x2);
377  if (maze[i][j] == '.')
378  in_wall = 0;
379  if (maze[i][j] == 0 || maze[i][j] == '#')
380  in_wall = 1;
381  for (/* i set already */; i < MAX(x1, x2); i++) {
382  if (in_wall == 0 && maze[i][j] == '#') {
383  in_wall = 1;
384  maze[i][j] = 'D';
385  } else if (in_wall && maze[i][j] == '.') {
386  in_wall = 0;
387  maze[i-1][j] = 'D';
388  } else
389  if (maze[i][j] != 'D' && maze[i][j] != '.')
390  maze[i][j] = 0;
391 
392  }
393  }
394  }
395 }
char ** roguelike_layout_gen(int xsize, int ysize, int options)
Definition: rogue_layout.c:69
int sy
Definition: rogue_layout.c:15
static void roguelike_link_rooms(Room *Rooms, char **maze, int xsize, int ysize)
Definition: rogue_layout.c:300
static struct Command_Line_Options options[]
Definition: init.c:234
int rtype
Definition: rogue_layout.c:18
static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms)
Definition: rogue_layout.c:180
int ax
Definition: rogue_layout.c:16
int sx
Definition: rogue_layout.c:14
static void roguelike_make_rooms(Room *Rooms, char **maze, int options)
Definition: rogue_layout.c:254
int ay
Definition: rogue_layout.c:16
#define MAX(x, y)
Definition: define.h:70
#define MIN(x, y)
Definition: define.h:67
int zy
Definition: rogue_layout.c:16
int zx
Definition: rogue_layout.c:16
int x
Definition: rogue_layout.c:11
int y
Definition: rogue_layout.c:12
int isqrt(int n)
Definition: porting.c:573
int surround_check(char **layout, int i, int j, int Xsize, int Ysize)
Definition: rogue_layout.c:44