From e1a2cae9868225b5e7f523d6603154c583854a21 Mon Sep 17 00:00:00 2001 From: captainurist <73941350+captainurist@users.noreply.github.com> Date: Sun, 10 Nov 2024 18:31:30 +0000 Subject: [PATCH] Moved GetTerrainHeightsAroundParty2 to OutdoorTerrain --- src/Engine/Graphics/Outdoor.cpp | 52 ++------------------------ src/Engine/Graphics/Outdoor.h | 1 - src/Engine/Graphics/OutdoorTerrain.cpp | 45 ++++++++++++++++++++++ src/Engine/Graphics/OutdoorTerrain.h | 5 +++ src/Engine/Spells/CastSpellInfo.cpp | 2 +- 5 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/Engine/Graphics/Outdoor.cpp b/src/Engine/Graphics/Outdoor.cpp index 305908b103c..8f6c16534b5 100644 --- a/src/Engine/Graphics/Outdoor.cpp +++ b/src/Engine/Graphics/Outdoor.cpp @@ -685,7 +685,7 @@ void OutdoorLocation::ArrangeSpriteObjects() { for (int i = 0; i < (signed int)pSpriteObjects.size(); ++i) { if (pSpriteObjects[i].uObjectDescID) { if (!(pSpriteObjects[i].uAttributes & SPRITE_DROPPED_BY_PLAYER) && !pSpriteObjects[i].IsUnpickable()) { - pSpriteObjects[i].vPosition.z = GetTerrainHeightsAroundParty2(pSpriteObjects[i].vPosition); + pSpriteObjects[i].vPosition.z = pOutdoor->pTerrain.heightByPos(pSpriteObjects[i].vPosition); } if (pSpriteObjects[i].containing_item.uItemID != ITEM_NULL) { if (pSpriteObjects[i].containing_item.uItemID != ITEM_POTION_BOTTLE && @@ -931,7 +931,7 @@ float ODM_GetFloorLevel(const Vec3f &pos, bool *pIsOnWater, int *faceId) { std::array odm_floor_level{}; // idb current_BModel_id[0] = -1; current_Face_id[0] = -1; - odm_floor_level[0] = GetTerrainHeightsAroundParty2(pos); + odm_floor_level[0] = pOutdoor->pTerrain.heightByPos(pos); *pIsOnWater = pOutdoor->pTerrain.isWaterByPos(pos); int surface_count = 1; @@ -1538,7 +1538,7 @@ void ODM_ProcessPartyActions() { pParty->uFlags &= ~(PARTY_FLAG_BURNING | PARTY_FLAG_WATER_DAMAGE); if (partyDrowningFlag) { - int pTerrainHeight = GetTerrainHeightsAroundParty2(pParty->pos); + int pTerrainHeight = pOutdoor->pTerrain.heightByPos(pParty->pos); if (pParty->pos.z <= pTerrainHeight + 1) { pParty->uFlags |= PARTY_FLAG_WATER_DAMAGE; } @@ -2071,52 +2071,6 @@ int GridCellToWorldPosX(int a1) { return (a1 - 64) << 9; } //----- (0047F476) -------------------------------------------------------- int GridCellToWorldPosY(int a1) { return (64 - a1) << 9; } -//----- (0048257A) -------------------------------------------------------- -int GetTerrainHeightsAroundParty2(const Vec3f &pos) { - // int result; // eax@9 - int originz; // ebx@11 - int lz; // eax@11 - int rz; // ecx@11 - int rpos; // [sp+10h] [bp-8h]@11 - int lpos; // [sp+24h] [bp+Ch]@11 - - // TODO(captainurist): this function had some code that would push the party -60 units down when on a water tile AND - // not water-walking, but this isn't enabled in the game. I tried it, and it actually looks - // good, as if the party is actually a bit submerged and swimming. The only problem is that - // party would be jerked up upon coming ashore, and this just looks ugly. Find a way to - // reimplement this properly. - - Vec2i gridPos = WorldPosToGrid(pos); - - OutdoorTileGeometry tile = pOutdoor->pTerrain.tileGeometryByGrid(gridPos); - - if (tile.v00.z != tile.v10.z || tile.v10.z != tile.v11.z || tile.v11.z != tile.v01.z) { - // On a slope. - if (std::abs(tile.v00.y - pos.y) >= std::abs(pos.x - tile.v00.x)) { - originz = tile.v01.z; - lz = tile.v11.z; - rz = tile.v00.z; - lpos = pos.x - tile.v00.x; - rpos = pos.y - tile.v11.y; - } else { - originz = tile.v10.z; - lz = tile.v00.z; - rz = tile.v11.z; - lpos = tile.v11.x - pos.x; - rpos = tile.v00.y - pos.y; - } - - assert(lpos >= 0 && lpos < 512); - assert(rpos >= 0 && rpos < 512); - - // (x >> 9) is basically (x / 512) but with consistent rounding towards -inf. - return originz + ((rpos * (rz - originz)) >> 9) + ((lpos * (lz - originz)) >> 9); - } else { - // On flat terrain. - return tile.v00.z; - } -} - //----- (00436A6D) -------------------------------------------------------- double OutdoorLocation::GetPolygonMinZ(RenderVertexSoft *pVertices, unsigned int unumverts) { double result = FLT_MAX; diff --git a/src/Engine/Graphics/Outdoor.h b/src/Engine/Graphics/Outdoor.h index 3b7a19b8643..92f1f1a002c 100644 --- a/src/Engine/Graphics/Outdoor.h +++ b/src/Engine/Graphics/Outdoor.h @@ -131,7 +131,6 @@ Vec2i WorldPosToGrid(Vec3f worldPos); int GridCellToWorldPosX(int); int GridCellToWorldPosY(int); void sub_481ED9_MessWithODMRenderParams(); -int GetTerrainHeightsAroundParty2(const Vec3f &pos); void TeleportToStartingPoint(MapStartPoint point); // idb extern MapStartPoint uLevel_StartingPointType; diff --git a/src/Engine/Graphics/OutdoorTerrain.cpp b/src/Engine/Graphics/OutdoorTerrain.cpp index c1b072f24f5..481d3b52b75 100644 --- a/src/Engine/Graphics/OutdoorTerrain.cpp +++ b/src/Engine/Graphics/OutdoorTerrain.cpp @@ -38,6 +38,51 @@ int OutdoorTerrain::heightByGrid(Vec2i gridPos) { return 32 * pHeightmap[gridPos.y * 128 + gridPos.x]; } +int OutdoorTerrain::heightByPos(const Vec3f &pos) { + // TODO(captainurist): This should return float. But we'll need to retrace. + int originz; // ebx@11 + int lz; // eax@11 + int rz; // ecx@11 + int rpos; // [sp+10h] [bp-8h]@11 + int lpos; // [sp+24h] [bp+Ch]@11 + + // TODO(captainurist): this function had some code that would push the party -60 units down when on a water tile AND + // not water-walking, but this isn't enabled in the game. I tried it, and it actually looks + // good, as if the party is actually a bit submerged and swimming. The only problem is that + // party would be jerked up upon coming ashore, and this just looks ugly. Find a way to + // reimplement this properly. + + Vec2i gridPos = WorldPosToGrid(pos); + + OutdoorTileGeometry tile = pOutdoor->pTerrain.tileGeometryByGrid(gridPos); + + if (tile.v00.z != tile.v10.z || tile.v10.z != tile.v11.z || tile.v11.z != tile.v01.z) { + // On a slope. + if (std::abs(tile.v00.y - pos.y) >= std::abs(pos.x - tile.v00.x)) { + originz = tile.v01.z; + lz = tile.v11.z; + rz = tile.v00.z; + lpos = pos.x - tile.v00.x; + rpos = pos.y - tile.v11.y; + } else { + originz = tile.v10.z; + lz = tile.v00.z; + rz = tile.v11.z; + lpos = tile.v11.x - pos.x; + rpos = tile.v00.y - pos.y; + } + + assert(lpos >= 0 && lpos < 512); + assert(rpos >= 0 && rpos < 512); + + // (x >> 9) is basically (x / 512) but with consistent rounding towards -inf. + return originz + ((rpos * (rz - originz)) >> 9) + ((lpos * (lz - originz)) >> 9); + } else { + // On flat terrain. + return tile.v00.z; + } +} + int OutdoorTerrain::tileIdByGrid(Vec2i gridPos) const { if (gridPos.x < 0 || gridPos.x > 127 || gridPos.y < 0 || gridPos.y > 127) return 0; diff --git a/src/Engine/Graphics/OutdoorTerrain.h b/src/Engine/Graphics/OutdoorTerrain.h index 2be5850cdbd..791cbf51a67 100644 --- a/src/Engine/Graphics/OutdoorTerrain.h +++ b/src/Engine/Graphics/OutdoorTerrain.h @@ -26,6 +26,11 @@ class OutdoorTerrain { int heightByGrid(Vec2i gridPos); + /** + * @offset 0x0048257A + */ + int heightByPos(const Vec3f &pos); + /** * @param gridPos Grid coordinates. * @return Tile id at `gridPos` that can then be used to get tile data from `TileTable`. diff --git a/src/Engine/Spells/CastSpellInfo.cpp b/src/Engine/Spells/CastSpellInfo.cpp index 297d671601a..2d73d68e46a 100644 --- a/src/Engine/Spells/CastSpellInfo.cpp +++ b/src/Engine/Spells/CastSpellInfo.cpp @@ -2904,7 +2904,7 @@ void CastSpellInfoHelpers::castSpell() { } for (unsigned i = 0; i < 50; i++) { Vec3f rand(grng->random(4096) - 2048, grng->random(4096) - 2048, 0); - int terr_height = GetTerrainHeightsAroundParty2(pParty->pos + rand); + int terr_height = pOutdoor->pTerrain.heightByPos(pParty->pos + rand); SpriteObject::dropItemAt(SPRITE_SPELL_EARTH_ROCK_BLAST, {rand.x + pParty->pos.x, rand.y + pParty->pos.y, terr_height + 16.0f}, grng->random(500) + 500); }