Crossfire Server, Branch 1.12  R12190
exit.c
Go to the documentation of this file.
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 }