Crossfire Server, Branch 1.12
R12190
|
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 }