[Scummvm-git-logs] scummvm master -> 2620f50339eeb7bd326ac28bc4676a86b089abac
OMGPizzaGuy
noreply at scummvm.org
Wed Oct 11 00:55:56 UTC 2023
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
2620f50339 ULTIMA8: Refactor valid position checking
Commit: 2620f50339eeb7bd326ac28bc4676a86b089abac
https://github.com/scummvm/scummvm/commit/2620f50339eeb7bd326ac28bc4676a86b089abac
Author: Matthew Jimenez (matthew.jimenez at outlook.com)
Date: 2023-10-10T19:55:34-05:00
Commit Message:
ULTIMA8: Refactor valid position checking
Changed paths:
A engines/ultima/ultima8/world/position_info.h
engines/ultima/ultima8/gumps/game_map_gump.cpp
engines/ultima/ultima8/world/actors/actor.cpp
engines/ultima/ultima8/world/actors/animation_tracker.cpp
engines/ultima/ultima8/world/actors/quick_avatar_mover_process.cpp
engines/ultima/ultima8/world/actors/rolling_thunder_process.cpp
engines/ultima/ultima8/world/camera_process.cpp
engines/ultima/ultima8/world/current_map.cpp
engines/ultima/ultima8/world/current_map.h
engines/ultima/ultima8/world/item.cpp
diff --git a/engines/ultima/ultima8/gumps/game_map_gump.cpp b/engines/ultima/ultima8/gumps/game_map_gump.cpp
index 648f4ca57b2..53a0a297c89 100644
--- a/engines/ultima/ultima8/gumps/game_map_gump.cpp
+++ b/engines/ultima/ultima8/gumps/game_map_gump.cpp
@@ -91,18 +91,19 @@ void GameMapGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool scaled)
uint16 roofid = 0;
int zlimit = 1 << 16; // should be high enough
+ const Item *roof = nullptr;
if (!camera) {
// Check roof
//!! This is _not_ the right place for this...
- int32 ax, ay, az, axd, ayd, azd;
const Actor *av = getMainActor();
- av->getLocation(ax, ay, az);
- av->getFootpadWorld(axd, ayd, azd);
- map->isValidPosition(ax, ay, az, 32, 32, 8, 0, 1, 0, &roofid);
- } else
+ Box b = av->getWorldBox();
+ PositionInfo info = map->getPositionInfo(b, b, 0, 1);
+ roof = info.roof;
+ } else {
roofid = camera->findRoof(lerp_factor);
+ roof = getItem(roofid);
+ }
- const Item *roof = getItem(roofid);
if (roof) {
zlimit = roof->getZ();
}
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index a904a4ab8bd..88382241cf4 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -1444,7 +1444,7 @@ ProcId Actor::dieCru(uint16 damageType, uint16 damagePts, Direction srcDir) {
moveToEtherealVoid();
CurrentMap *cm = world->getCurrentMap();
/* 0x576 - flaming guy running around */
- bool can_create_koresh = cm->isValidPosition(_x, _y, _z, 0x576, _objId);
+ bool can_create_koresh = cm->getPositionInfo(_x, _y, _z, 0x576, _objId).valid;
returnFromEtherealVoid();
if (can_create_koresh) {
diff --git a/engines/ultima/ultima8/world/actors/animation_tracker.cpp b/engines/ultima/ultima8/world/actors/animation_tracker.cpp
index 405a57edbb9..b9d0e7fe724 100644
--- a/engines/ultima/ultima8/world/actors/animation_tracker.cpp
+++ b/engines/ultima/ultima8/world/actors/animation_tracker.cpp
@@ -307,16 +307,13 @@ bool AnimationTracker::step() {
// If it succeeded, we proceed as usual
}
- const Item *support;
- bool targetok = cm->isValidPosition(tx, ty, tz,
- _startX, _startY, _startZ,
- xd, yd, zd,
- a->getShapeInfo()->_flags,
- _actor, &support, 0);
-
- if (is_u8 && targetok && support) {
+ Box target(tx, ty, tz, xd, yd, zd);
+ Box start(_startX, _startY, _startZ, xd, yd, zd);
+ PositionInfo info = cm->getPositionInfo(target, start, a->getShapeInfo()->_flags, _actor);
+
+ if (is_u8 && info.valid && info.supported) {
// Might need to check for bridge traversal adjustments
- uint32 supportshape = support->getShape();
+ uint32 supportshape = info.floor->getShape();
if (supportshape >= 675 && supportshape <= 681) {
// Could be a sloping portion of a bridge. For a bridge along the
// X axis, positive descent delta is a positive change in Y when
@@ -331,13 +328,13 @@ bool AnimationTracker::step() {
descentdelta = -20; // Descend
if (descentdelta) {
- if (dy == 0 && dx != 0 && !support->hasFlags(Item::FLG_FLIPPED)) {
+ if (dy == 0 && dx != 0 && !info.floor->hasFlags(Item::FLG_FLIPPED)) {
// Moving left or right on horizontal bridge
// descentdelta = 60*dy/dx
// 60*dy = descentdelta * dx
// dy = descentdelta * dx / 60;
ty += descentdelta * dx / 60;
- } else if (dx == 0 && dy != 0 && support->hasFlags(Item::FLG_FLIPPED)) {
+ } else if (dx == 0 && dy != 0 && info.floor->hasFlags(Item::FLG_FLIPPED)) {
// Moving up or down on vertical bridge
tx += descentdelta * dy / 60;
}
@@ -345,14 +342,14 @@ bool AnimationTracker::step() {
}
}
- if (!targetok || (f.is_onground() && !support)) {
+ if (!info.valid || (f.is_onground() && !info.supported)) {
// If on ground, try to adjust properly. Never do it for dead Crusader NPCs,
// as they don't get gravity and the death process gets stuck.
// TODO: Profile the effect of disabling this for pathfinding.
// It shouldn't be necessary in that case, and may provide a
// worthwhile speed-up.
if (f.is_onground() && zd > 8 && !(is_crusader && a->isDead())) {
- targetok = cm->scanForValidPosition(tx, ty, tz, a, _dir,
+ bool targetok = cm->scanForValidPosition(tx, ty, tz, a, _dir,
true, tx, ty, tz);
if (!targetok) {
@@ -367,7 +364,7 @@ bool AnimationTracker::step() {
#endif
}
} else {
- if (!targetok) {
+ if (!info.valid) {
_blocked = true;
return false;
}
@@ -394,14 +391,10 @@ bool AnimationTracker::step() {
if (f.is_onground()) {
// needs support
+ target = Box(tx, ty, tz, xd, yd, zd);
+ info = cm->getPositionInfo(target, start, a->getShapeInfo()->_flags, _actor);
- /*bool targetok = */ cm->isValidPosition(tx, ty, tz,
- _startX, _startY, _startZ,
- xd, yd, zd,
- a->getShapeInfo()->_flags,
- _actor, &support, 0);
-
- if (!support) {
+ if (!info.supported) {
_unsupported = true;
return false;
}
diff --git a/engines/ultima/ultima8/world/actors/quick_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/quick_avatar_mover_process.cpp
index 929fb14b412..25408aac61a 100644
--- a/engines/ultima/ultima8/world/actors/quick_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/quick_avatar_mover_process.cpp
@@ -99,53 +99,62 @@ void QuickAvatarMoverProcess::run() {
int32 dyv = dy;
int32 dzv = dz;
- for (int j = 0; j < 3; j++) {
- dxv = dx;
- dyv = dy;
- dzv = dz;
-
- if (j == 1) dxv = 0;
- else if (j == 2) dyv = 0;
-
- if (_quarter) {
- dxv /= 4;
- dyv /= 4;
- dzv /= 4;
- }
+ if (_clipping) {
+ for (int j = 0; j < 3; j++) {
+ dxv = dx;
+ dyv = dy;
+ dzv = dz;
+
+ if (j == 1)
+ dxv = 0;
+ else if (j == 2)
+ dyv = 0;
+
+ if (_quarter) {
+ dxv /= 4;
+ dyv /= 4;
+ dzv /= 4;
+ }
- bool ok = false;
-
- while (dxv || dyv || dzv) {
- uint32 shapeFlags = avatar->getShapeInfo()->_flags;
-
- if (!_clipping || cm->isValidPosition(x + dxv, y + dyv, z + dzv, ixd, iyd, izd, _flags, 1, 0, 0)) {
- if (_clipping && !dzv) {
- if (cm->isValidPosition(x + dxv, y + dyv, z - 8, ixd, iyd, izd, _flags, 1, 0, 0) &&
- !cm->isValidPosition(x, y, z - 8, ixd, iyd, izd, _flags, 1, 0, 0)) {
- dzv = -8;
- } else if (cm->isValidPosition(x + dxv, y + dyv, z - 16, ixd, iyd, izd, _flags, 1, 0, 0) &&
- !cm->isValidPosition(x, y, z - 16, ixd, iyd, izd, _flags, 1, 0, 0)) {
- dzv = -16;
- } else if (cm->isValidPosition(x + dxv, y + dyv, z - 24, ixd, iyd, izd, _flags, 1, 0, 0) &&
- !cm->isValidPosition(x, y, z - 24, ixd, iyd, izd, _flags, 1, 0, 0)) {
- dzv = -24;
- } else if (cm->isValidPosition(x + dxv, y + dyv, z - 32, ixd, iyd, izd, _flags, 1, 0, 0) &&
- !cm->isValidPosition(x, y, z - 32, ixd, iyd, izd, _flags, 1, 0, 0)) {
- dzv = -32;
+ bool ok = false;
+
+ while (dxv || dyv || dzv) {
+ uint32 shapeFlags = avatar->getShapeInfo()->_flags;
+
+ Box start(x, y, z, ixd, iyd, izd);
+ PositionInfo info = cm->getPositionInfo(Box(x + dxv, y + dyv, z + dzv, ixd, iyd, izd), start, shapeFlags, 1);
+ if (info.valid) {
+ if (!dzv && !info.supported) {
+ // Adjust to stay on ground
+ if (cm->getPositionInfo(Box(x + dxv, y + dyv, z - 8, ixd, iyd, izd), start, shapeFlags, 1).valid &&
+ !cm->getPositionInfo(Box(x, y, z - 8, ixd, iyd, izd), start, shapeFlags, 1).valid) {
+ dzv = -8;
+ } else if (cm->getPositionInfo(Box(x + dxv, y + dyv, z - 16, ixd, iyd, izd), start, shapeFlags, 1).valid &&
+ !cm->getPositionInfo(Box(x, y, z - 16, ixd, iyd, izd), start, shapeFlags, 1).valid) {
+ dzv = -16;
+ } else if (cm->getPositionInfo(Box(x + dxv, y + dyv, z - 24, ixd, iyd, izd), start, shapeFlags, 1).valid &&
+ !cm->getPositionInfo(Box(x, y, z - 24, ixd, iyd, izd), start, shapeFlags, 1).valid) {
+ dzv = -24;
+ } else if (cm->getPositionInfo(Box(x + dxv, y + dyv, z - 32, ixd, iyd, izd), start, shapeFlags, 1).valid &&
+ !cm->getPositionInfo(Box(x, y, z - 32, ixd, iyd, izd), start, shapeFlags, 1).valid) {
+ dzv = -32;
+ }
}
+ ok = true;
+ break;
+ } else if (cm->getPositionInfo(Box(x + dxv, y + dyv, z + dzv + 8, ixd, iyd, izd), start, shapeFlags, 1).valid) {
+ dzv += 8;
+ ok = true;
+ break;
}
- ok = true;
- break;
- } else if (cm->isValidPosition(x + dxv, y + dyv, z + dzv + 8, ixd, iyd, izd, shapeFlags, 1, 0, 0)) {
- dzv += 8;
- ok = true;
- break;
+ dxv /= 2;
+ dyv /= 2;
+ dzv /= 2;
}
- dxv /= 2;
- dyv /= 2;
- dzv /= 2;
+
+ if (ok)
+ break;
}
- if (ok) break;
}
// Yes, i know, not entirely correct
diff --git a/engines/ultima/ultima8/world/actors/rolling_thunder_process.cpp b/engines/ultima/ultima8/world/actors/rolling_thunder_process.cpp
index 0ef8ab0fd2b..811e8d08e91 100644
--- a/engines/ultima/ultima8/world/actors/rolling_thunder_process.cpp
+++ b/engines/ultima/ultima8/world/actors/rolling_thunder_process.cpp
@@ -260,11 +260,9 @@ bool RollingThunderProcess::fireDistance(Direction dir, int32 x, int32 y, int32
int32 cy = y + (i == 0 ? yoff : yoff2);
int32 cz = z + (i == 0 ? zoff : zoff2);
- const Item *blocker = nullptr;
- bool valid = cm->isValidPosition(cx, cy, cz, BULLET_SPLASH_SHAPE,
- _itemNum, nullptr, nullptr, &blocker);
- if (!valid) {
- if (blocker->getObjId() == target->getObjId())
+ PositionInfo info = cm->getPositionInfo(cx, cy, cz, BULLET_SPLASH_SHAPE, _itemNum);
+ if (!info.valid && info.blocker) {
+ if (info.blocker->getObjId() == target->getObjId())
dist = MAX(abs(x - tx), abs(y - ty));
} else {
int32 ocx, ocy, ocz;
diff --git a/engines/ultima/ultima8/world/camera_process.cpp b/engines/ultima/ultima8/world/camera_process.cpp
index e4610db2cdb..38f45ae51a7 100644
--- a/engines/ultima/ultima8/world/camera_process.cpp
+++ b/engines/ultima/ultima8/world/camera_process.cpp
@@ -289,9 +289,10 @@ uint16 CameraProcess::findRoof(int32 factor) {
int32 dx, dy, dz;
avatar->getFootpadWorld(dx, dy, dz);
- uint16 roofid;
- World::get_instance()->getCurrentMap()->isValidPosition(x, y, z - 10, dx / 2, dy / 2, dz / 2, 0, 1, 0, &roofid);
- return roofid;
+
+ Box target(x, y, z - 10, dx / 2, dy / 2, dz / 2);
+ PositionInfo info = World::get_instance()->getCurrentMap()->getPositionInfo(target, target, 0, 1);
+ return info.roof ? info.roof->getObjId() : 0;
}
void CameraProcess::saveData(Common::WriteStream *ws) {
diff --git a/engines/ultima/ultima8/world/current_map.cpp b/engines/ultima/ultima8/world/current_map.cpp
index afe2aae44e6..590d3a05396 100644
--- a/engines/ultima/ultima8/world/current_map.cpp
+++ b/engines/ultima/ultima8/world/current_map.cpp
@@ -35,6 +35,7 @@
#include "ultima/ultima8/games/game_data.h"
#include "ultima/ultima8/graphics/main_shape_archive.h"
#include "ultima/ultima8/gumps/game_map_gump.h"
+#include "ultima/ultima8/misc/box.h"
#include "ultima/ultima8/misc/direction_util.h"
#include "ultima/ultima8/world/get_object.h"
@@ -47,8 +48,6 @@ namespace Ultima8 {
typedef Std::list<Item *> item_list;
-static const int INT_MAX_VALUE = 0x7fffffff;
-
CurrentMap::CurrentMap() : _currentMap(0), _eggHatcher(0),
_fastXMin(-1), _fastYMin(-1), _fastXMax(-1), _fastYMax(-1) {
for (unsigned int i = 0; i < MAP_NUM_CHUNKS; i++) {
@@ -726,55 +725,30 @@ const Std::list<Item *> *CurrentMap::getItemList(int32 gx, int32 gy) const {
return &_items[gx][gy];
}
-
-bool CurrentMap::isValidPosition(int32 x, int32 y, int32 z,
- uint32 shape,
- ObjId item, const Item **support,
- ObjId *roof, const Item **blocker) const {
- const ShapeInfo *si = GameData::get_instance()->
- getMainShapes()->getShapeInfo(shape);
+PositionInfo CurrentMap::getPositionInfo(int32 x, int32 y, int32 z, uint32 shape, ObjId id) const {
+ const ShapeInfo *si = GameData::get_instance()->getMainShapes()->getShapeInfo(shape);
int32 xd, yd, zd;
// Note: this assumes the shape to be placed is not flipped
si->getFootpadWorld(xd, yd, zd, 0);
+ Box target(x, y, z, xd, yd, zd);
+ Box empty;
- return isValidPosition(x, y, z,
- INT_MAX_VALUE / 2, INT_MAX_VALUE / 2, INT_MAX_VALUE / 2,
- xd, yd, zd,
- si->_flags, item, support, roof, blocker);
+ return getPositionInfo(target, empty, si->_flags, id);
}
-bool CurrentMap::isValidPosition(int32 x, int32 y, int32 z,
- int xd, int yd, int zd,
- uint32 shapeflags,
- ObjId item, const Item **support,
- ObjId *roof, const Item **blocker) const {
- return isValidPosition(x, y, z,
- INT_MAX_VALUE / 2, INT_MAX_VALUE / 2, INT_MAX_VALUE / 2,
- xd, yd, zd,
- shapeflags, item, support, roof, blocker);
-}
-
-
-bool CurrentMap::isValidPosition(int32 x, int32 y, int32 z,
- int32 startx, int32 starty, int32 startz,
- int xd, int yd, int zd,
- uint32 shapeflags,
- ObjId item_, const Item **support_,
- ObjId *roof_, const Item **blocker_) const {
+PositionInfo CurrentMap::getPositionInfo(const Box &target, const Box &start, uint32 shapeflags, ObjId id) const {
+ PositionInfo info;
static const uint32 flagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING |
ShapeInfo::SI_ROOF);
static const uint32 blockflagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING);
- bool valid = true;
- const Item *support = nullptr;
- const Item *blocker = nullptr;
- ObjId roof = 0;
- int32 roofz = INT_MAX_VALUE;
+ int32 floorz = INT32_MIN;
+ int32 roofz = INT32_MAX;
- int minx = ((x - xd) / _mapChunkSize) - 1;
- int maxx = (x / _mapChunkSize) + 1;
- int miny = ((y - yd) / _mapChunkSize) - 1;
- int maxy = (y / _mapChunkSize) + 1;
+ int minx = ((target._x - target._xd) / _mapChunkSize) - 1;
+ int maxx = (target._x / _mapChunkSize) + 1;
+ int miny = ((target._y - target._yd) / _mapChunkSize) - 1;
+ int maxy = (target._y / _mapChunkSize) + 1;
clipMapChunks(minx, maxx, miny, maxy);
for (int cx = minx; cx <= maxx; cx++) {
@@ -783,7 +757,7 @@ bool CurrentMap::isValidPosition(int32 x, int32 y, int32 z,
for (iter = _items[cx][cy].begin();
iter != _items[cx][cy].end(); ++iter) {
const Item *item = *iter;
- if (item->getObjId() == item_)
+ if (item->getObjId() == id)
continue;
if (item->hasExtFlags(Item::EXT_SPRITE))
continue;
@@ -793,65 +767,42 @@ bool CurrentMap::isValidPosition(int32 x, int32 y, int32 z,
if (!(si->_flags & flagmask))
continue; // not an interesting item
- int32 ix, iy, iz, ixd, iyd, izd;
- item->getFootpadWorld(ixd, iyd, izd);
- item->getLocation(ix, iy, iz);
-
-#if 0
- if (item->getShape() == 145) {
- debugC(kDebugObject, "Shape 145: (%d, %d, %d)-(%d, %d, %d) %s",
- ix - ixd, iy - iyd, iz, ix, iy, iz + izd,
- si->is_solid() ? "solid" : "not solid");
- }
-#endif
+ Box ib = item->getWorldBox();
// check overlap
if ((si->_flags & shapeflags & blockflagmask) &&
- /* not non-overlapping */
- !(x <= ix - ixd || x - xd >= ix ||
- y <= iy - iyd || y - yd >= iy ||
- z + zd <= iz || z >= iz + izd) &&
- /* non-overlapping start position */
- (startx <= ix - ixd || startx - xd >= ix ||
- starty <= iy - iyd || starty - yd >= iy ||
- startz + zd <= iz || startz >= iz + izd)) {
+ target.overlaps(ib) && !start.overlaps(ib)) {
// overlapping an item. Invalid position
#if 0
debugC(kDebugObject, "%s", item->dumpInfo().c_str());
#endif
- if (blocker == nullptr) {
- blocker = item;
+ if (info.blocker == nullptr) {
+ info.blocker = item;
}
- valid = false;
}
// check xy overlap
- if (!(x <= ix - ixd || x - xd >= ix ||
- y <= iy - iyd || y - yd >= iy)) {
- // check support
- if (support == nullptr && si->is_solid() &&
- iz + izd == z) {
- support = item;
+ if (target._x > ib._x - ib._xd && target._x - target._xd < ib._x &&
+ target._y > ib._y - ib._yd && target._y - target._yd < ib._y) {
+ // check floor
+ if (si->is_solid() && ib._z + ib._zd > floorz && ib._z + ib._zd <= target._z) {
+ info.floor = item;
+ floorz = ib._z + ib._zd;
}
// check roof
- if (si->is_roof() && iz < roofz && iz >= z + zd) {
- roof = item->getObjId();
- roofz = iz;
+ if (si->is_roof() && ib._z < roofz && ib._z >= target._z + target._zd) {
+ info.roof = item;
+ roofz = ib._z;
}
}
}
}
}
- if (support_)
- *support_ = support;
- if (blocker_)
- *blocker_ = blocker;
- if (roof_)
- *roof_ = roof;
-
- return valid;
+ info.valid = info.blocker == nullptr;
+ info.supported = floorz == target._z;
+ return info;
}
bool CurrentMap::scanForValidPosition(int32 x, int32 y, int32 z, const Item *item,
@@ -1322,9 +1273,9 @@ uint32 CurrentMap::I_canExistAt(const uint8 *args, unsigned int argsize) {
//
const CurrentMap *cm = World::get_instance()->getCurrentMap();
- bool valid = cm->isValidPosition(x, y, z, shape, 0, 0, 0);
+ PositionInfo info = cm->getPositionInfo(x, y, z, shape, 0);
- if (valid)
+ if (info.valid)
return 1;
else
return 0;
@@ -1350,9 +1301,9 @@ uint32 CurrentMap::I_canExistAtPoint(const uint8 *args, unsigned int /*argsize*/
World_FromUsecodeXY(x, y);
const CurrentMap *cm = World::get_instance()->getCurrentMap();
- bool valid = cm->isValidPosition(x, y, z, shape, 0, 0, 0);
+ PositionInfo info = cm->getPositionInfo(x, y, z, shape, 0);
- if (valid)
+ if (info.valid)
return 1;
else
return 0;
diff --git a/engines/ultima/ultima8/world/current_map.h b/engines/ultima/ultima8/world/current_map.h
index a202bafe703..b0e5bea0baa 100644
--- a/engines/ultima/ultima8/world/current_map.h
+++ b/engines/ultima/ultima8/world/current_map.h
@@ -24,11 +24,13 @@
#include "ultima/shared/std/containers.h"
#include "ultima/ultima8/usecode/intrinsics.h"
+#include "ultima/ultima8/world/position_info.h"
#include "ultima/ultima8/misc/direction.h"
namespace Ultima {
namespace Ultima8 {
+struct Box;
class Map;
class Item;
class UCList;
@@ -105,35 +107,13 @@ public:
int32 origin[3], int32 dims[2],
bool above, bool below, bool recurse = false) const;
- // Collision detection. Returns true if the box [x,y,z]-[x-xd,y-yd,z+zd]
- // does not collide with any solid items.
- // Additionally:
- // * If support is not NULL, *support is set to the item supporting
- // the given box, or 0 if it isn't supported.
- // * If roof is not NULL, *roof is set to the roof item with the lowest
- // z coordinate that's over the box, or 0 if there is no roof above box.
- // * If blocker is not NULL, *blocker will be set to an item blocking
- // the whole box if there is one, or 0 if there is no such item.
- // Ignores collisions which were already occurring at the start position.
- // NB: isValidPosition doesn't consider item 'item'.
- bool isValidPosition(int32 x, int32 y, int32 z,
- int32 startx, int32 starty, int32 startz,
- int xd, int yd, int zd, uint32 shapeflags,
- ObjId item, const Item **support = 0,
- ObjId *roof = 0, const Item **blocker = 0) const;
-
- // Note that this version of isValidPosition does not look for start
- // position collisions.
- bool isValidPosition(int32 x, int32 y, int32 z,
- int xd, int yd, int zd, uint32 shapeflags,
- ObjId item, const Item **support = 0,
- ObjId *roof = 0, const Item **blocker = 0) const;
-
- // Note that this version of isValidPosition can not take 'flipped'
- // into account!
- bool isValidPosition(int32 x, int32 y, int32 z, uint32 shape,
- ObjId item, const Item **support = 0,
- ObjId *roof = 0, const Item **blocker = 0) const;
+ // Collision detection. Returns position information with valid being true
+ // when the target box does not collide with any solid items.
+ // Ignores collisions when overlapping with the start box.
+ PositionInfo getPositionInfo(const Box &target, const Box &start, uint32 shapeflags, ObjId id) const;
+
+ // Note that this version of getPositionInfo can not take 'flipped' into account!
+ PositionInfo getPositionInfo(int32 x, int32 y, int32 z, uint32 shape, ObjId id) const;
//! Scan for a valid position for item in directions orthogonal to movedir
bool scanForValidPosition(int32 x, int32 y, int32 z, const Item *item,
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index cbfa3836602..5279b0a7a5a 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -653,10 +653,13 @@ bool Item::isPartlyOnScreen() const {
bool Item::canExistAt(int32 x, int32 y, int32 z, bool needsupport) const {
CurrentMap *cm = World::get_instance()->getCurrentMap();
- const Item *support;
- bool valid = cm->isValidPosition(x, y, z, getShape(), getObjId(),
- &support, 0);
- return valid && (!needsupport || support);
+ int32 xd, yd, zd;
+ getFootpadWorld(xd, yd, zd);
+ Box target(x, y, z, xd, yd, zd);
+ Box empty;
+
+ PositionInfo info = cm->getPositionInfo(target, empty, 0, getObjId());
+ return info.valid && (!needsupport || info.supported);
}
Direction Item::getDirToItemCentre(const Item &item2) const {
@@ -1210,13 +1213,12 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
Common::RandomSource &rs = Ultima8Engine::get_instance()->getRandomSource();
int damage = firetypedat->getRandomDamage();
- const Item *blocker = nullptr;
// CHECKME: the original doesn't exclude the source like this,
// but it seems obvious we have to or NPCs shoot themselves?
- bool isvalid = currentmap->isValidPosition(ix, iy, iz, BULLET_SPLASH_SHAPE, _objId, nullptr, nullptr, &blocker);
+ PositionInfo info = currentmap->getPositionInfo(ix, iy, iz, BULLET_SPLASH_SHAPE, _objId);
- if (!isvalid && blocker) {
- Item *block = getItem(blocker->getObjId());
+ if (!info.valid && info.blocker) {
+ Item *block = getItem(info.blocker->getObjId());
Point3 blockpt;
block->getLocation(blockpt);
Direction damagedir = Direction_GetWorldDir(blockpt.y - iy, blockpt.x - ix, dirmode_8dirs);
@@ -1433,11 +1435,9 @@ uint16 Item::fireDistance(const Item *other, Direction dir, int16 xoff, int16 yo
int32 cx = x + (i == 0 ? xoff : xoff2);
int32 cy = y + (i == 0 ? yoff : yoff2);
int32 cz = z + (i == 0 ? zoff : zoff2);
- const Item *blocker = nullptr;
- bool valid = cm->isValidPosition(cx, cy, cz, BULLET_SPLASH_SHAPE,
- getObjId(), nullptr, nullptr, &blocker);
- if (!valid) {
- if (blocker->getObjId() == other->getObjId())
+ PositionInfo info = cm->getPositionInfo(cx, cy, cz, BULLET_SPLASH_SHAPE, getObjId());
+ if (!info.valid && info.blocker) {
+ if (info.blocker->getObjId() == other->getObjId())
dist = MAX(abs(_x - ox), abs(_y - oy));
} else {
int32 ocx, ocy, ocz;
@@ -3142,8 +3142,8 @@ uint32 Item::I_legalCreateAtPoint(const uint8 *args, unsigned int /*argsize*/) {
// check if item can exist
CurrentMap *cm = World::get_instance()->getCurrentMap();
- bool valid = cm->isValidPosition(x, y, z, shape, 0, 0, 0);
- if (!valid)
+ PositionInfo info = cm->getPositionInfo(x, y, z, shape, 0);
+ if (!info.valid)
return 0;
Item *newitem = ItemFactory::createItem(shape, frame, 0, 0, 0, 0, 0, true);
@@ -3174,8 +3174,8 @@ uint32 Item::I_legalCreateAtCoords(const uint8 *args, unsigned int /*argsize*/)
// check if item can exist
CurrentMap *cm = World::get_instance()->getCurrentMap();
- bool valid = cm->isValidPosition(x, y, z, shape, 0, 0, 0);
- if (!valid)
+ PositionInfo info = cm->getPositionInfo(x, y, z, shape, 0);
+ if (!info.valid)
return 0;
// if yes, create it
diff --git a/engines/ultima/ultima8/world/position_info.h b/engines/ultima/ultima8/world/position_info.h
new file mode 100644
index 00000000000..0097d3921af
--- /dev/null
+++ b/engines/ultima/ultima8/world/position_info.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the 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 GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef ULTIMA8_WORLD_POSITION_INFO_H
+#define ULTIMA8_WORLD_POSITION_INFO_H
+
+namespace Ultima {
+namespace Ultima8 {
+
+class Item;
+
+/**
+ * Position information for a desired target box for an item.
+ * The position is valid when the target box does not collide with any solid items.
+ *
+ * Floor is set to the solid item with the highest z coordinate under the target box,
+ * or null if there is no floor below box.
+ *
+ * Roof is set to the roof item with the lowest z coordinate over the target box,
+ * or null if there is no roof above box.
+ *
+ * Blocker is set to an item blocking the target box, or null if there is no such item.
+ *
+ * Supported is true if the floor is appropriate to support the item when at the target.
+ */
+struct PositionInfo {
+ bool valid;
+ bool supported;
+ const Item *floor;
+ const Item *roof;
+ const Item *blocker;
+
+ PositionInfo() : valid(false), supported(false), floor(nullptr), roof(nullptr), blocker(nullptr) {}
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
More information about the Scummvm-git-logs
mailing list