Crossfire Server, Branch 1.12  R12190
special.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_special_c =
00003  *   "$Id: special.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 2002 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 
00034 #include <global.h>
00035 #include <random_map.h>
00036 #include <rproto.h>
00037 
00042 #define NUM_OF_SPECIAL_TYPES 4
00043 #define NO_SPECIAL 0
00044 #define SPECIAL_SUBMAP 1
00045 #define SPECIAL_FOUNTAIN 2
00046 #define SPECIAL_EXIT 3
00047 
00053 #define GLORY_HOLE 1
00054 #define ORC_ZONE 2
00055 #define MINING_ZONE 3
00056 #define NR_OF_HOLE_TYPES 3
00057 
00070 void nuke_map_region(mapstruct *map, int xstart, int ystart, int xsize, int ysize) {
00071     int i, j;
00072     object *tmp;
00073 
00074     for (i = xstart; i < xstart+xsize; i++)
00075         for (j = ystart; j < ystart+ysize; j++) {
00076             for (tmp = GET_MAP_OB(map, i, j); tmp != NULL; tmp = tmp->above) {
00077                 if (!QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
00078                     if (tmp->head)
00079                         tmp = tmp->head;
00080                     remove_ob(tmp);
00081                     free_object(tmp);
00082                     tmp = GET_MAP_OB(map, i, j);
00083                 }
00084                 if (tmp == NULL)
00085                     break;
00086             }
00087         }
00088 }
00089 
00100 void include_map_in_map(mapstruct *dest_map, mapstruct *in_map, int x, int y) {
00101     int i, j;
00102     object *tmp;
00103     object *new_ob;
00104 
00105     /* First, splatter everything in the dest map at the location */
00106     nuke_map_region(dest_map, x, y, MAP_WIDTH(in_map), MAP_HEIGHT(in_map));
00107 
00108     for (i = 0; i < MAP_WIDTH(in_map); i++)
00109         for (j = 0; j < MAP_HEIGHT(in_map); j++) {
00110             for (tmp = GET_MAP_OB(in_map, i, j); tmp != NULL; tmp = tmp->above) {
00111                 /* don't copy things with multiple squares:  must be dealt with
00112                    specially. */
00113                 if (tmp->head != NULL)
00114                     continue;
00115                 new_ob = arch_to_object(tmp->arch);
00116                 copy_object_with_inv(tmp, new_ob);
00117                 if (QUERY_FLAG(tmp, FLAG_IS_LINKED))
00118                     add_button_link(new_ob, dest_map, tmp->path_attuned);
00119                 new_ob->x = i+x;
00120                 new_ob->y = j+y;
00121                 insert_multisquare_ob_in_map(new_ob, dest_map);
00122             }
00123         }
00124 }
00125 
00141 int find_spot_for_submap(mapstruct *map, char **layout, int *ix, int *iy, int xsize, int ysize) {
00142     int tries;
00143     int i = 0, j = 0; /* initialization may not be needed but prevents compiler warnings */
00144     int is_occupied = 0;
00145     int l, m;
00146 
00147     /* don't even try to place a submap into a map if the big map isn't
00148        sufficiently large. */
00149     if (2*xsize > MAP_WIDTH(map) || 2*ysize > MAP_HEIGHT(map))
00150         return 0;
00151 
00152     /* search a bit for a completely free spot. */
00153     for (tries = 0; tries < 20; tries++) {
00154         /* pick a random location in the layout */
00155         i = RANDOM()%(MAP_WIDTH(map)-xsize-2)+1;
00156         j = RANDOM()%(MAP_HEIGHT(map)-ysize-2)+1;
00157         is_occupied = 0;
00158         for (l = i; l < i+xsize; l++)
00159             for (m = j; m < j+ysize; m++)
00160                 is_occupied |= layout[l][m];
00161         if (!is_occupied)
00162             break;
00163     }
00164 
00165     /* if we failed, relax the restrictions */
00166     if (is_occupied) { /* failure, try a relaxed placer. */
00167         /* pick a random location in the layout */
00168         for (tries = 0; tries < 10; tries++) {
00169             i = RANDOM()%(MAP_WIDTH(map)-xsize-2)+1;
00170             j = RANDOM()%(MAP_HEIGHT(map)-ysize-2)+1;
00171             is_occupied = 0;
00172             for (l = i; l < i+xsize; l++)
00173                 for (m = j; m < j+ysize; m++)
00174                     if (layout[l][m] == 'C' || layout[l][m] == '>' || layout[l][m] == '<')
00175                         is_occupied |= 1;
00176         }
00177     }
00178     if (is_occupied)
00179         return 0;
00180     *ix = i;
00181     *iy = j;
00182     return 1;
00183 }
00184 
00192 void place_fountain_with_specials(mapstruct *map) {
00193     int ix, iy, i = -1, tries = 0;
00194     mapstruct *fountain_style = find_style("/styles/misc", "fountains", -1);
00195     object *fountain = create_archetype("fountain");
00196     object *potion = get_object();
00197 
00198     copy_object(pick_random_object(fountain_style), potion);
00199     while (i < 0 && tries < 10) {
00200         ix = RANDOM()%(MAP_WIDTH(map)-2)+1;
00201         iy = RANDOM()%(MAP_HEIGHT(map)-2)+1;
00202         i = find_first_free_spot(fountain, map, ix, iy);
00203         tries++;
00204     };
00205     if (i == -1) { /* can't place fountain */
00206         free_object(fountain);
00207         free_object(potion);
00208         return;
00209     }
00210     ix += freearr_x[i];
00211     iy += freearr_y[i];
00212     potion->face = fountain->face;
00213     SET_FLAG(potion, FLAG_NO_PICK);
00214     SET_FLAG(potion, FLAG_IDENTIFIED);
00215     potion->name = add_string("fountain");
00216     potion->name_pl = add_string("fountain");
00217     potion->x = ix;
00218     potion->y = iy;
00219     potion->material = M_ADAMANT;
00220     fountain->x = ix;
00221     fountain->y = iy;
00222     insert_ob_in_map(fountain, map, NULL, 0);
00223     insert_ob_in_map(potion, map, NULL, 0);
00224 }
00225 
00235 void place_special_exit(mapstruct *map, int hole_type, RMParms *RP) {
00236     int ix, iy, i = -1;
00237     char buf[HUGE_BUF];
00238     const char *style, *decor, *mon;
00239     mapstruct *exit_style = find_style("/styles/misc", "obscure_exits", -1);
00240     int g_xsize, g_ysize;
00241     object *the_exit = get_object();
00242 
00243     if (!exit_style)
00244         return;
00245 
00246     copy_object(pick_random_object(exit_style), the_exit);
00247 
00248     while (i < 0) {
00249         ix = RANDOM()%(MAP_WIDTH(map)-2)+1;
00250         iy = RANDOM()%(MAP_HEIGHT(map)-2)+1;
00251         i = find_first_free_spot(the_exit, map, ix, iy);
00252     }
00253 
00254     ix += freearr_x[i];
00255     iy += freearr_y[i];
00256     the_exit->x = ix;
00257     the_exit->y = iy;
00258 
00259     if (!hole_type)
00260         hole_type = RANDOM()%NR_OF_HOLE_TYPES+1;
00261 
00262     switch (hole_type) {
00263     case GLORY_HOLE: { /* treasures */
00264         g_xsize = RANDOM()%3+4+RP->difficulty/4;
00265         g_ysize = RANDOM()%3+4+RP->difficulty/4;
00266         style = "onion";
00267         decor = "wealth2";
00268         mon = "none";
00269         break;
00270     }
00271 
00272     case ORC_ZONE: { /* hole with orcs in it. */
00273         g_xsize = RANDOM()%3+4+RP->difficulty/4;
00274         g_ysize = RANDOM()%3+4+RP->difficulty/4;
00275         style = "onion";
00276         decor = "wealth2";
00277         mon = "orc";
00278         break;
00279     }
00280 
00281     case MINING_ZONE: { /* hole with orcs in it. */
00282         g_xsize = RANDOM()%9+4+RP->difficulty/4;
00283         g_ysize = RANDOM()%9+4+RP->difficulty/4;
00284         style = "maze";
00285         decor = "minerals2";
00286         mon = "none";
00287         break;
00288     }
00289 
00290     default:  /* undefined */
00291         LOG(llevError, "place_special_exit: undefined hole type %d\n", hole_type);
00292         return;
00293         break;
00294     }
00295 
00296     /* Need to be at least this size, otherwise the load
00297      * code will generate new size values which are too large.
00298      */
00299     if (g_xsize < MIN_RANDOM_MAP_SIZE)
00300         g_xsize = MIN_RANDOM_MAP_SIZE;
00301     if (g_ysize < MIN_RANDOM_MAP_SIZE)
00302         g_ysize = MIN_RANDOM_MAP_SIZE;
00303 
00304     write_parameters_to_string(buf, g_xsize, g_ysize, RP->wallstyle, RP->floorstyle, mon,
00305         "none", style, decor, "none", RP->exitstyle, NULL, NULL, NULL,
00306         OPT_WALLS_ONLY, 0, 0, 1, RP->dungeon_level, RP->dungeon_level,
00307         RP->difficulty, RP->difficulty, -1, 1, 0, 0, 0, 0, RP->difficulty_increase);
00308     the_exit->slaying = add_string("/!");
00309     the_exit->msg = add_string(buf);
00310 
00311     insert_ob_in_map(the_exit, map, NULL, 0);
00312 }
00313 
00323 void place_specials_in_map(mapstruct *map, char **layout, RMParms *RP) {
00324     mapstruct *special_map;
00325     int ix, iy;  /* map insertion locatons */
00326     int special_type; /* type of special to make */
00327 
00328     special_type = RANDOM()%NUM_OF_SPECIAL_TYPES;
00329     switch (special_type) {
00330         /* includes a special map into the random map being made. */
00331     case SPECIAL_SUBMAP: {
00332         special_map = find_style("/styles/specialmaps", NULL, RP->difficulty);
00333         if (special_map == NULL)
00334             return;
00335 
00336         if (find_spot_for_submap(map, layout, &ix, &iy, MAP_WIDTH(special_map), MAP_HEIGHT(special_map)))
00337             include_map_in_map(map, special_map, ix, iy);
00338         break;
00339     }
00340 
00341         /* Make a special fountain:  an unpickable potion disguised as
00342          * a fountain, or rather, colocated with a fountain.
00343          */
00344     case SPECIAL_FOUNTAIN: {
00345         place_fountain_with_specials(map);
00346         break;
00347     }
00348 
00349         /* Make an exit to another random map, e.g. a gloryhole. */
00350     case SPECIAL_EXIT: {
00351         place_special_exit(map, 0, RP);
00352         break;
00353     }
00354     }
00355 }