--- deliantra/server/common/map.C 2011/05/07 11:49:08 1.209
+++ deliantra/server/common/map.C 2018/12/01 20:22:12 1.222
@@ -1,24 +1,25 @@
/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
- *
- * Copyright (©) 2005,2006,2007,2008,2009,2010,2011 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
+ *
+ * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
+ * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
* Copyright (©) 2001-2003 Mark Wedel & Crossfire Development Team
* Copyright (©) 1992 Frank Tore Johansen
- *
+ *
* Deliantra is free software: you can redistribute it and/or modify it under
* the terms of the Affero GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the Affero GNU General Public License
* and the GNU General Public License along with this program. If not, see
* .
- *
+ *
* The authors can be reached via e-mail to
*/
@@ -61,7 +62,7 @@
/*
* Returns true if the given coordinate is blocked except by the
- * object passed is not blocking. This is used with
+ * object passed is not blocking. This is used with
* multipart monsters - if we want to see if a 2x2 monster
* can move 1 space to the left, we don't want its own area
* to block it from moving there.
@@ -485,8 +486,8 @@
//+GPL
-/* Takes a string from a map definition and outputs a pointer to the array of shopitems
- * corresponding to that string. Memory is allocated for this, it must be freed
+/* Takes a string from a map definition and outputs a pointer to the array of shopitems
+ * corresponding to that string. Memory is allocated for this, it must be freed
* at a later date.
* Called by parse_map_headers below.
*/
@@ -545,13 +546,13 @@
current_type = get_typedata_by_name (p);
if (current_type)
{
- items[i].name = current_type->name;
+ items[i].name = current_type->name;
items[i].typenum = current_type->number;
items[i].name_pl = current_type->name_pl;
}
else
{ /* oh uh, something's wrong, let's free up this one, and try
- * the next entry while we're at it, better print a warning
+ * the next entry while we're at it, better print a warning
*/
LOG (llevError, "invalid type %s defined in shopitems in string %s\n", p, input_string);
}
@@ -673,12 +674,12 @@
case KW_invisible: case KW_darkness: thawer.get (darkness); break;
case KW_stand_still: case KW_fixed_resettime: thawer.get (fixed_resettime); break;
- case KW_tile_path_1: thawer.get (tile_path [0]); break;
- case KW_tile_path_2: thawer.get (tile_path [1]); break;
- case KW_tile_path_3: thawer.get (tile_path [2]); break;
- case KW_tile_path_4: thawer.get (tile_path [3]); break;
- case KW_tile_path_5: thawer.get (tile_path [4]); break;
- case KW_tile_path_6: thawer.get (tile_path [5]); break;
+ case KW_tile_path_1: thawer.get (tile_path [TILE_NORTH]); break;
+ case KW_tile_path_2: thawer.get (tile_path [TILE_EAST ]); break;
+ case KW_tile_path_3: thawer.get (tile_path [TILE_SOUTH]); break;
+ case KW_tile_path_4: thawer.get (tile_path [TILE_WEST ]); break;
+ case KW_tile_path_5: thawer.get (tile_path [TILE_UP ]); break;
+ case KW_tile_path_6: thawer.get (tile_path [TILE_DOWN ]); break;
case KW_ERROR:
set_key_text (thawer.kw_str, thawer.value);
@@ -767,12 +768,12 @@
MAP_OUT (per_player);
MAP_OUT (per_party);
- if (tile_path [0]) MAP_OUT2 (tile_path_1, tile_path [0]);
- if (tile_path [1]) MAP_OUT2 (tile_path_2, tile_path [1]);
- if (tile_path [2]) MAP_OUT2 (tile_path_3, tile_path [2]);
- if (tile_path [3]) MAP_OUT2 (tile_path_4, tile_path [3]);
- if (tile_path [4]) MAP_OUT2 (tile_path_5, tile_path [4]);
- if (tile_path [5]) MAP_OUT2 (tile_path_6, tile_path [5]);
+ if (tile_path [TILE_NORTH]) MAP_OUT2 (tile_path_1, tile_path [TILE_NORTH]);
+ if (tile_path [TILE_EAST ]) MAP_OUT2 (tile_path_2, tile_path [TILE_EAST ]);
+ if (tile_path [TILE_SOUTH]) MAP_OUT2 (tile_path_3, tile_path [TILE_SOUTH]);
+ if (tile_path [TILE_WEST ]) MAP_OUT2 (tile_path_4, tile_path [TILE_WEST ]);
+ if (tile_path [TILE_UP ]) MAP_OUT2 (tile_path_5, tile_path [TILE_UP ]);
+ if (tile_path [TILE_DOWN ]) MAP_OUT2 (tile_path_6, tile_path [TILE_DOWN ]);
freezer.put (this);
freezer.put (KW(end));
@@ -839,7 +840,7 @@
shoprace = 0;
delete [] shopitems, shopitems = 0;
- for (int i = 0; i < array_length (tile_path); i++)
+ for (int i = 0; i < ecb_array_length (tile_path); i++)
tile_path [i] = 0;
}
@@ -856,7 +857,7 @@
* tiling can be asymetric, we just can not look to see which
* maps this map tiles with and clears those.
*/
- for (int i = 0; i < array_length (tile_path); i++)
+ for (int i = 0; i < ecb_array_length (tile_path); i++)
if (tile_map[i] == m)
tile_map[i] = 0;
}
@@ -1019,7 +1020,7 @@
return 1;
}
-/*
+/*
* This function updates various attributes about a specific space
* on the map (what it looks like, whether it blocks magic,
* has a living creatures, prevents people from passing
@@ -1133,7 +1134,7 @@
/* At this point, we have a floor face (if there is a floor),
* and the floor is set - we are not going to touch it at
* this point.
- * middle contains the highest visibility face.
+ * middle contains the highest visibility face.
* top contains a player/monster face, if there is one.
*
* We now need to fill in top.face and/or middle.face.
@@ -1141,7 +1142,7 @@
/* If the top face also happens to be high visibility, re-do our
* middle face. This should not happen, as we already have the
- * else statement above so middle should not get set. OTOH, it
+ * else statement above so middle should not get set. OTOH, it
* may be possible for the faces to match but be different objects.
*/
if (top == middle)
@@ -1180,7 +1181,7 @@
*
* Set the middle face and break out, since there is nothing
* more to fill in. We don't check visiblity here, since
- *
+ *
*/
if (tmp != top)
{
@@ -1197,29 +1198,26 @@
if (top == middle)
middle = 0;
- // dire hack to handle "transparent" floors - currently only open_space
- if (floor && floor->arch->archname == shstr_quad_open_space
- && !middle)
+ // set lower map transparent floor flag if applicable
+ if (floor && floor->flag [FLAG_IS_TRANSPARENT_FLOOR] && !middle && !top)
{
floor->set_anim_frame (0);
if (maptile *m = floor->map->tile_map [TILE_DOWN])
{
- // mirror the floor - very unreliable because usually outdated,
- // but somewhta works because floors do not change often :/
- middle = floor;
-
mapspace &ms = m->at (floor->x, floor->y);
-
ms.update ();
if (object *floor2 = ms.faces_obj [2])
- if (floor2->arch->archname != shstr_quad_open_space)
+ if (!floor2->flag [FLAG_IS_TRANSPARENT_FLOOR])
{
floor->set_anim_frame (1);
- middle = floor;
+ top = floor;
+ middle = ms.faces_obj [0];
floor = floor2;
}
+
+ ms.pflags |= PF_VIS_UP;
}
}
@@ -1230,18 +1228,63 @@
#endif
}
+void
+mapspace::update_up ()
+{
+ // invalidate up
+ if (!(pflags & PF_VIS_UP))
+ return;
+
+ pflags &= ~PF_VIS_UP;
+
+ if (bot)
+ if (maptile *m = bot->map->tile_map [TILE_UP])
+ m->at (bot->x, bot->y).invalidate ();
+}
+
maptile *
maptile::tile_available (int dir, bool load)
{
- if (tile_path[dir])
- {
- // map is there and we don't need to load it OR it's loaded => return what we have
- if (tile_map[dir] && (!load || tile_map[dir]->linkable ()))
- return tile_map[dir];
+ // map is there and we don't need to load it OR it's loaded => return what we have
+ if (tile_map [dir] && (!load || tile_map [dir]->linkable ()))
+ return tile_map [dir];
+ if (tile_path [dir])
+ {
// well, try to locate it then, if possible - maybe it's there already
- if ((tile_map[dir] = find_async (tile_path[dir], this, load)))
- return tile_map[dir];
+ // this is the ONLY place in the server that links maps with each other,
+ // so any kind of inter-map stuff has to be initiated here.
+ if (maptile *m = find_async (tile_path [dir], this, load))
+ {
+ bool mismatch = false;
+
+ if (dir == TILE_NORTH || dir == TILE_SOUTH || dir == TILE_UP || dir == TILE_DOWN)
+ if (width != m->width)
+ mismatch = true;
+
+ if (dir == TILE_EAST || dir == TILE_WEST || dir == TILE_UP || dir == TILE_DOWN)
+ if (height != m->height)
+ mismatch = true;
+
+ if (mismatch)
+ {
+ LOG (llevError, "tile dimension mismatch for direction %d from %s to %s\n",
+ dir, &path, &m->path);
+ m = 0;
+ }
+ else if (0)//D
+ {
+ // as an optimisation, link us against the other map if the other map
+ // has us as neighbour, which is very common, but not guaranteed.
+ int dir2 = REVERSE_TILE_DIR (dir);
+
+ if (m->tile_path [dir2] == path)
+ m->tile_map [dir2] = this;
+ }
+
+
+ return tile_map [dir] = m;
+ }
}
return 0;
@@ -1252,7 +1295,7 @@
* tiling considerations, loading adjacant maps as needed.
* This is the function should always be used when it
* necessary to check for valid coordinates.
- * This function will recursively call itself for the
+ * This function will recursively call itself for the
* tiled maps.
*/
int
@@ -1267,34 +1310,34 @@
if (x < 0)
{
- if (!m->tile_available (3))
+ if (!m->tile_available (TILE_WEST))
return 1;
- return out_of_map (m->tile_map[3], x + m->tile_map[3]->width, y);
+ return out_of_map (m->tile_map [TILE_WEST], x + m->tile_map [TILE_WEST]->width, y);
}
if (x >= m->width)
{
- if (!m->tile_available (1))
+ if (!m->tile_available (TILE_EAST))
return 1;
- return out_of_map (m->tile_map[1], x - m->width, y);
+ return out_of_map (m->tile_map [TILE_EAST], x - m->width, y);
}
if (y < 0)
{
- if (!m->tile_available (0))
+ if (!m->tile_available (TILE_NORTH))
return 1;
- return out_of_map (m->tile_map[0], x, y + m->tile_map[0]->height);
+ return out_of_map (m->tile_map [TILE_NORTH], x, y + m->tile_map [TILE_NORTH]->height);
}
if (y >= m->height)
{
- if (!m->tile_available (2))
+ if (!m->tile_available (TILE_SOUTH))
return 1;
- return out_of_map (m->tile_map[2], x, y - m->height);
+ return out_of_map (m->tile_map [TILE_SOUTH], x, y - m->height);
}
/* Simple case - coordinates are within this local
@@ -1306,7 +1349,7 @@
/* This is basically the same as out_of_map above, but
* instead we return NULL if no map is valid (coordinates
* out of bounds and no tiled map), otherwise it returns
- * the map as that the coordinates are really on, and
+ * the map as that the coordinates are really on, and
* updates x and y to be the localised coordinates.
* Using this is more efficient of calling out_of_map
* and then figuring out what the real map is
@@ -1316,38 +1359,38 @@
{
if (x < 0)
{
- if (!tile_available (3))
+ if (!tile_available (TILE_WEST))
return 0;
- x += tile_map[3]->width;
- return tile_map[3]->xy_find (x, y);
+ x += tile_map [TILE_WEST]->width;
+ return tile_map [TILE_WEST]->xy_find (x, y);
}
if (x >= width)
{
- if (!tile_available (1))
+ if (!tile_available (TILE_EAST))
return 0;
x -= width;
- return tile_map[1]->xy_find (x, y);
+ return tile_map [TILE_EAST]->xy_find (x, y);
}
if (y < 0)
{
- if (!tile_available (0))
+ if (!tile_available (TILE_NORTH))
return 0;
- y += tile_map[0]->height;
- return tile_map[0]->xy_find (x, y);
+ y += tile_map [TILE_NORTH]->height;
+ return tile_map [TILE_NORTH]->xy_find (x, y);
}
if (y >= height)
{
- if (!tile_available (2))
+ if (!tile_available (TILE_SOUTH))
return 0;
y -= height;
- return tile_map[2]->xy_find (x, y);
+ return tile_map [TILE_SOUTH]->xy_find (x, y);
}
/* Simple case - coordinates are within this local
@@ -1464,7 +1507,7 @@
* can be negative. direction is the crossfire direction scheme
* that the creature should head. part is the part of the
* monster that is closest.
- *
+ *
* get_rangevector looks at op1 and op2, and fills in the
* structure for op1 to get to op2.
* We already trust that the caller has verified that the
@@ -1530,9 +1573,9 @@
}
}
-/* this is basically the same as get_rangevector above, but instead of
+/* this is basically the same as get_rangevector above, but instead of
* the first parameter being an object, it instead is the map
- * and x,y coordinates - this is used for path to player -
+ * and x,y coordinates - this is used for path to player -
* since the object is not infact moving but we are trying to traverse
* the path, we need this.
* flags has no meaning for this function at this time - I kept it in to
@@ -1688,31 +1731,31 @@
if (maptile *tile = m->tile_available (TILE_EAST, 1))
split_to_tiles (buf, tile, max (x0 - m->width, 0), y0, x1 - m->width, y1, dx + m->width, dy);
- if (x0 > m->width) // entirely to the right
+ if (x0 >= m->width) // entirely to the right
return;
x1 = m->width;
}
- // clip to map above
+ // clip to map to the north
if (y0 < 0)
{
if (maptile *tile = m->tile_available (TILE_NORTH, 1))
split_to_tiles (buf, tile, x0, y0 + tile->height, x1, min (y1 + tile->height, tile->height), dx, dy - tile->height);
- if (y1 < 0) // entirely above
+ if (y1 < 0) // entirely to the north
return;
y0 = 0;
}
- // clip to map below
+ // clip to map to the south
if (y1 > m->height)
{
if (maptile *tile = m->tile_available (TILE_SOUTH, 1))
split_to_tiles (buf, tile, x0, max (y0 - m->height, 0), x1, y1 - m->height, dx, dy + m->height);
- if (y0 > m->height) // entirely below
+ if (y0 >= m->height) // entirely to the south
return;
y1 = m->height;