Crossfire Server, Trunk
special.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "global.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "random_map.h"
25 #include "rproto.h"
26 
31 #define NUM_OF_SPECIAL_TYPES 4
32 #define NO_SPECIAL 0
33 #define SPECIAL_SUBMAP 1
34 #define SPECIAL_FOUNTAIN 2
35 #define SPECIAL_EXIT 3
36 
42 #define GLORY_HOLE 1
43 #define ORC_ZONE 2
44 #define MINING_ZONE 3
45 #define NR_OF_HOLE_TYPES 3
46 
59 void nuke_map_region(mapstruct *map, int xstart, int ystart, int xsize, int ysize)
60 {
61  int i, j;
62 
63  for (i = xstart; i < xstart+xsize; i++)
64  for (j = ystart; j < ystart+ysize; j++) {
65  FOR_MAP_PREPARE(map, i, j, tmp) {
66  if (!QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
67  tmp = HEAD(tmp);
70  }
71  }
73  }
74 }
75 
86 void include_map_in_map(mapstruct *dest_map, const mapstruct *in_map, int x, int y)
87 {
88  int i, j;
89  object *new_ob;
90 
91  /* First, splatter everything in the dest map at the location */
92  nuke_map_region(dest_map, x, y, MAP_WIDTH(in_map), MAP_HEIGHT(in_map));
93 
94  for (i = 0; i < MAP_WIDTH(in_map); i++)
95  for (j = 0; j < MAP_HEIGHT(in_map); j++) {
96  FOR_MAP_PREPARE(in_map, i, j, tmp) {
97  /* don't copy things with multiple squares: must be dealt with
98  specially. */
99  if (tmp->head != NULL) {
100  continue;
101  }
102  new_ob = object_create_arch(tmp->arch);
103  object_copy_with_inv(tmp, new_ob);
104  if (QUERY_FLAG(tmp, FLAG_IS_LINKED)) {
105  add_button_link(new_ob, dest_map, tmp->path_attuned);
106  }
107  object_insert_in_map_at(new_ob, dest_map, NULL, INS_NO_MERGE|INS_NO_WALK_ON, i + x, j + y);
108  }
109  FOR_MAP_FINISH();
110  }
111 
112  /* Copy shop-related information.
113  * This ensures that, if a shop map is included, its information is correctly
114  * copied.
115  * Most of the time dest_map won't have any information set (random map), but better
116  * safe than sorry.
117  */
118 
119  if (in_map->shopgreed) {
120  dest_map->shopgreed = in_map->shopgreed;
121  }
122  if (in_map->shopmax) {
123  dest_map->shopmax = in_map->shopmax;
124  }
125  if (in_map->shopmin) {
126  dest_map->shopmin = in_map->shopmin;
127  }
128  if (in_map->shoprace) {
129  FREE_AND_CLEAR(dest_map->shoprace);
130  dest_map->shoprace = strdup_local(in_map->shoprace);
131  }
132  if (in_map->shopitems) {
133  FREE_AND_CLEAR(dest_map->shopitems);
134  dest_map->shopitems = CALLOC(in_map->shopitems[0].index + 1, sizeof(shopitems));
135  memcpy(dest_map->shopitems, in_map->shopitems, in_map->shopitems[0].index * sizeof(shopitems));
136  }
137 }
138 
154 int find_spot_for_submap(mapstruct *map, char **layout, int *ix, int *iy, int xsize, int ysize)
155 {
156  int tries;
157  int i = 0, j = 0; /* initialization may not be needed but prevents compiler warnings */
158  int is_occupied = 0;
159  int l, m;
160 
161  /* don't even try to place a submap into a map if the big map isn't
162  sufficiently large. */
163  if (2*xsize > MAP_WIDTH(map) || 2*ysize > MAP_HEIGHT(map)) {
164  return 0;
165  }
166 
167  tries = 20;
169  /* can't break layout, so try harder */
170  tries = 50;
171  }
172 
173  /* search for a completely free spot. */
174  for (; tries >= 0; tries--) {
175  /* pick a random location in the layout */
176  i = RANDOM()%(MAP_WIDTH(map)-xsize-2)+1;
177  j = RANDOM()%(MAP_HEIGHT(map)-ysize-2)+1;
178  is_occupied = 0;
179  for (l = i; l < i+xsize; l++)
180  for (m = j; m < j+ysize; m++) {
181  is_occupied |= layout[l][m];
182  }
183  if (!is_occupied) {
184  break;
185  }
186  }
187 
188  /* if we failed, relax the restrictions */
189  if (is_occupied && settings.special_break_map) { /* failure, try a relaxed placement if allowed. */
190  /* pick a random location in the layout */
191  for (tries = 0; tries < 10; tries++) {
192  i = RANDOM()%(MAP_WIDTH(map)-xsize-2)+1;
193  j = RANDOM()%(MAP_HEIGHT(map)-ysize-2)+1;
194  is_occupied = 0;
195  for (l = i; l < i+xsize; l++)
196  for (m = j; m < j+ysize; m++)
197  if (layout[l][m] == 'C' || layout[l][m] == '>' || layout[l][m] == '<') {
198  is_occupied |= 1;
199  }
200  }
201  }
202  if (is_occupied) {
203  return 0;
204  }
205  *ix = i;
206  *iy = j;
207  return 1;
208 }
209 
218 {
219  int ix, iy, i = -1, tries = 0;
220  mapstruct *fountain_style = find_style("/styles/misc", "fountains", -1);
221  const archetype *fountain = find_archetype("fountain");
222  if (fountain == NULL) {
223  return;
224  }
225  object *potion = object_new();
226 
227  object_copy_with_inv(pick_random_object(fountain_style), potion);
228  while (i < 0 && tries < 10) {
229  ix = RANDOM()%(MAP_WIDTH(map)-2)+1;
230  iy = RANDOM()%(MAP_HEIGHT(map)-2)+1;
231  i = object_find_first_free_spot(potion, map, ix, iy);
232  tries++;
233  };
234  if (i == -1) { /* can't place fountain */
236  return;
237  }
238  ix += freearr_x[i];
239  iy += freearr_y[i];
240  potion->speed = fountain->clone.speed;
241  potion->face = fountain->clone.face;
242  potion->anim_speed = fountain->clone.anim_speed;
243  potion->animation = fountain->clone.animation;
244  if (QUERY_FLAG(&fountain->clone, FLAG_ANIMATE)) {
245  SET_FLAG(potion, FLAG_ANIMATE);
247  } else {
248  CLEAR_FLAG(potion, FLAG_ANIMATE);
249  }
250  object_update_speed(potion);
251  SET_FLAG(potion, FLAG_NO_PICK);
252  SET_FLAG(potion, FLAG_IDENTIFIED);
253  FREE_AND_COPY(potion->name, fountain->clone.name);
254  FREE_AND_COPY(potion->name_pl, fountain->clone.name_pl);
255  object_set_value(potion, "on_use_yield", fountain->name, 1);
256  /*
257  * Giving no material and no materialname makes the fountain
258  * not get destroyed by spells.
259  * -- SilverNexus 2015-05-15
260  */
261  potion->material = 0;
262  // Free the string if it exists
263  if (potion->materialname)
265  object_insert_in_map_at(potion, map, NULL, 0, ix, iy);
266 }
267 
277 void place_special_exit(mapstruct *map, int hole_type, const RMParms *RP)
278 {
279  int ix, iy, i = -1;
280  char *buf;
281  const char *style, *decor, *mon;
282  mapstruct *exit_style = find_style("/styles/misc", "obscure_exits", -1);
283  int g_xsize, g_ysize;
284  object *the_exit;
285  RMParms hole;
286 
287  if (!exit_style) {
288  return;
289  }
290 
291  the_exit = object_new();
292 
293  object_copy(pick_random_object(exit_style), the_exit);
294 
295  while (i < 0) {
296  ix = RANDOM()%(MAP_WIDTH(map)-2)+1;
297  iy = RANDOM()%(MAP_HEIGHT(map)-2)+1;
298  i = object_find_first_free_spot(the_exit, map, ix, iy);
299  }
300 
301  if (!hole_type) {
302  hole_type = RANDOM()%NR_OF_HOLE_TYPES+1;
303  }
304 
305  switch (hole_type) {
306  case GLORY_HOLE: { /* treasures */
307  g_xsize = RANDOM()%3+4+RP->difficulty/4;
308  g_ysize = RANDOM()%3+4+RP->difficulty/4;
309  style = "onion";
310  decor = "wealth2";
311  mon = "none";
312  break;
313  }
314 
315  case ORC_ZONE: { /* hole with orcs in it. */
316  g_xsize = RANDOM()%3+4+RP->difficulty/4;
317  g_ysize = RANDOM()%3+4+RP->difficulty/4;
318  style = "onion";
319  decor = "wealth2";
320  mon = "orc";
321  break;
322  }
323 
324  case MINING_ZONE: { /* hole with orcs in it. */
325  g_xsize = RANDOM()%9+4+RP->difficulty/4;
326  g_ysize = RANDOM()%9+4+RP->difficulty/4;
327  style = "maze";
328  decor = "minerals2";
329  mon = "none";
330  break;
331  }
332 
333  default: /* undefined */
334  LOG(llevError, "place_special_exit: undefined hole type %d\n", hole_type);
335  return;
336  break;
337  }
338 
339  /* Need to be at least this size, otherwise the load
340  * code will generate new size values which are too large.
341  */
342  if (g_xsize < MIN_RANDOM_MAP_SIZE) {
343  g_xsize = MIN_RANDOM_MAP_SIZE;
344  }
345  if (g_ysize < MIN_RANDOM_MAP_SIZE) {
346  g_ysize = MIN_RANDOM_MAP_SIZE;
347  }
348 
349  memset(&hole, 0, sizeof(hole));
350  hole.Xsize = g_xsize;
351  hole.Ysize = g_ysize;
352  strcpy(hole.wallstyle, RP->wallstyle);
353  strcpy(hole.floorstyle, RP->floorstyle);
354  strcpy(hole.monsterstyle, mon);
355  strcpy(hole.treasurestyle, "none");
356  strcpy(hole.layoutstyle, style);
357  strcpy(hole.decorstyle, decor);
358  strcpy(hole.doorstyle, "none");
359  strcpy(hole.exitstyle, RP->exitstyle);
360  strcpy(hole.final_map, "");
361  strcpy(hole.exit_on_final_map, "");
362  strcpy(hole.this_map, "");
364  hole.layoutoptions2 = 0;
365  hole.symmetry = 1;
366  hole.dungeon_depth = RP->dungeon_level;
367  hole.dungeon_level = RP->dungeon_level;
368  hole.difficulty = RP->difficulty;
369  hole.difficulty_given = RP->difficulty;
370  hole.decoroptions = -1;
371  hole.orientation = 1;
372  hole.origin_x = 0;
373  hole.origin_y = 0;
374  hole.random_seed = 0;
375  hole.treasureoptions = 0;
377 
379  object_set_msg(the_exit, buf);
380  free(buf);
381 
382  the_exit->slaying = add_string("/!");
383 
384  object_insert_in_map_at(the_exit, map, NULL, 0, ix+freearr_x[i], iy+freearr_y[i]);
385 }
386 
397 {
398  mapstruct *special_map;
399  int ix, iy; /* map insertion locatons */
400  int special_type; /* type of special to make */
401 
402  special_type = RANDOM()%NUM_OF_SPECIAL_TYPES;
403  switch (special_type) {
404  /* includes a special map into the random map being made. */
405  case SPECIAL_SUBMAP: {
406  special_map = find_style("/styles/specialmaps", NULL, RP->difficulty);
407  if (special_map == NULL) {
408  return;
409  }
410 
411  if (find_spot_for_submap(map, layout, &ix, &iy, MAP_WIDTH(special_map), MAP_HEIGHT(special_map))) {
412  include_map_in_map(map, special_map, ix, iy);
413  }
414  break;
415  }
416 
417  /* Make a special fountain: an unpickable potion disguised as
418  * a fountain, or rather, colocated with a fountain.
419  */
420  case SPECIAL_FOUNTAIN: {
422  break;
423  }
424 
425  /* Make an exit to another random map, e.g. a gloryhole. */
426  case SPECIAL_EXIT: {
427  place_special_exit(map, 0, RP);
428  break;
429  }
430  }
431 }
Settings::special_break_map
uint8_t special_break_map
Definition: global.h:320
object_find_first_free_spot
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.c:3570
RMParms::layoutstyle
char layoutstyle[RM_SIZE]
Definition: random_map.h:41
global.h
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Definition: object.h:568
banquet.l
l
Definition: banquet.py:164
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
random_map.h
object_remove
void object_remove(object *op)
Definition: object.c:1819
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
NR_OF_HOLE_TYPES
#define NR_OF_HOLE_TYPES
Definition: special.c:45
obj::face
const Face * face
Definition: object.h:336
layout
Definition: main.c:85
RMParms::orientation
int orientation
Definition: random_map.h:87
RMParms::symmetry
int symmetry
Definition: random_map.h:79
llevError
@ llevError
Definition: logger.h:11
FLAG_CLIENT_ANIM_RANDOM
#define FLAG_CLIENT_ANIM_RANDOM
Definition: define.h:241
RMParms::difficulty_given
int difficulty_given
Definition: random_map.h:82
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
strdup_local
#define strdup_local
Definition: compat.h:29
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
object_new
object * object_new(void)
Definition: object.c:1255
obj::anim_speed
uint8_t anim_speed
Definition: object.h:422
RMParms::Ysize
int Ysize
Definition: random_map.h:75
find_spot_for_submap
int find_spot_for_submap(mapstruct *map, char **layout, int *ix, int *iy, int xsize, int ysize)
Definition: special.c:154
RMParms::dungeon_depth
int dungeon_depth
Definition: random_map.h:85
SPECIAL_EXIT
#define SPECIAL_EXIT
Definition: special.c:35
CALLOC
#define CALLOC(x, y)
Definition: compat.h:31
RMParms::origin_y
int origin_y
Definition: random_map.h:88
Ice.tmp
int tmp
Definition: Ice.py:207
find_style
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.c:180
RMParms::dungeon_level
int dungeon_level
Definition: random_map.h:84
GLORY_HOLE
#define GLORY_HOLE
Definition: special.c:42
OPT_WALLS_ONLY
#define OPT_WALLS_ONLY
Definition: random_map.h:135
NUM_OF_SPECIAL_TYPES
#define NUM_OF_SPECIAL_TYPES
Definition: special.c:31
RMParms
Definition: random_map.h:14
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:299
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:305
archt
Definition: object.h:469
settings
struct Settings settings
Definition: init.c:39
SPECIAL_FOUNTAIN
#define SPECIAL_FOUNTAIN
Definition: special.c:34
obj::slaying
sstring slaying
Definition: object.h:322
mapdef::shopmax
uint64_t shopmax
Definition: map.h:353
RMParms::origin_x
int origin_x
Definition: random_map.h:89
m
static event_registration m
Definition: citylife.cpp:427
mapdef::shopitems
struct shopitem * shopitems
Definition: map.h:349
disinfect.map
map
Definition: disinfect.py:4
object_copy_with_inv
void object_copy_with_inv(const object *src_ob, object *dest_ob)
Definition: object.c:1194
obj::name
sstring name
Definition: object.h:314
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:1064
mon
object * mon
Definition: comet_perf.c:75
RMParms::this_map
char this_map[RM_SIZE]
Definition: random_map.h:65
RMParms::decorstyle
char decorstyle[RM_SIZE]
Definition: random_map.h:48
RMParms::final_map
char final_map[RM_SIZE]
Definition: random_map.h:57
CFInsulter.style
style
Definition: CFInsulter.py:69
obj::name_pl
sstring name_pl
Definition: object.h:318
HEAD
#define HEAD(op)
Definition: object.h:593
nuke_map_region
void nuke_map_region(mapstruct *map, int xstart, int ystart, int xsize, int ysize)
Definition: special.c:59
MIN_RANDOM_MAP_SIZE
#define MIN_RANDOM_MAP_SIZE
Definition: random_map.h:153
MINING_ZONE
#define MINING_ZONE
Definition: special.c:44
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:201
place_fountain_with_specials
void place_fountain_with_specials(mapstruct *map)
Definition: special.c:217
INS_NO_MERGE
#define INS_NO_MERGE
Definition: object.h:566
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:301
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
mapdef::shoprace
char * shoprace
Definition: map.h:350
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.c:4470
obj::speed
float speed
Definition: object.h:332
rproto.h
RMParms::wallstyle
char wallstyle[RM_SIZE]
Definition: random_map.h:19
place_special_exit
void place_special_exit(mapstruct *map, int hole_type, const RMParms *RP)
Definition: special.c:277
mapdef
Definition: map.h:317
include_map_in_map
void include_map_in_map(mapstruct *dest_map, const mapstruct *in_map, int x, int y)
Definition: special.c:86
RMParms::doorstyle
char doorstyle[RM_SIZE]
Definition: random_map.h:43
obj::animation
const Animations * animation
Definition: object.h:421
obj::material
uint16_t material
Definition: object.h:352
place_specials_in_map
void place_specials_in_map(mapstruct *map, char **layout, RMParms *RP)
Definition: special.c:396
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:78
mapdef::shopgreed
double shopgreed
Definition: map.h:351
RANDOM
#define RANDOM()
Definition: define.h:644
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:195
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.c:4781
RMParms::difficulty
int difficulty
Definition: random_map.h:80
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Definition: global.h:190
archt::clone
object clone
Definition: object.h:473
RMParms::random_seed
int random_seed
Definition: random_map.h:90
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
add_button_link
void add_button_link(object *button, mapstruct *map, int connected)
Definition: button.c:656
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:284
RMParms::exit_on_final_map
char exit_on_final_map[RM_SIZE]
Definition: random_map.h:70
pick_random_object
object * pick_random_object(mapstruct *style)
Definition: style.c:289
RMParms::treasurestyle
char treasurestyle[RM_SIZE]
Definition: random_map.h:39
RMParms::treasureoptions
int treasureoptions
Definition: random_map.h:94
shopitem::index
int index
Definition: map.h:303
diamondslots.y
y
Definition: diamondslots.py:16
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
buf
StringBuffer * buf
Definition: readable.c:1610
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:80
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1330
RMParms::floorstyle
char floorstyle[RM_SIZE]
Definition: random_map.h:29
obj::materialname
sstring materialname
Definition: object.h:351
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2080
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
RMParms::monsterstyle
char monsterstyle[RM_SIZE]
Definition: random_map.h:34
archt::name
sstring name
Definition: object.h:470
FLAG_IS_LINKED
#define FLAG_IS_LINKED
Definition: define.h:315
RMParms::layoutoptions1
int layoutoptions1
Definition: random_map.h:77
RMParms::decoroptions
int decoroptions
Definition: random_map.h:86
RMParms::exitstyle
char exitstyle[RM_SIZE]
Definition: random_map.h:63
ORC_ZONE
#define ORC_ZONE
Definition: special.c:43
mapdef::shopmin
uint64_t shopmin
Definition: map.h:352
shopitem
Definition: map.h:297
RMParms::Xsize
int Xsize
Definition: random_map.h:74
RMParms::layoutoptions2
int layoutoptions2
Definition: random_map.h:78
write_map_parameters_to_string
StringBuffer * write_map_parameters_to_string(const RMParms *RP)
Definition: random_map.c:750
RMParms::difficulty_increase
float difficulty_increase
Definition: random_map.h:83
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
SPECIAL_SUBMAP
#define SPECIAL_SUBMAP
Definition: special.c:33
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261