Atrinik Server  4.0
exit.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 #include <arch.h>
32 
49 void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
50 {
51  int M, x, y;
52 
53  *fx = -1;
54  *fy = -1;
55 
56  /* if a starting point isn't given, pick one */
57  if (mode < 1 || mode > 4) {
58  M = rndm(1, 4);
59  } else {
60  M = mode;
61  }
62 
63  /* four different search starting points and methods so that
64  * we can do something different for symmetrical maps instead of
65  * the same damned thing every time. */
66  switch (M) {
67  /* Search from top left down/right */
68  case 1:
69  {
70  for (x = 1; x < RP->Xsize; x++) {
71  for (y = 1; y < RP->Ysize; y++) {
72  if (layout[x][y] == target) {
73  *fx = x;
74  *fy = y;
75 
76  return;
77  }
78  }
79  }
80 
81  break;
82  }
83 
84  /* Search from top right down/left */
85  case 2:
86  {
87  for (x = RP->Xsize - 2; x > 0; x--) {
88  for (y = 1; y < RP->Ysize - 1; y++) {
89  if (layout[x][y] == target) {
90  *fx = x;
91  *fy = y;
92 
93  return;
94  }
95  }
96  }
97 
98  break;
99  }
100 
101  /* Search from bottom-left up-right */
102  case 3:
103  {
104  for (x = 1; x < RP->Xsize - 1; x++) {
105  for (y = RP->Ysize - 2; y > 0; y--) {
106  if (layout[x][y] == target) {
107  *fx = x;
108  *fy = y;
109 
110  return;
111  }
112  }
113  }
114 
115  break;
116  }
117 
118  /* Search from bottom-right up-left */
119  case 4:
120  {
121  for (x = RP->Xsize - 2; x > 0; x--) {
122  for (y = RP->Ysize - 2; y > 0; y--) {
123  if (layout[x][y] == target) {
124  *fx = x;
125  *fy = y;
126 
127  return;
128  }
129  }
130  }
131 
132  break;
133  }
134  }
135 }
136 
155 void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
156 {
157  mapstruct *style_map_down = NULL, *style_map_up = NULL;
158  object *the_exit_down;
159  object *the_exit_up;
160  /* magic mouth saying this is a random map. */
161  object *random_sign;
162  int cx = -1, cy = -1;
163  int upx = -1, upy = -1;
164  int downx = -1, downy = -1, j;
165 
166  if (orientation == 0) {
167  orientation = rndm(1, 3);
168  }
169 
170  switch (orientation) {
171  case 1:
172  style_map_up = find_style("/styles/exitstyles/up", exitstyle, -1);
173  style_map_down = find_style("/styles/exitstyles/down", exitstyle, -1);
174 
175  break;
176 
177  case 2:
178  style_map_up = find_style("/styles/exitstyles/down", exitstyle, -1);
179  style_map_down = find_style("/styles/exitstyles/up", exitstyle, -1);
180 
181  break;
182 
183  default:
184  style_map_up = find_style("/styles/exitstyles/generic", exitstyle, -1);
185  style_map_down = style_map_up;
186 
187  break;
188  }
189 
190  if (style_map_up == NULL) {
191  the_exit_up = arch_to_object(arch_find("exit"));
192  } else {
193  object *tmp = pick_random_object(style_map_up);
194  the_exit_up = arch_to_object(tmp->arch);
195  }
196 
197  /* we need a down exit only if we're recursing. */
198  if (RP->dungeon_level < RP->dungeon_depth || RP->final_map[0] != 0) {
199  if (style_map_down == NULL) {
200  the_exit_down = arch_to_object(arch_find("exit"));
201  } else {
202  object *tmp = pick_random_object(style_map_down);
203  the_exit_down = arch_to_object(tmp->arch);
204  }
205  } else {
206  the_exit_down = NULL;
207  }
208 
209  /* Set up the up exit */
210  the_exit_up->stats.hp = RP->origin_x;
211  the_exit_up->stats.sp = RP->origin_y;
212  FREE_AND_COPY_HASH(the_exit_up->slaying, RP->origin_map);
213 
214  /* figure out where to put the entrance */
215 
216  /* First, look for a '<' char */
217  find_in_layout(0, '<', &upx, &upy, maze, RP);
218 
219  /* next, look for a C, the map center. */
220  find_in_layout(0, 'C', &cx, &cy, maze, RP);
221 
222  /* If we didn't find an up, find an empty place far from the center */
223  if (upx == -1 && cx != -1) {
224  if (cx > RP->Xsize / 2) {
225  upx = 1;
226  } else {
227  upx = RP->Xsize - 2;
228  }
229 
230  if (cy > RP->Ysize / 2) {
231  upy = 1;
232  } else {
233  upy = RP->Ysize - 2;
234  }
235 
236  /* find an empty place far from the center */
237  if (upx == 1 && upy == 1) {
238  find_in_layout(1, 0, &upx, &upy, maze, RP);
239  } else if (upx == 1 && upy > 1) {
240  find_in_layout(3, 0, &upx, &upy, maze, RP);
241  } else if (upx > 1 && upy == 1) {
242  find_in_layout(2, 0, &upx, &upy, maze, RP);
243  } else if (upx > 1 && upy > 1) {
244  find_in_layout(4, 0, &upx, &upy, maze, RP);
245  }
246  }
247 
248  /* No indication of where to place the exit, so just place it. */
249  if (upx == -1) {
250  find_in_layout(0, 0, &upx, &upy, maze, RP);
251  }
252 
253  the_exit_up->x = upx;
254  the_exit_up->y = upy;
255 
256  /* Surround the exits with notices that this is a random map. */
257  for (j = 1; j < 9; j++) {
258  if (!wall_blocked(map, the_exit_up->x + freearr_x[j], the_exit_up->y + freearr_y[j])) {
259  char buf[MAX_BUF];
260 
261  random_sign = arch_get("sign");
262  random_sign->x = the_exit_up->x + freearr_x[j];
263  random_sign->y = the_exit_up->y + freearr_y[j];
264 
265  snprintf(buf, sizeof(buf), "This is a random map.\nLevel: %d\n", RP->dungeon_level);
266  FREE_AND_COPY_HASH(random_sign->msg, buf);
267  object_insert_map(random_sign, map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
268  }
269  }
270 
271  /* Block the exit so things don't get dumped on top of it. */
272  SET_FLAG(the_exit_up, FLAG_NO_PASS);
273  object_insert_map(the_exit_up, map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
274  maze[the_exit_up->x][the_exit_up->y] = '<';
275 
276  /* Set the starting x, y for this map */
277  MAP_ENTER_X(map) = the_exit_up->x;
278  MAP_ENTER_Y(map) = the_exit_up->y;
279 
280  /* First, look for a '>' character */
281  find_in_layout(0, '>', &downx, &downy, maze, RP);
282 
283  /* If no > is found use C */
284  if (downx == -1) {
285  downx = cx;
286  downy = cy;
287  }
288 
289  /* make the other exit far away from this one if
290  * there's no center. */
291  if (downx == -1) {
292  if (upx > RP->Xsize / 2) {
293  downx = 1;
294  } else {
295  downx = RP->Xsize - 2;
296  }
297 
298  if (upy > RP->Ysize / 2) {
299  downy = 1;
300  } else {
301  downy = RP->Ysize - 2;
302  }
303 
304  /* find an empty place far from the entrance */
305  if (downx == 1 && downy == 1) {
306  find_in_layout(1, 0, &downx, &downy, maze, RP);
307  } else if (downx == 1 && downy > 1) {
308  find_in_layout(3, 0, &downx, &downy, maze, RP);
309  } else if (downx > 1 && downy == 1) {
310  find_in_layout(2, 0, &downx, &downy, maze, RP);
311  } else if (downx > 1 && downy > 1) {
312  find_in_layout(4, 0, &downx, &downy, maze, RP);
313  }
314  }
315 
316  /* No indication of where to place the down exit, so just place it */
317  if (downx == -1) {
318  find_in_layout(0, 0, &downx, &downy, maze, RP);
319  }
320 
321  if (the_exit_down != NULL) {
322  int i = map_free_spot_first(map, downx,
323  downy, the_exit_down->arch, NULL);
324  if (i == -1) {
325  LOG(ERROR, "Could not find a free spot for exit going down.");
326  the_exit_down = NULL;
327  } else {
328  the_exit_down->x = downx + freearr_x[i];
329  the_exit_down->y = downy + freearr_y[i];
330  }
331  }
332 
333  if (the_exit_down != NULL) {
334  RP->origin_x = the_exit_down->x;
335  RP->origin_y = the_exit_down->y;
336 
337  /* the identifier for making a random map. */
338  if (RP->dungeon_level >= RP->dungeon_depth && RP->final_map[0] != '\0') {
339  mapstruct *new_map;
340  object *the_exit_back = arch_to_object(the_exit_up->arch), *tmp;
341 
342  /* load it */
343  if ((new_map = ready_map_name(RP->final_map, NULL, 0)) == NULL) {
344  return;
345  }
346 
347  FREE_AND_COPY_HASH(the_exit_down->slaying, RP->final_map);
348  FREE_AND_COPY_HASH(new_map->path, RP->final_map);
349  the_exit_down->stats.hp = MAP_ENTER_X(new_map);
350  the_exit_down->stats.sp = MAP_ENTER_Y(new_map);
351 
352  for (tmp = GET_MAP_OB(new_map, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map)); tmp; tmp = tmp->above) {
353  /* Remove exit back to previous random map. There should only
354  * be one
355  * which is why we break out. To try to process more than one
356  * would require keeping a 'next' pointer, ad free_object kills
357  * tmp, which
358  * breaks the for loop. */
359  if (tmp->type == EXIT) {
360  object_remove(tmp, 0);
361  object_destroy(tmp);
362  break;
363  }
364  }
365 
366  /* Setup the exit back */
367  FREE_AND_ADD_REF_HASH(the_exit_back->slaying, map->path);
368  the_exit_back->stats.hp = the_exit_down->x;
369  the_exit_back->stats.sp = the_exit_down->y;
370  the_exit_back->x = MAP_ENTER_X(new_map);
371  the_exit_back->y = MAP_ENTER_Y(new_map);
372 
373  object_insert_map(the_exit_back, new_map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
374 
375  /* So it gets swapped out */
376  set_map_timeout(new_map);
377  } else {
378  char buf[2048];
379 
381  FREE_AND_COPY_HASH(the_exit_down->msg, buf);
382  FREE_AND_COPY_HASH(the_exit_down->slaying, "/random/");
383  the_exit_down->stats.hp = 0;
384  the_exit_down->stats.sp = 0;
385  }
386 
387  /* Block the exit so things don't get dumped on top of it. */
388  SET_FLAG(the_exit_down, FLAG_NO_PASS);
389 
390  object_insert_map(the_exit_down, map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
391 
392  maze[the_exit_down->x][the_exit_down->y] = '>';
393  }
394 }
395 
406 void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
407 {
408  int x, y;
409  object *walk;
410 
411  for (x = 0; x < RP->Xsize; x++) {
412  for (y = 0; y < RP->Ysize; y++) {
413  if (maze[x][y] == '>' || maze[x][y] == '<') {
414  for (walk = GET_MAP_OB(map, x, y); walk != NULL; walk = walk->above) {
415  if (QUERY_FLAG(walk, FLAG_NO_PASS) && walk->type != DOOR) {
416  CLEAR_FLAG(walk, FLAG_NO_PASS);
418  }
419  }
420  }
421  }
422  }
423 }
#define FREE_AND_ADD_REF_HASH(_sv_, _nv_)
Definition: global.h:116
#define FREE_AND_COPY_HASH(_sv_, _nv_)
Definition: global.h:100
void object_destroy(object *ob)
Definition: object.c:1441
#define EXIT
Definition: define.h:312
#define MAP_ENTER_X(m)
Definition: map.h:129
char final_map[RM_SIZE]
Definition: random_map.h:62
shstr * path
Definition: map.h:568
void write_map_parameters_to_string(char *buf, RMParms *RP)
Definition: random_map.c:811
const char * slaying
Definition: object.h:180
object * arch_get(const char *name)
Definition: arch.c:430
struct obj * above
Definition: object.h:120
void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
Definition: exit.c:155
int16_t sp
Definition: living.h:78
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
struct archetype * arch
Definition: object.h:225
void object_remove(object *op, int flags)
Definition: object.c:1623
int32_t hp
Definition: living.h:72
void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
Definition: exit.c:406
int16_t y
Definition: object.h:276
void object_update(object *op, int action)
Definition: object.c:1117
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.c:169
#define SET_FLAG(xyz, p)
Definition: define.h:741
object * arch_to_object(archetype_t *at)
Definition: arch.c:446
#define INS_NO_WALK_ON
Definition: object.h:570
int dungeon_level
Definition: random_map.h:101
void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
Definition: exit.c:49
#define MAP_ENTER_Y(m)
Definition: map.h:131
object * pick_random_object(mapstruct *style)
Definition: style.c:286
int16_t x
Definition: object.h:273
int Ysize
Definition: random_map.h:77
object * object_insert_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1741
int Xsize
Definition: random_map.h:74
char origin_map[RM_SIZE]
Definition: random_map.h:59
#define INS_NO_MERGE
Definition: object.h:564
int origin_y
Definition: random_map.h:113
living stats
Definition: object.h:481
int dungeon_depth
Definition: random_map.h:104
int wall_blocked(mapstruct *m, int x, int y)
Definition: map.c:2479
int freearr_x[SIZEOFFREE]
Definition: object.c:84
uint8_t type
Definition: object.h:360
#define CLEAR_FLAG(xyz, p)
Definition: define.h:751
const char * msg
Definition: object.h:183
#define DOOR
Definition: define.h:194
#define FLAG_NO_PASS
Definition: define.h:908
int map_free_spot_first(mapstruct *m, int x, int y, archetype_t *at, object *op)
Definition: map.c:3009
mapstruct * ready_map_name(const char *name, mapstruct *originator, int flags)
Definition: map.c:1584
Definition: map.h:536
int origin_x
Definition: random_map.h:116
int freearr_y[SIZEOFFREE]
Definition: object.c:99
#define UP_OBJ_FLAGS
Definition: object.h:535
void set_map_timeout(mapstruct *map)
Definition: main.c:124
archetype_t * arch_find(const char *name)
Definition: arch.c:407