Atrinik Server 2.5
random_maps/exit.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00043 void find_in_layout(int mode, char target, int *fx, int *fy, char **layout, RMParms *RP)
00044 {
00045     int M, x, y;
00046 
00047     *fx = -1;
00048     *fy = -1;
00049 
00050     /* if a starting point isn't given, pick one */
00051     if (mode < 1 || mode > 4)
00052     {
00053         M = RANDOM() % 4 + 1;
00054     }
00055     else
00056     {
00057         M = mode;
00058     }
00059 
00060     /* four different search starting points and methods so that
00061        we can do something different for symmetrical maps instead of
00062        the same damned thing every time. */
00063     switch (M)
00064     {
00065         /* Search from top left down/right */
00066         case 1:
00067         {
00068             for (x = 1; x < RP->Xsize; x++)
00069             {
00070                 for (y = 1; y < RP->Ysize; y++)
00071                 {
00072                     if (layout[x][y] == target)
00073                     {
00074                         *fx = x;
00075                         *fy = y;
00076 
00077                         return;
00078                     }
00079                 }
00080             }
00081 
00082             break;
00083         }
00084 
00085         /* Search from top right down/left */
00086         case 2:
00087         {
00088             for (x = RP->Xsize - 2; x > 0; x--)
00089             {
00090                 for (y = 1; y < RP->Ysize - 1; y++)
00091                 {
00092                     if (layout[x][y] == target)
00093                     {
00094                         *fx = x;
00095                         *fy = y;
00096 
00097                         return;
00098                     }
00099                 }
00100             }
00101 
00102             break;
00103         }
00104 
00105         /* Search from bottom-left up-right */
00106         case 3:
00107         {
00108             for (x = 1; x < RP->Xsize - 1; x++)
00109             {
00110                 for (y = RP->Ysize - 2; y > 0; y--)
00111                 {
00112                     if (layout[x][y] == target)
00113                     {
00114                         *fx = x;
00115                         *fy = y;
00116 
00117                         return;
00118                     }
00119                 }
00120             }
00121 
00122             break;
00123         }
00124 
00125         /* Search from bottom-right up-left */
00126         case 4:
00127         {
00128             for (x = RP->Xsize - 2; x > 0; x--)
00129             {
00130                 for (y = RP->Ysize - 2; y > 0; y--)
00131                 {
00132                     if (layout[x][y] == target)
00133                     {
00134                         *fx = x;
00135                         *fy = y;
00136 
00137                         return;
00138                     }
00139                 }
00140             }
00141 
00142             break;
00143         }
00144     }
00145 }
00146 
00159 void place_exits(mapstruct *map, char **maze, char *exitstyle, int orientation, RMParms *RP)
00160 {
00161     mapstruct *style_map_down = NULL, *style_map_up = NULL;
00162     object *the_exit_down;
00163     object *the_exit_up;
00164     /* magic mouth saying this is a random map. */
00165     object *random_sign;
00166     int cx = -1, cy = -1;
00167     int upx = -1, upy = -1;
00168     int downx = -1, downy = -1, j;
00169 
00170     if (orientation == 0)
00171     {
00172         orientation = RANDOM() % 6 + 1;
00173     }
00174 
00175     switch (orientation)
00176     {
00177         case 1:
00178             style_map_up = find_style("/styles/exitstyles/up", exitstyle, -1);
00179             style_map_down = find_style("/styles/exitstyles/down", exitstyle, -1);
00180 
00181             break;
00182 
00183         case 2:
00184             style_map_up = find_style("/styles/exitstyles/down", exitstyle, -1);
00185             style_map_down = find_style("/styles/exitstyles/up", exitstyle, -1);
00186 
00187             break;
00188 
00189         default:
00190             style_map_up = find_style("/styles/exitstyles/generic", exitstyle, -1);
00191             style_map_down = style_map_up;
00192 
00193             break;
00194     }
00195 
00196     if (style_map_up == NULL)
00197     {
00198         the_exit_up = arch_to_object(find_archetype("exit"));
00199     }
00200     else
00201     {
00202         object *tmp = pick_random_object(style_map_up);
00203         the_exit_up = arch_to_object(tmp->arch);
00204     }
00205 
00206     /* we need a down exit only if we're recursing. */
00207     if (RP->dungeon_level < RP->dungeon_depth || RP->final_map[0] != 0)
00208     {
00209         if (style_map_down == NULL)
00210         {
00211             the_exit_down = arch_to_object(find_archetype("exit"));
00212         }
00213         else
00214         {
00215             object *tmp = pick_random_object(style_map_down);
00216             the_exit_down = arch_to_object(tmp->arch);
00217         }
00218     }
00219     else
00220     {
00221         the_exit_down = NULL;
00222     }
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     FREE_AND_COPY_HASH(the_exit_up->slaying, RP->origin_map);
00228 
00229     /* figure out where to put the entrance */
00230 
00231     /* First, look for a '<' char */
00232     find_in_layout(0, '<', &upx, &upy, maze, RP);
00233 
00234     /* next, look for a C, the map center.  */
00235     find_in_layout(0, 'C', &cx, &cy, maze, RP);
00236 
00237     /* If we didn't find an up, find an empty place far from the center */
00238     if (upx == -1 && cx != -1)
00239     {
00240         if (cx > RP->Xsize / 2)
00241         {
00242             upx = 1;
00243         }
00244         else
00245         {
00246             upx = RP->Xsize - 2;
00247         }
00248 
00249         if (cy > RP->Ysize / 2)
00250         {
00251             upy = 1;
00252         }
00253         else
00254         {
00255             upy = RP->Ysize - 2;
00256         }
00257 
00258         /* find an empty place far from the center */
00259         if (upx == 1 && upy == 1)
00260         {
00261             find_in_layout(1, 0, &upx, &upy, maze, RP);
00262         }
00263         else if (upx == 1 && upy > 1)
00264         {
00265             find_in_layout(3, 0, &upx, &upy, maze, RP);
00266         }
00267         else if (upx > 1 && upy == 1)
00268         {
00269             find_in_layout(2, 0, &upx, &upy, maze, RP);
00270         }
00271         else if (upx > 1 && upy > 1)
00272         {
00273             find_in_layout(4, 0, &upx, &upy, maze, RP);
00274         }
00275     }
00276 
00277     /* No indication of where to place the exit, so just place it. */
00278     if (upx == -1)
00279     {
00280         find_in_layout(0, 0, &upx, &upy, maze, RP);
00281     }
00282 
00283     the_exit_up->x = upx;
00284     the_exit_up->y = upy;
00285 
00286     /* Surround the exits with notices that this is a random map. */
00287     for (j = 1; j < 9; j++)
00288     {
00289         if (!wall_blocked(map, the_exit_up->x + freearr_x[j], the_exit_up->y + freearr_y[j]))
00290         {
00291             char buf[MAX_BUF];
00292 
00293             random_sign = get_archetype("sign");
00294             random_sign->x = the_exit_up->x + freearr_x[j];
00295             random_sign->y = the_exit_up->y + freearr_y[j];
00296 
00297             snprintf(buf, sizeof(buf), "This is a random map.\nLevel: %d\n", RP->dungeon_level);
00298             FREE_AND_COPY_HASH(random_sign->msg, buf);
00299             insert_ob_in_map(random_sign, map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
00300         }
00301     }
00302 
00303     /* Block the exit so things don't get dumped on top of it. */
00304     SET_FLAG(the_exit_up, FLAG_NO_PASS);
00305     insert_ob_in_map(the_exit_up, map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
00306     maze[the_exit_up->x][the_exit_up->y] = '<';
00307 
00308     /* Set the starting x, y for this map */
00309     MAP_ENTER_X(map) = the_exit_up->x;
00310     MAP_ENTER_Y(map) = the_exit_up->y;
00311 
00312     /* First, look for a '>' character */
00313     find_in_layout(0, '>', &downx, &downy, maze, RP);
00314 
00315     /* If no > is found use C */
00316     if (downx == -1)
00317     {
00318         downx = cx;
00319         downy = cy;
00320     }
00321 
00322     /* make the other exit far away from this one if
00323      * there's no center. */
00324     if (downx == -1)
00325     {
00326         if (upx > RP->Xsize / 2)
00327         {
00328             downx = 1;
00329         }
00330         else
00331         {
00332             downx = RP->Xsize - 2;
00333         }
00334 
00335         if (upy > RP->Ysize / 2)
00336         {
00337             downy = 1;
00338         }
00339         else
00340         {
00341             downy = RP->Ysize - 2;
00342         }
00343 
00344         /* find an empty place far from the entrance */
00345         if (downx == 1 && downy == 1)
00346         {
00347             find_in_layout(1, 0, &downx, &downy, maze, RP);
00348         }
00349         else if (downx == 1 && downy > 1)
00350         {
00351             find_in_layout(3, 0, &downx, &downy, maze, RP);
00352         }
00353         else if (downx > 1 && downy == 1)
00354         {
00355             find_in_layout(2, 0, &downx, &downy, maze, RP);
00356         }
00357         else if (downx > 1 && downy > 1)
00358         {
00359             find_in_layout(4, 0, &downx, &downy, maze, RP);
00360         }
00361     }
00362 
00363     /* No indication of where to place the down exit, so just place it */
00364     if (downx == -1)
00365     {
00366         find_in_layout(0, 0, &downx, &downy, maze, RP);
00367     }
00368 
00369     if (the_exit_down)
00370     {
00371         int i = find_first_free_spot(the_exit_down->arch, NULL, map, downx, downy);
00372 
00373         the_exit_down->x = downx + freearr_x[i];
00374         the_exit_down->y = downy + freearr_y[i];
00375 
00376         RP->origin_x = the_exit_down->x;
00377         RP->origin_y = the_exit_down->y;
00378 
00379         /* the identifier for making a random map. */
00380         if (RP->dungeon_level >= RP->dungeon_depth && RP->final_map[0] != '\0')
00381         {
00382             mapstruct *new_map;
00383             object *the_exit_back = arch_to_object(the_exit_up->arch), *tmp;
00384 
00385             /* load it */
00386             if ((new_map = ready_map_name(RP->final_map, MAP_UNIQUE(map) ? 1 : 0)) == NULL)
00387             {
00388                 return;
00389             }
00390 
00391             FREE_AND_COPY_HASH(the_exit_down->slaying, RP->final_map);
00392             FREE_AND_COPY_HASH(new_map->path, RP->final_map);
00393             the_exit_down->stats.hp = MAP_ENTER_X(new_map);
00394             the_exit_down->stats.sp = MAP_ENTER_Y(new_map);
00395 
00396             for (tmp = GET_MAP_OB(new_map, MAP_ENTER_X(new_map), MAP_ENTER_Y(new_map)); tmp; tmp = tmp->above)
00397             {
00398                 /* Remove exit back to previous random map.  There should only be one
00399                  * which is why we break out.  To try to process more than one
00400                  * would require keeping a 'next' pointer, ad free_object kills tmp, which
00401                  * breaks the for loop. */
00402                 if (tmp->type == EXIT)
00403                 {
00404                     remove_ob(tmp);
00405                     break;
00406                 }
00407             }
00408 
00409             /* Setup the exit back */
00410             FREE_AND_ADD_REF_HASH(the_exit_back->slaying, map->path);
00411             the_exit_back->stats.hp = the_exit_down->x;
00412             the_exit_back->stats.sp = the_exit_down->y;
00413             the_exit_back->x = MAP_ENTER_X(new_map);
00414             the_exit_back->y = MAP_ENTER_Y(new_map);
00415 
00416             insert_ob_in_map(the_exit_back, new_map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
00417 
00418             /* So it gets swapped out */
00419             set_map_timeout(new_map);
00420         }
00421         else
00422         {
00423             char buf[2048];
00424 
00425             write_map_parameters_to_string(buf, RP);
00426             FREE_AND_COPY_HASH(the_exit_down->msg, buf);
00427             FREE_AND_COPY_HASH(the_exit_down->slaying, "/random/");
00428             the_exit_down->stats.hp = 0;
00429             the_exit_down->stats.sp = 0;
00430         }
00431 
00432         /* Block the exit so things don't get dumped on top of it. */
00433         SET_FLAG(the_exit_down, FLAG_NO_PASS);
00434 
00435         insert_ob_in_map(the_exit_down, map, NULL, INS_NO_MERGE | INS_NO_WALK_ON);
00436 
00437         maze[the_exit_down->x][the_exit_down->y] = '>';
00438     }
00439 }
00440 
00447 void unblock_exits(mapstruct *map, char **maze, RMParms *RP)
00448 {
00449     int x, y;
00450     object *walk;
00451 
00452     for (x = 0; x < RP->Xsize; x++)
00453     {
00454         for (y = 0; y < RP->Ysize; y++)
00455         {
00456             if (maze[x][y] == '>' || maze[x][y] == '<')
00457             {
00458                 for (walk = get_map_ob(map, x, y); walk != NULL; walk = walk->above)
00459                 {
00460                     if (QUERY_FLAG(walk, FLAG_NO_PASS) && walk->type != DOOR)
00461                     {
00462                         CLEAR_FLAG(walk, FLAG_NO_PASS);
00463                         update_object(walk, UP_OBJ_FLAGS);
00464                     }
00465                 }
00466             }
00467         }
00468     }
00469 }