Crossfire Server, Trunk
exit.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
14 #include "global.h"
15 
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include "random_map.h"
20 #include "rproto.h"
21 #include "sproto.h"
22 
47 void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
48 {
49  int M;
50  int i, j;
51 
52  *fx = -1;
53  *fy = -1;
54 
55  /* if a starting mode isn't given, pick one */
56  if (mode < 1 || mode > 4) {
57  M = RANDOM()%4+1;
58  } else {
59  M = mode;
60  }
61 
62  /* four different search starting points and methods so that
63  we can do something different for symmetrical maps instead of
64  the same damned thing every time. */
65  switch (M) {
66  case 1: { /* search from top left down/right */
67  for (i = 1; i < RP->Xsize; i++)
68  for (j = 1; j < RP->Ysize; j++) {
69  if (layout[i][j] == target) {
70  *fx = i;
71  *fy = j;
72  return;
73  }
74  }
75  break;
76  }
77 
78  case 2: { /* Search from top right down/left */
79  for (i = RP->Xsize-2; i > 0; i--)
80  for (j = 1; j < RP->Ysize-1; j++) {
81  if (layout[i][j] == target) {
82  *fx = i;
83  *fy = j;
84  return;
85  }
86  }
87  break;
88  }
89 
90  case 3: { /* search from bottom-left up-right */
91  for (i = 1; i < RP->Xsize-1; i++)
92  for (j = RP->Ysize-2; j > 0; j--) {
93  if (layout[i][j] == target) {
94  *fx = i;
95  *fy = j;
96  return;
97  }
98  }
99  break;
100  }
101 
102  case 4: { /* search from bottom-right up-left */
103  for (i = RP->Xsize-2; i > 0; i--)
104  for (j = RP->Ysize-2; j > 0; j--) {
105  if (layout[i][j] == target) {
106  *fx = i;
107  *fy = j;
108  return;
109  }
110  }
111  break;
112  }
113  }
114 }
115 
116 /* orientation:
117 */
118 
144 void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
145 {
146  char styledirname[256];
147  mapstruct *style_map_down = NULL; /* harder maze */
148  mapstruct *style_map_up = NULL; /* easier maze */
149  object *the_exit_down; /* harder maze */
150  object *the_exit_up; /* easier maze */
151  object *random_sign; /* magic mouth saying this is a random map. */
152  char buf[512];
153  int cx = -1, cy = -1; /* location of a map center */
154  int upx = -1, upy = -1; /* location of up exit */
155  int downx = -1, downy = -1;
156  int final_map_exit = 1;
157  int i, j;
158 
159  if (strstr(RP->exit_on_final_map, "no")) {
160  final_map_exit = 0;
161  }
162 
163  if (orientation == 0) {
164  orientation = RANDOM()%6+1;
165  }
166 
167  switch (orientation) {
168  case 1: {
169  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/up");
170  style_map_up = find_style(styledirname, exitstyle, -1);
171  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/down");
172  style_map_down = find_style(styledirname, exitstyle, -1);
173  break;
174  }
175 
176  case 2: {
177  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/down");
178  style_map_up = find_style(styledirname, exitstyle, -1);
179  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/up");
180  style_map_down = find_style(styledirname, exitstyle, -1);
181  break;
182  }
183 
184  default: {
185  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/generic");
186  style_map_up = find_style(styledirname, exitstyle, -1);
187  style_map_down = style_map_up;
188  break;
189  }
190  }
191 
192  if (style_map_up == NULL) {
193  archetype *exit_arch = find_archetype("exit");
194  if (exit_arch == NULL) {
195  return;
196  }
197  the_exit_up = arch_to_object(exit_arch);
198  } else {
199  object *tmp;
200 
201  tmp = pick_random_object(style_map_up);
202  the_exit_up = arch_to_object(tmp->arch);
203  }
204 
205  /* we need a down exit only if we're recursing. */
206  if (RP->dungeon_level < RP->dungeon_depth || RP->final_map[0] != 0)
207  if (RP->dungeon_level >= RP->dungeon_depth && RP->final_exit_archetype[0] != 0) {
209  if (arch == NULL) {
210  return;
211  }
212  the_exit_down = arch_to_object(arch);
213  } else if (style_map_down == NULL) {
214  archetype *arch = find_archetype("exit");
215  if (arch == NULL) {
216  return;
217  }
218  the_exit_down = arch_to_object(arch);
219  } else {
220  object *tmp;
221 
222  tmp = pick_random_object(style_map_down);
223  the_exit_down = arch_to_object(tmp->arch);
224  }
225  else {
226  the_exit_down = NULL;
227  }
228 
229  /* set up the up exit */
230  the_exit_up->stats.hp = RP->origin_x;
231  the_exit_up->stats.sp = RP->origin_y;
232  the_exit_up->slaying = add_string(RP->origin_map);
233 
234  /* figure out where to put the entrance */
235  /* First, look for a '<' char */
236  find_in_layout(0, '<', &upx, &upy, maze, RP);
237 
238  /* next, look for a C, the map center. */
239  find_in_layout(0, 'C', &cx, &cy, maze, RP);
240 
241  /* if we didn't find an up, find an empty place far from the center */
242  if (upx == -1 && cx != -1) {
243  if (cx > RP->Xsize/2) {
244  upx = 1;
245  } else {
246  upx = RP->Xsize-2;
247  }
248  if (cy > RP->Ysize/2) {
249  upy = 1;
250  } else {
251  upy = RP->Ysize-2;
252  }
253 
254  /* find an empty place far from the center */
255  if (upx == 1 && upy == 1) {
256  find_in_layout(1, 0, &upx, &upy, maze, RP);
257  } else if (upx == 1 && upy > 1) {
258  find_in_layout(3, 0, &upx, &upy, maze, RP);
259  } else if (upx > 1 && upy == 1) {
260  find_in_layout(2, 0, &upx, &upy, maze, RP);
261  } else if (upx > 1 && upy > 1) {
262  find_in_layout(4, 0, &upx, &upy, maze, RP);
263  }
264  }
265 
266  /* no indication of where to place the exit, so just place it at any empty spot. */
267  if (upx == -1) {
268  find_in_layout(0, 0, &upx, &upy, maze, RP);
269  }
270 
271  /* surround the exits with notices that this is a random map. */
272  for (j = 1; j < 9; j++) {
273  if (!wall_blocked(map, upx+freearr_x[j], upy+freearr_y[j])) {
274  random_sign = create_archetype("sign");
275 
276  snprintf(buf, sizeof(buf), "This is a random map.\nLevel: %d\n", (RP->dungeon_level)-1);
277  object_set_msg(random_sign, buf);
278  object_insert_in_map_at(random_sign, map, NULL, 0, upx+freearr_x[j], upy+freearr_y[j]);
279  }
280  }
281  /* Block the exit so things don't get dumped on top of it. */
282  the_exit_up->move_block = MOVE_ALL;
283 
284  object_insert_in_map_at(the_exit_up, map, NULL, 0, upx, upy);
285  maze[upx][upy] = '<';
286 
287  /* set the starting x,y for this map */
288  MAP_ENTER_X(map) = upx;
289  MAP_ENTER_Y(map) = upy;
290 
291  /* first, look for a '>' character */
292  find_in_layout(0, '>', &downx, &downy, maze, RP);
293  /* if no > is found use C */
294  if (downx == -1) {
295  downx = cx;
296  downy = cy;
297  }
298 
299  /* make the other exit far away from this one if
300  there's no center. */
301  if (downx == -1) {
302  if (upx > RP->Xsize/2) {
303  downx = 1;
304  } else {
305  downx = RP->Xsize-2;
306  }
307  if (upy > RP->Ysize/2) {
308  downy = 1;
309  } else {
310  downy = RP->Ysize-2;
311  }
312 
313  /* find an empty place far from the entrance */
314  if (downx == 1 && downy == 1) {
315  find_in_layout(1, 0, &downx, &downy, maze, RP);
316  } else if (downx == 1 && downy > 1) {
317  find_in_layout(3, 0, &downx, &downy, maze, RP);
318  } else if (downx > 1 && downy == 1) {
319  find_in_layout(2, 0, &downx, &downy, maze, RP);
320  } else if (downx > 1 && downy > 1) {
321  find_in_layout(4, 0, &downx, &downy, maze, RP);
322  }
323  }
324  /* no indication of where to place the down exit, so just place it on an empty spot. */
325  if (downx == -1) {
326  find_in_layout(0, 0, &downx, &downy, maze, RP);
327  }
328  if (the_exit_down) {
329  char *buf;
330 
331  i = object_find_first_free_spot(the_exit_down, map, downx, downy);
332  RP->origin_x = downx+freearr_x[i];
333  RP->origin_y = downy+freearr_y[i];
335  object_set_msg(the_exit_down, buf);
336  free(buf);
337  /* the identifier for making a random map. */
338  if (RP->dungeon_level >= RP->dungeon_depth && RP->final_map[0] != 0) {
339  /* Next map is the final map, special case. */
340  mapstruct *new_map;
341  object *the_exit_back = arch_to_object(the_exit_up->arch);
342 
343  /* load it */
344  if ((new_map = ready_map_name(RP->final_map, 0)) == NULL) {
345  return;
346  }
347 
348  the_exit_down->slaying = add_string(RP->final_map);
349  EXIT_X(the_exit_down) = MAP_ENTER_X(new_map);
350  EXIT_Y(the_exit_down) = MAP_ENTER_Y(new_map);
351  strncpy(new_map->path, RP->final_map, sizeof(new_map->path));
352 
353  FOR_MAP_PREPARE(new_map, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map), tmp)
354  /* Remove exit back to previous random map. There should only be one
355  * which is why we break out. To try to process more than one
356  * would require keeping a 'next' pointer, as object_free_drop_inventory() kills tmp, which
357  * breaks the for loop.
358  */
359  if (tmp->type == EXIT && EXIT_PATH(tmp) && !strncmp(EXIT_PATH(tmp), "/random/", 8)) {
362  break;
363  }
364  FOR_MAP_FINISH();
365 
366  if (final_map_exit == 1) {
367  /* setup the exit back */
368  the_exit_back->slaying = add_string(map->path);
369  the_exit_back->stats.hp = downx+freearr_x[i];
370  the_exit_back->stats.sp = downy+freearr_y[i];
371  object_insert_in_map_at(the_exit_back, new_map, NULL, 0, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map));
372  }
373 
374  set_map_timeout(new_map); /* So it gets swapped out */
375  if (map->reset_group && !new_map->reset_group) {
376  /* So the random maps don't reset before the final map */
377  new_map->reset_group = add_string(map->reset_group);
378  }
379  } else {
380  the_exit_down->slaying = add_string("/!");
381  }
382 
383  /* Block the exit so things don't get dumped on top of it. */
384  the_exit_down->move_block = MOVE_ALL;
385  object_insert_in_map_at(the_exit_down, map, NULL, 0, downx+freearr_x[i], downy+freearr_y[i]);
386  maze[the_exit_down->x][the_exit_down->y] = '>';
387  }
388 }
389 
401 void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
402 {
403  int i = 0, j = 0;
404 
405  for (i = 0; i < RP->Xsize; i++)
406  for (j = 0; j < RP->Ysize; j++)
407  if (maze[i][j] == '>' || maze[i][j] == '<') {
408  FOR_MAP_PREPARE(map, i, j, walk) {
409  if (walk->move_block == MOVE_ALL && walk->type != LOCKED_DOOR) {
410  walk->move_block = MOVE_BLOCK_DEFAULT;
412  }
413  }
414  FOR_MAP_FINISH();
415  }
416 }
mapdef::reset_group
sstring reset_group
Definition: map.h:329
object_find_first_free_spot
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.c:3570
ready_map_name
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.c:1785
global.h
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
random_map.h
object_remove
void object_remove(object *op)
Definition: object.c:1819
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
MOVE_BLOCK_DEFAULT
#define MOVE_BLOCK_DEFAULT
Definition: define.h:409
obj::move_block
MoveType move_block
Definition: object.h:430
layout
Definition: main.c:85
RMParms::origin_map
char origin_map[RM_SIZE]
Definition: random_map.h:55
MOVE_ALL
#define MOVE_ALL
Definition: define.h:398
place_exits
void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
Definition: exit.c:144
object_update
void object_update(object *op, int action)
Definition: object.c:1420
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
RMParms::Ysize
int Ysize
Definition: random_map.h:75
set_map_timeout
void set_map_timeout(mapstruct *oldmap)
Definition: main.c:305
RMParms::dungeon_depth
int dungeon_depth
Definition: random_map.h:85
unblock_exits
void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
Definition: exit.c:401
liv::hp
int16_t hp
Definition: living.h:40
RMParms::origin_y
int origin_y
Definition: random_map.h:88
Ice.tmp
int tmp
Definition: Ice.py:207
find_style
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.c:180
RMParms::dungeon_level
int dungeon_level
Definition: random_map.h:84
RMParms
Definition: random_map.h:14
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:299
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:305
archt
Definition: object.h:469
obj::slaying
sstring slaying
Definition: object.h:322
RMParms::origin_x
int origin_x
Definition: random_map.h:89
disinfect.map
map
Definition: disinfect.py:4
RMParms::final_map
char final_map[RM_SIZE]
Definition: random_map.h:57
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:123
obj::x
int16_t x
Definition: object.h:330
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
find_in_layout
void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
Definition: exit.c:47
rproto.h
sproto.h
mapdef
Definition: map.h:317
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:281
RANDOM
#define RANDOM()
Definition: define.h:644
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
EXIT
@ EXIT
Definition: object.h:181
obj::y
int16_t y
Definition: object.h:330
obj::arch
struct archt * arch
Definition: object.h:417
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.c:4781
RMParms::final_exit_archetype
char final_exit_archetype[RM_SIZE]
Definition: random_map.h:59
obj::stats
living stats
Definition: object.h:373
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:284
RMParms::exit_on_final_map
char exit_on_final_map[RM_SIZE]
Definition: random_map.h:70
pick_random_object
object * pick_random_object(mapstruct *style)
Definition: style.c:289
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
buf
StringBuffer * buf
Definition: readable.c:1610
MAP_ENTER_Y
#define MAP_ENTER_Y(m)
Definition: map.h:87
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2080
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
MAP_ENTER_X
#define MAP_ENTER_X(m)
Definition: map.h:85
wall_blocked
int wall_blocked(mapstruct *m, int x, int y)
Definition: treasure.c:62
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:288
UP_OBJ_CHANGE
#define UP_OBJ_CHANGE
Definition: object.h:518
mapdef::path
char path[HUGE_BUF]
Definition: map.h:358
liv::sp
int16_t sp
Definition: living.h:42
RMParms::Xsize
int Xsize
Definition: random_map.h:74
write_map_parameters_to_string
StringBuffer * write_map_parameters_to_string(const RMParms *RP)
Definition: random_map.c:750