--- deliantra/server/common/map.C 2009/11/09 18:47:56 1.173
+++ deliantra/server/common/map.C 2012/10/29 23:55:52 1.218
@@ -1,31 +1,30 @@
/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
- *
- * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
- * Copyright (©) 2001-2003,2007 Mark Wedel & Crossfire Development Team
- * Copyright (©) 1992,2007 Frank Tore Johansen
- *
+ *
+ * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 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
*/
#include
#include "global.h"
-#include "loader.h"
#include "path.h"
//+GPL
@@ -80,7 +79,7 @@
*/
if (OUT_OF_REAL_MAP (m, sx, sy))
{
- LOG (llevError, "blocked_link: Passed map, x, y coordinates outside of map\n");
+ LOG (llevError | logBacktrace, "blocked_link: Passed map, x, y coordinates outside of map\n");
return 1;
}
@@ -93,7 +92,7 @@
* go further. Not true for players - all sorts of special
* things we need to do for players.
*/
- if (ob->type != PLAYER && !(mflags & P_IS_ALIVE) && (blocked == 0))
+ if (ob->type != PLAYER && !(mflags & P_IS_ALIVE) && blocked == 0)
return 0;
/* if there isn't anything alive on this space, and this space isn't
@@ -113,7 +112,7 @@
* true. If we get through the entire stack, that must mean
* ob is blocking it, so return 0.
*/
- for (object *tmp = ms.bot; tmp; tmp = tmp->above)
+ for (object *tmp = ms.top; tmp; tmp = tmp->below)
{
if (OB_MOVE_BLOCK (ob, tmp))
{
@@ -147,13 +146,11 @@
} else {
// space does not block the ob, directly, but
// anything alive that is not a door still
- // blocks anything but wizards.
+ // blocks anything
if (tmp->flag [FLAG_ALIVE]
- && tmp->head_ () != ob
- && tmp != ob
&& tmp->type != DOOR
- && !tmp->flag [FLAG_WIZPASS])
+ && tmp->head_ () != ob) //TODO: maybe move these check up?
return 1;
}
}
@@ -162,7 +159,7 @@
}
/*
- * Returns qthe blocking object if the given object can't fit in the given
+ * Returns the blocking object if the given object can't fit in the given
* spot. This is meant for multi space objects - for single space objecs,
* just calling get_map_blocked and checking that against movement type
* of object. This function goes through all the parts of the multipart
@@ -219,33 +216,6 @@
return 0;
}
-/* When the map is loaded, load_object does not actually insert objects
- * into inventory, but just links them. What this does is go through
- * and insert them properly.
- * The object 'container' is the object that contains the inventory.
- * This is needed so that we can update the containers weight.
- */
-static void
-fix_container (object *container)
-{
- object *tmp = container->inv, *next;
-
- container->inv = 0;
- while (tmp)
- {
- next = tmp->below;
- if (tmp->inv)
- fix_container (tmp);
-
- insert_ob_in_ob (tmp, container);
- tmp = next;
- }
-
- // go through and calculate what all the containers are carrying.
- //TODO: remove
- container->update_weight ();
-}
-
//-GPL
void
@@ -272,6 +242,19 @@
INVOKE_OBJECT (RESET, tmp);
}
+void
+maptile::post_load ()
+{
+#if 0
+ if (!spaces)
+ return;
+
+ for (mapspace *ms = spaces + size (); ms-- > spaces; )
+ for (object *tmp = ms->bot; tmp; tmp = tmp->above)
+ ; // nop
+#endif
+}
+
//+GPL
/* link_multipart_objects go through all the objects on the map looking
@@ -330,7 +313,10 @@
{
// TODO: why?
if (op->inv)
- op->update_weight ();
+ {
+ op->carrying = 0;
+ op->update_weight ();
+ }
if (IN_RANGE_EXC (op->x, 0, width) && IN_RANGE_EXC (op->y, 0, height))
{
@@ -377,19 +363,29 @@
void
maptile::activate ()
{
- if (spaces)
- for (mapspace *ms = spaces + size (); ms-- > spaces; )
- for (object *op = ms->bot; op; op = op->above)
- op->activate_recursive ();
+ if (state != MAP_INACTIVE)
+ return;
+
+ for (mapspace *ms = spaces + size (); ms-- > spaces; )
+ for (object *op = ms->bot; op; op = op->above)
+ op->activate_recursive ();
+
+ state = MAP_ACTIVE;
+
+ activate_physics ();
}
void
maptile::deactivate ()
{
- if (spaces)
- for (mapspace *ms = spaces + size (); ms-- > spaces; )
- for (object *op = ms->bot; op; op = op->above)
- op->deactivate_recursive ();
+ if (state != MAP_ACTIVE)
+ return;
+
+ for (mapspace *ms = spaces + size (); ms-- > spaces; )
+ for (object *op = ms->bot; op; op = op->above)
+ op->deactivate_recursive ();
+
+ state = MAP_INACTIVE;
}
bool
@@ -440,30 +436,35 @@
return freezer.save (path);
}
-maptile::maptile ()
+void
+maptile::init ()
{
- in_memory = MAP_SWAPPED;
+ state = MAP_SWAPPED;
/* The maps used to pick up default x and y values from the
* map archetype. Mimic that behaviour.
*/
- width = 16;
- height = 16;
- timeout = 300;
- max_items = MAX_ITEM_PER_ACTION;
- max_volume = 2000000; // 2m³
+ width = 16;
+ height = 16;
+ timeout = 300;
+ max_items = MAX_ITEM_PER_ACTION;
+ max_volume = 2000000; // 2m³
+ reset_timeout = 0;
+ enter_x = 0;
+ enter_y = 0;
+}
+
+maptile::maptile ()
+{
+ init ();
}
maptile::maptile (int w, int h)
{
- in_memory = MAP_SWAPPED;
+ init ();
- width = w;
- height = h;
- reset_timeout = 0;
- timeout = 300;
- enter_x = 0;
- enter_y = 0;
+ width = w;
+ height = h;
alloc ();
}
@@ -544,7 +545,7 @@
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;
}
@@ -573,20 +574,26 @@
print_shop_string (maptile *m)
{
static dynbuf_text buf; buf.clear ();
+ bool first = true;
for (int i = 0; i < m->shopitems[0].index; i++)
{
+ if (!first)
+ buf << ';';
+
+ first = false;
+
if (m->shopitems[i].typenum)
{
if (m->shopitems[i].strength)
- buf.printf ("%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
+ buf.printf ("%s:%d", m->shopitems[i].name, m->shopitems[i].strength);
else
- buf.printf ("%s;", m->shopitems[i].name);
+ buf.printf ("%s", m->shopitems[i].name);
}
else
{
if (m->shopitems[i].strength)
- buf.printf ("*:%d;", m->shopitems[i].strength);
+ buf.printf ("*:%d", m->shopitems[i].strength);
else
buf.printf ("*");
}
@@ -619,7 +626,7 @@
thawer.get_ml (KW_endmsg, msg);
break;
- case KW_lore: // CF+ extension
+ case KW_lore: // deliantra extension
thawer.get_ml (KW_endlore, maplore);
break;
@@ -646,19 +653,13 @@
case KW_shopmax: thawer.get (shopmax); break;
case KW_shoprace: thawer.get (shoprace); break;
case KW_outdoor: thawer.get (outdoor); break;
- case KW_temp: thawer.get (temp); break;
- case KW_pressure: thawer.get (pressure); break;
- case KW_humid: thawer.get (humid); break;
- case KW_windspeed: thawer.get (windspeed); break;
- case KW_winddir: thawer.get (winddir); break;
- case KW_sky: thawer.get (sky); break;
case KW_per_player: thawer.get (per_player); break;
case KW_per_party: thawer.get (per_party); break;
case KW_no_reset: thawer.get (no_reset); break;
case KW_no_drop: thawer.get (no_drop); break;
- case KW_region: default_region = region::find (thawer.get_str ()); break;
+ case KW_region: thawer.get (default_region); break;
case KW_shopitems: shopitems = parse_shop_string (thawer.get_str ()); break;
// old names new names
@@ -672,10 +673,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_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);
@@ -686,7 +689,7 @@
return true;
default:
- if (!thawer.parse_error ("map", 0))
+ if (!thawer.parse_error ("map"))
return false;
break;
}
@@ -714,10 +717,10 @@
{
object *above = op->above;
- if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE))
+ if (op->flag [FLAG_IS_FLOOR] && op->flag [FLAG_UNIQUE])
unique = 1;
- if (op->head_ () == op && (QUERY_FLAG (op, FLAG_UNIQUE) || unique))
+ if (op->head_ () == op && (op->flag [FLAG_UNIQUE] || unique))
op->destroy ();
op = above;
@@ -730,10 +733,10 @@
bool
maptile::_save_header (object_freezer &freezer)
{
-#define MAP_OUT(k) freezer.put (KW_ ## k, k)
-#define MAP_OUT2(k,v) freezer.put (KW_ ## k, v)
+#define MAP_OUT(k) freezer.put (KW(k), k)
+#define MAP_OUT2(k,v) freezer.put (KW(k), v)
- MAP_OUT2 (arch, "map");
+ MAP_OUT2 (arch, CS(map));
if (name) MAP_OUT (name);
MAP_OUT (swap_time);
@@ -751,33 +754,28 @@
MAP_OUT (shopmax);
if (shoprace) MAP_OUT (shoprace);
- MAP_OUT (darkness);
MAP_OUT (width);
MAP_OUT (height);
MAP_OUT (enter_x);
MAP_OUT (enter_y);
-
- if (msg) freezer.put (KW_msg , KW_endmsg , msg);
- if (maplore) freezer.put (KW_maplore, KW_endmaplore, maplore);
-
+ MAP_OUT (darkness);
MAP_OUT (outdoor);
- MAP_OUT (temp);
- MAP_OUT (pressure);
- MAP_OUT (humid);
- MAP_OUT (windspeed);
- MAP_OUT (winddir);
- MAP_OUT (sky);
+
+ if (msg) freezer.put (KW(msg) , KW(endmsg) , msg);
+ if (maplore) freezer.put (KW(maplore), KW(endmaplore), maplore);
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 [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);
+ freezer.put (KW(end));
return true;
}
@@ -841,7 +839,7 @@
shoprace = 0;
delete [] shopitems, shopitems = 0;
- for (int i = 0; i < 4; i++)
+ for (int i = 0; i < array_length (tile_path); i++)
tile_path [i] = 0;
}
@@ -858,7 +856,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 < 4; i++)
+ for (int i = 0; i < array_length (tile_path); i++)
if (tile_map[i] == m)
tile_map[i] = 0;
}
@@ -872,6 +870,7 @@
}
/* decay and destroy perishable items in a map */
+// TODO: should be done regularly, not on map load?
void
maptile::do_decay_objects ()
{
@@ -883,17 +882,17 @@
{
above = op->above;
- bool destroy = 0;
-
// do not decay anything above unique floor tiles (yet :)
- if (QUERY_FLAG (op, FLAG_IS_FLOOR) && QUERY_FLAG (op, FLAG_UNIQUE))
+ if (op->flag [FLAG_IS_FLOOR] && op->flag [FLAG_UNIQUE])
break;
- if (QUERY_FLAG (op, FLAG_IS_FLOOR)
- || QUERY_FLAG (op, FLAG_OBJ_ORIGINAL)
- || QUERY_FLAG (op, FLAG_UNIQUE)
- || QUERY_FLAG (op, FLAG_OVERLAY_FLOOR)
- || QUERY_FLAG (op, FLAG_UNPAID)
+ bool destroy = 0;
+
+ if (op->flag [FLAG_IS_FLOOR]
+ || op->flag [FLAG_OBJ_ORIGINAL]
+ || op->flag [FLAG_UNIQUE]
+ || op->flag [FLAG_OVERLAY_FLOOR]
+ || op->flag [FLAG_UNPAID]
|| op->is_alive ())
; // do not decay
else if (op->is_weapon ())
@@ -928,7 +927,8 @@
|| (mat & M_GLASS && rndm (1, 2) == 1)
|| ((mat & M_STONE || mat & M_ADAMANT) && rndm (1, 10) == 1)
|| ((mat & M_SOFT_METAL || mat & M_BONE) && rndm (1, 3) == 1)
- || (mat & M_ICE && temp > 32))
+ //|| (mat & M_ICE && temp > 32)
+ )
destroy = 1;
}
@@ -958,13 +958,13 @@
for (mapspace *ms = spaces + size (); ms-- > spaces; )
for (object *op = ms->bot; op; op = op->above)
{
- if (QUERY_FLAG (op, FLAG_MONSTER))
+ if (op->flag [FLAG_MONSTER])
{
total_exp += op->stats.exp;
monster_cnt++;
}
- if (QUERY_FLAG (op, FLAG_GENERATOR))
+ if (op->flag [FLAG_GENERATOR])
{
total_exp += op->stats.exp;
@@ -1035,6 +1035,7 @@
uint64_t volume = 0;
uint32_t items = 0;
object *anywhere = 0;
+ uint8_t middle_visibility = 0;
//object *middle = 0;
//object *top = 0;
@@ -1061,38 +1062,39 @@
*/
if (expect_true (!tmp->invisible))
{
- if (tmp->type == PLAYER || tmp->flag [FLAG_MONSTER])
+ if (expect_false (tmp->type == PLAYER || tmp->flag [FLAG_MONSTER]))
top = tmp;
+ else if (expect_false (tmp->flag [FLAG_IS_FLOOR]))
+ {
+ /* If we got a floor, that means middle and top were below it,
+ * so should not be visible, so we clear them.
+ */
+ middle = 0;
+ top = 0;
+ floor = tmp;
+ volume = 0;
+ items = 0;
+ }
else
{
- if (expect_false (tmp->flag [FLAG_IS_FLOOR]))
+ if (expect_true (!tmp->flag [FLAG_NO_PICK]))
{
- /* If we got a floor, that means middle and top were below it,
- * so should not be visible, so we clear them.
- */
- middle = 0;
- top = 0;
- floor = tmp;
- volume = 0;
- items = 0;
+ ++items;
+ volume += tmp->volume ();
}
- else
+
+ /* Flag anywhere have high priority */
+ if (expect_false (tmp->flag [FLAG_SEE_ANYWHERE]))
+ anywhere = tmp;
+
+ /* Find the highest visible face around. If equal
+ * visibilities, we still want the one nearer to the
+ * top
+ */
+ if (expect_false (::faces [tmp->face].visibility >= middle_visibility))
{
- if (expect_true (!tmp->flag [FLAG_NO_PICK]))
- {
- ++items;
- volume += tmp->volume ();
- }
-
- /* Flag anywhere have high priority */
- if (expect_false (tmp->flag [FLAG_SEE_ANYWHERE]))
- anywhere = tmp;
- /* Find the highest visible face around. If equal
- * visibilities, we still want the one nearer to the
- * top
- */
- else if (!middle || (::faces [tmp->face].visibility > ::faces [middle->face].visibility))
- middle = tmp;
+ middle_visibility = ::faces [tmp->face].visibility;
+ middle = tmp;
}
}
}
@@ -1154,7 +1156,7 @@
for (object *tmp = last; tmp; tmp = tmp->below)
{
/* Once we get to a floor, stop, since we already have a floor object */
- if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
+ if (tmp->flag [FLAG_IS_FLOOR])
break;
/* If two top faces are already set, quit processing */
@@ -1195,6 +1197,29 @@
if (top == middle)
middle = 0;
+ // 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])
+ {
+ mapspace &ms = m->at (floor->x, floor->y);
+ ms.update ();
+
+ if (object *floor2 = ms.faces_obj [2])
+ if (!floor2->flag [FLAG_IS_TRANSPARENT_FLOOR])
+ {
+ floor->set_anim_frame (1);
+ top = floor;
+ middle = ms.faces_obj [0];
+ floor = floor2;
+ }
+
+ ms.pflags |= PF_VIS_UP;
+ }
+ }
+
#if 0
faces_obj [0] = top;
faces_obj [1] = middle;
@@ -1202,16 +1227,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])
- {
- if (tile_map[dir] && (!load || tile_map[dir]->in_memory == MAP_ACTIVE))
- 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
+ // 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;
+ }
+
- if ((tile_map[dir] = find_async (tile_path[dir], this, load)))
- return tile_map[dir];
+ return tile_map [dir] = m;
+ }
}
return 0;
@@ -1237,34 +1309,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
@@ -1286,38 +1358,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
@@ -1331,7 +1403,7 @@
* map1 to map2 in dx/dy.
*/
int
-adjacent_map (const maptile *map1, const maptile *map2, int *dx, int *dy)
+adjacent_map (maptile *map1, maptile *map2, int *dx, int *dy)
{
if (!map1 || !map2)
return 0;
@@ -1343,65 +1415,65 @@
*dx = 0;
*dy = 0;
}
- else if (map1->tile_map[0] == map2)
- { /* up */
+ else if (map1->tile_available (TILE_NORTH, false) == map2)
+ {
*dx = 0;
*dy = -map2->height;
}
- else if (map1->tile_map[1] == map2)
- { /* right */
+ else if (map1->tile_available (TILE_EAST , false) == map2)
+ {
*dx = map1->width;
*dy = 0;
}
- else if (map1->tile_map[2] == map2)
- { /* down */
+ else if (map1->tile_available (TILE_SOUTH, false) == map2)
+ {
*dx = 0;
*dy = map1->height;
}
- else if (map1->tile_map[3] == map2)
- { /* left */
+ else if (map1->tile_available (TILE_WEST , false) == map2)
+ {
*dx = -map2->width;
*dy = 0;
}
- else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2)
+ else if (map1->tile_map[TILE_NORTH] && map1->tile_map[TILE_NORTH]->tile_available (TILE_EAST , false) == map2)
{ /* up right */
- *dx = map1->tile_map[0]->width;
- *dy = -map1->tile_map[0]->height;
+ *dx = +map1->tile_map[TILE_NORTH]->width;
+ *dy = -map1->tile_map[TILE_NORTH]->height;
}
- else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2)
+ else if (map1->tile_map[TILE_NORTH] && map1->tile_map[TILE_NORTH]->tile_available (TILE_WEST , false) == map2)
{ /* up left */
*dx = -map2->width;
- *dy = -map1->tile_map[0]->height;
+ *dy = -map1->tile_map[TILE_NORTH]->height;
}
- else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2)
+ else if (map1->tile_map[TILE_EAST ] && map1->tile_map[TILE_EAST ]->tile_available (TILE_NORTH, false) == map2)
{ /* right up */
- *dx = map1->width;
+ *dx = +map1->width;
*dy = -map2->height;
}
- else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2)
+ else if (map1->tile_map[TILE_EAST ] && map1->tile_map[TILE_EAST ]->tile_available (TILE_SOUTH, false) == map2)
{ /* right down */
- *dx = map1->width;
- *dy = map1->tile_map[1]->height;
+ *dx = +map1->width;
+ *dy = +map1->tile_map[TILE_EAST]->height;
}
- else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2)
+ else if (map1->tile_map[TILE_SOUTH] && map1->tile_map[TILE_SOUTH]->tile_available (TILE_EAST , false) == map2)
{ /* down right */
- *dx = map1->tile_map[2]->width;
- *dy = map1->height;
+ *dx = +map1->tile_map[TILE_SOUTH]->width;
+ *dy = +map1->height;
}
- else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2)
+ else if (map1->tile_map[TILE_SOUTH] && map1->tile_map[TILE_SOUTH]->tile_available (TILE_WEST , false) == map2)
{ /* down left */
*dx = -map2->width;
- *dy = map1->height;
+ *dy = +map1->height;
}
- else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2)
+ else if (map1->tile_map[TILE_WEST ] && map1->tile_map[TILE_WEST ]->tile_available (TILE_NORTH, false) == map2)
{ /* left up */
- *dx = -map1->tile_map[3]->width;
+ *dx = -map1->tile_map[TILE_WEST]->width;
*dy = -map2->height;
}
- else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2)
+ else if (map1->tile_map[TILE_WEST ] && map1->tile_map[TILE_WEST ]->tile_available (TILE_SOUTH, false) == map2)
{ /* left down */
- *dx = -map1->tile_map[3]->width;
- *dy = map1->tile_map[3]->height;
+ *dx = -map1->tile_map[TILE_WEST]->width;
+ *dy = +map1->tile_map[TILE_WEST]->height;
}
else
return 0;
@@ -1434,7 +1506,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
@@ -1447,29 +1519,28 @@
* closest body part of 'op1'
*/
void
-get_rangevector (object *op1, object *op2, rv_vector * retval, int flags)
+get_rangevector (object *op1, object *op2, rv_vector *retval, int flags)
{
if (!adjacent_map (op1->map, op2->map, &retval->distance_x, &retval->distance_y))
{
/* be conservative and fill in _some_ data */
- retval->distance = 10000;
+ retval->distance = 10000;
retval->distance_x = 10000;
retval->distance_y = 10000;
- retval->direction = 0;
- retval->part = 0;
+ retval->direction = 0;
+ retval->part = 0;
}
else
{
- object *best;
-
retval->distance_x += op2->x - op1->x;
retval->distance_y += op2->y - op1->y;
- best = op1;
+ object *best = op1;
+
/* If this is multipart, find the closest part now */
- if (!(flags & 0x1) && op1->more)
+ if (!(flags & 1) && op1->more)
{
- int best_distance = retval->distance_x * retval->distance_x + retval->distance_y * retval->distance_y, tmpi;
+ int best_distance = idistance (retval->distance_x, retval->distance_y);
/* we just take the offset of the piece to head to figure
* distance instead of doing all that work above again
@@ -1479,12 +1550,12 @@
*/
for (object *tmp = op1->more; tmp; tmp = tmp->more)
{
- tmpi = (op1->x - tmp->x + retval->distance_x) * (op1->x - tmp->x + retval->distance_x) +
- (op1->y - tmp->y + retval->distance_y) * (op1->y - tmp->y + retval->distance_y);
+ int tmpi = idistance (op1->x - tmp->x + retval->distance_x, op1->y - tmp->y + retval->distance_y);
+
if (tmpi < best_distance)
{
best_distance = tmpi;
- best = tmp;
+ best = tmp;
}
}
@@ -1495,9 +1566,9 @@
}
}
- retval->part = best;
- retval->distance = upos_max (abs (retval->distance_x), abs (retval->distance_y));
- retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
+ retval->part = best;
+ retval->distance = upos_max (abs (retval->distance_x), abs (retval->distance_y));
+ retval->direction = find_dir_2 (retval->distance_x, retval->distance_y);
}
}
@@ -1512,25 +1583,25 @@
* field of the rv_vector is set to NULL.
*/
void
-get_rangevector_from_mapcoord (const maptile *m, int x, int y, const object *op2, rv_vector *retval, int flags)
+get_rangevector_from_mapcoord (maptile *m, int x, int y, const object *op2, rv_vector *retval, int flags)
{
if (!adjacent_map (m, op2->map, &retval->distance_x, &retval->distance_y))
{
/* be conservative and fill in _some_ data */
- retval->distance = 100000;
+ retval->distance = 100000;
retval->distance_x = 32767;
retval->distance_y = 32767;
- retval->direction = 0;
- retval->part = 0;
+ retval->direction = 0;
+ retval->part = 0;
}
else
{
retval->distance_x += op2->x - x;
retval->distance_y += op2->y - y;
- retval->part = 0;
- retval->distance = upos_max (abs (retval->distance_x), abs (retval->distance_y));
- retval->direction = find_dir_2 (-retval->distance_x, -retval->distance_y);
+ retval->part = 0;
+ retval->distance = upos_max (abs (retval->distance_x), abs (retval->distance_y));
+ retval->direction = find_dir_2 (retval->distance_x, retval->distance_y);
}
}
@@ -1590,9 +1661,9 @@
{
object *pick = at (gen (width), gen (height)).bot;
- // do not prefer big monsters just because they are big.
+ // must be head: do not prefer big monsters just because they are big.
if (pick && pick->is_head ())
- return pick->head_ ();
+ return pick;
}
// instead of crashing in the unlikely(?) case, try to return *something*
@@ -1636,13 +1707,15 @@
}
}
+dynbuf mapwalk_buf (sizeof (maprect) * 25, sizeof (maprect) * 25);
+
static void
split_to_tiles (dynbuf &buf, maptile *m, int x0, int y0, int x1, int y1, int dx, int dy)
{
// clip to map to the left
if (x0 < 0)
{
- if (maptile *tile = m->tile_available (TILE_LEFT, 1))
+ if (maptile *tile = m->tile_available (TILE_WEST, 1))
split_to_tiles (buf, tile, x0 + tile->width, y0, min (x1 + tile->width, tile->width), y1, dx - tile->width, dy);
if (x1 < 0) // entirely to the left
@@ -1654,34 +1727,34 @@
// clip to map to the right
if (x1 > m->width)
{
- if (maptile *tile = m->tile_available (TILE_RIGHT, 1))
+ 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_UP, 1))
+ 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_DOWN, 1))
+ 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;
@@ -1700,9 +1773,8 @@
}
maprect *
-maptile::split_to_tiles (int x0, int y0, int x1, int y1)
+maptile::split_to_tiles (dynbuf &buf, int x0, int y0, int x1, int y1)
{
- static dynbuf buf (sizeof (maprect) * 8, sizeof (maprect) * 8);
buf.clear ();
::split_to_tiles (buf, this, x0, y0, x1, y1, 0, 0);