Crossfire Server, Trunk
exit.cpp
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 }
global.h
random_map.h
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
MOVE_BLOCK_DEFAULT
#define MOVE_BLOCK_DEFAULT
Definition: define.h:409
layout
Definition: main.cpp:84
MOVE_ALL
#define MOVE_ALL
Definition: define.h:398
ready_map_name
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.cpp:1759
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
RMParms::origin_y
int origin_y
Definition: random_map.h:88
object::arch
struct archetype * arch
Definition: object.h:422
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
object::x
int16_t x
Definition: object.h:335
set_map_timeout
void set_map_timeout(mapstruct *oldmap)
Definition: main.cpp:304
object_find_first_free_spot
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.cpp:3590
M
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points wd Cleric or Dwarf sm Elf M
Definition: stats.txt:94
Ice.tmp
int tmp
Definition: Ice.py:207
mode
linux kernel c mode(defun linux-c-mode() "C mode with adjusted defaults for use with the Linux kernel."(interactive)(c-mode)(c-set-style "K&R")(setq c-basic-offset 8))
RMParms::origin_map
char origin_map[RM_SIZE]
Definition: random_map.h:55
find_style
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.cpp:180
RMParms::Ysize
int Ysize
Definition: random_map.h:75
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:355
buf
StringBuffer * buf
Definition: readable.cpp:1552
object::y
int16_t y
Definition: object.h:335
RMParms::Xsize
int Xsize
Definition: random_map.h:74
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
object_update
void object_update(object *op, int action)
Definition: object.cpp:1429
disinfect.map
map
Definition: disinfect.py:4
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.cpp:305
RMParms
Definition: random_map.h:14
place_exits
void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
Definition: exit.cpp:144
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
archetype
Definition: object.h:474
mapstruct::reset_group
sstring reset_group
Definition: map.h:326
rproto.h
sproto.h
living::sp
int16_t sp
Definition: living.h:42
RMParms::origin_x
int origin_x
Definition: random_map.h:89
unblock_exits
void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
Definition: exit.cpp:401
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.cpp:2095
find_in_layout
void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
Definition: exit.cpp:47
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
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:186
RMParms::final_map
char final_map[RM_SIZE]
Definition: random_map.h:57
object::slaying
sstring slaying
Definition: object.h:327
RMParms::exit_on_final_map
char exit_on_final_map[RM_SIZE]
Definition: random_map.h:70
mapstruct
Definition: map.h:314
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
pick_random_object
object * pick_random_object(mapstruct *style)
Definition: style.cpp:289
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.cpp:4802
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
RMParms::dungeon_level
int dungeon_level
Definition: random_map.h:84
MAP_ENTER_Y
#define MAP_ENTER_Y(m)
Definition: map.h:83
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
MAP_ENTER_X
#define MAP_ENTER_X(m)
Definition: map.h:81
wall_blocked
int wall_blocked(mapstruct *m, int x, int y)
Definition: treasure.cpp:62
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
UP_OBJ_CHANGE
#define UP_OBJ_CHANGE
Definition: object.h:523
RMParms::final_exit_archetype
char final_exit_archetype[RM_SIZE]
Definition: random_map.h:59
object::stats
living stats
Definition: object.h:378
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
RMParms::dungeon_depth
int dungeon_depth
Definition: random_map.h:85
object::move_block
MoveType move_block
Definition: object.h:435
living::hp
int16_t hp
Definition: living.h:40
write_map_parameters_to_string
StringBuffer * write_map_parameters_to_string(const RMParms *RP)
Definition: random_map.cpp:749