Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_exit_c = 00003 * "$Id: exit.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00029 #include <global.h> 00030 #include <random_map.h> 00031 #include <sproto.h> 00032 #include <rproto.h> 00033 00058 void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP) { 00059 int M; 00060 int i, j; 00061 00062 *fx = -1; 00063 *fy = -1; 00064 00065 /* if a starting mode isn't given, pick one */ 00066 if (mode < 1 || mode > 4) 00067 M = RANDOM()%4+1; 00068 else 00069 M = mode; 00070 00071 /* four different search starting points and methods so that 00072 we can do something different for symmetrical maps instead of 00073 the same damned thing every time. */ 00074 switch (M) { 00075 case 1: { /* search from top left down/right */ 00076 for (i = 1; i < RP->Xsize; i++) 00077 for (j = 1; j < RP->Ysize; j++) { 00078 if (layout[i][j] == target) { 00079 *fx = i; 00080 *fy = j; 00081 return; 00082 } 00083 } 00084 break; 00085 } 00086 00087 case 2: { /* Search from top right down/left */ 00088 for (i = RP->Xsize-2; i > 0; i--) 00089 for (j = 1; j < RP->Ysize-1; j++) { 00090 if (layout[i][j] == target) { 00091 *fx = i; 00092 *fy = j; 00093 return; 00094 } 00095 } 00096 break; 00097 } 00098 00099 case 3: { /* search from bottom-left up-right */ 00100 for (i = 1; i < RP->Xsize-1; i++) 00101 for (j = RP->Ysize-2; j > 0; j--) { 00102 if (layout[i][j] == target) { 00103 *fx = i; 00104 *fy = j; 00105 return; 00106 } 00107 } 00108 break; 00109 } 00110 00111 case 4: { /* search from bottom-right up-left */ 00112 for (i = RP->Xsize-2; i > 0; i--) 00113 for (j = RP->Ysize-2; j > 0; j--) { 00114 if (layout[i][j] == target) { 00115 *fx = i; 00116 *fy = j; 00117 return; 00118 } 00119 } 00120 break; 00121 } 00122 } 00123 } 00124 00125 /* orientation: 00126 */ 00127 00153 void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP) { 00154 char styledirname[256]; 00155 mapstruct *style_map_down = NULL; /* harder maze */ 00156 mapstruct *style_map_up = NULL; /* easier maze */ 00157 object *the_exit_down; /* harder maze */ 00158 object *the_exit_up; /* easier maze */ 00159 object *random_sign; /* magic mouth saying this is a random map. */ 00160 char buf[512]; 00161 int cx = -1, cy = -1; /* location of a map center */ 00162 int upx = -1, upy = -1; /* location of up exit */ 00163 int downx = -1, downy = -1; 00164 int final_map_exit = 1; 00165 int i, j; 00166 00167 if (RP->exit_on_final_map) { 00168 if (strstr(RP->exit_on_final_map, "no")) 00169 final_map_exit = 0; 00170 } 00171 00172 if (orientation == 0) 00173 orientation = RANDOM()%6+1; 00174 00175 switch (orientation) { 00176 case 1: { 00177 snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/up"); 00178 style_map_up = find_style(styledirname, exitstyle, -1); 00179 snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/down"); 00180 style_map_down = find_style(styledirname, exitstyle, -1); 00181 break; 00182 } 00183 00184 case 2: { 00185 snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/down"); 00186 style_map_up = find_style(styledirname, exitstyle, -1); 00187 snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/up"); 00188 style_map_down = find_style(styledirname, exitstyle, -1); 00189 break; 00190 } 00191 00192 default: { 00193 snprintf(styledirname, sizeof(styledirname), "/styles/exitstyles/generic"); 00194 style_map_up = find_style(styledirname, exitstyle, -1); 00195 style_map_down = style_map_up; 00196 break; 00197 } 00198 } 00199 00200 if (style_map_up == NULL) 00201 the_exit_up = arch_to_object(find_archetype("exit")); 00202 else { 00203 object *tmp; 00204 00205 tmp = pick_random_object(style_map_up); 00206 the_exit_up = arch_to_object(tmp->arch); 00207 } 00208 00209 /* we need a down exit only if we're recursing. */ 00210 if (RP->dungeon_level < RP->dungeon_depth || RP->final_map[0] != 0) 00211 if (RP->dungeon_level >= RP->dungeon_depth && RP->final_exit_archetype[0] != 0) 00212 the_exit_down = arch_to_object(find_archetype(RP->final_exit_archetype)); 00213 else if (style_map_down == NULL) 00214 the_exit_down = arch_to_object(find_archetype("exit")); 00215 else { 00216 object *tmp; 00217 00218 tmp = pick_random_object(style_map_down); 00219 the_exit_down = arch_to_object(tmp->arch); 00220 } 00221 else 00222 the_exit_down = NULL; 00223 00224 /* set up the up exit */ 00225 the_exit_up->stats.hp = RP->origin_x; 00226 the_exit_up->stats.sp = RP->origin_y; 00227 the_exit_up->slaying = add_string(RP->origin_map); 00228 00229 /* figure out where to put the entrance */ 00230 /* First, look for a '<' char */ 00231 find_in_layout(0, '<', &upx, &upy, maze, RP); 00232 00233 /* next, look for a C, the map center. */ 00234 find_in_layout(0, 'C', &cx, &cy, maze, RP); 00235 00236 /* if we didn't find an up, find an empty place far from the center */ 00237 if (upx == -1 && cx != -1) { 00238 if (cx > RP->Xsize/2) 00239 upx = 1; 00240 else 00241 upx = RP->Xsize-2; 00242 if (cy > RP->Ysize/2) 00243 upy = 1; 00244 else 00245 upy = RP->Ysize-2; 00246 00247 /* find an empty place far from the center */ 00248 if (upx == 1 && upy == 1) 00249 find_in_layout(1, 0, &upx, &upy, maze, RP); 00250 else if (upx == 1 && upy > 1) 00251 find_in_layout(3, 0, &upx, &upy, maze, RP); 00252 else if (upx > 1 && upy == 1) 00253 find_in_layout(2, 0, &upx, &upy, maze, RP); 00254 else if (upx > 1 && upy > 1) 00255 find_in_layout(4, 0, &upx, &upy, maze, RP); 00256 } 00257 00258 /* no indication of where to place the exit, so just place it at any empty spot. */ 00259 if (upx == -1) 00260 find_in_layout(0, 0, &upx, &upy, maze, RP); 00261 00262 the_exit_up->x = upx; 00263 the_exit_up->y = upy; 00264 00265 /* surround the exits with notices that this is a random map. */ 00266 for (j = 1; j < 9; j++) { 00267 if (!wall_blocked(map, the_exit_up->x+freearr_x[j], the_exit_up->y+freearr_y[j])) { 00268 random_sign = create_archetype("sign"); 00269 random_sign->x = the_exit_up->x+freearr_x[j]; 00270 random_sign->y = the_exit_up->y+freearr_y[j]; 00271 00272 snprintf(buf, sizeof(buf), "This is a random map.\nLevel: %d\n", (RP->dungeon_level)-1); 00273 00274 random_sign->msg = add_string(buf); 00275 insert_ob_in_map(random_sign, map, NULL, 0); 00276 } 00277 } 00278 /* Block the exit so things don't get dumped on top of it. */ 00279 the_exit_up->move_block = MOVE_ALL; 00280 00281 insert_ob_in_map(the_exit_up, map, NULL, 0); 00282 maze[the_exit_up->x][the_exit_up->y] = '<'; 00283 00284 /* set the starting x,y for this map */ 00285 MAP_ENTER_X(map) = the_exit_up->x; 00286 MAP_ENTER_Y(map) = the_exit_up->y; 00287 00288 /* first, look for a '>' character */ 00289 find_in_layout(0, '>', &downx, &downy, maze, RP); 00290 /* if no > is found use C */ 00291 if (downx == -1) { 00292 downx = cx; 00293 downy = cy; 00294 } 00295 00296 /* make the other exit far away from this one if 00297 there's no center. */ 00298 if (downx == -1) { 00299 if (upx > RP->Xsize/2) 00300 downx = 1; 00301 else 00302 downx = RP->Xsize-2; 00303 if (upy > RP->Ysize/2) 00304 downy = 1; 00305 else 00306 downy = RP->Ysize-2; 00307 00308 /* find an empty place far from the entrance */ 00309 if (downx == 1 && downy == 1) 00310 find_in_layout(1, 0, &downx, &downy, maze, RP); 00311 else if (downx == 1 && downy > 1) 00312 find_in_layout(3, 0, &downx, &downy, maze, RP); 00313 else if (downx > 1 && downy == 1) 00314 find_in_layout(2, 0, &downx, &downy, maze, RP); 00315 else if (downx > 1 && downy > 1) 00316 find_in_layout(4, 0, &downx, &downy, maze, RP); 00317 00318 } 00319 /* no indication of where to place the down exit, so just place it on an empty spot. */ 00320 if (downx == -1) 00321 find_in_layout(0, 0, &downx, &downy, maze, RP); 00322 if (the_exit_down) { 00323 char buf[2048]; 00324 00325 i = find_first_free_spot(the_exit_down, map, downx, downy); 00326 the_exit_down->x = downx+freearr_x[i]; 00327 the_exit_down->y = downy+freearr_y[i]; 00328 RP->origin_x = the_exit_down->x; 00329 RP->origin_y = the_exit_down->y; 00330 write_map_parameters_to_string(RP, buf, sizeof(buf)); 00331 the_exit_down->msg = add_string(buf); 00332 /* the identifier for making a random map. */ 00333 if (RP->dungeon_level >= RP->dungeon_depth && RP->final_map[0] != 0) { 00334 /* Next map is the final map, special case. */ 00335 mapstruct *new_map; 00336 object *the_exit_back = arch_to_object(the_exit_up->arch), *tmp; 00337 00338 /* load it */ 00339 if ((new_map = ready_map_name(RP->final_map, 0)) == NULL) 00340 return; 00341 00342 the_exit_down->slaying = add_string(RP->final_map); 00343 EXIT_X(the_exit_down) = MAP_ENTER_X(new_map); 00344 EXIT_Y(the_exit_down) = MAP_ENTER_Y(new_map); 00345 strncpy(new_map->path, RP->final_map, sizeof(new_map->path)); 00346 00347 for (tmp = GET_MAP_OB(new_map, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map)); tmp; tmp = tmp->above) 00348 /* Remove exit back to previous random map. There should only be one 00349 * which is why we break out. To try to process more than one 00350 * would require keeping a 'next' pointer, as free_object kills tmp, which 00351 * breaks the for loop. 00352 */ 00353 if (tmp->type == EXIT && EXIT_PATH(tmp) && !strncmp(EXIT_PATH(tmp), "/random/", 8)) { 00354 remove_ob(tmp); 00355 free_object(tmp); 00356 break; 00357 } 00358 00359 if (final_map_exit == 1) { 00360 /* setup the exit back */ 00361 the_exit_back->slaying = add_string(map->path); 00362 the_exit_back->stats.hp = the_exit_down->x; 00363 the_exit_back->stats.sp = the_exit_down->y; 00364 the_exit_back->x = MAP_ENTER_X(new_map); 00365 the_exit_back->y = MAP_ENTER_Y(new_map); 00366 00367 insert_ob_in_map(the_exit_back, new_map, NULL, 0); 00368 } 00369 00370 set_map_timeout(new_map); /* So it gets swapped out */ 00371 } else 00372 the_exit_down->slaying = add_string("/!"); 00373 00374 /* Block the exit so things don't get dumped on top of it. */ 00375 the_exit_down->move_block = MOVE_ALL; 00376 insert_ob_in_map(the_exit_down, map, NULL, 0); 00377 maze[the_exit_down->x][the_exit_down->y] = '>'; 00378 } 00379 } 00380 00392 void unblock_exits(mapstruct *map, char **maze, RMParms *RP) { 00393 int i = 0, j = 0; 00394 object *walk; 00395 00396 for (i = 0; i < RP->Xsize; i++) 00397 for (j = 0; j < RP->Ysize; j++) 00398 if (maze[i][j] == '>' || maze[i][j] == '<') { 00399 for (walk = GET_MAP_OB(map, i, j); walk != NULL; walk = walk->above) { 00400 if (walk->move_block == MOVE_ALL && walk->type != LOCKED_DOOR) { 00401 walk->move_block = MOVE_BLOCK_DEFAULT; 00402 update_object(walk, UP_OBJ_CHANGE); 00403 } 00404 } 00405 } 00406 }