From cbcebce55ddf90e1d4e7da35299520b53a04be86 Mon Sep 17 00:00:00 2001 From: Matthew Duggan Date: Tue, 25 May 2021 21:26:03 +0900 Subject: [PATCH] ULTIMA8: Fix I_legalMoveToPoint to match original games Inspecting the disassembly more closely and trying to fix the usecode for the Crusader spider bombs (CRU_SPID::ordinal20), the parameter for this intrinsic is not "force", but more like "move until blocked", and when it's false the item should not move at all if there is a block. The spider bomb usecode tries to move the bomb down every now and then to check for a fall, but if it meant "force" then the bomb would go into the floor. It would also never explode because it was always forced into the new position and never fails. The return value is whether the move completed. --- engines/ultima/ultima8/world/item.cpp | 34 +++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp index bf2b3ef7b0a..6ee684d3372 100644 --- a/engines/ultima/ultima8/world/item.cpp +++ b/engines/ultima/ultima8/world/item.cpp @@ -3487,7 +3487,7 @@ uint32 Item::I_move(const uint8 *args, unsigned int /*argsize*/) { uint32 Item::I_legalMoveToPoint(const uint8 *args, unsigned int argsize) { ARG_ITEM_FROM_PTR(item); ARG_WORLDPOINT(point); - ARG_UINT16(force); // 0/1 + ARG_UINT16(move_if_blocked); // 0/1 ARG_UINT16(unknown2); // always 0 int32 x = point.getX(); @@ -3501,10 +3501,34 @@ uint32 Item::I_legalMoveToPoint(const uint8 *args, unsigned int argsize) { if (!item) return 0; - //! What should this do to ethereal items? - if (item->collideMove(x, y, z, false, force == 1) == 0x4000) - return 1; - return 0; + + // + // Return true when there are no blockers. + // If there are blockers, only move if move_if_blocked is set. + // + int retval = 1; + Std::list collisions; + int32 start[3], end[3], dims[3]; + end[0] = x; + end[1] = y; + end[2] = z; + item->getLocation(start[0], start[1], start[2]); + item->getFootpadWorld(dims[0], dims[1], dims[2]); + CurrentMap *map = World::get_instance()->getCurrentMap(); + map->sweepTest(start, end, dims, item->getShapeInfo()->_flags, + item->getObjId(), true, &collisions); + for (Std::list::iterator it = collisions.begin(); + it != collisions.end(); it++) { + if (it->_blocking && !it->_touching && it->_endTime > 0) { + if (!move_if_blocked) + return 0; + retval = 0; + break; + } + } + + item->collideMove(x, y, z, false, false); + return retval; } uint32 Item::I_legalMoveToContainer(const uint8 *args, unsigned int /*argsize*/) {