Crossfire Server, Trunk
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 #include <string>
33 
46 region *get_region_by_name(const char *region_name) {
47  for (auto reg : all_regions)
48  if (!strcmp(reg->name, region_name))
49  return reg;
50 
51  for (auto reg : all_regions) {
52  if (reg->fallback) {
53  LOG(llevDebug, "region called %s requested, but not found, fallback used.\n", region_name);
54  return reg;
55  }
56  }
57  LOG(llevInfo, "Got no region or fallback for region %s.\n", region_name);
58  return NULL;
59 }
60 
74 }
75 
90 const char *get_name_of_region_for_map(const mapstruct *m) {
91  if (m->region != NULL)
92  return m->region->name;
93  for (auto reg : all_regions) {
94  if (reg->fallback)
95  return reg->name;
96  }
97  LOG(llevInfo, "map %s had no region and I couldn't find a fallback to use.\n", m->name);
98  return "unknown";
99 }
100 
118  region *reg;
119  char *substr;
120 
121  if (all_regions.empty()) {
122  return NULL;
123  }
124 
125  if (*name == '\0') {
126  for (reg = all_regions.front(); reg->parent != NULL; reg = reg->parent)
127  ;
128  return reg;
129  }
130 
131  for (auto reg : all_regions)
132  if (!strcasecmp(reg->name, name))
133  return reg;
134 
135  for (auto reg : all_regions)
136  if (reg->longname != NULL) {
137  if (!strcasecmp(reg->longname, name))
138  return reg;
139  }
140 
141  substr = NULL;
142  for (auto reg : all_regions)
143  if (reg->longname != NULL) {
144  substr = strstr(reg->longname, name);
145  if (substr != NULL)
146  return reg;
147  }
148  for (auto reg : all_regions)
149  if (reg->longname != NULL) {
150  /*
151  * This is not a bug, we want the region that is most identifiably a discrete
152  * area in the game, eg if we have 'scor', we want to return 'scorn' and not
153  * 'scornarena', regardless of their order on the list so we only look at those
154  * regions with a longname set.
155  */
156  substr = strstr(reg->name, name);
157  if (substr != NULL)
158  return reg;
159  }
160  for (auto reg : all_regions) {
161  substr = strstr(reg->name, name);
162  if (substr != NULL)
163  return reg;
164  }
165  /* if we are still here, we are going to have to give up, and give the top level region */
166  for (reg = all_regions.front(); reg->parent != NULL; reg = reg->parent)
167  ;
168  return reg;
169 }
170 
183 int region_is_child_of_region(const region *child, const region *r) {
184  if (r == NULL)
185  return -1;
186  if (child == NULL)
187  return 0;
188  if (!strcmp(child->name, r->name))
189  return 1;
190  else if (child->parent != NULL)
191  return region_is_child_of_region(child->parent, r);
192  else
193  return 0;
194 }
195 
210 const char *get_region_longname(const region *r) {
211  if (r->longname != NULL)
212  return r->longname;
213  else if (r->parent != NULL)
214  return get_region_longname(r->parent);
215  else {
216  LOG(llevDebug, "NOTICE region %s has no parent and no longname.\n", r->name);
217  return "no name can be found for the current region";
218  }
219 }
220 
231 const char *get_region_msg(const region *r) {
232  if (r->msg != NULL)
233  return r->msg;
234  else if (r->parent != NULL)
235  return get_region_msg(r->parent);
236  else {
237  LOG(llevDebug, "NOTICE region %s has no parent and no msg.\n", r->name);
238  return "no description can be found for the current region";
239  }
240 }
241 
253 object *get_jail_exit(object *op) {
254  region *reg, *orig;
255  object *exit;
256 
257  if (op->type != PLAYER) {
258  LOG(llevError, "region.c: get_jail_exit called against non-player object.\n");
259  return NULL;
260  }
261 
262  reg = get_region_by_map(op->map);
263  orig = reg;
264  while (reg != NULL) {
265  if (reg->jailmap) {
266  exit = object_new();
267  EXIT_PATH(exit) = add_string(reg->jailmap);
268  /* damned exits reset savebed and remove teleports, so the prisoner can't escape */
270  EXIT_X(exit) = reg->jailx;
271  EXIT_Y(exit) = reg->jaily;
272  return exit;
273  } else
274  reg = reg->parent;
275  }
276  LOG(llevDebug, "No suitable jailmap for region %s was found.\n", orig ? orig->name : "(unknown region?)");
277  return NULL;
278 }
279 
295  region *add = (region *)calloc(1, sizeof(region));
296  if (add == NULL)
298 
299  return add;
300 }
301 
311 void init_regions(BufferReader *reader, const char *filename) {
312  region *add;
313  char *buf;
314 
315  char msgbuf[HUGE_BUF], *value;
316  int msgpos = 0;
317 
319  if (!all_regions.empty()) /* Only do this once */
320  return;
321 
322  std::map<region *, std::string> parents;
323 
324  add = NULL;
325  while ((buf = bufferreader_next_line(reader)) != NULL) {
326  while (isspace(*buf))
327  buf++;
328  if (*buf == 0)
329  continue; /* empty line */
330  value = strchr(buf, ' ');
331  if (value) {
332  *value = 0;
333  value++;
334  while (isspace(*value))
335  value++;
336  }
337 
338  /*
339  * This is a bizzare mutated form of the map and archetype parser
340  * rolled into one. Key is the field name, value is what it should
341  * be set to.
342  * We've already done the work to null terminate key,
343  * and strip off any leading spaces for both of these.
344  * We have not touched the newline at the end of the line -
345  * these might be needed for some values. the end pointer
346  * points to the first of the newlines.
347  * value could be NULL! It would be easy enough to just point
348  * this to "" to prevent cores, but that would let more errors slide
349  * through.
350  */
351  if (!strcmp(buf, "region")) {
352  add = get_region_struct();
353  add->name = strdup_local(value);
354  } else if (!strcmp(buf, "parent")) {
355  /*
356  * Note that this is in the initialisation code, so we don't actually
357  * assign the pointer to the parent yet, because it might not have been
358  * parsed.
359  */
360 
361  if (!add) {
362  LOG(llevError, "region.c: malformated regions file: \"parent\" before \"region\".\n");
364  }
365  if (!value) {
366  LOG(llevError, "region.c: malformated regions file: No value given for \"parent\" key.\n");
368  }
369  parents[add] = value;
370  } else if (!strcmp(buf, "longname")) {
371  if (!add) {
372  LOG(llevError, "region.c: malformated regions file: \"longname\" before \"region\".\n");
374  }
375  if (!value) {
376  LOG(llevError, "region.c: malformated regions file: No value given for \"longname\" key.\n");
378  }
379  add->longname = strdup_local(value);
380  } else if (!strcmp(buf, "jail")) {
381  /* jail entries are of the form: /path/to/map x y */
382  char path[MAX_BUF];
383  int x, y;
384 
385  if (!add) {
386  LOG(llevError, "region.c: malformated regions file: \"jail\" before \"region\".\n");
388  }
389  if (!value) {
390  LOG(llevError, "region.c: malformated regions file: No value given for \"jail\" key.\n");
392  }
393 
394  if (sscanf(value, "%[^ ] %d %d\n", path, &x, &y) != 3) {
395  LOG(llevError, "region.c: malformated regions entry: jail %s\n", value);
396  continue;
397  }
398  add->jailmap = strdup_local(path);
399  add->jailx = x;
400  add->jaily = y;
401  } else if (!strcmp(buf, "msg")) {
402  if (!add) {
403  LOG(llevError, "region.c: malformated regions file: \"msg\" before \"region\".\n");
405  }
406  char *other;
407  while ((other = bufferreader_next_line(reader)) != NULL) {
408  while (isspace(*other))
409  other++;
410  if (strcmp(other, "endmsg") == 0)
411  break;
412  else {
413  strcpy(msgbuf+msgpos, other);
414  msgpos += strlen(other);
415  strcpy(msgbuf+msgpos, "\n");
416  ++msgpos;
417  }
418  }
419  /*
420  * There may be regions with empty messages (eg, msg/endmsg
421  * with nothing between). When maps are loaded, this is done
422  * so better do it here too...
423  */
424  if (msgpos != 0)
425  add->msg = strdup_local(msgbuf);
426 
427  /* we have to reset msgpos, or the next region will store both msg blocks.*/
428  msgpos = 0;
429  } else if (!strcmp(buf, "fallback")) {
430  if (!add) {
431  LOG(llevError, "region.c: malformated regions file %s: \"fallback\" before \"region\".\n", filename);
433  }
434  if (!value) {
435  LOG(llevError, "region.c: malformated regions file %s: No value given for \"fallback\" key.\n", filename);
437  }
438  add->fallback = atoi(value);
439  } else if (!strcmp(buf, "end")) {
440  if (!add) {
441  LOG(llevError, "region.c: Ignoring spurious \"end\" between regions.\n");
442  continue;
443  }
444  all_regions.push_back(add);
445  add = NULL;
446  } else if (!strcmp(buf, "nomore")) {
447  if (add) {
448  LOG(llevError, "region.c: Last region not properly closed.\n");
449  free(add);
450  }
451  /* we have reached the end of the region specs....*/
452  break;
453  } else {
454  /* we should never get here, if we have, then something is wrong */
455  LOG(llevError, "Got unknown value in region file %s: %s %s\n", filename, buf, value);
456  }
457  }
458  if (!buf || strcmp(buf, "nomore")) {
459  LOG(llevError, "Got premature eof on regions file %s!\n", filename);
460  free(add);
461  }
462 
463  for (auto p : parents) {
464  p.first->parent = get_region_by_name(p.second.c_str());
465  if (!p.first->parent) {
466  LOG(llevError, "Couldn't find parent %s for region %s\n", p.second.c_str(), p.first->name);
467  }
468  }
469 }
PLAYER
@ PLAYER
Definition: object.h:112
get_name_of_region_for_map
const char * get_name_of_region_for_map(const mapstruct *m)
Definition: region.cpp:90
global.h
llevError
@ llevError
Definition: logger.h:11
get_region_struct
region * get_region_struct(void)
Definition: region.cpp:294
region::fallback
int8_t fallback
Definition: map.h:284
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
get_region_by_name
region * get_region_by_name(const char *region_name)
Definition: region.cpp:46
strdup_local
#define strdup_local
Definition: compat.h:29
diamondslots.x
x
Definition: diamondslots.py:15
init_regions
void init_regions(BufferReader *reader, const char *filename)
Definition: region.cpp:311
region_is_child_of_region
int region_is_child_of_region(const region *child, const region *r)
Definition: region.cpp:183
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
msgbuf
static char msgbuf[HUGE_BUF]
Definition: loader.c:2079
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
region::name
char * name
Definition: map.h:274
npc_dialog.filename
filename
Definition: npc_dialog.py:99
buf
StringBuffer * buf
Definition: readable.cpp:1552
get_region_longname
const char * get_region_longname(const region *r)
Definition: region.cpp:210
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
region::longname
char * longname
Definition: map.h:280
m
static event_registration m
Definition: citylife.cpp:425
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
region::parent
region * parent
Definition: map.h:275
get_region_msg
const char * get_region_msg(const region *r)
Definition: region.cpp:231
region::msg
char * msg
Definition: map.h:282
region::jailmap
char * jailmap
Definition: map.h:286
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
MAX_BUF
#define MAX_BUF
Definition: define.h:35
object_new
object * object_new(void)
Definition: object.cpp:1268
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
region
Definition: map.h:273
llevInfo
@ llevInfo
Definition: logger.h:12
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:570
all_regions
std::vector< region * > all_regions
Definition: init.cpp:108
get_jail_exit
object * get_jail_exit(object *op)
Definition: region.cpp:253
mapstruct
Definition: map.h:314
BufferReader
Definition: bufferreader.cpp:21
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
exit
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
diamondslots.y
y
Definition: diamondslots.py:16
get_region_from_string
region * get_region_from_string(const char *name)
Definition: region.cpp:117
strcasecmp
int strcasecmp(const char *s1, const char *s2)
get_region_by_map
region * get_region_by_map(mapstruct *m)
Definition: region.cpp:72
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
llevDebug
@ llevDebug
Definition: logger.h:13
region::jaily
int16_t jaily
Definition: map.h:287
region::jailx
int16_t jailx
Definition: map.h:287
bufferreader_next_line
char * bufferreader_next_line(BufferReader *br)
Definition: bufferreader.cpp:102