Crossfire Server, Trunk  1.75.0
region.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 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 
21 #include "global.h"
22 
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #ifndef WIN32 /* ---win32 exclude header */
28 #include <unistd.h>
29 #endif /* win32 */
30 
31 #include <map>
32 
45 region *get_region_by_name(const char *region_name) {
46  for (auto reg : all_regions)
47  if (!strcmp(reg->name, region_name))
48  return reg;
49 
50  for (auto reg : all_regions) {
51  if (reg->fallback) {
52  LOG(llevDebug, "region called %s requested, but not found, fallback used.\n", region_name);
53  return reg;
54  }
55  }
56  LOG(llevInfo, "Got no region or fallback for region %s.\n", region_name);
57  return NULL;
58 }
59 
73 }
74 
89 const char *get_name_of_region_for_map(const mapstruct *m) {
90  if (m->region != NULL)
91  return m->region->name;
92  for (auto reg : all_regions) {
93  if (reg->fallback)
94  return reg->name;
95  }
96  LOG(llevInfo, "map %s had no region and I couldn't find a fallback to use.\n", m->name);
97  return "unknown";
98 }
99 
117  region *reg;
118  char *substr;
119 
120  if (all_regions.empty()) {
121  return NULL;
122  }
123 
124  if (*name == '\0') {
125  for (reg = all_regions.front(); reg->parent != NULL; reg = reg->parent)
126  ;
127  return reg;
128  }
129 
130  for (auto reg : all_regions)
131  if (!strcasecmp(reg->name, name))
132  return reg;
133 
134  for (auto reg : all_regions)
135  if (reg->longname != NULL) {
136  if (!strcasecmp(reg->longname, name))
137  return reg;
138  }
139 
140  substr = NULL;
141  for (auto reg : all_regions)
142  if (reg->longname != NULL) {
143  substr = strstr(reg->longname, name);
144  if (substr != NULL)
145  return reg;
146  }
147  for (auto reg : all_regions)
148  if (reg->longname != NULL) {
149  /*
150  * This is not a bug, we want the region that is most identifiably a discrete
151  * area in the game, eg if we have 'scor', we want to return 'scorn' and not
152  * 'scornarena', regardless of their order on the list so we only look at those
153  * regions with a longname set.
154  */
155  substr = strstr(reg->name, name);
156  if (substr != NULL)
157  return reg;
158  }
159  for (auto reg : all_regions) {
160  substr = strstr(reg->name, name);
161  if (substr != NULL)
162  return reg;
163  }
164  /* if we are still here, we are going to have to give up, and give the top level region */
165  for (reg = all_regions.front(); reg->parent != NULL; reg = reg->parent)
166  ;
167  return reg;
168 }
169 
182 int region_is_child_of_region(const region *child, const region *r) {
183  if (r == NULL)
184  return -1;
185  if (child == NULL)
186  return 0;
187  if (!strcmp(child->name, r->name))
188  return 1;
189  else if (child->parent != NULL)
190  return region_is_child_of_region(child->parent, r);
191  else
192  return 0;
193 }
194 
209 const char *get_region_longname(const region *r) {
210  if (r->longname != NULL)
211  return r->longname;
212  else if (r->parent != NULL)
213  return get_region_longname(r->parent);
214  else {
215  LOG(llevDebug, "NOTICE region %s has no parent and no longname.\n", r->name);
216  return "no name can be found for the current region";
217  }
218 }
219 
230 const char *get_region_msg(const region *r) {
231  if (r->msg != NULL)
232  return r->msg;
233  else if (r->parent != NULL)
234  return get_region_msg(r->parent);
235  else {
236  LOG(llevDebug, "NOTICE region %s has no parent and no msg.\n", r->name);
237  return "no description can be found for the current region";
238  }
239 }
240 
252 object *get_jail_exit(object *op) {
253  region *reg, *orig;
254  object *exit;
255 
256  if (op->type != PLAYER) {
257  LOG(llevError, "region.c: get_jail_exit called against non-player object.\n");
258  return NULL;
259  }
260 
261  reg = get_region_by_map(op->map);
262  orig = reg;
263  while (reg != NULL) {
264  if (reg->jailmap) {
265  exit = object_new();
266  EXIT_PATH(exit) = add_string(reg->jailmap);
267  /* damned exits reset savebed and remove teleports, so the prisoner can't escape */
268  SET_FLAG(exit, FLAG_DAMNED);
269  EXIT_X(exit) = reg->jailx;
270  EXIT_Y(exit) = reg->jaily;
271  return exit;
272  } else
273  reg = reg->parent;
274  }
275  LOG(llevDebug, "No suitable jailmap for region %s was found.\n", orig ? orig->name : "(unknown region?)");
276  return NULL;
277 }
278 
294  region *add = (region *)calloc(1, sizeof(region));
295  if (add == NULL)
297 
298  return add;
299 }
300 
310 void init_regions(BufferReader *reader, const char *filename) {
311  region *add;
312  char *buf;
313 
314  char msgbuf[HUGE_BUF], *value;
315  int msgpos = 0;
316 
318  if (!all_regions.empty()) /* Only do this once */
319  return;
320 
321  std::map<region *, std::string> parents;
322 
323  add = NULL;
324  while ((buf = bufferreader_next_line(reader)) != NULL) {
325  while (isspace(*buf))
326  buf++;
327  if (*buf == 0)
328  continue; /* empty line */
329  value = strchr(buf, ' ');
330  if (value) {
331  *value = 0;
332  value++;
333  while (isspace(*value))
334  value++;
335  }
336 
337  /*
338  * This is a bizzare mutated form of the map and archetype parser
339  * rolled into one. Key is the field name, value is what it should
340  * be set to.
341  * We've already done the work to null terminate key,
342  * and strip off any leading spaces for both of these.
343  * We have not touched the newline at the end of the line -
344  * these might be needed for some values. the end pointer
345  * points to the first of the newlines.
346  * value could be NULL! It would be easy enough to just point
347  * this to "" to prevent cores, but that would let more errors slide
348  * through.
349  */
350  if (!strcmp(buf, "region")) {
351  add = get_region_struct();
352  add->name = strdup_local(value);
353  } else if (!strcmp(buf, "parent")) {
354  /*
355  * Note that this is in the initialisation code, so we don't actually
356  * assign the pointer to the parent yet, because it might not have been
357  * parsed.
358  */
359 
360  if (!add) {
361  LOG(llevError, "region.c: malformated regions file: \"parent\" before \"region\".\n");
363  }
364  if (!value) {
365  LOG(llevError, "region.c: malformated regions file: No value given for \"parent\" key.\n");
367  }
368  parents[add] = value;
369  } else if (!strcmp(buf, "longname")) {
370  if (!add) {
371  LOG(llevError, "region.c: malformated regions file: \"longname\" before \"region\".\n");
373  }
374  if (!value) {
375  LOG(llevError, "region.c: malformated regions file: No value given for \"longname\" key.\n");
377  }
378  add->longname = strdup_local(value);
379  } else if (!strcmp(buf, "jail")) {
380  /* jail entries are of the form: /path/to/map x y */
381  char path[MAX_BUF];
382  int x, y;
383 
384  if (!add) {
385  LOG(llevError, "region.c: malformated regions file: \"jail\" before \"region\".\n");
387  }
388  if (!value) {
389  LOG(llevError, "region.c: malformated regions file: No value given for \"jail\" key.\n");
391  }
392 
393  if (sscanf(value, "%[^ ] %d %d\n", path, &x, &y) != 3) {
394  LOG(llevError, "region.c: malformated regions entry: jail %s\n", value);
395  continue;
396  }
397  add->jailmap = strdup_local(path);
398  add->jailx = x;
399  add->jaily = y;
400  } else if (!strcmp(buf, "msg")) {
401  if (!add) {
402  LOG(llevError, "region.c: malformated regions file: \"msg\" before \"region\".\n");
404  }
405  char *other;
406  while ((other = bufferreader_next_line(reader)) != NULL) {
407  while (isspace(*other))
408  other++;
409  if (strcmp(other, "endmsg") == 0)
410  break;
411  else {
412  strcpy(msgbuf+msgpos, other);
413  msgpos += strlen(other);
414  strcpy(msgbuf+msgpos, "\n");
415  ++msgpos;
416  }
417  }
418  /*
419  * There may be regions with empty messages (eg, msg/endmsg
420  * with nothing between). When maps are loaded, this is done
421  * so better do it here too...
422  */
423  if (msgpos != 0)
424  add->msg = strdup_local(msgbuf);
425 
426  /* we have to reset msgpos, or the next region will store both msg blocks.*/
427  msgpos = 0;
428  } else if (!strcmp(buf, "fallback")) {
429  if (!add) {
430  LOG(llevError, "region.c: malformated regions file %s: \"fallback\" before \"region\".\n", filename);
432  }
433  if (!value) {
434  LOG(llevError, "region.c: malformated regions file %s: No value given for \"fallback\" key.\n", filename);
436  }
437  add->fallback = atoi(value);
438  } else if (!strcmp(buf, "end")) {
439  if (!add) {
440  LOG(llevError, "region.c: Ignoring spurious \"end\" between regions.\n");
441  continue;
442  }
443  all_regions.push_back(add);
444  add = NULL;
445  } else if (!strcmp(buf, "nomore")) {
446  if (add) {
447  LOG(llevError, "region.c: Last region not properly closed.\n");
448  free(add);
449  }
450  /* we have reached the end of the region specs....*/
451  break;
452  } else {
453  /* we should never get here, if we have, then something is wrong */
454  LOG(llevError, "Got unknown value in region file %s: %s %s\n", filename, buf, value);
455  }
456  }
457  if (!buf || strcmp(buf, "nomore")) {
458  LOG(llevError, "Got premature eof on regions file %s!\n", filename);
459  free(add);
460  }
461 
462  for (auto p : parents) {
463  p.first->parent = get_region_by_name(p.second.c_str());
464  if (!p.first->parent) {
465  LOG(llevError, "Couldn't find parent %s for region %s\n", p.second.c_str(), p.first->name);
466  }
467  }
468 }
PLAYER
@ PLAYER
Definition: object.h:112
get_name_of_region_for_map
const char * get_name_of_region_for_map(const mapstruct *m)
Gets the name of a region for a map.
Definition: region.cpp:89
global.h
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
get_region_struct
region * get_region_struct(void)
Allocates and zeros a region struct, this isn't free()'d anywhere, so might be a memory leak,...
Definition: region.cpp:293
region::fallback
int8_t fallback
Whether, in the event of a region not existing, this should be the one we fall back on as the default...
Definition: map.h:285
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
get_region_by_name
region * get_region_by_name(const char *region_name)
Gets a region by name.
Definition: region.cpp:45
strdup_local
#define strdup_local
Definition: compat.h:29
init_regions
void init_regions(BufferReader *reader, const char *filename)
Reads/parses the region file, and copies into a linked list of region structs.
Definition: region.cpp:310
region_is_child_of_region
int region_is_child_of_region(const region *child, const region *r)
Checks if a region is a child of another.
Definition: region.cpp:182
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:433
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
region::name
char * name
Shortend name of the region as maps refer to it.
Definition: map.h:275
buf
StringBuffer * buf
Definition: readable.cpp:1565
get_region_longname
const char * get_region_longname(const region *r)
Gets the longname of a region.
Definition: region.cpp:209
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
region::longname
char * longname
Official title of the region, this might be defined to be the same as name.
Definition: map.h:281
m
static event_registration m
Definition: citylife.cpp:424
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
region::parent
region * parent
Pointer to the region that is a parent of the current region, if a value isn't defined in the current...
Definition: map.h:276
get_region_msg
const char * get_region_msg(const region *r)
Gets a message for a region.
Definition: region.cpp:230
region::msg
char * msg
The description of the region.
Definition: map.h:283
region::jailmap
char * jailmap
Where a player that is arrested in this region should be imprisoned.
Definition: map.h:287
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:435
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1258
region
This is a game region.
Definition: map.h:274
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
all_regions
std::vector< region * > all_regions
Definition: init.cpp:108
get_jail_exit
object * get_jail_exit(object *op)
Returns an object which is an exit through which the player represented by op should be sent in order...
Definition: region.cpp:252
mapstruct
This is a game-map.
Definition: map.h:315
msgbuf
static char msgbuf[HUGE_BUF]
Definition: loader.cpp:35880
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:436
get_region_from_string
region * get_region_from_string(const char *name)
Tries to find a region that 'name' corresponds to.
Definition: region.cpp:116
strcasecmp
int strcasecmp(const char *s1, const char *s2)
get_region_by_map
region * get_region_by_map(mapstruct *m)
Gets a region from a map.
Definition: region.cpp:71
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
BufferReader
Definition: bufferreader.cpp:21
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
region::jaily
int16_t jaily
The coodinates in jailmap to which the player should be sent.
Definition: map.h:288
region::jailx
int16_t jailx
Definition: map.h:288
bufferreader_next_line
char * bufferreader_next_line(BufferReader *br)
Return the next line in the buffer, as separated by a newline.
Definition: bufferreader.cpp:102