|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 #include <loader.h> 00032 00033 int global_darkness_table[MAX_DARKNESS + 1] = 00034 { 00035 0, 20, 40, 80, 160, 320, 640, 1280 00036 }; 00037 00039 int map_tiled_reverse[TILED_MAPS] = 00040 { 00041 2, 3, 0, 1, 6, 7, 4, 5 00042 }; 00043 00044 #define DEBUG_OLDFLAGS 1 00045 00046 static void load_objects(mapstruct *m, FILE *fp, int mapflags); 00047 static void save_objects(mapstruct *m, FILE *fp, FILE *fp2); 00048 static void allocate_map(mapstruct *m); 00049 static void free_all_objects(mapstruct *m); 00050 00056 static inline mapstruct *load_and_link_tiled_map(mapstruct *orig_map, int tile_num) 00057 { 00058 mapstruct *map = ready_map_name(orig_map->tile_path[tile_num], MAP_NAME_SHARED | (MAP_UNIQUE(orig_map) ? 1 : 0)); 00059 00060 if (!map || map != orig_map->tile_map[tile_num]) 00061 { 00062 LOG(llevBug, "Failed to connect map %s with tile #%d (%s).\n", STRING_SAFE(orig_map->path), tile_num, STRING_SAFE(orig_map->tile_path[tile_num])); 00063 FREE_AND_CLEAR_HASH(orig_map->tile_path[tile_num]); 00064 return NULL; 00065 } 00066 00067 return map; 00068 } 00069 00080 static int relative_tile_position_rec(mapstruct *map1, mapstruct *map2, int *x, int *y, uint32 id, int level) 00081 { 00082 int i; 00083 00084 if (map1 == map2) 00085 { 00086 return 1; 00087 } 00088 00089 if (level <= 0) 00090 { 00091 return 0; 00092 } 00093 00094 level--; 00095 map1->traversed = id; 00096 00097 /* Depth-first search for the destination map */ 00098 for (i = 0; i < TILED_MAPS; i++) 00099 { 00100 if (map1->tile_path[i]) 00101 { 00102 if (!map1->tile_map[i] || map1->tile_map[i]->in_memory != MAP_IN_MEMORY) 00103 { 00104 if (!load_and_link_tiled_map(map1, i)) 00105 { 00106 continue; 00107 } 00108 } 00109 00110 if (map1->tile_map[i]->traversed != id && ((map1->tile_map[i] == map2) || relative_tile_position_rec(map1->tile_map[i], map2, x, y, id, level))) 00111 { 00112 switch (i) 00113 { 00114 /* North */ 00115 case 0: 00116 *y -= MAP_HEIGHT(map1->tile_map[i]); 00117 return 1; 00118 00119 /* East */ 00120 case 1: 00121 *x += MAP_WIDTH(map1); 00122 return 1; 00123 00124 /* South */ 00125 case 2: 00126 *y += MAP_HEIGHT(map1); 00127 return 1; 00128 00129 /* West */ 00130 case 3: 00131 *x -= MAP_WIDTH(map1->tile_map[i]); 00132 return 1; 00133 00134 /* Northest */ 00135 case 4: 00136 *y -= MAP_HEIGHT(map1->tile_map[i]); 00137 *x += MAP_WIDTH(map1); 00138 return 1; 00139 00140 /* Southest */ 00141 case 5: 00142 *y += MAP_HEIGHT(map1); 00143 *x += MAP_WIDTH(map1); 00144 return 1; 00145 00146 /* Southwest */ 00147 case 6: 00148 *y += MAP_HEIGHT(map1); 00149 *x -= MAP_WIDTH(map1->tile_map[i]); 00150 return 1; 00151 00152 /* Northwest */ 00153 case 7: 00154 *y -= MAP_HEIGHT(map1->tile_map[i]); 00155 *x -= MAP_WIDTH(map1->tile_map[i]); 00156 return 1; 00157 } 00158 } 00159 } 00160 } 00161 00162 return 0; 00163 } 00164 00185 static int relative_tile_position(mapstruct *map1, mapstruct *map2, int *x, int *y) 00186 { 00187 int i; 00188 static uint32 traversal_id = 0; 00189 00190 /* Save some time in the simplest cases ( very similar to on_same_map() )*/ 00191 if (map1 == NULL || map2 == NULL) 00192 { 00193 return 0; 00194 } 00195 00196 if (map1 == map2) 00197 { 00198 return 1; 00199 } 00200 00201 for (i = 0; i < TILED_MAPS; i++) 00202 { 00203 if (map1->tile_path[i]) 00204 { 00205 if (!map1->tile_map[i] || map1->tile_map[i]->in_memory != MAP_IN_MEMORY) 00206 { 00207 if (!load_and_link_tiled_map(map1, i)) 00208 { 00209 continue; 00210 } 00211 } 00212 00213 if (map1->tile_map[i] == map2) 00214 { 00215 switch (i) 00216 { 00217 /* North */ 00218 case 0: 00219 *y -= MAP_HEIGHT(map1->tile_map[i]); 00220 return 1; 00221 00222 /* East */ 00223 case 1: 00224 *x += MAP_WIDTH(map1); 00225 return 1; 00226 00227 /* South */ 00228 case 2: 00229 *y += MAP_HEIGHT(map1); 00230 return 1; 00231 00232 /* West */ 00233 case 3: 00234 *x -= MAP_WIDTH(map1->tile_map[i]); 00235 return 1; 00236 00237 /* Northest */ 00238 case 4: 00239 *y -= MAP_HEIGHT(map1->tile_map[i]); 00240 *x += MAP_WIDTH(map1); 00241 return 1; 00242 00243 /* Southest */ 00244 case 5: 00245 *y += MAP_HEIGHT(map1); 00246 *x += MAP_WIDTH(map1); 00247 return 1; 00248 00249 /* Southwest */ 00250 case 6: 00251 *y += MAP_HEIGHT(map1); 00252 *x -= MAP_WIDTH(map1->tile_map[i]); 00253 return 1; 00254 00255 /* Northwest */ 00256 case 7: 00257 *y -= MAP_HEIGHT(map1->tile_map[i]); 00258 *x -= MAP_WIDTH(map1->tile_map[i]); 00259 return 1; 00260 } 00261 } 00262 } 00263 } 00264 00265 /* Avoid overflow of traversal_id */ 00266 if (traversal_id == 4294967295U) 00267 { 00268 mapstruct *m; 00269 00270 LOG(llevDebug, "relative_tile_position(): resetting traversal id\n"); 00271 00272 for (m = first_map; m != NULL; m = m->next) 00273 { 00274 m->traversed = 0; 00275 } 00276 00277 traversal_id = 0; 00278 } 00279 00280 /* Recursive search */ 00281 return relative_tile_position_rec(map1, map2, x, y, ++traversal_id, 2); 00282 } 00283 00290 mapstruct *has_been_loaded_sh(shstr *name) 00291 { 00292 mapstruct *map; 00293 00294 if (!name || !*name) 00295 { 00296 return NULL; 00297 } 00298 00299 if (*name != '/' && *name != '.') 00300 { 00301 LOG(llevDebug, "has_been_loaded_sh(): Found map name without starting '/' or '.' (%s)\n", name); 00302 return NULL; 00303 } 00304 00305 for (map = first_map; map; map = map->next) 00306 { 00307 if (name == map->path) 00308 { 00309 break; 00310 } 00311 } 00312 00313 return map; 00314 } 00315 00323 char *create_pathname(const char *name) 00324 { 00325 static char buf[MAX_BUF]; 00326 00327 if (*name == '/') 00328 { 00329 snprintf(buf, sizeof(buf), "%s%s", settings.mapdir, name); 00330 } 00331 else 00332 { 00333 snprintf(buf, sizeof(buf), "%s/%s", settings.mapdir, name); 00334 } 00335 00336 return buf; 00337 } 00338 00346 static char *create_items_path(shstr *s) 00347 { 00348 static char buf[MAX_BUF]; 00349 char *t; 00350 00351 if (*s == '/') 00352 { 00353 s++; 00354 } 00355 00356 snprintf(buf, sizeof(buf), "%s/%s/", settings.localdir, settings.uniquedir); 00357 00358 for (t = buf + strlen(buf); *s; s++, t++) 00359 { 00360 if (*s == '/') 00361 { 00362 *t = '@'; 00363 } 00364 else 00365 { 00366 *t = *s; 00367 } 00368 } 00369 00370 *t = '\0'; 00371 return buf; 00372 } 00373 00384 int check_path(const char *name, int prepend_dir) 00385 { 00386 char buf[MAX_BUF]; 00387 #ifndef WIN32 00388 char *endbuf; 00389 struct stat statbuf; 00390 int mode = 0, i; 00391 #endif 00392 00393 if (prepend_dir) 00394 { 00395 strcpy(buf, create_pathname(name)); 00396 } 00397 else 00398 { 00399 strcpy(buf, name); 00400 } 00401 00402 #ifdef WIN32 00403 return _access(buf, 0); 00404 #else 00405 endbuf = buf + strlen(buf); 00406 00407 for (i = 0; i < NROF_COMPRESS_METHODS; i++) 00408 { 00409 if (uncomp[i][0]) 00410 { 00411 strcpy(endbuf, uncomp[i][0]); 00412 } 00413 else 00414 { 00415 *endbuf = '\0'; 00416 } 00417 00418 if (!stat(buf, &statbuf)) 00419 { 00420 break; 00421 } 00422 } 00423 00424 if (i == NROF_COMPRESS_METHODS) 00425 { 00426 return -1; 00427 } 00428 00429 if (!S_ISREG(statbuf.st_mode)) 00430 { 00431 return -1; 00432 } 00433 00434 if (((statbuf.st_mode & S_IRGRP) && getegid() == statbuf.st_gid) || ((statbuf.st_mode & S_IRUSR) && geteuid() == statbuf.st_uid) || (statbuf.st_mode & S_IROTH)) 00435 { 00436 mode |= 4; 00437 } 00438 00439 if ((statbuf.st_mode & S_IWGRP && getegid() == statbuf.st_gid) || (statbuf.st_mode & S_IWUSR && geteuid() == statbuf.st_uid) || (statbuf.st_mode & S_IWOTH)) 00440 { 00441 mode |= 2; 00442 } 00443 00444 return mode; 00445 #endif 00446 } 00447 00463 char *normalize_path(const char *src, const char *dst, char *path) 00464 { 00465 char *p; 00466 char buf[HUGE_BUF]; 00467 00468 if (*dst == '/') 00469 { 00470 strcpy(buf, dst); 00471 } 00472 else 00473 { 00474 strcpy(buf, src); 00475 00476 if ((p = strrchr(buf, '/'))) 00477 { 00478 p[1] = '\0'; 00479 } 00480 else 00481 { 00482 strcpy(buf, "/"); 00483 } 00484 00485 strcat(buf, dst); 00486 } 00487 00488 p = buf; 00489 00490 if (strstr(p, "//")) 00491 { 00492 LOG(llevBug, "Map path with unhandled '//' element: %s\n", buf); 00493 } 00494 00495 *path = '\0'; 00496 p = strtok(p, "/"); 00497 00498 while (p) 00499 { 00500 /* Ignore "./" path elements */ 00501 if (!strcmp(p, ".")) 00502 { 00503 } 00504 else if (!strcmp(p, "..")) 00505 { 00506 /* Remove last inserted path element from 'path' */ 00507 char *separator = strrchr(path, '/'); 00508 00509 if (separator) 00510 { 00511 *separator = '\0'; 00512 } 00513 else 00514 { 00515 LOG(llevBug, "Illegal path (too many \"..\" entries): %s\n", dst); 00516 *path = '\0'; 00517 return path; 00518 } 00519 } 00520 else 00521 { 00522 strcat(path, "/"); 00523 strcat(path, p); 00524 } 00525 00526 p = strtok(NULL, "/"); 00527 } 00528 00529 return path; 00530 } 00531 00535 void dump_map(mapstruct *m) 00536 { 00537 LOG(llevSystem, "Map %s status: %d.\n", m->path, m->in_memory); 00538 LOG(llevSystem, "Size: %dx%d Start: %d, %d\n", MAP_WIDTH(m), MAP_HEIGHT(m), MAP_ENTER_X(m), MAP_ENTER_Y(m)); 00539 00540 if (m->msg != NULL) 00541 { 00542 LOG(llevSystem, "Message:\n%s", m->msg); 00543 } 00544 00545 if (m->tmpname != NULL) 00546 { 00547 LOG(llevSystem, "Tmpname: %s\n", m->tmpname); 00548 } 00549 00550 LOG(llevSystem, "Difficulty: %d\n", m->difficulty); 00551 LOG(llevSystem, "Darkness: %d\n", m->darkness); 00552 LOG(llevSystem, "Light: %d\n", m->light_value); 00553 LOG(llevSystem, "Outdoor: %d\n", MAP_OUTDOORS(m)); 00554 } 00555 00561 void dump_all_maps() 00562 { 00563 mapstruct *m; 00564 00565 for (m = first_map; m != NULL; m = m->next) 00566 { 00567 dump_map(m); 00568 } 00569 } 00570 00584 int wall(mapstruct *m, int x, int y) 00585 { 00586 if (!(m = get_map_from_coord(m, &x, &y))) 00587 { 00588 return (P_BLOCKSVIEW | P_NO_PASS | P_OUT_OF_MAP); 00589 } 00590 00591 return (GET_MAP_FLAGS(m, x, y) & (P_DOOR_CLOSED | P_PLAYER_ONLY | P_NO_PASS | P_PASS_THRU)); 00592 } 00593 00601 int blocks_view(mapstruct *m, int x, int y) 00602 { 00603 mapstruct *nm; 00604 00605 if (!(nm = get_map_from_coord(m, &x, &y))) 00606 { 00607 return (P_BLOCKSVIEW | P_NO_PASS | P_OUT_OF_MAP); 00608 } 00609 00610 return (GET_MAP_FLAGS(nm, x, y) & P_BLOCKSVIEW); 00611 } 00612 00619 int blocks_magic(mapstruct *m, int x, int y) 00620 { 00621 if (!(m = get_map_from_coord(m, &x, &y))) 00622 { 00623 return (P_BLOCKSVIEW | P_NO_PASS | P_NO_MAGIC | P_OUT_OF_MAP); 00624 } 00625 00626 return (GET_MAP_FLAGS(m, x, y) & P_NO_MAGIC) || (GET_MAP_SPACE_PTR(m, x, y)->extra_flags & MSP_EXTRA_NO_MAGIC); 00627 } 00628 00636 int blocks_cleric(mapstruct *m, int x, int y) 00637 { 00638 if (!(m = get_map_from_coord(m, &x, &y))) 00639 { 00640 return (P_BLOCKSVIEW | P_NO_PASS | P_NO_CLERIC | P_OUT_OF_MAP); 00641 } 00642 00643 return (GET_MAP_FLAGS(m, x, y) & P_NO_CLERIC) || (GET_MAP_SPACE_PTR(m, x, y)->extra_flags & MSP_EXTRA_NO_CLERIC); 00644 } 00645 00656 int blocked(object *op, mapstruct *m, int x, int y, int terrain) 00657 { 00658 int flags; 00659 MapSpace *msp; 00660 00661 flags = (msp = GET_MAP_SPACE_PTR(m, x, y))->flags; 00662 00663 /* Flying objects can move over various terrains. */ 00664 if (op && QUERY_FLAG(op, FLAG_FLYING)) 00665 { 00666 terrain |= TERRAIN_AIRBREATH | TERRAIN_WATERWALK | TERRAIN_FIREWALK | TERRAIN_CLOUDWALK; 00667 } 00668 00669 /* First, look at the terrain. If we don't have a valid terrain flag, 00670 * this is forbidden to enter. */ 00671 if (msp->move_flags & ~terrain) 00672 { 00673 return ((flags & (P_NO_PASS | P_IS_ALIVE | P_IS_PLAYER | P_CHECK_INV | P_PASS_THRU)) | P_NO_TERRAIN); 00674 } 00675 00676 if (flags & P_IS_ALIVE) 00677 { 00678 return (flags & (P_DOOR_CLOSED | P_NO_PASS | P_IS_ALIVE | P_IS_PLAYER | P_CHECK_INV | P_PASS_THRU)); 00679 } 00680 00681 if (flags & P_NO_PASS) 00682 { 00683 if (!(flags & P_PASS_THRU) || !op || !QUERY_FLAG(op, FLAG_CAN_PASS_THRU)) 00684 { 00685 return (flags & (P_DOOR_CLOSED | P_NO_PASS | P_IS_PLAYER | P_CHECK_INV | P_PASS_THRU)); 00686 } 00687 } 00688 00689 if (flags & P_IS_PLAYER) 00690 { 00691 if (!op || (m->map_flags & MAP_FLAG_PVP && !(flags & P_NO_PVP) && !(msp->extra_flags & MSP_EXTRA_NO_PVP))) 00692 { 00693 return (flags & (P_DOOR_CLOSED | P_IS_PLAYER | P_CHECK_INV)); 00694 } 00695 00696 if (op->type != PLAYER) 00697 { 00698 return (flags & (P_DOOR_CLOSED | P_IS_PLAYER | P_CHECK_INV)); 00699 } 00700 } 00701 00702 /* We have an object pointer - do some last checks */ 00703 if (op) 00704 { 00705 /* Player only space and not a player - no pass and possible checker here */ 00706 if ((flags & P_PLAYER_ONLY) && op->type != PLAYER) 00707 { 00708 return (flags & (P_DOOR_CLOSED | P_NO_PASS | P_CHECK_INV | P_PLAYER_ONLY)); 00709 } 00710 00711 if (flags & P_CHECK_INV) 00712 { 00713 if (blocked_tile(op, m, x, y)) 00714 { 00715 return (flags & (P_DOOR_CLOSED | P_NO_PASS | P_CHECK_INV)); 00716 } 00717 } 00718 } 00719 00720 return (flags & (P_DOOR_CLOSED)); 00721 } 00722 00733 int blocked_link(object *op, int xoff, int yoff) 00734 { 00735 object *tmp, *tmp2; 00736 mapstruct *m; 00737 int xtemp, ytemp, flags; 00738 00739 for (tmp = op; tmp; tmp = tmp->more) 00740 { 00741 /* We search for this new position */ 00742 xtemp = tmp->arch->clone.x + xoff; 00743 ytemp = tmp->arch->clone.y + yoff; 00744 00745 /* Check if match is a different part of us */ 00746 for (tmp2 = op; tmp2; tmp2 = tmp2->more) 00747 { 00748 /* If this is true, we can be sure this position is valid */ 00749 if (xtemp == tmp2->arch->clone.x && ytemp == tmp2->arch->clone.y) 00750 { 00751 break; 00752 } 00753 } 00754 00755 /* If this is NULL, tmp will move in a new node */ 00756 if (!tmp2) 00757 { 00758 xtemp = tmp->x + xoff; 00759 ytemp = tmp->y + yoff; 00760 00761 /* If this new node is illegal, we can skip all */ 00762 if (!(m = get_map_from_coord(tmp->map, &xtemp, &ytemp))) 00763 { 00764 return -1; 00765 } 00766 00767 /* We use always head for tests - no need to copy any flags to the tail */ 00768 if ((flags = blocked(op, m, xtemp, ytemp, op->terrain_flag))) 00769 { 00770 if ((flags & P_DOOR_CLOSED) && (op->behavior & BEHAVIOR_OPEN_DOORS)) 00771 { 00772 if (open_door(op, m, xtemp, ytemp, 1)) 00773 { 00774 continue; 00775 } 00776 } 00777 00778 return flags; 00779 } 00780 } 00781 } 00782 00783 return 0; 00784 } 00785 00796 int blocked_link_2(object *op, mapstruct *map, int x, int y) 00797 { 00798 object *tmp, *tmp2; 00799 int xtemp, ytemp, flags; 00800 mapstruct *m; 00801 00802 for (tmp = op; tmp; tmp = tmp->more) 00803 { 00804 /* We search for this new position */ 00805 xtemp = x + tmp->arch->clone.x; 00806 ytemp = y + tmp->arch->clone.y; 00807 00808 /* Check if match is a different part of us */ 00809 for (tmp2 = op; tmp2; tmp2 = tmp2->more) 00810 { 00811 /* If this is true, we can be sure this position is valid */ 00812 if (xtemp == tmp2->x && ytemp == tmp2->y) 00813 { 00814 break; 00815 } 00816 } 00817 00818 /* If this is NULL, tmp will move in a new node */ 00819 if (!tmp2) 00820 { 00821 /* If this new node is illegal, we can skip all */ 00822 if (!(m = get_map_from_coord(map, &xtemp, &ytemp))) 00823 { 00824 return -1; 00825 } 00826 00827 /* We use always head for tests - no need to copy any flags to the tail */ 00828 if ((flags = blocked(op, m, xtemp, ytemp, op->terrain_flag))) 00829 { 00830 if ((flags & P_DOOR_CLOSED) && (op->behavior & BEHAVIOR_OPEN_DOORS)) 00831 { 00832 if (open_door(op, m, xtemp, ytemp, 0)) 00833 { 00834 continue; 00835 } 00836 } 00837 00838 return flags; 00839 } 00840 } 00841 } 00842 00843 return 0; 00844 } 00845 00854 int blocked_tile(object *op, mapstruct *m, int x, int y) 00855 { 00856 object *tmp; 00857 00858 for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above) 00859 { 00860 /* This must be before the checks below. Code for inventory checkers. */ 00861 if (tmp->type == CHECK_INV && tmp->last_grace) 00862 { 00863 if (QUERY_FLAG(tmp, FLAG_XRAYS) && op->type != PLAYER) 00864 { 00865 continue; 00866 } 00867 00868 /* If last_sp is set, the player/monster needs an object, 00869 * so we check for it. If they don't have it, they can't 00870 * pass through this space. */ 00871 if (tmp->last_sp) 00872 { 00873 if (check_inv_recursive(op, tmp) == NULL) 00874 { 00875 return 1; 00876 } 00877 00878 continue; 00879 } 00880 /* In this case, the player must not have the object - 00881 * if they do, they can't pass through. */ 00882 else 00883 { 00884 if (check_inv_recursive(op, tmp) != NULL) 00885 { 00886 return 1; 00887 } 00888 00889 continue; 00890 } 00891 } 00892 } 00893 00894 return 0; 00895 } 00896 00907 int arch_blocked(archetype *at, object *op, mapstruct *m, int x, int y) 00908 { 00909 archetype *tmp; 00910 mapstruct *mt; 00911 int xt, yt, t; 00912 00913 if (op) 00914 { 00915 t = op->terrain_flag; 00916 } 00917 else 00918 { 00919 t = TERRAIN_ALL; 00920 } 00921 00922 if (at == NULL) 00923 { 00924 if (!(m = get_map_from_coord(m, &x, &y))) 00925 { 00926 return -1; 00927 } 00928 00929 return blocked(op, m, x, y, t); 00930 } 00931 00932 for (tmp = at; tmp; tmp = tmp->more) 00933 { 00934 xt = x + tmp->clone.x; 00935 yt = y + tmp->clone.y; 00936 00937 if (!(mt = get_map_from_coord(m, &xt, &yt))) 00938 { 00939 return -1; 00940 } 00941 00942 if ((xt = blocked(op, mt, xt, yt, t))) 00943 { 00944 return xt; 00945 } 00946 } 00947 00948 return 0; 00949 } 00950 00957 static void load_objects(mapstruct *m, FILE *fp, int mapflags) 00958 { 00959 int i; 00960 archetype *tail; 00961 void *mybuffer; 00962 object *op, *prev = NULL, *last_more = NULL, *tmp; 00963 00964 op = get_object(); 00965 00966 /* To handle buttons correctly */ 00967 op->map = m; 00968 mybuffer = create_loader_buffer(fp); 00969 00970 while ((i = load_object(fp, op, mybuffer, LO_REPEAT, mapflags))) 00971 { 00972 if (i == LL_MORE) 00973 { 00974 LOG(llevDebug, "load_objects(%s): object %s - its a tail!\n", m->path ? m->path : ">no map<", query_short_name(op, NULL)); 00975 continue; 00976 } 00977 00978 /* If the archetype for the object is null, means that we 00979 * got an invalid object. Don't do anything with it - the game 00980 * will not be able to do anything with it either. */ 00981 if (op->arch == NULL) 00982 { 00983 LOG(llevDebug, "load_objects(%s): object %s (%d)- invalid archetype. (pos:%d,%d)\n", m->path ? m->path : ">no map<", query_short_name(op, NULL), op->type, op->x, op->y); 00984 continue; 00985 } 00986 00987 /* Do some safety for containers */ 00988 if (op->type == CONTAINER) 00989 { 00990 /* Used for containers as link to players viewing it */ 00991 op->attacked_by = NULL; 00992 op->attacked_by_count = 0; 00993 sum_weight(op); 00994 } 00995 00996 if (op->type == MONSTER) 00997 { 00998 fix_monster(op); 00999 } 01000 01001 /* Important pre set for the animation/face of a object */ 01002 if (QUERY_FLAG(op, FLAG_IS_TURNABLE) || QUERY_FLAG(op, FLAG_ANIMATE)) 01003 { 01004 SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction + op->state); 01005 } 01006 01007 /* We have a multi arch head? */ 01008 if (op->arch->more) 01009 { 01010 tail = op->arch->more; 01011 prev = op, last_more = op; 01012 01013 /* Clone the tail using the default arch */ 01014 do 01015 { 01016 tmp = get_object(); 01017 copy_object(&tail->clone, tmp, 0); 01018 01019 tmp->x += op->x; 01020 tmp->y += op->y; 01021 tmp->map = op->map; 01022 01023 /* Adjust the single object specific data except flags. */ 01024 tmp->type = op->type; 01025 tmp->layer = op->layer; 01026 01027 /* Link the tail object... */ 01028 tmp->head = prev, last_more->more = tmp, last_more = tmp; 01029 01030 } 01031 while ((tail = tail->more)); 01032 01033 /* To speed up some core functions like moving or remove_ob()/insert_ob 01034 * and because there are some "arch depending and not object depending" 01035 * flags, we init the tails with some of the head settings. */ 01036 01037 if (QUERY_FLAG(op, FLAG_SYS_OBJECT)) 01038 { 01039 SET_MULTI_FLAG(op->more, FLAG_SYS_OBJECT); 01040 } 01041 else 01042 { 01043 CLEAR_MULTI_FLAG(tmp->more, FLAG_SYS_OBJECT); 01044 } 01045 01046 if (QUERY_FLAG(op, FLAG_NO_APPLY)) 01047 { 01048 SET_MULTI_FLAG(op->more, FLAG_NO_APPLY); 01049 } 01050 else 01051 { 01052 CLEAR_MULTI_FLAG(tmp->more, FLAG_NO_APPLY); 01053 } 01054 01055 if (QUERY_FLAG(op, FLAG_IS_INVISIBLE)) 01056 { 01057 SET_MULTI_FLAG(op->more, FLAG_IS_INVISIBLE); 01058 } 01059 else 01060 { 01061 CLEAR_MULTI_FLAG(tmp->more, FLAG_IS_INVISIBLE); 01062 } 01063 01064 if (QUERY_FLAG(op, FLAG_IS_ETHEREAL)) 01065 { 01066 SET_MULTI_FLAG(op->more, FLAG_IS_ETHEREAL); 01067 } 01068 else 01069 { 01070 CLEAR_MULTI_FLAG(tmp->more, FLAG_IS_ETHEREAL); 01071 } 01072 01073 if (QUERY_FLAG(op, FLAG_CAN_PASS_THRU)) 01074 { 01075 SET_MULTI_FLAG(op->more, FLAG_CAN_PASS_THRU); 01076 } 01077 else 01078 { 01079 CLEAR_MULTI_FLAG(tmp->more, FLAG_CAN_PASS_THRU); 01080 } 01081 01082 if (QUERY_FLAG(op, FLAG_FLYING)) 01083 { 01084 SET_MULTI_FLAG(op->more, FLAG_FLYING); 01085 } 01086 else 01087 { 01088 CLEAR_MULTI_FLAG(tmp->more, FLAG_FLYING); 01089 } 01090 01091 if (QUERY_FLAG(op, FLAG_BLOCKSVIEW)) 01092 { 01093 SET_MULTI_FLAG(op->more, FLAG_BLOCKSVIEW); 01094 } 01095 else 01096 { 01097 CLEAR_MULTI_FLAG(tmp->more, FLAG_BLOCKSVIEW); 01098 } 01099 } 01100 01101 insert_ob_in_map(op, m, op, INS_NO_MERGE | INS_NO_WALK_ON); 01102 01103 /* auto_apply() will remove FLAG_AUTO_APPLY after first use */ 01104 if (QUERY_FLAG(op, FLAG_AUTO_APPLY)) 01105 { 01106 auto_apply(op); 01107 } 01108 /* For fresh maps, create treasures */ 01109 else if ((mapflags & MAP_ORIGINAL) && op->randomitems) 01110 { 01111 create_treasure(op->randomitems, op, op->type != TREASURE ? GT_APPLY : 0, op->level ? op->level : m->difficulty, T_STYLE_UNSET, ART_CHANCE_UNSET, 0, NULL); 01112 } 01113 01114 op = get_object(); 01115 op->map = m; 01116 } 01117 01118 delete_loader_buffer(mybuffer); 01119 01120 m->in_memory = MAP_IN_MEMORY; 01121 check_light_source_list(m); 01122 } 01123 01129 static void save_objects(mapstruct *m, FILE *fp, FILE *fp2) 01130 { 01131 int i, j = 0, unique = 0; 01132 object *head, *op, *otmp, *tmp, *last_valid; 01133 01134 for (i = 0; i < MAP_WIDTH(m); i++) 01135 { 01136 for (j = 0; j < MAP_HEIGHT(m); j++) 01137 { 01138 for (op = get_map_ob (m, i, j); op; op = otmp) 01139 { 01140 otmp = op->above; 01141 01142 last_valid = op->below; 01143 01144 if (op->type == PLAYER) 01145 { 01146 continue; 01147 } 01148 01149 head = op->head ? op->head : op; 01150 01151 if (QUERY_FLAG(head, FLAG_NO_SAVE)) 01152 { 01153 remove_ob(head); 01154 check_walk_off(head, NULL, MOVE_APPLY_VANISHED | MOVE_APPLY_SAVING); 01155 01156 /* Invalid next pointer */ 01157 if (otmp && (QUERY_FLAG(otmp, FLAG_REMOVED) || OBJECT_FREE(otmp))) 01158 { 01159 if (!QUERY_FLAG(op, FLAG_REMOVED) && !OBJECT_FREE(op)) 01160 { 01161 otmp = op->above; 01162 } 01163 else if (last_valid) 01164 { 01165 otmp = last_valid->above; 01166 } 01167 /* Should be really rare */ 01168 else 01169 { 01170 otmp = get_map_ob(m, i, j); 01171 } 01172 } 01173 01174 continue; 01175 } 01176 /* Don't save spawn point monsters; instead, get the spawn point 01177 * they came from, and reset that spawn point so it will generate 01178 * a new monster when the map loads again. */ 01179 else if (QUERY_FLAG(op, FLAG_SPAWN_MOB)) 01180 { 01181 /* Browse the inventory for the spawn info */ 01182 for (tmp = head->inv; tmp; tmp = tmp->below) 01183 { 01184 if (tmp->type == SPAWN_POINT_INFO) 01185 { 01186 if (tmp->owner && tmp->owner->type == SPAWN_POINT) 01187 { 01188 /* Force a pre spawn setting */ 01189 tmp->owner->stats.sp = tmp->owner->last_sp; 01190 /* We force active spawn point */ 01191 tmp->owner->speed_left += 1.0f; 01192 tmp->owner->enemy = NULL; 01193 } 01194 else 01195 { 01196 LOG(llevBug, "Spawn mob (%s (%s)) has SPAWN INFO without or illegal owner set (%s)!\n", op->arch->name, query_name(head, NULL), query_name(tmp->owner, NULL)); 01197 } 01198 01199 remove_ob(head); 01200 check_walk_off(head, NULL, MOVE_APPLY_VANISHED | MOVE_APPLY_SAVING); 01201 01202 goto save_objects_jump1; 01203 } 01204 } 01205 01206 LOG(llevBug, "Spawn mob (%s %s) without SPAWN INFO.\n", head->arch->name, query_name(head, NULL)); 01207 remove_ob(head); 01208 check_walk_off(head, NULL, MOVE_APPLY_VANISHED | MOVE_APPLY_SAVING); 01209 01210 if (!OBJECT_FREE(tmp) && tmp->owner && tmp->owner->type == SPAWN_POINT) 01211 { 01212 tmp->owner->enemy = NULL; 01213 } 01214 01215 save_objects_jump1: 01216 01217 /* Invalid next pointer */ 01218 if (otmp && (QUERY_FLAG(otmp, FLAG_REMOVED) || OBJECT_FREE(otmp))) 01219 { 01220 if (!QUERY_FLAG(op, FLAG_REMOVED) && !OBJECT_FREE(op)) 01221 { 01222 otmp = op->above; 01223 } 01224 else if (last_valid) 01225 { 01226 otmp = last_valid->above; 01227 } 01228 /* Should be really rare */ 01229 else 01230 { 01231 otmp = get_map_ob(m, i, j); 01232 } 01233 } 01234 01235 continue; 01236 } 01237 else if (op->type == SPAWN_POINT) 01238 { 01239 if (op->enemy) 01240 { 01241 if (op->enemy_count == op->enemy->count && !QUERY_FLAG(op->enemy, FLAG_REMOVED) && !OBJECT_FREE(op->enemy)) 01242 { 01243 /* Force a pre spawn setting */ 01244 op->stats.sp = op->last_sp; 01245 op->speed_left += 1.0f; 01246 /* And delete the spawn */ 01247 remove_ob(op->enemy); 01248 check_walk_off (op->enemy, NULL, MOVE_APPLY_VANISHED | MOVE_APPLY_SAVING); 01249 op->enemy = NULL; 01250 01251 /* Invalid next pointer */ 01252 if (otmp && (QUERY_FLAG(otmp, FLAG_REMOVED) || OBJECT_FREE(otmp))) 01253 { 01254 if (!QUERY_FLAG(op, FLAG_REMOVED) && !OBJECT_FREE(op)) 01255 { 01256 otmp = op->above; 01257 } 01258 else if (last_valid) 01259 { 01260 otmp = last_valid->above; 01261 } 01262 /* Should be really rare */ 01263 else 01264 { 01265 otmp = get_map_ob(m, i, j); 01266 } 01267 } 01268 } 01269 } 01270 } 01271 01272 if (head->owner) 01273 { 01274 LOG(llevDebug, "save_obj(): obj w. owner. map:%s obj:%s (%s) (%d,%d)\n", m->path, query_name(op, NULL), op->arch && op->arch->name ? op->arch->name : "<no arch name>", op->x, op->y); 01275 head->owner = NULL; 01276 continue; 01277 } 01278 } 01279 } 01280 } 01281 01282 /* The map is now cleared from non-static objects on this or other maps 01283 * (when the source was from this map). Now all can be saved as a legal 01284 * snapshot of the map. */ 01285 for (i = 0; i < MAP_WIDTH(m); i++) 01286 { 01287 for (j = 0; j < MAP_HEIGHT(m); j++) 01288 { 01289 unique = 0; 01290 01291 for (op = get_map_ob(m, i, j); op; op = otmp) 01292 { 01293 otmp = op->above; 01294 01295 last_valid = op->below; 01296 01297 if (QUERY_FLAG(op, FLAG_IS_FLOOR) && QUERY_FLAG(op, FLAG_UNIQUE)) 01298 { 01299 unique = 1; 01300 } 01301 01302 /* Do some testing... */ 01303 if (op->type == PLAYER) 01304 { 01305 continue; 01306 } 01307 01308 if (op->head) 01309 { 01310 int xt, yt; 01311 01312 tmp = op->head; 01313 xt = tmp->x; 01314 yt = tmp->y; 01315 tmp->x = op->x - op->arch->clone.x; 01316 tmp->y = op->y - op->arch->clone.y; 01317 01318 if (unique || QUERY_FLAG(tmp, FLAG_UNIQUE)) 01319 { 01320 save_object(fp2 , tmp, 3); 01321 } 01322 else 01323 { 01324 save_object(fp, tmp, 3); 01325 } 01326 01327 tmp->x = xt; 01328 tmp->y = yt; 01329 /* Technical remove, no walk off check */ 01330 remove_ob(tmp); 01331 01332 /* Invalid next pointer */ 01333 if (otmp && (QUERY_FLAG(otmp, FLAG_REMOVED) || OBJECT_FREE(otmp))) 01334 { 01335 if (!QUERY_FLAG(op, FLAG_REMOVED) && !OBJECT_FREE(op)) 01336 { 01337 otmp = op->above; 01338 } 01339 else if (last_valid) 01340 { 01341 otmp = last_valid->above; 01342 } 01343 /* Should be really rare */ 01344 else 01345 { 01346 otmp = get_map_ob(m, i, j); 01347 } 01348 } 01349 01350 continue; 01351 } 01352 01353 if (unique || QUERY_FLAG(op, FLAG_UNIQUE)) 01354 { 01355 save_object(fp2, op, 3); 01356 } 01357 else 01358 { 01359 save_object(fp, op, 3); 01360 } 01361 01362 /* It's a head */ 01363 if (op->more) 01364 { 01365 remove_ob(op); 01366 01367 /* Invalid next pointer */ 01368 if (otmp && (QUERY_FLAG(otmp, FLAG_REMOVED) || OBJECT_FREE(otmp))) 01369 { 01370 if (!QUERY_FLAG(op, FLAG_REMOVED) && !OBJECT_FREE(op)) 01371 { 01372 otmp = op->above; 01373 } 01374 else if (last_valid) 01375 { 01376 otmp = last_valid->above; 01377 } 01378 /* Should be really rare */ 01379 else 01380 { 01381 otmp = get_map_ob(m, i, j); 01382 } 01383 } 01384 } 01385 } 01386 } 01387 } 01388 } 01389 01396 void set_map_darkness(mapstruct *m, int value) 01397 { 01398 if (value < 0 || value > MAX_DARKNESS) 01399 { 01400 value = MAX_DARKNESS; 01401 } 01402 01403 MAP_DARKNESS(m) = (sint32) value; 01404 m->light_value = (sint32) global_darkness_table[value]; 01405 } 01406 01410 mapstruct *get_linked_map() 01411 { 01412 mapstruct *map = (mapstruct *) calloc(1, sizeof(mapstruct)); 01413 01414 if (map == NULL) 01415 { 01416 LOG(llevError, "get_linked_map(): Out of memory.\n"); 01417 } 01418 01419 if (first_map) 01420 { 01421 first_map->previous = map; 01422 } 01423 01424 map->next = first_map; 01425 first_map = map; 01426 01427 map->in_memory = MAP_SWAPPED; 01428 01429 /* The maps used to pick up default x and y values from the 01430 * map archetype. Mimic that behavior. */ 01431 MAP_WIDTH(map) = 16; 01432 MAP_HEIGHT(map) = 16; 01433 MAP_RESET_TIMEOUT(map) = 0; 01434 MAP_TIMEOUT(map) = MAP_DEFAULTTIMEOUT; 01435 set_map_darkness(map, MAP_DEFAULT_DARKNESS); 01436 01437 MAP_ENTER_X(map) = 0; 01438 MAP_ENTER_Y(map) = 0; 01439 01440 return map; 01441 } 01442 01447 static void allocate_map(mapstruct *m) 01448 { 01449 m->in_memory = MAP_LOADING; 01450 01451 if (m->spaces || m->bitmap) 01452 { 01453 LOG(llevError, "allocate_map(): Callled with already allocated map (%s)\n", m->path); 01454 } 01455 01456 if (m->buttons) 01457 { 01458 LOG(llevBug, "allocate_map(): Callled with already set buttons (%s)\n", m->path); 01459 } 01460 01461 m->spaces = calloc(1, MAP_WIDTH(m) * MAP_HEIGHT(m) * sizeof(MapSpace)); 01462 01463 m->bitmap = malloc(((MAP_WIDTH(m) + 31) / 32) * MAP_HEIGHT(m) * sizeof(uint32)); 01464 01465 if (m->spaces == NULL || m->bitmap == NULL) 01466 { 01467 LOG(llevError, "allocate_map(): Out of memory.\n"); 01468 } 01469 } 01470 01478 mapstruct *get_empty_map(int sizex, int sizey) 01479 { 01480 mapstruct *m = get_linked_map(); 01481 m->width = sizex; 01482 m->height = sizey; 01483 allocate_map(m); 01484 01485 m->in_memory = MAP_IN_MEMORY; 01486 01487 return m; 01488 } 01489 01502 mapstruct *load_original_map(const char *filename, int flags) 01503 { 01504 FILE *fp; 01505 mapstruct *m; 01506 int comp; 01507 char pathname[MAX_BUF], tmp_fname[MAX_BUF]; 01508 01509 /* No sense in doing this all for random maps, it will all fail anyways. */ 01510 if (!strncmp(filename, "/random/", 8)) 01511 { 01512 return NULL; 01513 } 01514 01515 if (*filename != '/' && *filename != '.') 01516 { 01517 LOG(llevDebug, "load_original_map(): Filename without starting '/' - fixed. %s\n", filename); 01518 tmp_fname[0] = '/'; 01519 strcpy(tmp_fname + 1, filename); 01520 filename = tmp_fname; 01521 } 01522 01523 if (flags & MAP_PLAYER_UNIQUE) 01524 { 01525 LOG(llevDebug, "load_original_map unique: %s (%x)\n", filename, flags); 01526 strcpy(pathname, filename); 01527 } 01528 else 01529 { 01530 LOG(llevDebug, "load_original_map: %s (%x) ", filename, flags); 01531 strcpy(pathname, create_pathname(filename)); 01532 } 01533 01534 if ((fp = open_and_uncompress(pathname, 0, &comp)) == NULL) 01535 { 01536 if (!(flags & MAP_PLAYER_UNIQUE)) 01537 { 01538 LOG(llevBug, "Can't open map file %s\n", pathname); 01539 } 01540 01541 return NULL; 01542 } 01543 01544 LOG(llevDebug, "link map. "); 01545 m = get_linked_map(); 01546 01547 LOG(llevDebug, "header: "); 01548 FREE_AND_COPY_HASH(m->path, filename); 01549 01550 if (!load_map_header(m, fp)) 01551 { 01552 LOG(llevBug, "Failure loading map header for %s, flags=%d\n", filename, flags); 01553 delete_map(m); 01554 return NULL; 01555 } 01556 01557 LOG(llevDebug, "alloc. "); 01558 allocate_map(m); 01559 m->compressed = comp; 01560 01561 m->in_memory = MAP_LOADING; 01562 LOG(llevDebug, "load objs:"); 01563 load_objects(m, fp, (flags & (MAP_BLOCK | MAP_STYLE)) | MAP_ORIGINAL); 01564 LOG(llevDebug, "close. "); 01565 close_and_delete(fp, comp); 01566 LOG(llevDebug, "post set. "); 01567 01568 if (!MAP_DIFFICULTY(m)) 01569 { 01570 LOG(llevBug, "\nBUG: Map %s has difficulty 0. Changing to 1.\n", filename); 01571 MAP_DIFFICULTY(m) = 1; 01572 } 01573 01574 set_map_reset_time(m); 01575 LOG(llevDebug, "done!\n"); 01576 return m; 01577 } 01578 01584 static mapstruct *load_temporary_map(mapstruct *m) 01585 { 01586 FILE *fp; 01587 int comp; 01588 char buf[MAX_BUF]; 01589 01590 if (!m->tmpname) 01591 { 01592 LOG(llevBug, "No temporary filename for map %s! Fallback to original!\n", m->path); 01593 strcpy(buf, m->path); 01594 delete_map(m); 01595 m = load_original_map(buf, 0); 01596 01597 if (m == NULL) 01598 { 01599 return NULL; 01600 } 01601 01602 return m; 01603 } 01604 01605 LOG(llevDebug, "load_temporary_map: %s (%s) ", m->tmpname, m->path); 01606 01607 if ((fp = open_and_uncompress(m->tmpname, 0, &comp)) == NULL) 01608 { 01609 if (!strncmp(m->path, "/random/", 8)) 01610 { 01611 return NULL; 01612 } 01613 01614 LOG(llevBug, "Can't open temporary map %s! Fallback to original!\n", m->tmpname); 01615 strcpy(buf, m->path); 01616 delete_map(m); 01617 m = load_original_map(buf, 0); 01618 01619 if (m == NULL) 01620 { 01621 return NULL; 01622 } 01623 01624 return m; 01625 } 01626 01627 LOG(llevDebug, "header: "); 01628 01629 if (!load_map_header(m, fp)) 01630 { 01631 LOG(llevBug, "Error loading map header for %s (%s)! Fallback to original!\n", m->path, m->tmpname); 01632 delete_map(m); 01633 m = load_original_map(m->path, 0); 01634 01635 if (m == NULL) 01636 { 01637 return NULL; 01638 } 01639 01640 return m; 01641 } 01642 01643 LOG(llevDebug, "alloc. "); 01644 m->compressed = comp; 01645 allocate_map(m); 01646 01647 m->in_memory = MAP_LOADING; 01648 LOG(llevDebug, "load objs:"); 01649 load_objects (m, fp, 0); 01650 LOG(llevDebug, "close. "); 01651 close_and_delete(fp, comp); 01652 LOG(llevDebug, "done!\n"); 01653 return m; 01654 } 01655 01659 static void delete_unique_items(mapstruct *m) 01660 { 01661 int i, j, unique = 0; 01662 object *op, *next; 01663 01664 for (i = 0; i < MAP_WIDTH(m); i++) 01665 { 01666 for (j = 0; j < MAP_HEIGHT(m); j++) 01667 { 01668 unique = 0; 01669 01670 for (op = get_map_ob(m, i, j); op; op = next) 01671 { 01672 next = op->above; 01673 01674 if (QUERY_FLAG(op, FLAG_IS_FLOOR) && QUERY_FLAG(op, FLAG_UNIQUE)) 01675 { 01676 unique = 1; 01677 } 01678 01679 if (op->head == NULL && (QUERY_FLAG(op, FLAG_UNIQUE) || unique)) 01680 { 01681 if (QUERY_FLAG(op, FLAG_IS_LINKED)) 01682 { 01683 remove_button_link(op); 01684 } 01685 01686 remove_ob(op); 01687 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01688 } 01689 } 01690 } 01691 } 01692 } 01693 01697 static void load_unique_objects(mapstruct *m) 01698 { 01699 FILE *fp; 01700 int comp, count; 01701 char firstname[MAX_BUF]; 01702 01703 for (count = 0; count < 10; count++) 01704 { 01705 sprintf(firstname, "%s.v%02d", create_items_path(m->path), count); 01706 01707 if (!access(firstname, R_OK)) 01708 { 01709 break; 01710 } 01711 } 01712 01713 /* If we get here, we did not find any map */ 01714 if (count == 10) 01715 { 01716 return; 01717 } 01718 01719 LOG(llevDebug, "open unique items file for %s\n", create_items_path(m->path)); 01720 01721 if ((fp = open_and_uncompress(firstname, 0, &comp)) == NULL) 01722 { 01723 /* There is no expectation that every map will have unique items, but this 01724 * is debug output, so leave it in. */ 01725 LOG(llevDebug, "Can't open unique items file for %s\n", create_items_path(m->path)); 01726 return; 01727 } 01728 01729 m->in_memory = MAP_LOADING; 01730 01731 /* If we have loaded unique items from */ 01732 if (m->tmpname == NULL) 01733 { 01734 delete_unique_items(m); 01735 } 01736 01737 load_objects(m, fp, 0); 01738 close_and_delete(fp, comp); 01739 } 01740 01751 int new_save_map(mapstruct *m, int flag) 01752 { 01753 FILE *fp, *fp2; 01754 char filename[MAX_BUF], buf[MAX_BUF]; 01755 01756 if (flag && !*m->path) 01757 { 01758 LOG(llevBug, "Tried to save map without path.\n"); 01759 return -1; 01760 } 01761 01762 if (flag || MAP_UNIQUE(m)) 01763 { 01764 if (!MAP_UNIQUE(m)) 01765 { 01766 strcpy(filename, create_pathname(m->path)); 01767 } 01768 else 01769 { 01770 /* This ensures we always reload from original maps */ 01771 if (MAP_NOSAVE(m)) 01772 { 01773 LOG(llevDebug, "skip map %s (no_save flag)\n", m->path); 01774 return 0; 01775 } 01776 01777 strcpy(filename, m->path); 01778 } 01779 01780 /* If the compression suffix already exists on the filename, don't 01781 * put it on again. This nasty looking strcmp checks to see if the 01782 * compression suffix is at the end of the filename already. 01783 * i don't checked them - perhaps we need compression in the future 01784 * even i can't see it - the if is harmless because self terminating 01785 * after the m->compressed fails. */ 01786 if (m->compressed && strcmp((filename + strlen(filename) - strlen(uncomp[m->compressed][0])), uncomp[m->compressed][0])) 01787 { 01788 strcat(filename, uncomp[m->compressed][0]); 01789 } 01790 01791 make_path_to_file(filename); 01792 } 01793 else 01794 { 01795 if (m->tmpname == NULL) 01796 { 01797 m->tmpname = tempnam_local(settings.tmpdir, NULL); 01798 } 01799 01800 strcpy(filename, m->tmpname); 01801 } 01802 01803 LOG(llevDebug, "Saving map %s to %s\n", m->path, filename); 01804 01805 m->in_memory = MAP_SAVING; 01806 01807 /* Compress if it isn't a temporary save. Do compress if unique */ 01808 if (m->compressed && (MAP_UNIQUE(m) || flag)) 01809 { 01810 strcpy(buf, uncomp[m->compressed][2]); 01811 strcat(buf, " > "); 01812 strcat(buf, filename); 01813 fp = popen(buf, "w"); 01814 } 01815 else 01816 { 01817 fp = fopen(filename, "w"); 01818 } 01819 01820 if (!fp) 01821 { 01822 LOG(llevError, "Can't open file %s for saving.\n", filename); 01823 return -1; 01824 } 01825 01826 save_map_header(m, fp, flag); 01827 01828 /* Save unique items into fp2 */ 01829 fp2 = fp; 01830 01831 if (!MAP_UNIQUE(m)) 01832 { 01833 snprintf(buf, sizeof(buf), "%s.v00", create_items_path(m->path)); 01834 01835 if ((fp2 = fopen(buf, "w")) == NULL) 01836 { 01837 LOG(llevBug, "Can't open unique items file %s\n", buf); 01838 } 01839 01840 save_objects(m, fp, fp2); 01841 01842 if (fp2) 01843 { 01844 if (ftell(fp2) == 0) 01845 { 01846 fclose(fp2); 01847 unlink(buf); 01848 } 01849 else 01850 { 01851 LOG(llevDebug, "Saving unique items map to %s\n", buf); 01852 fclose(fp2); 01853 chmod(buf, SAVE_MODE); 01854 } 01855 } 01856 } 01857 /* Otherwise to the same file, like apartments */ 01858 else 01859 { 01860 save_objects(m, fp, fp); 01861 } 01862 01863 if (fp) 01864 { 01865 if (m->compressed && !flag) 01866 { 01867 pclose(fp); 01868 } 01869 else 01870 { 01871 fclose(fp); 01872 } 01873 } 01874 01875 chmod(filename, SAVE_MODE); 01876 return 0; 01877 } 01878 01882 static void free_all_objects(mapstruct *m) 01883 { 01884 int i, j; 01885 object *op; 01886 01887 for (i = 0; i < MAP_WIDTH(m); i++) 01888 { 01889 for (j = 0; j < MAP_HEIGHT(m); j++) 01890 { 01891 object *previous_obj = NULL; 01892 01893 while ((op = GET_MAP_OB(m, i, j)) != NULL) 01894 { 01895 if (op == previous_obj) 01896 { 01897 LOG(llevDebug, "free_all_objects: Link error, bailing out.\n"); 01898 break; 01899 } 01900 01901 previous_obj = op; 01902 01903 if (op->head) 01904 { 01905 op = op->head; 01906 } 01907 01908 remove_ob(op); 01909 } 01910 } 01911 } 01912 } 01913 01920 void free_map(mapstruct *m, int flag) 01921 { 01922 int i; 01923 01924 if (!m->in_memory) 01925 { 01926 LOG(llevBug, "Trying to free freed map.\n"); 01927 return; 01928 } 01929 01930 remove_light_source_list(m); 01931 01932 if (m->buttons) 01933 { 01934 free_objectlinkpt(m->buttons); 01935 } 01936 01937 if (flag && m->spaces) 01938 { 01939 free_all_objects(m); 01940 } 01941 01942 FREE_AND_NULL_PTR(m->name); 01943 FREE_AND_NULL_PTR(m->bg_music); 01944 FREE_AND_NULL_PTR(m->weather); 01945 FREE_AND_NULL_PTR(m->spaces); 01946 FREE_AND_NULL_PTR(m->msg); 01947 m->buttons = NULL; 01948 m->first_light = NULL; 01949 01950 for (i = 0; i < TILED_MAPS; i++) 01951 { 01952 /* Delete the backlinks in other tiled maps to our map */ 01953 if (m->tile_map[i]) 01954 { 01955 if (m->tile_map[i]->tile_map[map_tiled_reverse[i]] && m->tile_map[i]->tile_map[map_tiled_reverse[i]] != m) 01956 { 01957 LOG(llevBug, "Freeing map %s linked to %s which links back to another map.\n", STRING_SAFE(m->path), STRING_SAFE(m->tile_map[i]->path)); 01958 } 01959 01960 m->tile_map[i]->tile_map[map_tiled_reverse[i]] = NULL; 01961 m->tile_map[i] = NULL; 01962 } 01963 01964 FREE_AND_CLEAR_HASH(m->tile_path[i]); 01965 } 01966 01967 if (m->events) 01968 { 01969 map_event *tmp, *next; 01970 01971 for (tmp = m->events; tmp; tmp = next) 01972 { 01973 next = tmp->next; 01974 map_event_free(tmp); 01975 } 01976 01977 m->events = NULL; 01978 } 01979 01980 FREE_AND_NULL_PTR(m->bitmap); 01981 m->in_memory = MAP_SWAPPED; 01982 } 01983 01988 void delete_map(mapstruct *m) 01989 { 01990 if (!m) 01991 { 01992 return; 01993 } 01994 01995 if (m->in_memory == MAP_IN_MEMORY) 01996 { 01997 /* Change to MAP_SAVING, even though we are not, 01998 * so that remove_ob doesn't do as much work. */ 01999 m->in_memory = MAP_SAVING; 02000 free_map(m, 1); 02001 } 02002 else 02003 { 02004 remove_light_source_list(m); 02005 } 02006 02007 /* Remove m from the global map list */ 02008 if (m->next) 02009 { 02010 m->next->previous = m->previous; 02011 } 02012 02013 if (m->previous) 02014 { 02015 m->previous->next = m->next; 02016 } 02017 /* If there is no previous, we are first map */ 02018 else 02019 { 02020 first_map = m->next; 02021 } 02022 02023 /* tmpname can still be needed if the map is swapped out, so we don't 02024 * do it in free_map(). */ 02025 FREE_AND_NULL_PTR(m->tmpname); 02026 FREE_AND_CLEAR_HASH(m->path); 02027 free(m); 02028 } 02029 02039 mapstruct *ready_map_name(const char *name, int flags) 02040 { 02041 mapstruct *m; 02042 shstr *name_sh; 02043 02044 if (!name) 02045 { 02046 return NULL; 02047 } 02048 02049 /* Have we been at this level before? */ 02050 if (flags & MAP_NAME_SHARED) 02051 { 02052 m = has_been_loaded_sh(name); 02053 } 02054 else 02055 { 02056 /* Create a temporary shared string for the name if not explicitly given */ 02057 name_sh = add_string(name); 02058 m = has_been_loaded_sh(name_sh); 02059 free_string_shared(name_sh); 02060 } 02061 02062 /* Map is good to go, so just return it */ 02063 if (m && (m->in_memory == MAP_LOADING || m->in_memory == MAP_IN_MEMORY)) 02064 { 02065 return m; 02066 } 02067 02068 /* Unique maps always get loaded from their original location, and never 02069 * a temp location. Likewise, if map_flush is set, or we have never loaded 02070 * this map, load it now. I removed the reset checking from here - 02071 * it seems the probability of a player trying to enter a map that should 02072 * reset but hasn't yet is quite low, and removing that makes this function 02073 * a bit cleaner (and players probably shouldn't rely on exact timing for 02074 * resets in any case - if they really care, they should use the 'maps command. */ 02075 if (!m || (flags & (MAP_FLUSH | MAP_PLAYER_UNIQUE))) 02076 { 02077 /* First visit or time to reset */ 02078 if (m) 02079 { 02080 /* Doesn't make much difference */ 02081 clean_tmp_map(m); 02082 delete_map(m); 02083 } 02084 02085 /* Create and load a map */ 02086 if (!(m = load_original_map(name, (flags & MAP_PLAYER_UNIQUE)))) 02087 { 02088 return NULL; 02089 } 02090 02091 /* If a player unique map, no extra unique object file to load. 02092 * if from the editor, likewise. */ 02093 if (!(flags & (MAP_FLUSH | MAP_PLAYER_UNIQUE))) 02094 { 02095 load_unique_objects(m); 02096 } 02097 } 02098 else 02099 { 02100 /* If in this loop, we found a temporary map, so load it up. */ 02101 m = load_temporary_map(m); 02102 02103 if (m == NULL) 02104 { 02105 return NULL; 02106 } 02107 02108 LOG(llevDebug, "RMN: unique. "); 02109 load_unique_objects(m); 02110 02111 LOG(llevDebug, "clean. "); 02112 clean_tmp_map(m); 02113 m->in_memory = MAP_IN_MEMORY; 02114 } 02115 02116 /* Below here is stuff common to both first time loaded maps and 02117 * temp maps. */ 02118 02119 /* In case other objects press some buttons down. 02120 * We handle here all kind of "triggers" which are triggered 02121 * permanent by objects like buttons or inventory checkers. 02122 * We don't check here instant stuff like sacrificing altars. 02123 * Because this should be handled on map making side. */ 02124 LOG(llevDebug, "buttons. "); 02125 update_buttons(m); 02126 LOG(llevDebug, "end ready_map_name(%s)\n", m->path ? m->path : "<nopath>"); 02127 02128 return m; 02129 } 02130 02134 void clean_tmp_map(mapstruct *m) 02135 { 02136 if (m->tmpname == NULL) 02137 { 02138 return; 02139 } 02140 02141 unlink(m->tmpname); 02142 } 02143 02146 void free_all_maps() 02147 { 02148 int real_maps = 0; 02149 02150 while (first_map) 02151 { 02152 /* I think some of the callers above before it gets here set this to be 02153 * saving, but we still want to free this data */ 02154 if (first_map->in_memory == MAP_SAVING) 02155 { 02156 first_map->in_memory = MAP_IN_MEMORY; 02157 } 02158 02159 delete_map(first_map); 02160 real_maps++; 02161 } 02162 02163 LOG(llevDebug, "free_all_maps: Freed %d maps\n", real_maps); 02164 } 02165 02173 void update_position(mapstruct *m, int x, int y) 02174 { 02175 object *tmp; 02176 int flags, move_flags; 02177 02178 #ifdef DEBUG_OLDFLAGS 02179 int oldflags; 02180 02181 if (!((oldflags = GET_MAP_FLAGS(m, x, y)) & (P_NEED_UPDATE | P_FLAGS_UPDATE))) 02182 { 02183 LOG(llevDebug, "update_position called with P_NEED_UPDATE|P_FLAGS_UPDATE not set: %s (%d, %d)\n", m->path, x, y); 02184 } 02185 #endif 02186 02187 /* save our update flag */ 02188 flags = oldflags & P_NEED_UPDATE; 02189 02190 /* update our flags */ 02191 if (oldflags & P_FLAGS_UPDATE) 02192 { 02193 #ifdef DEBUG_CORE 02194 LOG(llevDebug, "UP - FLAGS: %d,%d\n", x, y); 02195 #endif 02196 move_flags = 0; 02197 02198 /* This is a key function and highly often called - every saved tick is good. */ 02199 for (tmp = get_map_ob (m, x, y); tmp; tmp = tmp->above) 02200 { 02201 if (QUERY_FLAG(tmp, FLAG_PLAYER_ONLY)) 02202 { 02203 flags |= P_PLAYER_ONLY; 02204 } 02205 02206 if (tmp->type == CHECK_INV) 02207 { 02208 flags |= P_CHECK_INV; 02209 } 02210 02211 if (tmp->type == MAGIC_EAR) 02212 { 02213 flags |= P_MAGIC_EAR; 02214 } 02215 02216 if (QUERY_FLAG(tmp, FLAG_IS_PLAYER)) 02217 { 02218 flags |= P_IS_PLAYER; 02219 } 02220 02221 if (QUERY_FLAG(tmp, FLAG_DOOR_CLOSED)) 02222 { 02223 flags |= P_DOOR_CLOSED; 02224 } 02225 02226 if (QUERY_FLAG(tmp, FLAG_ALIVE)) 02227 { 02228 flags |= P_IS_ALIVE; 02229 } 02230 02231 if (QUERY_FLAG(tmp, FLAG_NO_MAGIC)) 02232 { 02233 flags |= P_NO_MAGIC; 02234 } 02235 02236 if (QUERY_FLAG(tmp, FLAG_NO_CLERIC)) 02237 { 02238 flags |= P_NO_CLERIC; 02239 } 02240 02241 if (QUERY_FLAG(tmp, FLAG_BLOCKSVIEW)) 02242 { 02243 flags |= P_BLOCKSVIEW; 02244 } 02245 02246 if (QUERY_FLAG(tmp, FLAG_WALK_ON)) 02247 { 02248 flags |= P_WALK_ON; 02249 } 02250 02251 if (QUERY_FLAG(tmp, FLAG_WALK_OFF)) 02252 { 02253 flags |= P_WALK_OFF; 02254 } 02255 02256 if (QUERY_FLAG(tmp, FLAG_FLY_ON)) 02257 { 02258 flags |= P_FLY_ON; 02259 } 02260 02261 if (QUERY_FLAG(tmp, FLAG_FLY_OFF)) 02262 { 02263 flags |= P_FLY_OFF; 02264 } 02265 02266 if (QUERY_FLAG(tmp, FLAG_NO_PASS)) 02267 { 02268 if (flags & P_NO_PASS) 02269 { 02270 if (!QUERY_FLAG(tmp, FLAG_PASS_THRU)) 02271 { 02272 flags &= ~P_PASS_THRU; 02273 } 02274 } 02275 else 02276 { 02277 flags |= P_NO_PASS; 02278 02279 if (QUERY_FLAG(tmp, FLAG_PASS_THRU)) 02280 { 02281 flags |= P_PASS_THRU; 02282 } 02283 } 02284 } 02285 02286 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) 02287 { 02288 move_flags |= tmp->terrain_type; 02289 } 02290 02291 if (QUERY_FLAG(tmp, FLAG_NO_PVP)) 02292 { 02293 flags |= P_NO_PVP; 02294 } 02295 02296 if (tmp->type == MAGIC_MIRROR) 02297 { 02298 flags |= P_MAGIC_MIRROR; 02299 } 02300 02301 if (QUERY_FLAG(tmp, FLAG_OUTDOOR)) 02302 { 02303 flags |= P_OUTDOOR; 02304 } 02305 } 02306 02307 #ifdef DEBUG_OLDFLAGS 02308 /* We don't want to rely on this function to have accurate flags, but 02309 * since we're already doing the work, we calculate them here. 02310 * if they don't match, logic is broken someplace. */ 02311 if (((oldflags & ~(P_FLAGS_UPDATE | P_FLAGS_ONLY | P_NO_ERROR)) != flags) && (!(oldflags & P_NO_ERROR))) 02312 { 02313 LOG(llevDebug,"update_position: updated flags do not match old flags: %s (%d,%d) old:%x != %x\n", m->path, x, y, (oldflags & ~P_NEED_UPDATE), flags); 02314 } 02315 #endif 02316 02317 SET_MAP_FLAGS(m, x, y, flags); 02318 SET_MAP_MOVE_FLAGS(m, x, y, move_flags); 02319 } 02320 02321 /* Check if we must rebuild the map layers for client view */ 02322 if ((oldflags & P_FLAGS_ONLY) || !(oldflags & P_NEED_UPDATE)) 02323 { 02324 return; 02325 } 02326 02327 /* Clear out need update flag */ 02328 SET_MAP_FLAGS(m, x, y, GET_MAP_FLAGS(m, x, y) & ~P_NEED_UPDATE); 02329 } 02330 02334 void set_map_reset_time(mapstruct *map) 02335 { 02336 uint32 timeout = MAP_RESET_TIMEOUT(map); 02337 02338 if (timeout == 0) 02339 { 02340 timeout = MAP_DEFAULTRESET; 02341 } 02342 02343 if (timeout >= MAP_MAXRESET) 02344 { 02345 timeout = MAP_MAXRESET; 02346 } 02347 02348 MAP_WHEN_RESET(map) = seconds() + timeout; 02349 } 02350 02362 mapstruct *get_map_from_coord(mapstruct *m, int *x, int *y) 02363 { 02364 /* m should never be null, but if a tiled map fails to load below, it 02365 * could happen. */ 02366 if (!m) 02367 { 02368 return NULL; 02369 } 02370 02371 /* Simple case - coordinates are within this local map. */ 02372 if (*x >= 0 && *x < MAP_WIDTH(m) && *y >= 0 && *y < MAP_HEIGHT(m)) 02373 { 02374 return m; 02375 } 02376 02377 /* West, Northwest or Southwest (3, 7 or 6) */ 02378 if (*x < 0) 02379 { 02380 /* Northwest */ 02381 if (*y < 0) 02382 { 02383 if (!m->tile_path[7]) 02384 { 02385 return NULL; 02386 } 02387 02388 if (!m->tile_map[7] || m->tile_map[7]->in_memory != MAP_IN_MEMORY) 02389 { 02390 if (!load_and_link_tiled_map(m, 7)) 02391 { 02392 return NULL; 02393 } 02394 } 02395 02396 *y += MAP_HEIGHT(m->tile_map[7]); 02397 *x += MAP_WIDTH(m->tile_map[7]); 02398 return get_map_from_coord(m->tile_map[7], x, y); 02399 } 02400 02401 /* Southwest */ 02402 if (*y >= MAP_HEIGHT(m)) 02403 { 02404 if (!m->tile_path[6]) 02405 { 02406 return NULL; 02407 } 02408 02409 if (!m->tile_map[6] || m->tile_map[6]->in_memory != MAP_IN_MEMORY) 02410 { 02411 if (!load_and_link_tiled_map(m, 6)) 02412 { 02413 return NULL; 02414 } 02415 } 02416 02417 *y -= MAP_HEIGHT(m); 02418 *x += MAP_WIDTH(m->tile_map[6]); 02419 return get_map_from_coord(m->tile_map[6], x, y); 02420 } 02421 02422 /* West */ 02423 if (!m->tile_path[3]) 02424 { 02425 return NULL; 02426 } 02427 02428 if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) 02429 { 02430 if (!load_and_link_tiled_map(m, 3)) 02431 { 02432 return NULL; 02433 } 02434 } 02435 02436 *x += MAP_WIDTH(m->tile_map[3]); 02437 return get_map_from_coord(m->tile_map[3], x, y); 02438 } 02439 02440 /* East, Northeast or Southeast (1, 4 or 5) */ 02441 if (*x >= MAP_WIDTH(m)) 02442 { 02443 /* Northeast */ 02444 if (*y < 0) 02445 { 02446 if (!m->tile_path[4]) 02447 { 02448 return NULL; 02449 } 02450 02451 if (!m->tile_map[4] || m->tile_map[4]->in_memory != MAP_IN_MEMORY) 02452 { 02453 if (!load_and_link_tiled_map(m, 4)) 02454 { 02455 return NULL; 02456 } 02457 } 02458 02459 *y += MAP_HEIGHT(m->tile_map[4]); 02460 *x -= MAP_WIDTH(m); 02461 return get_map_from_coord(m->tile_map[4], x, y); 02462 } 02463 02464 /* Southeast */ 02465 if (*y >= MAP_HEIGHT(m)) 02466 { 02467 if (!m->tile_path[5]) 02468 { 02469 return NULL; 02470 } 02471 02472 if (!m->tile_map[5] || m->tile_map[5]->in_memory != MAP_IN_MEMORY) 02473 { 02474 if (!load_and_link_tiled_map(m, 5)) 02475 { 02476 return NULL; 02477 } 02478 } 02479 02480 *y -= MAP_HEIGHT(m); 02481 *x -= MAP_WIDTH(m); 02482 return get_map_from_coord(m->tile_map[5], x, y); 02483 } 02484 02485 /* East */ 02486 if (!m->tile_path[1]) 02487 { 02488 return NULL; 02489 } 02490 02491 if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY) 02492 { 02493 if (!load_and_link_tiled_map(m, 1)) 02494 { 02495 return NULL; 02496 } 02497 } 02498 02499 *x -= MAP_WIDTH(m); 02500 return get_map_from_coord(m->tile_map[1], x, y); 02501 } 02502 02503 /* Because we have tested x above, we don't need to check for 02504 * Northwest, Southwest, Northeast and Northwest here again. */ 02505 if (*y < 0) 02506 { 02507 if (!m->tile_path[0]) 02508 { 02509 return NULL; 02510 } 02511 02512 if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY) 02513 { 02514 if (!load_and_link_tiled_map(m, 0)) 02515 { 02516 return NULL; 02517 } 02518 } 02519 02520 *y += MAP_HEIGHT(m->tile_map[0]); 02521 return get_map_from_coord(m->tile_map[0], x, y); 02522 } 02523 02524 if (*y >= MAP_HEIGHT(m)) 02525 { 02526 if (!m->tile_path[2]) 02527 { 02528 return NULL; 02529 } 02530 02531 if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) 02532 { 02533 if (!load_and_link_tiled_map(m, 2)) 02534 { 02535 return NULL; 02536 } 02537 } 02538 02539 *y -= MAP_HEIGHT(m); 02540 return get_map_from_coord(m->tile_map[2], x, y); 02541 } 02542 02543 return NULL; 02544 } 02545 02556 mapstruct *get_map_from_coord2(mapstruct *m, int *x, int *y) 02557 { 02558 if (!m) 02559 { 02560 *x = 0; 02561 return NULL; 02562 } 02563 02564 /* Simple case - coordinates are within this local map. */ 02565 if (*x >= 0 && *x < MAP_WIDTH(m) && *y >= 0 && *y < MAP_HEIGHT(m)) 02566 { 02567 return m; 02568 } 02569 02570 /* West, Northwest or Southwest (3, 7 or 6) */ 02571 if (*x < 0) 02572 { 02573 /* Northwest */ 02574 if (*y < 0) 02575 { 02576 if (!m->tile_path[7]) 02577 { 02578 *x = 0; 02579 return NULL; 02580 } 02581 02582 if (!m->tile_map[7] || m->tile_map[7]->in_memory != MAP_IN_MEMORY) 02583 { 02584 *x = -1; 02585 return NULL; 02586 } 02587 02588 *y += MAP_HEIGHT(m->tile_map[7]); 02589 *x += MAP_WIDTH(m->tile_map[7]); 02590 02591 return get_map_from_coord2(m->tile_map[7], x, y); 02592 } 02593 02594 /* Southwest */ 02595 if (*y >= MAP_HEIGHT(m)) 02596 { 02597 if (!m->tile_path[6]) 02598 { 02599 *x = 0; 02600 return NULL; 02601 } 02602 02603 if (!m->tile_map[6] || m->tile_map[6]->in_memory != MAP_IN_MEMORY) 02604 { 02605 *x = -1; 02606 return NULL; 02607 } 02608 02609 *y -= MAP_HEIGHT(m); 02610 *x += MAP_WIDTH(m->tile_map[6]); 02611 02612 return get_map_from_coord2(m->tile_map[6], x, y); 02613 } 02614 02615 /* West */ 02616 if (!m->tile_path[3]) 02617 { 02618 *x = 0; 02619 return NULL; 02620 } 02621 02622 if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) 02623 { 02624 *x = -1; 02625 return NULL; 02626 } 02627 02628 *x += MAP_WIDTH(m->tile_map[3]); 02629 return get_map_from_coord2(m->tile_map[3], x, y); 02630 } 02631 02632 /* East, Northeast or Southeast (1, 4 or 5) */ 02633 if (*x >= MAP_WIDTH(m)) 02634 { 02635 /* Northeast */ 02636 if (*y < 0) 02637 { 02638 if (!m->tile_path[4]) 02639 { 02640 *x = 0; 02641 return NULL; 02642 } 02643 02644 if (!m->tile_map[4] || m->tile_map[4]->in_memory != MAP_IN_MEMORY) 02645 { 02646 *x = -1; 02647 return NULL; 02648 } 02649 02650 *y += MAP_HEIGHT(m->tile_map[4]); 02651 *x -= MAP_WIDTH(m); 02652 02653 return get_map_from_coord2(m->tile_map[4], x, y); 02654 } 02655 02656 /* Southeast */ 02657 if (*y >= MAP_HEIGHT(m)) 02658 { 02659 if (!m->tile_path[5]) 02660 { 02661 *x = 0; 02662 return NULL; 02663 } 02664 02665 if (!m->tile_map[5] || m->tile_map[5]->in_memory != MAP_IN_MEMORY) 02666 { 02667 *x = -1; 02668 return NULL; 02669 } 02670 02671 *y -= MAP_HEIGHT(m); 02672 *x -= MAP_WIDTH(m); 02673 02674 return get_map_from_coord2(m->tile_map[5], x, y); 02675 } 02676 02677 /* East */ 02678 if (!m->tile_path[1]) 02679 { 02680 *x = 0; 02681 return NULL; 02682 } 02683 02684 if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY) 02685 { 02686 *x = -1; 02687 return NULL; 02688 } 02689 02690 *x -= MAP_WIDTH(m); 02691 return get_map_from_coord2(m->tile_map[1], x, y); 02692 } 02693 02694 /* Because we have tested x above, we don't need to check for 02695 * Northwest, Southwest, Northeast and Northwest here again. */ 02696 if (*y < 0) 02697 { 02698 if (!m->tile_path[0]) 02699 { 02700 *x = 0; 02701 return NULL; 02702 } 02703 02704 if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY) 02705 { 02706 *x = -1; 02707 return NULL; 02708 } 02709 02710 *y += MAP_HEIGHT(m->tile_map[0]); 02711 02712 return get_map_from_coord2(m->tile_map[0], x, y); 02713 } 02714 02715 if (*y >= MAP_HEIGHT(m)) 02716 { 02717 if (!m->tile_path[2]) 02718 { 02719 *x = 0; 02720 return NULL; 02721 } 02722 02723 if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) 02724 { 02725 *x = -1; 02726 return NULL; 02727 } 02728 02729 *y -= MAP_HEIGHT(m); 02730 return get_map_from_coord2(m->tile_map[2], x, y); 02731 } 02732 02733 *x = 0; 02734 return NULL; 02735 } 02736 02760 int get_rangevector(object *op1, object *op2, rv_vector *retval, int flags) 02761 { 02762 if (!get_rangevector_from_mapcoords(op1->map, op1->x, op1->y, op2->map, op2->x, op2->y, retval, flags | RV_NO_DISTANCE)) 02763 { 02764 return 0; 02765 } 02766 02767 retval->part = op1; 02768 02769 /* If this is multipart, find the closest part now */ 02770 if (!(flags & RV_IGNORE_MULTIPART) && op1->more) 02771 { 02772 object *tmp, *best = NULL; 02773 int best_distance = retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y, tmpi; 02774 02775 /* we just take the offset of the piece to head to figure 02776 * distance instead of doing all that work above again 02777 * since the distance fields we set above are positive in the 02778 * same axis as is used for multipart objects, the simply arithmetic 02779 * below works. */ 02780 for (tmp = op1->more; tmp; tmp = tmp->more) 02781 { 02782 tmpi = (retval->distance_x - tmp->arch->clone.x) * (retval->distance_x - tmp->arch->clone.x) + (retval->distance_y - tmp->arch->clone.y) * (retval->distance_y - tmp->arch->clone.y); 02783 02784 if (tmpi < best_distance) 02785 { 02786 best_distance = tmpi; 02787 best = tmp; 02788 } 02789 } 02790 02791 if (best) 02792 { 02793 retval->distance_x -= best->arch->clone.x; 02794 retval->distance_y -= best->arch->clone.y; 02795 retval->part = best; 02796 } 02797 } 02798 02799 retval->distance = isqrt(retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y); 02800 retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); 02801 02802 return 1; 02803 } 02804 02821 int get_rangevector_from_mapcoords(mapstruct *map1, int x1, int y1, mapstruct *map2, int x2, int y2, rv_vector *retval, int flags) 02822 { 02823 retval->part = NULL; 02824 02825 if (map1 == map2) 02826 { 02827 retval->distance_x = x2 - x1; 02828 retval->distance_y = y2 - y1; 02829 } 02830 else if (map1->tile_map[0] == map2) 02831 { 02832 retval->distance_x = x2 - x1; 02833 retval->distance_y = -(y1 + (MAP_HEIGHT(map2) - y2)); 02834 } 02835 else if (map1->tile_map[1] == map2) 02836 { 02837 retval->distance_y = y2 - y1; 02838 retval->distance_x = (MAP_WIDTH(map1) - x1) + x2; 02839 } 02840 else if (map1->tile_map[2] == map2) 02841 { 02842 retval->distance_x = x2 - x1; 02843 retval->distance_y = (MAP_HEIGHT(map1) - y1) + y2; 02844 } 02845 else if (map1->tile_map[3] == map2) 02846 { 02847 retval->distance_y = y2 - y1; 02848 retval->distance_x = -(x1 + (MAP_WIDTH(map2) - x2)); 02849 } 02850 else if (map1->tile_map[4] == map2) 02851 { 02852 retval->distance_y = -(y1 + (MAP_HEIGHT(map2)- y2)); 02853 retval->distance_x = (MAP_WIDTH(map1) - x1) + x2; 02854 } 02855 else if (map1->tile_map[5] == map2) 02856 { 02857 retval->distance_x = (MAP_WIDTH(map1) - x1) + x2; 02858 retval->distance_y = (MAP_HEIGHT(map1) - y1) + y2; 02859 } 02860 else if (map1->tile_map[6] == map2) 02861 { 02862 retval->distance_y = (MAP_HEIGHT(map1) - y1) + y2; 02863 retval->distance_x = -(x1 + (MAP_WIDTH(map2) - x2)); 02864 } 02865 else if (map1->tile_map[7] == map2) 02866 { 02867 retval->distance_x = -(x1 + (MAP_WIDTH(map2) - x2)); 02868 retval->distance_y = -(y1 + (MAP_HEIGHT(map2) - y2)); 02869 } 02870 else if (flags & RV_RECURSIVE_SEARCH) 02871 { 02872 retval->distance_x = x2; 02873 retval->distance_y = y2; 02874 02875 if (!relative_tile_position(map1, map2, &retval->distance_x, &retval->distance_y)) 02876 { 02877 return 0; 02878 } 02879 02880 retval->distance_x -= x1; 02881 retval->distance_y -= y1; 02882 } 02883 else 02884 { 02885 return 0; 02886 } 02887 02888 switch (flags & (0x04 | 0x08)) 02889 { 02890 case RV_MANHATTAN_DISTANCE: 02891 retval->distance = abs(retval->distance_x) + abs(retval->distance_y); 02892 break; 02893 02894 case RV_EUCLIDIAN_DISTANCE: 02895 retval->distance = isqrt(retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y); 02896 break; 02897 02898 case RV_DIAGONAL_DISTANCE: 02899 retval->distance = MAX(abs(retval->distance_x), abs(retval->distance_y)); 02900 break; 02901 02902 /* No distance calc */ 02903 case RV_NO_DISTANCE: 02904 return 1; 02905 } 02906 02907 retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); 02908 return 1; 02909 } 02910 02917 int on_same_map(object *op1, object *op2) 02918 { 02919 if (!op1->map || !op2->map) 02920 { 02921 return 0; 02922 } 02923 02924 if (op1->map == op2->map || op1->map->tile_map[0] == op2->map || op1->map->tile_map[1] == op2->map || op1->map->tile_map[2] == op2->map || op1->map->tile_map[3] == op2->map || op1->map->tile_map[4] == op2->map || op1->map->tile_map[5] == op2->map || op1->map->tile_map[6] == op2->map || op1->map->tile_map[7] == op2->map) 02925 { 02926 return 1; 02927 } 02928 02929 return 0; 02930 } 02931 02936 int players_on_map(mapstruct *m) 02937 { 02938 object *tmp; 02939 int count; 02940 02941 for (count = 0, tmp = m->player_first; tmp; tmp = CONTR(tmp)->map_above) 02942 { 02943 count++; 02944 } 02945 02946 return count; 02947 } 02948 02956 int wall_blocked(mapstruct *m, int x, int y) 02957 { 02958 int r; 02959 02960 if (!(m = get_map_from_coord(m, &x, &y))) 02961 { 02962 return 1; 02963 } 02964 02965 r = GET_MAP_FLAGS(m, x, y) & (P_NO_PASS | P_PASS_THRU); 02966 02967 return r; 02968 } 02969 02978 void SockList_AddMapName(SockList *sl, object *pl, mapstruct *map, object *map_info) 02979 { 02980 (void) pl; 02981 SockList_AddStringUnterm(sl, "<b><o=0,0,0>"); 02982 SockList_AddStringUnterm(sl, map_info && map_info->race ? map_info->race : map->name); 02983 SockList_AddString(sl, "</o></b>"); 02984 } 02985 02994 void SockList_AddMapMusic(SockList *sl, object *pl, mapstruct *map, object *map_info) 02995 { 02996 (void) pl; 02997 SockList_AddString(sl, map_info && map_info->slaying ? map_info->slaying : (map->bg_music ? map->bg_music : "no_music")); 02998 } 02999 03008 void SockList_AddMapWeather(SockList *sl, object *pl, mapstruct *map, object *map_info) 03009 { 03010 if (pl && CONTR(pl)->socket.socket_version < 1047) 03011 { 03012 return; 03013 } 03014 03015 SockList_AddString(sl, map_info && map_info->title ? map_info->title : (map->weather ? map->weather : "none")); 03016 }
1.7.4