From 302eb9c93bc2a3c20e78ecfee490c13f0641f4e5 Mon Sep 17 00:00:00 2001 From: Adngel <60930991+Adngel@users.noreply.github.com> Date: Mon, 20 Feb 2023 14:26:16 +0100 Subject: [PATCH] Electric Cleaner with vectors adngel (#1005) * Add cleaner code; * Do smooth turns * Revert acceleration (not working properly yet) * Update cleaner.cpp * Fix AdjustStopperFlag function, modify turn speed * Move electric cleaner into namespace * Cleaning cleaner first pass * Demagic turn tolerance, use bools * Update ElectricCleaner.cpp * Revert smooth turns * Format code according to conventions, rename function * cleaner update * Updated * Updated OCB to flag data. * Formula simplified * restored original radius I had reduced while I was working on it, but that's not needed anymore. * Update comment * Temporary Fix: Method to detect pushables. * Feedback applied * Revert primitive variable from auto to float --------- Co-authored-by: Troye Co-authored-by: Lwmte <3331699+Lwmte@users.noreply.github.com> Co-authored-by: Sezz Co-authored-by: Kubsy <80340234+Kubsy@users.noreply.github.com> --- TombEngine/Game/collision/collide_room.cpp | 5 + TombEngine/Game/collision/collide_room.h | 1 + TombEngine/Game/control/box.cpp | 6 +- TombEngine/Game/control/box.h | 2 +- .../Objects/TR3/Trap/ElectricCleaner.cpp | 422 ++++++++++++++++++ TombEngine/Objects/TR3/Trap/ElectricCleaner.h | 21 + TombEngine/Objects/TR3/tr3_objects.cpp | 14 + .../Objects/TR5/Object/tr5_pushableblock.cpp | 7 +- TombEngine/Objects/game_object_ids.h | 1 + .../Internal/TEN/Objects/ObjectIDs.h | 2 + TombEngine/TombEngine.vcxproj | 2 + 11 files changed, 475 insertions(+), 8 deletions(-) create mode 100644 TombEngine/Objects/TR3/Trap/ElectricCleaner.cpp create mode 100644 TombEngine/Objects/TR3/Trap/ElectricCleaner.h diff --git a/TombEngine/Game/collision/collide_room.cpp b/TombEngine/Game/collision/collide_room.cpp index b5dbd9f69..b3abfb054 100644 --- a/TombEngine/Game/collision/collide_room.cpp +++ b/TombEngine/Game/collision/collide_room.cpp @@ -168,6 +168,11 @@ CollisionResult GetCollision(int x, int y, int z, short roomNumber) return result; } +CollisionResult GetCollision(const GameVector& point) +{ + return GetCollision(point.x, point.y, point.z, point.RoomNumber); +} + // A reworked legacy GetFloorHeight() function which writes data // into a special CollisionResult struct instead of global variables. // It writes for both floor and ceiling heights at the same coordinates, meaning it should be used diff --git a/TombEngine/Game/collision/collide_room.h b/TombEngine/Game/collision/collide_room.h index 8feb44d11..8ecee4e23 100644 --- a/TombEngine/Game/collision/collide_room.h +++ b/TombEngine/Game/collision/collide_room.h @@ -126,6 +126,7 @@ CollisionResult GetCollision(ItemInfo* item); CollisionResult GetCollision(ItemInfo* item, short headingAngle, float forward, float down = 0.0f, float right = 0.0f); CollisionResult GetCollision(Vector3i pos, int roomNumber, short headingAngle, float forward, float down = 0.0f, float right = 0.0f); CollisionResult GetCollision(int x, int y, int z, short roomNumber); +CollisionResult GetCollision(const GameVector& point); CollisionResult GetCollision(FloorInfo* floor, int x, int y, int z); void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offset, bool resetRoom = false); diff --git a/TombEngine/Game/control/box.cpp b/TombEngine/Game/control/box.cpp index 7ae0a0a4c..c894db5b5 100644 --- a/TombEngine/Game/control/box.cpp +++ b/TombEngine/Game/control/box.cpp @@ -2081,21 +2081,21 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT) return TARGET_TYPE::NO_TARGET; } -void AdjustStopperFlag(ItemInfo* item, int direction, bool set) +void AdjustStopperFlag(ItemInfo* item, int direction) { int x = item->Pose.Position.x; int z = item->Pose.Position.z; auto* room = &g_Level.Rooms[item->RoomNumber]; auto* floor = GetSector(room, x - room->x, z - room->z); - floor->Stopper = set; + floor->Stopper = !floor->Stopper; x = item->Pose.Position.x + SECTOR(1) * phd_sin(direction); z = item->Pose.Position.z + SECTOR(1) * phd_cos(direction); room = &g_Level.Rooms[GetCollision(x, item->Pose.Position.y, z, item->RoomNumber).RoomNumber]; floor = GetSector(room, x - room->x, z - room->z); - floor->Stopper = set; + floor->Stopper = !floor->Stopper; } void InitialiseItemBoxData() diff --git a/TombEngine/Game/control/box.h b/TombEngine/Game/control/box.h index d930d4aa3..f2f181170 100644 --- a/TombEngine/Game/control/box.h +++ b/TombEngine/Game/control/box.h @@ -187,7 +187,7 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI); TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT); bool CreatureAnimation(short itemNumber, short angle, short tilt); void CreatureHealth(ItemInfo* item); -void AdjustStopperFlag(ItemInfo* item, int direction, bool set); +void AdjustStopperFlag(ItemInfo* item, int direction); void InitialiseItemBoxData(); bool CanCreatureJump(ItemInfo& item, JumpDistance jumpDistType); diff --git a/TombEngine/Objects/TR3/Trap/ElectricCleaner.cpp b/TombEngine/Objects/TR3/Trap/ElectricCleaner.cpp new file mode 100644 index 000000000..00255ac87 --- /dev/null +++ b/TombEngine/Objects/TR3/Trap/ElectricCleaner.cpp @@ -0,0 +1,422 @@ +#include "framework.h" +#include "Objects/TR3/Trap/ElectricCleaner.h" + +#include "Game/collision/collide_item.h" +#include "Game/control/box.h" +#include "Game/effects/item_fx.h" +#include "Game/effects/spark.h" +#include "Game/effects/tomb4fx.h" +#include "Game/Lara/lara_helpers.h" +#include "Specific/setup.h" + +using namespace TEN::Effects::Items; +using namespace TEN::Effects::Spark; + +// ItemFlags[0]: Rotation speed and heading angle. +// ItemFlags[1]: Flags, each bit is used to check the status of a flag +// b0: flagDoDetection +// b1: flagTurnRight +// b2: flagPriorityForward +// b3: flagAntiClockWiseOrder +// b4: flagStopAfterKill - If true the cleaner will stop when kills Lara. +// ItemFlags[2]: Movement velocity. +// ItemFlags[3, 4, 5]: Counters for dynamic lights and sparks. +// ItemFlags[6]: Goal direction angle. + +// OCB: +// 0: Stop after killing the player. +// Anything else: Don't stop after killing the player. + +namespace TEN::Entities::Traps +{ + constexpr auto ELECTRIC_CLEANER_VELOCITY = BLOCK(1 / 16.0f); + constexpr auto ELECTRIC_CLEANER_TURN_RATE = 1024; + + const auto ElectricCleanerHarmJoints = std::vector{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; + + std::vector MyPushablesList = {}; + + void InitialiseElectricCleaner(short itemNumber) + { + auto& item = g_Level.Items[itemNumber]; + + // Align to the middle of the block. + item.Pose.Position.x = (item.Pose.Position.x & ~WALL_MASK) | (int)BLOCK(0.5f); + item.Pose.Position.z = (item.Pose.Position.z & ~WALL_MASK) | (int)BLOCK(0.5f); + + // Init flags. + item.ItemFlags[0] = ELECTRIC_CLEANER_TURN_RATE; + item.ItemFlags[1] = 0; + item.ItemFlags[2] = ELECTRIC_CLEANER_VELOCITY; + item.ItemFlags[6] = item.Pose.Orientation.y; + item.Collidable = true; + + if (item.TriggerFlags) + item.ItemFlags[1] &= ~(1 << 4); // Turn off 1st bit for flagStopAfterKill. + else + item.ItemFlags[1] |= (1 << 4); // Turn on 1st bit for flagStopAfterKill. + + CollectLevelPushables(MyPushablesList); + } + + void ElectricCleanerControl(short itemNumber) + { + auto& item = g_Level.Items[itemNumber]; + auto& object = Objects[item.ObjectNumber]; + + auto& rotationVel = item.ItemFlags[0]; + auto& moveVel = item.ItemFlags[2]; + auto& goalAngle = item.ItemFlags[6]; + + if (!TriggerActive(&item)) + { + if (moveVel > 0) + { + moveVel = 0; + SoundEffect(SFX_TR3_CLEANER_FUSEBOX, &item.Pose); + } + + return; + } + + if (moveVel <= 0) + return; + + auto angleDifference = abs(TO_RAD(goalAngle) - TO_RAD(item.Pose.Orientation.y)); + + bool flagDoDetection = ((item.ItemFlags[1] & (1 << 0)) != 0); + bool flagTurnRight = ((item.ItemFlags[1] & (1 << 1)) != 0); + bool flagPriorityForward = ((item.ItemFlags[1] & (1 << 2)) != 0); + bool flagAntiClockWiseOrder = ((item.ItemFlags[1] & (1 << 3)) != 0); + + auto col = GetCollision(item.Pose.Position.x, item.Pose.Position.y, item.Pose.Position.z, item.RoomNumber); + + float yaw = TO_RAD(item.Pose.Orientation.y); + + auto forwardDirection = Vector3(sin(yaw), 0, cos(yaw)); + forwardDirection.Normalize(); + + auto rightDirection = Vector3(cos(yaw), 0, -sin(yaw)); + rightDirection.Normalize(); + + if (angleDifference > TO_RAD(rotationVel)) + { + if (flagTurnRight) + item.Pose.Orientation.y -= rotationVel; + else + item.Pose.Orientation.y += rotationVel; + + // Recalculate new difference to check if we should force align with axis for safety check. + angleDifference = abs(TO_RAD(goalAngle) - TO_RAD(item.Pose.Orientation.y)); + if (angleDifference <= TO_RAD(rotationVel)) + item.Pose.Orientation.y = goalAngle; + } + else + { + if (flagDoDetection && + (item.Pose.Position.x & WALL_MASK) == BLOCK(0.5f) && + (item.Pose.Position.z & WALL_MASK) == BLOCK(0.5f)) + { + //Do triggers + TestTriggers(&item, true); + + //Search for next direction + Vector3 NewDirection; + + if (flagPriorityForward) + { + if (flagAntiClockWiseOrder) //Forward Right Left + NewDirection = ElectricCleanerSearchDirections(item, forwardDirection, rightDirection, -rightDirection); + else //Forward Left Right + NewDirection = ElectricCleanerSearchDirections(item, forwardDirection, -rightDirection, rightDirection); + } + else + { + if (flagAntiClockWiseOrder) //Right Forward Left + NewDirection = ElectricCleanerSearchDirections(item, rightDirection, forwardDirection, -rightDirection); + else //Left Forward Right + NewDirection = ElectricCleanerSearchDirections(item, -rightDirection, forwardDirection, rightDirection); + } + + if (NewDirection == Vector3::Zero) //Return back. (We already know is a valid one because it came from there). + NewDirection = -forwardDirection; + + //Will turn left or right? + auto crossProductResult = NewDirection.Cross(forwardDirection); + if (crossProductResult.y > 0) + item.ItemFlags[1] |= (1 << 1); // Turn on 1st bit for flagTurnRight. + else if (crossProductResult.y < 0) + item.ItemFlags[1] &= ~(1 << 1); // Turn off 1st bit for flagTurnRight. (So it'll turn to the left) + + //Store goal angle to control the rotation. + item.ItemFlags[6] = FROM_RAD(atan2(NewDirection.x, NewDirection.z)); + + if (item.Pose.Orientation.y - item.ItemFlags[6] == 0) + //If it doesn't have to rotate, do forward movement to keep smooth movement. + item.Pose.Position = item.Pose.Position + forwardDirection * moveVel; + else + //If it has to rotate, stop detection so it doesn't calculate collisions again while rotating in the same sector. + item.ItemFlags[1] &= ~(1 << 0); // Turn off 1st bit for flagDoDetection. + } + else + { + item.Pose.Position.y = col.Position.Floor; + + //Is not in the center of a tile, keep moving forward. + item.Pose.Position = item.Pose.Position + forwardDirection * moveVel; + + auto slope = col.Block->FloorSlope(0); + + if (slope.LengthSquared() > 0) //If it's a slope, don't do turns. + item.ItemFlags[1] &= ~(1 << 0); // Turn off 1st bit for flagDoDetection. + else + item.ItemFlags[1] |= (1 << 0); // Turn on 1st bit for flagDoDetection. + } + } + + AnimateItem(&item); + + int probedRoomNumber = GetCollision(&item).RoomNumber; + if (item.RoomNumber != probedRoomNumber) + ItemNewRoom(itemNumber, probedRoomNumber); + + auto radius = Vector2(object.radius, object.radius); + AlignEntityToSurface(&item, radius); + + SpawnElectricCleanerSparks(item); + ElectricCleanerToItemCollision(item); + } + + bool IsNextSectorValid(ItemInfo& item, const Vector3& dir) + { + GameVector detectionPoint = item.Pose.Position + dir * BLOCK(1); + detectionPoint.RoomNumber = item.RoomNumber; + + auto col = GetCollision(detectionPoint); + + //Is a wall + if (col.Block->IsWall(detectionPoint.x, detectionPoint.z)) + return false; + + //Is it a sliding slope? + if (col.Position.FloorSlope) + return false; + + if (abs(col.FloorTilt.x) == 0 && abs(col.FloorTilt.y) == 0) //Is a flat tile + { + //Is a 1 click step (higher or lower). + int distanceToFloor = abs(col.Position.Floor - item.Pose.Position.y); + if (distanceToFloor >= CLICK(1)) + return false; + } + else //Is a slope tile + { + //Is a 2 click step (higher or lower). + int distanceToFloor = abs(col.Position.Floor - item.Pose.Position.y); + if (distanceToFloor > CLICK(2)) + return false; + + short slopeAngle = ANGLE(0.0f); + + if (col.FloorTilt.x > 0) + slopeAngle = -ANGLE(90.0f); + else if (col.FloorTilt.x < 0) + slopeAngle = ANGLE(90.0f); + + if (col.FloorTilt.y > 0 && col.FloorTilt.y > abs(col.FloorTilt.x)) + slopeAngle = ANGLE(180.0f); + else if (col.FloorTilt.y < 0 && -col.FloorTilt.y > abs(col.FloorTilt.x)) + slopeAngle = ANGLE(0.0f); + + auto angleDir = FROM_RAD(atan2(dir.x, dir.z)); + auto alignment = slopeAngle - angleDir; + + //Is slope not aligned with the direction? + if ((alignment != 32768) && (alignment != 0) && (alignment != -32768)) + return false; + } + + //Is diagonal floor? + if (col.Position.DiagonalStep) + return false; + + //Is ceiling (square or diagonal) high enough? + int distanceToCeiling = abs(col.Position.Ceiling - col.Position.Floor); + int cleanerHeight = BLOCK(1); //TODO change it for the collision bounding box height. + if (distanceToCeiling < cleanerHeight) + return false; + + //Is a non walkable tile? (So there is not any box) + if (col.Block->Box == NO_BOX) + return false; + + //Is a blocked grey box (So it's an Isolated box) + if (g_Level.Boxes[col.Block->Box].flags & BLOCKABLE) + return false; + + //Is a stopper tile? (There is still a shatter object). + if (col.Block->Stopper) + return false; + + //Is there a pushable block? + if (CheckPushableList(MyPushablesList, detectionPoint.ToVector3())) + return false; + + //If nothing of that happened, then it must be a valid sector. + return true; + } + + Vector3 ElectricCleanerSearchDirections(ItemInfo& item, const Vector3& dir1, const Vector3& dir2, const Vector3& dir3) + { + if (IsNextSectorValid(item, dir1)) + return dir1; + if (IsNextSectorValid(item, dir2)) + return dir2; + if (IsNextSectorValid(item, dir3)) + return dir3; + + return Vector3::Zero; + } + + void ElectricCleanerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll) + { + auto& item = g_Level.Items[itemNumber]; + + ObjectCollision(itemNumber, laraItem, coll); + + if (item.TouchBits.Test(ElectricCleanerHarmJoints) && item.ItemFlags[2]) + { + ItemElectricBurn(laraItem, -1); + laraItem->HitPoints = 0; + + bool flagStopAfterKill = ((item.ItemFlags[1] & (1 << 4)) != 0); + if (flagStopAfterKill) + item.ItemFlags[2] = 0; + + SoundEffect(SFX_TR3_CLEANER_FUSEBOX, &item.Pose); + } + } + + void ElectricCleanerToItemCollision(ItemInfo& item) + { + auto backupPos = item.Pose.Position; + + switch (item.Pose.Orientation.y) + { + case ANGLE(0.0f): + item.Pose.Position.z += BLOCK(0.5f); + break; + + case ANGLE(90.0f): + item.Pose.Position.x += BLOCK(0.5f); + break; + + case ANGLE(-180.0f): + item.Pose.Position.z -= BLOCK(0.5f); + break; + + case ANGLE(-90.0f): + item.Pose.Position.x -= BLOCK(0.5f); + break; + } + + if (GetCollidedObjects(&item, CLICK(1), true, CollidedItems, CollidedMeshes, true)) + { + int lp = 0; + while (CollidedItems[lp] != nullptr) + { + if (Objects[CollidedItems[lp]->ObjectNumber].intelligent) + { + CollidedItems[lp]->HitPoints = 0; + ItemElectricBurn(CollidedItems[lp], 120); + } + + lp++; + } + } + + item.Pose.Position = backupPos; + } + + void SpawnElectricCleanerSparks(ItemInfo& item) + { + static auto wireEndJoints = std::array{ 5, 9, 13 }; + + SoundEffect(SFX_TR3_CLEANER_LOOP, &item.Pose); + + auto vel = Vector3i( + (Random::GenerateInt(0, 255) * 4) - 512, + Random::GenerateInt(0, 7) - 4, + (Random::GenerateInt(0, 255) * 4) - 512); + + for (int i = 0; i < 3; i++) + { + if ((!(GetRandomControl() & 7) && !item.ItemFlags[3 + i]) || item.ItemFlags[3 + i]) + { + if (!item.ItemFlags[3 + i]) + item.ItemFlags[3 + i] = Random::GenerateInt(0, 12) + 8; + else + item.ItemFlags[3 + i]--; + + int joint = wireEndJoints[i]; + auto pos = GetJointPosition(&item, joint, Vector3i(-160, -8, 16)); + + byte c = Random::GenerateInt(0, 64) + 128; + TriggerDynamicLight(pos.x, pos.y, pos.z, 10, c >> 2, c >> 1, c); + + auto& spark = GetFreeSparkParticle(); + + spark = {}; + spark.active = true; + spark.age = 0; + float color = (192.0F + Random::GenerateFloat(0, 63.0F)) / 255.0F; + spark.sourceColor = Vector4(color / 4, color / 2, color, 1.0F); + color = (192.0F + Random::GenerateFloat(0, 63.0F)) / 255.0F; + spark.destinationColor = Vector4(color / 4, color / 2, color, 1.0F); + spark.life = Random::GenerateFloat(20, 27); + spark.friction = 1.2f; + spark.gravity = 1.5f; + spark.width = 8.0f; + spark.height = 96.0f; + auto v = vel.ToVector3(); + v.Normalize(v); + spark.velocity = v; + spark.pos = pos.ToVector3(); + spark.room = item.RoomNumber; + } + } + } + + //TODO method to detect pushables while Pushable_Object get refactored. + + void CollectLevelPushables(std::vector & PushablesList) + { + for (int index = 0; index < g_Level.Items.size(); index++) + { + ItemInfo* currentItem = &g_Level.Items[index]; + if (currentItem->ObjectNumber >= (ID_PUSHABLE_OBJECT1) && + currentItem->ObjectNumber <= (ID_PUSHABLE_OBJECT10)) + PushablesList.push_back(currentItem); + } + } + + bool CheckPushableList(std::vector & PushablesList, Vector3& refPoint) + { + auto pushableDistance = INFINITE; + for (int index = 0; index < PushablesList.size(); index++) + { + ItemInfo* currentObj = PushablesList[index]; + + if (currentObj == nullptr) + continue; + + auto PushablePos = currentObj->Pose.Position.ToVector3(); + auto currentDistance = Vector3::Distance(PushablePos, refPoint); + + if (currentDistance < 1024) + return true; + } + return false; + } + +} diff --git a/TombEngine/Objects/TR3/Trap/ElectricCleaner.h b/TombEngine/Objects/TR3/Trap/ElectricCleaner.h new file mode 100644 index 000000000..3902998db --- /dev/null +++ b/TombEngine/Objects/TR3/Trap/ElectricCleaner.h @@ -0,0 +1,21 @@ +#pragma once + +struct CollisionInfo; +struct ItemInfo; + +namespace TEN::Entities::Traps +{ + void InitialiseElectricCleaner(short itemNumber); + void ElectricCleanerControl(short itemNumber); + void ElectricCleanerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll); + + bool IsNextSectorValid(ItemInfo& item, const Vector3& dir); + Vector3 ElectricCleanerSearchDirections(ItemInfo& item, const Vector3& dir1, const Vector3& dir2, const Vector3& dir3); + void ElectricCleanerToItemCollision(ItemInfo& item); + void SpawnElectricCleanerSparks(ItemInfo& item); + + //TODO method to detect pushables while Pushable_Object get refactored. + void CollectLevelPushables (std::vector & PushablesList); + bool CheckPushableList (std::vector & PushablesList, Vector3& refPoint); + +} diff --git a/TombEngine/Objects/TR3/tr3_objects.cpp b/TombEngine/Objects/TR3/tr3_objects.cpp index 72e464d97..fa9319f39 100644 --- a/TombEngine/Objects/TR3/tr3_objects.cpp +++ b/TombEngine/Objects/TR3/tr3_objects.cpp @@ -32,6 +32,7 @@ #include "Objects/Effects/Boss.h" // Traps +#include "Objects/TR3/Trap/ElectricCleaner.h" #include "Objects/TR3/Trap/train.h" // Vehicles @@ -44,6 +45,7 @@ #include "Objects/Utils/object_helper.h" using namespace TEN::Entities::Creatures::TR3; +using namespace TEN::Entities::Traps; using namespace TEN::Effects::Boss; static void StartEntity(ObjectInfo* obj) @@ -398,6 +400,18 @@ static void StartTrap(ObjectInfo* obj) obj->collision = TrainCollision; obj->SetupHitEffect(true); } + + obj = &Objects[ID_ELECTRIC_CLEANER]; + if (obj->loaded) + { + obj->initialise = InitialiseElectricCleaner; + obj->control = ElectricCleanerControl; + obj->collision = ElectricCleanerCollision; + obj->shadowType = ShadowMode::All; + obj->HitPoints = NOT_TARGETABLE; + obj->nonLot = 1; + obj->radius = 512; + } } static void StartVehicles(ObjectInfo* obj) diff --git a/TombEngine/Objects/TR5/Object/tr5_pushableblock.cpp b/TombEngine/Objects/TR5/Object/tr5_pushableblock.cpp index f84d63b4b..bb66d76f2 100644 --- a/TombEngine/Objects/TR5/Object/tr5_pushableblock.cpp +++ b/TombEngine/Objects/TR5/Object/tr5_pushableblock.cpp @@ -192,7 +192,7 @@ namespace TEN::Entities::Generic if (pushable->hasFloorCeiling) { //AlterFloorHeight(item, -((item->triggerFlags - 64) * 256)); - AdjustStopperFlag(item, item->ItemFlags[0] + 0x8000, false); + AdjustStopperFlag(item, item->ItemFlags[0] + ANGLE(180)); } } @@ -390,7 +390,7 @@ namespace TEN::Entities::Generic if (pushable->hasFloorCeiling) { //AlterFloorHeight(item, -((item->triggerFlags - 64) * 256)); - AdjustStopperFlag(item, item->ItemFlags[0] + 0x8000, false); + AdjustStopperFlag(item, item->ItemFlags[0] + ANGLE(180)); } } @@ -498,8 +498,7 @@ namespace TEN::Entities::Generic if (pushable->hasFloorCeiling) { - //AlterFloorHeight(item, ((item->triggerFlags - 64) * 256)); - AdjustStopperFlag(pushableItem, pushableItem->ItemFlags[0], false); + AdjustStopperFlag(pushableItem, pushableItem->ItemFlags[0]); } } else diff --git a/TombEngine/Objects/game_object_ids.h b/TombEngine/Objects/game_object_ids.h index 4b49649b6..0c80dec29 100644 --- a/TombEngine/Objects/game_object_ids.h +++ b/TombEngine/Objects/game_object_ids.h @@ -357,6 +357,7 @@ enum GAME_OBJECT_ID : short ID_TRAIN, ID_EXPLOSION, ID_DAMOCLES_SWORD, + ID_ELECTRIC_CLEANER, ID_PUZZLE_ITEM1 = 500, ID_PUZZLE_ITEM2, diff --git a/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h b/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h index 0394a9c54..97c99d6e5 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h +++ b/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h @@ -364,6 +364,7 @@ The following constants are inside ObjID. TRAIN EXPLOSION DAMOCLES_SWORD + ELECTRIC_CLEANER PUZZLE_ITEM1 PUZZLE_ITEM2 PUZZLE_ITEM3 @@ -1531,6 +1532,7 @@ static const std::unordered_map kObjIDs { { "TRAIN", ID_TRAIN }, { "EXPLOSION", ID_EXPLOSION }, { "DAMOCLES_SWORD", ID_DAMOCLES_SWORD }, + { "ELECTRIC_CLEANER", ID_ELECTRIC_CLEANER }, { "PUZZLE_ITEM1", ID_PUZZLE_ITEM1 }, { "PUZZLE_ITEM2", ID_PUZZLE_ITEM2 }, { "PUZZLE_ITEM3", ID_PUZZLE_ITEM3 }, diff --git a/TombEngine/TombEngine.vcxproj b/TombEngine/TombEngine.vcxproj index 3a5b6c093..13633daee 100644 --- a/TombEngine/TombEngine.vcxproj +++ b/TombEngine/TombEngine.vcxproj @@ -169,6 +169,7 @@ CALL gen.bat + @@ -648,6 +649,7 @@ CALL gen.bat +