Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_map_c = 00003 * "$Id: region.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2001-2003 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 00036 #include <global.h> 00037 00038 #ifndef WIN32 /* ---win32 exclude header */ 00039 #include <unistd.h> 00040 #endif /* win32 */ 00041 00042 static void parse_regions(FILE *fp); 00043 static void assign_region_parents(void); 00044 00057 region *get_region_by_name(const char *region_name) { 00058 region *reg; 00059 00060 for (reg = first_region; reg != NULL; reg = reg->next) 00061 if (!strcmp(reg->name, region_name)) 00062 return reg; 00063 00064 for (reg = first_region; reg != NULL; reg = reg->next) { 00065 if (reg->fallback) { 00066 LOG(llevDebug, "region called %s requested, but not found, fallback used.\n", region_name); 00067 return reg; 00068 } 00069 } 00070 LOG(llevInfo, "Got no region or fallback for region %s.\n", region_name); 00071 return NULL; 00072 } 00073 00085 region *get_region_by_map(mapstruct *m) { 00086 return get_region_by_name(get_name_of_region_for_map(m)); 00087 } 00088 00103 const char *get_name_of_region_for_map(const mapstruct *m) { 00104 region *reg; 00105 00106 if (m->region != NULL) 00107 return m->region->name; 00108 for (reg = first_region; reg != NULL; reg = reg->next) { 00109 if (reg->fallback) 00110 return reg->name; 00111 } 00112 LOG(llevInfo, "map %s had no region and I couldn't find a fallback to use.\n", m->name); 00113 return "unknown"; 00114 } 00115 00132 region *get_region_from_string(const char *name) { 00133 region *reg; 00134 char *substr; 00135 char *p; 00136 00137 if (first_region == NULL) { 00138 return NULL; 00139 } 00140 00141 if (name == NULL) { 00142 for (reg = first_region; reg->parent != NULL; reg = reg->parent) 00143 ; 00144 return reg; 00145 } 00146 p = strchr(name, '\n'); 00147 if (p) 00148 *p = '\0'; 00149 for (reg = first_region; reg != NULL; reg = reg->next) 00150 if (!strcasecmp(reg->name, name)) 00151 return reg; 00152 00153 for (reg = first_region; reg != NULL; reg = reg->next) 00154 if (reg->longname != NULL) { 00155 if (!strcasecmp(reg->longname, name)) 00156 return reg; 00157 } 00158 00159 substr = NULL; 00160 for (reg = first_region; reg != NULL; reg = reg->next) 00161 if (reg->longname != NULL) { 00162 substr = strstr(reg->longname, name); 00163 if (substr != NULL) 00164 return reg; 00165 } 00166 for (reg = first_region; reg != NULL; reg = reg->next) 00167 if (reg->longname != NULL) { 00168 /* 00169 * This is not a bug, we want the region that is most identifiably a discrete 00170 * area in the game, eg if we have 'scor', we want to return 'scorn' and not 00171 * 'scornarena', regardless of their order on the list so we only look at those 00172 * regions with a longname set. 00173 */ 00174 substr = strstr(reg->name, name); 00175 if (substr != NULL) 00176 return reg; 00177 } 00178 for (reg = first_region; reg != NULL; reg = reg->next) { 00179 substr = strstr(reg->name, name); 00180 if (substr != NULL) 00181 return reg; 00182 } 00183 /* if we are still here, we are going to have to give up, and give the top level region */ 00184 for (reg = first_region; reg->parent != NULL; reg = reg->parent) 00185 ; 00186 return reg; 00187 } 00188 00201 int region_is_child_of_region(const region *child, const region *r) { 00202 00203 if (r == NULL) 00204 return -1; 00205 if (child == NULL) 00206 return 0; 00207 if (!strcmp(child->name, r->name)) 00208 return 1; 00209 else if (child->parent != NULL) 00210 return region_is_child_of_region(child->parent, r); 00211 else 00212 return 0; 00213 } 00214 00229 const char *get_region_longname(const region *r) { 00230 if (r->longname != NULL) 00231 return r->longname; 00232 else if (r->parent != NULL) 00233 return get_region_longname(r->parent); 00234 else { 00235 LOG(llevDebug, "NOTICE region %s has no parent and no longname.\n", r->name); 00236 return "no name can be found for the current region"; 00237 } 00238 } 00239 00250 const char *get_region_msg(const region *r) { 00251 if (r->msg != NULL) 00252 return r->msg; 00253 else if (r->parent != NULL) 00254 return get_region_msg(r->parent); 00255 else { 00256 LOG(llevDebug, "NOTICE region %s has no parent and no msg.\n", r->name); 00257 return "no description can be found for the current region"; 00258 } 00259 } 00260 00272 object *get_jail_exit(object *op) { 00273 region *reg; 00274 object *exit; 00275 00276 if (op->type != PLAYER) { 00277 LOG(llevError, "region.c: get_jail_exit called against non-player object.\n"); 00278 return NULL; 00279 } 00280 00281 reg = get_region_by_map(op->map); 00282 while (reg != NULL) { 00283 if (reg->jailmap) { 00284 exit = get_object(); 00285 EXIT_PATH(exit) = add_string(reg->jailmap); 00286 /* damned exits reset savebed and remove teleports, so the prisoner can't escape */ 00287 SET_FLAG(exit, FLAG_DAMNED); 00288 EXIT_X(exit) = reg->jailx; 00289 EXIT_Y(exit) = reg->jaily; 00290 return exit; 00291 } else 00292 reg = reg->parent; 00293 } 00294 LOG(llevDebug, "No suitable jailmap for region %s was found.\n", reg->name); 00295 return NULL; 00296 } 00297 00301 void init_regions(void) { 00302 FILE *fp; 00303 char filename[MAX_BUF]; 00304 int comp; 00305 00306 if (first_region != NULL) /* Only do this once */ 00307 return; 00308 00309 snprintf(filename, sizeof(filename), "%s/%s/%s", settings.datadir, settings.mapdir, settings.regions); 00310 LOG(llevDebug, "Reading regions from %s...\n", filename); 00311 if ((fp = open_and_uncompress(filename, 0, &comp)) == NULL) { 00312 LOG(llevError, " Can't open regions file %s in init_regions.\n", filename); 00313 return; 00314 } 00315 parse_regions(fp); 00316 assign_region_parents(); 00317 LOG(llevDebug, " done\n"); 00318 00319 close_and_delete(fp, comp); 00320 } 00321 00336 region *get_region_struct(void) { 00337 region *new; 00338 00339 new = (region *)CALLOC(1, sizeof(region)); 00340 if (new == NULL) 00341 fatal(OUT_OF_MEMORY); 00342 00343 memset(new, '\0', sizeof(region)); 00344 00345 return new; 00346 } 00347 00355 static void parse_regions(FILE *fp) { 00356 region *new; 00357 region *reg; 00358 00359 char buf[HUGE_BUF], msgbuf[HUGE_BUF], *key = NULL, *value, *end; 00360 int msgpos = 0; 00361 00362 new = NULL; 00363 while (fgets(buf, HUGE_BUF-1, fp) != NULL) { 00364 buf[HUGE_BUF-1] = 0; 00365 key = buf; 00366 while (isspace(*key)) 00367 key++; 00368 if (*key == 0) 00369 continue; /* empty line */ 00370 value = strchr(key, ' '); 00371 if (!value) { 00372 end = strchr(key, '\n'); 00373 *end = 0; 00374 } else { 00375 *value = 0; 00376 value++; 00377 while (isspace(*value)) 00378 value++; 00379 end = strchr(value, '\n'); 00380 } 00381 00382 /* 00383 * This is a bizzare mutated form of the map and archetype parser 00384 * rolled into one. Key is the field name, value is what it should 00385 * be set to. 00386 * We've already done the work to null terminate key, 00387 * and strip off any leading spaces for both of these. 00388 * We have not touched the newline at the end of the line - 00389 * these might be needed for some values. the end pointer 00390 * points to the first of the newlines. 00391 * value could be NULL! It would be easy enough to just point 00392 * this to "" to prevent cores, but that would let more errors slide 00393 * through. 00394 */ 00395 if (!strcmp(key, "region")) { 00396 *end = 0; 00397 new = get_region_struct(); 00398 new->name = strdup_local(value); 00399 } else if (!strcmp(key, "parent")) { 00400 /* 00401 * Note that this is in the initialisation code, so we don't actually 00402 * assign the pointer to the parent yet, because it might not have been 00403 * parsed. 00404 */ 00405 *end = 0; 00406 new->parent_name = strdup_local(value); 00407 } else if (!strcmp(key, "longname")) { 00408 *end = 0; 00409 new->longname = strdup_local(value); 00410 } else if (!strcmp(key, "jail")) { 00411 /* jail entries are of the form: /path/to/map x y */ 00412 char path[MAX_BUF]; 00413 int x, y; 00414 00415 if (sscanf(value, "%[^ ] %d %d\n", path, &x, &y) != 3) { 00416 LOG(llevError, "region.c: malformated regions entry: jail %s\n", value); 00417 continue; 00418 } 00419 new->jailmap = strdup_local(path); 00420 new->jailx = x; 00421 new->jaily = y; 00422 } else if (!strcmp(key, "msg")) { 00423 while (fgets(buf, HUGE_BUF-1, fp) != NULL) { 00424 if (!strcmp(buf, "endmsg\n")) 00425 break; 00426 else { 00427 strcpy(msgbuf+msgpos, buf); 00428 msgpos += strlen(buf); 00429 } 00430 } 00431 /* 00432 * There may be regions with empty messages (eg, msg/endmsg 00433 * with nothing between). When maps are loaded, this is done 00434 * so better do it here too... 00435 */ 00436 if (msgpos != 0) 00437 new->msg = strdup_local(msgbuf); 00438 00439 /* we have to reset msgpos, or the next region will store both msg blocks.*/ 00440 msgpos = 0; 00441 } else if (!strcmp(key, "fallback")) { 00442 *end = 0; 00443 new->fallback = atoi(value); 00444 } else if (!strcmp(key, "end")) { 00445 /* Place this new region last on the list, if the list is empty put it first */ 00446 for (reg = first_region; reg != NULL && reg->next != NULL; reg = reg->next) 00447 ; 00448 00449 if (reg == NULL) 00450 first_region = new; 00451 else 00452 reg->next = new; 00453 new = NULL; 00454 } else if (!strcmp(key, "nomore")) { 00455 /* we have reached the end of the region specs....*/ 00456 break; 00457 } else { 00458 /* we should never get here, if we have, then something is wrong */ 00459 LOG(llevError, "Got unknown value in region file: %s %s\n", key, value); 00460 } 00461 } 00462 if (!key || strcmp(key, "nomore")) 00463 LOG(llevError, "Got premature eof on regions file!\n"); 00464 } 00465 00469 static void assign_region_parents(void) { 00470 region *reg; 00471 uint32 parent_count = 0; 00472 uint32 region_count = 0; 00473 00474 for (reg = first_region; reg != NULL && reg->next != NULL; reg = reg->next) { 00475 if (reg->parent_name != NULL) { 00476 reg->parent = get_region_by_name(reg->parent_name); 00477 parent_count++; 00478 } 00479 region_count++; 00480 } 00481 LOG(llevDebug, "Assigned %u regions with %u parents.\n", region_count, parent_count); 00482 }