Atrinik Server 2.5
server/map.c
Go to the documentation of this file.
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 }