Crossfire Server, Branches 1.12  R18729
exit.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_exit_c =
3  * "$Id: exit.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
29 #include <global.h>
30 #include <random_map.h>
31 #include <sproto.h>
32 #include <rproto.h>
33 
58 void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP) {
59  int M;
60  int i, j;
61 
62  *fx = -1;
63  *fy = -1;
64 
65  /* if a starting mode isn't given, pick one */
66  if (mode < 1 || mode > 4)
67  M = RANDOM()%4+1;
68  else
69  M = mode;
70 
71  /* four different search starting points and methods so that
72  we can do something different for symmetrical maps instead of
73  the same damned thing every time. */
74  switch (M) {
75  case 1: { /* search from top left down/right */
76  for (i = 1; i < RP->Xsize; i++)
77  for (j = 1; j < RP->Ysize; j++) {
78  if (layout[i][j] == target) {
79  *fx = i;
80  *fy = j;
81  return;
82  }
83  }
84  break;
85  }
86 
87  case 2: { /* Search from top right down/left */
88  for (i = RP->Xsize-2; i > 0; i--)
89  for (j = 1; j < RP->Ysize-1; j++) {
90  if (layout[i][j] == target) {
91  *fx = i;
92  *fy = j;
93  return;
94  }
95  }
96  break;
97  }
98 
99  case 3: { /* search from bottom-left up-right */
100  for (i = 1; i < RP->Xsize-1; i++)
101  for (j = RP->Ysize-2; j > 0; j--) {
102  if (layout[i][j] == target) {
103  *fx = i;
104  *fy = j;
105  return;
106  }
107  }
108  break;
109  }
110 
111  case 4: { /* search from bottom-right up-left */
112  for (i = RP->Xsize-2; i > 0; i--)
113  for (j = RP->Ysize-2; j > 0; j--) {
114  if (layout[i][j] == target) {
115  *fx = i;
116  *fy = j;
117  return;
118  }
119  }
120  break;
121  }
122  }
123 }
124 
125 /* orientation:
126 */
127 
153 void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP) {
154  char styledirname[256];
155  mapstruct *style_map_down = NULL; /* harder maze */
156  mapstruct *style_map_up = NULL; /* easier maze */
157  object *the_exit_down; /* harder maze */
158  object *the_exit_up; /* easier maze */
159  object *random_sign; /* magic mouth saying this is a random map. */
160  char buf[512];
161  int cx = -1, cy = -1; /* location of a map center */
162  int upx = -1, upy = -1; /* location of up exit */
163  int downx = -1, downy = -1;
164  int final_map_exit = 1;
165  int i, j;
166 
167  if (RP->exit_on_final_map) {
168  if (strstr(RP->exit_on_final_map, "no"))
169  final_map_exit = 0;
170  }
171 
172  if (orientation == 0)
173  orientation = RANDOM()%6+1;
174 
175  switch (orientation) {
176  case 1: {
177  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/up");
178  style_map_up = find_style(styledirname, exitstyle, -1);
179  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/down");
180  style_map_down = find_style(styledirname, exitstyle, -1);
181  break;
182  }
183 
184  case 2: {
185  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/down");
186  style_map_up = find_style(styledirname, exitstyle, -1);
187  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/up");
188  style_map_down = find_style(styledirname, exitstyle, -1);
189  break;
190  }
191 
192  default: {
193  snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/generic");
194  style_map_up = find_style(styledirname, exitstyle, -1);
195  style_map_down = style_map_up;
196  break;
197  }
198  }
199 
200  if (style_map_up == NULL)
201  the_exit_up = arch_to_object(find_archetype("exit"));
202  else {
203  object *tmp;
204 
205  tmp = pick_random_object(style_map_up);
206  the_exit_up = arch_to_object(tmp->arch);
207  }
208 
209  /* we need a down exit only if we're recursing. */
210  if (RP->dungeon_level < RP->dungeon_depth || RP->final_map[0] != 0)
211  if (RP->dungeon_level >= RP->dungeon_depth && RP->final_exit_archetype[0] != 0)
212  the_exit_down = arch_to_object(find_archetype(RP->final_exit_archetype));
213  else if (style_map_down == NULL)
214  the_exit_down = arch_to_object(find_archetype("exit"));
215  else {
216  object *tmp;
217 
218  tmp = pick_random_object(style_map_down);
219  the_exit_down = arch_to_object(tmp->arch);
220  }
221  else
222  the_exit_down = NULL;
223 
224  /* set up the up exit */
225  the_exit_up->stats.hp = RP->origin_x;
226  the_exit_up->stats.sp = RP->origin_y;
227  the_exit_up->slaying = add_string(RP->origin_map);
228 
229  /* figure out where to put the entrance */
230  /* First, look for a '<' char */
231  find_in_layout(0, '<', &upx, &upy, maze, RP);
232 
233  /* next, look for a C, the map center. */
234  find_in_layout(0, 'C', &cx, &cy, maze, RP);
235 
236  /* if we didn't find an up, find an empty place far from the center */
237  if (upx == -1 && cx != -1) {
238  if (cx > RP->Xsize/2)
239  upx = 1;
240  else
241  upx = RP->Xsize-2;
242  if (cy > RP->Ysize/2)
243  upy = 1;
244  else
245  upy = RP->Ysize-2;
246 
247  /* find an empty place far from the center */
248  if (upx == 1 && upy == 1)
249  find_in_layout(1, 0, &upx, &upy, maze, RP);
250  else if (upx == 1 && upy > 1)
251  find_in_layout(3, 0, &upx, &upy, maze, RP);
252  else if (upx > 1 && upy == 1)
253  find_in_layout(2, 0, &upx, &upy, maze, RP);
254  else if (upx > 1 && upy > 1)
255  find_in_layout(4, 0, &upx, &upy, maze, RP);
256  }
257 
258  /* no indication of where to place the exit, so just place it at any empty spot. */
259  if (upx == -1)
260  find_in_layout(0, 0, &upx, &upy, maze, RP);
261 
262  the_exit_up->x = upx;
263  the_exit_up->y = upy;
264 
265  /* surround the exits with notices that this is a random map. */
266  for (j = 1; j < 9; j++) {
267  if (!wall_blocked(map, the_exit_up->x+freearr_x[j], the_exit_up->y+freearr_y[j])) {
268  random_sign = create_archetype("sign");
269  random_sign->x = the_exit_up->x+freearr_x[j];
270  random_sign->y = the_exit_up->y+freearr_y[j];
271 
272  snprintf(buf, sizeof(buf), "This is a random map.\nLevel: %d\n", (RP->dungeon_level)-1);
273 
274  random_sign->msg = add_string(buf);
275  insert_ob_in_map(random_sign, map, NULL, 0);
276  }
277  }
278  /* Block the exit so things don't get dumped on top of it. */
279  the_exit_up->move_block = MOVE_ALL;
280 
281  insert_ob_in_map(the_exit_up, map, NULL, 0);
282  maze[the_exit_up->x][the_exit_up->y] = '<';
283 
284  /* set the starting x,y for this map */
285  MAP_ENTER_X(map) = the_exit_up->x;
286  MAP_ENTER_Y(map) = the_exit_up->y;
287 
288  /* first, look for a '>' character */
289  find_in_layout(0, '>', &downx, &downy, maze, RP);
290  /* if no > is found use C */
291  if (downx == -1) {
292  downx = cx;
293  downy = cy;
294  }
295 
296  /* make the other exit far away from this one if
297  there's no center. */
298  if (downx == -1) {
299  if (upx > RP->Xsize/2)
300  downx = 1;
301  else
302  downx = RP->Xsize-2;
303  if (upy > RP->Ysize/2)
304  downy = 1;
305  else
306  downy = RP->Ysize-2;
307 
308  /* find an empty place far from the entrance */
309  if (downx == 1 && downy == 1)
310  find_in_layout(1, 0, &downx, &downy, maze, RP);
311  else if (downx == 1 && downy > 1)
312  find_in_layout(3, 0, &downx, &downy, maze, RP);
313  else if (downx > 1 && downy == 1)
314  find_in_layout(2, 0, &downx, &downy, maze, RP);
315  else if (downx > 1 && downy > 1)
316  find_in_layout(4, 0, &downx, &downy, maze, RP);
317 
318  }
319  /* no indication of where to place the down exit, so just place it on an empty spot. */
320  if (downx == -1)
321  find_in_layout(0, 0, &downx, &downy, maze, RP);
322  if (the_exit_down) {
323  char buf[2048];
324 
325  i = find_first_free_spot(the_exit_down, map, downx, downy);
326  the_exit_down->x = downx+freearr_x[i];
327  the_exit_down->y = downy+freearr_y[i];
328  RP->origin_x = the_exit_down->x;
329  RP->origin_y = the_exit_down->y;
330  write_map_parameters_to_string(RP, buf, sizeof(buf));
331  the_exit_down->msg = add_string(buf);
332  /* the identifier for making a random map. */
333  if (RP->dungeon_level >= RP->dungeon_depth && RP->final_map[0] != 0) {
334  /* Next map is the final map, special case. */
335  mapstruct *new_map;
336  object *the_exit_back = arch_to_object(the_exit_up->arch), *tmp;
337 
338  /* load it */
339  if ((new_map = ready_map_name(RP->final_map, 0)) == NULL)
340  return;
341 
342  the_exit_down->slaying = add_string(RP->final_map);
343  EXIT_X(the_exit_down) = MAP_ENTER_X(new_map);
344  EXIT_Y(the_exit_down) = MAP_ENTER_Y(new_map);
345  strncpy(new_map->path, RP->final_map, sizeof(new_map->path));
346 
347  for (tmp = GET_MAP_OB(new_map, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map)); tmp; tmp = tmp->above)
348  /* Remove exit back to previous random map. There should only be one
349  * which is why we break out. To try to process more than one
350  * would require keeping a 'next' pointer, as free_object kills tmp, which
351  * breaks the for loop.
352  */
353  if (tmp->type == EXIT && EXIT_PATH(tmp) && !strncmp(EXIT_PATH(tmp), "/random/", 8)) {
354  remove_ob(tmp);
355  free_object(tmp);
356  break;
357  }
358 
359  if (final_map_exit == 1) {
360  /* setup the exit back */
361  the_exit_back->slaying = add_string(map->path);
362  the_exit_back->stats.hp = the_exit_down->x;
363  the_exit_back->stats.sp = the_exit_down->y;
364  the_exit_back->x = MAP_ENTER_X(new_map);
365  the_exit_back->y = MAP_ENTER_Y(new_map);
366 
367  insert_ob_in_map(the_exit_back, new_map, NULL, 0);
368  }
369 
370  set_map_timeout(new_map); /* So it gets swapped out */
371  } else
372  the_exit_down->slaying = add_string("/!");
373 
374  /* Block the exit so things don't get dumped on top of it. */
375  the_exit_down->move_block = MOVE_ALL;
376  insert_ob_in_map(the_exit_down, map, NULL, 0);
377  maze[the_exit_down->x][the_exit_down->y] = '>';
378  }
379 }
380 
392 void unblock_exits(mapstruct *map, char **maze, RMParms *RP) {
393  int i = 0, j = 0;
394  object *walk;
395 
396  for (i = 0; i < RP->Xsize; i++)
397  for (j = 0; j < RP->Ysize; j++)
398  if (maze[i][j] == '>' || maze[i][j] == '<') {
399  for (walk = GET_MAP_OB(map, i, j); walk != NULL; walk = walk->above) {
400  if (walk->move_block == MOVE_ALL && walk->type != LOCKED_DOOR) {
403  }
404  }
405  }
406 }
char path[HUGE_BUF]
Definition: map.h:384
void set_map_timeout(mapstruct *oldmap)
Definition: standalone.c:77
char final_exit_archetype[RM_SIZE]
Definition: random_map.h:53
archetype * find_archetype(const char *name)
Definition: arch.c:700
char final_map[RM_SIZE]
Definition: random_map.h:52
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.c:1809
#define MAP_ENTER_X(m)
Definition: map.h:104
char exit_on_final_map[RM_SIZE]
Definition: random_map.h:56
short freearr_x[SIZEOFFREE]
Definition: object.c:75
const char * slaying
Definition: object.h:172
void update_object(object *op, int action)
Definition: object.c:1112
struct obj * above
Definition: object.h:146
void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
Definition: exit.c:153
sint16 x
Definition: object.h:179
sint16 sp
Definition: living.h:83
object * pick_random_object(mapstruct *style)
Definition: style.c:275
sint16 hp
Definition: living.h:81
short freearr_y[SIZEOFFREE]
Definition: object.c:81
#define MOVE_ALL
Definition: define.h:706
void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
Definition: exit.c:392
void remove_ob(object *op)
Definition: object.c:1515
object * create_archetype(const char *name)
Definition: arch.c:625
void write_map_parameters_to_string(RMParms *RP, char *buf, int bufsize)
Definition: random_map.c:689
int find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.c:3240
#define EXIT_PATH(xyz)
Definition: define.h:748
int dungeon_level
Definition: random_map.h:69
#define MAP_ENTER_Y(m)
Definition: map.h:106
#define EXIT_X(xyz)
Definition: define.h:750
sint16 y
Definition: object.h:179
#define LOCKED_DOOR
Definition: define.h:132
void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
Definition: exit.c:58
#define EXIT
Definition: define.h:228
#define EXIT_Y(xyz)
Definition: define.h:751
object * insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1992
int Ysize
Definition: random_map.h:60
#define MOVE_BLOCK_DEFAULT
Definition: define.h:717
int wall_blocked(mapstruct *m, int x, int y)
Definition: treasure.c:73
int Xsize
Definition: random_map.h:59
char origin_map[RM_SIZE]
Definition: random_map.h:51
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
#define UP_OBJ_CHANGE
Definition: object.h:355
int origin_y
Definition: random_map.h:73
living stats
Definition: object.h:219
struct archt * arch
Definition: object.h:263
int dungeon_depth
Definition: random_map.h:70
const char * msg
Definition: object.h:175
sstring add_string(const char *str)
Definition: shstr.c:116
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
MoveType move_block
Definition: object.h:278
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.c:177
void free_object(object *ob)
Definition: object.c:1238
Definition: map.h:346
int origin_x
Definition: random_map.h:74
object * arch_to_object(archetype *at)
Definition: arch.c:576
uint8 type
Definition: object.h:189