Crossfire Server, Trunk  R20513
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);
68  object_remove(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  object *potion = object_new();
223 
224  object_copy_with_inv(pick_random_object(fountain_style), potion);
225  while (i < 0 && tries < 10) {
226  ix = RANDOM()%(MAP_WIDTH(map)-2)+1;
227  iy = RANDOM()%(MAP_HEIGHT(map)-2)+1;
228  i = object_find_first_free_spot(potion, map, ix, iy);
229  tries++;
230  };
231  if (i == -1) { /* can't place fountain */
233  return;
234  }
235  ix += freearr_x[i];
236  iy += freearr_y[i];
237  potion->speed = fountain->clone.speed;
238  potion->face = fountain->clone.face;
239  potion->anim_speed = fountain->clone.anim_speed;
240  potion->animation_id = fountain->clone.animation_id;
241  if (QUERY_FLAG(&fountain->clone, FLAG_ANIMATE)) {
242  SET_FLAG(potion, FLAG_ANIMATE);
244  } else {
245  CLEAR_FLAG(potion, FLAG_ANIMATE);
246  }
247  object_update_speed(potion);
248  SET_FLAG(potion, FLAG_NO_PICK);
249  SET_FLAG(potion, FLAG_IDENTIFIED);
250  FREE_AND_COPY(potion->name, fountain->clone.name);
251  FREE_AND_COPY(potion->name_pl, fountain->clone.name_pl);
252  object_set_value(potion, "on_use_yield", fountain->name, 1);
253  /*
254  * Giving no material and no materialname makes the fountain
255  * not get destroyed by spells.
256  * -- SilverNexus 2015-05-15
257  */
258  potion->material = 0;
259  // Free the string if it exists
260  if (potion->materialname)
262  object_insert_in_map_at(potion, map, NULL, 0, ix, iy);
263 }
264 
274 void place_special_exit(mapstruct *map, int hole_type, const RMParms *RP)
275 {
276  int ix, iy, i = -1;
277  char *buf;
278  const char *style, *decor, *mon;
279  mapstruct *exit_style = find_style("/styles/misc", "obscure_exits", -1);
280  int g_xsize, g_ysize;
281  object *the_exit;
282  RMParms hole;
283 
284  if (!exit_style) {
285  return;
286  }
287 
288  the_exit = object_new();
289 
290  object_copy(pick_random_object(exit_style), the_exit);
291 
292  while (i < 0) {
293  ix = RANDOM()%(MAP_WIDTH(map)-2)+1;
294  iy = RANDOM()%(MAP_HEIGHT(map)-2)+1;
295  i = object_find_first_free_spot(the_exit, map, ix, iy);
296  }
297 
298  if (!hole_type) {
299  hole_type = RANDOM()%NR_OF_HOLE_TYPES+1;
300  }
301 
302  switch (hole_type) {
303  case GLORY_HOLE: { /* treasures */
304  g_xsize = RANDOM()%3+4+RP->difficulty/4;
305  g_ysize = RANDOM()%3+4+RP->difficulty/4;
306  style = "onion";
307  decor = "wealth2";
308  mon = "none";
309  break;
310  }
311 
312  case ORC_ZONE: { /* hole with orcs in it. */
313  g_xsize = RANDOM()%3+4+RP->difficulty/4;
314  g_ysize = RANDOM()%3+4+RP->difficulty/4;
315  style = "onion";
316  decor = "wealth2";
317  mon = "orc";
318  break;
319  }
320 
321  case MINING_ZONE: { /* hole with orcs in it. */
322  g_xsize = RANDOM()%9+4+RP->difficulty/4;
323  g_ysize = RANDOM()%9+4+RP->difficulty/4;
324  style = "maze";
325  decor = "minerals2";
326  mon = "none";
327  break;
328  }
329 
330  default: /* undefined */
331  LOG(llevError, "place_special_exit: undefined hole type %d\n", hole_type);
332  return;
333  break;
334  }
335 
336  /* Need to be at least this size, otherwise the load
337  * code will generate new size values which are too large.
338  */
339  if (g_xsize < MIN_RANDOM_MAP_SIZE) {
340  g_xsize = MIN_RANDOM_MAP_SIZE;
341  }
342  if (g_ysize < MIN_RANDOM_MAP_SIZE) {
343  g_ysize = MIN_RANDOM_MAP_SIZE;
344  }
345 
346  memset(&hole, 0, sizeof(hole));
347  hole.Xsize = g_xsize;
348  hole.Ysize = g_ysize;
349  strcpy(hole.wallstyle, RP->wallstyle);
350  strcpy(hole.floorstyle, RP->floorstyle);
351  strcpy(hole.monsterstyle, mon);
352  strcpy(hole.treasurestyle, "none");
353  strcpy(hole.layoutstyle, style);
354  strcpy(hole.decorstyle, decor);
355  strcpy(hole.doorstyle, "none");
356  strcpy(hole.exitstyle, RP->exitstyle);
357  strcpy(hole.final_map, "");
358  strcpy(hole.exit_on_final_map, "");
359  strcpy(hole.this_map, "");
361  hole.layoutoptions2 = 0;
362  hole.symmetry = 1;
363  hole.dungeon_depth = RP->dungeon_level;
364  hole.dungeon_level = RP->dungeon_level;
365  hole.difficulty = RP->difficulty;
366  hole.difficulty_given = RP->difficulty;
367  hole.decoroptions = -1;
368  hole.orientation = 1;
369  hole.origin_x = 0;
370  hole.origin_y = 0;
371  hole.random_seed = 0;
372  hole.treasureoptions = 0;
374 
376  object_set_msg(the_exit, buf);
377  free(buf);
378 
379  the_exit->slaying = add_string("/!");
380 
381  object_insert_in_map_at(the_exit, map, NULL, 0, ix+freearr_x[i], iy+freearr_y[i]);
382 }
383 
394 {
395  mapstruct *special_map;
396  int ix, iy; /* map insertion locatons */
397  int special_type; /* type of special to make */
398 
399  special_type = RANDOM()%NUM_OF_SPECIAL_TYPES;
400  switch (special_type) {
401  /* includes a special map into the random map being made. */
402  case SPECIAL_SUBMAP: {
403  special_map = find_style("/styles/specialmaps", NULL, RP->difficulty);
404  if (special_map == NULL) {
405  return;
406  }
407 
408  if (find_spot_for_submap(map, layout, &ix, &iy, MAP_WIDTH(special_map), MAP_HEIGHT(special_map))) {
409  include_map_in_map(map, special_map, ix, iy);
410  }
411  break;
412  }
413 
414  /* Make a special fountain: an unpickable potion disguised as
415  * a fountain, or rather, colocated with a fountain.
416  */
417  case SPECIAL_FOUNTAIN: {
419  break;
420  }
421 
422  /* Make an exit to another random map, e.g. a gloryhole. */
423  case SPECIAL_EXIT: {
424  place_special_exit(map, 0, RP);
425  break;
426  }
427  }
428 }
Error, serious thing.
Definition: logger.h:11
double shopgreed
How much our shopkeeper overcharges.
Definition: map.h:358
Random map parameters.
Definition: random_map.h:14
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:303
#define ORC_ZONE
Definition: special.c:43
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:316
int decoroptions
Definition: random_map.h:81
#define SET_FLAG(xyz, p)
Definition: define.h:223
uint16_t animation_id
An index into the animation array.
Definition: object.h:416
uint16_t material
What materials this object consist of.
Definition: object.h:347
#define strdup_local
Definition: compat.h:25
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:417
void object_copy_with_inv(const object *src_ob, object *dest_ob)
copy an object with an inventory...
Definition: object.c:975
char floorstyle[RM_SIZE]
Name of the floor style file, in /styles/floors, can be an empty string in which case a random one is...
Definition: random_map.h:29
object * mon
Definition: comet_perf.c:74
char final_map[RM_SIZE]
If not empty, the path of the final map this whole maze leads to.
Definition: random_map.h:52
char exit_on_final_map[RM_SIZE]
If this is "no", then no exit will be made to the final map from the previous random map...
Definition: random_map.h:65
Random map related variables.
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:80
object clone
An object from which to do object_copy()
Definition: object.h:470
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
int difficulty_given
If non zero, this means the difficulty was not zero initially.
Definition: random_map.h:77
const char * slaying
Which race to do double damage to.
Definition: object.h:319
char doorstyle[RM_SIZE]
Name of the doors style file, in /styles/doorstyles, see put_doors().
Definition: random_map.h:43
int find_spot_for_submap(mapstruct *map, char **layout, int *ix, int *iy, int xsize, int ysize)
Finds a place to put a submap into.
Definition: special.c:154
int random_seed
Definition: random_map.h:85
Global type definitions and header inclusions.
#define SPECIAL_EXIT
Definition: special.c:35
object * pick_random_object(mapstruct *style)
Picks a random object from a style map.
Definition: style.c:286
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
void nuke_map_region(mapstruct *map, int xstart, int ystart, int xsize, int ysize)
Erases all objects (except floor) in the given rectangle.
Definition: special.c:59
#define CALLOC(x, y)
Definition: compat.h:27
#define NR_OF_HOLE_TYPES
Definition: special.c:45
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
void place_fountain_with_specials(mapstruct *map)
Places a special fountain on the map.
Definition: special.c:217
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.c:4375
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
#define SPECIAL_SUBMAP
Definition: special.c:33
#define FLAG_CLIENT_ANIM_RANDOM
Client animate this, randomized.
Definition: define.h:241
int layoutoptions2
Definition: random_map.h:73
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.c:1037
const char * name_pl
The plural name of the object.
Definition: object.h:315
int symmetry
Definition: random_map.h:74
int index
Being the size of the shopitems array.
Definition: map.h:311
void place_special_exit(mapstruct *map, int hole_type, const RMParms *RP)
Place an exit with a resource map.
Definition: special.c:274
const char * materialname
Specific material name.
Definition: object.h:346
char monsterstyle[RM_SIZE]
Name of the monster style directory, in /styles/monsters, can be an empty string in which case a rand...
Definition: random_map.h:34
int layoutoptions1
Definition: random_map.h:72
uint64_t shopmin
Minimum price a shop will trade for.
Definition: map.h:359
int orientation
Definition: random_map.h:82
int treasureoptions
Definition: random_map.h:89
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
const char * name
The name of the object, obviously...
Definition: object.h:311
#define INS_NO_WALK_ON
Don&#39;t call check_walk_on against the originator.
Definition: object.h:570
int dungeon_level
Definition: random_map.h:79
#define MIN_RANDOM_MAP_SIZE
Minimal size a random should have to actually be generated.
Definition: random_map.h:146
#define SPECIAL_FOUNTAIN
Definition: special.c:34
char exitstyle[RM_SIZE]
Name of the exit style files, in /styles/exitstyles/{up,down}, can be an empty string in which case a...
Definition: random_map.h:58
void add_button_link(object *button, mapstruct *map, int connected)
Links specified object in the map.
Definition: button.c:661
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:208
float speed
The overall speed of this object.
Definition: object.h:328
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
char layoutstyle[RM_SIZE]
Contains the layout type to generate, see layoutgen() for valid types.
Definition: random_map.h:41
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:594
StringBuffer * write_map_parameters_to_string(const RMParms *RP)
Creates a suitable message for exit from RP.
Definition: random_map.c:735
void include_map_in_map(mapstruct *dest_map, const mapstruct *in_map, int x, int y)
Copy in_map into dest_map at point x,y.
Definition: special.c:86
object * object_create_arch(archetype *at)
Create a full object using the given archetype.
Definition: arch.c:736
int Ysize
Definition: random_map.h:70
int object_find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
object_find_first_free_spot(archetype, mapstruct, x, y) works like object_find_free_spot(), but it will search max number of squares.
Definition: object.c:3458
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
int Xsize
Definition: random_map.h:69
uint8_t special_break_map
If set, then submaps in random maps can break the walls.
Definition: global.h:323
float difficulty_increase
Definition: random_map.h:78
void place_specials_in_map(mapstruct *map, char **layout, RMParms *RP)
Main function for specials.
Definition: special.c:393
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:242
#define INS_NO_MERGE
Don&#39;t try to merge with other items.
Definition: object.h:568
#define RANDOM()
Definition: define.h:679
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:213
int origin_y
Definition: random_map.h:83
#define MAP_WIDTH(m)
Map width.
Definition: map.h:78
int dungeon_depth
Definition: random_map.h:80
char this_map[RM_SIZE]
Path of the map from which the random map(s) were created.
Definition: random_map.h:60
uint64_t shopmax
MMaximum price a shop will offer.
Definition: map.h:360
struct Settings settings
Server settings.
Definition: init.c:40
Shop-related information for a map.
Definition: map.h:305
#define MINING_ZONE
Definition: special.c:44
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.c:838
#define OPT_WALLS_ONLY
Only walls.
Definition: random_map.h:128
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
int difficulty
Definition: random_map.h:75
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
struct shopitem * shopitems
List of item-types the map&#39;s shop will trade in.
Definition: map.h:356
char treasurestyle[RM_SIZE]
Name of the treasures style file, in /styles/treasurestyles, can be an empty string in which case a r...
Definition: random_map.h:39
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Loads and returns the map requested.
Definition: style.c:180
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.c:4695
char * shoprace
The preffered race of the local shopkeeper.
Definition: map.h:357
This is a game-map.
Definition: map.h:325
const New_Face * face
Face with colors.
Definition: object.h:332
char decorstyle[RM_SIZE]
Name of the decor style file, in /styles/decorstyles, can be an empty string in which case a random o...
Definition: random_map.h:48
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:203
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:239
int origin_x
Definition: random_map.h:84
#define NUM_OF_SPECIAL_TYPES
Definition: special.c:31
#define GLORY_HOLE
Definition: special.c:42
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.c:1129
char wallstyle[RM_SIZE]
Name of the wall style file, in /styles/wallstyles, can be an empty string in which case a random one...
Definition: random_map.h:19
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.c:76
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
Definition: main.c:88