Crossfire Server, Trunk  R20513
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  the_exit_up = arch_to_object(find_archetype("exit"));
194  } else {
195  object *tmp;
196 
197  tmp = pick_random_object(style_map_up);
198  the_exit_up = arch_to_object(tmp->arch);
199  }
200 
201  /* we need a down exit only if we're recursing. */
202  if (RP->dungeon_level < RP->dungeon_depth || RP->final_map[0] != 0)
203  if (RP->dungeon_level >= RP->dungeon_depth && RP->final_exit_archetype[0] != 0) {
204  the_exit_down = arch_to_object(find_archetype(RP->final_exit_archetype));
205  } else if (style_map_down == NULL) {
206  the_exit_down = arch_to_object(find_archetype("exit"));
207  } else {
208  object *tmp;
209 
210  tmp = pick_random_object(style_map_down);
211  the_exit_down = arch_to_object(tmp->arch);
212  }
213  else {
214  the_exit_down = NULL;
215  }
216 
217  /* set up the up exit */
218  the_exit_up->stats.hp = RP->origin_x;
219  the_exit_up->stats.sp = RP->origin_y;
220  the_exit_up->slaying = add_string(RP->origin_map);
221 
222  /* figure out where to put the entrance */
223  /* First, look for a '<' char */
224  find_in_layout(0, '<', &upx, &upy, maze, RP);
225 
226  /* next, look for a C, the map center. */
227  find_in_layout(0, 'C', &cx, &cy, maze, RP);
228 
229  /* if we didn't find an up, find an empty place far from the center */
230  if (upx == -1 && cx != -1) {
231  if (cx > RP->Xsize/2) {
232  upx = 1;
233  } else {
234  upx = RP->Xsize-2;
235  }
236  if (cy > RP->Ysize/2) {
237  upy = 1;
238  } else {
239  upy = RP->Ysize-2;
240  }
241 
242  /* find an empty place far from the center */
243  if (upx == 1 && upy == 1) {
244  find_in_layout(1, 0, &upx, &upy, maze, RP);
245  } else if (upx == 1 && upy > 1) {
246  find_in_layout(3, 0, &upx, &upy, maze, RP);
247  } else if (upx > 1 && upy == 1) {
248  find_in_layout(2, 0, &upx, &upy, maze, RP);
249  } else if (upx > 1 && upy > 1) {
250  find_in_layout(4, 0, &upx, &upy, maze, RP);
251  }
252  }
253 
254  /* no indication of where to place the exit, so just place it at any empty spot. */
255  if (upx == -1) {
256  find_in_layout(0, 0, &upx, &upy, maze, RP);
257  }
258 
259  /* surround the exits with notices that this is a random map. */
260  for (j = 1; j < 9; j++) {
261  if (!wall_blocked(map, upx+freearr_x[j], upy+freearr_y[j])) {
262  random_sign = create_archetype("sign");
263 
264  snprintf(buf, sizeof(buf), "This is a random map.\nLevel: %d\n", (RP->dungeon_level)-1);
265  object_set_msg(random_sign, buf);
266  object_insert_in_map_at(random_sign, map, NULL, 0, upx+freearr_x[j], upy+freearr_y[j]);
267  }
268  }
269  /* Block the exit so things don't get dumped on top of it. */
270  the_exit_up->move_block = MOVE_ALL;
271 
272  object_insert_in_map_at(the_exit_up, map, NULL, 0, upx, upy);
273  maze[upx][upy] = '<';
274 
275  /* set the starting x,y for this map */
276  MAP_ENTER_X(map) = upx;
277  MAP_ENTER_Y(map) = upy;
278 
279  /* first, look for a '>' character */
280  find_in_layout(0, '>', &downx, &downy, maze, RP);
281  /* if no > is found use C */
282  if (downx == -1) {
283  downx = cx;
284  downy = cy;
285  }
286 
287  /* make the other exit far away from this one if
288  there's no center. */
289  if (downx == -1) {
290  if (upx > RP->Xsize/2) {
291  downx = 1;
292  } else {
293  downx = RP->Xsize-2;
294  }
295  if (upy > RP->Ysize/2) {
296  downy = 1;
297  } else {
298  downy = RP->Ysize-2;
299  }
300 
301  /* find an empty place far from the entrance */
302  if (downx == 1 && downy == 1) {
303  find_in_layout(1, 0, &downx, &downy, maze, RP);
304  } else if (downx == 1 && downy > 1) {
305  find_in_layout(3, 0, &downx, &downy, maze, RP);
306  } else if (downx > 1 && downy == 1) {
307  find_in_layout(2, 0, &downx, &downy, maze, RP);
308  } else if (downx > 1 && downy > 1) {
309  find_in_layout(4, 0, &downx, &downy, maze, RP);
310  }
311  }
312  /* no indication of where to place the down exit, so just place it on an empty spot. */
313  if (downx == -1) {
314  find_in_layout(0, 0, &downx, &downy, maze, RP);
315  }
316  if (the_exit_down) {
317  char *buf;
318 
319  i = object_find_first_free_spot(the_exit_down, map, downx, downy);
320  RP->origin_x = downx+freearr_x[i];
321  RP->origin_y = downy+freearr_y[i];
323  object_set_msg(the_exit_down, buf);
324  free(buf);
325  /* the identifier for making a random map. */
326  if (RP->dungeon_level >= RP->dungeon_depth && RP->final_map[0] != 0) {
327  /* Next map is the final map, special case. */
328  mapstruct *new_map;
329  object *the_exit_back = arch_to_object(the_exit_up->arch);
330 
331  /* load it */
332  if ((new_map = ready_map_name(RP->final_map, 0)) == NULL) {
333  return;
334  }
335 
336  the_exit_down->slaying = add_string(RP->final_map);
337  EXIT_X(the_exit_down) = MAP_ENTER_X(new_map);
338  EXIT_Y(the_exit_down) = MAP_ENTER_Y(new_map);
339  strncpy(new_map->path, RP->final_map, sizeof(new_map->path));
340 
341  FOR_MAP_PREPARE(new_map, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map), tmp)
342  /* Remove exit back to previous random map. There should only be one
343  * which is why we break out. To try to process more than one
344  * would require keeping a 'next' pointer, as object_free_drop_inventory() kills tmp, which
345  * breaks the for loop.
346  */
347  if (tmp->type == EXIT && EXIT_PATH(tmp) && !strncmp(EXIT_PATH(tmp), "/random/", 8)) {
348  object_remove(tmp);
350  break;
351  }
352  FOR_MAP_FINISH();
353 
354  if (final_map_exit == 1) {
355  /* setup the exit back */
356  the_exit_back->slaying = add_string(map->path);
357  the_exit_back->stats.hp = downx+freearr_x[i];
358  the_exit_back->stats.sp = downy+freearr_y[i];
359  object_insert_in_map_at(the_exit_back, new_map, NULL, 0, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map));
360  }
361 
362  set_map_timeout(new_map); /* So it gets swapped out */
363  } else {
364  the_exit_down->slaying = add_string("/!");
365  }
366 
367  /* Block the exit so things don't get dumped on top of it. */
368  the_exit_down->move_block = MOVE_ALL;
369  object_insert_in_map_at(the_exit_down, map, NULL, 0, downx+freearr_x[i], downy+freearr_y[i]);
370  maze[the_exit_down->x][the_exit_down->y] = '>';
371  }
372 }
373 
385 void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
386 {
387  int i = 0, j = 0;
388 
389  for (i = 0; i < RP->Xsize; i++)
390  for (j = 0; j < RP->Ysize; j++)
391  if (maze[i][j] == '>' || maze[i][j] == '<') {
392  FOR_MAP_PREPARE(map, i, j, walk) {
393  if (walk->move_block == MOVE_ALL && walk->type != LOCKED_DOOR) {
394  walk->move_block = MOVE_BLOCK_DEFAULT;
396  }
397  }
398  FOR_MAP_FINISH();
399  }
400 }
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
void set_map_timeout(mapstruct *oldmap)
Applies the map timeout.
Definition: main.c:307
char final_exit_archetype[RM_SIZE]
If not empty, the archetype name of the exit leading to the final map.
Definition: random_map.h:54
Random map parameters.
Definition: random_map.h:14
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
char final_map[RM_SIZE]
If not empty, the path of the final map this whole maze leads to.
Definition: random_map.h:52
mapstruct * ready_map_name(const char *name, int flags)
Makes sure the given map is loaded and swapped in.
Definition: map.c:1803
#define MAP_ENTER_X(m)
Default X coordinate for map enter.
Definition: map.h:85
char exit_on_final_map[RM_SIZE]
If this is "no", then no exit will be made to the final map from the previous random map...
Definition: random_map.h:65
Random map related variables.
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
const char * slaying
Which race to do double damage to.
Definition: object.h:319
void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
Place exits in the map.
Definition: exit.c:144
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.c:1239
int16_t sp
Spell points.
Definition: living.h:41
Global type definitions and header inclusions.
object * pick_random_object(mapstruct *style)
Picks a random object from a style map.
Definition: style.c:286
int16_t hp
Hit Points.
Definition: living.h:39
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:413
void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
This function unblocks the exits.
Definition: exit.c:385
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
int16_t y
Position in the map for this object.
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
See Exit.
Definition: object.h:181
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.c:620
#define snprintf
Definition: win32.h:46
#define EXIT_PATH(xyz)
Definition: define.h:455
int dungeon_level
Definition: random_map.h:79
#define MAP_ENTER_Y(m)
Default Y coordinate for map enter.
Definition: map.h:87
#define EXIT_X(xyz)
Definition: define.h:457
void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
Find a character in the layout.
Definition: exit.c:47
StringBuffer * write_map_parameters_to_string(const RMParms *RP)
Creates a suitable message for exit from RP.
Definition: random_map.c:735
See Locked Door.
Definition: object.h:123
#define EXIT_Y(xyz)
Definition: define.h:458
int16_t x
Definition: object.h:326
int Ysize
Definition: random_map.h:70
#define MOVE_BLOCK_DEFAULT
The normal assumption is that objects are walking/flying.
Definition: define.h:424
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
object_find_first_free_spot(archetype, mapstruct, x, y) works like object_find_free_spot(), but it will search max number of squares.
Definition: object.c:3458
int wall_blocked(mapstruct *m, int x, int y)
Returns true if square x,y has P_NO_PASS set, which is true for walls and doors but not monsters...
Definition: treasure.c:62
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
int Xsize
Definition: random_map.h:69
char origin_map[RM_SIZE]
Path to the map this random map is generated from, to make an exit back.
Definition: random_map.h:50
#define UP_OBJ_CHANGE
Object changed.
Definition: object.h:518
#define RANDOM()
Definition: define.h:679
int origin_y
Definition: random_map.h:83
living stats
Str, Con, Dex, etc.
Definition: object.h:368
struct archt * arch
Pointer to archetype.
Definition: object.h:412
int dungeon_depth
Definition: random_map.h:80
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
MoveType move_block
What movement types this blocks.
Definition: object.h:425
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Loads and returns the map requested.
Definition: style.c:180
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.c:4695
This is a game-map.
Definition: map.h:325
int origin_x
Definition: random_map.h:84
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.c:76
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
Definition: main.c:88