Atrinik Server  4.0
rogue_layout.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 
32 typedef struct {
33  /* coordinates of room centers */
34  int x;
35  int y;
36 
37  /* sizes */
38  int sx;
39  int sy;
40 
41  /* coordinates of extrema of the rectangle */
42  int ax, ay, zx, zy;
43 
44  /* Circle or rectangular */
45  int rtype;
46 } Room;
47 
48 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms);
49 static void roguelike_make_rooms(Room *Rooms, char **maze, int options);
50 static void roguelike_link_rooms(Room *Rooms, char **maze);
51 
71 int surround_check(char **layout, int i, int j, int Xsize, int Ysize)
72 {
73  int surround_index = 0;
74 
75  if ((i > 0) && (layout[i - 1][j] != 0 && layout[i - 1][j] != '.')) {
76  surround_index += 1;
77  }
78 
79  if ((i < Xsize - 1) && (layout[i + 1][j] != 0 && layout[i + 1][j] != '.')) {
80  surround_index += 2;
81  }
82 
83  if ((j > 0) && (layout[i][j - 1] != 0 && layout[i][j - 1] != '.')) {
84  surround_index += 4;
85  }
86 
87  if ((j < Ysize - 1) && (layout[i][j + 1] != 0 && layout[i][j + 1] != '.')) {
88  surround_index += 8;
89  }
90 
91  return surround_index;
92 }
93 
108 char **roguelike_layout_gen(int xsize, int ysize, int options)
109 {
110  int i, j = 0;
111  Room *Rooms = NULL, *walk;
112  int nrooms = 0;
113  int tries = 0;
114 
115  /* Allocate that array, write walls everywhere up */
116  char **maze = emalloc(sizeof(char *) * xsize);
117 
118  for (i = 0; i < xsize; i++) {
119  maze[i] = emalloc(sizeof(char) * ysize);
120 
121  for (j = 0; j < ysize; j++) {
122  maze[i][j] = '#';
123  }
124  }
125 
126  /* minimum room size is basically 5x5: if xsize/ysize is
127  * less than 3x that then hollow things out, stick in
128  * a stairsup and stairs down, and exit */
129  if (xsize < 11 || ysize < 11) {
130  for (i = 1; i < xsize - 1; i++) {
131  for (j = 1; j < ysize - 1; j++) {
132  maze[i][j] = 0;
133  }
134  }
135 
136  maze[i / 2][j / 2] = '>';
137  maze[i / 2][j / 2 + 1] = '<';
138 
139  return maze;
140  }
141 
142  /* decide on the number of rooms */
143  nrooms = RANDOM() % 10 + 6;
144  Rooms = ecalloc(nrooms + 1, sizeof(Room));
145 
146  /* Actually place the rooms */
147  i = 0;
148 
149  while (tries < 450 && i < nrooms) {
150  /* Try to place the room */
151  if (!roguelike_place_room(Rooms, xsize, ysize, nrooms)) {
152  tries++;
153  } else {
154  i++;
155  }
156  }
157 
158  /* no can do! */
159  if (i == 0) {
160  for (i = 1; i < xsize - 1; i++) {
161  for (j = 1; j < ysize - 1; j++) {
162  maze[i][j] = 0;
163  }
164  }
165 
166  maze[i / 2][j / 2] = '>';
167  maze[i / 2][j / 2 + 1] = '<';
168  efree(Rooms);
169 
170  return maze;
171  }
172 
173  /* Erase the areas occupied by the rooms */
174  roguelike_make_rooms(Rooms, maze, options);
175 
176  roguelike_link_rooms(Rooms, maze);
177 
178  /* Put in the stairs */
179  maze[Rooms->x][Rooms->y] = '<';
180 
181  /* Get the last one */
182  for (walk = Rooms; walk->x != 0; walk++) {
183  }
184 
185  /* Back up one */
186  walk--;
187 
188  maze[walk->x][walk->y] = '>';
189 
190  /* convert all the '.' to 0, we're through with the '.' */
191  for (i = 0; i < xsize; i++) {
192  for (j = 0; j < ysize; j++) {
193  if (maze[i][j] == '.') {
194  maze[i][j] = 0;
195  }
196 
197  /* Remove bad door. */
198  if (maze[i][j] == 'D') {
199  int si = surround_check(maze, i, j, xsize, ysize);
200 
201  if (si != 3 && si != 12) {
202  maze[i][j] = 0;
203 
204  /* back up and recheck any nearby doors */
205  i = 0;
206  j = 0;
207  }
208  }
209  }
210  }
211 
212  efree(Rooms);
213 
214  return maze;
215 }
216 
230 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms)
231 {
232  /* trial center locations */
233  int tx, ty;
234  /* trial sizes */
235  int sx, sy;
236  /* min coords of rect */
237  int ax, ay;
238  /* max coords of rect */
239  int zx, zy;
240  int x_basesize, y_basesize;
241  Room *walk;
242 
243  /* Decide on the base x and y sizes */
244  x_basesize = (int) (xsize / sqrt(nrooms));
245  y_basesize = (int) (ysize / sqrt(nrooms));
246 
247  tx = RANDOM() % xsize;
248  ty = RANDOM() % ysize;
249 
250  /* Generate a distribution of sizes centered about basesize */
251  sx = (RANDOM() % x_basesize) + (RANDOM() % x_basesize)+ (RANDOM() % x_basesize);
252  sy = (RANDOM() % y_basesize) + (RANDOM() % y_basesize)+ (RANDOM() % y_basesize);
253 
254  /* Renormalize */
255  sy = (int) (sy * 0.5);
256 
257  /* Find the corners */
258  ax = tx - sx / 2;
259  zx = tx + sx / 2 + sx % 2;
260 
261  ay = ty - sy / 2;
262  zy = ty + sy / 2 + sy % 2;
263 
264  /* Check to see if it's in the map */
265  if (zx > xsize - 1 || ax < 1) {
266  return 0;
267  }
268 
269  if (zy > ysize - 1 || ay < 1) {
270  return 0;
271  }
272 
273  /* No small fish */
274  if (sx < 3 || sy < 3) {
275  return 0;
276  }
277 
278  /* Check overlap with existing rooms */
279  for (walk = Rooms; walk->x != 0; walk++) {
280  int dx = abs(tx - walk->x), dy = abs(ty - walk->y);
281 
282  if ((dx < (walk->sx + sx) / 2 + 2) && (dy < (walk->sy + sy) / 2 + 2)) {
283  return 0;
284  }
285  }
286 
287  /* If we've got here, presumably the room is OK. */
288 
289  /* Get a pointer to the first free room */
290  for (walk = Rooms; walk->x != 0; walk++) {
291  }
292 
293  walk->x = tx;
294  walk->y = ty;
295  walk->sx = sx;
296  walk->sy = sy;
297  walk->ax = ax;
298  walk->ay = ay;
299  walk->zx = zx;
300  walk->zy = zy;
301 
302  /* success */
303  return 1;
304 }
305 
316 static void roguelike_make_rooms(Room *Rooms, char **maze, int options)
317 {
318  int making_circle = 0, i, j, R = 0;
319  Room *walk;
320 
321  for (walk = Rooms; walk->x != 0; walk++) {
322  /* First decide what shape to make */
323  switch (options) {
324  case 1:
325  making_circle = 0;
326  break;
327 
328  case 2:
329  making_circle = 1;
330  break;
331 
332  default:
333  making_circle = rndm_chance(3);
334 
335  if (walk->sx < walk->sy) {
336  R = walk->sx / 2;
337  } else {
338  R = walk->sy / 2;
339  }
340  }
341 
342  /* Enscribe a rectangle */
343  for (i = walk->ax; i < walk->zx; i++) {
344  for (j = walk->ay; j < walk->zy; j++) {
345  if (!making_circle || ((int) (0.5 + hypot(walk->x - i, walk->y - j))) <= R) {
346  maze[i][j] = '.';
347  }
348  }
349  }
350  }
351 }
352 
364 static void roguelike_link_rooms(Room *Rooms, char **maze)
365 {
366  Room *walk;
367  int i, j;
368 
369  /* Link each room to the previous room */
370  if (Rooms[1].x == 0) {
371  /* only 1 room */
372  return;
373  }
374 
375  for (walk = Rooms + 1; walk->x != 0; walk++) {
376  int x = walk->x, y = walk->y, x2 = (walk - 1)->x, y2 = (walk - 1)->y, in_wall = 0;
377 
378  /* Connect in x direction first */
379  if (rndm_chance(2)) {
380  /* horizontal connect */
381  /* swap (x1, y1) (x2, y2) if necessary */
382  if (x2 < x) {
383  int tx = x2, ty = y2;
384 
385  x2 = x;
386  y2 = y;
387  x = tx;
388  y = ty;
389  }
390 
391  j = y;
392 
393  for (i = x; i < x2; i++) {
394  if (in_wall == 0 && maze[i][j] == '#') {
395  in_wall = 1;
396  maze[i][j] = 'D';
397  } else if (in_wall && maze[i][j] == '.') {
398  in_wall = 0;
399  maze[i - 1][j] = 'D';
400  } else if (maze[i][j] != 'D' && maze[i][j] != '.') {
401  maze[i][j] = 0;
402  }
403  }
404 
405  j = MIN(y, y2);
406 
407  if (maze[i][j] == '.') {
408  in_wall = 0;
409  }
410 
411  if (maze[i][j] == 0 || maze[i][j] == '#') {
412  in_wall = 1;
413  }
414 
415  for (; j < MAX(y, y2); j++) {
416  if (in_wall == 0 && maze[i][j] == '#') {
417  in_wall = 1;
418  maze[i][j] = 'D';
419  } else if (in_wall && maze[i][j] == '.') {
420  in_wall = 0;
421  maze[i][j - 1] = 'D';
422  } else if (maze[i][j] != 'D' && maze[i][j] != '.') {
423  maze[i][j] = 0;
424  }
425  }
426  } else {
427  /* Connect in y direction first */
428 
429  in_wall = 0;
430 
431  /* Swap if necessary */
432  if (y2 < y) {
433  int tx = x2, ty = y2;
434 
435  x2 = x;
436  y2 = y;
437  x = tx;
438  y = ty;
439  }
440 
441  i = x;
442 
443  /* vertical connect */
444  for (j = y; j < y2; j++) {
445  if (in_wall == 0 && maze[i][j] == '#') {
446  in_wall = 1;
447  maze[i][j] = 'D';
448  } else if (in_wall && maze[i][j] == '.') {
449  in_wall = 0;
450  maze[i][j - 1] = 'D';
451  } else if (maze[i][j] != 'D' && maze[i][j] != '.') {
452  maze[i][j] = 0;
453  }
454  }
455 
456  i = MIN(x, x2);
457 
458  if (maze[i][j] == '.') {
459  in_wall = 0;
460  }
461 
462  if (maze[i][j] == 0 || maze[i][j] == '#') {
463  in_wall = 1;
464  }
465 
466  for (; i < MAX(x, x2); i++) {
467  if (in_wall == 0 && maze[i][j] == '#') {
468  in_wall = 1;
469  maze[i][j] = 'D';
470  } else if (in_wall && maze[i][j] == '.') {
471  in_wall = 0;
472  maze[i - 1][j] = 'D';
473  } else if (maze[i][j] != 'D' && maze[i][j] != '.') {
474  maze[i][j] = 0;
475  }
476  }
477  }
478  }
479 }
char ** roguelike_layout_gen(int xsize, int ysize, int options)
Definition: rogue_layout.c:108
static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms)
Definition: rogue_layout.c:230
static void roguelike_make_rooms(Room *Rooms, char **maze, int options)
Definition: rogue_layout.c:316
static void roguelike_link_rooms(Room *Rooms, char **maze)
Definition: rogue_layout.c:364
int surround_check(char **layout, int i, int j, int Xsize, int Ysize)
Definition: rogue_layout.c:71