diff --git a/Documentation/Changes.txt b/Documentation/Changes.txt index b937c0fbc..dcf38bfd1 100644 --- a/Documentation/Changes.txt +++ b/Documentation/Changes.txt @@ -21,7 +21,9 @@ Version 1.0.2 * Fix occasional leave event calls when moving closer to volumes. * Fix incorrect viewport size in windowed mode. * Fix late landing animation dispatch in rare cases. -* Fix Lara's subway train death so that she no longer slides slowly after the animation has finished. +* Fix Lara's subway train death so that she no longer slides slowly after the animation has finished. +* Fix horseman's axe attack using his left foot as the damaging joint. +* Fix stargate blades needlessly pushing the player around while hardly doing any damage. Lua API changes: diff --git a/TombEngine/Game/animation.cpp b/TombEngine/Game/animation.cpp index 1b8763dc0..aeca7aac6 100644 --- a/TombEngine/Game/animation.cpp +++ b/TombEngine/Game/animation.cpp @@ -477,7 +477,9 @@ BOUNDING_BOX* GetBoundsAccurate(ItemInfo* item) InterpolatedBounds.Y2 = framePtr[0]->boundingBox.Y2 + (framePtr[1]->boundingBox.Y2 - framePtr[0]->boundingBox.Y2) * frac / rate; InterpolatedBounds.Z1 = framePtr[0]->boundingBox.Z1 + (framePtr[1]->boundingBox.Z1 - framePtr[0]->boundingBox.Z1) * frac / rate; InterpolatedBounds.Z2 = framePtr[0]->boundingBox.Z2 + (framePtr[1]->boundingBox.Z2 - framePtr[0]->boundingBox.Z2) * frac / rate; - return &InterpolatedBounds; + { + return &InterpolatedBounds; + } } } diff --git a/TombEngine/Game/collision/collide_item.cpp b/TombEngine/Game/collision/collide_item.cpp index 9a4f6c12b..6d76aa247 100644 --- a/TombEngine/Game/collision/collide_item.cpp +++ b/TombEngine/Game/collision/collide_item.cpp @@ -271,10 +271,10 @@ bool TestWithGlobalCollisionBounds(ItemInfo* item, ItemInfo* laraItem, Collision { auto* framePtr = GetBestFrame(laraItem); - if (item->Pose.Position.y + GlobalCollisionBounds.Y2 <= laraItem->Pose.Position.y + framePtr->boundingBox.Y1) + if ((item->Pose.Position.y + GlobalCollisionBounds.Y2) <= (laraItem->Pose.Position.y + framePtr->boundingBox.Y1)) return false; - if (item->Pose.Position.y + GlobalCollisionBounds.Y1 >= framePtr->boundingBox.Y2) + if ((item->Pose.Position.y + GlobalCollisionBounds.Y1) >= framePtr->boundingBox.Y2) return false; float sinY = phd_sin(item->Pose.Orientation.y); @@ -286,10 +286,10 @@ bool TestWithGlobalCollisionBounds(ItemInfo* item, ItemInfo* laraItem, Collision int x = (dx * cosY) - (dz * sinY); int z = (dz * cosY) + (dx * sinY); - if (x < GlobalCollisionBounds.X1 - coll->Setup.Radius || - x > GlobalCollisionBounds.X2 + coll->Setup.Radius || - z < GlobalCollisionBounds.Z1 - coll->Setup.Radius || - z > GlobalCollisionBounds.Z2 + coll->Setup.Radius) + if (x < (GlobalCollisionBounds.X1 - coll->Setup.Radius) || + x > (GlobalCollisionBounds.X2 + coll->Setup.Radius) || + z < (GlobalCollisionBounds.Z1 - coll->Setup.Radius) || + z > (GlobalCollisionBounds.Z2 + coll->Setup.Radius)) { return false; } @@ -346,16 +346,14 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll) itemNumber = item2->NextItem; } - for (int j = 0; j < g_Level.Rooms[i].mesh.size(); j++) + for (auto& mesh : g_Level.Rooms[i].mesh) { - auto* mesh = &g_Level.Rooms[i].mesh[j]; - - if (!(mesh->flags & StaticMeshFlags::SM_VISIBLE)) + if (!(mesh.flags & StaticMeshFlags::SM_VISIBLE)) continue; - if (Vector3i::Distance(item->Pose.Position, mesh->pos.Position) < COLLISION_CHECK_DISTANCE) + if (Vector3i::Distance(item->Pose.Position, mesh.pos.Position) < COLLISION_CHECK_DISTANCE) { - auto box = TO_DX_BBOX(mesh->pos, GetBoundsAccurate(mesh, false)); + auto box = TO_DX_BBOX(mesh.pos, GetBoundsAccurate(&mesh, false)); float distance; if (box.Intersects(origin, direction, distance) && distance < coll->Setup.Radius * 2) @@ -476,12 +474,12 @@ static bool ItemInRange(int x, int z, int radius) return ((SQUARE(x) + SQUARE(z)) <= SQUARE(radius)); } -bool ItemNearLara(PoseData* pos, int radius) +bool ItemNearLara(Vector3i* origin, int radius) { auto target = GameVector( - pos->Position.x - LaraItem->Pose.Position.x, - pos->Position.y - LaraItem->Pose.Position.y, - pos->Position.z - LaraItem->Pose.Position.z + origin->x - LaraItem->Pose.Position.x, + origin->y - LaraItem->Pose.Position.y, + origin->z - LaraItem->Pose.Position.z ); if (!ItemCollide(target.y, ITEM_RADIUS_YMAX)) @@ -500,9 +498,9 @@ bool ItemNearLara(PoseData* pos, int radius) return false; } -bool ItemNearTarget(PoseData* origin, ItemInfo* target, int radius) +bool ItemNearTarget(Vector3i* origin, ItemInfo* targetEntity, int radius) { - auto pos = origin->Position - target->Pose.Position; + auto pos = *origin - targetEntity->Pose.Position; if (!ItemCollide(pos.y, ITEM_RADIUS_YMAX)) return false; @@ -513,31 +511,31 @@ bool ItemNearTarget(PoseData* origin, ItemInfo* target, int radius) if (!ItemInRange(pos.x, pos.z, radius)) return false; - auto* bounds = GetBoundsAccurate(target); + auto* bounds = GetBoundsAccurate(targetEntity); if (pos.y >= bounds->Y1 && pos.y <= bounds->Y2) return true; return false; } -bool Move3DPosTo3DPos(PoseData* origin, PoseData* target, int velocity, short angleAdd) +bool Move3DPosTo3DPos(PoseData* fromPose, PoseData* toPose, int velocity, short angleAdd) { - auto direction = target->Position - origin->Position; - int distance = sqrt(SQUARE(direction.x) + SQUARE(direction.y) + SQUARE(direction.z)); + auto direction = toPose->Position - fromPose->Position; + float distance = Vector3i::Distance(fromPose->Position, toPose->Position); if (velocity < distance) - origin->Position += direction * velocity / distance; + fromPose->Position += direction * (velocity / distance); else - origin->Position = target->Position; + fromPose->Position = toPose->Position; if (!Lara.Control.IsMoving) { - bool shouldAnimate = (distance - velocity) > (velocity * ANIMATED_ALIGNMENT_FRAME_COUNT_THRESHOLD); + bool shouldAnimate = ((distance - velocity) > (velocity * ANIMATED_ALIGNMENT_FRAME_COUNT_THRESHOLD)); if (shouldAnimate && Lara.Control.WaterStatus != WaterStatus::Underwater) { - int angle = mGetAngle(target->Position.x, target->Position.z, origin->Position.x, origin->Position.z); - int direction = (GetQuadrant(angle) - GetQuadrant(target->Orientation.y)) & 3; + int angle = mGetAngle(toPose->Position.x, toPose->Position.z, fromPose->Position.x, fromPose->Position.z); + int direction = (GetQuadrant(angle) - GetQuadrant(toPose->Orientation.y)) & 3; switch (direction) { @@ -568,31 +566,31 @@ bool Move3DPosTo3DPos(PoseData* origin, PoseData* target, int velocity, short an Lara.Control.Count.PositionAdjust = 0; } - short deltaAngle = target->Orientation.x - origin->Orientation.x; + short deltaAngle = toPose->Orientation.x - fromPose->Orientation.x; if (deltaAngle > angleAdd) - origin->Orientation.x += angleAdd; + fromPose->Orientation.x += angleAdd; else if (deltaAngle < -angleAdd) - origin->Orientation.x -= angleAdd; + fromPose->Orientation.x -= angleAdd; else - origin->Orientation.x = target->Orientation.x; + fromPose->Orientation.x = toPose->Orientation.x; - deltaAngle = target->Orientation.y - origin->Orientation.y; + deltaAngle = toPose->Orientation.y - fromPose->Orientation.y; if (deltaAngle > angleAdd) - origin->Orientation.y += angleAdd; + fromPose->Orientation.y += angleAdd; else if (deltaAngle < -angleAdd) - origin->Orientation.y -= angleAdd; + fromPose->Orientation.y -= angleAdd; else - origin->Orientation.y = target->Orientation.y; + fromPose->Orientation.y = toPose->Orientation.y; - deltaAngle = target->Orientation.z - origin->Orientation.z; + deltaAngle = toPose->Orientation.z - fromPose->Orientation.z; if (deltaAngle > angleAdd) - origin->Orientation.z += angleAdd; + fromPose->Orientation.z += angleAdd; else if (deltaAngle < -angleAdd) - origin->Orientation.z -= angleAdd; + fromPose->Orientation.z -= angleAdd; else - origin->Orientation.z = target->Orientation.z; + fromPose->Orientation.z = toPose->Orientation.z; - return (origin->Position == target->Position && origin->Orientation == target->Orientation); + return (fromPose->Position == toPose->Position && fromPose->Orientation == toPose->Orientation); } bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius) @@ -611,13 +609,13 @@ bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius) int x = laraItem->Pose.Position.x - item->Pose.Position.x; int z = laraItem->Pose.Position.z - item->Pose.Position.z; - int dx = (cosY * x) - (sinY * z); - int dz = (cosY * z) + (sinY * x); + int dx = (x * cosY) - (z * sinY); + int dz = (z * cosY) + (x * sinY); - if (dx >= bounds->X1 - radius && - dx <= radius + bounds->X2 && - dz >= bounds->Z1 - radius && - dz <= radius + bounds->Z2) + if (dx >= (bounds->X1 - radius) && + dx <= (radius + bounds->X2) && + dz >= (bounds->Z1 - radius) && + dz <= (radius + bounds->Z2)) { return true; } @@ -673,11 +671,7 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa int rx = (dx * cosY) - (dz * sinY); int rz = (dz * cosY) + (dx * sinY); - BOUNDING_BOX* bounds; - if (bigPush & 2) - bounds = &GlobalCollisionBounds; - else - bounds = (BOUNDING_BOX*)GetBestFrame(item); + auto* bounds = (bigPush & 2) ? &GlobalCollisionBounds : (BOUNDING_BOX*)GetBestFrame(item); int minX = bounds->X1; int maxX = bounds->X2; @@ -714,8 +708,8 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa else rz -= bottom; - item2->Pose.Position.x = item->Pose.Position.x + cosY * rx + sinY * rz; - item2->Pose.Position.z = item->Pose.Position.z + cosY * rz - sinY * rx; + item2->Pose.Position.x = item->Pose.Position.x + (rx * cosY) + (rz * sinY); + item2->Pose.Position.z = item->Pose.Position.z + (rz * cosY) - (rx * sinY); auto* lara = item2->IsLara() ? GetLaraInfo(item2) : nullptr; @@ -740,12 +734,12 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa coll->Setup.LowerCeilingBound = 0; coll->Setup.UpperCeilingBound = MAX_HEIGHT; - auto facing = coll->Setup.ForwardAngle; + auto headingAngle = coll->Setup.ForwardAngle; coll->Setup.ForwardAngle = phd_atan(item2->Pose.Position.z - coll->Setup.OldPosition.z, item2->Pose.Position.x - coll->Setup.OldPosition.x); GetCollisionInfo(coll, item2); - coll->Setup.ForwardAngle = facing; + coll->Setup.ForwardAngle = headingAngle; if (coll->CollisionType == CT_NONE) { @@ -763,8 +757,8 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa // If Lara is in the process of aligning to an object, cancel it. if (lara != nullptr && lara->Control.Count.PositionAdjust > (LARA_POSITION_ADJUST_MAX_TIME / 6)) { - Lara.Control.IsMoving = false; - Lara.Control.HandStatus = HandStatus::Free; + lara->Control.IsMoving = false; + lara->Control.HandStatus = HandStatus::Free; } return true; @@ -853,7 +847,7 @@ void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll) { auto* mesh = &g_Level.Rooms[i].mesh[j]; - // Only process meshes which are visible and solid + // Only process meshes which are visible and solid. if ((mesh->flags & StaticMeshFlags::SM_VISIBLE) && (mesh->flags & StaticMeshFlags::SM_SOLID)) { if (Vector3i::Distance(item->Pose.Position, mesh->pos.Position) < COLLISION_CHECK_DISTANCE) @@ -867,39 +861,39 @@ void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll) } } -bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, CollisionInfo* coll) +bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pose, CollisionInfo* coll) { bool result = false; - // Get DX static bounds in global coords - auto staticBounds = TO_DX_BBOX(pos, box); + // Get DX static bounds in global coordinates. + auto staticBounds = TO_DX_BBOX(pose, box); - // Get local TR bounds and DX item bounds in global coords + // Get local TR bounds and DX item bounds in global coordinates. auto itemBBox = GetBoundsAccurate(item); auto itemBounds = TO_DX_BBOX(item->Pose, itemBBox); - // Extend bounds a bit for visual testing - itemBounds.Extents = itemBounds.Extents + Vector3(WALL_SIZE); + // Extend bounds a bit for visual testing. + itemBounds.Extents = itemBounds.Extents + Vector3(SECTOR(1)); - // Filter out any further checks if static isn't nearby + // Filter out any further checks if static isn't nearby. if (!staticBounds.Intersects(itemBounds)) return false; - // Bring back extents - itemBounds.Extents = itemBounds.Extents - Vector3(WALL_SIZE); + // Bring back extents. + itemBounds.Extents = itemBounds.Extents - Vector3(SECTOR(1)); - // Draw static bounds + // Draw static bounds. g_Renderer.AddDebugBox(staticBounds, Vector4(1, 0.3f, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS); - // Calculate horizontal item coll bounds according to radius + // Calculate horizontal item collision bounds according to radius. BOUNDING_BOX collBox; collBox.X1 = -coll->Setup.Radius; collBox.X2 = coll->Setup.Radius; collBox.Z1 = -coll->Setup.Radius; collBox.Z2 = coll->Setup.Radius; - // Calculate vertical item coll bounds according to either height (land mode) or precise bounds (water mode). - // Water mode needs special processing because height calc in original engines is inconsistent in such cases. + // Calculate vertical item collision bounds according to either height (land mode) or precise bounds (water mode). + // Water mode needs special processing because height calculation in original engines is inconsistent in such cases. if (TestEnvironment(ENV_FLAG_WATER, item)) { collBox.Y1 = itemBBox->Y1; @@ -911,18 +905,18 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi collBox.Y2 = 0; } - // Get and test DX item coll bounds + // Get and test DX item collision bounds. auto collBounds = TO_DX_BBOX(PoseData(item->Pose.Position), &collBox); bool intersects = staticBounds.Intersects(collBounds); - // Check if previous item horizontal position intersects bounds + // Check if previous item horizontal position intersects bounds. auto oldCollBounds = TO_DX_BBOX(PoseData(coll->Setup.OldPosition.x, item->Pose.Position.y, coll->Setup.OldPosition.z), &collBox); bool oldHorIntersects = staticBounds.Intersects(oldCollBounds); - // Draw item coll bounds + // Draw item coll bounds. g_Renderer.AddDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS); - // Decompose static bounds into top/bottom plane vertices + // Decompose static bounds into top/bottom plane vertices. Vector3 corners[8]; staticBounds.GetCorners(corners); Vector3 planeVertices[4][3] = @@ -933,7 +927,7 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi { corners[3], corners[6], corners[2] } }; - // Determine collision box vertical dimensions + // Determine collision box vertical dimensions. auto height = collBox.Height(); auto center = item->Pose.Position.y - height / 2; @@ -945,24 +939,23 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi for (int i = 0; i < 4; i++) { - // Calculate ray direction + // Calculate ray direction. auto mxR = Matrix::CreateFromYawPitchRoll(TO_RAD(item->Pose.Orientation.y), TO_RAD(item->Pose.Orientation.x + (ANGLE(90 * i))), 0.0f); auto mxT = Matrix::CreateTranslation(Vector3::UnitY); auto direction = (mxT * mxR).Translation(); - // Make a ray and do ray tests against all decomposed planes + // Make a ray and do ray tests against all decomposed planes. auto ray = Ray(collBounds.Center, direction); - // Determine if top/bottom planes are closest ones or not + // Determine if top/bottom planes are closest ones or not. for (int p = 0; p < 4; p++) { - // No plane intersection, quickly discard + // No plane intersection, quickly discard. float d = 0.0f; if (!ray.Intersects(planeVertices[p][0], planeVertices[p][1], planeVertices[p][2], d)) continue; - // Process plane intersection only if distance is smaller - // than already found minimum + // Process plane intersection only if distance is smaller than already found minimum. if (d < minDistance) { closestRay = ray; @@ -972,24 +965,25 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi } } - if (closestPlane != -1) // Top/bottom plane found + // Top/bottom plane found. + if (closestPlane != -1) { auto bottom = closestPlane >= 2; auto yPoint = abs((closestRay.direction * minDistance).y); auto distanceToVerticalPlane = height / 2 - yPoint; - // Correct position according to top/bottom bounds, if collided and plane is nearby + // Correct position according to top/bottom bounds, if collided and plane is nearby. if (intersects && oldHorIntersects && minDistance < height) { if (bottom) { - // HACK: additionally subtract 2 from bottom plane, or else false positives may occur. + // HACK: Additionally subtract 2 from bottom plane, otherwise false positives may occur. item->Pose.Position.y += distanceToVerticalPlane + 2; coll->CollisionType = CT_TOP; } else { - // Set collision type only if dry room (in water rooms it causes stucking) + // Set collision type only if dry room (in water rooms the player can get stuck). item->Pose.Position.y -= distanceToVerticalPlane; coll->CollisionType = (g_Level.Rooms[item->RoomNumber].flags & 1) ? coll->CollisionType : CT_CLAMP; } @@ -1005,29 +999,29 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi if (!intersects) return false; - // Check if bounds still collide after top/bottom position correction + // Check if bounds still collide after top/bottom position correction. if (!staticBounds.Intersects(TO_DX_BBOX(PoseData(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z), &collBox))) return result; - // Determine identity rotation/distance - auto distance = Vector3(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z); - auto sinY = phd_sin(pos.Orientation.y); - auto cosY = phd_cos(pos.Orientation.y); + // Determine identity orientation/distance. + auto distance = (item->Pose.Position - pose.Position).ToVector3(); + auto sinY = phd_sin(pose.Orientation.y); + auto cosY = phd_cos(pose.Orientation.y); - // Rotate item to collision bounds identity - auto x = round(distance.x * cosY - distance.z * sinY) + pos.Position.x; + // Rotate item to collision bounds identity. + auto x = round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x; auto y = item->Pose.Position.y; - auto z = round(distance.x * sinY + distance.z * cosY) + pos.Position.z; + auto z = round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z; - // Determine identity static collision bounds - auto XMin = pos.Position.x + box->X1; - auto XMax = pos.Position.x + box->X2; - auto YMin = pos.Position.y + box->Y1; - auto YMax = pos.Position.y + box->Y2; - auto ZMin = pos.Position.z + box->Z1; - auto ZMax = pos.Position.z + box->Z2; + // Determine identity static collision bounds. + auto XMin = pose.Position.x + box->X1; + auto XMax = pose.Position.x + box->X2; + auto YMin = pose.Position.y + box->Y1; + auto YMax = pose.Position.y + box->Y2; + auto ZMin = pose.Position.z + box->Z1; + auto ZMax = pose.Position.z + box->Z2; - // Determine item collision bounds + // Determine item collision bounds. auto inXMin = x + collBox.X1; auto inXMax = x + collBox.X2; auto inYMin = y + collBox.Y1; @@ -1035,16 +1029,15 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi auto inZMin = z + collBox.Z1; auto inZMax = z + collBox.Z2; - // Don't calculate shifts if not in bounds + // Don't calculate shifts if not in bounds. if (inXMax <= XMin || inXMin >= XMax || inYMax <= YMin || inYMin >= YMax || inZMax <= ZMin || inZMin >= ZMax) return result; - // Calculate shifts - - Vector3i rawShift = {}; + // Calculate shifts. + auto rawShift = Vector3i::Zero; auto shiftLeft = inXMax - XMin; auto shiftRight = XMax - inXMin; @@ -1061,13 +1054,13 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi else rawShift.z = shiftRight; - // Rotate previous collision position to identity - distance = Vector3(coll->Setup.OldPosition.x, coll->Setup.OldPosition.y, coll->Setup.OldPosition.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z); - auto ox = round(distance.x * cosY - distance.z * sinY) + pos.Position.x; - auto oz = round(distance.x * sinY + distance.z * cosY) + pos.Position.z; + // Rotate previous collision position to identity. + distance = (coll->Setup.OldPosition - pose.Position).ToVector3(); + auto ox = round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x; + auto oz = round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z; - // Calculate collisison type based on identity rotation - switch (GetQuadrant(coll->Setup.ForwardAngle - pos.Orientation.y)) + // Calculate collisison type based on identity orientation. + switch (GetQuadrant(coll->Setup.ForwardAngle - pose.Orientation.y)) { case NORTH: if (rawShift.x > coll->Setup.Radius || rawShift.x < -coll->Setup.Radius) @@ -1158,19 +1151,19 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, Collisi break; } - // Determine final shifts rotation/distance - distance = Vector3(x + coll->Shift.x, y, z + coll->Shift.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z); - sinY = phd_sin(-pos.Orientation.y); - cosY = phd_cos(-pos.Orientation.y); + // Determine final shifts orientation/distance. + distance = Vector3(x + coll->Shift.x, y, z + coll->Shift.z) - pose.Position.ToVector3(); + sinY = phd_sin(-pose.Orientation.y); + cosY = phd_cos(-pose.Orientation.y); - // Calculate final shifts rotation/distance - coll->Shift.x = (round(distance.x * cosY - distance.z * sinY) + pos.Position.x) - item->Pose.Position.x; - coll->Shift.z = (round(distance.x * sinY + distance.z * cosY) + pos.Position.z) - item->Pose.Position.z; + // Calculate final shifts orientation/distance. + coll->Shift.x = (round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x) - item->Pose.Position.x; + coll->Shift.z = (round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z) - item->Pose.Position.z; if (coll->Shift.x == 0 && coll->Shift.z == 0) - coll->CollisionType = CT_NONE; // Paranoid + coll->CollisionType = CT_NONE; // Paranoid. - // Set splat state flag if item is Lara and bounds are taller than Lara's headroom + // Set splat state flag if item is Lara and bounds are taller than Lara's headroom. if (item == LaraItem && coll->CollisionType == CT_FRONT) coll->HitTallObject = (YMin <= inYMin + LARA_HEADROOM); @@ -1182,39 +1175,39 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { auto* item = &g_Level.Items[itemNumber]; - auto prevCollResult = GetCollision(x, y, z, item->RoomNumber); - auto collResult = GetCollision(item); + auto prevPointProbe = GetCollision(x, y, z, item->RoomNumber); + auto pointProbe = GetCollision(item); auto* bounds = GetBoundsAccurate(item); int radius = bounds->Height(); item->Pose.Position.y += radius; - if (item->Pose.Position.y >= collResult.Position.Floor) + if (item->Pose.Position.y >= pointProbe.Position.Floor) { int bs = 0; - if (collResult.Position.FloorSlope && prevCollResult.Position.Floor < collResult.Position.Floor) + if (pointProbe.Position.FloorSlope && prevPointProbe.Position.Floor < pointProbe.Position.Floor) { int yAngle = (long)((unsigned short)item->Pose.Orientation.y); - if (collResult.FloorTilt.x < 0) + if (pointProbe.FloorTilt.x < 0) { if (yAngle >= ANGLE(180.0f)) bs = 1; } - else if (collResult.FloorTilt.x > 0) + else if (pointProbe.FloorTilt.x > 0) { if (yAngle <= ANGLE(180.0f)) bs = 1; } - if (collResult.FloorTilt.y < 0) + if (pointProbe.FloorTilt.y < 0) { if (yAngle >= ANGLE(90.0f) && yAngle <= ANGLE(270.0f)) bs = 1; } - else if (collResult.FloorTilt.y > 0) + else if (pointProbe.FloorTilt.y > 0) { if (yAngle <= ANGLE(90.0f) || yAngle >= ANGLE(270.0f)) bs = 1; @@ -1223,7 +1216,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, // If last position of item was also below this floor height, we've hit a wall, else we've hit a floor. - if (y > (collResult.Position.Floor + 32) && bs == 0 && + if (y > (pointProbe.Position.Floor + 32) && bs == 0 && (((x / SECTOR(1)) != (item->Pose.Position.x / SECTOR(1))) || ((z / SECTOR(1)) != (item->Pose.Position.z / SECTOR(1))))) { @@ -1231,8 +1224,8 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, long xs; - if ((x & (~(WALL_SIZE - 1))) != (item->Pose.Position.x & (~(WALL_SIZE - 1))) && // X crossed boundary? - (z & (~(WALL_SIZE - 1))) != (item->Pose.Position.z & (~(WALL_SIZE - 1)))) // Z crossed boundary as well? + if ((x & (~WALL_MASK)) != (item->Pose.Position.x & (~WALL_MASK)) && // X crossed boundary? + (z & (~WALL_MASK)) != (item->Pose.Position.z & (~WALL_MASK))) // Z crossed boundary as well? { if (abs(x - item->Pose.Position.x) < abs(z - item->Pose.Position.z)) xs = 1; // X has travelled the shortest, so (maybe) hit first. (Seems to work ok). @@ -1242,7 +1235,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, else xs = 1; - if ((x & (~(WALL_SIZE - 1))) != (item->Pose.Position.x & (~(WALL_SIZE - 1))) && xs) // X crossed boundary? + if ((x & (~WALL_MASK)) != (item->Pose.Position.x & (~WALL_MASK)) && xs) // X crossed boundary? { // Hit angle = ANGLE(270.0f). if (xv <= 0) @@ -1263,14 +1256,14 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, item->Pose.Position.z = z; } // Hit a steep slope? - else if (collResult.Position.FloorSlope) + else if (pointProbe.Position.FloorSlope) { // Need to know which direction the slope is. item->Animation.Velocity.z -= (item->Animation.Velocity.z / 4); // Hit angle = ANGLE(90.0f) - if (collResult.FloorTilt.x < 0 && ((abs(collResult.FloorTilt.x)) - (abs(collResult.FloorTilt.y)) >= 2)) + if (pointProbe.FloorTilt.x < 0 && ((abs(pointProbe.FloorTilt.x)) - (abs(pointProbe.FloorTilt.y)) >= 2)) { if (((unsigned short)item->Pose.Orientation.y) > ANGLE(180.0f)) { @@ -1282,7 +1275,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z -= collResult.FloorTilt.x * 2; + item->Animation.Velocity.z -= pointProbe.FloorTilt.x * 2; if ((unsigned short)item->Pose.Orientation.y > ANGLE(90.0f) && (unsigned short)item->Pose.Orientation.y < ANGLE(270.0f)) { item->Pose.Orientation.y -= ANGLE(22.5f); @@ -1304,7 +1297,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } // Hit angle = ANGLE(270.0f) - else if (collResult.FloorTilt.x > 0 && ((abs(collResult.FloorTilt.x)) - (abs(collResult.FloorTilt.y)) >= 2)) + else if (pointProbe.FloorTilt.x > 0 && ((abs(pointProbe.FloorTilt.x)) - (abs(pointProbe.FloorTilt.y)) >= 2)) { if (((unsigned short)item->Pose.Orientation.y) < ANGLE(180.0f)) { @@ -1316,7 +1309,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z += collResult.FloorTilt.x * 2; + item->Animation.Velocity.z += pointProbe.FloorTilt.x * 2; if ((unsigned short)item->Pose.Orientation.y > ANGLE(270.0f) || (unsigned short)item->Pose.Orientation.y < ANGLE(90.0f)) { item->Pose.Orientation.y -= ANGLE(22.5f); @@ -1338,7 +1331,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } // Hit angle = 0 - else if (collResult.FloorTilt.y < 0 && ((abs(collResult.FloorTilt.y)) - (abs(collResult.FloorTilt.x)) >= 2)) + else if (pointProbe.FloorTilt.y < 0 && ((abs(pointProbe.FloorTilt.y)) - (abs(pointProbe.FloorTilt.x)) >= 2)) { if (((unsigned short)item->Pose.Orientation.y) > ANGLE(90.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(270.0f)) { @@ -1350,7 +1343,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z -= collResult.FloorTilt.y * 2; + item->Animation.Velocity.z -= pointProbe.FloorTilt.y * 2; if ((unsigned short)item->Pose.Orientation.y < ANGLE(180.0f)) { @@ -1373,7 +1366,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } // Hit angle = ANGLE(180.0f) - else if (collResult.FloorTilt.y > 0 && ((abs(collResult.FloorTilt.y)) - (abs(collResult.FloorTilt.x)) >= 2)) + else if (pointProbe.FloorTilt.y > 0 && ((abs(pointProbe.FloorTilt.y)) - (abs(pointProbe.FloorTilt.x)) >= 2)) { if (((unsigned short)item->Pose.Orientation.y) > ANGLE(270.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(90.0f)) { @@ -1385,7 +1378,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z += collResult.FloorTilt.y * 2; + item->Animation.Velocity.z += pointProbe.FloorTilt.y * 2; if ((unsigned short)item->Pose.Orientation.y > ANGLE(180.0f)) { @@ -1407,7 +1400,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, item->Animation.Velocity.y = 0; } } - else if (collResult.FloorTilt.x < 0 && collResult.FloorTilt.y < 0) // Hit angle = 0x2000 + else if (pointProbe.FloorTilt.x < 0 && pointProbe.FloorTilt.y < 0) // Hit angle = 0x2000 { if (((unsigned short)item->Pose.Orientation.y) > ANGLE(135.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(315.0f)) { @@ -1419,7 +1412,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z += -collResult.FloorTilt.x + -collResult.FloorTilt.y; + item->Animation.Velocity.z += -pointProbe.FloorTilt.x + -pointProbe.FloorTilt.y; if ((unsigned short)item->Pose.Orientation.y > ANGLE(45.0f) && (unsigned short)item->Pose.Orientation.y < ANGLE(225.0f)) { item->Pose.Orientation.y -= ANGLE(22.5f); @@ -1441,7 +1434,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } // Hit angle = ANGLE(135.0f) - else if (collResult.FloorTilt.x < 0 && collResult.FloorTilt.y > 0) + else if (pointProbe.FloorTilt.x < 0 && pointProbe.FloorTilt.y > 0) { if (((unsigned short)item->Pose.Orientation.y) > ANGLE(225.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(45.0f)) { @@ -1453,7 +1446,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z += (-collResult.FloorTilt.x) + collResult.FloorTilt.y; + item->Animation.Velocity.z += (-pointProbe.FloorTilt.x) + pointProbe.FloorTilt.y; if ((unsigned short)item->Pose.Orientation.y < ANGLE(315.0f) && (unsigned short)item->Pose.Orientation.y > ANGLE(135.0f)) { item->Pose.Orientation.y -= ANGLE(22.5f); @@ -1475,7 +1468,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } // Hit angle = ANGLE(225.5f) - else if (collResult.FloorTilt.x > 0 && collResult.FloorTilt.y > 0) + else if (pointProbe.FloorTilt.x > 0 && pointProbe.FloorTilt.y > 0) { if (((unsigned short)item->Pose.Orientation.y) > ANGLE(315.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(135.0f)) { @@ -1487,7 +1480,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z += collResult.FloorTilt.x + collResult.FloorTilt.y; + item->Animation.Velocity.z += pointProbe.FloorTilt.x + pointProbe.FloorTilt.y; if ((unsigned short)item->Pose.Orientation.y < ANGLE(45.0f) || (unsigned short)item->Pose.Orientation.y > ANGLE(225.5f)) { item->Pose.Orientation.y -= ANGLE(22.5f); @@ -1509,7 +1502,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } // Hit angle = ANGLE(315.0f) - else if (collResult.FloorTilt.x > 0 && collResult.FloorTilt.y < 0) + else if (pointProbe.FloorTilt.x > 0 && pointProbe.FloorTilt.y < 0) { if (((unsigned short)item->Pose.Orientation.y) > ANGLE(45.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(225.5f)) { @@ -1521,7 +1514,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (item->Animation.Velocity.z < 32) { - item->Animation.Velocity.z += collResult.FloorTilt.x + (-collResult.FloorTilt.y); + item->Animation.Velocity.z += pointProbe.FloorTilt.x + (-pointProbe.FloorTilt.y); if ((unsigned short)item->Pose.Orientation.y < ANGLE(135.0f) || (unsigned short)item->Pose.Orientation.y > ANGLE(315.0f)) { item->Pose.Orientation.y -= ANGLE(22.5f); @@ -1543,7 +1536,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } - // Put item back in its last position. + // Move item back to its previous position. item->Pose.Position.x = x; item->Pose.Position.y = y; item->Pose.Position.z = z; @@ -1582,7 +1575,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } - item->Pose.Position.y = collResult.Position.Floor; + item->Pose.Position.y = pointProbe.Position.Floor; } } // Check for on top of object. @@ -1590,8 +1583,8 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, { if (yv >= 0) { - prevCollResult = GetCollision(item->Pose.Position.x, y, item->Pose.Position.z, item->RoomNumber); - collResult = GetCollision(item); + prevPointProbe = GetCollision(item->Pose.Position.x, y, item->Pose.Position.z, item->RoomNumber); + pointProbe = GetCollision(item); // Bounce off floor. @@ -1599,7 +1592,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, // was always set to 0 by GetHeight() function which was called before the check. // Possibly a mistake or unfinished feature by Core? -- Lwmte, 27.08.21 - if (item->Pose.Position.y >= prevCollResult.Position.Floor) + if (item->Pose.Position.y >= prevPointProbe.Position.Floor) { // Hit the floor; bounce and slow down. if (item->Animation.Velocity.y > 0) @@ -1633,17 +1626,17 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } - item->Pose.Position.y = prevCollResult.Position.Floor; + item->Pose.Position.y = prevPointProbe.Position.Floor; } } // else { // Bounce off ceiling. - collResult = GetCollision(item); + pointProbe = GetCollision(item); - if (item->Pose.Position.y < collResult.Position.Ceiling) + if (item->Pose.Position.y < pointProbe.Position.Ceiling) { - if (y < collResult.Position.Ceiling && + if (y < pointProbe.Position.Ceiling && (((x / SECTOR(1)) != (item->Pose.Position.x / SECTOR(1))) || ((z / SECTOR(1)) != (item->Pose.Position.z / SECTOR(1))))) { @@ -1666,13 +1659,13 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, else item->Animation.Velocity.z /= 2; - // Put item back in its last position. + // Move item back to its previous position. item->Pose.Position.x = x; item->Pose.Position.y = y; item->Pose.Position.z = z; } else - item->Pose.Position.y = collResult.Position.Ceiling; + item->Pose.Position.y = pointProbe.Position.Ceiling; if (item->Animation.Velocity.y < 0) item->Animation.Velocity.y = -item->Animation.Velocity.y; @@ -1680,14 +1673,14 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, } } - collResult = GetCollision(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber); + pointProbe = GetCollision(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber); - if (collResult.RoomNumber != item->RoomNumber) + if (pointProbe.RoomNumber != item->RoomNumber) { - if (item->ObjectNumber == ID_GRENADE && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, collResult.RoomNumber)) + if (item->ObjectNumber == ID_GRENADE && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, pointProbe.RoomNumber)) Splash(item); - ItemNewRoom(itemNumber, collResult.RoomNumber); + ItemNewRoom(itemNumber, pointProbe.RoomNumber); } item->Pose.Position.y -= radius; @@ -1776,8 +1769,8 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll) else { DoDamage(item, INT_MAX); - - DoLotsOfBlood(item->Pose.Position.x, + DoLotsOfBlood( + item->Pose.Position.x, laraItem->Pose.Position.y - CLICK(1), item->Pose.Position.z, laraItem->Animation.Velocity.z, @@ -1882,7 +1875,7 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll int rx = (frame->boundingBox.X1 + frame->boundingBox.X2) / 2; int rz = (frame->boundingBox.X2 + frame->boundingBox.Z2) / 2; - if (frame->boundingBox.Height() > STEP_SIZE) + if (frame->boundingBox.Height() > CLICK(1)) { auto* lara = GetLaraInfo(laraItem); @@ -1890,7 +1883,7 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll lara->HitDirection = (short)angle; - // TODO: check if a second Lara.hitFrame++; is required there ! + // TODO: Check if a second Lara.hitFrame++ is required. -- TokyoSU lara->HitFrame++; if (lara->HitFrame > 30) lara->HitFrame = 30; diff --git a/TombEngine/Game/collision/collide_item.h b/TombEngine/Game/collision/collide_item.h index a35117285..e0256f776 100644 --- a/TombEngine/Game/collision/collide_item.h +++ b/TombEngine/Game/collision/collide_item.h @@ -1,16 +1,15 @@ #pragma once #include "Math/Math.h" -#include "Math/Math.h" -struct ItemInfo; -struct CollisionInfo; class FloorInfo; +struct CollisionInfo; +struct ItemInfo; struct MESH_INFO; constexpr auto MAX_COLLIDED_OBJECTS = 1024; constexpr auto ITEM_RADIUS_YMAX = SECTOR(3); -constexpr auto VEHICLE_COLLISION_TERMINAL_VELOCITY = 30; +constexpr auto VEHICLE_COLLISION_TERMINAL_VELOCITY = 30.0f; extern BOUNDING_BOX GlobalCollisionBounds; extern ItemInfo* CollidedItems[MAX_COLLIDED_OBJECTS]; @@ -36,17 +35,17 @@ bool TestLaraPosition(OBJECT_COLLISION_BOUNDS* bounds, ItemInfo* item, ItemInfo* bool AlignLaraPosition(Vector3i* offset, ItemInfo* item, ItemInfo* laraItem); bool MoveLaraPosition(Vector3i* pos, ItemInfo* item, ItemInfo* laraItem); -bool ItemNearLara(PoseData* pos, int radius); -bool ItemNearTarget(PoseData* origin, ItemInfo* target, int radius); +bool ItemNearLara(Vector3i* origin, int radius); +bool ItemNearTarget(Vector3i* origin, ItemInfo* targetEntity, int radius); -bool Move3DPosTo3DPos(PoseData* origin, PoseData* target, int velocity, short angleAdd); +bool Move3DPosTo3DPos(PoseData* fromPose, PoseData* toPose, int velocity, short angleAdd); bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius); bool TestBoundsCollideStatic(ItemInfo* item, MESH_INFO* mesh, int radius); bool ItemPushItem(ItemInfo* item, ItemInfo* laraItem, CollisionInfo* coll, bool spasmEnabled, char bigPush); bool ItemPushStatic(ItemInfo* laraItem, MESH_INFO* mesh, CollisionInfo* coll); -bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pos, CollisionInfo* coll); +bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PoseData pose, CollisionInfo* coll); void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll); void AIPickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll); diff --git a/TombEngine/Game/collision/sphere.cpp b/TombEngine/Game/collision/sphere.cpp index 3685f5143..858352b41 100644 --- a/TombEngine/Game/collision/sphere.cpp +++ b/TombEngine/Game/collision/sphere.cpp @@ -77,7 +77,7 @@ int TestCollision(ItemInfo* item, ItemInfo* laraItem) int dz = z1 - z2; int r = r1 + r2; - if ((pow(dx, 2) + pow(dy, 2) + pow(dz, 2)) < pow(r, 2)) + if ((SQUARE(dx) + SQUARE(dy) + SQUARE(dz)) < SQUARE(r)) { item->SetBits(JointBitType::Touch, i); laraItem->SetBits(JointBitType::Touch, j); diff --git a/TombEngine/Game/control/box.cpp b/TombEngine/Game/control/box.cpp index 8ab789b79..5da2c2df5 100644 --- a/TombEngine/Game/control/box.cpp +++ b/TombEngine/Game/control/box.cpp @@ -92,7 +92,7 @@ void DrawNearbyPathfinding(int boxIndex) void DropEntityPickups(ItemInfo* item) { - ItemInfo* pickup = NULL; + ItemInfo* pickup = nullptr; for (short pickupNumber = item->CarriedItem; pickupNumber != NO_ITEM; pickupNumber = pickup->CarriedItem) { @@ -157,7 +157,7 @@ void CreatureYRot2(PoseData* fromPose, short angle, short angleAdd) bool SameZone(CreatureInfo* creature, ItemInfo* target) { - int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data(); + int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data(); auto* item = &g_Level.Items[creature->ItemNumber]; auto* room = &g_Level.Rooms[item->RoomNumber]; @@ -447,12 +447,13 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) short top; auto* item = &g_Level.Items[itemNumber]; - if (!item->Data) + + if (!item->IsCreature()) return false; auto* creature = GetCreatureInfo(item); auto* LOT = &creature->LOT; - int* zone = g_Level.Zones[LOT->Zone][FlipStatus].data(); + int* zone = g_Level.Zones[(int)LOT->Zone][FlipStatus].data(); int boxHeight; if (item->BoxNumber != NO_BOX) @@ -460,7 +461,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) else boxHeight = item->Floor; - auto old = item->Pose.Position; + auto prevPos = item->Pose.Position; AnimateItem(item); @@ -475,7 +476,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) int y = item->Pose.Position.y + bounds->Y1; short roomNumber = item->RoomNumber; - GetFloor(old.x, y, old.z, &roomNumber); + GetFloor(prevPos.x, y, prevPos.z, &roomNumber); FloorInfo* floor = GetFloor(item->Pose.Position.x, y, item->Pose.Position.z, &roomNumber); // TODO: Check why some blocks have box = -1 assigned to them -- Lwmte, 10.11.21 @@ -504,18 +505,18 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) { xPos = item->Pose.Position.x / SECTOR(1); zPos = item->Pose.Position.z / SECTOR(1); - shiftX = old.x / SECTOR(1); - shiftZ = old.z / SECTOR(1); + shiftX = prevPos.x / SECTOR(1); + shiftZ = prevPos.z / SECTOR(1); if (xPos < shiftX) - item->Pose.Position.x = old.x & (~(SECTOR(1) - 1)); + item->Pose.Position.x = prevPos.x & (~WALL_MASK); else if (xPos > shiftX) - item->Pose.Position.x = old.x | (SECTOR(1) - 1); + item->Pose.Position.x = prevPos.x | WALL_MASK; if (zPos < shiftZ) - item->Pose.Position.z = old.z & (~(SECTOR(1) - 1)); + item->Pose.Position.z = prevPos.z & (~WALL_MASK); else if (zPos > shiftZ) - item->Pose.Position.z = old.z | (SECTOR(1) - 1); + item->Pose.Position.z = prevPos.z | (WALL_MASK); floor = GetFloor(item->Pose.Position.x, y, item->Pose.Position.z, &roomNumber); height = g_Level.Boxes[floor->Box].height; @@ -536,8 +537,8 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) int x = item->Pose.Position.x; int z = item->Pose.Position.z; - xPos = x & (SECTOR(1) - 1); - zPos = z & (SECTOR(1) - 1); + xPos = x & WALL_MASK; + zPos = z & WALL_MASK; short radius = Objects[item->ObjectNumber].radius; shiftX = 0; shiftZ = 0; @@ -667,8 +668,8 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) { if (item->Pose.Position.y + top < ceiling) { - item->Pose.Position.x = old.x; - item->Pose.Position.z = old.z; + item->Pose.Position.x = prevPos.x; + item->Pose.Position.z = prevPos.z; dy = LOT->Fly; } else @@ -687,13 +688,13 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) } else if (item->Pose.Position.y <= height) { - dy = 0; item->Pose.Position.y = height; + dy = 0; } else { - item->Pose.Position.x = old.x; - item->Pose.Position.z = old.z; + item->Pose.Position.x = prevPos.x; + item->Pose.Position.z = prevPos.z; dy = -LOT->Fly; } @@ -730,11 +731,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) if (item->Pose.Position.y > item->Floor) { if (item->Pose.Position.y > (item->Floor + CLICK(1))) - { - item->Pose.Position.x = old.x; - item->Pose.Position.y = old.y; - item->Pose.Position.z = old.z; - } + item->Pose.Position = prevPos; else item->Pose.Position.y = item->Floor; } @@ -751,11 +748,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) top = bounds->Y1; // TODO: check if Y1 or Y2 if (item->Pose.Position.y + top < ceiling) - { - item->Pose.Position.x = old.x; - item->Pose.Position.z = old.z; - item->Pose.Position.y = old.y; - } + item->Pose.Position = prevPos; floor = GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &roomNumber); item->Floor = GetFloorHeight(floor, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z); @@ -771,7 +764,6 @@ int CreatureAnimation(short itemNumber, short angle, short tilt) } CreatureSwitchRoom(itemNumber); - return true; } @@ -890,7 +882,7 @@ int ValidBox(ItemInfo* item, short zoneNumber, short boxNumber) return false; auto* creature = GetCreatureInfo(item); - int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data(); + int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data(); if (creature->LOT.Fly == NO_FLYING && zone[boxNumber] != zoneNumber) return false; @@ -976,7 +968,7 @@ int UpdateLOT(LOTInfo* LOT, int depth) int SearchLOT(LOTInfo* LOT, int depth) { - int* zone = g_Level.Zones[LOT->Zone][FlipStatus].data(); + int* zone = g_Level.Zones[(int)LOT->Zone][FlipStatus].data(); int searchZone = zone[LOT->Head]; if (depth <= 0) @@ -1090,7 +1082,7 @@ int CreatureActive(short itemNumber) if (item->Flags & IFLAG_KILLED) return false; // Object is already dead - if (item->Status == ITEM_INVISIBLE || !item->Data.is()) + if (item->Status == ITEM_INVISIBLE || !item->IsCreature()) { if (!EnableEntityAI(itemNumber, 0)) return false; // AI couldn't be activated @@ -1168,7 +1160,7 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift) vault = 0; else if (item->Floor > y + CHECK_CLICK(7)) vault = -4; - // FIXME: edit assets adding climb down animations for Von Croy and baddys? + // FIXME: edit assets adding climb down animations for Von Croy and baddies? else if (item->Floor > y + CHECK_CLICK(5) && item->ObjectNumber != ID_VON_CROY && item->ObjectNumber != ID_BADDY1 && @@ -1373,7 +1365,7 @@ void FindAITargetObject(CreatureInfo* creature, short objectNumber) if (g_Level.AIObjects.size() > 0) { - AI_OBJECT* foundObject = NULL; + AI_OBJECT* foundObject = nullptr; for (int i = 0; i < g_Level.AIObjects.size(); i++) { @@ -1381,7 +1373,7 @@ void FindAITargetObject(CreatureInfo* creature, short objectNumber) if (aiObject->objectNumber == objectNumber && aiObject->triggerFlags == item->ItemFlags[3] && aiObject->roomNumber != NO_ROOM) { - int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data(); + int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data(); auto* room = &g_Level.Rooms[item->RoomNumber]; item->BoxNumber = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z)->Box; @@ -1400,7 +1392,7 @@ void FindAITargetObject(CreatureInfo* creature, short objectNumber) } } - if (foundObject != NULL) + if (foundObject != nullptr) { auto* aiItem = creature->AITarget; @@ -1441,7 +1433,7 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI) creature->Enemy = LaraItem; } - int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data(); + int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data(); auto* room = &g_Level.Rooms[item->RoomNumber]; item->BoxNumber = NO_BOX; @@ -1463,8 +1455,8 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI) // This prevents enemies from running to Lara and attacking nothing when she is hanging or shimmying. -- Lwmte, 27.06.22 bool reachable = false; - if (object->zoneType == ZoneType::ZONE_FLYER || - (object->zoneType == ZoneType::ZONE_WATER && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, item->RoomNumber))) + if (object->ZoneType == ZoneType::Flyer || + (object->ZoneType == ZoneType::Water && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, item->RoomNumber))) { reachable = true; // If NPC is flying or swimming in water, always reach Lara } diff --git a/TombEngine/Game/control/lot.cpp b/TombEngine/Game/control/lot.cpp index 712558575..83cf70a2d 100644 --- a/TombEngine/Game/control/lot.cpp +++ b/TombEngine/Game/control/lot.cpp @@ -112,15 +112,15 @@ void DisableEntityAI(short itemNumber) item->Data = nullptr; } -void InitialiseSlot(short itemNum, short slot, bool makeTarget) +void InitialiseSlot(short itemNumber, short slot, bool makeTarget) { - auto* item = &g_Level.Items[itemNum]; - auto* obj = &Objects[item->ObjectNumber]; - + auto* item = &g_Level.Items[itemNumber]; + auto* object = &Objects[item->ObjectNumber]; item->Data = CreatureInfo(); auto* creature = GetCreatureInfo(item); - InitialiseLOTarray(itemNum); - creature->ItemNumber = itemNum; + + InitialiseLOTarray(itemNumber); + creature->ItemNumber = itemNumber; creature->Mood = MoodType::Bored; creature->JointRotation[0] = 0; creature->JointRotation[1] = 0; @@ -136,12 +136,12 @@ void InitialiseSlot(short itemNum, short slot, bool makeTarget) creature->MonkeySwingAhead = false; creature->LOT.CanJump = false; creature->LOT.CanMonkey = false; - creature->LOT.IsAmphibious = false; // only the crocodile can go water and land. (default: true) + creature->LOT.IsAmphibious = false; // True for crocodile by default as the only the crocodile that can move in water and on land. creature->LOT.IsJumping = false; creature->LOT.IsMonkeying = false; creature->MaxTurn = ANGLE(1); creature->Flags = 0; - creature->Enemy = NULL; + creature->Enemy = nullptr; creature->LOT.Fly = NO_FLYING; creature->LOT.BlockMask = BLOCKED; @@ -155,117 +155,116 @@ void InitialiseSlot(short itemNum, short slot, bool makeTarget) else creature->AITarget = nullptr; - switch (obj->zoneType) + switch (object->ZoneType) { default: - case ZONE_NULL: + case ZoneType::None: creature->LOT.Step = CLICK(1); creature->LOT.Drop = -CLICK(1); - obj->zoneType = ZONE_BASIC; // only entity that use CreatureActive() will reach InitialiseSlot() ! + object->ZoneType = ZoneType::Basic; // Only entities that use CreatureActive() will reach InitialiseSlot(). break; - case ZONE_SKELLY: - // Can jump + // Can jump. + case ZoneType::Skeleton: creature->LOT.Step = CLICK(1); creature->LOT.Drop = -CLICK(1); creature->LOT.CanJump = true; - creature->LOT.Zone = ZONE_SKELLY; + creature->LOT.Zone = ZoneType::Skeleton; break; - case ZONE_BASIC: + case ZoneType::Basic: creature->LOT.Step = CLICK(1); creature->LOT.Drop = -CLICK(1); - creature->LOT.Zone = ZONE_BASIC; + creature->LOT.Zone = ZoneType::Basic; break; - case ZONE_FLYER: - // Can fly + // Can fly. + case ZoneType::Flyer: creature->LOT.Step = SECTOR(20); creature->LOT.Drop = -SECTOR(20); creature->LOT.Fly = DEFAULT_FLY_UPDOWN_SPEED; - creature->LOT.Zone = ZONE_FLYER; + creature->LOT.Zone = ZoneType::Flyer; break; - case ZONE_WATER: - // Can swim + // Can swim. + case ZoneType::Water: creature->LOT.Step = SECTOR(20); creature->LOT.Drop = -SECTOR(20); - creature->LOT.Zone = ZONE_WATER; + creature->LOT.Zone = ZoneType::Water; if (item->ObjectNumber == ID_CROCODILE) { - creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED / 2; // is more slow than the other underwater entity - creature->LOT.IsAmphibious = true; // crocodile can walk and swim. + creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED / 2; // Slower than the other underwater creatures. + creature->LOT.IsAmphibious = true; // Can walk and swim. } else if (item->ObjectNumber == ID_BIG_RAT) { - creature->LOT.Fly = NO_FLYING; // dont want the bigrat to be able to go in water (just the surface !) - creature->LOT.IsAmphibious = true; // bigrat can walk and swim. + creature->LOT.Fly = NO_FLYING; // Can't swim underwater, only on the surface. + creature->LOT.IsAmphibious = true; // Can walk and swim. } else - { creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED; - } + break; - case ZONE_HUMAN_CLASSIC: - // Can climb + // Can climb. + case ZoneType::HumanClassic: creature->LOT.Step = SECTOR(1); creature->LOT.Drop = -SECTOR(1); - creature->LOT.Zone = ZONE_HUMAN_CLASSIC; + creature->LOT.Zone = ZoneType::HumanClassic; break; - case ZONE_HUMAN_JUMP: - // Can climb and jump + // Can climb and jump. + case ZoneType::HumanJump: creature->LOT.Step = SECTOR(1); creature->LOT.Drop = -SECTOR(1); creature->LOT.CanJump = true; - creature->LOT.Zone = ZONE_HUMAN_CLASSIC; + creature->LOT.Zone = ZoneType::HumanClassic; break; - case ZONE_HUMAN_JUMP_AND_MONKEY: - // Can climb, jump, monkey + // Can climb, jump, monkeyswing. + case ZoneType::HumanJumpAndMonkey: creature->LOT.Step = SECTOR(1); creature->LOT.Drop = -SECTOR(1); creature->LOT.CanJump = true; creature->LOT.CanMonkey = true; - creature->LOT.Zone = ZONE_HUMAN_CLASSIC; + creature->LOT.Zone = ZoneType::HumanClassic; break; - case ZONE_HUMAN_LONGJUMP_AND_MONKEY: - // Can climb, jump, monkey, long jump + // Can climb, jump, monkey swing, long jump. + case ZoneType::HumanLongJumpAndMonkey: creature->LOT.Step = SECTOR(1) + CLICK(3); creature->LOT.Drop = -(SECTOR(1) + CLICK(3)); creature->LOT.CanJump = true; creature->LOT.CanMonkey = true; - creature->LOT.Zone = ZONE_VON_CROY; + creature->LOT.Zone = ZoneType::VonCroy; break; - case ZONE_SPIDER: + case ZoneType::Spider: creature->LOT.Step = SECTOR(1) - CLICK(2); creature->LOT.Drop = -(SECTOR(1) - CLICK(2)); - creature->LOT.Zone = ZONE_HUMAN_CLASSIC; + creature->LOT.Zone = ZoneType::HumanClassic; break; - case ZONE_BLOCKABLE: + case ZoneType::Blockable: creature->LOT.BlockMask = BLOCKABLE; - creature->LOT.Zone = ZONE_BASIC; + creature->LOT.Zone = ZoneType::Basic; break; - case ZONE_APE: + case ZoneType::Ape: creature->LOT.Step = CLICK(2); creature->LOT.Drop = -SECTOR(1); break; - case ZONE_SOPHIALEE: + case ZoneType::SophiaLee: creature->LOT.Step = SECTOR(1); creature->LOT.Drop = -CLICK(3); - creature->LOT.Zone = ZONE_HUMAN_CLASSIC; + creature->LOT.Zone = ZoneType::HumanClassic; break; } ClearLOT(&creature->LOT); - if (itemNum != Lara.ItemNumber) + if (itemNumber != Lara.ItemNumber) CreateZone(item); SlotsUsed++; @@ -304,16 +303,16 @@ void ClearLOT(LOTInfo* LOT) void CreateZone(ItemInfo* item) { auto* creature = GetCreatureInfo(item); - auto* r = &g_Level.Rooms[item->RoomNumber]; + auto* room = &g_Level.Rooms[item->RoomNumber]; - item->BoxNumber = GetSector(r, item->Pose.Position.x - r->x, item->Pose.Position.z - r->z)->Box; + item->BoxNumber = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z)->Box; if (creature->LOT.Fly) { - BOX_NODE* node = creature->LOT.Node.data(); + auto* node = creature->LOT.Node.data(); creature->LOT.ZoneCount = 0; - for (int i = 0; i < g_Level.Boxes.size(); i++) + for (size_t i = 0; i < g_Level.Boxes.size(); i++) { node->boxNumber = i; node++; @@ -322,8 +321,8 @@ void CreateZone(ItemInfo* item) } else { - int* zone = g_Level.Zones[creature->LOT.Zone][0].data(); - int* flippedZone = g_Level.Zones[creature->LOT.Zone][1].data(); + int* zone = g_Level.Zones[(int)creature->LOT.Zone][0].data(); + int* flippedZone = g_Level.Zones[(int)creature->LOT.Zone][1].data(); int zoneNumber = zone[item->BoxNumber]; int flippedZoneNumber = flippedZone[item->BoxNumber]; @@ -331,7 +330,7 @@ void CreateZone(ItemInfo* item) auto* node = creature->LOT.Node.data(); creature->LOT.ZoneCount = 0; - for (int i = 0; i < g_Level.Boxes.size(); i++) + for (size_t i = 0; i < g_Level.Boxes.size(); i++) { if (*zone == zoneNumber || *flippedZone == flippedZoneNumber) { diff --git a/TombEngine/Game/control/trigger.cpp b/TombEngine/Game/control/trigger.cpp index ec97fd506..ee5e38f49 100644 --- a/TombEngine/Game/control/trigger.cpp +++ b/TombEngine/Game/control/trigger.cpp @@ -56,6 +56,7 @@ int TriggerActive(ItemInfo* item) flag = !flag; } } + return flag; } diff --git a/TombEngine/Game/itemdata/creature_info.h b/TombEngine/Game/itemdata/creature_info.h index 7d9ba96d7..ffa76e87f 100644 --- a/TombEngine/Game/itemdata/creature_info.h +++ b/TombEngine/Game/itemdata/creature_info.h @@ -1,7 +1,8 @@ #pragma once -#include #include "Math/Math.h" +using std::vector; + struct ItemInfo; struct BOX_NODE @@ -12,34 +13,37 @@ struct BOX_NODE int boxNumber; }; -enum ZoneType : char +enum class ZoneType { - ZONE_NULL = -1, // default zone - ZONE_SKELLY = 0, - ZONE_BASIC, - ZONE_FLYER, - ZONE_HUMAN_CLASSIC, - ZONE_VON_CROY, - ZONE_WATER, - ZONE_MAX, - /// custom zone (using zone above for LOT.zone): - ZONE_HUMAN_JUMP_AND_MONKEY, - ZONE_HUMAN_JUMP, - ZONE_SPIDER, - ZONE_BLOCKABLE, // for trex, shiva, etc.. - ZONE_SOPHIALEE, // dont want sophia to go down again ! - ZONE_APE, // only 2 click climb - ZONE_HUMAN_LONGJUMP_AND_MONKEY, + None = -1, + Skeleton, + Basic, + Flyer, + HumanClassic, + VonCroy, + Water, + Max, + + // Custom zones (above zones are used for LOT.zone): + HumanJumpAndMonkey, + HumanJump, + Spider, + Blockable, // For large creatures such as trex and shiva. + SophiaLee, // Prevents Sophia from going to lower levels again. + Ape, // Only 0.5 block climb. + HumanLongJumpAndMonkey, }; struct LOTInfo { bool Initialised; - std::vector Node; + vector Node; int Head; int Tail; + ZoneType Zone = ZoneType::None; + Vector3i Target = Vector3i::Zero; int SearchNumber; int BlockMask; short Step; @@ -49,18 +53,16 @@ struct LOTInfo int RequiredBox; short Fly; - bool CanJump; - bool CanMonkey; - bool IsJumping; - bool IsMonkeying; - bool IsAmphibious; - - Vector3i Target; - ZoneType Zone; + bool CanJump = false; + bool CanMonkey = false; + bool IsJumping = false; + bool IsMonkeying = false; + bool IsAmphibious = false; }; enum class MoodType { + None, Bored, Attack, Escape, @@ -70,45 +72,43 @@ enum class MoodType enum class CreatureAIPriority { None, - High, + Low, Medium, - Low + High }; struct CreatureInfo { - short ItemNumber; + short ItemNumber = -1; - short MaxTurn; - short JointRotation[4]; - bool HeadLeft; - bool HeadRight; + LOTInfo LOT = {}; + MoodType Mood = MoodType::None; + ItemInfo* Enemy = nullptr; + ItemInfo* AITarget = nullptr; + short AITargetNumber = -1; + Vector3i Target = Vector3i::Zero; - bool Patrol; // Unused? - bool Alerted; - bool Friendly; - bool HurtByLara; - bool Poisoned; - bool JumpAhead; - bool MonkeySwingAhead; - bool ReachedGoal; + short MaxTurn = 0; + short JointRotation[4] = {}; + bool HeadLeft = false; + bool HeadRight = false; + bool Patrol = false; // Unused? + bool Alerted = false; + bool Friendly = false; + bool HurtByLara = false; + bool Poisoned = false; + bool JumpAhead = false; + bool MonkeySwingAhead = false; + bool ReachedGoal = false; + + short FiredWeapon; short Tosspad; short LocationAI; - short FiredWeapon; - - LOTInfo LOT; - MoodType Mood; - ItemInfo* Enemy; - short AITargetNumber; - ItemInfo* AITarget; - short Pad; // Unused? - Vector3i Target; + short Flags = 0; #ifdef CREATURE_AI_PRIORITY_OPTIMIZATION - CreatureAIPriority Priority; - size_t FramesSinceLOTUpdate; + CreatureAIPriority Priority = CreatureAIPriority::None; + size_t FramesSinceLOTUpdate = 0; #endif - - short Flags; }; diff --git a/TombEngine/Game/itemdata/itemdata.h b/TombEngine/Game/itemdata/itemdata.h index 1aca59b62..0b5b397ab 100644 --- a/TombEngine/Game/itemdata/itemdata.h +++ b/TombEngine/Game/itemdata/itemdata.h @@ -26,7 +26,7 @@ template struct visitor : Ts... { using Ts::operator()...; }; template visitor(Ts...)->visitor; // line not needed in C++20... using namespace TEN::Entities::TR4; -using namespace TEN::Entities::TR5; +using namespace TEN::Entities::Creatures::TR5; using namespace TEN::Entities::Vehicles; struct ItemInfo; diff --git a/TombEngine/Game/missile.cpp b/TombEngine/Game/missile.cpp index c12ae482e..85c0021ab 100644 --- a/TombEngine/Game/missile.cpp +++ b/TombEngine/Game/missile.cpp @@ -57,7 +57,7 @@ void ControlMissile(short fxNumber) fx->pos.Position.x += velocity * phd_sin(fx->pos.Orientation.y); auto probe = GetCollision(fx->pos.Position.x, fx->pos.Position.y, fx->pos.Position.z, fx->roomNumber); - auto hitLara = ItemNearLara(&fx->pos, 200); + auto hitLara = ItemNearLara(&fx->pos.Position, 200); // Check for hitting something. if (fx->pos.Position.y >= probe.Position.Floor || diff --git a/TombEngine/Game/people.cpp b/TombEngine/Game/people.cpp index 8c5a996f8..6e9b9eda8 100644 --- a/TombEngine/Game/people.cpp +++ b/TombEngine/Game/people.cpp @@ -17,45 +17,45 @@ bool ShotLara(ItemInfo* item, AI_INFO* AI, BiteInfo gun, short extraRotation, in auto* creature = GetCreatureInfo(item); auto* enemy = creature->Enemy; - bool hit = false; - bool targetable = false; + bool hasHit = false; + bool isTargetable = false; - if (AI->distance <= pow(MAX_VISIBILITY_DISTANCE, 2) && Targetable(item, AI)) + if (AI->distance <= SQUARE(MAX_VISIBILITY_DISTANCE) && Targetable(item, AI)) { int distance = phd_sin(AI->enemyFacing) * enemy->Animation.Velocity.z * pow(MAX_VISIBILITY_DISTANCE, 2) / 300; - distance = pow(distance, 2) + AI->distance; - if (distance <= pow(MAX_VISIBILITY_DISTANCE, 2)) + distance = SQUARE(distance) + AI->distance; + if (distance <= SQUARE(MAX_VISIBILITY_DISTANCE)) { - int random = (pow(MAX_VISIBILITY_DISTANCE, 2) - AI->distance) / (pow(MAX_VISIBILITY_DISTANCE, 2) / 0x5000) + 8192; - hit = GetRandomControl() < random; + int random = (SQUARE(MAX_VISIBILITY_DISTANCE) - AI->distance) / (SQUARE(MAX_VISIBILITY_DISTANCE) / 0x5000) + 8192; + hasHit = GetRandomControl() < random; } else - hit = false; + hasHit = false; - targetable = true; + isTargetable = true; } else { - hit = false; - targetable = false; + hasHit = false; + isTargetable = false; } if (damage) { if (enemy->IsLara()) { - if (hit) + if (hasHit) { DoDamage(enemy, damage); CreatureEffect(item, gun, &GunHit); } - else if (targetable) + else if (isTargetable) CreatureEffect(item, gun, &GunMiss); } else { CreatureEffect(item, gun, &GunShot); - if (hit) + if (hasHit) { enemy->HitStatus = true; enemy->HitPoints += damage / -10; @@ -72,7 +72,7 @@ bool ShotLara(ItemInfo* item, AI_INFO* AI, BiteInfo gun, short extraRotation, in // TODO: smash objects - return targetable; + return isTargetable; } short GunMiss(int x, int y, int z, short velocity, short yRot, short roomNumber) @@ -141,32 +141,32 @@ bool TargetVisible(ItemInfo* item, AI_INFO* AI, float maxAngle) return false; // Check just in case. - auto* creatureInfo = GetCreatureInfo(item); - if (creatureInfo == nullptr) + auto* creature = GetCreatureInfo(item); + if (creature == nullptr) return false; - auto* enemy = creatureInfo->Enemy; + auto* enemy = creature->Enemy; if (enemy == nullptr || enemy->HitPoints == 0) return false; - short angle = AI->angle - creatureInfo->JointRotation[2]; - if (angle > -ANGLE(maxAngle) && angle < ANGLE(maxAngle)) + short angle = AI->angle - creature->JointRotation[2]; + if (angle > ANGLE(-maxAngle) && angle < ANGLE(maxAngle)) { - GameVector start; - GameVector target; auto& bounds = GetBestFrame(enemy)->boundingBox; - start.x = item->Pose.Position.x; - start.y = item->Pose.Position.y - CLICK(3); - start.z = item->Pose.Position.z; - start.roomNumber = item->RoomNumber; - - target.x = enemy->Pose.Position.x; - target.y = enemy->Pose.Position.y + ((((bounds.Y1 * 2) + bounds.Y1) + bounds.Y2) / 4); - target.z = enemy->Pose.Position.z; - target.roomNumber = enemy->RoomNumber; // TODO: Check why this line didn't exist before. -- TokyoSU, 10/8/2022 - - return LOS(&start, &target); + auto origin = GameVector( + item->Pose.Position.x, + item->Pose.Position.y - CLICK(3), + item->Pose.Position.z, + item->RoomNumber + ); + auto target = GameVector( + enemy->Pose.Position.x, + enemy->Pose.Position.y + ((((bounds.Y1 * 2) + bounds.Y1) + bounds.Y2) / 4), + enemy->Pose.Position.z, + enemy->RoomNumber // TODO: Check why this line didn't exist before. -- TokyoSU, 10/8/2022 + ); + return LOS(&origin, &target); } return false; diff --git a/TombEngine/Game/savegame.cpp b/TombEngine/Game/savegame.cpp index c78cfb51c..ca8988d72 100644 --- a/TombEngine/Game/savegame.cpp +++ b/TombEngine/Game/savegame.cpp @@ -1093,11 +1093,11 @@ bool SaveGame::Save(int slot) putDataInVec(Save::VarUnion::funcName, funcNameOffset); } - else if (std::holds_alternative(s)) + else if (std::holds_alternative(s)) { Save::vec3TableBuilder vtb{ fbb }; - Vector3Int data = std::get(s); - Save::Vector3 saveVec = FromVector3(std::get(s)); + Vector3i data = std::get(s); + Save::Vector3 saveVec = FromVector3(std::get(s)); vtb.add_vec(&saveVec); auto vec3Offset = vtb.Finish(); @@ -1934,7 +1934,7 @@ bool SaveGame::Load(int slot) } else if (var->u_type() == Save::VarUnion::vec3) { - loadedVars.push_back(ToVector3Int(var->u_as_vec3()->vec())); + loadedVars.push_back(ToVector3i(var->u_as_vec3()->vec())); } else if (var->u_type() == Save::VarUnion::funcName) { diff --git a/TombEngine/Objects/Effects/enemy_missile.cpp b/TombEngine/Objects/Effects/enemy_missile.cpp index 458c53aa2..d31b5ed34 100644 --- a/TombEngine/Objects/Effects/enemy_missile.cpp +++ b/TombEngine/Objects/Effects/enemy_missile.cpp @@ -260,7 +260,7 @@ namespace TEN::Entities::Effects return; } - if (ItemNearLara(&fx->pos, 200)) + if (ItemNearLara(&fx->pos.Position, 200)) { LaraItem->HitStatus = true; if (fx->flag1 != 6) diff --git a/TombEngine/Objects/Effects/flame_emitters.cpp b/TombEngine/Objects/Effects/flame_emitters.cpp index 8aee17b03..064c44fa6 100644 --- a/TombEngine/Objects/Effects/flame_emitters.cpp +++ b/TombEngine/Objects/Effects/flame_emitters.cpp @@ -154,7 +154,7 @@ namespace TEN::Entities::Effects SoundEffect(SFX_TR4_LOOP_FOR_SMALL_FIRES, &item->Pose); if (!Lara.Burn && - ItemNearLara(&item->Pose, 600) && + ItemNearLara(&item->Pose.Position, 600) && (pow(LaraItem->Pose.Position.x - item->Pose.Position.x, 2) + pow(LaraItem->Pose.Position.z - item->Pose.Position.z, 2) < pow(SECTOR(0.5f), 2)) && Lara.Control.WaterStatus != WaterStatus::FlyCheat) @@ -561,8 +561,7 @@ namespace TEN::Entities::Effects TriggerDynamicLight(x, item->Pose.Position.y, z, 12, (GetRandomControl() & 0x3F) + 192, ((GetRandomControl() >> 4) & 0x1F) + 96, 0); - auto pos = PoseData(item->Pose.Position); - + auto pos = item->Pose.Position; if (ItemNearLara(&pos, 600)) { if ((!Lara.Burn) && Lara.Control.WaterStatus != WaterStatus::FlyCheat) diff --git a/TombEngine/Objects/Effects/tr4_locusts.cpp b/TombEngine/Objects/Effects/tr4_locusts.cpp index 448cd71ef..898ae6b1c 100644 --- a/TombEngine/Objects/Effects/tr4_locusts.cpp +++ b/TombEngine/Objects/Effects/tr4_locusts.cpp @@ -186,7 +186,7 @@ namespace TEN::Entities::TR4 locust->pos.Position.y += locust->randomRotation * phd_sin(-locust->pos.Orientation.x); locust->pos.Position.z += locust->randomRotation * phd_cos(locust->pos.Orientation.x) * phd_cos(locust->pos.Orientation.y); - if (ItemNearTarget(&locust->pos, LaraItem, CLICK(1) / 2)) + if (ItemNearTarget(&locust->pos.Position, LaraItem, CLICK(1) / 2)) { TriggerBlood(locust->pos.Position.x, locust->pos.Position.y, locust->pos.Position.z, 2 * GetRandomControl(), 2); DoDamage(LaraItem, LOCUST_LARA_DAMAGE); diff --git a/TombEngine/Objects/TR1/Entity/tr1_ape.cpp b/TombEngine/Objects/TR1/Entity/tr1_ape.cpp index 894174239..bb5ac3452 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_ape.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_ape.cpp @@ -15,19 +15,23 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { constexpr auto APE_ATTACK_DAMAGE = 200; constexpr auto APE_ATTACK_RANGE = SQUARE(SECTOR(0.42f)); constexpr auto APE_PANIC_RANGE = SQUARE(SECTOR(2)); - constexpr auto APE_JUMP_CHANCE = 0xA0; - constexpr auto APE_POUND_CHEST_CHANCE = APE_JUMP_CHANCE + 0xA0; - constexpr auto APE_POUND_GROUND_CHANCE = APE_POUND_CHEST_CHANCE + 0xA0; - constexpr auto APE_RUN_LEFT_CHANCE = APE_POUND_GROUND_CHANCE + 0xA0; + constexpr auto APE_IDLE_JUMP_CHANCE = 1.0f / 6; + constexpr auto APE_IDLE_POUND_CHEST_CHANCE = 1.0f / 3; + constexpr auto APE_IDLE_POUND_GROUND_CHANCE = 1.0f / 2; + constexpr auto APE_IDLE_RUN_LEFT_CHANCE = 1.0f / 2; + constexpr auto APE_RUN_JUMP_CHANCE = APE_IDLE_JUMP_CHANCE / 32; + constexpr auto APE_RUN_POUND_CHEST_CHANCE = APE_IDLE_POUND_CHEST_CHANCE / 32; + constexpr auto APE_RUN_POUND_GROUND_CHANCE = APE_IDLE_POUND_GROUND_CHANCE / 32; + constexpr auto APE_RUN_RUN_LEFT_CHANCE = APE_IDLE_RUN_LEFT_CHANCE / 32; - constexpr auto SHIFT = 75; + constexpr auto APE_SHIFT = 75; #define APE_RUN_TURN_RATE_MAX ANGLE(5.0f) #define APE_DISPLAY_ANGLE ANGLE(45.0f) @@ -118,12 +122,12 @@ namespace TEN::Entities::TR1 if (yy < yFloor) { - item->Pose.Position.x = (yFloor * SECTOR(1)) - SHIFT; + item->Pose.Position.x = (yFloor * SECTOR(1)) - APE_SHIFT; item->Pose.Orientation.y = ANGLE(90.0f); } else { - item->Pose.Position.x = (yy * SECTOR(1)) + SHIFT; + item->Pose.Position.x = (yy * SECTOR(1)) + APE_SHIFT; item->Pose.Orientation.y = -ANGLE(90.0f); } } @@ -131,12 +135,12 @@ namespace TEN::Entities::TR1 { if (xx < xFloor) { - item->Pose.Position.z = (xFloor * SECTOR(1)) - SHIFT; + item->Pose.Position.z = (xFloor * SECTOR(1)) - APE_SHIFT; item->Pose.Orientation.y = 0; } else { - item->Pose.Position.z = (xx * SECTOR(1)) + SHIFT; + item->Pose.Position.z = (xx * SECTOR(1)) + APE_SHIFT; item->Pose.Orientation.y = -ANGLE(180.0f); } } @@ -145,7 +149,7 @@ namespace TEN::Entities::TR1 // diagonal } - if (CreatureVault(itemNumber, angle, 2, SHIFT) == 2) + if (CreatureVault(itemNumber, angle, 2, APE_SHIFT) == 2) { item->Pose.Position.y = y; SetAnimation(item, APE_ANIM_VAULT); @@ -184,8 +188,6 @@ namespace TEN::Entities::TR1 if (item->HitStatus || AI.distance < APE_PANIC_RANGE) creatureInfo->Flags |= APE_FLAG_ATTACK; - short random; - switch (item->Animation.ActiveState) { case APE_STATE_IDLE: @@ -207,14 +209,13 @@ namespace TEN::Entities::TR1 else if (!(creatureInfo->Flags & APE_FLAG_ATTACK) && AI.zoneNumber == AI.enemyZone && AI.ahead) { - random = (short)(GetRandomControl() / 32); - if (random < APE_JUMP_CHANCE) + if (TestProbability(APE_IDLE_JUMP_CHANCE)) item->Animation.TargetState = APE_STATE_JUMP; - else if (random < APE_POUND_CHEST_CHANCE) + else if (TestProbability(APE_IDLE_POUND_CHEST_CHANCE)) item->Animation.TargetState = APE_STATE_POUND_CHEST; - else if (random < APE_POUND_GROUND_CHANCE) + else if (TestProbability(APE_IDLE_POUND_GROUND_CHANCE)) item->Animation.TargetState = APE_STATE_POUND_GROUND; - else if (random < APE_RUN_LEFT_CHANCE) + else if (TestProbability(APE_IDLE_RUN_LEFT_CHANCE)) { item->Animation.TargetState = APE_STATE_RUN_LEFT; creatureInfo->MaxTurn = 0; @@ -246,18 +247,17 @@ namespace TEN::Entities::TR1 } else if (creatureInfo->Mood != MoodType::Escape) { - random = (short)GetRandomControl(); - if (random < APE_JUMP_CHANCE) + if (TestProbability(APE_RUN_JUMP_CHANCE)) { item->Animation.RequiredState = APE_STATE_JUMP; item->Animation.TargetState = APE_STATE_IDLE; } - else if (random < APE_POUND_CHEST_CHANCE) + else if (TestProbability(APE_RUN_POUND_CHEST_CHANCE)) { item->Animation.RequiredState = APE_STATE_POUND_CHEST; item->Animation.TargetState = APE_STATE_IDLE; } - else if (random < APE_POUND_GROUND_CHANCE) + else if (TestProbability(APE_RUN_POUND_GROUND_CHANCE)) { item->Animation.RequiredState = APE_STATE_POUND_GROUND; item->Animation.TargetState = APE_STATE_IDLE; diff --git a/TombEngine/Objects/TR1/Entity/tr1_ape.h b/TombEngine/Objects/TR1/Entity/tr1_ape.h index 9edc287ab..081f18fdf 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_ape.h +++ b/TombEngine/Objects/TR1/Entity/tr1_ape.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void ApeControl(short itemNumber); } diff --git a/TombEngine/Objects/TR1/Entity/tr1_bear.cpp b/TombEngine/Objects/TR1/Entity/tr1_bear.cpp index 0038f9e06..025f98eb0 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_bear.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_bear.cpp @@ -11,9 +11,10 @@ #include "Specific/level.h" #include "Specific/setup.h" +using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { constexpr auto BEAR_RUN_DAMAGE = 3; constexpr auto BEAR_ATTACK_DAMAGE = 200; @@ -24,10 +25,10 @@ namespace TEN::Entities::TR1 constexpr auto BEAR_REAR_RANGE = SECTOR(2); constexpr auto BEAR_REAR_SWIPE_ATTACK_RANGE = SECTOR(0.6f); constexpr auto BEAR_EAT_RANGE = CLICK(3); - - constexpr auto BEAR_ROAR_CHANCE = 0x50; - constexpr auto BEAR_REAR_CHANCE = 0x300; - constexpr auto BEAR_DROP_CHANCE = 0x600; + + constexpr auto BEAR_ROAR_CHANCE = 1.0f / 400; + constexpr auto BEAR_REAR_CHANCE = 1.0f / 40; + constexpr auto BEAR_DROP_CHANCE = 1.0f / 22; #define BEAR_WALK_TURN_RATE_MAX ANGLE(2.0f) #define BEAR_RUN_TURN_RATE_MAX ANGLE(5.0f) @@ -81,8 +82,8 @@ namespace TEN::Entities::TR1 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; + short head = 0; if (item->HitPoints <= 0) { @@ -117,8 +118,8 @@ namespace TEN::Entities::TR1 { if (creature->Flags && item->TestBits(JointBitType::Touch, BearAttackJoints)) { - creature->Flags = 0; DoDamage(creature->Enemy, BEAR_SLAM_DAMAGE); + creature->Flags = 0; } break; @@ -141,12 +142,12 @@ namespace TEN::Entities::TR1 if (item->HitStatus) creature->Flags = 1; - const bool laraDead = LaraItem->HitPoints <= 0; + bool isLaraDead = LaraItem->HitPoints <= 0; switch (item->Animation.ActiveState) { case BEAR_STATE_IDLE: - if (laraDead) + if (isLaraDead) { if (AI.bite && AI.distance < pow(BEAR_EAT_RANGE, 2)) item->Animation.TargetState = BEAR_STATE_EAT; @@ -165,7 +166,7 @@ namespace TEN::Entities::TR1 case BEAR_STATE_STROLL: creature->MaxTurn = BEAR_WALK_TURN_RATE_MAX; - if (laraDead && item->TestBits(JointBitType::Touch, BearAttackJoints) && AI.ahead) + if (isLaraDead && item->TestBits(JointBitType::Touch, BearAttackJoints) && AI.ahead) item->Animation.TargetState = BEAR_STATE_IDLE; else if (creature->Mood != MoodType::Bored) { @@ -174,10 +175,10 @@ namespace TEN::Entities::TR1 if (creature->Mood == MoodType::Escape) item->Animation.RequiredState = BEAR_STATE_STROLL; } - else if (GetRandomControl() < BEAR_ROAR_CHANCE) + else if (TestProbability(BEAR_ROAR_CHANCE)) { - item->Animation.RequiredState = BEAR_STATE_ROAR; item->Animation.TargetState = BEAR_STATE_IDLE; + item->Animation.RequiredState = BEAR_STATE_ROAR; } break; @@ -186,16 +187,14 @@ namespace TEN::Entities::TR1 creature->MaxTurn = BEAR_RUN_TURN_RATE_MAX; if (item->TestBits(JointBitType::Touch, BearAttackJoints)) - { DoDamage(creature->Enemy, BEAR_RUN_DAMAGE); - } - if (creature->Mood == MoodType::Bored || laraDead) + if (creature->Mood == MoodType::Bored || isLaraDead) item->Animation.TargetState = BEAR_STATE_IDLE; else if (AI.ahead && !item->Animation.RequiredState) { if (AI.distance < pow(BEAR_REAR_RANGE, 2) && - GetRandomControl() < BEAR_REAR_CHANCE && + TestProbability(BEAR_REAR_CHANCE) && !creature->Flags) { item->Animation.RequiredState = BEAR_STATE_REAR; @@ -227,8 +226,8 @@ namespace TEN::Entities::TR1 case BEAR_STATE_WALK_FORWARD: if (creature->Flags) { - item->Animation.RequiredState = BEAR_STATE_STROLL; item->Animation.TargetState = BEAR_STATE_REAR; + item->Animation.RequiredState = BEAR_STATE_STROLL; } else if (AI.ahead && item->TestBits(JointBitType::Touch, BearAttackJoints)) item->Animation.TargetState = BEAR_STATE_REAR; @@ -237,15 +236,15 @@ namespace TEN::Entities::TR1 item->Animation.TargetState = BEAR_STATE_REAR; item->Animation.RequiredState = BEAR_STATE_STROLL; } - else if (creature->Mood == MoodType::Bored || GetRandomControl() < BEAR_ROAR_CHANCE) + else if (creature->Mood == MoodType::Bored || TestProbability(BEAR_ROAR_CHANCE)) { + item->Animation.TargetState = BEAR_STATE_REAR; item->Animation.RequiredState = BEAR_STATE_ROAR; - item->Animation.TargetState = BEAR_STATE_REAR; } - else if (AI.distance > pow(BEAR_REAR_RANGE, 2) || GetRandomControl() < BEAR_DROP_CHANCE) + else if (AI.distance > pow(BEAR_REAR_RANGE, 2) || TestProbability(BEAR_DROP_CHANCE)) { - item->Animation.RequiredState = BEAR_STATE_IDLE; item->Animation.TargetState = BEAR_STATE_REAR; + item->Animation.RequiredState = BEAR_STATE_IDLE; } break; @@ -264,8 +263,8 @@ namespace TEN::Entities::TR1 if (!item->Animation.RequiredState && item->TestBits(JointBitType::Touch, BearAttackJoints)) { - CreatureEffect(item, BearBite, DoBloodSplat); DoDamage(creature->Enemy, BEAR_ATTACK_DAMAGE); + CreatureEffect(item, BearBite, DoBloodSplat); item->Animation.RequiredState = BEAR_STATE_IDLE; } diff --git a/TombEngine/Objects/TR1/Entity/tr1_bear.h b/TombEngine/Objects/TR1/Entity/tr1_bear.h index dcfd85eb9..24107b33d 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_bear.h +++ b/TombEngine/Objects/TR1/Entity/tr1_bear.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void BearControl(short itemNumber); } diff --git a/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp b/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp index 921296140..727d7211a 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp @@ -16,7 +16,7 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { constexpr auto BIG_RAT_BITE_ATTACK_DAMAGE = 20; constexpr auto BIG_RAT_POUNCE_ATTACK_DAMAGE = 25; @@ -27,7 +27,7 @@ namespace TEN::Entities::TR1 constexpr auto BIG_RAT_POUNCE_ATTACK_RANGE = SQUARE(SECTOR(0.5f)); constexpr auto BIG_RAT_WATER_BITE_ATTACK_RANGE = SQUARE(SECTOR(0.3f)); - constexpr auto BIG_RAT_REAR_POSE_CHANCE = 0.008f; + constexpr auto BIG_RAT_REAR_POSE_CHANCE = 1.0f / 128; constexpr auto BIG_RAT_SWIM_UP_DOWN_SPEED = 32; constexpr auto BIG_RAT_WATER_SURFACE_OFFSET = 10; @@ -115,10 +115,11 @@ namespace TEN::Entities::TR1 auto* creature = GetCreatureInfo(item); int waterHeight = GetRatWaterHeight(item); - short head = 0; - short angle = 0; bool isOnWater = waterHeight != NO_HEIGHT; + short angle = 0; + short head = 0; + if (item->HitPoints <= 0) { if (item->Animation.ActiveState != BIG_RAT_STATE_LAND_DEATH && @@ -183,9 +184,9 @@ namespace TEN::Entities::TR1 if (!item->Animation.RequiredState && AI.ahead && item->TestBits(JointBitType::Touch, BigRatBite.meshNum)) { - item->Animation.RequiredState = BIG_RAT_STATE_IDLE; DoDamage(creature->Enemy, BIG_RAT_BITE_ATTACK_DAMAGE); CreatureEffect(item, BigRatBite, DoBloodSplat); + item->Animation.RequiredState = BIG_RAT_STATE_IDLE; } break; @@ -194,9 +195,9 @@ namespace TEN::Entities::TR1 if (!item->Animation.RequiredState && AI.ahead && item->TestBits(JointBitType::Touch, BigRatBite.meshNum)) { - item->Animation.RequiredState = BIG_RAT_STATE_RUN_FORWARD; DoDamage(creature->Enemy, BIG_RAT_POUNCE_ATTACK_DAMAGE); CreatureEffect(item, BigRatBite, DoBloodSplat); + item->Animation.RequiredState = BIG_RAT_STATE_RUN_FORWARD; } break; diff --git a/TombEngine/Objects/TR1/Entity/tr1_big_rat.h b/TombEngine/Objects/TR1/Entity/tr1_big_rat.h index bdf2afe97..d0e38f9a6 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_big_rat.h +++ b/TombEngine/Objects/TR1/Entity/tr1_big_rat.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void InitialiseBigRat(short itemNumber); void BigRatControl(short itemNumber); diff --git a/TombEngine/Objects/TR1/Entity/tr1_centaur.cpp b/TombEngine/Objects/TR1/Entity/tr1_centaur.cpp index 27f76ce0a..25a8e9e53 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_centaur.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_centaur.cpp @@ -17,19 +17,20 @@ #include "Specific/level.h" #include "Specific/setup.h" +using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { - constexpr auto CENTAUR_REAR_DAMAGE = 200; - constexpr auto CENTAUR_REAR_RANGE = SECTOR(1.5f); - constexpr auto CENTAUR_REAR_CHANCE = 0x60; + constexpr auto CENTAUR_REAR_DAMAGE = 200; + constexpr auto CENTAUR_REAR_RANGE = SECTOR(1.5f); + constexpr auto CENTAUR_REAR_CHANCE = 1.0f / 340; constexpr auto CENTAUR_BOMB_VELOCITY = 20; #define CENTAUR_TURN_RATE_MAX ANGLE(4.0f) const auto CentaurRocketBite = BiteInfo(Vector3(11.0f, 415.0f, 41.0f), 13); - const auto CentaurRearBite = BiteInfo(Vector3(50.0f, 30.0f, 0.0f), 5); + const auto CentaurRearBite = BiteInfo(Vector3(50.0f, 30.0f, 0.0f), 5); const vector CentaurAttackJoints = { 0, 3, 4, 7, 8, 16, 17 }; enum CentaurState @@ -56,17 +57,14 @@ namespace TEN::Entities::TR1 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; + short angle = 0; + short head = 0; if (item->HitPoints <= 0) { if (item->Animation.ActiveState != CENTAUR_STATE_DEATH) - { - item->Animation.AnimNumber = Objects[ID_CENTAUR_MUTANT].animIndex + CENTAUR_ANIM_DEATH; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = CENTAUR_STATE_DEATH; - } + SetAnimation(item, CENTAUR_ANIM_DEATH); } else { @@ -98,18 +96,18 @@ namespace TEN::Entities::TR1 case CENTAUR_STATE_RUN_FORWARD: if (AI.bite && AI.distance < pow(CENTAUR_REAR_RANGE, 2)) { - item->Animation.RequiredState = CENTAUR_STATE_WARNING; item->Animation.TargetState = CENTAUR_STATE_IDLE; + item->Animation.RequiredState = CENTAUR_STATE_WARNING; } else if (Targetable(item, &AI)) { + item->Animation.TargetState = CENTAUR_STATE_IDLE; item->Animation.RequiredState = CENTAUR_STATE_AIM; - item->Animation.TargetState = CENTAUR_STATE_IDLE; } - else if (GetRandomControl() < CENTAUR_REAR_CHANCE) + else if (TestProbability(CENTAUR_REAR_CHANCE)) { - item->Animation.RequiredState = CENTAUR_STATE_WARNING; item->Animation.TargetState = CENTAUR_STATE_IDLE; + item->Animation.RequiredState = CENTAUR_STATE_WARNING; } break; @@ -137,8 +135,8 @@ namespace TEN::Entities::TR1 if (!item->Animation.RequiredState && item->TestBits(JointBitType::Touch, CentaurAttackJoints)) { - CreatureEffect(item, CentaurRearBite, DoBloodSplat); DoDamage(creature->Enemy, CENTAUR_REAR_DAMAGE); + CreatureEffect(item, CentaurRearBite, DoBloodSplat); item->Animation.RequiredState = CENTAUR_STATE_IDLE; } diff --git a/TombEngine/Objects/TR1/Entity/tr1_centaur.h b/TombEngine/Objects/TR1/Entity/tr1_centaur.h index ebf3a4984..cf34267d2 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_centaur.h +++ b/TombEngine/Objects/TR1/Entity/tr1_centaur.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { constexpr auto SHARD_VELOCITY = 250; constexpr auto BOMB_VELOCITY = 220; diff --git a/TombEngine/Objects/TR1/Entity/tr1_doppelganger.cpp b/TombEngine/Objects/TR1/Entity/tr1_doppelganger.cpp index 2af343a10..57b2880da 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_doppelganger.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_doppelganger.cpp @@ -14,7 +14,7 @@ // - Bacon Lara cannot be targeted. // - Bacon Lara cannot move like Lara. -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { // Original: void InitialiseDoppelganger(short itemNumber) @@ -80,26 +80,24 @@ namespace TEN::Entities::TR1 int laraFloorHeight = GetCollision(LaraItem).Position.Floor; // Animate bacon Lara, mirroring Lara's position. - item->Animation.FrameNumber = LaraItem->Animation.FrameNumber; item->Animation.AnimNumber = LaraItem->Animation.AnimNumber; - item->Pose.Position.x = pos.x; - item->Pose.Position.y = pos.y; - item->Pose.Position.z = pos.z; + item->Animation.FrameNumber = LaraItem->Animation.FrameNumber; + item->Pose.Position = pos; item->Pose.Orientation.x = LaraItem->Pose.Orientation.x; item->Pose.Orientation.y = LaraItem->Pose.Orientation.y - ANGLE(180.0f); item->Pose.Orientation.z = LaraItem->Pose.Orientation.z; ItemNewRoom(itemNumber, LaraItem->RoomNumber); // Compare floor heights. - if (item->Floor >= laraFloorHeight + SECTOR(1) + 1 && // Add 1 to avoid bacon Lara dying when exiting water. + if (item->Floor >= (laraFloorHeight + SECTOR(1) + 1) && // Add 1 to avoid bacon Lara dying when exiting water. !LaraItem->Animation.IsAirborne) { SetAnimation(item, LA_JUMP_WALL_SMASH_START); - item->Animation.Velocity.z = 0; - item->Animation.Velocity.y = 0; item->Animation.IsAirborne = true; - item->Data = -1; + item->Animation.Velocity.y = 0.0f; + item->Animation.Velocity.z = 0.0f; item->Pose.Position.y += 50; + item->Data = -1; } } @@ -114,8 +112,8 @@ namespace TEN::Entities::TR1 item->Pose.Position.y = item->Floor; TestTriggers(item, true); - item->Animation.Velocity.y = 0; item->Animation.IsAirborne = false; + item->Animation.Velocity.y = 0.0f; item->Animation.TargetState = LS_DEATH; item->Animation.RequiredState = LS_DEATH; } diff --git a/TombEngine/Objects/TR1/Entity/tr1_doppelganger.h b/TombEngine/Objects/TR1/Entity/tr1_doppelganger.h index 0c44a7406..d0b6df5ed 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_doppelganger.h +++ b/TombEngine/Objects/TR1/Entity/tr1_doppelganger.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void InitialiseDoppelganger(short itemNumber); void DoppelgangerControl(short itemNumber); diff --git a/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.cpp b/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.cpp index 7061059ec..3aa6fd345 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.cpp @@ -14,9 +14,10 @@ #include "Specific/level.h" #include "Specific/setup.h" +using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { constexpr auto MUTANT_ATTACK_DAMAGE = 500; constexpr auto MUTANT_CONTACT_DAMAGE = 6; @@ -24,16 +25,17 @@ namespace TEN::Entities::TR1 constexpr auto MUTANT_ATTACK_RANGE = SQUARE(SECTOR(2.5f)); constexpr auto MUTANT_CLOSE_RANGE = SQUARE(SECTOR(2.2f)); - constexpr auto MUTANT_ATTACK_1_CHANCE = 0x2AF8; - constexpr auto MUTANT_ATTACK_2_CHANCE = 0x55F0; + // TODO: Unused. + constexpr auto MUTANT_ATTACK_1_CHANCE = 1.0f / 3.0f; + constexpr auto MUTANT_ATTACK_2_CHANCE = MUTANT_ATTACK_1_CHANCE * 2; #define MUTANT_NEED_TURN ANGLE(45.0f) #define MUTANT_TURN ANGLE(3.0f) #define LARA_GIANT_MUTANT_DEATH 6 // TODO: Not 13? Check this. - const vector MutantAttackJoints = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; - const vector MutantAttackLeftJoints = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; + const vector MutantAttackJoints = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; + const vector MutantAttackLeftJoint = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; const vector MutantAttackRightJoints = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }; enum GiantMutantState @@ -66,17 +68,13 @@ namespace TEN::Entities::TR1 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; + short head = 0; if (item->HitPoints <= 0) { if (item->Animation.ActiveState != MUTANT_STATE_DEATH) - { - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + MUTANT_ANIM_DEATH; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = MUTANT_STATE_DEATH; - } + SetAnimation(item, MUTANT_ANIM_DEATH); } else { @@ -92,9 +90,7 @@ namespace TEN::Entities::TR1 angle = (short)phd_atan(creature->Target.z - item->Pose.Position.z, creature->Target.x - item->Pose.Position.x) - item->Pose.Orientation.y; if (item->TouchBits) - { DoDamage(creature->Enemy, MUTANT_CONTACT_DAMAGE); - } switch (item->Animation.ActiveState) { @@ -122,7 +118,7 @@ namespace TEN::Entities::TR1 else item->Animation.TargetState = MUTANT_STATE_FORWARD; } - else if (GetRandomControl() < 0x4000) + else if (TestProbability(0.5f)) item->Animation.TargetState = MUTANT_STATE_ATTACK_1; else item->Animation.TargetState = MUTANT_STATE_ATTACK_2; @@ -178,8 +174,8 @@ namespace TEN::Entities::TR1 case MUTANT_STATE_ATTACK_1: if (!creature->Flags && item->TestBits(JointBitType::Touch, MutantAttackRightJoints)) { - creature->Flags = 1; DoDamage(creature->Enemy, MUTANT_ATTACK_DAMAGE); + creature->Flags = 1; } break; @@ -187,8 +183,8 @@ namespace TEN::Entities::TR1 case MUTANT_STATE_ATTACK_2: if (!creature->Flags && item->TestBits(JointBitType::Touch, MutantAttackJoints)) { - creature->Flags = 1; DoDamage(creature->Enemy, MUTANT_ATTACK_DAMAGE); + creature->Flags = 1; } break; @@ -202,14 +198,11 @@ namespace TEN::Entities::TR1 LaraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_GIANT_MUTANT_DEATH; LaraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase; - LaraItem->Animation.ActiveState = LaraItem->Animation.TargetState = 46; - LaraItem->RoomNumber = item->RoomNumber; - LaraItem->Pose.Position.x = item->Pose.Position.x; - LaraItem->Pose.Position.y = item->Pose.Position.y; - LaraItem->Pose.Position.z = item->Pose.Position.z; - LaraItem->Pose.Orientation.y = item->Pose.Orientation.y; - LaraItem->Pose.Orientation.x = LaraItem->Pose.Orientation.z = 0; + LaraItem->Animation.ActiveState = 46; + LaraItem->Animation.TargetState = 46; LaraItem->Animation.IsAirborne = false; + LaraItem->Pose = PoseData(item->Pose.Position, 0, item->Pose.Orientation.y, 0); + LaraItem->RoomNumber = item->RoomNumber; LaraItem->HitPoints = -1; Lara.Air = -1; Lara.Control.HandStatus = HandStatus::Busy; diff --git a/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.h b/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.h index 67c8af943..7c34920d3 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.h +++ b/TombEngine/Objects/TR1/Entity/tr1_giant_mutant.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void GiantMutantControl(short itemNumber); } diff --git a/TombEngine/Objects/TR1/Entity/tr1_natla.cpp b/TombEngine/Objects/TR1/Entity/tr1_natla.cpp index 418a284b9..811c959bb 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_natla.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_natla.cpp @@ -8,11 +8,13 @@ #include "Game/misc.h" #include "Game/missile.h" #include "Game/people.h" +#include "Math/Math.h" #include "Sound/sound.h" #include "Specific/level.h" -#include "Math/Math.h" -namespace TEN::Entities::TR1 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR1 { // TODO: Organise. constexpr auto NATLA_SHOT_DAMAGE = 100; @@ -20,9 +22,10 @@ namespace TEN::Entities::TR1 constexpr auto NATLA_DEATH_TIME = (FPS * 16); // 16 seconds. constexpr auto NATLA_FLYMODE = 0x8000; constexpr auto NATLA_TIMER = 0x7FFF; - constexpr auto NATLA_LAND_CHANCE = 0x100; constexpr auto NATLA_GUN_VELOCITY = 400; + constexpr auto NATLA_LAND_CHANCE = 0.008f; + #define NATLA_TURN_NEAR_DEATH_SPEED ANGLE(6.0f) #define NATLA_TURN_SPEED ANGLE(5.0f) #define NATLA_FLY_ANGLE_SPEED ANGLE(5.0f) @@ -183,7 +186,7 @@ namespace TEN::Entities::TR1 if (item->Animation.ActiveState == NATLA_STATE_FLY && (creature->Flags & NATLA_FLYMODE)) { - if (creature->Flags & NATLA_FLYMODE && shoot && GetRandomControl() < NATLA_LAND_CHANCE) + if (creature->Flags & NATLA_FLYMODE && shoot && TestProbability(NATLA_LAND_CHANCE)) creature->Flags -= NATLA_FLYMODE; if (!(creature->Flags & NATLA_FLYMODE)) diff --git a/TombEngine/Objects/TR1/Entity/tr1_natla.h b/TombEngine/Objects/TR1/Entity/tr1_natla.h index 1140021da..1cbebf286 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_natla.h +++ b/TombEngine/Objects/TR1/Entity/tr1_natla.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void NatlaControl(short itemNumber); } diff --git a/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.cpp b/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.cpp index ffefff5a3..491b17754 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.cpp @@ -11,13 +11,14 @@ #include "Game/misc.h" #include "Game/missile.h" #include "Game/people.h" +#include "Math/Math.h" #include "Sound/sound.h" #include "Specific/level.h" -#include "Math/Math.h" +using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE = 150; constexpr auto WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE = 100; @@ -29,8 +30,8 @@ namespace TEN::Entities::TR1 constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_RANGE = SQUARE(SECTOR(2.5f)); constexpr auto WINGED_MUTANT_ATTACK_RANGE = SQUARE(SECTOR(3.75f)); - constexpr auto WINGED_MUTANT_POSE_CHANCE = 85; - constexpr auto WINGED_MUTANT_UNPOSE_CHANCE = 200; + constexpr auto WINGED_MUTANT_POSE_CHANCE = 1.0f / 400; + constexpr auto WINGED_MUTANT_UNPOSE_CHANCE = 1.0f / 164; constexpr auto WINGED_MUTANT_FLY_VELOCITY = CLICK(1) / 8; constexpr auto WINGED_MUTANT_SHARD_VELOCITY = 250; @@ -337,7 +338,7 @@ namespace TEN::Entities::TR1 if (AI.distance < WINGED_MUTANT_WALK_RANGE) { if (AI.zoneNumber == AI.enemyZone || - GetRandomControl() < WINGED_MUTANT_UNPOSE_CHANCE) + TestProbability(WINGED_MUTANT_UNPOSE_CHANCE)) { item->Animation.TargetState = WMUTANT_STATE_WALK_FORWARD; } @@ -345,7 +346,7 @@ namespace TEN::Entities::TR1 else item->Animation.TargetState = WMUTANT_STATE_IDLE; } - else if (creature->Mood == MoodType::Bored && GetRandomControl() < WINGED_MUTANT_UNPOSE_CHANCE) + else if (creature->Mood == MoodType::Bored && TestProbability(WINGED_MUTANT_UNPOSE_CHANCE)) item->Animation.TargetState = WMUTANT_STATE_WALK_FORWARD; else if (creature->Mood == MoodType::Attack || creature->Mood == MoodType::Escape) @@ -363,7 +364,7 @@ namespace TEN::Entities::TR1 else if (creature->Mood == MoodType::Bored || (creature->Mood == MoodType::Stalk && AI.zoneNumber != AI.enemyZone)) { - if (GetRandomControl() < WINGED_MUTANT_POSE_CHANCE) + if (TestProbability(WINGED_MUTANT_POSE_CHANCE)) item->Animation.TargetState = WMUTANT_STATE_POSE; } else if (creature->Mood == MoodType::Stalk && diff --git a/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.h b/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.h index d8d9f8688..e637dead4 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.h +++ b/TombEngine/Objects/TR1/Entity/tr1_winged_mutant.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void InitialiseWingedMutant(short itemNumber); void WingedMutantControl(short itemNumber); diff --git a/TombEngine/Objects/TR1/Entity/tr1_wolf.cpp b/TombEngine/Objects/TR1/Entity/tr1_wolf.cpp index 20ab213b8..9aa8cc516 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_wolf.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_wolf.cpp @@ -11,9 +11,10 @@ #include "Specific/level.h" #include "Specific/setup.h" +using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { constexpr auto WOLF_BITE_DAMAGE = 100; constexpr auto WOLF_LUNGE_DAMAGE = 50; @@ -21,9 +22,9 @@ namespace TEN::Entities::TR1 constexpr auto WOLF_ATTACK_RANGE = SQUARE(SECTOR(1.5f)); constexpr auto WOLF_STALK_RANGE = SQUARE(SECTOR(2)); - constexpr auto WOLF_WAKE_CHANCE = 0x20; - constexpr auto WOLF_SLEEP_CHANCE = 0x20; - constexpr auto WOLF_HOWL_CHANCE = 0x180; + constexpr auto WOLF_WAKE_CHANCE = 1.0f / 1000; + constexpr auto WOLF_SLEEP_CHANCE = 1.0f / 1000; + constexpr auto WOLF_HOWL_CHANCE = 1.0f / 85; constexpr auto WOLF_SLEEP_FRAME = 96; @@ -110,7 +111,7 @@ namespace TEN::Entities::TR1 item->Animation.RequiredState = WOLF_STATE_CROUCH; item->Animation.TargetState = WOLF_STATE_IDLE; } - else if (GetRandomControl() < WOLF_WAKE_CHANCE) + else if (TestProbability(WOLF_WAKE_CHANCE)) { item->Animation.RequiredState = WOLF_STATE_WALK; item->Animation.TargetState = WOLF_STATE_IDLE; @@ -133,7 +134,7 @@ namespace TEN::Entities::TR1 item->Animation.TargetState = WOLF_STATE_STALK; item->Animation.RequiredState = WOLF_STATE_NONE; } - else if (GetRandomControl() < WOLF_SLEEP_CHANCE) + else if (TestProbability(WOLF_SLEEP_CHANCE)) { item->Animation.RequiredState = WOLF_STATE_SLEEP; item->Animation.TargetState = WOLF_STATE_IDLE; @@ -174,7 +175,7 @@ namespace TEN::Entities::TR1 item->Animation.TargetState = WOLF_STATE_RUN; } } - else if (GetRandomControl() < WOLF_HOWL_CHANCE) + else if (TestProbability(WOLF_HOWL_CHANCE)) { item->Animation.RequiredState = WOLF_STATE_HOWL; item->Animation.TargetState = WOLF_STATE_CROUCH; diff --git a/TombEngine/Objects/TR1/Entity/tr1_wolf.h b/TombEngine/Objects/TR1/Entity/tr1_wolf.h index c9a4ec7ec..38b83ab1c 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_wolf.h +++ b/TombEngine/Objects/TR1/Entity/tr1_wolf.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR1 +namespace TEN::Entities::Creatures::TR1 { void InitialiseWolf(short itemNumber); void WolfControl(short itemNumber); diff --git a/TombEngine/Objects/TR1/tr1_objects.cpp b/TombEngine/Objects/TR1/tr1_objects.cpp index bd5211126..7a8b0c68f 100644 --- a/TombEngine/Objects/TR1/tr1_objects.cpp +++ b/TombEngine/Objects/TR1/tr1_objects.cpp @@ -1,7 +1,6 @@ #include "framework.h" #include "Objects/TR1/tr1_objects.h" -/// necessary import #include "Game/control/box.h" #include "Game/collision/collide_item.h" #include "Game/itemdata/creature_info.h" @@ -9,7 +8,7 @@ #include "Specific/setup.h" #include "Specific/level.h" -/// entities +// Creatures #include "Objects/TR1/Entity/tr1_ape.h" // OK #include "Objects/TR1/Entity/tr1_bear.h" // OK #include "Objects/TR1/Entity/tr1_doppelganger.h" // OK @@ -21,7 +20,7 @@ #include "Objects/TR1/Entity/tr1_winged_mutant.h" #include "Objects/Utils/object_helper.h" -using namespace TEN::Entities::TR1; +using namespace TEN::Entities::Creatures::TR1; static void StartEntity(ObjectInfo* obj) { @@ -78,7 +77,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_APE; + obj->ZoneType = ZoneType::Ape; } obj = &Objects[ID_BIG_RAT]; @@ -98,7 +97,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveAnim = true; obj->saveFlags = true; obj->waterCreature = true; - obj->zoneType = ZONE_WATER; + obj->ZoneType = ZoneType::Water; obj->SetBoneRotation(1, ROT_Y); // head } @@ -174,7 +173,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_BLOCKABLE; + obj->ZoneType = ZoneType::Blockable; obj->SetBoneRotation(10, ROT_X | ROT_Y); } @@ -194,7 +193,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; obj->SetBoneRotation(1, ROT_Y); // torso obj->SetBoneRotation(2, ROT_Y); // head } diff --git a/TombEngine/Objects/TR2/Entity/tr2_barracuda.cpp b/TombEngine/Objects/TR2/Entity/tr2_barracuda.cpp index 4346a201c..99b759bbf 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_barracuda.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_barracuda.cpp @@ -12,7 +12,7 @@ using std::vector; -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { constexpr auto BARRACUDA_ATTACK_DAMAGE = 100; constexpr auto BARRACUDA_IDLE_ATTACK_RANGE = SQUARE(SECTOR(0.67f)); @@ -23,7 +23,7 @@ namespace TEN::Entities::TR2 enum BarracudaState { - BARRACUDA_STATE_NONE = 0, + // No state 0. BARRACUDA_STATE_IDLE = 1, BARRACUDA_STATE_SWIM_SLOW = 2, BARRACUDA_STATE_SWIM_FAST = 3, diff --git a/TombEngine/Objects/TR2/Entity/tr2_barracuda.h b/TombEngine/Objects/TR2/Entity/tr2_barracuda.h index dfde88ccf..64ddf1939 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_barracuda.h +++ b/TombEngine/Objects/TR2/Entity/tr2_barracuda.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void BarracudaControl(short itemNumber); } diff --git a/TombEngine/Objects/TR2/Entity/tr2_bird_monster.cpp b/TombEngine/Objects/TR2/Entity/tr2_bird_monster.cpp index 0d34f2516..91aca80e1 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_bird_monster.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_bird_monster.cpp @@ -14,7 +14,7 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { constexpr auto BIRD_MONSTER_ATTACK_DAMAGE = 200; constexpr auto BIRD_MONSTER_SLAM_CRUSH_ATTACK_RANGE = SQUARE(SECTOR(1)); @@ -29,7 +29,7 @@ namespace TEN::Entities::TR2 enum BirdMonsterState { - BMONSTER_STATE_NONE = 0, + // No state 0. BMONSTER_STATE_IDLE = 1, BMONSTER_STATE_WALK_FORWARD = 2, BMONSTER_STATE_SLAM_ATTACK_START = 3, diff --git a/TombEngine/Objects/TR2/Entity/tr2_bird_monster.h b/TombEngine/Objects/TR2/Entity/tr2_bird_monster.h index 5756af247..3c97478ce 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_bird_monster.h +++ b/TombEngine/Objects/TR2/Entity/tr2_bird_monster.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void BirdMonsterControl(short itemNumber); } diff --git a/TombEngine/Objects/TR2/Entity/tr2_dragon.cpp b/TombEngine/Objects/TR2/Entity/tr2_dragon.cpp index 8bb783680..129af7a09 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_dragon.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_dragon.cpp @@ -18,28 +18,23 @@ #include "Specific/setup.h" using namespace TEN::Input; +using std::vector; -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { - const auto DragonMouthBite = BiteInfo(Vector3(35.0f, 171.0f, 1168.0f), 12); - constexpr auto DRAGON_SWIPE_ATTACK_DAMAGE = 250; - constexpr auto DRAGON_TOUCH_DAMAGE = 10; - + constexpr auto DRAGON_CONTACT_DAMAGE = 10; + const auto DragonMouthBite = BiteInfo(Vector3(35.0f, 171.0f, 1168.0f), 12); + const vector DragonSwipeAttackJointsLeft = { 24, 25, 26, 27, 28, 29, 30 }; + const vector DragonSwipeAttackJointsRight = { 1, 2, 3, 4, 5, 6, 7 }; // TODO: Organise. - #define DRAGON_SWIPE_DAMAGE 250 - #define DRAGON_TOUCH_DAMAGE 10 - #define DRAGON_LIVE_TIME (30 * 11) #define DRAGON_CLOSE_RANGE pow(SECTOR(3), 2) #define DRAGON_STATE_IDLE_RANGE pow(SECTOR(6), 2) #define DRAGON_FLAME_SPEED 200 - #define DRAGON_TOUCH_R 0x0fe - #define DRAGON_TOUCH_L 0x7f000000 - #define DRAGON_ALMOST_LIVE 100 #define BOOM_TIME 130 #define BOOM_TIME_MIDDLE 140 @@ -58,7 +53,7 @@ namespace TEN::Entities::TR2 enum DragonState { - DRAGON_STATE_NONE = 0, + // No state 0. DRAGON_STATE_WALK = 1, DRAGON_STATE_LEFT = 2, DRAGON_STATE_RIGHT = 3, @@ -255,8 +250,8 @@ namespace TEN::Entities::TR2 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; + short head = 0; bool ahead; @@ -318,9 +313,7 @@ namespace TEN::Entities::TR2 ahead = (AI.ahead && AI.distance > DRAGON_CLOSE_RANGE && AI.distance < DRAGON_STATE_IDLE_RANGE); if (item->TouchBits) - { - DoDamage(creature->Enemy, DRAGON_TOUCH_DAMAGE); - } + DoDamage(creature->Enemy, DRAGON_CONTACT_DAMAGE); switch (item->Animation.ActiveState) { @@ -350,19 +343,19 @@ namespace TEN::Entities::TR2 break; case DRAGON_STATE_SWIPE_LEFT: - if (item->TouchBits & DRAGON_TOUCH_L) + if (item->TestBits(JointBitType::Touch, DragonSwipeAttackJointsLeft)) { + DoDamage(creature->Enemy, DRAGON_SWIPE_ATTACK_DAMAGE); creature->Flags = 0; - DoDamage(creature->Enemy, DRAGON_SWIPE_DAMAGE); } break; case DRAGON_STATE_SWIPE_RIGHT: - if (item->TouchBits & DRAGON_TOUCH_R) + if (item->TestBits(JointBitType::Touch, DragonSwipeAttackJointsRight)) { + DoDamage(creature->Enemy, DRAGON_SWIPE_ATTACK_DAMAGE); creature->Flags = 0; - DoDamage(creature->Enemy, DRAGON_SWIPE_DAMAGE); } break; @@ -404,13 +397,11 @@ namespace TEN::Entities::TR2 case DRAGON_STATE_TURN_LEFT: item->Pose.Orientation.y += -(ANGLE(1.0f) - angle); creature->Flags = 0; - break; case DRAGON_STATE_TURN_RIGHT: item->Pose.Orientation.y += (ANGLE(1.0f) - angle); creature->Flags = 0; - break; case DRAGON_STATE_AIM_1: @@ -434,12 +425,11 @@ namespace TEN::Entities::TR2 case DRAGON_STATE_FIRE_1: item->Pose.Orientation.y -= angle; + SoundEffect(SFX_TR2_DRAGON_FIRE, &item->Pose); if (AI.ahead) head = -AI.angle; - SoundEffect(SFX_TR2_DRAGON_FIRE, &item->Pose); - if (creature->Flags) { if (AI.ahead) @@ -459,12 +449,7 @@ namespace TEN::Entities::TR2 back->Animation.ActiveState = item->Animation.ActiveState; back->Animation.AnimNumber = Objects[ID_DRAGON_BACK].animIndex + (item->Animation.AnimNumber - Objects[ID_DRAGON_FRONT].animIndex); back->Animation.FrameNumber = g_Level.Anims[back->Animation.AnimNumber].frameBase + (item->Animation.FrameNumber - g_Level.Anims[item->Animation.AnimNumber].frameBase); - back->Pose.Position.x = item->Pose.Position.x; - back->Pose.Position.y = item->Pose.Position.y; - back->Pose.Position.z = item->Pose.Position.z; - back->Pose.Orientation.x = item->Pose.Orientation.x; - back->Pose.Orientation.y = item->Pose.Orientation.y; - back->Pose.Orientation.z = item->Pose.Orientation.z; + back->Pose = item->Pose; if (back->RoomNumber != item->RoomNumber) ItemNewRoom(backItemNumber, item->RoomNumber); @@ -484,9 +469,7 @@ namespace TEN::Entities::TR2 { auto* back = &g_Level.Items[backItem]; back->ObjectNumber = ID_DRAGON_BACK; - back->Pose.Position.x = item->Pose.Position.x; - back->Pose.Position.y = item->Pose.Position.y; - back->Pose.Position.z = item->Pose.Position.z; + back->Pose.Position = item->Pose.Position; back->Pose.Orientation.y = item->Pose.Orientation.y; back->RoomNumber = item->RoomNumber; back->Status = ITEM_INVISIBLE; @@ -500,9 +483,7 @@ namespace TEN::Entities::TR2 auto* front = &g_Level.Items[frontItem]; front->ObjectNumber = ID_DRAGON_FRONT; - front->Pose.Position.x = item->Pose.Position.x; - front->Pose.Position.y = item->Pose.Position.y; - front->Pose.Position.z = item->Pose.Position.z; + front->Pose.Position = item->Pose.Position; front->Pose.Orientation.y = item->Pose.Orientation.y; front->RoomNumber = item->RoomNumber; front->Status = ITEM_INVISIBLE; diff --git a/TombEngine/Objects/TR2/Entity/tr2_dragon.h b/TombEngine/Objects/TR2/Entity/tr2_dragon.h index 0809af93a..d501de501 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_dragon.h +++ b/TombEngine/Objects/TR2/Entity/tr2_dragon.h @@ -2,7 +2,7 @@ #include "Game/collision/collide_room.h" #include "Game/items.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void DragonCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll); void DragonControl(short backNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.cpp b/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.cpp index a5b078769..b59911c68 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.cpp @@ -10,7 +10,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto EagleBite = BiteInfo(Vector3(15.0f, 46.0f, 21.0f), 6); const auto CrowBite = BiteInfo(Vector3(2.0f, 10.0f, 60.0f), 14); diff --git a/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.h b/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.h index 4b704e256..828b15bf8 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.h +++ b/TombEngine/Objects/TR2/Entity/tr2_eagle_or_crow.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseEagle(short itemNumber); void EagleControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.cpp b/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.cpp index 8d2fac248..7fbb34b6c 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.cpp @@ -18,7 +18,7 @@ using namespace TEN::Math::Random; -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { constexpr auto KNIFE_PROJECTILE_DAMAGE = 50; @@ -29,7 +29,7 @@ namespace TEN::Entities::TR2 enum KnifeThrowerState { - KTHROWER_STATE_NONE = 0, + // No state 0. KTHROWER_STATE_IDLE = 1, KTHROWER_STATE_WALK_FORWARD = 2, KTHROWER_STATE_RUN_FORWARD = 3, @@ -101,7 +101,7 @@ namespace TEN::Entities::TR2 fx->pos.Orientation.z += ANGLE(30.0f); - if (ItemNearLara(&fx->pos, 200)) + if (ItemNearLara(&fx->pos.Position, 200)) { DoDamage(LaraItem, KNIFE_PROJECTILE_DAMAGE); diff --git a/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.h b/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.h index 640373f24..2204a999c 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.h +++ b/TombEngine/Objects/TR2/Entity/tr2_knife_thrower.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void KnifeControl(short fxNumber); void KnifeThrowerControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_mercenary.cpp b/TombEngine/Objects/TR2/Entity/tr2_mercenary.cpp index 9a95a077a..cec1b6609 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_mercenary.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_mercenary.cpp @@ -11,7 +11,7 @@ #include "Specific/setup.h" #include "Math/Math.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto MercenaryUziBite = BiteInfo(Vector3(0.0f, 150.0f, 19.0f), 17); const auto MercenaryAutoPistolBite = BiteInfo(Vector3(0.0f, 230.0f, 9.0f), 17); diff --git a/TombEngine/Objects/TR2/Entity/tr2_mercenary.h b/TombEngine/Objects/TR2/Entity/tr2_mercenary.h index 5199716ad..80f95100d 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_mercenary.h +++ b/TombEngine/Objects/TR2/Entity/tr2_mercenary.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void MercenaryUziControl(short itemNumber); void MercenaryAutoPistolControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_monk.cpp b/TombEngine/Objects/TR2/Entity/tr2_monk.cpp index 6dd61eb4d..1308c90e5 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_monk.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_monk.cpp @@ -11,7 +11,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto MonkBite = BiteInfo(Vector3(-23.0f, 16.0f, 265.0f), 14); diff --git a/TombEngine/Objects/TR2/Entity/tr2_monk.h b/TombEngine/Objects/TR2/Entity/tr2_monk.h index dcf98f279..5fa99a252 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_monk.h +++ b/TombEngine/Objects/TR2/Entity/tr2_monk.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void MonkControl(short itemNumber); } diff --git a/TombEngine/Objects/TR2/Entity/tr2_rat.cpp b/TombEngine/Objects/TR2/Entity/tr2_rat.cpp index 44c22094d..40486f24b 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_rat.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_rat.cpp @@ -14,7 +14,7 @@ using namespace TEN::Math::Random; -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { constexpr auto RAT_ATTACK_DAMAGE = 20; constexpr auto RAT_ATTACK_RANGE = SQUARE(CLICK(0.7f)); @@ -29,7 +29,7 @@ namespace TEN::Entities::TR2 enum RatState { - RAT_STATE_NONE = 0, + // No state 0. RAT_STATE_WALK_FORWARD = 1, RAT_STATE_IDLE = 2, RAT_STATE_SQUEAK = 3, diff --git a/TombEngine/Objects/TR2/Entity/tr2_rat.h b/TombEngine/Objects/TR2/Entity/tr2_rat.h index 1b4ebadcc..9afbf9b8a 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_rat.h +++ b/TombEngine/Objects/TR2/Entity/tr2_rat.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void RatControl(short itemNumber); } diff --git a/TombEngine/Objects/TR2/Entity/tr2_shark.cpp b/TombEngine/Objects/TR2/Entity/tr2_shark.cpp index 6d1e71a10..ba8a93458 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_shark.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_shark.cpp @@ -11,9 +11,14 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +using std::vector; + +namespace TEN::Entities::Creatures::TR2 { + constexpr auto SHARK_BITE_ATTACK_DAMAGE = 400; + const auto SharkBite = BiteInfo(Vector3(17.0f, -22.0f, 344.0f), 12); + const vector SharkBiteAttackJoints = { 10, 12, 13 }; void SharkControl(short itemNumber) { @@ -21,7 +26,7 @@ namespace TEN::Entities::TR2 return; auto* item = &g_Level.Items[itemNumber]; - auto* info = GetCreatureInfo(item); + auto* creature = GetCreatureInfo(item); short angle = 0; short head = 0; @@ -29,11 +34,7 @@ namespace TEN::Entities::TR2 if (item->HitPoints <= 0) { if (item->Animation.ActiveState != 5) - { - item->Animation.AnimNumber = Objects[ID_SHARK].animIndex + 4; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 5; - } + SetAnimation(item, 4); CreatureFloat(itemNumber); return; @@ -46,39 +47,40 @@ namespace TEN::Entities::TR2 GetCreatureMood(item, &AI, true); CreatureMood(item, &AI, true); - angle = CreatureTurn(item, info->MaxTurn); + angle = CreatureTurn(item, creature->MaxTurn); switch (item->Animation.ActiveState) { case 0: - info->Flags = 0; - info->MaxTurn = 0; + creature->MaxTurn = 0; + creature->Flags = 0; if (AI.ahead && AI.distance < pow(SECTOR(0.75f), 2) && AI.zoneNumber == AI.enemyZone) item->Animation.TargetState = 3; else item->Animation.TargetState = 1; + break; case 1: - info->MaxTurn = ANGLE(0.5f); + creature->MaxTurn = ANGLE(0.5f); - if (info->Mood == MoodType::Bored) + if (creature->Mood == MoodType::Bored) break; else if (AI.ahead && AI.distance < pow(SECTOR(0.75f), 2)) item->Animation.TargetState = 0; - else if (info->Mood == MoodType::Escape || AI.distance > pow(SECTOR(3), 2) || !AI.ahead) + else if (creature->Mood == MoodType::Escape || AI.distance > pow(SECTOR(3), 2) || !AI.ahead) item->Animation.TargetState = 2; break; case 2: - info->MaxTurn = ANGLE(2.0f); - info->Flags = 0; + creature->MaxTurn = ANGLE(2.0f); + creature->Flags = 0; - if (info->Mood == MoodType::Bored) + if (creature->Mood == MoodType::Bored) item->Animation.TargetState = 1; - else if (info->Mood == MoodType::Escape) + else if (creature->Mood == MoodType::Escape) break; else if (AI.ahead && AI.distance < pow(1365, 2) && AI.zoneNumber == AI.enemyZone) { @@ -95,11 +97,11 @@ namespace TEN::Entities::TR2 if (AI.ahead) head = AI.angle; - if (!info->Flags && item->TouchBits & 0x3400) + if (!creature->Flags && item->TestBits(JointBitType::Touch, SharkBiteAttackJoints)) { + DoDamage(creature->Enemy, SHARK_BITE_ATTACK_DAMAGE); CreatureEffect(item, SharkBite, DoBloodSplat); - DoDamage(info->Enemy, 400); - info->Flags = 1; + creature->Flags = 1; } break; diff --git a/TombEngine/Objects/TR2/Entity/tr2_shark.h b/TombEngine/Objects/TR2/Entity/tr2_shark.h index 1f2d76299..5788ee192 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_shark.h +++ b/TombEngine/Objects/TR2/Entity/tr2_shark.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void SharkControl(short itemNumber); } diff --git a/TombEngine/Objects/TR2/Entity/tr2_silencer.cpp b/TombEngine/Objects/TR2/Entity/tr2_silencer.cpp index c5f124b5f..00061baea 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_silencer.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_silencer.cpp @@ -10,20 +10,67 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR2 { + constexpr auto SILENCER_SHOOT_ATTACK_DAMAGE = 50; + constexpr auto SILENCER_RUN_RANGE = SQUARE(SECTOR(2)); + const auto SilencerGunBite = BiteInfo(Vector3(3.0f, 331.0f, 56.0f), 10); - // TODO + #define SILENCER_WALK_TURN_RATE_MAX ANGLE(5.0f) + #define SILENCER_RUN_TURN_RATE_MAX ANGLE(5.0f) + enum SilencerState { - + // No state 0. + SILENCER_STATE_WALK_FORWARD = 1, + SILENCER_STATE_RUN_FORWARD = 2, + SILENCER_STATE_IDLE_FRAME = 3, + SILENCER_STATE_IDLE = 4, + SILENCER_STATE_POSE = 5, + SILENCER_STATE_AIM_1 = 6, + SILENCER_STATE_SHOOT_1 = 7, + // No state 8. + SILENCER_STATE_RUN_SHOOT = 9, + SILENCER_STATE_AIM_2 = 10, + SILENCER_STATE_SHOOT_2 = 11, + SILENCER_STATE_DEATH_1 = 12, + SILENCER_STATE_DEATH_2 = 13 }; - // TODO enum SilencerAnim { - + SILENCER_ANIM_IDLE_FRAME = 0, + SILENCER_ANIM_IDLE_TO_WALK_FORWARD = 1, + SILENCER_ANIM_WALK_FORWARD = 2, + SILENCER_ANIM_WALK_FORWARD_TO_IDLE = 3, + SILENCER_ANIM_WALK_FORWARD_TO_POSE = 4, + SILENCER_ANIM_POSE = 5, + SILENCER_ANIM_WALK_FORWARD_TO_RUN_FORWARD = 6, + SILENCER_ANIM_RUN_FORWARD = 7, + SILENCER_ANIM_RUN_FORWARD_TO_IDLE = 8, + SILENCER_ANIM_IDLE_TO_RUN_FORWARD = 9, + SILENCER_ANIM_POSE_TO_IDLE = 10, + SILENCER_ANIM_RUN_FORWARD_AIM_LEFT = 11, + SILENCER_ANIM_RUN_FORWARD_SHOOT_LEFT = 12, + SILENCER_ANIM_RUN_FORWARD_UNAIM_LEFT = 13, + SILENCER_ANIM_AIM_1_START = 14, + SILENCER_ANIM_AIM_1_CONTINUE = 15, + SILENCER_ANIM_SHOOT_1 = 16, + SILENCER_ANIM_UNAIM_1 = 17, + SILENCER_ANIM_POSE_TO_AIM_1 = 18, + SILENCER_ANIM_IDLE = 19, + SILENCER_ANIM_DEATH_1 = 20, + SILENCER_ANIM_DEATH_2 = 21, // Unused. + SILENCER_ANIM_AIM_2_START = 22, + SILENCER_ANIM_AIM_2_CONTINUE = 23, + SILENCER_ANIM_SHOOT_2 = 24, + SILENCER_ANIM_UNAIM_2 = 25, + SILENCER_ANIM_RUN_FORWARD_AIM_RIGHT = 26, + SILENCER_ANIM_RUN_FORWARD_SHOOT_RIGHT = 27, + SILENCER_ANIM_RUN_FORWARD_UNAIM_RIGHT = 28 }; void SilencerControl(short itemNumber) @@ -32,21 +79,19 @@ namespace TEN::Entities::TR2 return; auto* item = &g_Level.Items[itemNumber]; - auto* info = GetCreatureInfo(item); + auto* creature = GetCreatureInfo(item); short angle = 0; - short torsoX = 0; - short torsoY = 0; - short head = 0; short tilt = 0; + auto extraHeadRot = EulerAngles::Zero; + auto extraTorsoRot = EulerAngles::Zero; if (item->HitPoints <= 0) { - if (item->Animation.ActiveState != 12 && item->Animation.ActiveState != 13) + if (item->Animation.ActiveState != SILENCER_STATE_DEATH_1 && + item->Animation.ActiveState != SILENCER_STATE_DEATH_2) { - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 20; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 13; + SetAnimation(item, SILENCER_ANIM_DEATH_1); } } else @@ -57,205 +102,207 @@ namespace TEN::Entities::TR2 GetCreatureMood(item, &AI, true); CreatureMood(item, &AI, true); - angle = CreatureTurn(item, info->MaxTurn); + angle = CreatureTurn(item, creature->MaxTurn); switch (item->Animation.ActiveState) { - case 3: + case SILENCER_STATE_IDLE_FRAME: + creature->MaxTurn = 0; + if (AI.ahead) - head = AI.angle; - info->MaxTurn = 0; + extraHeadRot.y = AI.angle; if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; break; - case 4: - if (AI.ahead) - head = AI.angle; - info->MaxTurn = 0; + case SILENCER_STATE_IDLE: + creature->MaxTurn = 0; - if (info->Mood == MoodType::Escape) + if (AI.ahead) + extraHeadRot.y = AI.angle; + + if (creature->Mood == MoodType::Escape) { - item->Animation.RequiredState = 2; - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = SILENCER_STATE_RUN_FORWARD; } else { if (Targetable(item, &AI)) { - item->Animation.RequiredState = (GetRandomControl() >= 0x4000 ? 10 : 6); - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = TestProbability(0.5f) ? SILENCER_STATE_AIM_1 : SILENCER_STATE_AIM_2; } - if (info->Mood == MoodType::Attack || !AI.ahead) + if (creature->Mood == MoodType::Attack || !AI.ahead) { - if (AI.distance >= pow(SECTOR(2), 2)) + if (AI.distance >= SILENCER_RUN_RANGE) { - item->Animation.RequiredState = 2; - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = SILENCER_STATE_RUN_FORWARD; } else { - item->Animation.RequiredState = 1; - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = SILENCER_STATE_WALK_FORWARD; } } else { - if (GetRandomControl() >= 1280) + if (TestProbability(0.96f)) { - if (GetRandomControl() < 2560) + if (TestProbability(0.08f)) { - item->Animation.RequiredState = 1; - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = SILENCER_STATE_WALK_FORWARD; } } else { - item->Animation.RequiredState = 5; - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = SILENCER_STATE_POSE; } } } break; - case 1: + case SILENCER_STATE_WALK_FORWARD: + creature->MaxTurn = SILENCER_WALK_TURN_RATE_MAX; + if (AI.ahead) - head = AI.angle; + extraHeadRot.y = AI.angle; - info->MaxTurn = 910; - - if (info->Mood == MoodType::Escape) - item->Animation.TargetState = 2; + if (creature->Mood == MoodType::Escape) + item->Animation.TargetState = SILENCER_STATE_RUN_FORWARD; else if (Targetable(item, &AI)) { - item->Animation.RequiredState = (GetRandomControl() >= 0x4000 ? 10 : 6); - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = TestProbability(0.5f) ? SILENCER_STATE_AIM_1 : SILENCER_STATE_AIM_2; } else { - if (AI.distance > pow(SECTOR(2), 2) || !AI.ahead) - item->Animation.TargetState = 2; - if (info->Mood == MoodType::Bored && GetRandomControl() < 0x300) - item->Animation.TargetState = 3; + if (AI.distance > SILENCER_RUN_RANGE || !AI.ahead) + item->Animation.TargetState = SILENCER_STATE_RUN_FORWARD; + if (creature->Mood == MoodType::Bored && TestProbability(0.025f)) + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; } break; - case 2: - if (AI.ahead) - head = AI.angle; - - info->MaxTurn = ANGLE(5.0f); - info->Flags = 0; + case SILENCER_STATE_RUN_FORWARD: + creature->MaxTurn = SILENCER_RUN_TURN_RATE_MAX; + creature->Flags = 0; tilt = angle / 4; - if (info->Mood == MoodType::Escape) + if (AI.ahead) + extraHeadRot.y = AI.angle; + + if (creature->Mood == MoodType::Escape) { if (Targetable(item, &AI)) - item->Animation.TargetState = 9; + item->Animation.TargetState = SILENCER_STATE_RUN_SHOOT; break; - } if (Targetable(item, &AI)) { - if (AI.distance >= pow(SECTOR(2), 2) && AI.zoneNumber == AI.enemyZone) - item->Animation.TargetState = 9; + if (AI.distance >= SILENCER_RUN_RANGE && AI.zoneNumber == AI.enemyZone) + item->Animation.TargetState = SILENCER_STATE_RUN_SHOOT; break; } - else if (info->Mood == MoodType::Attack) - item->Animation.TargetState = (GetRandomControl() >= 0x4000) ? 3 : 2; + else if (creature->Mood == MoodType::Attack) + item->Animation.TargetState = TestProbability(0.5f) ? SILENCER_STATE_RUN_FORWARD : SILENCER_STATE_IDLE_FRAME; else - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; break; - case 5: - if (AI.ahead) - head = AI.angle; + case SILENCER_STATE_POSE: + creature->MaxTurn = 0; - info->MaxTurn = 0; + if (AI.ahead) + extraHeadRot.y = AI.angle; if (Targetable(item, &AI)) { - item->Animation.RequiredState = 6; - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + item->Animation.RequiredState = SILENCER_STATE_AIM_1; } else { - if (info->Mood == MoodType::Attack || GetRandomControl() < 0x100) - item->Animation.TargetState = 3; + if (creature->Mood == MoodType::Attack || TestProbability(1.0f / 128)) + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; + if (!AI.ahead) - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; } break; - case 6: - case 10: - info->MaxTurn = 0; - info->Flags = 0; + case SILENCER_STATE_AIM_1: + case SILENCER_STATE_AIM_2: + creature->MaxTurn = 0; + creature->Flags = 0; if (AI.ahead) { - torsoY = AI.angle; - torsoX = AI.xAngle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } else - head = AI.angle; + extraHeadRot.y = AI.angle; - if (info->Mood == MoodType::Escape) - item->Animation.TargetState = 3; + if (creature->Mood == MoodType::Escape) + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; else if (Targetable(item, &AI)) - item->Animation.TargetState = item->Animation.ActiveState != 6 ? 11 : 7; + item->Animation.TargetState = (item->Animation.ActiveState != SILENCER_STATE_AIM_1) ? SILENCER_STATE_SHOOT_2 : SILENCER_STATE_SHOOT_1; else - item->Animation.TargetState = 3; + item->Animation.TargetState = SILENCER_STATE_IDLE_FRAME; break; - case 7: - case 11: - info->MaxTurn = 0; + case SILENCER_STATE_SHOOT_1: + case SILENCER_STATE_SHOOT_2: + creature->MaxTurn = 0; if (AI.ahead) { - torsoY = AI.angle; - torsoX = AI.xAngle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } else - head = AI.angle; + extraHeadRot.y = AI.angle; - if (!info->Flags) + if (!creature->Flags) { - ShotLara(item, &AI, SilencerGunBite, torsoY, 50); - info->Flags = 1; + ShotLara(item, &AI, SilencerGunBite, extraTorsoRot.y, SILENCER_SHOOT_ATTACK_DAMAGE); + creature->Flags = 1; } break; - case 9: - info->MaxTurn = ANGLE(5.0f); + case SILENCER_STATE_RUN_SHOOT: + creature->MaxTurn = SILENCER_RUN_TURN_RATE_MAX; if (AI.ahead) { - torsoY = AI.angle; - torsoX = AI.xAngle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } else - head = AI.angle; + extraHeadRot.y = AI.angle; if (!item->Animation.RequiredState) { - if (!ShotLara(item, &AI, SilencerGunBite, torsoY, 50)) - item->Animation.TargetState = 2; + if (!ShotLara(item, &AI, SilencerGunBite, extraTorsoRot.y, SILENCER_SHOOT_ATTACK_DAMAGE)) + item->Animation.TargetState = SILENCER_STATE_RUN_FORWARD; - item->Animation.RequiredState = 9; + item->Animation.RequiredState = SILENCER_STATE_RUN_SHOOT; } break; @@ -263,9 +310,9 @@ namespace TEN::Entities::TR2 } CreatureTilt(item, tilt); - CreatureJoint(item, 0, torsoY); - CreatureJoint(item, 1, torsoX); - CreatureJoint(item, 2, head); + CreatureJoint(item, 0, extraTorsoRot.y); + CreatureJoint(item, 1, extraTorsoRot.x); + CreatureJoint(item, 2, extraHeadRot.y); CreatureAnimation(itemNumber, angle, tilt); } } diff --git a/TombEngine/Objects/TR2/Entity/tr2_silencer.h b/TombEngine/Objects/TR2/Entity/tr2_silencer.h index 3b91c1f71..69e903dfc 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_silencer.h +++ b/TombEngine/Objects/TR2/Entity/tr2_silencer.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void SilencerControl(short itemNumber); } diff --git a/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp b/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp index dec4daf4e..a075d43ec 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp @@ -17,7 +17,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { #define SMAN_MIN_TURN (ANGLE(2.0f)) #define SMAN_TARGET_ANGLE ANGLE(15.0f) @@ -28,7 +28,7 @@ namespace TEN::Entities::TR2 enum SnowmobileManState { - SMAN_STATE_NONE = 0, + // No state 0. SMAN_STATE_WAIT = 1, SMAN_STATE_MOVING = 2, SMAN_STATE_START_LEFT = 3, diff --git a/TombEngine/Objects/TR2/Entity/tr2_skidman.h b/TombEngine/Objects/TR2/Entity/tr2_skidman.h index 3a79818c5..bc6147943 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_skidman.h +++ b/TombEngine/Objects/TR2/Entity/tr2_skidman.h @@ -2,7 +2,7 @@ #include "Game/collision/collide_room.h" #include "Game/items.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseSkidooMan(short itemNumber); void SkidooManCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll); diff --git a/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.cpp b/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.cpp index 3ad9912e7..0a658d24a 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.cpp @@ -12,7 +12,9 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR2 { const auto SpearBiteLeft = BiteInfo(Vector3(0.0f, 0.0f, 920.0f), 11); const auto SpearBiteRight = BiteInfo(Vector3(0.0f, 0.0f, 920.0f), 18); @@ -29,7 +31,7 @@ namespace TEN::Entities::TR2 }; - static void XianDamage(ItemInfo* item, int damage) + void XianDamage(ItemInfo* item, int damage) { auto* creature = GetCreatureInfo(item); @@ -76,7 +78,7 @@ namespace TEN::Entities::TR2 short neck = 0; short tilt = 0; - bool laraAlive = LaraItem->HitPoints > 0; + bool isLaraAlive = LaraItem->HitPoints > 0; if (item->HitPoints <= 0) { @@ -125,10 +127,9 @@ namespace TEN::Entities::TR2 if (creature->Mood == MoodType::Bored) { - int random = GetRandomControl(); - if (random < 0x200) + if (TestProbability(1.0f / 64)) item->Animation.TargetState = 2; - else if (random < 0x400) + else if (TestProbability(1.0f / 30)) item->Animation.TargetState = 3; } else if (AI.ahead && AI.distance < pow(SECTOR(1), 2)) @@ -148,10 +149,9 @@ namespace TEN::Entities::TR2 item->Animation.TargetState = 3; else if (creature->Mood == MoodType::Bored) { - int random = GetRandomControl(); - if (random < 0x200) + if (TestProbability(1.0f / 64)) item->Animation.TargetState = 1; - else if (random < 0x400) + else if (TestProbability(1.0f / 30)) item->Animation.TargetState = 3; } else if (AI.ahead && AI.distance < pow(SECTOR(1), 2)) @@ -171,17 +171,16 @@ namespace TEN::Entities::TR2 item->Animation.TargetState = 4; else if (creature->Mood == MoodType::Bored) { - int random = GetRandomControl(); - if (random < 0x200) + if (TestProbability(1.0f / 64)) item->Animation.TargetState = 1; - else if (random < 0x400) + else if (TestProbability(1.0f / 30)) item->Animation.TargetState = 2; } else if (AI.ahead && AI.distance < pow(SECTOR(2), 2)) { if (AI.distance < pow(SECTOR(1.5f), 2)) item->Animation.TargetState = 7; - else if (GetRandomControl() < 0x4000) + else if (TestProbability(0.5f)) item->Animation.TargetState = 9; else item->Animation.TargetState = 11; @@ -201,7 +200,7 @@ namespace TEN::Entities::TR2 break; else if (creature->Mood == MoodType::Bored) { - if (GetRandomControl() < 0x4000) + if (TestProbability(0.5f)) item->Animation.TargetState = 1; else item->Animation.TargetState = 2; @@ -301,7 +300,7 @@ namespace TEN::Entities::TR2 if (AI.ahead && AI.distance < pow(SECTOR(1), 2)) { - if (GetRandomControl() < 0x4000) + if (TestProbability(0.5f)) item->Animation.TargetState = 1; else item->Animation.TargetState = 2; @@ -332,7 +331,7 @@ namespace TEN::Entities::TR2 if (AI.ahead && AI.distance < pow(SECTOR(1), 2)) { - if (GetRandomControl() < 0x4000) + if (TestProbability(0.5f)) item->Animation.TargetState = 1; else item->Animation.TargetState = 2; @@ -346,7 +345,7 @@ namespace TEN::Entities::TR2 } } - if (laraAlive && LaraItem->HitPoints <= 0) + if (isLaraAlive && LaraItem->HitPoints <= 0) { CreatureKill(item, 49, 19, 2); return; diff --git a/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.h b/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.h index d7965b761..e46bb4ea1 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.h +++ b/TombEngine/Objects/TR2/Entity/tr2_spear_guardian.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseSpearGuardian(short itemNumber); void SpearGuardianControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_spider.cpp b/TombEngine/Objects/TR2/Entity/tr2_spider.cpp index c2ce3d48a..3b1803c70 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_spider.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_spider.cpp @@ -14,17 +14,17 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto SpiderBite = BiteInfo(Vector3(0.0f, 0.0f, 41.0f), 1); - static void S_SpiderBite(ItemInfo* item) + void S_SpiderBite(ItemInfo* item) { auto pos = GetJointPosition(item, SpiderBite.meshNum, Vector3i(SpiderBite.Position)); DoBloodSplat(pos.x, pos.y, pos.z, 10, item->Pose.Position.y, item->RoomNumber); } - static void SpiderLeap(short itemNumber, ItemInfo* item, short angle) + void SpiderLeap(short itemNumber, ItemInfo* item, short angle) { auto vec = GameVector( item->Pose.Position.x, @@ -38,9 +38,7 @@ namespace TEN::Entities::TR2 if (item->Pose.Position.y > (vec.y - CLICK(1.5f))) return; - item->Pose.Position.x = vec.x; - item->Pose.Position.y = vec.y; - item->Pose.Position.z = vec.z; + item->Pose.Position = Vector3i(vec.x, vec.y, vec.z); if (item->RoomNumber != vec.roomNumber) ItemNewRoom(item->RoomNumber, vec.roomNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_spider.h b/TombEngine/Objects/TR2/Entity/tr2_spider.h index 23d72cc40..9b5876eec 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_spider.h +++ b/TombEngine/Objects/TR2/Entity/tr2_spider.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void SmallSpiderControl(short itemNumber); void BigSpiderControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.cpp b/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.cpp index 029bf528e..3e22f1adf 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.cpp @@ -13,7 +13,9 @@ #include "Sound/sound.h" #include "Specific/level.h" -namespace TEN::Entities::TR2 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR2 { const auto SwordBite = BiteInfo(Vector3(0.0f, 37.0f, 550.0f), 15); @@ -24,7 +26,7 @@ namespace TEN::Entities::TR2 ClearItem(itemNumber); } - static void SwordGuardianFly(ItemInfo* item) + void SwordGuardianFly(ItemInfo* item) { Vector3i pos; pos.x = (GetRandomControl() * 256 / 32768) + item->Pose.Position.x - 128; @@ -47,7 +49,7 @@ namespace TEN::Entities::TR2 short head = 0; short torso = 0; - bool laraAlive = LaraItem->HitPoints > 0; + bool isLaraAlive = LaraItem->HitPoints > 0; if (item->HitPoints <= 0) { @@ -68,7 +70,7 @@ namespace TEN::Entities::TR2 creature->LOT.Step = STEP_SIZE; creature->LOT.Drop = -STEP_SIZE; creature->LOT.Fly = NO_FLYING; - creature->LOT.Zone = ZONE_BASIC; + creature->LOT.Zone = ZoneType::Basic; AI_INFO AI; CreatureAIInfo(item, &AI); @@ -80,7 +82,7 @@ namespace TEN::Entities::TR2 creature->LOT.Step = WALL_SIZE * 20; creature->LOT.Drop = -WALL_SIZE * 20; creature->LOT.Fly = STEP_SIZE / 4; - creature->LOT.Zone = ZONE_FLYER; + creature->LOT.Zone = ZoneType::Flyer; CreatureAIInfo(item, &AI); } } @@ -114,15 +116,10 @@ namespace TEN::Entities::TR2 if (AI.ahead) head = AI.angle; - if (laraAlive) + if (isLaraAlive) { if (AI.bite && AI.distance < pow(SECTOR(1), 2)) - { - if (GetRandomControl() >= 0x4000) - item->Animation.TargetState = 5; - else - item->Animation.TargetState = 3; - } + item->Animation.TargetState = TestProbability(0.5f) ? 3 : 5; else { if (AI.zoneNumber == AI.enemyZone) @@ -142,7 +139,7 @@ namespace TEN::Entities::TR2 if (AI.ahead) head = AI.angle; - if (laraAlive) + if (isLaraAlive) { if (AI.bite && AI.distance < pow(SECTOR(2), 2)) item->Animation.TargetState = 10; diff --git a/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.h b/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.h index 9c837688b..588df13b8 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.h +++ b/TombEngine/Objects/TR2/Entity/tr2_sword_guardian.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseSwordGuardian(short itemNumber); void SwordGuardianControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.cpp b/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.cpp index 66e424bf2..5ab9a903b 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.cpp @@ -10,7 +10,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto WorkerDualGunBiteLeft = BiteInfo(Vector3(-2.0f, 275.0f, 23.0f), 6); const auto WorkerDualGunBiteRight = BiteInfo(Vector3(2.0f, 275.0f, 23.0f), 10); diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.h b/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.h index fd95395f8..d4a1761d3 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.h +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_dualrevolver.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void WorkerDualGunControl(short itemNumber); } diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.cpp b/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.cpp index 033534750..ab4ef1b0b 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.cpp @@ -16,7 +16,7 @@ #include "Specific/level.h" #include "Math/Math.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto WorkerFlamethrowerOffset = Vector3i(0, 140, 0); const auto WorkerFlamethrowerBite = BiteInfo(Vector3(0.0f, 250.0f, 32.0f), 9); diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.h b/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.h index 89fa4122b..f8b851421 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.h +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_flamethrower.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseWorkerFlamethrower(short itemNumber); void WorkerFlamethrower(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.cpp b/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.cpp index 6a69c3e15..2a198c8f5 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.cpp @@ -11,7 +11,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto WorkerMachineGunBite = BiteInfo(Vector3(0.0f, 308.0f, 32.0f), 9); diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.h b/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.h index fef58f199..1ba9b187a 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.h +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_machinegun.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseWorkerMachineGun(short itemNumber); void WorkerMachineGunControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.cpp b/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.cpp index 7bc96a3a8..c459c21ce 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.cpp @@ -12,7 +12,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { const auto WorkerShotgunBite = BiteInfo(Vector3(0.0f, 281.0f, 40.0f), 9); diff --git a/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.h b/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.h index a6ad5f5a6..5022fcbd7 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.h +++ b/TombEngine/Objects/TR2/Entity/tr2_worker_shotgun.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseWorkerShotgun(short itemNumber); void WorkerShotgunControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/Entity/tr2_yeti.cpp b/TombEngine/Objects/TR2/Entity/tr2_yeti.cpp index 9e127d5f4..d8a0028ae 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_yeti.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_yeti.cpp @@ -13,11 +13,14 @@ #include "Specific/setup.h" using namespace TEN::Math::Random; +using std::vector; -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { - const auto YetiBiteLeft = BiteInfo(Vector3(12.0f, 101.0f, 19.0f), 13); + const auto YetiBiteLeft = BiteInfo(Vector3(12.0f, 101.0f, 19.0f), 13); const auto YetiBiteRight = BiteInfo(Vector3(12.0f, 101.0f, 19.0f), 10); + const vector YetiAttackJoints1 = { 10, 12 }; // TODO: Rename. + const vector YetiAttackJoints2 = { 8, 9, 10 }; // TODO enum YetiState @@ -50,9 +53,9 @@ namespace TEN::Entities::TR2 bool isLaraAlive = LaraItem->HitPoints > 0; short angle = 0; + short tilt = 0; short torso = 0; short head = 0; - short tilt = 0; if (item->HitPoints <= 0) { @@ -88,9 +91,9 @@ namespace TEN::Entities::TR2 item->Animation.TargetState = item->Animation.RequiredState; else if (info->Mood == MoodType::Bored) { - if (TestProbability(0.008f) || !isLaraAlive) + if (TestProbability(1.0f / 128) || !isLaraAlive) item->Animation.TargetState = 7; - else if (TestProbability(0.015f)) + else if (TestProbability(1.0f / 64)) item->Animation.TargetState = 9; else if (TestProbability(0.025f)) item->Animation.TargetState = 3; @@ -116,9 +119,9 @@ namespace TEN::Entities::TR2 { if (isLaraAlive) { - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) item->Animation.TargetState = 2; - else if (TestProbability(0.015f)) + else if (TestProbability(1.0f / 64)) item->Animation.TargetState = 9; else if (TestProbability(0.025f)) { @@ -127,7 +130,7 @@ namespace TEN::Entities::TR2 } } } - else if (TestProbability(0.015f)) + else if (TestProbability(1.0f / 64)) item->Animation.TargetState = 2; break; @@ -140,9 +143,9 @@ namespace TEN::Entities::TR2 item->Animation.TargetState = 2; else if (info->Mood == MoodType::Bored) { - if (TestProbability(0.008f) || !isLaraAlive) + if (TestProbability(1.0f / 128) || !isLaraAlive) item->Animation.TargetState = 7; - else if (TestProbability(0.015f)) + else if (TestProbability(1.0f / 64)) item->Animation.TargetState = 2; else if (TestProbability(0.025f)) { @@ -150,7 +153,7 @@ namespace TEN::Entities::TR2 item->Animation.RequiredState = 3; } } - else if (TestProbability(0.015f)) + else if (TestProbability(1.0f / 64)) item->Animation.TargetState = 2; break; @@ -165,12 +168,12 @@ namespace TEN::Entities::TR2 item->Animation.TargetState = 1; else if (info->Mood == MoodType::Bored) { - if (TestProbability(0.008f) || !isLaraAlive) + if (TestProbability(1.0f / 128) || !isLaraAlive) { item->Animation.TargetState = 2; item->Animation.RequiredState = 7; } - else if (TestProbability(0.015f)) + else if (TestProbability(1.0f / 64)) { item->Animation.TargetState = 2; item->Animation.RequiredState = 9; @@ -213,8 +216,7 @@ namespace TEN::Entities::TR2 if (AI.ahead) torso = AI.angle; - if (!info->Flags && - item->TouchBits & 0x1400) + if (!info->Flags && item->TestBits(JointBitType::Touch, YetiAttackJoints1)) { CreatureEffect(item, YetiBiteRight, DoBloodSplat); DoDamage(info->Enemy, 100); @@ -230,11 +232,12 @@ namespace TEN::Entities::TR2 torso = AI.angle; if (!info->Flags && - item->TouchBits & (0x0700 | 0x1400)) + (item->TestBits(JointBitType::Touch, YetiAttackJoints1) || item->TestBits(JointBitType::Touch, YetiAttackJoints2))) { - if (item->TouchBits & 0x0700) + if (item->TestBits(JointBitType::Touch, YetiAttackJoints2)) CreatureEffect(item, YetiBiteLeft, DoBloodSplat); - if (item->TouchBits & 0x1400) + + if (item->TestBits(JointBitType::Touch, YetiAttackJoints1)) CreatureEffect(item, YetiBiteRight, DoBloodSplat); DoDamage(info->Enemy, 150); @@ -248,11 +251,12 @@ namespace TEN::Entities::TR2 torso = AI.angle; if (!info->Flags && - item->TouchBits & (0x0700 | 0x1400)) + (item->TestBits(JointBitType::Touch, YetiAttackJoints1) || item->TestBits(JointBitType::Touch, YetiAttackJoints2))) { - if (item->TouchBits & 0x0700) + if (item->TestBits(JointBitType::Touch, YetiAttackJoints2)) CreatureEffect(item, YetiBiteLeft, DoBloodSplat); - if (item->TouchBits & 0x1400) + + if (item->TestBits(JointBitType::Touch, YetiAttackJoints1)) CreatureEffect(item, YetiBiteRight, DoBloodSplat); DoDamage(info->Enemy, 200); diff --git a/TombEngine/Objects/TR2/Entity/tr2_yeti.h b/TombEngine/Objects/TR2/Entity/tr2_yeti.h index aa6ae5f16..f77c73350 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_yeti.h +++ b/TombEngine/Objects/TR2/Entity/tr2_yeti.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR2 +namespace TEN::Entities::Creatures::TR2 { void InitialiseYeti(short itemNumber); void YetiControl(short itemNumber); diff --git a/TombEngine/Objects/TR2/tr2_objects.cpp b/TombEngine/Objects/TR2/tr2_objects.cpp index 67c07965b..33375d613 100644 --- a/TombEngine/Objects/TR2/tr2_objects.cpp +++ b/TombEngine/Objects/TR2/tr2_objects.cpp @@ -37,7 +37,7 @@ #include "Objects/TR2/Vehicles/speedboat.h" #include "Objects/TR2/Vehicles/skidoo.h" -using namespace TEN::Entities::TR2; +using namespace TEN::Entities::Creatures::TR2; static void StartEntity(ObjectInfo* obj) { @@ -57,7 +57,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_WATER; + obj->ZoneType = ZoneType::Water; g_Level.Bones[obj->boneIndex + 9 * 4] |= ROT_Y; } @@ -78,7 +78,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_WATER; + obj->ZoneType = ZoneType::Water; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; } @@ -99,7 +99,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveAnim = true; obj->saveFlags = true; obj->pivotLength = 0; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; } obj = &Objects[ID_CROW]; @@ -118,7 +118,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveAnim = true; obj->saveFlags = true; obj->pivotLength = 0; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; } obj = &Objects[ID_RAT]; @@ -154,7 +154,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= (ROT_Y); g_Level.Bones[obj->boneIndex + 14 * 4] |= (ROT_Y); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_civvy.cpp b/TombEngine/Objects/TR3/Entity/tr3_civvy.cpp index 141414a5b..8301a9d78 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_civvy.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_civvy.cpp @@ -16,7 +16,7 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { constexpr auto CIVVY_ATTACK_DAMAGE = 40; constexpr auto CIVVY_SWIPE_DAMAGE = 50; @@ -42,7 +42,6 @@ namespace TEN::Entities::TR3 // TODO enum CivvyState { - CIVVY_STATE_NONE, CIVVY_STATE_IDLE, CIVVY_STATE_WALK_FORWARD, CIVVY_PUNCH2, @@ -89,11 +88,10 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short torsoX = 0; - short torsoY = 0; - short head = 0; short angle = 0; short tilt = 0; + auto extraHeadRot = EulerAngles::Zero; + auto extraTorsoRot = EulerAngles::Zero; if (item->BoxNumber != NO_BOX && (g_Level.Boxes[item->BoxNumber].flags & BLOCKED)) { @@ -119,18 +117,18 @@ namespace TEN::Entities::TR3 AI_INFO AI; CreatureAIInfo(item, &AI); - AI_INFO laraAiInfo; + AI_INFO laraAI; if (creature->Enemy == LaraItem) { - laraAiInfo.angle = AI.angle; - laraAiInfo.distance = AI.distance; + laraAI.angle = AI.angle; + laraAI.distance = AI.distance; } else { int laraDz = LaraItem->Pose.Position.z - item->Pose.Position.z; int laraDx = LaraItem->Pose.Position.x - item->Pose.Position.x; - laraAiInfo.angle = phd_atan(laraDz, laraDx) - item->Pose.Orientation.y; - laraAiInfo.distance = pow(laraDx, 2) + pow(laraDz, 2); + laraAI.angle = phd_atan(laraDz, laraDx) - item->Pose.Orientation.y; + laraAI.distance = pow(laraDx, 2) + pow(laraDz, 2); } GetCreatureMood(item, &AI, true); @@ -150,7 +148,7 @@ namespace TEN::Entities::TR3 auto* realEnemy = creature->Enemy; creature->Enemy = LaraItem; - if ((laraAiInfo.distance < CIVVY_AWARE_RANGE || item->HitStatus || TargetVisible(item, &laraAiInfo)) && + if ((laraAI.distance < CIVVY_AWARE_RANGE || item->HitStatus || TargetVisible(item, &laraAI)) && !(item->AIBits & FOLLOW)) { if (!creature->Alerted) @@ -170,13 +168,13 @@ namespace TEN::Entities::TR3 } case CIVVY_STATE_IDLE: - head = laraAiInfo.angle; creature->MaxTurn = 0; creature->Flags = 0; + extraHeadRot.y = laraAI.angle; if (item->AIBits & GUARD) { - head = AIGuard(creature); + extraHeadRot.y = AIGuard(creature); if (!(GetRandomControl() & 0xFF)) { if (item->Animation.ActiveState == CIVVY_STATE_IDLE) @@ -199,7 +197,7 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = CIVVY_STATE_RUN_FORWARD; } else if (creature->Mood == MoodType::Bored || - (item->AIBits & FOLLOW && (creature->ReachedGoal || laraAiInfo.distance > pow(SECTOR(2), 2)))) + (item->AIBits & FOLLOW && (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2)))) { if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; @@ -221,11 +219,11 @@ namespace TEN::Entities::TR3 case CIVVY_STATE_WALK_FORWARD: creature->MaxTurn = CIVVY_WALK_TURN_RATE_MAX; - head = laraAiInfo.angle; + extraHeadRot.y = laraAI.angle; if (item->AIBits & PATROL1) { - head = 0; + extraHeadRot.y = 0; item->Animation.TargetState = CIVVY_STATE_WALK_FORWARD; } else if (creature->Mood == MoodType::Escape) @@ -252,7 +250,7 @@ namespace TEN::Entities::TR3 tilt = angle / 2; if (AI.ahead) - head = AI.angle; + extraHeadRot.y = AI.angle; if (item->AIBits & GUARD) item->Animation.TargetState = CIVVY_WAIT; @@ -262,7 +260,7 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = CIVVY_STATE_IDLE; break; } - else if ((item->AIBits & FOLLOW) && (creature->ReachedGoal || laraAiInfo.distance > pow(SECTOR(2), 2))) + else if ((item->AIBits & FOLLOW) && (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) item->Animation.TargetState = CIVVY_STATE_IDLE; else if (creature->Mood == MoodType::Bored) item->Animation.TargetState = CIVVY_STATE_WALK_FORWARD; @@ -273,11 +271,12 @@ namespace TEN::Entities::TR3 case CIVVY_AIM0: creature->MaxTurn = CIVVY_WALK_TURN_RATE_MAX; + creature->Flags = 0; if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (AI.bite && AI.distance < CIVVY_ATTACK0_RANGE) @@ -285,16 +284,16 @@ namespace TEN::Entities::TR3 else item->Animation.TargetState = CIVVY_STATE_IDLE; - creature->Flags = 0; break; case CIVVY_AIM1: creature->MaxTurn = CIVVY_WALK_TURN_RATE_MAX; + creature->Flags = 0; if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (AI.ahead && AI.distance < CIVVY_ATTACK1_RANGE) @@ -302,7 +301,6 @@ namespace TEN::Entities::TR3 else item->Animation.TargetState = CIVVY_STATE_IDLE; - creature->Flags = 0; break; case CIVVY_AIM2: @@ -311,8 +309,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (AI.bite && AI.distance < CIVVY_ATTACK2_RANGE) @@ -327,8 +325,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (!creature->Flags && item->TestBits(JointBitType::Touch, CivvyAttackJoints)) @@ -346,8 +344,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (!creature->Flags && item->TestBits(JointBitType::Touch, CivvyAttackJoints)) @@ -368,8 +366,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (creature->Flags != 2 && item->TestBits(JointBitType::Touch, CivvyAttackJoints)) @@ -385,9 +383,9 @@ namespace TEN::Entities::TR3 } CreatureTilt(item, tilt); - CreatureJoint(item, 0, torsoY); - CreatureJoint(item, 1, torsoX); - CreatureJoint(item, 2, head); + CreatureJoint(item, 0, extraTorsoRot.y); + CreatureJoint(item, 1, extraTorsoRot.x); + CreatureJoint(item, 2, extraHeadRot.y); if (item->Animation.ActiveState < CIVVY_DEATH) { diff --git a/TombEngine/Objects/TR3/Entity/tr3_civvy.h b/TombEngine/Objects/TR3/Entity/tr3_civvy.h index 0bb46d8b8..f541c16e5 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_civvy.h +++ b/TombEngine/Objects/TR3/Entity/tr3_civvy.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void InitialiseCivvy(short itemNumber); void CivvyControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_cobra.cpp b/TombEngine/Objects/TR3/Entity/tr3_cobra.cpp index 899c40376..fdd54f640 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_cobra.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_cobra.cpp @@ -14,7 +14,7 @@ using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { constexpr auto COBRA_BITE_ATTACK_DAMAGE = 80; constexpr auto COBRA_BITE_POISON_POTENCY = 8; @@ -23,8 +23,7 @@ namespace TEN::Entities::TR3 constexpr auto COBRA_AWARE_RANGE = SQUARE(SECTOR(1.5f)); constexpr auto COBRA_SLEEP_RANGE = SQUARE(SECTOR(2.5f)); - constexpr auto PLAYER_DISTURB_VELOCITY = 15; - + constexpr auto COBRA_DISTURBANCE_VELOCITY = 15; constexpr auto COBRA_SLEEP_FRAME = 45; const auto CobraBite = BiteInfo(Vector3::Zero, 13); @@ -42,7 +41,7 @@ namespace TEN::Entities::TR3 enum CobraAnim { COBRA_ANIM_IDLE = 0, - COBRA_ANIM_WAKE_UP = 1, + COBRA_ANIM_SLEEP_TO_IDLE = 1, COBRA_ANIM_IDLE_TO_SLEEP = 2, COBRA_ANIM_BITE_ATTACK = 3, COBRA_ANIM_DEATH = 4 @@ -65,9 +64,9 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; short tilt = 0; + short head = 0; if (item->HitPoints <= 0 && item->HitPoints != NOT_TARGETABLE) { @@ -84,19 +83,23 @@ namespace TEN::Entities::TR3 GetCreatureMood(item, &AI, 1); CreatureMood(item, &AI, 1); - bool enemyMoving = false; - bool enemyVisible = false; - if (creature->Enemy && (GlobalCounter & 2)) - { - auto src = GameVector(creature->Enemy->Pose.Position, creature->Enemy->RoomNumber); - auto dest = GameVector(item->Pose.Position, item->RoomNumber); - enemyVisible = LOS(&src, &dest); + bool isEnemyMoving = false; + bool isEnemyVisible = false; - enemyMoving = creature->Enemy->Animation.Velocity.z > PLAYER_DISTURB_VELOCITY || - abs(creature->Enemy->Animation.Velocity.y) > PLAYER_DISTURB_VELOCITY; + if (creature->Enemy != nullptr && (GlobalCounter & 2)) + { + auto origin = GameVector(creature->Enemy->Pose.Position, creature->Enemy->RoomNumber); + auto target = GameVector(item->Pose.Position, item->RoomNumber); + isEnemyVisible = LOS(&origin, &target); + + if (creature->Enemy->Animation.Velocity.z > COBRA_DISTURBANCE_VELOCITY || + abs(creature->Enemy->Animation.Velocity.y) > COBRA_DISTURBANCE_VELOCITY) + { + isEnemyMoving = true; + } } - if (enemyVisible && item->Animation.ActiveState != COBRA_STATE_SLEEP) + if (isEnemyVisible && item->Animation.ActiveState != COBRA_STATE_SLEEP) { creature->Target.x = creature->Enemy->Pose.Position.x; creature->Target.z = creature->Enemy->Pose.Position.z; @@ -119,12 +122,10 @@ namespace TEN::Entities::TR3 creature->Flags = 0; if (AI.distance > COBRA_SLEEP_RANGE) - { item->Animation.TargetState = COBRA_STATE_SLEEP; - } - else if (creature->Enemy->HitPoints > 0 && enemyVisible && - ((AI.ahead && AI.distance < COBRA_ATTACK_RANGE && AI.verticalDistance <= GetBoundsAccurate(item)->Height()) || - item->HitStatus || enemyMoving)) + else if (creature->Enemy->HitPoints > 0 && isEnemyVisible && + ((AI.ahead && AI.distance < COBRA_ATTACK_RANGE && AI.verticalDistance <= GetBoundsAccurate(item)->Height()) || + item->HitStatus || isEnemyMoving)) { item->Animation.TargetState = COBRA_STATE_ATTACK; } @@ -149,12 +150,12 @@ namespace TEN::Entities::TR3 break; case COBRA_STATE_ATTACK: - if (creature->Flags != 1 && + if (!(creature->Flags & 1) && // 1 = is attacking. item->TestBits(JointBitType::Touch, CobraAttackJoints)) { DoDamage(creature->Enemy, COBRA_BITE_ATTACK_DAMAGE); CreatureEffect(item, CobraBite, DoBloodSplat); - creature->Flags = 1; + creature->Flags |= 1; // 1 = is attacking. if (creature->Enemy->IsLara()) GetLaraInfo(creature->Enemy)->PoisonPotency += COBRA_BITE_POISON_POTENCY; diff --git a/TombEngine/Objects/TR3/Entity/tr3_cobra.h b/TombEngine/Objects/TR3/Entity/tr3_cobra.h index 53e817328..261d28bd3 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_cobra.h +++ b/TombEngine/Objects/TR3/Entity/tr3_cobra.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void InitialiseCobra(short itemNum); void CobraControl(short itemNum); diff --git a/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.cpp b/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.cpp index 76e987e2e..bff45c5e8 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.cpp @@ -9,7 +9,7 @@ #include "Objects/TR3/fish.h" #include "Specific/level.h" -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { int PirahnaHitWait = false; int CarcassItem = NO_ITEM; diff --git a/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.h b/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.h index 8f99aa324..5b7cb0af4 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.h +++ b/TombEngine/Objects/TR3/Entity/tr3_fish_emitter.h @@ -1,7 +1,7 @@ #pragma once #include "Game/items.h" -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void SetupShoal(int shoalNumber); void ControlFish(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_flamethrower.cpp b/TombEngine/Objects/TR3/Entity/tr3_flamethrower.cpp index 3a27347f9..56be2df8e 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_flamethrower.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_flamethrower.cpp @@ -16,7 +16,9 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR3 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR3 { const auto FlamethrowerOffset = Vector3i(0, 340, 0); const auto FlamethrowerBite = BiteInfo(Vector3(0.0f, 340.0f, 64.0f), 7); @@ -41,33 +43,26 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short torsoX = 0; - short torsoY = 0; short angle = 0; short tilt = 0; - short head = 0; + auto extraHeadRot = EulerAngles::Zero; + auto extraTorsoRot = EulerAngles::Zero; auto pos = GetJointPosition(item, FlamethrowerBite.meshNum, Vector3i(FlamethrowerBite.Position)); - int random = GetRandomControl(); + int randomInt = GetRandomControl(); if (item->Animation.ActiveState != 6 && item->Animation.ActiveState != 11) { - TriggerDynamicLight(pos.x, pos.y, pos.z, (random & 3) + 6, 24 - ((random / 16) & 3), 16 - ((random / 64) & 3), random & 3); + TriggerDynamicLight(pos.x, pos.y, pos.z, (randomInt & 3) + 6, 24 - ((randomInt / 16) & 3), 16 - ((randomInt / 64) & 3), randomInt & 3); TriggerPilotFlame(itemNumber, 9); } else - { - TriggerDynamicLight(pos.x, pos.y, pos.z, (random & 3) + 10, 31 - ((random / 16) & 3), 24 - ((random / 64) & 3), random & 7); - } + TriggerDynamicLight(pos.x, pos.y, pos.z, (randomInt & 3) + 10, 31 - ((randomInt / 16) & 3), 24 - ((randomInt / 64) & 3), randomInt & 7); if (item->HitPoints <= 0) { if (item->Animation.ActiveState != 7) - { - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 19; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 7; - } + SetAnimation(item, 19); } else { @@ -82,9 +77,8 @@ namespace TEN::Entities::TR3 ItemInfo* target = nullptr; int minDistance = INT_MAX; - for (int i = 0; i < ActiveCreatures.size(); i++) + for (auto& currentCreature : ActiveCreatures) { - auto* currentCreature = ActiveCreatures[i]; if (currentCreature->ItemNumber == NO_ITEM || currentCreature->ItemNumber == itemNumber) continue; @@ -147,13 +141,13 @@ namespace TEN::Entities::TR3 case 1: creature->MaxTurn = 0; creature->Flags = 0; - head = laraAI.angle; + extraHeadRot.y = laraAI.angle; if (item->AIBits & GUARD) { - head = AIGuard(creature); + extraHeadRot.y = AIGuard(creature); - if (!(GetRandomControl() & 0xFF)) + if (TestProbability(1.0f / 128)) item->Animation.TargetState = 4; break; @@ -169,21 +163,21 @@ namespace TEN::Entities::TR3 else item->Animation.TargetState = 2; } - else if (creature->Mood == MoodType::Bored && AI.ahead && !(GetRandomControl() & 0xFF)) + else if (creature->Mood == MoodType::Bored && AI.ahead && TestProbability(1.0f / 128)) item->Animation.TargetState = 4; - else if (creature->Mood == MoodType::Attack || !(GetRandomControl() & 0xFF)) + else if (creature->Mood == MoodType::Attack || TestProbability(1.0f / 128)) item->Animation.TargetState = 2; break; case 4: - head = laraAI.angle; + extraHeadRot.y = laraAI.angle; if (item->AIBits & GUARD) { - head = AIGuard(creature); + extraHeadRot.y = AIGuard(creature); - if (!(GetRandomControl() & 0xFF)) + if (TestProbability(1.0f / 128)) item->Animation.TargetState = 1; break; @@ -192,7 +186,7 @@ namespace TEN::Entities::TR3 AI.distance < pow(SECTOR(4), 2) && (realEnemy != LaraItem || creature->HurtByLara) || creature->Mood != MoodType::Bored || - !(GetRandomControl() & 0xFF))) + TestProbability(1.0f / 128))) { item->Animation.TargetState = 1; } @@ -200,17 +194,12 @@ namespace TEN::Entities::TR3 break; case 2: - creature->Flags = 0; creature->MaxTurn = ANGLE(5.0f); - head = laraAI.angle; + creature->Flags = 0; + extraHeadRot.y = laraAI.angle; if (item->AIBits & GUARD) - { - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 12; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 1; - item->Animation.TargetState = 1; - } + SetAnimation(item, 12); else if (item->AIBits & PATROL1) item->Animation.TargetState = 2; else if (creature->Mood == MoodType::Escape) @@ -235,8 +224,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; if (Targetable(item, &AI) && AI.distance < pow(SECTOR(4), 2) && @@ -255,8 +244,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; if (Targetable(item, &AI) && AI.distance < pow(SECTOR(4), 2) && @@ -276,8 +265,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; if (Targetable(item, &AI) && AI.distance < pow(SECTOR(4), 2) && @@ -311,12 +300,12 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; if (Targetable(item, &AI) && AI.distance < pow(SECTOR(4), 2) && - (realEnemy != LaraItem || creature->HurtByLara)) + (!realEnemy->IsLara() || creature->HurtByLara)) { item->Animation.TargetState = 6; } @@ -343,9 +332,9 @@ namespace TEN::Entities::TR3 } CreatureTilt(item, tilt); - CreatureJoint(item, 0, torsoY); - CreatureJoint(item, 1, torsoX); - CreatureJoint(item, 2, head); + CreatureJoint(item, 0, extraTorsoRot.y); + CreatureJoint(item, 1, extraTorsoRot.x); + CreatureJoint(item, 2, extraHeadRot.y); CreatureAnimation(itemNumber, angle, 0); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_flamethrower.h b/TombEngine/Objects/TR3/Entity/tr3_flamethrower.h index 61044cf99..761df41cf 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_flamethrower.h +++ b/TombEngine/Objects/TR3/Entity/tr3_flamethrower.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void FlameThrowerControl(short itemNumber); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_monkey.cpp b/TombEngine/Objects/TR3/Entity/tr3_monkey.cpp index d01d4a5fb..0cb7a9784 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_monkey.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_monkey.cpp @@ -12,23 +12,85 @@ #include "Specific/level.h" #include "Specific/setup.h" +using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { - const vector MonkeyAttackJoints = { 10, 13 }; + // TODO: Work out damage constants. + constexpr auto MONKEY_SWIPE_ATTACK_PLAYER_DAMAGE = 40; + constexpr auto MONKEY_SWIPE_ATTACK_CREATURE_DAMAGE = 20; + + // TODO: Range constants. + const auto MonkeyBite = BiteInfo(Vector3(10.0f, 10.0f, 11.0f), 13); + const vector MonkeyAttackJoints = { 10, 13 }; + + enum MonkeyState + { + // No states 0-1. + MONKEY_STATE_WALK_FORWARD = 2, + MONKEY_STATE_IDLE = 3, + MONKEY_STATE_RUN_FORWARD = 4, + MONKEY_STATE_BITE_ATTACK = 5, // Check. + MONKEY_STATE_SIT = 6, + MONKEY_STATE_SIT_EAT = 7, + MONKEY_STATE_SIT_SCRATCH = 8, + MONKEY_STATE_RUN_FORWARD_ROLL = 9, + MONKEY_STATE_POUND_GROUND = 10, + MONKEY_STATE_DEATH = 11, + MONKEY_STATE_SWIPE_ATTACK = 12, + MONKEY_STATE_JUMP_ATTACK = 13, + MONKEY_STATE_HIGH_JUMP_ATTACK = 14, + MONKEY_STATE_VAULT_UP_1_BLOCK = 15, + MONKEY_STATE_VAULT_UP_0_POINT_3_BLOCKS = 16, + MONKEY_STATE_VAULT_UP_0_POINT_2_BLOCKS = 17, + MONKEY_STATE_VAULT_DOWN_1_BLOCK = 18, + MONKEY_STATE_VAULT_DOWN_0_POINT_3_BLOCKS = 19, + MONKEY_STATE_VAULT_DOWN_0_POINT_2_BLOCKS = 20 + }; + + enum MonkeyAnim + { + MONKEY_ANIM_WALK_FORWARD = 0, + MONKEY_ANIM_WALK_FORWARD_TO_SIT = 1, + MONKEY_ANIM_SIT = 2, + MONKEY_ANIM_SIT_TO_WALK_FORWARD = 3, + MONKEY_ANIM_SIT_EAT = 4, + MONKEY_ANIM_SIT_SCRATCH = 5, + MONKEY_ANIM_RUN_FORWARD = 6, + MONKEY_ANIM_RUN_FORWARD_ROLL = 7, + MONKEY_ANIM_IDLE_POUND_GROUND = 8, + MONKEY_ANIM_IDLE = 9, + MONKEY_ANIM_IDLE_TO_RUN_FORWARD = 10, + MONKEY_ANIM_WALK_FORWARD_TO_RUN_FORWARD = 11, + MONKEY_ANIM_RUN_FORWARD_TO_IDLE = 12, + MONKEY_ANIM_SIT_TO_IDLE = 13, + MONKEY_ANIM_DEATH = 14, + MONKEY_ANIM_RUN_FORWARD_TO_WALK_FORWARD = 15, + MONKEY_ANIM_IDLE_TO_SIT = 16, + MONKEY_ANIM_VAULT_UP_1_BLOCK = 17, + MONKEY_ANIM_VAULT_UP_0_POINT_3_BLOCKS = 18, + MONKEY_ANIM_VAULT_UP_0_POINT_2_BLOCKS = 19, + MONKEY_ANIM_VAULT_DOWN_1_BLOCK = 20, + MONKEY_ANIM_VAULT_DOWN_0_POINT_3_BLOCKS = 21, + MONKEY_ANIM_VAULT_DOWN_0_POINT_2_BLOCKS = 22, + MONKEY_ANIM_SWIPE_ATTACK = 23, + MONKEY_ANIM_JUMP_ATTACK = 24, + MONKEY_ANIM_BITE_ATTACK = 25, + MONKEY_ANIM_HIGH_JUMP_ATTACK_START = 26, + MONKEY_ANIM_HIGH_JUMP_ATTACK_CONTINUE = 27, + MONKEY_ANIM_HIGH_JUMP_ATTACK_END = 28, + MONKEY_ANIM_IDLE_TO_WALK_FORWARD = 29, + MONKEY_ANIM_WALK_FORWARD_TO_IDLE = 30 + }; void InitialiseMonkey(short itemNumber) { auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 2; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 6; - item->Animation.TargetState = 6; + SetAnimation(item, MONKEY_ANIM_SIT); } void MonkeyControl(short itemNumber) @@ -39,20 +101,17 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short headX = 0; - short headY = 0; - short torsoY = 0; short angle = 0; short tilt = 0; + auto extraHeadRot = EulerAngles::Zero; + auto extraTorsoRot = EulerAngles::Zero; if (item->HitPoints <= 0) { - if (item->Animation.ActiveState != 11) + if (item->Animation.ActiveState != MONKEY_STATE_DEATH) { + SetAnimation(item, MONKEY_ANIM_DEATH); item->MeshBits = ALL_JOINT_BITS; - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 14; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 11; } } else @@ -63,12 +122,11 @@ namespace TEN::Entities::TR3 creature->Enemy = LaraItem; else { - int minDistance = 0x7FFFFFFF; creature->Enemy = nullptr; + int minDistance = INT_MAX; - for (int i = 0; i < ActiveCreatures.size(); i++) + for (auto& currentCreature : ActiveCreatures) { - auto* currentCreature = ActiveCreatures[i]; if (currentCreature->ItemNumber == NO_ITEM || currentCreature->ItemNumber == itemNumber) continue; @@ -109,11 +167,11 @@ namespace TEN::Entities::TR3 AI_INFO AI; CreatureAIInfo(item, &AI); - if (!creature->HurtByLara && creature->Enemy == LaraItem) + if (!creature->HurtByLara && creature->Enemy->IsLara()) creature->Enemy = nullptr; AI_INFO laraAI; - if (creature->Enemy == LaraItem) + if (creature->Enemy->IsLara()) { laraAI.angle = AI.angle; laraAI.distance = AI.distance; @@ -146,144 +204,147 @@ namespace TEN::Entities::TR3 switch (item->Animation.ActiveState) { - case 6: - creature->Flags = 0; + case MONKEY_STATE_SIT: creature->MaxTurn = 0; - torsoY = laraAI.angle; + creature->Flags = 0; + extraTorsoRot.y = laraAI.angle; if (item->AIBits & GUARD) { - torsoY = AIGuard(creature); - if (!(GetRandomControl() & 0xF)) + extraTorsoRot.y = AIGuard(creature); + if (TestProbability(0.06f)) { - if (GetRandomControl() & 0x1) - item->Animation.TargetState = 8; + if (TestProbability(0.5f)) + item->Animation.TargetState = MONKEY_STATE_SIT_EAT; else - item->Animation.TargetState = 7; + item->Animation.TargetState = MONKEY_STATE_SIT_SCRATCH; } break; } - else if (item->AIBits & PATROL1) - item->Animation.TargetState = 2; + item->Animation.TargetState = MONKEY_STATE_WALK_FORWARD; else if (creature->Mood == MoodType::Escape) - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; else if (creature->Mood == MoodType::Bored) { if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; - else if (!(GetRandomControl() & 0xF)) - item->Animation.TargetState = 2; - else if (!(GetRandomControl() & 0xF)) + else if (TestProbability(0.06f)) + item->Animation.TargetState = MONKEY_STATE_WALK_FORWARD; + else if (TestProbability(0.06f)) { - if (GetRandomControl() & 0x1) - item->Animation.TargetState = 8; + if (TestProbability(0.5f)) + item->Animation.TargetState = MONKEY_STATE_SIT_EAT; else - item->Animation.TargetState = 7; + item->Animation.TargetState = MONKEY_STATE_SIT_SCRATCH; } } - else if ((item->AIBits & FOLLOW) && (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) + else if ((item->AIBits & FOLLOW) && + (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) { if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; else if (AI.ahead) - item->Animation.TargetState = 6; + item->Animation.TargetState = MONKEY_STATE_SIT; else - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; } else if (AI.bite && AI.distance < pow(682, 2)) - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; else if (AI.bite && AI.distance < pow(682, 2)) - item->Animation.TargetState = 2; + item->Animation.TargetState = MONKEY_STATE_WALK_FORWARD; else - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; break; - case 3: + case MONKEY_STATE_IDLE: creature->MaxTurn = 0; creature->Flags = 0; - torsoY = laraAI.angle; + extraTorsoRot.y = laraAI.angle; if (item->AIBits & GUARD) { - torsoY = AIGuard(creature); + extraTorsoRot.y = AIGuard(creature); - if (!(GetRandomControl() & 15)) + if (TestProbability(0.06f)) { - if (GetRandomControl() & 1) - item->Animation.TargetState = 10; + if (TestProbability(0.5f)) + item->Animation.TargetState = MONKEY_STATE_POUND_GROUND; else - item->Animation.TargetState = 6; + item->Animation.TargetState = MONKEY_STATE_SIT; } break; } else if (item->AIBits & PATROL1) - item->Animation.TargetState = 2; + item->Animation.TargetState = MONKEY_STATE_WALK_FORWARD; else if (creature->Mood == MoodType::Escape) { if (Lara.TargetEntity != item && AI.ahead) - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; else - item->Animation.TargetState = 4; + item->Animation.TargetState = MONKEY_STATE_RUN_FORWARD; } else if (creature->Mood == MoodType::Bored) { if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; - else if (!(GetRandomControl() & 15)) - item->Animation.TargetState = 2; - else if (!(GetRandomControl() & 15)) + else if (TestProbability(0.06f)) + item->Animation.TargetState = MONKEY_STATE_WALK_FORWARD; + else if (TestProbability(0.06f)) { - if (GetRandomControl() & 1) - item->Animation.TargetState = 10; + if (TestProbability(0.5f)) + item->Animation.TargetState = MONKEY_STATE_POUND_GROUND; else - item->Animation.TargetState = 6; + item->Animation.TargetState = MONKEY_STATE_SIT; } } - else if (item->AIBits & FOLLOW && (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) + else if (item->AIBits & FOLLOW && + (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) { if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; else if (AI.ahead) - item->Animation.TargetState = 6; + item->Animation.TargetState = MONKEY_STATE_SIT; else - item->Animation.TargetState = 4; + item->Animation.TargetState = MONKEY_STATE_RUN_FORWARD; } else if (AI.bite && AI.distance < pow(341, 2)) { if (LaraItem->Pose.Position.y < item->Pose.Position.y) - item->Animation.TargetState = 13; + item->Animation.TargetState = MONKEY_STATE_JUMP_ATTACK; else - item->Animation.TargetState = 12; + item->Animation.TargetState = MONKEY_STATE_SWIPE_ATTACK; } else if (AI.bite && AI.distance < pow(682, 2)) - item->Animation.TargetState = 14; + item->Animation.TargetState = MONKEY_STATE_HIGH_JUMP_ATTACK; else if (AI.bite && AI.distance < pow(682, 2)) - item->Animation.TargetState = 2; - else if (AI.distance < pow(682, 2) && creature->Enemy != LaraItem && creature->Enemy != nullptr && - creature->Enemy->ObjectNumber != ID_AI_PATROL1 && creature->Enemy->ObjectNumber != ID_AI_PATROL2 && - abs(item->Pose.Position.y - creature->Enemy->Pose.Position.y) < 256) + item->Animation.TargetState = MONKEY_STATE_WALK_FORWARD; + else if (AI.distance < pow(682, 2) && + !creature->Enemy->IsLara() && creature->Enemy != nullptr && + creature->Enemy->ObjectNumber != ID_AI_PATROL1 && + creature->Enemy->ObjectNumber != ID_AI_PATROL2 && + abs(item->Pose.Position.y - creature->Enemy->Pose.Position.y) < CLICK(1)) { - item->Animation.TargetState = 5; + item->Animation.TargetState = MONKEY_STATE_BITE_ATTACK; } else if (AI.bite && AI.distance < pow(SECTOR(1), 2)) - item->Animation.TargetState = 9; + item->Animation.TargetState = MONKEY_STATE_RUN_FORWARD_ROLL; else - item->Animation.TargetState = 4; + item->Animation.TargetState = MONKEY_STATE_RUN_FORWARD; break; - case 5: + case MONKEY_STATE_BITE_ATTACK: creature->ReachedGoal = true; if (creature->Enemy == nullptr) break; else if ((creature->Enemy->ObjectNumber == ID_SMALLMEDI_ITEM || creature->Enemy->ObjectNumber == ID_KEY_ITEM4) && - item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 12) + item->Animation.FrameNumber == (g_Level.Anims[item->Animation.AnimNumber].frameBase + 12)) { if (creature->Enemy->RoomNumber == NO_ROOM || creature->Enemy->Status == ITEM_INVISIBLE || @@ -298,9 +359,8 @@ namespace TEN::Entities::TR3 creature->Enemy->RoomNumber = NO_ROOM; creature->Enemy->CarriedItem = NO_ITEM; - for (int i = 0; i < ActiveCreatures.size(); i++) + for (auto& currentCreature : ActiveCreatures) { - auto* currentCreature = ActiveCreatures[i]; if (currentCreature->ItemNumber == NO_ITEM || currentCreature->ItemNumber == itemNumber) continue; @@ -318,15 +378,14 @@ namespace TEN::Entities::TR3 } } } - else if (creature->Enemy->ObjectNumber == ID_AI_AMBUSH && item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 12) + else if (creature->Enemy->ObjectNumber == ID_AI_AMBUSH && + item->Animation.FrameNumber == (g_Level.Anims[item->Animation.AnimNumber].frameBase + 12)) { item->AIBits = 0; auto* carriedItem = &g_Level.Items[item->CarriedItem]; - carriedItem->Pose.Position.x = item->Pose.Position.x; - carriedItem->Pose.Position.y = item->Pose.Position.y; - carriedItem->Pose.Position.z = item->Pose.Position.z; + carriedItem->Pose.Position = item->Pose.Position; ItemNewRoom(item->CarriedItem, item->RoomNumber); item->CarriedItem = NO_ITEM; @@ -348,60 +407,106 @@ namespace TEN::Entities::TR3 break; - case 2: + case MONKEY_STATE_WALK_FORWARD: creature->MaxTurn = ANGLE(7.0f); - torsoY = laraAI.angle; + extraTorsoRot.y = laraAI.angle; if (item->AIBits & PATROL1) { - item->Animation.TargetState = 2; - torsoY = 0; + item->Animation.TargetState = MONKEY_STATE_WALK_FORWARD; + extraTorsoRot.y = 0; } else if (creature->Mood == MoodType::Escape) - item->Animation.TargetState = 4; + item->Animation.TargetState = MONKEY_STATE_RUN_FORWARD; else if (creature->Mood == MoodType::Bored) { - if (GetRandomControl() < 256) - item->Animation.TargetState = 6; + if (TestProbability(1.0f / 128)) + item->Animation.TargetState = MONKEY_STATE_SIT; } else if (AI.bite && AI.distance < pow(682, 2)) - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; break; - case 4: + case MONKEY_STATE_RUN_FORWARD: creature->MaxTurn = ANGLE(11.0f); tilt = angle / 2; if (AI.ahead) - torsoY = AI.angle; + extraTorsoRot.y = AI.angle; if (item->AIBits & GUARD) - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; else if (creature->Mood == MoodType::Escape) { if (Lara.TargetEntity != item && AI.ahead) - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; + break; } - else if ((item->AIBits & FOLLOW) && (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) - item->Animation.TargetState = 3; + else if ((item->AIBits & FOLLOW) && + (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) + { + item->Animation.TargetState = MONKEY_STATE_IDLE; + } else if (creature->Mood == MoodType::Bored) - item->Animation.TargetState = 9; + item->Animation.TargetState = MONKEY_STATE_RUN_FORWARD_ROLL; else if (AI.distance < pow(682, 2)) - item->Animation.TargetState = 3; + item->Animation.TargetState = MONKEY_STATE_IDLE; else if (AI.bite && AI.distance < pow(SECTOR(1), 2)) - item->Animation.TargetState = 9; + item->Animation.TargetState = MONKEY_STATE_RUN_FORWARD_ROLL; break; - case 12: + case MONKEY_STATE_SWIPE_ATTACK: creature->MaxTurn = 0; if (AI.ahead) { - headY = AI.angle; - headX = AI.xAngle; + extraHeadRot.x = AI.xAngle; + extraHeadRot.y = AI.angle; + } + + if (abs(AI.angle) < ANGLE(7.0f)) + item->Pose.Orientation.y += AI.angle; + else if (AI.angle < 0) + item->Pose.Orientation.y -= ANGLE(7.0f); + else + item->Pose.Orientation.y += ANGLE(7.0f); + + if (enemy->IsLara()) + { + if (!creature->Flags && item->TestBits(JointBitType::Touch, MonkeyAttackJoints)) + { + DoDamage(enemy, MONKEY_SWIPE_ATTACK_PLAYER_DAMAGE); + CreatureEffect(item, MonkeyBite, DoBloodSplat); + creature->Flags = 1; + } + } + else + { + if (!creature->Flags && enemy) + { + if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < CLICK(1) && + abs(enemy->Pose.Position.y - item->Pose.Position.y) <= CLICK(1) && + abs(enemy->Pose.Position.z - item->Pose.Position.z) < CLICK(1)) + { + DoDamage(enemy, MONKEY_SWIPE_ATTACK_CREATURE_DAMAGE); + CreatureEffect(item, MonkeyBite, DoBloodSplat); + creature->Flags = 1; + } + } + } + + break; + + case MONKEY_STATE_JUMP_ATTACK: + creature->MaxTurn = 0; + + if (AI.ahead) + { + extraHeadRot.x = AI.xAngle; + extraHeadRot.y = AI.angle; } if (abs(AI.angle) < ANGLE(7.0f)) @@ -422,11 +527,9 @@ namespace TEN::Entities::TR3 } else { - if (!creature->Flags && enemy) + if (!creature->Flags && enemy != nullptr) { - if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < CLICK(1) && - abs(enemy->Pose.Position.y - item->Pose.Position.y) <= CLICK(1) && - abs(enemy->Pose.Position.z - item->Pose.Position.z) < CLICK(1)) + if (Vector3i::Distance(item->Pose.Position, enemy->Pose.Position) <= CLICK(1)) { DoDamage(enemy, 20); CreatureEffect(item, MonkeyBite, DoBloodSplat); @@ -437,55 +540,13 @@ namespace TEN::Entities::TR3 break; - case 13: + case MONKEY_STATE_HIGH_JUMP_ATTACK: creature->MaxTurn = 0; if (AI.ahead) { - headY = AI.angle; - headX = AI.xAngle; - } - - if (abs(AI.angle) < ANGLE(7.0f)) - item->Pose.Orientation.y += AI.angle; - else if (AI.angle < 0) - item->Pose.Orientation.y -= ANGLE(7.0f); - else - item->Pose.Orientation.y += ANGLE(7.0f); - - if (enemy->IsLara()) - { - if (!creature->Flags && item->TestBits(JointBitType::Touch, MonkeyAttackJoints)) - { - DoDamage(enemy, 40); - CreatureEffect(item, MonkeyBite, DoBloodSplat); - creature->Flags = 1; - } - } - else - { - if (!creature->Flags && enemy) - { - if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < CLICK(1) && - abs(enemy->Pose.Position.y - item->Pose.Position.y) <= CLICK(1) && - abs(enemy->Pose.Position.z - item->Pose.Position.z) < CLICK(1)) - { - DoDamage(enemy, 20); - CreatureEffect(item, MonkeyBite, DoBloodSplat); - creature->Flags = 1; - } - } - } - - break; - - case 14: - creature->MaxTurn = 0; - - if (AI.ahead) - { - headX = AI.xAngle; - headY = AI.angle; + extraHeadRot.x = AI.xAngle; + extraHeadRot.y = AI.angle; } if (abs(AI.angle) < ANGLE(7.0f)) @@ -508,9 +569,7 @@ namespace TEN::Entities::TR3 { if (creature->Flags != 1 && enemy) { - if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < CLICK(1) && - abs(enemy->Pose.Position.y - item->Pose.Position.y) <= CLICK(1) && - abs(enemy->Pose.Position.z - item->Pose.Position.z) < CLICK(1)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= CLICK(1)) { DoDamage(enemy, 25); CreatureEffect(item, MonkeyBite, DoBloodSplat); @@ -524,54 +583,42 @@ namespace TEN::Entities::TR3 } CreatureTilt(item, tilt); - CreatureJoint(item, 0, headY); - CreatureJoint(item, 1, headX); - CreatureJoint(item, 2, torsoY); + CreatureJoint(item, 0, extraHeadRot.y); + CreatureJoint(item, 1, extraHeadRot.x); + CreatureJoint(item, 2, extraTorsoRot.y); - if (item->Animation.ActiveState < 15) + if (item->Animation.ActiveState < MONKEY_STATE_VAULT_UP_1_BLOCK) { - switch (CreatureVault(itemNumber, angle, 2, 128)) + switch (CreatureVault(itemNumber, angle, 2, CLICK(0.5f))) { case 2: + SetAnimation(item, MONKEY_ANIM_VAULT_UP_0_POINT_2_BLOCKS); creature->MaxTurn = 0; - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 19; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 17; break; case 3: + SetAnimation(item, MONKEY_ANIM_VAULT_UP_0_POINT_3_BLOCKS); creature->MaxTurn = 0; - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 18; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 16; break; case 4: + SetAnimation(item, MONKEY_ANIM_VAULT_UP_1_BLOCK); creature->MaxTurn = 0; - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 17; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 15; break; case -2: + SetAnimation(item, MONKEY_ANIM_VAULT_DOWN_0_POINT_2_BLOCKS); creature->MaxTurn = 0; - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 22; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 20; break; case -3: + SetAnimation(item, MONKEY_ANIM_VAULT_DOWN_0_POINT_3_BLOCKS); creature->MaxTurn = 0; - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 21; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 19; break; case -4: + SetAnimation(item, MONKEY_ANIM_VAULT_DOWN_1_BLOCK); creature->MaxTurn = 0; - item->Animation.AnimNumber = Objects[ID_MONKEY].animIndex + 20; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 18; break; } } diff --git a/TombEngine/Objects/TR3/Entity/tr3_monkey.h b/TombEngine/Objects/TR3/Entity/tr3_monkey.h index e136456b9..8b617e255 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_monkey.h +++ b/TombEngine/Objects/TR3/Entity/tr3_monkey.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void InitialiseMonkey(short itemNumber); void MonkeyControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_mp_gun.cpp b/TombEngine/Objects/TR3/Entity/tr3_mp_gun.cpp index b7357ef54..b4e9b714d 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_mp_gun.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_mp_gun.cpp @@ -16,13 +16,14 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR3 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR3 { const auto MPGunBite = BiteInfo(Vector3(0.0f, 160.0f, 40.0f), 13); enum MPGunState { - MPGUN_STATE_NONE = 0, MPGUN_STATE_WAIT = 1, MPGUN_STATE_WALK = 2, MPGUN_STATE_RUN = 3, @@ -59,11 +60,10 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; short tilt = 0; - short torsoX = 0; - short torsoY = 0; + short head = 0; + auto extraTorsoRot = EulerAngles::Zero; if (creature->FiredWeapon) { @@ -75,8 +75,8 @@ namespace TEN::Entities::TR3 if (item->BoxNumber != NO_BOX && (g_Level.Boxes[item->BoxNumber].flags & BLOCKED)) { - DoLotsOfBlood(item->Pose.Position.x, item->Pose.Position.y - (GetRandomControl() & 255) - 32, item->Pose.Position.z, (GetRandomControl() & 127) + 128, GetRandomControl() * 2, item->RoomNumber, 3); DoDamage(item, 20); + DoLotsOfBlood(item->Pose.Position.x, item->Pose.Position.y - (GetRandomControl() & 255) - 32, item->Pose.Position.z, (GetRandomControl() & 127) + 128, GetRandomControl() * 2, item->RoomNumber, 3); } AI_INFO AI; @@ -90,7 +90,7 @@ namespace TEN::Entities::TR3 item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; item->Animation.ActiveState = 13; } - else if (!(GetRandomControl() & 3) && item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 1) + else if (TestProbability(0.25f) && item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 1) { CreatureAIInfo(item, &AI); @@ -100,8 +100,8 @@ namespace TEN::Entities::TR3 AI.angle < ANGLE(45.0f)) { head = AI.angle; - torsoY = AI.angle; - ShotLara(item, &AI, MPGunBite, torsoY, 32); + extraTorsoRot.y = AI.angle; + ShotLara(item, &AI, MPGunBite, extraTorsoRot.y, 32); SoundEffect(SFX_TR3_OIL_SMG_FIRE, &item->Pose, SoundEnvironment::Land, 1.0f, 0.7f); creature->FiredWeapon = 1; } @@ -219,10 +219,9 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = MPGUN_STATE_RUN; else if (Targetable(item, &AI)) { - int random = GetRandomControl(); - if (random < 0x2000) + if (TestProbability(0.25f)) item->Animation.TargetState = MPGUN_STATE_SHOOT_1; - else if (random < 0x4000) + else if (TestProbability(0.5f)) item->Animation.TargetState = MPGUN_STATE_SHOOT_2; else item->Animation.TargetState = MPGUN_STATE_AIM_3; @@ -304,17 +303,18 @@ namespace TEN::Entities::TR3 case MPGUN_STATE_AIM_1: if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (item->Animation.AnimNumber == Objects[ID_MP_WITH_GUN].animIndex + 12 || - (item->Animation.AnimNumber == Objects[ID_MP_WITH_GUN].animIndex + 1 && item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 10)) + (item->Animation.AnimNumber == Objects[ID_MP_WITH_GUN].animIndex + 1 && + item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 10)) { - if (!ShotLara(item, &AI, MPGunBite, torsoY, 32)) + if (!ShotLara(item, &AI, MPGunBite, extraTorsoRot.y, 32)) item->Animation.RequiredState = MPGUN_STATE_WAIT; } - else if (item->HitStatus && !(GetRandomControl() & 0x3) && cover) + else if (item->HitStatus && TestProbability(0.25f) && cover) { item->Animation.RequiredState = MPGUN_STATE_CROUCH; item->Animation.TargetState = MPGUN_STATE_WAIT; @@ -325,8 +325,8 @@ namespace TEN::Entities::TR3 case MPGUN_STATE_SHOOT_1: if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (item->Animation.RequiredState == MPGUN_STATE_WAIT) @@ -337,16 +337,16 @@ namespace TEN::Entities::TR3 case MPGUN_STATE_SHOOT_2: if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase) { - if (!ShotLara(item, &AI, MPGunBite, torsoY, 32)) + if (!ShotLara(item, &AI, MPGunBite, extraTorsoRot.y, 32)) item->Animation.TargetState = MPGUN_STATE_WAIT; } - else if (item->HitStatus && !(GetRandomControl() & 0x3) && cover) + else if (item->HitStatus && TestProbability(0.25f) && cover) { item->Animation.RequiredState = MPGUN_STATE_CROUCH; item->Animation.TargetState = MPGUN_STATE_WAIT; @@ -358,17 +358,17 @@ namespace TEN::Entities::TR3 case MPGUN_STATE_SHOOT_3B: if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase || item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 11) { - if (!ShotLara(item, &AI, MPGunBite, torsoY, 32)) + if (!ShotLara(item, &AI, MPGunBite, extraTorsoRot.y, 32)) item->Animation.TargetState = MPGUN_STATE_WAIT; } - else if (item->HitStatus && !(GetRandomControl() & 0x3) && cover) + else if (item->HitStatus && TestProbability(0.25f) && cover) { item->Animation.RequiredState = MPGUN_STATE_CROUCH; item->Animation.TargetState = MPGUN_STATE_WAIT; @@ -379,17 +379,19 @@ namespace TEN::Entities::TR3 case MPGUN_STATE_AIM_4: if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } - if ((item->Animation.AnimNumber == Objects[ID_MP_WITH_GUN].animIndex + 18 && item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 17) || - (item->Animation.AnimNumber == Objects[ID_MP_WITH_GUN].animIndex + 19 && item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 6)) + if ((item->Animation.AnimNumber == Objects[ID_MP_WITH_GUN].animIndex + 18 && + item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 17) || + (item->Animation.AnimNumber == Objects[ID_MP_WITH_GUN].animIndex + 19 && + item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 6)) { - if (!ShotLara(item, &AI, MPGunBite, torsoY, 32)) + if (!ShotLara(item, &AI, MPGunBite, extraTorsoRot.y, 32)) item->Animation.RequiredState = MPGUN_STATE_WALK; } - else if (item->HitStatus && !(GetRandomControl() & 0x3) && cover) + else if (item->HitStatus && TestProbability(0.25f) && cover) { item->Animation.RequiredState = MPGUN_STATE_CROUCH; item->Animation.TargetState = MPGUN_STATE_WAIT; @@ -404,8 +406,8 @@ namespace TEN::Entities::TR3 case MPGUN_STATE_SHOOT_4B: if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (item->Animation.RequiredState == MPGUN_STATE_WALK) @@ -413,7 +415,7 @@ namespace TEN::Entities::TR3 if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase + 16) { - if (!ShotLara(item, &AI, MPGunBite, torsoY, 32)) + if (!ShotLara(item, &AI, MPGunBite, extraTorsoRot.y, 32)) item->Animation.TargetState = MPGUN_STATE_WALK; } @@ -430,7 +432,7 @@ namespace TEN::Entities::TR3 if (Targetable(item, &AI)) item->Animation.TargetState = MPGUN_STATE_CROUCH_AIM; - else if (item->HitStatus || !cover || (AI.ahead && !(GetRandomControl() & 0x1F))) + else if (item->HitStatus || !cover || (AI.ahead && TestProbability(1.0f / 30))) item->Animation.TargetState = MPGUN_STATE_STAND; else item->Animation.TargetState = MPGUN_STATE_CROUCH_WALK; @@ -441,7 +443,7 @@ namespace TEN::Entities::TR3 creature->MaxTurn = ANGLE(1.0f); if (AI.ahead) - torsoY = AI.angle; + extraTorsoRot.y = AI.angle; if (Targetable(item, &AI)) item->Animation.TargetState = MPGUN_STATE_CROUCH_SHOT; @@ -452,11 +454,11 @@ namespace TEN::Entities::TR3 case MPGUN_STATE_CROUCH_SHOT: if (AI.ahead) - torsoY = AI.angle; + extraTorsoRot.y = AI.angle; if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase) { - if (!ShotLara(item, &AI, MPGunBite, torsoY, 32) || !(GetRandomControl() & 0x7)) + if (!ShotLara(item, &AI, MPGunBite, extraTorsoRot.y, 32) || TestProbability(0.125f)) item->Animation.TargetState = MPGUN_STATE_CROUCHED; } @@ -468,7 +470,7 @@ namespace TEN::Entities::TR3 if (AI.ahead) head = AI.angle; - if (Targetable(item, &AI) || item->HitStatus || !cover || (AI.ahead && !(GetRandomControl() & 0x1F))) + if (Targetable(item, &AI) || item->HitStatus || !cover || (AI.ahead && TestProbability(1.0f / 30))) item->Animation.TargetState = MPGUN_STATE_CROUCHED; break; @@ -476,8 +478,8 @@ namespace TEN::Entities::TR3 } CreatureTilt(item, tilt); - CreatureJoint(item, 0, torsoY); - CreatureJoint(item, 1, torsoX); + CreatureJoint(item, 0, extraTorsoRot.y); + CreatureJoint(item, 1, extraTorsoRot.x); CreatureJoint(item, 2, head); CreatureAnimation(itemNumber, angle, tilt); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_mp_gun.h b/TombEngine/Objects/TR3/Entity/tr3_mp_gun.h index 9c768f11b..47a21c4e1 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_mp_gun.h +++ b/TombEngine/Objects/TR3/Entity/tr3_mp_gun.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void MPGunControl(short itemNumber); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_mp_stick.cpp b/TombEngine/Objects/TR3/Entity/tr3_mp_stick.cpp index 94676c6f2..7e655d2d3 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_mp_stick.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_mp_stick.cpp @@ -13,18 +13,18 @@ #include "Specific/level.h" #include "Specific/setup.h" +using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { const auto MPStickBite1 = BiteInfo(Vector3(247.0f, 10.0f, 11.0f), 13); const auto MPStickBite2 = BiteInfo(Vector3(0.0f, 0.0f, 100.0f), 6); const vector MPStickPunchAttackJoints = { 10, 13 }; - const vector MPStickKickAttackJoints = { 5, 6 }; + const vector MPStickKickAttackJoints = { 5, 6 }; enum MPStickState { - MPSTICK_STATE_NONE, MPSTICK_STATE_STOP, MPSTICK_STATE_WALK, MPSTICK_STATE_PUNCH2, @@ -54,10 +54,7 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[ID_MP_WITH_STICK].animIndex + 6; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = item->Animation.TargetState = MPSTICK_STATE_STOP; + SetAnimation(item, 6); } void MPStickControl(short itemNumber) @@ -68,11 +65,10 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; short tilt = 0; - short torsoX = 0; - short torsoY = 0; + short head = 0; + auto extraTorsoRot = EulerAngles::Zero; if (item->BoxNumber != NO_BOX && (g_Level.Boxes[item->BoxNumber].flags & BLOCKED)) { @@ -85,9 +81,7 @@ namespace TEN::Entities::TR3 { if (item->Animation.ActiveState != MPSTICK_STATE_DEATH) { - item->Animation.AnimNumber = Objects[ID_MP_WITH_STICK].animIndex + 26; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = MPSTICK_STATE_DEATH; + SetAnimation(item, 26); creature->LOT.Step = 256; } } @@ -103,7 +97,7 @@ namespace TEN::Entities::TR3 int dz = LaraItem->Pose.Position.z - item->Pose.Position.z; laraAI.distance = pow(dx, 2) + pow(dx, 2); - int bestDistance = 0x7fffffff; + int bestDistance = INT_MAX; for (int slot = 0; slot < ActiveCreatures.size(); slot++) { auto* currentCreature = ActiveCreatures[slot]; @@ -184,7 +178,7 @@ namespace TEN::Entities::TR3 if (item->AIBits & GUARD) { head = AIGuard(creature); - if (!(GetRandomControl() & 0xFF)) + if (TestProbability(1.0f / 256)) { if (item->Animation.ActiveState == MPSTICK_STATE_STOP) item->Animation.TargetState = MPSTICK_STATE_WAIT; @@ -194,7 +188,6 @@ namespace TEN::Entities::TR3 break; } - else if (item->AIBits & PATROL1) item->Animation.TargetState = MPSTICK_STATE_WALK; @@ -240,7 +233,7 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = MPSTICK_STATE_RUN; else if (creature->Mood == MoodType::Bored) { - if (GetRandomControl() < 0x100) + if (TestProbability(1.0f / 128)) { item->Animation.RequiredState = MPSTICK_STATE_WAIT; item->Animation.TargetState = MPSTICK_STATE_STOP; @@ -288,8 +281,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (AI.bite && AI.distance < pow(SECTOR(0.5f), 2)) @@ -305,8 +298,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (AI.ahead && AI.distance < pow(SECTOR(1), 2)) @@ -322,8 +315,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (AI.bite && AI.distance < pow(SECTOR(1.25f), 2)) @@ -338,32 +331,30 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } - if (enemy->IsLara()) + if (creature->Enemy->IsLara()) { if (!creature->Flags && item->TestBits(JointBitType::Touch, MPStickPunchAttackJoints)) { - CreatureEffect(item, MPStickBite1, DoBloodSplat); DoDamage(enemy, 80); + CreatureEffect(item, MPStickBite1, DoBloodSplat); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); creature->Flags = 1; } } else { - if (!creature->Flags && enemy) + if (!creature->Flags && enemy != nullptr) { - if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < SECTOR(0.25f) && - abs(enemy->Pose.Position.y - item->Pose.Position.y) <= SECTOR(0.25f) && - abs(enemy->Pose.Position.z - item->Pose.Position.z) < SECTOR(0.25f)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.25f)) { - creature->Flags = 1; - CreatureEffect(item, MPStickBite1, DoBloodSplat); DoDamage(enemy, 5); + CreatureEffect(item, MPStickBite1, DoBloodSplat); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); + creature->Flags = 1; } } } @@ -375,32 +366,30 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } - if (enemy->IsLara()) + if (creature->Enemy->IsLara()) { if (!creature->Flags && item->TestBits(JointBitType::Touch, MPStickPunchAttackJoints)) { + DoDamage(creature->Enemy, 80); CreatureEffect(item, MPStickBite1, DoBloodSplat); - DoDamage(enemy, 80); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); creature->Flags = 1; } } else { - if (!creature->Flags && enemy) + if (!creature->Flags && creature->Enemy != nullptr) { - if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < SECTOR(0.25f) && - abs(enemy->Pose.Position.y - item->Pose.Position.y) <= SECTOR(0.25f) && - abs(enemy->Pose.Position.z - item->Pose.Position.z) < SECTOR(0.25f)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.25f)) { - creature->Flags = 1; + DoDamage(creature->Enemy, 5); CreatureEffect(item, MPStickBite1, DoBloodSplat); - DoDamage(enemy, 5); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); + creature->Flags = 1; } } } @@ -415,32 +404,30 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } - if (enemy->IsLara()) + if (creature->Enemy->IsLara()) { if (creature->Flags != 2 && item->TestBits(JointBitType::Touch, MPStickPunchAttackJoints)) { + DoDamage(creature->Enemy, 100); CreatureEffect(item, MPStickBite1, DoBloodSplat); - DoDamage(enemy, 100); - creature->Flags = 2; SoundEffect(70, &item->Pose); + creature->Flags = 2; } } else { - if (creature->Flags != 2 && enemy) + if (creature->Flags != 2 && creature->Enemy) { - if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < SECTOR(0.25f) && - abs(enemy->Pose.Position.y - item->Pose.Position.y) <= SECTOR(0.25f) && - abs(enemy->Pose.Position.z - item->Pose.Position.z) < SECTOR(0.25f)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.25f)) { - creature->Flags = 2; + DoDamage(creature->Enemy, 6); CreatureEffect(item, MPStickBite1, DoBloodSplat); - DoDamage(enemy, 6); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); + creature->Flags = 2; } } } @@ -451,32 +438,30 @@ namespace TEN::Entities::TR3 creature->MaxTurn = ANGLE(6.0f); if (AI.ahead) - torsoY = AI.angle; + extraTorsoRot.y = AI.angle; - if (enemy->IsLara()) + if (creature->Enemy->IsLara()) { if (creature->Flags != 1 && item->TestBits(JointBitType::Touch, MPStickKickAttackJoints) && item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 8) { + DoDamage(creature->Enemy, 150); CreatureEffect(item, MPStickBite2, DoBloodSplat); - DoDamage(enemy, 150); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); creature->Flags = 1; } } else { - if (!creature->Flags != 1 && enemy && + if (!creature->Flags != 1 && creature->Enemy && item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 8) { - if (abs(enemy->Pose.Position.x - item->Pose.Position.x) < SECTOR(0.25f) && - abs(enemy->Pose.Position.y - item->Pose.Position.y) <= SECTOR(0.25f) && - abs(enemy->Pose.Position.z - item->Pose.Position.z) < SECTOR(0.25f)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.25f)) { - creature->Flags = 1; + DoDamage(creature->Enemy, 9); CreatureEffect(item, MPStickBite2, DoBloodSplat); - DoDamage(enemy, 9); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); + creature->Flags = 1; } } } @@ -486,8 +471,8 @@ namespace TEN::Entities::TR3 } CreatureTilt(item, tilt); - CreatureJoint(item, 0, torsoY); - CreatureJoint(item, 1, torsoX); + CreatureJoint(item, 0, extraTorsoRot.y); + CreatureJoint(item, 1, extraTorsoRot.x); CreatureJoint(item, 2, head); if (item->Animation.ActiveState < MPSTICK_STATE_DEATH) diff --git a/TombEngine/Objects/TR3/Entity/tr3_mp_stick.h b/TombEngine/Objects/TR3/Entity/tr3_mp_stick.h index 75d1addcb..8848a7f72 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_mp_stick.h +++ b/TombEngine/Objects/TR3/Entity/tr3_mp_stick.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void InitialiseMPStick(short itemNumber); void MPStickControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_raptor.cpp b/TombEngine/Objects/TR3/Entity/tr3_raptor.cpp index f1ae5c50b..00dcfcba5 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_raptor.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_raptor.cpp @@ -16,10 +16,17 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { constexpr auto RAPTOR_ATTACK_DAMAGE = 100; + constexpr auto RAPTOR_BITE_ATTACK_RANGE = SQUARE(585); + constexpr auto RAPTOR_JUMP_ATTACK_RANGE = SQUARE(SECTOR(1.5f)); + constexpr auto RAPTOR_RUN_ATTACK_RANGE = SQUARE(SECTOR(1.5f)); + + constexpr auto RAPTOR_ROAR_CHANCE = 1.0f / 256; + constexpr auto RAPTOR_SWITCH_TARGET_CHANCE = 1.0f / 128; + #define RAPTOR_WALK_TURN_RATE_MAX ANGLE(2.0f) #define RAPTOR_RUN_TURN_RATE_MAX ANGLE(2.0f) #define RAPTOR_ATTACK_TURN_RATE_MAX ANGLE(2.0f) @@ -74,10 +81,10 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; - short neck = 0; short angle = 0; short tilt = 0; + short head = 0; + short neck = 0; if (item->HitPoints <= 0) { @@ -86,14 +93,13 @@ namespace TEN::Entities::TR3 } else { - if (creature->Enemy == nullptr || !(GetRandomControl() & 0x7F)) // TODO: Probability is 0.004f or 0.996f? + if (creature->Enemy == nullptr || TestProbability(RAPTOR_SWITCH_TARGET_CHANCE)) { ItemInfo* nearestItem = nullptr; int minDistance = INT_MAX; - for (int i = 0; i < ActiveCreatures.size(); i++) + for (auto* currentCreature : ActiveCreatures) { - auto* currentCreature = ActiveCreatures[i]; if (currentCreature->ItemNumber == NO_ITEM || currentCreature->ItemNumber == itemNumber) { currentCreature++; @@ -106,7 +112,7 @@ namespace TEN::Entities::TR3 int y = (targetItem->Pose.Position.y - item->Pose.Position.y) / 64; int z = (targetItem->Pose.Position.z - item->Pose.Position.z) / 64; - int distance = pow(x, 2) + pow(y, 2) + pow(z, 2); + int distance = SQUARE(x) + SQUARE(y) + SQUARE(z); if (distance < minDistance && item->HitPoints > 0) { nearestItem = targetItem; @@ -118,7 +124,7 @@ namespace TEN::Entities::TR3 if (nearestItem != nullptr && (nearestItem->ObjectNumber != ID_RAPTOR || - (TestProbability(0.03f) && minDistance < pow(SECTOR(2), 2)))) + (TestProbability(1.0f / 30) && minDistance < SQUARE(SECTOR(2))))) { creature->Enemy = nearestItem; } @@ -127,7 +133,7 @@ namespace TEN::Entities::TR3 int y = (LaraItem->Pose.Position.y - item->Pose.Position.y) / 64; int z = (LaraItem->Pose.Position.z - item->Pose.Position.z) / 64; - int distance = pow(x, 2) + pow(y, 2) + pow(z, 2); + int distance = SQUARE(x) + SQUARE(y) + SQUARE(z); if (distance <= minDistance) creature->Enemy = LaraItem; } @@ -164,11 +170,11 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = RAPTOR_STATE_ROAR; } else if (item->TestBits(JointBitType::Touch, RaptorAttackJoints) || - (AI.distance < pow(585, 2) && AI.bite)) + (AI.distance < RAPTOR_BITE_ATTACK_RANGE && AI.bite)) { item->Animation.TargetState = RAPTOR_STATE_BITE_ATTACK; } - else if (AI.bite && AI.distance < pow(SECTOR(1.5f), 2)) + else if (AI.bite && AI.distance < RAPTOR_JUMP_ATTACK_RANGE) item->Animation.TargetState = RAPTOR_STATE_JUMP_ATTACK; else if (creature->Mood == MoodType::Escape && Lara.TargetEntity != item && AI.ahead && !item->HitStatus) @@ -188,7 +194,7 @@ namespace TEN::Entities::TR3 if (creature->Mood != MoodType::Bored) item->Animation.TargetState = RAPTOR_STATE_IDLE; - else if (AI.ahead && TestProbability(0.004f)) + else if (AI.ahead && TestProbability(RAPTOR_ROAR_CHANCE)) { item->Animation.TargetState = RAPTOR_STATE_IDLE; item->Animation.RequiredState = RAPTOR_STATE_ROAR; @@ -210,7 +216,7 @@ namespace TEN::Entities::TR3 item->Animation.RequiredState = RAPTOR_STATE_ROAR; creature->Flags &= ~2; } - else if (AI.bite && AI.distance < pow(SECTOR(1.5f), 2)) + else if (AI.bite && AI.distance < RAPTOR_RUN_ATTACK_RANGE) { if (item->Animation.TargetState == RAPTOR_STATE_RUN_FORWARD) { @@ -221,7 +227,7 @@ namespace TEN::Entities::TR3 } } else if (AI.ahead && creature->Mood != MoodType::Escape && - TestProbability(0.004f)) + TestProbability(RAPTOR_ROAR_CHANCE)) { item->Animation.TargetState = RAPTOR_STATE_IDLE; item->Animation.RequiredState = RAPTOR_STATE_ROAR; @@ -257,10 +263,7 @@ namespace TEN::Entities::TR3 { if (!(creature->Flags & 1) && creature->Enemy != nullptr) { - auto direction = creature->Enemy->Pose.Position - item->Pose.Position; - if (abs(direction.x) < SECTOR(0.5f) && - abs(direction.y) < SECTOR(0.5f) && - abs(direction.z) < SECTOR(0.5f)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.5f)) { if (creature->Enemy->HitPoints <= 0) creature->Flags |= 2; @@ -297,10 +300,7 @@ namespace TEN::Entities::TR3 { if (!(creature->Flags & 1) && creature->Enemy != nullptr) { - auto direction = creature->Enemy->Pose.Position - item->Pose.Position; - if (abs(direction.x) < SECTOR(0.5f) && - abs(direction.y) < SECTOR(0.5f) && - abs(direction.z) < SECTOR(0.5f)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.5f)) { if (creature->Enemy->HitPoints <= 0) creature->Flags |= 2; @@ -336,10 +336,7 @@ namespace TEN::Entities::TR3 { if (!(creature->Flags & 1) && creature->Enemy != nullptr) { - auto direction = creature->Enemy->Pose.Position - item->Pose.Position; - if (abs(direction.x) < SECTOR(0.5f) && - abs(direction.y) < SECTOR(0.5f) && - abs(direction.z) < SECTOR(0.5f)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.5f)) { if (creature->Enemy->HitPoints <= 0) creature->Flags |= 2; diff --git a/TombEngine/Objects/TR3/Entity/tr3_raptor.h b/TombEngine/Objects/TR3/Entity/tr3_raptor.h index a9424ca89..640e202ec 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_raptor.h +++ b/TombEngine/Objects/TR3/Entity/tr3_raptor.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void RaptorControl(short itemNumber); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.cpp b/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.cpp index 824cdef6b..6d6ecb267 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.cpp @@ -13,7 +13,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { constexpr auto SCUBA_DIVER_ATTACK_DAMAGE = 50; @@ -23,7 +23,6 @@ namespace TEN::Entities::TR3 enum ScubaDiverState { - SDIVER_STATE_NONE = 0, SDIVER_STATE_SWIM = 1, SDIVER_STATE_TREAD_WATER_IDLE = 2, SDIVER_STATE_SWIM_SHOOT = 3, @@ -60,23 +59,23 @@ namespace TEN::Entities::TR3 static void ShootHarpoon(ItemInfo* item, Vector3i pos, short velocity, short yRot, short roomNumber) { short harpoonItemNumber = CreateItem(); - if (harpoonItemNumber != NO_ITEM) - { - auto* harpoonItem = &g_Level.Items[harpoonItemNumber]; + if (harpoonItemNumber == NO_ITEM) + return; - harpoonItem->ObjectNumber = ID_SCUBA_HARPOON; - harpoonItem->RoomNumber = item->RoomNumber; - harpoonItem->Pose.Position = pos; + auto* harpoonItem = &g_Level.Items[harpoonItemNumber]; - InitialiseItem(harpoonItemNumber); + harpoonItem->ObjectNumber = ID_SCUBA_HARPOON; + harpoonItem->RoomNumber = item->RoomNumber; + harpoonItem->Pose.Position = pos; - harpoonItem->Animation.Velocity.z = 150; - harpoonItem->Pose.Orientation.x = 0; - harpoonItem->Pose.Orientation.y = yRot; + InitialiseItem(harpoonItemNumber); - AddActiveItem(harpoonItemNumber); - harpoonItem->Status = ITEM_ACTIVE; - } + harpoonItem->Animation.Velocity.z = 150.0f; + harpoonItem->Pose.Orientation.x = 0; + harpoonItem->Pose.Orientation.y = yRot; + + AddActiveItem(harpoonItemNumber); + harpoonItem->Status = ITEM_ACTIVE; } void ScubaHarpoonControl(short itemNumber) @@ -91,14 +90,7 @@ namespace TEN::Entities::TR3 } else { - int ox = item->Pose.Position.x; - int oz = item->Pose.Position.z; - - int velocity = item->Animation.Velocity.z * phd_cos(item->Pose.Orientation.x); - - item->Pose.Position.z += velocity * phd_cos(item->Pose.Orientation.y); - item->Pose.Position.x += velocity * phd_sin(item->Pose.Orientation.y); - item->Pose.Position.y += -item->Animation.Velocity.z * phd_sin(item->Pose.Orientation.x); + TranslateItem(item, item->Pose.Orientation, item->Animation.Velocity.z); auto probe = GetCollision(item); @@ -123,7 +115,8 @@ namespace TEN::Entities::TR3 short head = 0; short neck = 0; - int waterHeight; + int waterHeight = 0; + if (item->HitPoints <= 0) { if (item->Animation.ActiveState != SDIVER_STATE_DEATH) @@ -140,22 +133,23 @@ namespace TEN::Entities::TR3 GetCreatureMood(item, &AI, false); CreatureMood(item, &AI, false); - GameVector origin; - GameVector target; bool shoot = false; - if (Lara.Control.WaterStatus == WaterStatus::Dry) { - origin.x = item->Pose.Position.x; - origin.y = item->Pose.Position.y - CLICK(1); - origin.z = item->Pose.Position.z; - origin.roomNumber = item->RoomNumber; - - target.x = LaraItem->Pose.Position.x; - target.y = LaraItem->Pose.Position.y - (LARA_HEIGHT - 150); - target.z = LaraItem->Pose.Position.z; + auto origin = GameVector( + item->Pose.Position.x, + item->Pose.Position.y - CLICK(1), + item->Pose.Position.z, + item->RoomNumber + ); + auto target = GameVector( + LaraItem->Pose.Position.x, + LaraItem->Pose.Position.y - (LARA_HEIGHT - 150), + LaraItem->Pose.Position.z + ); shoot = LOS(&origin, &target); + if (shoot) creature->Target = LaraItem->Pose.Position; @@ -164,19 +158,11 @@ namespace TEN::Entities::TR3 } else if (AI.angle > -ANGLE(45.0f) && AI.angle < ANGLE(45.0f)) { - origin.x = item->Pose.Position.x; - origin.y = item->Pose.Position.y; - origin.z = item->Pose.Position.z; - origin.roomNumber = item->RoomNumber; - - target.x = LaraItem->Pose.Position.x; - target.y = LaraItem->Pose.Position.y; - target.z = LaraItem->Pose.Position.z; - + auto origin = GameVector(item->Pose.Position, item->RoomNumber); + auto target = GameVector(LaraItem->Pose.Position); + shoot = LOS(&origin, &target); } - else - shoot = false; angle = CreatureTurn(item, creature->MaxTurn); waterHeight = GetWaterSurface(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber) + SECTOR(0.5f); @@ -202,7 +188,7 @@ namespace TEN::Entities::TR3 break; case SDIVER_STATE_SWIM_AIM: - creature->Flags = NULL; + creature->Flags = 0; if (shoot) neck = -AI.angle; @@ -270,7 +256,6 @@ namespace TEN::Entities::TR3 } break; - } } diff --git a/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.h b/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.h index d5bc5b60d..23f9b6167 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.h +++ b/TombEngine/Objects/TR3/Entity/tr3_scuba_diver.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void ScubaHarpoonControl(short itemNumber); void ScubaControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_shiva.cpp b/TombEngine/Objects/TR3/Entity/tr3_shiva.cpp index b16a743e8..144c5d086 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_shiva.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_shiva.cpp @@ -19,7 +19,7 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { constexpr auto SHIVA_GRAB_ATTACK_DAMAGE = 150; constexpr auto SHIVA_DOWNWARD_ATTACK_DAMAGE = 180; @@ -29,10 +29,10 @@ namespace TEN::Entities::TR3 #define SHIVA_WALK_TURN_RATE_MAX ANGLE(4.0f) #define SHIVA_ATTACK_TURN_RATE_MAX ANGLE(4.0f) - const vector ShivaAttackLeftJoints = { 10, 13 }; - const vector ShivaAttackRightJoints = { 22, 25 }; const auto ShivaBiteLeft = BiteInfo(Vector3(0.0f, 0.0f, 920.0f), 13); const auto ShivaBiteRight = BiteInfo(Vector3(0.0f, 0.0f, 920.0f), 22); + const vector ShivaAttackLeftJoints = { 10, 13 }; + const vector ShivaAttackRightJoints = { 22, 25 }; enum ShivaState { @@ -81,7 +81,7 @@ namespace TEN::Entities::TR3 }; - static void TriggerShivaSmoke(long x, long y, long z, long uw) + void TriggerShivaSmoke(long x, long y, long z, long uw) { long dx = LaraItem->Pose.Position.x - x; long dz = LaraItem->Pose.Position.z - z; @@ -169,7 +169,7 @@ namespace TEN::Entities::TR3 sptr->dSize = size; } - static void ShivaDamage(ItemInfo* item, CreatureInfo* creature, int damage) + void ShivaDamage(ItemInfo* item, CreatureInfo* creature, int damage) { if (!(creature->Flags) && item->TestBits(JointBitType::Touch, ShivaAttackRightJoints)) { @@ -208,14 +208,15 @@ namespace TEN::Entities::TR3 return; auto* item = &g_Level.Items[itemNumber]; - auto* shiva = GetCreatureInfo(item); + auto* creature = GetCreatureInfo(item); - bool laraAlive = LaraItem->HitPoints > 0; + auto pos = Vector3i(0, 0, CLICK(1)); + bool isLaraAlive = LaraItem->HitPoints > 0; - EulerAngles extraHeadRot; - EulerAngles extraTorsoRot; short angle = 0; short tilt = 0; + EulerAngles extraHeadRot = EulerAngles::Zero; + EulerAngles extraTorsoRot = EulerAngles::Zero; if (item->HitPoints <= 0) { @@ -234,13 +235,13 @@ namespace TEN::Entities::TR3 GetCreatureMood(item, &AI, true); CreatureMood(item, &AI, true); - if (shiva->Mood == MoodType::Escape) + if (creature->Mood == MoodType::Escape) { - shiva->Target.x = LaraItem->Pose.Position.x; - shiva->Target.z = LaraItem->Pose.Position.z; + creature->Target.x = LaraItem->Pose.Position.x; + creature->Target.z = LaraItem->Pose.Position.z; } - angle = CreatureTurn(item, shiva->MaxTurn); + angle = CreatureTurn(item, creature->MaxTurn); if (item->Animation.ActiveState != SHIVA_STATE_INACTIVE) item->MeshBits = ALL_JOINT_BITS; @@ -251,15 +252,15 @@ namespace TEN::Entities::TR3 switch (item->Animation.ActiveState) { case SHIVA_STATE_INACTIVE: - shiva->MaxTurn = 0; + creature->MaxTurn = 0; - if (!shiva->Flags) + if (!creature->Flags) { if (!item->MeshBits) effectMesh = 0; item->MeshBits = (item->MeshBits * 2) + 1; - shiva->Flags = 1; + creature->Flags = 1; pos = GetJointPosition(item, effectMesh++, pos); TriggerExplosionSparks(pos.x, pos.y, pos.z, 2, 0, 0, item->RoomNumber); @@ -267,45 +268,45 @@ namespace TEN::Entities::TR3 } else - shiva->Flags--; + creature->Flags--; if (item->MeshBits == 0x7FFFFFFF) { item->Animation.TargetState = SHIVA_STATE_IDLE; - shiva->Flags = -45; + creature->Flags = -45; effectMesh = 0; } break; case SHIVA_STATE_IDLE: - shiva->MaxTurn = 0; + creature->MaxTurn = 0; if (AI.ahead) extraHeadRot.y = AI.angle; - if (shiva->Flags < 0) + if (creature->Flags < 0) { - shiva->Flags++; + creature->Flags++; TriggerShivaSmoke(item->Pose.Position.x + (GetRandomControl() & 0x5FF) - 0x300, pos.y - (GetRandomControl() & 0x5FF), item->Pose.Position.z + (GetRandomControl() & 0x5FF) - 0x300, 1); break; } - if (shiva->Flags == 1) - shiva->Flags = 0; + if (creature->Flags == 1) + creature->Flags = 0; - if (shiva->Mood == MoodType::Escape) + if (creature->Mood == MoodType::Escape) { int x = item->Pose.Position.x + SECTOR(1) * phd_sin(item->Pose.Orientation.y + ANGLE(180.0f)); int z = item->Pose.Position.z + SECTOR(1) * phd_cos(item->Pose.Orientation.y + ANGLE(180.0f)); auto box = GetCollision(x, item->Pose.Position.y, z, item->RoomNumber).BottomBlock->Box; - if (box != NO_BOX && !(g_Level.Boxes[box].flags & BLOCKABLE) && !shiva->Flags) + if (box != NO_BOX && !(g_Level.Boxes[box].flags & BLOCKABLE) && !creature->Flags) item->Animation.TargetState = SHIVA_STATE_WALK_BACK; else item->Animation.TargetState = SHIVA_STATE_GUARD_IDLE; } - else if (shiva->Mood == MoodType::Bored) + else if (creature->Mood == MoodType::Bored) { if (TestProbability(0.0325f)) item->Animation.TargetState = SHIVA_STATE_WALK_FORWARD; @@ -313,17 +314,17 @@ namespace TEN::Entities::TR3 else if (AI.bite && AI.distance < pow(SECTOR(1.25f), 2)) { item->Animation.TargetState = SHIVA_STATE_GRAB_ATTACK; - shiva->Flags = 0; + creature->Flags = 0; } else if (AI.bite && AI.distance < pow(SECTOR(4) / 3, 2)) { item->Animation.TargetState = SHIVA_STATE_DOWNWARD_ATTACK; - shiva->Flags = 0; + creature->Flags = 0; } else if (item->HitStatus && AI.ahead) { item->Animation.TargetState = SHIVA_STATE_GUARD_IDLE; - shiva->Flags = 4; + creature->Flags = 4; } else item->Animation.TargetState = SHIVA_STATE_WALK_FORWARD; @@ -331,103 +332,103 @@ namespace TEN::Entities::TR3 break; case SHIVA_STATE_GUARD_IDLE: - shiva->MaxTurn = 0; + creature->MaxTurn = 0; if (AI.ahead) extraHeadRot.y = AI.angle; - if (item->HitStatus || shiva->Mood == MoodType::Escape) - shiva->Flags = 4; + if (item->HitStatus || creature->Mood == MoodType::Escape) + creature->Flags = 4; if (AI.bite && AI.distance < pow(SECTOR(4) / 3, 2) || (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase && - !shiva->Flags) || + !creature->Flags) || !AI.ahead) { item->Animation.TargetState = SHIVA_STATE_IDLE; - shiva->Flags = 0; + creature->Flags = 0; } - else if (shiva->Flags) + else if (creature->Flags) item->Animation.TargetState = SHIVA_STATE_GUARD_IDLE; if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase && - shiva->Flags > 1) + creature->Flags > 1) { - shiva->Flags -= 2; + creature->Flags -= 2; } break; case SHIVA_STATE_WALK_FORWARD: - shiva->MaxTurn = SHIVA_WALK_TURN_RATE_MAX; + creature->MaxTurn = SHIVA_WALK_TURN_RATE_MAX; if (AI.ahead) extraHeadRot.y = AI.angle; - if (shiva->Mood == MoodType::Escape) + if (creature->Mood == MoodType::Escape) item->Animation.TargetState = SHIVA_STATE_IDLE; - else if (shiva->Mood == MoodType::Bored) + else if (creature->Mood == MoodType::Bored) item->Animation.TargetState = SHIVA_STATE_IDLE; else if (AI.bite && AI.distance < pow(SECTOR(4) / 3, 2)) { item->Animation.TargetState = SHIVA_STATE_IDLE; - shiva->Flags = 0; + creature->Flags = 0; } else if (item->HitStatus) { item->Animation.TargetState = SHIVA_STATE_WALK_FORWARD_GUARDING; - shiva->Flags = 4; + creature->Flags = 4; } break; case SHIVA_STATE_WALK_FORWARD_GUARDING: - shiva->MaxTurn = SHIVA_WALK_TURN_RATE_MAX; + creature->MaxTurn = SHIVA_WALK_TURN_RATE_MAX; if (AI.ahead) extraHeadRot.y = AI.angle; if (item->HitStatus) - shiva->Flags = 4; + creature->Flags = 4; if (AI.bite && AI.distance < pow(SECTOR(1.25f), 2) || (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase && - !shiva->Flags)) + !creature->Flags)) { item->Animation.TargetState = SHIVA_STATE_WALK_FORWARD; - shiva->Flags = 0; + creature->Flags = 0; } - else if (shiva->Flags) + else if (creature->Flags) item->Animation.TargetState = SHIVA_STATE_WALK_FORWARD_GUARDING; if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase) - shiva->Flags = 0; + creature->Flags = 0; break; case SHIVA_STATE_WALK_BACK: - shiva->MaxTurn = SHIVA_WALK_TURN_RATE_MAX; + creature->MaxTurn = SHIVA_WALK_TURN_RATE_MAX; if (AI.ahead) extraHeadRot.y = AI.angle; if (AI.ahead && AI.distance < pow(SECTOR(4) / 3, 2) || (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase && - !shiva->Flags)) + !creature->Flags)) { item->Animation.TargetState = SHIVA_STATE_IDLE; } else if (item->HitStatus) { item->Animation.TargetState = SHIVA_STATE_IDLE; - shiva->Flags = 4; + creature->Flags = 4; } break; case SHIVA_STATE_GRAB_ATTACK: - shiva->MaxTurn = SHIVA_ATTACK_TURN_RATE_MAX; + creature->MaxTurn = SHIVA_ATTACK_TURN_RATE_MAX; if (AI.ahead) { @@ -435,22 +436,22 @@ namespace TEN::Entities::TR3 extraTorsoRot = EulerAngles(AI.xAngle, AI.angle, 0); } - ShivaDamage(item, shiva, SHIVA_GRAB_ATTACK_DAMAGE); + ShivaDamage(item, creature, SHIVA_GRAB_ATTACK_DAMAGE); break; case SHIVA_STATE_DOWNWARD_ATTACK: - shiva->MaxTurn = SHIVA_ATTACK_TURN_RATE_MAX; + creature->MaxTurn = SHIVA_ATTACK_TURN_RATE_MAX; extraHeadRot.y = AI.angle; extraTorsoRot.y = AI.angle; if (AI.xAngle > 0) extraTorsoRot.x = AI.xAngle; - ShivaDamage(item, shiva, SHIVA_DOWNWARD_ATTACK_DAMAGE); + ShivaDamage(item, creature, SHIVA_DOWNWARD_ATTACK_DAMAGE); break; case SHIVA_STATE_KILL: - shiva->MaxTurn = 0; + creature->MaxTurn = 0; extraHeadRot = EulerAngles::Zero; extraTorsoRot = EulerAngles::Zero; @@ -466,23 +467,21 @@ namespace TEN::Entities::TR3 } } - // Dispatch kill animation - if (laraAlive && LaraItem->HitPoints <= 0) + // Dispatch kill animation. + if (isLaraAlive && LaraItem->HitPoints <= 0) { item->Animation.TargetState = SHIVA_STATE_KILL; if (LaraItem->RoomNumber != item->RoomNumber) ItemNewRoom(Lara.ItemNumber, item->RoomNumber); - LaraItem->Pose.Position = item->Pose.Position; - LaraItem->Pose.Orientation = EulerAngles(0, item->Pose.Orientation.y, 0); - LaraItem->Animation.IsAirborne = false; - LaraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_ANIM_SHIVA_DEATH; LaraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase; LaraItem->Animation.ActiveState = LS_DEATH; LaraItem->Animation.TargetState = LS_DEATH; - + LaraItem->Animation.IsAirborne = false; + LaraItem->Pose.Position = item->Pose.Position; + LaraItem->Pose.Orientation = EulerAngles(0, item->Pose.Orientation.y, 0); LaraItem->HitPoints = NOT_TARGETABLE; Lara.Air = -1; Lara.Control.HandStatus = HandStatus::Special; diff --git a/TombEngine/Objects/TR3/Entity/tr3_shiva.h b/TombEngine/Objects/TR3/Entity/tr3_shiva.h index 2aa7cac52..4f208c955 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_shiva.h +++ b/TombEngine/Objects/TR3/Entity/tr3_shiva.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void InitialiseShiva(short itemNumber); void ShivaControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_sophia.cpp b/TombEngine/Objects/TR3/Entity/tr3_sophia.cpp index 213c3fb05..7f85fb091 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_sophia.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_sophia.cpp @@ -9,7 +9,7 @@ #include "Sound/sound.h" #include "Specific/level.h" -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { static BOSS_STRUCT BossData; diff --git a/TombEngine/Objects/TR3/Entity/tr3_sophia.h b/TombEngine/Objects/TR3/Entity/tr3_sophia.h index 52778680c..5a96a3725 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_sophia.h +++ b/TombEngine/Objects/TR3/Entity/tr3_sophia.h @@ -1,7 +1,7 @@ #pragma once #include "Game/items.h" -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void ControlLaserBolts(short itemNumber); void ControlLondBossPlasmaBall(short fxNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_tiger.cpp b/TombEngine/Objects/TR3/Entity/tr3_tiger.cpp index e6d8a9fd1..6a4e5ba75 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_tiger.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_tiger.cpp @@ -15,23 +15,52 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { constexpr auto TIGER_ATTACK_DAMAGE = 90; + constexpr auto TIGER_BITE_ATTACK_RANGE = SQUARE(SECTOR(0.33f)); + constexpr auto TIGER_POUNCE_ATTACK_RANGE = SQUARE(SECTOR(1)); + constexpr auto TIGER_RUN_ATTACK_RANGE = SQUARE(SECTOR(1.5f)); + + constexpr auto TIGER_WALK_CHANCE = 0.035f; + constexpr auto TIGER_ROAR_CHANCE = 1.0f / 340; + const auto TigerBite = BiteInfo(Vector3(19.0f, -13.0f, 3.0f), 26); const vector TigerAttackJoints = { 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; - // TODO + #define TIGER_WALK_TURN_RATE_MAX ANGLE(3.0f) + #define TIGER_RUN_TURN_RATE_MAX ANGLE(6.0f) + #define TIGER_POUNCE_ATTACK_TURN_RATE_MAX ANGLE(3.0f) + enum TigerState { - + TIGER_STATE_DEATH = 0, + TIGER_STATE_IDLE = 1, + TIGER_STATE_WALK_FORWARD = 2, + TIGER_STATE_RUN_FORWARD = 3, + // No state 4. + TIGER_STATE_ROAR = 5, + TIGER_STATE_BITE_ATTACK = 6, + TIGER_STATE_RUN_SWIPE_ATTACK = 7, + TIGER_STATE_POUNCE_ATTACK = 8 }; - // TODO enum TigerAnim { - + TIGER_ANIM_IDLE_TO_RUN_FORWARD = 0, + TIGER_ANIM_BITE_ATTACK = 1, + TIGER_ANIM_RUN_SWIPE_ATTACK = 2, + TIGER_ANIM_POUNCE_ATTACK_START = 3, + TIGER_ANIM_ROAR = 4, + TIGER_ANIM_RUN_FORWARD = 5, + TIGER_ANIM_RUN_FORWARD_TO_IDLE = 6, + TIGER_ANIM_IDLE = 7, + TIGER_ANIM_WALK_FORWARD = 8, + TIGER_ANIM_IDLE_TO_WALK_FORWARD = 9, + TIGER_ANIM_WALK_FORWARD_TO_IDLE = 10, + TIGER_ANIM_DEATH = 11, + TIGER_ANIM_POUNCE_ATTACK_END = 12 }; void TigerControl(short itemNumber) @@ -40,20 +69,16 @@ namespace TEN::Entities::TR3 return; auto* item = &g_Level.Items[itemNumber]; - auto* info = GetCreatureInfo(item); + auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; short tilt = 0; + auto extraHeadRot = EulerAngles::Zero; if (item->HitPoints <= 0) { - if (item->Animation.ActiveState != 9) - { - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 11; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 9; - } + if (item->Animation.ActiveState != TIGER_STATE_DEATH) + SetAnimation(item, TIGER_ANIM_DEATH); } else { @@ -61,99 +86,105 @@ namespace TEN::Entities::TR3 CreatureAIInfo(item, &AI); if (AI.ahead) - head = AI.angle; + extraHeadRot.y = AI.angle; - GetCreatureMood(item, &AI, 1); + GetCreatureMood(item, &AI, true); - if (info->Alerted && AI.zoneNumber != AI.enemyZone) - info->Mood = MoodType::Escape; + if (creature->Alerted && AI.zoneNumber != AI.enemyZone) + creature->Mood = MoodType::Escape; - CreatureMood(item, &AI, 1); + CreatureMood(item, &AI, true); - angle = CreatureTurn(item, info->MaxTurn); + angle = CreatureTurn(item, creature->MaxTurn); switch (item->Animation.ActiveState) { - case 1: - info->MaxTurn = 0; - info->Flags = 0; + case TIGER_STATE_IDLE: + creature->MaxTurn = 0; + creature->Flags = 0; - if (info->Mood == MoodType::Escape) + if (creature->Mood == MoodType::Escape) { if (Lara.TargetEntity != item && AI.ahead) - item->Animation.TargetState = 1; + item->Animation.TargetState = TIGER_STATE_IDLE; else - item->Animation.TargetState = 3; + item->Animation.TargetState = TIGER_STATE_RUN_FORWARD; } - else if (info->Mood == MoodType::Bored) + else if (creature->Mood == MoodType::Bored) { - if (TestProbability(0.003f)) - item->Animation.TargetState = 5; - else if (TestProbability(0.035f)) - item->Animation.TargetState = 2; + if (TestProbability(TIGER_ROAR_CHANCE)) + item->Animation.TargetState = TIGER_STATE_ROAR; + else if (TestProbability(TIGER_WALK_CHANCE)) + item->Animation.TargetState = TIGER_STATE_WALK_FORWARD; } - else if (AI.bite && AI.distance < pow(340, 2)) - item->Animation.TargetState = 6; - else if (AI.bite && AI.distance < pow(SECTOR(1), 2)) + else if (AI.bite && AI.distance < TIGER_BITE_ATTACK_RANGE) + item->Animation.TargetState = TIGER_STATE_BITE_ATTACK; + else if (AI.bite && AI.distance < TIGER_POUNCE_ATTACK_RANGE) { - info->MaxTurn = ANGLE(3.0f); - item->Animation.TargetState = 8; + item->Animation.TargetState = TIGER_STATE_POUNCE_ATTACK; + creature->MaxTurn = TIGER_POUNCE_ATTACK_TURN_RATE_MAX; } else if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; - else if (info->Mood != MoodType::Attack && TestProbability(0.003f)) - item->Animation.TargetState = 5; + else if (creature->Mood != MoodType::Attack && TestProbability(TIGER_ROAR_CHANCE)) + item->Animation.TargetState = TIGER_STATE_ROAR; else - item->Animation.TargetState = 3; + item->Animation.TargetState = TIGER_STATE_RUN_FORWARD; break; - case 2: - info->MaxTurn = ANGLE(3.0f); + case TIGER_STATE_WALK_FORWARD: + creature->MaxTurn = TIGER_WALK_TURN_RATE_MAX; - if (info->Mood == MoodType::Escape || info->Mood == MoodType::Attack) - item->Animation.TargetState = 3; - else if (TestProbability(0.003f)) + if (creature->Mood == MoodType::Escape || + creature->Mood == MoodType::Attack) { - item->Animation.TargetState = 1; - item->Animation.RequiredState = 5; + item->Animation.TargetState = TIGER_STATE_RUN_FORWARD; + } + else if (TestProbability(TIGER_ROAR_CHANCE)) + { + item->Animation.TargetState = TIGER_STATE_IDLE; + item->Animation.RequiredState = TIGER_STATE_ROAR; } break; - case 3: - info->MaxTurn = ANGLE(6.0f); + case TIGER_STATE_RUN_FORWARD: + creature->MaxTurn = TIGER_RUN_TURN_RATE_MAX; - if (info->Mood == MoodType::Bored) - item->Animation.TargetState = 1; - else if (info->Flags && AI.ahead) - item->Animation.TargetState = 1; - else if (AI.bite && AI.distance < pow(SECTOR(1.5f), 2)) + if (creature->Mood == MoodType::Bored) + item->Animation.TargetState = TIGER_STATE_IDLE; + else if (creature->Flags && AI.ahead) + item->Animation.TargetState = TIGER_STATE_IDLE; + else if (AI.bite && AI.distance < TIGER_RUN_ATTACK_RANGE) { - if (LaraItem->Animation.Velocity.z == 0) - item->Animation.TargetState = 1; + if (LaraItem->Animation.Velocity.z == 0.0f) + item->Animation.TargetState = TIGER_STATE_IDLE; else - item->Animation.TargetState = 7; + item->Animation.TargetState = TIGER_STATE_RUN_SWIPE_ATTACK; } - else if (info->Mood != MoodType::Attack && TestProbability(0.003f)) + else if (creature->Mood != MoodType::Attack && TestProbability(TIGER_ROAR_CHANCE)) { - item->Animation.TargetState = 1; - item->Animation.RequiredState = 5; + item->Animation.TargetState = TIGER_STATE_IDLE; + item->Animation.RequiredState = TIGER_STATE_ROAR; + } + else if (creature->Mood == MoodType::Escape && + Lara.TargetEntity != item && AI.ahead) + { + item->Animation.TargetState = TIGER_STATE_IDLE; } - else if (info->Mood == MoodType::Escape && Lara.TargetEntity != item && AI.ahead) - item->Animation.TargetState = 1; - info->Flags = 0; + creature->Flags = 0; break; - case 6: - case 7: - case 8: - if (!info->Flags && item->TestBits(JointBitType::Touch, TigerAttackJoints)) + case TIGER_STATE_BITE_ATTACK: + case TIGER_STATE_RUN_SWIPE_ATTACK: + case TIGER_STATE_POUNCE_ATTACK: + if (!creature->Flags && item->TestBits(JointBitType::Touch, TigerAttackJoints)) { - DoDamage(info->Enemy, TIGER_ATTACK_DAMAGE); + DoDamage(creature->Enemy, TIGER_ATTACK_DAMAGE); CreatureEffect(item, TigerBite, DoBloodSplat); - info->Flags = 1; + creature->Flags = 1; // 1 = is attacking. } break; @@ -161,7 +192,7 @@ namespace TEN::Entities::TR3 } CreatureTilt(item, tilt); - CreatureJoint(item, 0, head); + CreatureJoint(item, 0, extraHeadRot.y); CreatureAnimation(itemNumber, angle, tilt); } } diff --git a/TombEngine/Objects/TR3/Entity/tr3_tiger.h b/TombEngine/Objects/TR3/Entity/tr3_tiger.h index d1966b8fb..4f002d68a 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_tiger.h +++ b/TombEngine/Objects/TR3/Entity/tr3_tiger.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void TigerControl(short itemNumber); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_tony.cpp b/TombEngine/Objects/TR3/Entity/tr3_tony.cpp index 27986862f..a9d8ed164 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_tony.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_tony.cpp @@ -20,7 +20,7 @@ using namespace TEN::Effects::Lara; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { static BOSS_STRUCT BossData; @@ -452,7 +452,7 @@ namespace TEN::Entities::TR3 if (!Lara.Burn) { - if (ItemNearLara(&fx->pos, 200)) + if (ItemNearLara(&fx->pos.Position, 200)) { LaraItem->HitStatus = true; KillEffect(fxNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_tony.h b/TombEngine/Objects/TR3/Entity/tr3_tony.h index 398cb37e5..2606a52a2 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_tony.h +++ b/TombEngine/Objects/TR3/Entity/tr3_tony.h @@ -1,7 +1,7 @@ #pragma once #include "Game/items.h" -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void InitialiseTony(short itemNumber); void TonyControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_trex.cpp b/TombEngine/Objects/TR3/Entity/tr3_trex.cpp index 08eef7f86..1f88b76a8 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_trex.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_trex.cpp @@ -15,15 +15,20 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { + constexpr auto TREX_CONTACT_DAMAGE = 1; + constexpr auto TREX_RUN_CONTACT_DAMAGE = 10; + constexpr auto TREX_ROAR_CHANCE = 0.015f; constexpr auto LARA_ANIM_TREX_DEATH_ANIM = 4; const vector TRexAttackJoints = { 12, 13 }; + #define TREX_WALK_TURN_RATE_MAX ANGLE(2.0f) + #define TREX_RUN_TURN_RATE_MAX ANGLE(4.0f) + enum TRexState { - TREX_STATE_NONE = 0, TREX_STATE_IDLE = 1, TREX_STATE_WALK_FORWARD = 2, TREX_STATE_RUN_FORWARD = 3, @@ -57,8 +62,10 @@ namespace TEN::Entities::TR3 if (laraItem->RoomNumber != tRexItem->RoomNumber) ItemNewRoom(Lara.ItemNumber, tRexItem->RoomNumber); - laraItem->Pose.Position = tRexItem->Pose.Position; - laraItem->Pose.Orientation = EulerAngles(0, tRexItem->Pose.Orientation.y, 0); + laraItem->Pose = PoseData( + tRexItem->Pose.Position, + EulerAngles(0, tRexItem->Pose.Orientation.y, 0) + ); laraItem->Animation.IsAirborne = false; laraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_ANIM_TREX_DEATH_ANIM; @@ -82,10 +89,10 @@ namespace TEN::Entities::TR3 return; auto* item = &g_Level.Items[itemNumber]; - auto* info = GetCreatureInfo(item); + auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; + short head = 0; if (item->HitPoints <= 0) { @@ -105,18 +112,18 @@ namespace TEN::Entities::TR3 GetCreatureMood(item, &AI, true); CreatureMood(item, &AI, true); - angle = CreatureTurn(item, info->MaxTurn); + angle = CreatureTurn(item, creature->MaxTurn); if (item->TouchBits) - DoDamage(LaraItem, (item->Animation.ActiveState == TREX_STATE_RUN_FORWARD) ? 10 : 1); + DoDamage(LaraItem, (item->Animation.ActiveState == TREX_STATE_RUN_FORWARD) ? TREX_RUN_CONTACT_DAMAGE : TREX_CONTACT_DAMAGE); - info->Flags = (info->Mood != MoodType::Escape && !AI.ahead && AI.enemyFacing > -FRONT_ARC && AI.enemyFacing < FRONT_ARC); + creature->Flags = (creature->Mood != MoodType::Escape && !AI.ahead && AI.enemyFacing > -FRONT_ARC && AI.enemyFacing < FRONT_ARC); if (AI.distance > pow(1500, 2) && AI.distance < pow(SECTOR(4), 2) && - AI.bite && !info->Flags) + AI.bite && !creature->Flags) { - info->Flags = 1; + creature->Flags = 1; } switch (item->Animation.ActiveState) @@ -126,7 +133,7 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = item->Animation.RequiredState; else if (AI.distance < pow(1500, 2) && AI.bite) item->Animation.TargetState = TREX_STATE_ATTACK; - else if (info->Mood == MoodType::Bored || info->Flags) + else if (creature->Mood == MoodType::Bored || creature->Flags) item->Animation.TargetState = TREX_STATE_WALK_FORWARD; else item->Animation.TargetState = TREX_STATE_RUN_FORWARD; @@ -134,32 +141,32 @@ namespace TEN::Entities::TR3 break; case TREX_STATE_WALK_FORWARD: - info->MaxTurn = ANGLE(2.0f); + creature->MaxTurn = TREX_WALK_TURN_RATE_MAX; - if (info->Mood != MoodType::Bored || !info->Flags) + if (creature->Mood != MoodType::Bored || !creature->Flags) item->Animation.TargetState = TREX_STATE_IDLE; - else if (AI.ahead && TestProbability(0.015f)) + else if (AI.ahead && TestProbability(TREX_ROAR_CHANCE)) { - item->Animation.RequiredState = TREX_STATE_ROAR; item->Animation.TargetState = TREX_STATE_IDLE; + item->Animation.RequiredState = TREX_STATE_ROAR; } break; case TREX_STATE_RUN_FORWARD: - info->MaxTurn = ANGLE(4.0f); + creature->MaxTurn = TREX_RUN_TURN_RATE_MAX; if (AI.distance < pow(SECTOR(5), 2) && AI.bite) item->Animation.TargetState = TREX_STATE_IDLE; - else if (info->Flags) + else if (creature->Flags) item->Animation.TargetState = TREX_STATE_IDLE; - else if (info->Mood != MoodType::Escape && - AI.ahead && TestProbability(0.015f)) + else if (creature->Mood != MoodType::Escape && + AI.ahead && TestProbability(TREX_ROAR_CHANCE)) { - item->Animation.RequiredState = TREX_STATE_ROAR; item->Animation.TargetState = TREX_STATE_IDLE; + item->Animation.RequiredState = TREX_STATE_ROAR; } - else if (info->Mood == MoodType::Bored) + else if (creature->Mood == MoodType::Bored) item->Animation.TargetState = TREX_STATE_IDLE; break; @@ -178,8 +185,8 @@ namespace TEN::Entities::TR3 } } - CreatureJoint(item, 0, (short)(head * 2)); - info->JointRotation[1] = info->JointRotation[0]; + CreatureJoint(item, 0, head * 2); + creature->JointRotation[1] = creature->JointRotation[0]; CreatureAnimation(itemNumber, angle, 0); diff --git a/TombEngine/Objects/TR3/Entity/tr3_trex.h b/TombEngine/Objects/TR3/Entity/tr3_trex.h index 7975f0b52..af6ba80f7 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_trex.h +++ b/TombEngine/Objects/TR3/Entity/tr3_trex.h @@ -1,7 +1,7 @@ #pragma once #include "Game/items.h" -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void LaraTRexDeath(ItemInfo* tRexItem, ItemInfo* laraItem); void TRexControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Entity/tr3_tribesman.cpp b/TombEngine/Objects/TR3/Entity/tr3_tribesman.cpp index 260926811..94381920f 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_tribesman.cpp +++ b/TombEngine/Objects/TR3/Entity/tr3_tribesman.cpp @@ -21,7 +21,7 @@ using namespace TEN::Math; using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { const auto TribesmanAxeBite = BiteInfo(Vector3(0.0f, 16.0f, 265.0f), 13); const auto TribesmanDartBite1 = BiteInfo(Vector3(0.0f, 0.0f, -200.0f), 13); @@ -48,7 +48,6 @@ namespace TEN::Entities::TR3 enum TribesmanState { - TRIBESMAN_STATE_NONE = 0, TRIBESMAN_STATE_CROUCH_IDLE = 1, TRIBESMAN_STATE_WALK_FORWARD = 2, TRIBESMAN_STATE_RUN_FORWARD = 3, @@ -106,9 +105,9 @@ namespace TEN::Entities::TR3 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short head = 0; short angle = 0; short tilt = 0; + short head = 0; if (item->HitPoints <= 0) { @@ -154,7 +153,7 @@ namespace TEN::Entities::TR3 { creature->MaxTurn = 0; - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) item->Animation.TargetState = TRIBESMAN_STATE_WALK_FORWARD; } else if (creature->Mood == MoodType::Escape) @@ -193,7 +192,7 @@ namespace TEN::Entities::TR3 { creature->MaxTurn = 0; - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) item->Animation.TargetState = TRIBESMAN_STATE_WALK_FORWARD; } else if (creature->Mood == MoodType::Escape) @@ -218,15 +217,15 @@ namespace TEN::Entities::TR3 break; case TRIBESMAN_STATE_WALK_FORWARD: - tilt = angle / 8; creature->MaxTurn = ANGLE(9.0f); creature->Flags = 0; + tilt = angle / 8; if (creature->Mood == MoodType::Bored) { creature->MaxTurn /= 4; - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) { if (TestProbability(0.25f)) item->Animation.TargetState = TRIBESMAN_STATE_CROUCH_IDLE; @@ -249,15 +248,15 @@ namespace TEN::Entities::TR3 break; case TRIBESMAN_STATE_RUN_FORWARD: - tilt = angle / 4; creature->MaxTurn = ANGLE(6.0f); creature->Flags = 0; + tilt = angle / 4; if (creature->Mood == MoodType::Bored) { creature->MaxTurn /= 4; - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) { if (TestProbability(0.5f)) item->Animation.TargetState = TRIBESMAN_STATE_CROUCH_IDLE; @@ -281,6 +280,7 @@ namespace TEN::Entities::TR3 case TRIBESMAN_STATE_AXE_ATTACK_HIGH_START: creature->MaxTurn = ANGLE(4.0f); + if (AI.bite || AI.distance < pow(682, 2)) item->Animation.TargetState = TRIBESMAN_STATE_AXE_ATTACK_HIGH_CONTINUE; else @@ -312,12 +312,9 @@ namespace TEN::Entities::TR3 } else { - if (creature->Enemy) + if (creature->Enemy != nullptr) { - auto direction = creature->Enemy->Pose.Position - item->Pose.Position; - if (abs(direction.x) < SECTOR(0.5f) && - abs(direction.y) < SECTOR(0.5f) && - abs(direction.z) < SECTOR(0.5f) && + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.5f) && creature->Flags >= TribesmanAxeHit[item->Animation.ActiveState][0] && creature->Flags <= TribesmanAxeHit[item->Animation.ActiveState][1]) { @@ -386,10 +383,8 @@ namespace TEN::Entities::TR3 short angle = 0; short tilt = 0; - short headX = 0; - short headY = 0; - short torsoX = 0; - short torsoY = 0; + auto extraHeadRot = EulerAngles::Zero; + auto extraTorsoRot = EulerAngles::Zero; if (item->HitPoints <= 0) { @@ -422,8 +417,8 @@ namespace TEN::Entities::TR3 angle = CreatureTurn(item, creature->Mood == MoodType::Bored ? ANGLE(2.0f) : creature->MaxTurn); if (AI.ahead) { - headY = AI.angle / 2; - torsoY = AI.angle / 2; + extraHeadRot.y = AI.angle / 2; + extraTorsoRot.y = AI.angle / 2; } if (item->HitStatus || @@ -441,18 +436,18 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoY = AI.angle; - torsoX = AI.xAngle / 2; + extraTorsoRot.x = AI.xAngle / 2; + extraTorsoRot.y = AI.angle; } if (item->AIBits & GUARD) { creature->MaxTurn = 0; - headY = AIGuard(creature); - torsoX = 0; - torsoY = 0; + extraHeadRot.y = AIGuard(creature); + extraTorsoRot.x = 0; + extraTorsoRot.y = 0; - if (!(GetRandomControl() & 0xFF)) + if (TestProbability(1.0f / 256)) item->Animation.TargetState = TRIBESMAN_STATE_IDLE; break; @@ -472,7 +467,7 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = TRIBESMAN_STATE_DART_ATTACK; else if (creature->Mood == MoodType::Bored) { - if (TestProbability(0.015f)) + if (TestProbability(1.0f / 64)) item->Animation.TargetState = TRIBESMAN_STATE_WALK_FORWARD; else break; @@ -482,18 +477,18 @@ namespace TEN::Entities::TR3 break; - case 11: + case TRIBESMAN_STATE_IDLE: creature->MaxTurn = ANGLE(2.0f); creature->Flags &= 0x0FFF; if (item->AIBits & GUARD) { creature->MaxTurn = 0; - headY = AIGuard(creature); - torsoX = 0; - torsoY = 0; + extraHeadRot.y = AIGuard(creature); + extraTorsoRot.x = 0; + extraTorsoRot.y = 0; - if (!(GetRandomControl() & 0xFF)) + if (TestProbability(1.0f / 256)) item->Animation.TargetState = TRIBESMAN_STATE_CROUCH_IDLE; break; @@ -511,7 +506,7 @@ namespace TEN::Entities::TR3 item->Animation.TargetState = TRIBESMAN_STATE_WALK_FORWARD; else if (Targetable(item, &AI) && AI.distance < pow(MAX_VISIBILITY_DISTANCE, 2)) item->Animation.TargetState = TRIBESMAN_STATE_CROUCH_IDLE; - else if (creature->Mood == MoodType::Bored && TestProbability(0.015f)) + else if (creature->Mood == MoodType::Bored && TestProbability(1.0f / 64)) item->Animation.TargetState = TRIBESMAN_STATE_WALK_FORWARD; else item->Animation.TargetState = TRIBESMAN_STATE_RUN_FORWARD; @@ -543,7 +538,7 @@ namespace TEN::Entities::TR3 break; - case 3: + case TRIBESMAN_STATE_RUN_FORWARD: creature->MaxTurn = ANGLE(6.0f); creature->Flags &= 0x0FFF; tilt = angle / 4; @@ -575,8 +570,8 @@ namespace TEN::Entities::TR3 if (AI.ahead) { - torsoX = AI.xAngle; - torsoY = AI.angle; + extraTorsoRot.x = AI.xAngle; + extraTorsoRot.y = AI.angle; } if (abs(AI.angle) < ANGLE(2.0f)) @@ -610,9 +605,7 @@ namespace TEN::Entities::TR3 { if (creature->Enemy != nullptr && !(creature->Flags & 0xf000)) { - if (abs(creature->Enemy->Pose.Position.x - item->Pose.Position.x) < pow(SECTOR(0.5f), 2) && - abs(creature->Enemy->Pose.Position.y - item->Pose.Position.y) < pow(SECTOR(0.5f), 2) && - abs(creature->Enemy->Pose.Position.z - item->Pose.Position.z) < pow(SECTOR(0.5f), 2)) + if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= SECTOR(0.5f)) { DoDamage(creature->Enemy, 5); SoundEffect(SFX_TR4_LARA_THUD, &item->Pose); @@ -627,12 +620,12 @@ namespace TEN::Entities::TR3 CreatureTilt(item, tilt); - headY -= torsoY; + extraHeadRot.y -= extraTorsoRot.y; - CreatureJoint(item, 0, torsoY); - CreatureJoint(item, 1, torsoX); - CreatureJoint(item, 2, headY); - CreatureJoint(item, 3, headX); + CreatureJoint(item, 0, extraTorsoRot.y); + CreatureJoint(item, 1, extraTorsoRot.x); + CreatureJoint(item, 2, extraHeadRot.y); + CreatureJoint(item, 3, extraHeadRot.x); CreatureAnimation(itemNumber, angle, 0); } diff --git a/TombEngine/Objects/TR3/Entity/tr3_tribesman.h b/TombEngine/Objects/TR3/Entity/tr3_tribesman.h index 72743252a..696518dea 100644 --- a/TombEngine/Objects/TR3/Entity/tr3_tribesman.h +++ b/TombEngine/Objects/TR3/Entity/tr3_tribesman.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR3 +namespace TEN::Entities::Creatures::TR3 { void TribemanAxeControl(short itemNumber); void TribemanDartsControl(short itemNumber); diff --git a/TombEngine/Objects/TR3/Trap/train.cpp b/TombEngine/Objects/TR3/Trap/train.cpp index 32093fce9..565a71f64 100644 --- a/TombEngine/Objects/TR3/Trap/train.cpp +++ b/TombEngine/Objects/TR3/Trap/train.cpp @@ -21,14 +21,16 @@ long TrainTestHeight(ItemInfo* item, long x, long z, short* roomNumber) { - float s = phd_sin(item->Pose.Orientation.y); - float c = phd_cos(item->Pose.Orientation.y); - - Vector3i pos; - pos.x = round(item->Pose.Position.x + z * s + x * c); - pos.y = round(item->Pose.Position.y - z * phd_sin(item->Pose.Orientation.x) + x * phd_sin(item->Pose.Orientation.z)); - pos.z = round(item->Pose.Position.z + z * c - x * s); + float sinX = phd_sin(item->Pose.Orientation.x); + float sinY = phd_sin(item->Pose.Orientation.y); + float cosY = phd_cos(item->Pose.Orientation.y); + float sinZ = phd_sin(item->Pose.Orientation.z); + auto pos = Vector3i( + round(item->Pose.Position.x + ((z * sinY) + (x * cosY))), + round(item->Pose.Position.y - ((z * sinX) + (x * sinZ))), + round(item->Pose.Position.z + ((z * cosY) - (x * sinY))) + ); auto probe = GetCollision(pos.x, pos.y, pos.z, item->RoomNumber); *roomNumber = probe.RoomNumber; @@ -45,11 +47,11 @@ void TrainControl(short itemNumber) if (item->ItemFlags[0] == 0) item->ItemFlags[0] = item->ItemFlags[1] = TRAIN_VEL; - float s = phd_sin(item->Pose.Orientation.y); - float c = phd_cos(item->Pose.Orientation.y); + float sinY = phd_sin(item->Pose.Orientation.y); + float cosY = phd_cos(item->Pose.Orientation.y); - item->Pose.Position.x += item->ItemFlags[1] * s; - item->Pose.Position.z += item->ItemFlags[1] * c; + item->Pose.Position.x += item->ItemFlags[1] * sinY; + item->Pose.Position.z += item->ItemFlags[1] * cosY; short roomNumber; long rh = TrainTestHeight(item, 0, SECTOR(5), &roomNumber); @@ -70,7 +72,7 @@ void TrainControl(short itemNumber) item->Pose.Orientation.x = -(rh - floorHeight) * 2; - TriggerDynamicLight(item->Pose.Position.x + SECTOR(3) * s, item->Pose.Position.y, item->Pose.Position.z + SECTOR(3) * c, 16, 31, 31, 31); + TriggerDynamicLight(item->Pose.Position.x + SECTOR(3) * sinY, item->Pose.Position.y, item->Pose.Position.z + SECTOR(3) * cosY, 16, 31, 31, 31); if (item->ItemFlags[1] != TRAIN_VEL) { @@ -80,8 +82,8 @@ void TrainControl(short itemNumber) if (!UseForcedFixedCamera) { - ForcedFixedCamera.x = item->Pose.Position.x + SECTOR(8) * s; - ForcedFixedCamera.z = item->Pose.Position.z + SECTOR(8) * c; + ForcedFixedCamera.x = item->Pose.Position.x + SECTOR(8) * sinY; + ForcedFixedCamera.z = item->Pose.Position.z + SECTOR(8) * cosY; ForcedFixedCamera.y = GetCollision(ForcedFixedCamera.x, item->Pose.Position.y - CLICK(2), ForcedFixedCamera.z, item->RoomNumber).Position.Floor; @@ -95,12 +97,13 @@ void TrainControl(short itemNumber) void TrainCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll) { + auto* item = &g_Level.Items[itemNumber]; auto* laraInfo = GetLaraInfo(laraItem); - auto* trainItem = &g_Level.Items[itemNumber]; - if (!TestBoundsCollide(trainItem, laraItem, coll->Setup.Radius)) + if (!TestBoundsCollide(item, laraItem, coll->Setup.Radius)) return; - if (!TestCollision(trainItem, laraItem)) + + if (!TestCollision(item, laraItem)) return; SoundEffect(SFX_TR4_LARA_GENERAL_DEATH, &laraItem->Pose, SoundEnvironment::Always); @@ -111,10 +114,10 @@ void TrainCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll) laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase; // laraItem->Animation.ActiveState = EXTRA_TRAINKILL; // laraItem->Animation.TargetState = EXTRA_TRAINKILL; - laraItem->Pose.Orientation.y = trainItem->Pose.Orientation.y; - laraItem->Animation.Velocity.z = 0; - laraItem->Animation.Velocity.y = 0; laraItem->Animation.IsAirborne = false; + laraItem->Animation.Velocity.y = 0.0f; + laraItem->Animation.Velocity.z = 0.0f; + laraItem->Pose.Orientation.y = item->Pose.Orientation.y; DoDamage(laraItem, INT_MAX); @@ -126,13 +129,13 @@ void TrainCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll) laraInfo->HitDirection = -1; laraInfo->Air = -1; - trainItem->ItemFlags[1] = 160; + item->ItemFlags[1] = 160; - float s = phd_sin(trainItem->Pose.Orientation.y); - float c = phd_cos(trainItem->Pose.Orientation.y); + float sinY = phd_sin(item->Pose.Orientation.y); + float cosY = phd_cos(item->Pose.Orientation.y); - long x = laraItem->Pose.Position.x + CLICK(1) * s; - long z = laraItem->Pose.Position.z + CLICK(1) * c; + long x = laraItem->Pose.Position.x + CLICK(1) * sinY; + long z = laraItem->Pose.Position.z + CLICK(1) * cosY; - DoLotsOfBlood(x, laraItem->Pose.Position.y - CLICK(2), z, SECTOR(1), trainItem->Pose.Orientation.y, laraItem->RoomNumber, 15); + DoLotsOfBlood(x, laraItem->Pose.Position.y - CLICK(2), z, SECTOR(1), item->Pose.Orientation.y, laraItem->RoomNumber, 15); } diff --git a/TombEngine/Objects/TR3/tr3_objects.cpp b/TombEngine/Objects/TR3/tr3_objects.cpp index c9dde913f..4a0503d97 100644 --- a/TombEngine/Objects/TR3/tr3_objects.cpp +++ b/TombEngine/Objects/TR3/tr3_objects.cpp @@ -7,7 +7,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -// Entities +// Creatures #include "Objects/TR3/Entity/tr3_civvy.h" // OK #include "Objects/TR3/Entity/tr3_cobra.h" // OK #include "Objects/TR3/Entity/tr3_fish_emitter.h" // OK @@ -35,7 +35,7 @@ #include "Objects/TR3/Vehicles/upv.h" #include "Objects/TR3/Vehicles/rubber_boat.h" -using namespace TEN::Entities::TR3; +using namespace TEN::Entities::Creatures::TR3; static void StartEntity(ObjectInfo* obj) { @@ -198,7 +198,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveAnim = true; obj->saveFlags = true; obj->pivotLength = 50; - obj->zoneType = ZONE_WATER; + obj->ZoneType = ZoneType::Water; g_Level.Bones[obj->boneIndex + 10 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 14 * 4] |= ROT_Z; @@ -293,7 +293,7 @@ static void StartEntity(ObjectInfo* obj) obj->saveAnim = true; obj->saveFlags = true; obj->pivotLength = 0; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; diff --git a/TombEngine/Objects/TR4/Entity/tr4_ahmet.cpp b/TombEngine/Objects/TR4/Entity/tr4_ahmet.cpp index 4aab4f7d7..fb7aa3909 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_ahmet.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_ahmet.cpp @@ -44,7 +44,7 @@ namespace TEN::Entities::TR4 enum AhmetState { - AHMET_STATE_NONE = 0, + // No state 0. AHMET_STATE_IDLE = 1, AHMET_STATE_WALK_FORWARD = 2, AHMET_STATE_RUN_FORWARD = 3, @@ -131,7 +131,7 @@ namespace TEN::Entities::TR4 auto* creature = GetCreatureInfo(item); short angle = 0; - short headY = 0; + auto extraHeadRot = EulerAngles::Zero; if (item->HitPoints <= 0) { @@ -147,14 +147,14 @@ namespace TEN::Entities::TR4 else { SetAnimation(item, AHMET_ANIM_DEATH); - Lara.InteractedItem = itemNumber; // TODO: Check if it's really required! -- TokyoSU, 3/8/2022 + Lara.InteractedItem = itemNumber; // TODO: Check if it's really required! -- TokyoSU 3/8/2022 } TriggerAhmetDeathEffect(item); } else { - if (item->AIBits != 0) // Does this entity have AI object? NOTE: Previous one checked "& ALL_AIOBJ" -- TokyoSU, 3/8/2022 + if (item->AIBits != 0) // Does this entity have AI object? NOTE: Previous one checked "& ALL_AIOBJ" -- TokyoSU 3/8/2022 GetAITarget(creature); AI_INFO AI, laraAI; @@ -167,7 +167,7 @@ namespace TEN::Entities::TR4 } else { - int dx = LaraItem->Pose.Position.x - item->Pose.Position.x; // TODO: Make ahmet to not use LaraItem global -- TokyoSU, 3/8/2022 + int dx = LaraItem->Pose.Position.x - item->Pose.Position.x; // TODO: Make ahmet to not use LaraItem global -- TokyoSU 3/8/2022 int dz = LaraItem->Pose.Position.z - item->Pose.Position.z; laraAI.angle = short(phd_atan(dx, dz)) - item->Pose.Orientation.y; laraAI.distance = SQUARE(dx) + SQUARE(dz); @@ -186,7 +186,7 @@ namespace TEN::Entities::TR4 } if (AI.ahead) - headY = AI.angle; + extraHeadRot.y = AI.angle; switch (item->Animation.ActiveState) { @@ -197,16 +197,16 @@ namespace TEN::Entities::TR4 if (item->AIBits & GUARD) { item->Animation.TargetState = AHMET_STATE_IDLE; - headY = AIGuard(creature); + extraHeadRot.y = AIGuard(creature); } else if (item->AIBits & PATROL1) { item->Animation.TargetState = AHMET_STATE_WALK_FORWARD; - headY = 0; + extraHeadRot.y = 0; } else if (creature->Mood == MoodType::Bored || creature->Mood == MoodType::Escape) { - if (Lara.TargetEntity == item || !AI.ahead) // TODO: Make ahmet not use LaraInfo global. -- TokyoSU, 3/8/2022 + if (Lara.TargetEntity == item || !AI.ahead) // TODO: Make ahmet not use LaraInfo global. -- TokyoSU 3/8/2022 item->Animation.TargetState = AHMET_STATE_RUN_FORWARD; else item->Animation.TargetState = AHMET_STATE_IDLE; @@ -239,7 +239,7 @@ namespace TEN::Entities::TR4 if (item->AIBits & PATROL1) { item->Animation.TargetState = AHMET_STATE_WALK_FORWARD; - headY = 0; + extraHeadRot.y = 0; } else if (AI.bite && AI.distance < AHMET_IDLE_RANGE) item->Animation.TargetState = AHMET_STATE_IDLE; @@ -323,7 +323,8 @@ namespace TEN::Entities::TR4 if (!(creature->Flags & 1) && item->Animation.AnimNumber == (Objects[item->ObjectNumber].animIndex + AHMET_ANIM_JUMP_BITE_ATTACK_CONTINUE)) { - if (item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 11) && item->TestBits(JointBitType::Touch, AhmetSwipeAttackLeftJoints)) + if (item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 11) && + item->TestBits(JointBitType::Touch, AhmetSwipeAttackLeftJoints)) { DoDamage(creature->Enemy, AHMET_BITE_ATTACK_DAMAGE); CreatureEffect2(item, AhmetBiteJaw, 10, -1, DoBloodSplat); @@ -351,13 +352,17 @@ namespace TEN::Entities::TR4 } else { - if (!(creature->Flags & 1) && item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 14) && item->TestBits(JointBitType::Touch, AhmetSwipeAttackLeftJoints)) + if (!(creature->Flags & 1) && + item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 14) && + item->TestBits(JointBitType::Touch, AhmetSwipeAttackLeftJoints)) { DoDamage(creature->Enemy, AHMET_SWIPE_ATTACK_DAMAGE); CreatureEffect2(item, AhmetBiteLeft, 10, -1, DoBloodSplat); creature->Flags |= 1; } - else if (!(creature->Flags & 2) && item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 22) && item->TestBits(JointBitType::Touch, AhmetSwipeAttackRightJoints)) + else if (!(creature->Flags & 2) && + item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 22) && + item->TestBits(JointBitType::Touch, AhmetSwipeAttackRightJoints)) { DoDamage(creature->Enemy, AHMET_SWIPE_ATTACK_DAMAGE); CreatureEffect2(item, AhmetBiteRight, 10, -1, DoBloodSplat); @@ -371,7 +376,7 @@ namespace TEN::Entities::TR4 TestTriggers(item, true); CreatureTilt(item, 0); - CreatureJoint(item, 0, headY); + CreatureJoint(item, 0, extraHeadRot.y); CreatureAnimation(itemNumber, angle, 0); } diff --git a/TombEngine/Objects/TR4/Entity/tr4_baboon.cpp b/TombEngine/Objects/TR4/Entity/tr4_baboon.cpp index 9d5653226..95ee501a7 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_baboon.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_baboon.cpp @@ -49,8 +49,7 @@ namespace TEN::Entities::TR4 enum BaboonState { - BABOON_STATE_NULL = 0, - BABOON_STATE_NONE = 1, + // No states 0-1. BABOON_STATE_WALK_FORWARD = 2, BABOON_STATE_IDLE = 3, BABOON_STATE_RUN_FORWARD = 4, @@ -437,7 +436,7 @@ namespace TEN::Entities::TR4 { if (item->AIBits & FOLLOW) item->Animation.TargetState = BABOON_STATE_WALK_FORWARD; - else if (TestProbability(0.008f)) + else if (TestProbability(1.0f / 128)) item->Animation.TargetState = BABOON_STATE_SIT_IDLE; } else if (creature->Mood == MoodType::Escape) @@ -447,7 +446,7 @@ namespace TEN::Entities::TR4 if (AI.bite && AI.distance < BABOON_ATTACK_READY_RANGE) item->Animation.TargetState = BABOON_STATE_IDLE; } - else if (TestProbability(0.008f)) + else if (TestProbability(1.0f / 128)) item->Animation.TargetState = BABOON_STATE_SIT_IDLE; break; diff --git a/TombEngine/Objects/TR4/Entity/tr4_baddy.cpp b/TombEngine/Objects/TR4/Entity/tr4_baddy.cpp index 85c1929f6..358a97e5f 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_baddy.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_baddy.cpp @@ -1213,7 +1213,7 @@ namespace TEN::Entities::TR4 case BADDY_STATE_BLIND: if (!FlashGrenadeAftershockTimer) { - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) item->Animation.TargetState = BADDY_STATE_IDLE; } diff --git a/TombEngine/Objects/TR4/Entity/tr4_bat.cpp b/TombEngine/Objects/TR4/Entity/tr4_bat.cpp index e32e31a35..c099de619 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_bat.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_bat.cpp @@ -29,7 +29,7 @@ namespace TEN::Entities::TR4 enum BatState { - BAT_STATE_NONE = 0, + // No state 0. BAT_STATE_DROP_FROM_CEILING = 1, BAT_STATE_FLY = 2, BAT_STATE_ATTACK = 3, @@ -102,7 +102,7 @@ namespace TEN::Entities::TR4 break; case BAT_STATE_FLY: - if (AI.distance < BAT_ATTACK_RANGE || TestProbability(0.015f)) + if (AI.distance < BAT_ATTACK_RANGE || TestProbability(1.0f / 64)) creature->Flags = 0; if (!creature->Flags) diff --git a/TombEngine/Objects/TR4/Entity/tr4_big_beetle.cpp b/TombEngine/Objects/TR4/Entity/tr4_big_beetle.cpp index d9d61fa46..15d3e2c93 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_big_beetle.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_big_beetle.cpp @@ -28,7 +28,7 @@ namespace TEN::Entities::TR4 enum BigBeetleState { - BBEETLE_STATE_NONE = 0, + // No state 0. BBEETLE_STATE_IDLE = 1, BBEETLE_STATE_TAKE_OFF = 2, BBEETLE_STATE_FLY_FORWARD = 3, @@ -122,7 +122,7 @@ namespace TEN::Entities::TR4 angle = CreatureTurn(item, creature->MaxTurn); if (item->HitStatus || AI.distance > BIG_BEETLE_AWARE_RANGE || - TestProbability(0.008f)) + TestProbability(1.0f / 128)) { creature->Flags = 0; } diff --git a/TombEngine/Objects/TR4/Entity/tr4_big_scorpion.cpp b/TombEngine/Objects/TR4/Entity/tr4_big_scorpion.cpp index 032437edd..0aa04e342 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_big_scorpion.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_big_scorpion.cpp @@ -22,7 +22,7 @@ namespace TEN::Entities::TR4 { constexpr auto BIG_SCORPION_ATTACK_DAMAGE = 120; constexpr auto BIG_SCORPION_TROOP_ATTACK_DAMAGE = 15; - constexpr auto BIG_SCORPION_STINGER_POISON_POTENCY = 8; + constexpr auto BIG_SCORPION_STINGER_POISON_POTENCY = 16; constexpr auto BIG_SCORPION_ATTACK_RANGE = SQUARE(SECTOR(1.35)); constexpr auto BIG_SCORPION_RUN_RANGE = SQUARE(SECTOR(2)); @@ -35,7 +35,7 @@ namespace TEN::Entities::TR4 enum BigScorpionState { - BSCORPION_STATE_NONE = 0, + // No state 0. BSCORPION_STATE_IDLE = 1, BSCORPION_STATE_WALK_FORWARD = 2, BSCORPION_STATE_RUN_FORWARD = 3, diff --git a/TombEngine/Objects/TR4/Entity/tr4_crocodile.cpp b/TombEngine/Objects/TR4/Entity/tr4_crocodile.cpp index df03467e2..97cdf795c 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_crocodile.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_crocodile.cpp @@ -30,9 +30,9 @@ namespace TEN::Entities::TR4 constexpr auto CROC_SWIM_SPEED = 16; - #define CROC_STATE_WALK_FORWARD_ANGLE ANGLE(3.0f) - #define CROC_SWIM_ANGLE ANGLE(3.0f) - #define CROC_STATE_RUN_FORWARD_ANGLE ANGLE(5.0f) + #define CROC_STATE_WALK_TURN_RATE_MAX ANGLE(3.0f) + #define CROC_STATE_RUN_TURN_RATE_MAX ANGLE(5.0f) + #define CROC_STATE_SWIM_TURN_RATE_MAX ANGLE(3.0f) const auto CrocodileBite = BiteInfo(Vector3(0.0f, -100.0f, 500.0f), 9); const vector CrocodileBiteAttackJoints = { 8, 9 }; @@ -49,7 +49,7 @@ namespace TEN::Entities::TR4 CROC_STATE_DEATH = 7, CROC_STATE_SWIM_FORWARD = 8, CROC_STATE_WATER_BITE_ATTACK = 9, - CROC_STATE_WATER_DEATH = 10, + CROC_STATE_WATER_DEATH = 10 }; enum CrocodileAnim @@ -119,12 +119,12 @@ namespace TEN::Entities::TR4 return; auto* item = &g_Level.Items[itemNumber]; - auto* creature = GetCreatureInfo(item); auto* object = &Objects[item->ObjectNumber]; + auto* creature = GetCreatureInfo(item); - AI_INFO AI; short angle = 0; short boneAngle = 0; + AI_INFO AI; if (item->HitPoints <= 0) { @@ -178,7 +178,7 @@ namespace TEN::Entities::TR4 item->Animation.TargetState = CROC_STATE_IDLE; item->ItemFlags[0] += item->ItemFlags[1]; - if (TestProbability(0.03f)) + if (TestProbability(1.0f / 30)) { if (TestProbability(0.5f)) item->ItemFlags[1] = 0; @@ -203,7 +203,7 @@ namespace TEN::Entities::TR4 break; case CROC_STATE_WALK_FORWARD: - creature->MaxTurn = CROC_STATE_WALK_FORWARD_ANGLE; + creature->MaxTurn = CROC_STATE_WALK_TURN_RATE_MAX; // Land to water transition. if (IsCrocodileInWater(item) && !item->Animation.RequiredState) @@ -222,7 +222,7 @@ namespace TEN::Entities::TR4 break; case CROC_STATE_RUN_FORWARD: - creature->MaxTurn = CROC_STATE_RUN_FORWARD_ANGLE; + creature->MaxTurn = CROC_STATE_RUN_TURN_RATE_MAX; // Land to water transition. if (IsCrocodileInWater(item)) @@ -243,7 +243,7 @@ namespace TEN::Entities::TR4 case CROC_STATE_BITE_ATTACK: if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase) - item->Animation.RequiredState = 0; + item->Animation.RequiredState = CROC_STATE_NONE_1; if (AI.bite && item->TestBits(JointBitType::Touch, CrocodileBiteAttackJoints)) @@ -261,7 +261,7 @@ namespace TEN::Entities::TR4 break; case CROC_STATE_SWIM_FORWARD: - creature->MaxTurn = CROC_SWIM_ANGLE; + creature->MaxTurn = CROC_STATE_SWIM_TURN_RATE_MAX; // Water to land transition. if (!IsCrocodileInWater(item)) diff --git a/TombEngine/Objects/TR4/Entity/tr4_dog.cpp b/TombEngine/Objects/TR4/Entity/tr4_dog.cpp index 9c5fccf96..46b861691 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_dog.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_dog.cpp @@ -169,7 +169,7 @@ namespace TEN::Entities::TR4 creature->Flags++; creature->MaxTurn = 0; - if (creature->Flags > 300 && TestProbability(0.004f)) + if (creature->Flags > 300 && TestProbability(1.0f / 256)) item->Animation.TargetState = DOG_STATE_IDLE; } @@ -202,7 +202,7 @@ namespace TEN::Entities::TR4 else { if (item->Animation.ActiveState == DOG_STATE_STALK_IDLE && - TestProbability(0.004f)) + TestProbability(1.0f / 256)) { item->Animation.TargetState = DOG_STATE_IDLE; break; @@ -243,7 +243,7 @@ namespace TEN::Entities::TR4 creature->MaxTurn = ANGLE(1.0f); creature->Flags = 0; - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) { if (item->AIBits & MODIFY) { @@ -258,7 +258,7 @@ namespace TEN::Entities::TR4 if (TestProbability(0.875f)) { - if (TestProbability(0.03f)) + if (TestProbability(1.0f / 30)) item->Animation.TargetState = DOG_STATE_HOWL; break; @@ -279,7 +279,7 @@ namespace TEN::Entities::TR4 if (item->AIBits & PATROL1) item->Animation.TargetState = DOG_STATE_WALK_FORWARD; - else if (creature->Mood == MoodType::Bored && TestProbability(0.008f)) + else if (creature->Mood == MoodType::Bored && TestProbability(1.0f / 128)) item->Animation.TargetState = DOG_STATE_IDLE; else item->Animation.TargetState = DOG_STATE_STALK; diff --git a/TombEngine/Objects/TR4/Entity/tr4_hammerhead.cpp b/TombEngine/Objects/TR4/Entity/tr4_hammerhead.cpp index 53c67e5b3..029fe7793 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_hammerhead.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_hammerhead.cpp @@ -16,6 +16,7 @@ using std::vector; namespace TEN::Entities::TR4 { constexpr auto HAMMERHEAD_BITE_ATTACK_DAMAGE = 120; + constexpr auto HAMMERHEAD_ATTACK_RANGE = SQUARE(SECTOR(0.66f)); const auto HammerheadBite = BiteInfo(Vector3::Zero, 12); const vector HammerheadBiteAttackJoints = { 10, 12, 13 }; @@ -60,109 +61,100 @@ namespace TEN::Entities::TR4 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + HAMMERHEAD_ANIM_IDLE; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = HAMMERHEAD_STATE_IDLE; - item->Animation.TargetState = HAMMERHEAD_STATE_IDLE; + SetAnimation(item, HAMMERHEAD_ANIM_IDLE); } void HammerheadControl(short itemNumber) { - if (CreatureActive(itemNumber)) + if (!CreatureActive(itemNumber)) + return; + + auto* item = &g_Level.Items[itemNumber]; + auto* creature = GetCreatureInfo(item); + + if (item->HitPoints <= 0) { - auto* item = &g_Level.Items[itemNumber]; - auto* creature = GetCreatureInfo(item); + if (item->Animation.ActiveState != HAMMERHEAD_STATE_DEATH) + SetAnimation(item, HAMMERHEAD_ANIM_DEATH_START); - if (item->HitPoints > 0) + item->HitPoints = 0; + CreatureFloat(itemNumber); + } + else + { + if (item->AIBits) + GetAITarget(creature); + else if (creature->HurtByLara) + creature->Enemy = LaraItem; + + AI_INFO AI; + CreatureAIInfo(item, &AI); + + if (!creature->Enemy->IsLara()) + phd_atan(LaraItem->Pose.Position.z - item->Pose.Position.z, LaraItem->Pose.Position.x - item->Pose.Position.x); + + GetCreatureMood(item, &AI, true); + CreatureMood(item, &AI, true); + + short angle = CreatureTurn(item, creature->MaxTurn); + + switch (item->Animation.ActiveState) { - if (item->AIBits) - GetAITarget(creature); - else if (creature->HurtByLara) - creature->Enemy = LaraItem; + case HAMMERHEAD_STATE_IDLE: + item->Animation.TargetState = HAMMERHEAD_STATE_SWIM_SLOW; + creature->Flags = 0; + break; - AI_INFO AI; - CreatureAIInfo(item, &AI); + case HAMMERHEAD_STATE_SWIM_SLOW: + creature->MaxTurn = ANGLE(7.0f); - if (creature->Enemy != LaraItem) - phd_atan(LaraItem->Pose.Position.z - item->Pose.Position.z, LaraItem->Pose.Position.x - item->Pose.Position.x); - - GetCreatureMood(item, &AI, true); - CreatureMood(item, &AI, true); - - short angle = CreatureTurn(item, creature->MaxTurn); - - switch (item->Animation.ActiveState) + if (AI.distance <= pow(SECTOR(1), 2)) { - case HAMMERHEAD_STATE_IDLE: - item->Animation.TargetState = HAMMERHEAD_STATE_SWIM_SLOW; - creature->Flags = 0; - break; - - case HAMMERHEAD_STATE_SWIM_SLOW: - creature->MaxTurn = ANGLE(7.0f); - - if (AI.distance <= pow(SECTOR(1), 2)) - { - if (AI.distance < pow(682, 2)) - item->Animation.TargetState = HAMMERHEAD_STATE_IDLE_BITE_ATTACK; - } - else - item->Animation.TargetState = HAMMERHEAD_STATE_SWIM_FAST; - - break; - - case HAMMERHEAD_STATE_SWIM_FAST: - if (AI.distance < pow(SECTOR(1), 2)) - item->Animation.TargetState = HAMMERHEAD_STATE_SWIM_SLOW; - - break; - - case HAMMERHEAD_STATE_IDLE_BITE_ATTACK: - if (!creature->Flags) - { - if (item->TestBits(JointBitType::Touch, HammerheadBiteAttackJoints)) - { - DoDamage(creature->Enemy, HAMMERHEAD_BITE_ATTACK_DAMAGE); - CreatureEffect(item, HammerheadBite, DoBloodSplat); - creature->Flags = 1; - } - } - - break; - - default: - break; + if (AI.distance < HAMMERHEAD_ATTACK_RANGE) + item->Animation.TargetState = HAMMERHEAD_STATE_IDLE_BITE_ATTACK; } - - CreatureTilt(item, 0); - CreatureJoint(item, 0, angle * -2); - CreatureJoint(item, 1, angle * -2); - CreatureJoint(item, 2, angle * -2); - CreatureJoint(item, 3, angle * 2); - - // NOTE: in TR2 shark there was a call to CreatureKill with special kill anim - // Hammerhead seems to not have it in original code but this check is still there as a leftover - if (item->Animation.ActiveState == HAMMERHEAD_STATE_KILL) - AnimateItem(item); else + item->Animation.TargetState = HAMMERHEAD_STATE_SWIM_FAST; + + break; + + case HAMMERHEAD_STATE_SWIM_FAST: + if (AI.distance < pow(SECTOR(1), 2)) + item->Animation.TargetState = HAMMERHEAD_STATE_SWIM_SLOW; + + break; + + case HAMMERHEAD_STATE_IDLE_BITE_ATTACK: + if (!creature->Flags) { - CreatureAnimation(itemNumber, angle, 0); - CreatureUnderwater(item, 341); + if (item->TestBits(JointBitType::Touch, HammerheadBiteAttackJoints)) + { + DoDamage(creature->Enemy, HAMMERHEAD_BITE_ATTACK_DAMAGE); + CreatureEffect(item, HammerheadBite, DoBloodSplat); + creature->Flags = 1; + } } + + break; + + default: + break; } + + CreatureTilt(item, 0); + CreatureJoint(item, 0, angle * -2); + CreatureJoint(item, 1, angle * -2); + CreatureJoint(item, 2, angle * -2); + CreatureJoint(item, 3, angle * 2); + + // NOTE: in TR2 shark there was a call to CreatureKill with special kill anim + // Hammerhead seems to not have it in original code but this check is still there as a leftover + if (item->Animation.ActiveState == HAMMERHEAD_STATE_KILL) + AnimateItem(item); else { - item->HitPoints = 0; - - if (item->Animation.ActiveState != HAMMERHEAD_STATE_DEATH) - { - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + HAMMERHEAD_ANIM_DEATH_START; - item->Animation.ActiveState = HAMMERHEAD_STATE_DEATH; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.FrameNumber].frameBase; - } - - CreatureFloat(itemNumber); + CreatureAnimation(itemNumber, angle, 0); + CreatureUnderwater(item, 341); } } } diff --git a/TombEngine/Objects/TR4/Entity/tr4_harpy.cpp b/TombEngine/Objects/TR4/Entity/tr4_harpy.cpp index 15e47142d..e79bf09c1 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_harpy.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_harpy.cpp @@ -76,31 +76,32 @@ namespace TEN::Entities::TR4 HARPY_ANIM_GLIDE = 18 }; - static void TriggerHarpyMissile(PoseData* pose, short roomNumber, short mesh) + void TriggerHarpyMissile(PoseData* pose, short roomNumber, short mesh) { short fxNumber = CreateNewEffect(roomNumber); - if (fxNumber != -1) - { - auto* fx = &EffectList[fxNumber]; + if (fxNumber == -1) + return; - fx->pos.Position.x = pose->Position.x; - fx->pos.Position.y = pose->Position.y - (GetRandomControl() & 0x3F) - 32; - fx->pos.Position.z = pose->Position.z; - fx->pos.Orientation.x = pose->Orientation.x; - fx->pos.Orientation.y = pose->Orientation.y; - fx->pos.Orientation.z = 0; - fx->roomNumber = roomNumber; - fx->counter = short(2 * GetRandomControl() + 0x8000); - fx->objectNumber = ID_ENERGY_BUBBLES; - fx->speed = (GetRandomControl() & 0x1F) + 96; - fx->flag1 = mesh; - fx->frameNumber = Objects[fx->objectNumber].meshIndex + mesh * 2; - } + auto* fx = &EffectList[fxNumber]; + + fx->pos.Position.x = pose->Position.x; + fx->pos.Position.y = pose->Position.y - (GetRandomControl() & 0x3F) - 32; + fx->pos.Position.z = pose->Position.z; + fx->pos.Orientation.x = pose->Orientation.x; + fx->pos.Orientation.y = pose->Orientation.y; + fx->pos.Orientation.z = 0; + fx->roomNumber = roomNumber; + fx->counter = short(2 * GetRandomControl() + 0x8000); + fx->objectNumber = ID_ENERGY_BUBBLES; + fx->speed = (GetRandomControl() & 0x1F) + 96; + fx->flag1 = mesh; + fx->frameNumber = Objects[fx->objectNumber].meshIndex + mesh * 2; } - static void TriggerHarpyFlame(short itemNumber, ItemInfo* target, byte nodeNumber, short size) + void TriggerHarpyFlame(short itemNumber, ItemInfo* target, byte nodeNumber, short size) { auto* item = &g_Level.Items[itemNumber]; + int dx = target->Pose.Position.x - item->Pose.Position.x; int dz = target->Pose.Position.z - item->Pose.Position.z; @@ -144,7 +145,7 @@ namespace TEN::Entities::TR4 } } - static void TriggerHarpySparks(ItemInfo* target, int x, int y, int z, short xv, short yv, short zv) + void TriggerHarpySparks(ItemInfo* target, int x, int y, int z, short xv, short yv, short zv) { int dx = target->Pose.Position.x - x; int dz = target->Pose.Position.z - z; @@ -181,7 +182,7 @@ namespace TEN::Entities::TR4 } } - static void DoHarpyEffects(ItemInfo* item, CreatureInfo* creature, short itemNumber) + void DoHarpyEffects(ItemInfo* item, CreatureInfo* creature, short itemNumber) { item->ItemFlags[0]++; @@ -262,9 +263,9 @@ namespace TEN::Entities::TR4 if (item->HitPoints <= 0) { - int state = item->Animation.ActiveState - 9; item->HitPoints = 0; + int state = item->Animation.ActiveState - 9; if (state) { state--; @@ -300,7 +301,7 @@ namespace TEN::Entities::TR4 { item->Animation.TargetState = HARPY_STATE_DEATH_END; item->Animation.IsAirborne = false; - item->Animation.Velocity.y = 0; + item->Animation.Velocity.y = 0.0f; item->Pose.Position.y = item->Floor; } @@ -315,10 +316,8 @@ namespace TEN::Entities::TR4 creature->Enemy = nullptr; - for (int i = 0; i < ActiveCreatures.size(); i++) + for (auto& currentCreature : ActiveCreatures) { - auto* currentCreature = ActiveCreatures[i]; - if (currentCreature->ItemNumber == NO_ITEM || currentCreature->ItemNumber == itemNumber) continue; @@ -341,7 +340,7 @@ namespace TEN::Entities::TR4 AI_INFO AI; CreatureAIInfo(item, &AI); - if (creature->Enemy != LaraItem) + if (!creature->Enemy->IsLara()) phd_atan(LaraItem->Pose.Position.z - item->Pose.Position.z, LaraItem->Pose.Position.x - item->Pose.Position.x); GetCreatureMood(item, &AI, true); @@ -430,10 +429,9 @@ namespace TEN::Entities::TR4 { if (AI.distance >= pow(341, 2)) { - if (AI.ahead && + if (AI.ahead && TestProbability(0.5f) && AI.distance >= pow(SECTOR(2), 2) && - AI.distance > pow(SECTOR(3.5f), 2) && - TestProbability(0.5f)) + AI.distance > pow(SECTOR(3.5f), 2)) { item->Animation.TargetState = HARPY_STATE_FLAME_ATTACK; item->ItemFlags[0] = 0; @@ -500,7 +498,7 @@ namespace TEN::Entities::TR4 creature->MaxTurn = ANGLE(2.0f); if (item->TestBits(JointBitType::Touch, HarpySwoopAttackJoints) || - creature->Enemy && !creature->Enemy->IsLara() && + creature->Enemy != nullptr && !creature->Enemy->IsLara() && abs(creature->Enemy->Pose.Position.y - item->Pose.Position.y) <= SECTOR(1) && AI.distance < pow(SECTOR(2), 2)) { @@ -519,7 +517,7 @@ namespace TEN::Entities::TR4 if (creature->Flags == 0 && (item->TestBits(JointBitType::Touch, HarpyStingerAttackJoints) || - creature->Enemy && !creature->Enemy->IsLara() && + creature->Enemy != nullptr && !creature->Enemy->IsLara() && abs(creature->Enemy->Pose.Position.y - item->Pose.Position.y) <= SECTOR(1) && AI.distance < pow(SECTOR(2), 2))) { diff --git a/TombEngine/Objects/TR4/Entity/tr4_horseman.cpp b/TombEngine/Objects/TR4/Entity/tr4_horseman.cpp index b180b5cf6..d938b877a 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_horseman.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_horseman.cpp @@ -18,12 +18,17 @@ #include "Math/Math.h" using namespace TEN::Math::Random; +using std::vector; namespace TEN::Entities::TR4 { const auto HorsemanBite1 = BiteInfo(Vector3::Zero, 6); const auto HorsemanBite2 = BiteInfo(Vector3::Zero, 14); const auto HorsemanBite3 = BiteInfo(Vector3::Zero, 10); + const vector HorsemanAxeAttackJoints = { 5, 6 }; + const vector HorsemanKickAttackJoints = { 14 }; + const vector HorsemanMountedAttackJoints = { 5, 6, 10 }; + const vector HorsemanShieldAttackJoints = { 10 }; const auto HorseBite1 = BiteInfo(Vector3::Zero, 13); const auto HorseBite2 = BiteInfo(Vector3::Zero, 17); @@ -549,7 +554,7 @@ namespace TEN::Entities::TR4 case HORSEMAN_STATE_MOUNTED_ATTACK_RIGHT: if (!creature->Flags) { - if (item->TouchBits & 0x60) + if (item->TestBits(JointBitType::Touch, HorsemanAxeAttackJoints)) { DoDamage(creature->Enemy, 250); CreatureEffect2(item, HorsemanBite1, 10, item->Pose.Orientation.y, DoBloodSplat); @@ -565,7 +570,7 @@ namespace TEN::Entities::TR4 case HORSEMAN_STATE_MOUNTED_ATTACK_LEFT: if (!creature->Flags) { - if (item->TouchBits & 0x4000) + if (item->TestBits(JointBitType::Touch, HorsemanKickAttackJoints)) { DoDamage(creature->Enemy, 100); CreatureEffect2(item, HorsemanBite2, 3, item->Pose.Orientation.y, DoBloodSplat); @@ -654,7 +659,7 @@ namespace TEN::Entities::TR4 if (!creature->Flags) { - if (item->TouchBits & 0x4000) + if (item->TestBits(JointBitType::Touch, HorsemanAxeAttackJoints)) { DoDamage(creature->Enemy, 100); CreatureEffect2(item, HorsemanBite2, 3, item->Pose.Orientation.y, DoBloodSplat); @@ -695,16 +700,16 @@ namespace TEN::Entities::TR4 if (!creature->Flags) { - if (item->TouchBits & 0x460) + if (item->TestBits(JointBitType::Touch, HorsemanMountedAttackJoints)) { LaraItem->HitStatus = true; - if (item->TouchBits & 0x60) + if (item->TestBits(JointBitType::Touch, HorsemanAxeAttackJoints)) { DoDamage(creature->Enemy, 250); CreatureEffect2(horseItem, HorsemanBite1, 20, -1, DoBloodSplat); } - else if (item->TouchBits & 0x400) + else if (item->TestBits(JointBitType::Touch, HorsemanShieldAttackJoints)) { DoDamage(creature->Enemy, 150); CreatureEffect2(horseItem, HorsemanBite3, 10, -1, DoBloodSplat); diff --git a/TombEngine/Objects/TR4/Entity/tr4_knight_templar.cpp b/TombEngine/Objects/TR4/Entity/tr4_knight_templar.cpp index 937adf250..606127067 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_knight_templar.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_knight_templar.cpp @@ -29,7 +29,7 @@ namespace TEN::Entities::TR4 enum KnightTemplarState { - KTEMPLAR_STATE_NONE = 0, + // No state 0. KTEMPLAR_STATE_IDLE = 1, KTEMPLAR_STATE_WALK_FORWARD = 2, KTEMPLAR_STATE_SWORD_ATTACK_1 = 3, @@ -62,10 +62,7 @@ namespace TEN::Entities::TR4 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - item->Animation.AnimNumber = Objects[ID_KNIGHT_TEMPLAR].animIndex + KTEMPLAR_ANIM_IDLE; - item->Animation.TargetState = KTEMPLAR_STATE_IDLE; - item->Animation.ActiveState = KTEMPLAR_STATE_IDLE; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; + SetAnimation(item, KTEMPLAR_ANIM_IDLE); item->MeshBits &= 0xF7FF; } @@ -75,8 +72,14 @@ namespace TEN::Entities::TR4 return; auto* item = &g_Level.Items[itemNumber]; - auto* creature = GetCreatureInfo(item); auto* object = &Objects[item->ObjectNumber]; + auto* creature = GetCreatureInfo(item); + + short angle = 0; + short tilt = 0; + short joint0 = 0; + short joint1 = 0; + short joint2 = 0; if (item->Animation.AnimNumber == object->animIndex || (item->Animation.AnimNumber - object->animIndex) == KTEMPLAR_ANIM_WALK_FORWARD_RIGHT_1 || @@ -90,12 +93,6 @@ namespace TEN::Entities::TR4 } } - short tilt = 0; - short angle = 0; - short joint0 = 0; - short joint1 = 0; - short joint2 = 0; - // Knight is immortal. if (item->HitPoints < object->HitPoints) item->HitPoints = object->HitPoints; diff --git a/TombEngine/Objects/TR4/Entity/tr4_mummy.cpp b/TombEngine/Objects/TR4/Entity/tr4_mummy.cpp index 4476c9dc9..7a9c27dc6 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_mummy.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_mummy.cpp @@ -17,7 +17,7 @@ using std::vector; namespace TEN::Entities::TR4 { - constexpr auto MUMMY_ATTACK_DAMAGE = 100; + constexpr auto MUMMY_SWIPE_ATTACK_DAMAGE = 100; constexpr auto MUMMY_IDLE_SWIPE_ATTACK_RANGE = SQUARE(SECTOR(0.5f)); constexpr auto MUMMY_WALK_SWIPE_ATTACK_RANGE = SQUARE(SECTOR(0.67f)); @@ -26,11 +26,12 @@ namespace TEN::Entities::TR4 constexpr auto MUMMY_ARMS_UP_RANGE = SQUARE(SECTOR(3)); constexpr auto MUMMY_AWARE_RANGE = SQUARE(SECTOR(7)); - #define MUMMY_WALK_TURN_ANGLE ANGLE(7.0f) + #define MUMMY_WALK_TURN_RATE_MAX ANGLE(7.0f) + #define MUMMY_ATTACK_TURN_RATE_MAX ANGLE(7.0f) const auto MummyBite1 = BiteInfo(Vector3::Zero, 11); const auto MummyBite2 = BiteInfo(Vector3::Zero, 14); - const vector MummyAttackJoints { 11, 14 }; + const vector MummySwipeAttackJoints { 11, 14 }; enum MummyState { @@ -81,16 +82,10 @@ namespace TEN::Entities::TR4 if (item->TriggerFlags == 2) { SetAnimation(item, MUMMY_ANIM_COLLAPSE_END); - item->Animation.TargetState = MUMMY_STATE_INACTIVE_LYING_DOWN; // TODO: Check if needed. -- Sezz - item->Animation.ActiveState = MUMMY_STATE_INACTIVE_LYING_DOWN; item->Status -= ITEM_INVISIBLE; } else - { SetAnimation(item, MUMMY_ANIM_ARMS_CROSSED); - item->Animation.TargetState = MUMMY_STATE_INACTIVE_ARMS_CROSSED; // TODO: Check if needed. -- Sezz - item->Animation.ActiveState = MUMMY_STATE_INACTIVE_ARMS_CROSSED; - } } void MummyControl(short itemNumber) @@ -101,8 +96,8 @@ namespace TEN::Entities::TR4 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short tilt = 0; short angle = 0; + short tilt = 0; short joint0 = 0; short joint1 = 0; short joint2 = 0; @@ -209,7 +204,7 @@ namespace TEN::Entities::TR4 } else { - creature->MaxTurn = MUMMY_WALK_TURN_ANGLE; + creature->MaxTurn = MUMMY_WALK_TURN_RATE_MAX; if (AI.distance >= MUMMY_ARMS_UP_RANGE) { @@ -223,7 +218,7 @@ namespace TEN::Entities::TR4 break; case MUMMY_STATE_WALK_FORWARD_ARMS_UP: - creature->MaxTurn = MUMMY_WALK_TURN_ANGLE; + creature->MaxTurn = MUMMY_WALK_TURN_RATE_MAX; creature->Flags = 0; if (AI.distance < MUMMY_IDLE_SWIPE_ATTACK_RANGE) @@ -260,7 +255,7 @@ namespace TEN::Entities::TR4 joint1 = 0; joint2 = 0; - if (AI.distance < MUMMY_ACTIVATE_RANGE || TestProbability(0.008f)) + if (AI.distance < MUMMY_ACTIVATE_RANGE || TestProbability(1.0f / 128)) { item->Animation.TargetState = MUMMY_STATE_COLLAPSED_TO_IDLE; item->HitPoints = Objects[item->ObjectNumber].HitPoints; @@ -272,26 +267,26 @@ namespace TEN::Entities::TR4 case MUMMY_STATE_IDLE_SWIPE_ATTACK: creature->MaxTurn = 0; - if (abs(AI.angle) >= ANGLE(7.0f)) + if (abs(AI.angle) >= MUMMY_ATTACK_TURN_RATE_MAX) { if (AI.angle >= 0) - item->Pose.Orientation.y += ANGLE(7.0f); + item->Pose.Orientation.y += MUMMY_ATTACK_TURN_RATE_MAX; else - item->Pose.Orientation.y -= ANGLE(7.0f); + item->Pose.Orientation.y -= MUMMY_ATTACK_TURN_RATE_MAX; } else item->Pose.Orientation.y += AI.angle; if (!creature->Flags) { - if (item->TestBits(JointBitType::Touch, MummyAttackJoints)) + if (item->TestBits(JointBitType::Touch, MummySwipeAttackJoints)) { if (item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase && item->Animation.FrameNumber < g_Level.Anims[item->Animation.AnimNumber].frameEnd) { - DoDamage(creature->Enemy, MUMMY_ATTACK_DAMAGE); + DoDamage(creature->Enemy, MUMMY_SWIPE_ATTACK_DAMAGE); - if (item->Animation.AnimNumber == Objects[item->ObjectNumber].animIndex + MUMMY_ANIM_IDLE_SWIPE_ATTACK_LEFT) + if (item->Animation.AnimNumber == (Objects[item->ObjectNumber].animIndex + MUMMY_ANIM_IDLE_SWIPE_ATTACK_LEFT)) CreatureEffect2(item, MummyBite1, 5, -1, DoBloodSplat); else CreatureEffect2(item, MummyBite2, 5, -1, DoBloodSplat); @@ -309,11 +304,9 @@ namespace TEN::Entities::TR4 } CreatureTilt(item, 0); - CreatureJoint(item, 0, joint0); CreatureJoint(item, 1, joint1); CreatureJoint(item, 2, joint2); - CreatureAnimation(itemNumber, angle, 0); } } diff --git a/TombEngine/Objects/TR4/Entity/tr4_sas.cpp b/TombEngine/Objects/TR4/Entity/tr4_sas.cpp index 5e41a6a04..204b35d05 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_sas.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_sas.cpp @@ -625,7 +625,7 @@ namespace TEN::Entities::TR4 if (item->Animation.ActiveState == 1) { - if (TestProbability(0.008f)) + if (TestProbability(1.0f / 128)) { item->Animation.TargetState = 2; AnimateItem(item); @@ -634,7 +634,7 @@ namespace TEN::Entities::TR4 item->Animation.TargetState = 3; } else if (item->Animation.ActiveState == 4 && - TestProbability(0.008f)) + TestProbability(1.0f / 128)) { item->Animation.TargetState = 5; AnimateItem(item); diff --git a/TombEngine/Objects/TR4/Entity/tr4_setha.cpp b/TombEngine/Objects/TR4/Entity/tr4_setha.cpp index 702389cab..0a5849f5a 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_setha.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_setha.cpp @@ -29,10 +29,7 @@ namespace TEN::Entities::TR4 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 4; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = 12; - item->Animation.TargetState = 12; + SetAnimation(item, 4); } void SethaControl(short itemNumber) @@ -113,8 +110,7 @@ namespace TEN::Entities::TR4 else if (LaraItem->Pose.Position.y >= (item->Pose.Position.y - SECTOR(1))) { if (AI.distance < pow(SECTOR(2.5f), 2) && - AI.ahead && - TestProbability(0.5f) && + AI.ahead && TestProbability(0.5f) && Targetable(item, &AI)) { item->Animation.TargetState = 11; @@ -195,8 +191,7 @@ namespace TEN::Entities::TR4 if (AI.bite && AI.distance < pow(SECTOR(4), 2) || - canJump || - creature->ReachedGoal) + canJump || creature->ReachedGoal) { item->Animation.TargetState = 1; } @@ -210,8 +205,7 @@ namespace TEN::Entities::TR4 if (AI.bite && AI.distance < pow(SECTOR(4), 2) || - canJump || - creature->ReachedGoal) + canJump || creature->ReachedGoal) { item->Animation.TargetState = 1; } diff --git a/TombEngine/Objects/TR4/Entity/tr4_skeleton.cpp b/TombEngine/Objects/TR4/Entity/tr4_skeleton.cpp index 20f9e9f72..233405e3f 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_skeleton.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_skeleton.cpp @@ -29,6 +29,7 @@ namespace TEN::Entities::TR4 const auto SkeletonBite = BiteInfo(Vector3(0.0f, -16.0f, 200.0f), 11); const vector SkeletonSwordAttackJoints = { 15, 16 }; + // TODO: Fill in missign states. enum SkeletonState { SKELETON_STATE_SUBTERRANEAN = 0, @@ -72,36 +73,28 @@ namespace TEN::Entities::TR4 void InitialiseSkeleton(short itemNumber) { auto* item = &g_Level.Items[itemNumber]; - auto* object = &Objects[item->ObjectNumber]; ClearItem(itemNumber); + // TODO: Check cases 0 and 3. switch (item->TriggerFlags) { case 0: - item->Animation.AnimNumber = object->animIndex; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; + SetAnimation(item, SKELETON_ANIM_EMERGE); item->Animation.ActiveState = SKELETON_STATE_SUBTERRANEAN; item->Animation.TargetState = SKELETON_STATE_SUBTERRANEAN; break; case 1: - item->Animation.AnimNumber = object->animIndex + SKELETON_ANIM_JUMP_RIGHT_START; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = SKELETON_STATE_JUMP_RIGHT; - item->Animation.TargetState = SKELETON_STATE_JUMP_RIGHT; + SetAnimation(item, SKELETON_ANIM_JUMP_RIGHT_START); break; case 2: - item->Animation.AnimNumber = object->animIndex + SKELETON_ANIM_JUMP_LEFT_START; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = SKELETON_STATE_JUMP_LEFT; - item->Animation.TargetState = SKELETON_STATE_JUMP_LEFT; + SetAnimation(item, SKELETON_ANIM_JUMP_LEFT_START); break; case 3: - item->Animation.AnimNumber = object->animIndex; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; + SetAnimation(item, SKELETON_ANIM_EMERGE); item->Animation.ActiveState = SKELETON_STATE_JUMP_LIE_DOWN; item->Animation.TargetState = SKELETON_STATE_JUMP_LIE_DOWN; //item->status = ITEM_DEACTIVATED; @@ -175,15 +168,15 @@ namespace TEN::Entities::TR4 bool jumpLeft = false; bool jumpRight = false; - int distance = 0; - short tilt = 0; short angle = 0; + short tilt = 0; short joint1 = 0; short joint2 = 0; short joint3 = 0; short rotation = 0; + int distance = 0; - // Can skeleton jump? Check for a distance of 1 and 2 sectors. + // Can skeleton jump? Check for a distance of 1 and 2 blocks. int x = item->Pose.Position.x; int y = item->Pose.Position.y; int z = item->Pose.Position.z; @@ -204,24 +197,24 @@ namespace TEN::Entities::TR4 int height3 = GetCollision(x, y, z, item->RoomNumber).Position.Floor; int height = 0; - bool canJump1sector = true; - if (enemyItem && item->BoxNumber == LaraItem->BoxNumber && item->MeshBits & 0x200 || - y >= height1 - CLICK(1.5f) || - y >= height2 + CLICK(2) || - y <= height2 - CLICK(2)) + bool canJump1Block = true; + if (enemyItem && item->BoxNumber == LaraItem->BoxNumber && (item->MeshBits & 0x200) || + y >= (height1 - CLICK(1.5f)) || + y >= (height2 + CLICK(2)) || + y <= (height2 - CLICK(2))) { height = height2; - canJump1sector = false; + canJump1Block = false; } - bool canJump2sectors = true; - if (enemyItem && item->BoxNumber == LaraItem->BoxNumber && item->MeshBits & 0x200 || - y >= height1 - CLICK(1.5f) || - y >= height - CLICK(1.5f) || - y >= height3 + CLICK(2) || - y <= height3 - CLICK(2)) + bool canJump2Blocks = true; + if (enemyItem && item->BoxNumber == LaraItem->BoxNumber && (item->MeshBits & 0x200) || + y >= (height1 - CLICK(1.5f)) || + y >= (height - CLICK(1.5f)) || + y >= (height3 + CLICK(2)) || + y <= (height3 - CLICK(2))) { - canJump2sectors = false; + canJump2Blocks = false; } if (item->AIBits) @@ -235,17 +228,17 @@ namespace TEN::Entities::TR4 if (item->HitStatus && Lara.Control.Weapon.GunType == LaraWeaponType::Shotgun && AI.distance < pow(SECTOR(3.5f), 2) && - item->Animation.ActiveState != 7 && + item->Animation.ActiveState != SKELETON_STATE_USE_SHIELD && item->Animation.ActiveState != 17 && item->Animation.ActiveState != SKELETON_STATE_HURT_BY_SHOTGUN_1 && item->Animation.ActiveState != SKELETON_STATE_HURT_BY_SHOTGUN_2 && - item->Animation.ActiveState != 25) + item->Animation.ActiveState != SKELETON_STATE_JUMP_LIE_DOWN) { if (AI.angle >= ANGLE(67.5f) || AI.angle <= -ANGLE(67.5f)) { item->Animation.ActiveState = SKELETON_STATE_HURT_BY_SHOTGUN_2; item->Animation.AnimNumber = Objects[ID_SKELETON].animIndex + 33; - item->Pose.Orientation.y += AI.angle + -32768; + item->Pose.Orientation.y += AI.angle - ANGLE(180.0f); } else { @@ -365,7 +358,7 @@ namespace TEN::Entities::TR4 creature->Flags = 0; if (item->AIBits & GUARD || - TestProbability(0.03f) && + TestProbability(1.0f / 30) && (AI.distance > pow(SECTOR(1), 2) || creature->Mood != MoodType::Attack)) { @@ -381,14 +374,14 @@ namespace TEN::Entities::TR4 { if (item->AIBits & PATROL1) item->Animation.TargetState = 15; - else if (canJump1sector || canJump2sectors) + else if (canJump1Block || canJump2Blocks) { item->Animation.AnimNumber = Objects[ID_SKELETON].animIndex + 40; item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; item->Animation.ActiveState = SKELETON_STATE_JUMP_LEFT; creature->MaxTurn = 0; - if (!canJump2sectors) + if (!canJump2Blocks) { item->Animation.TargetState = SKELETON_STATE_JUMP_FORWARD_1_BLOCK; creature->LOT.IsJumping = true; @@ -400,26 +393,15 @@ namespace TEN::Entities::TR4 } } else if (jumpLeft) - { - item->Animation.AnimNumber = Objects[ID_SKELETON].animIndex + 34; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = SKELETON_STATE_JUMP_LEFT; - item->Animation.TargetState = SKELETON_STATE_JUMP_LEFT; - } + SetAnimation(item, SKELETON_ANIM_JUMP_LEFT_START); else if (jumpRight) - { - item->Animation.AnimNumber = Objects[ID_SKELETON].animIndex + 37; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = SKELETON_STATE_JUMP_RIGHT; - item->Animation.TargetState = SKELETON_STATE_JUMP_RIGHT; - } + SetAnimation(item, SKELETON_ANIM_JUMP_RIGHT_START); else { if (creature->Mood == MoodType::Escape) { if (Lara.TargetEntity == item || - !AI.ahead || - item->HitStatus || + !AI.ahead || item->HitStatus || !(item->MeshBits & 0x200)) { item->Animation.TargetState = 15; @@ -430,8 +412,7 @@ namespace TEN::Entities::TR4 } else if (creature->Mood == MoodType::Bored || item->AIBits & FOLLOW && - (creature->ReachedGoal || - laraAI.distance > pow(SECTOR(2), 2))) + (creature->ReachedGoal || laraAI.distance > pow(SECTOR(2), 2))) { if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; @@ -439,8 +420,7 @@ namespace TEN::Entities::TR4 item->Animation.TargetState = 15; } else if (Lara.TargetEntity == item && - laraAI.angle && - laraAI.distance < pow(SECTOR(2), 2) && + laraAI.angle && laraAI.distance < pow(SECTOR(2), 2) && TestProbability(0.5f) && (Lara.Control.Weapon.GunType == LaraWeaponType::Shotgun || TestProbability(0.06f)) && item->MeshBits == -1) @@ -509,7 +489,7 @@ namespace TEN::Entities::TR4 { if (AI.bite && AI.distance < pow(SECTOR(1), 2)) item->Animation.TargetState = 18; - else if (canJump1sector || canJump2sectors) + else if (canJump1Block || canJump2Blocks) { item->Animation.TargetState = 2; creature->MaxTurn = 0; @@ -530,7 +510,7 @@ namespace TEN::Entities::TR4 creature->MaxTurn = ANGLE(7.0f); creature->LOT.IsJumping = false; - if (item->AIBits & GUARD || canJump1sector || canJump2sectors) + if (item->AIBits & GUARD || canJump1Block || canJump2Blocks) { if (item->MeshBits & 0x200) { @@ -667,7 +647,7 @@ namespace TEN::Entities::TR4 else item->Animation.TargetState = 2; } - else if (Lara.TargetEntity != item || item->MeshBits != -1 || Lara.Control.Weapon.GunType != LaraWeaponType::Shotgun || TestProbability(0.008f)) + else if (Lara.TargetEntity != item || item->MeshBits != -1 || Lara.Control.Weapon.GunType != LaraWeaponType::Shotgun || TestProbability(1.0f / 128)) item->Animation.TargetState = 2; break; @@ -727,7 +707,7 @@ namespace TEN::Entities::TR4 if (GetCollision(item).Position.Floor <= (item->Pose.Position.y + SECTOR(1))) { - if (TestProbability(0.03f)) + if (TestProbability(1.0f / 30)) item->Animation.TargetState = 14; } else diff --git a/TombEngine/Objects/TR4/Entity/tr4_small_scorpion.cpp b/TombEngine/Objects/TR4/Entity/tr4_small_scorpion.cpp index 709d5917d..151adb096 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_small_scorpion.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_small_scorpion.cpp @@ -57,11 +57,7 @@ namespace TEN::Entities::TR4 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[ID_SMALL_SCORPION].animIndex + SSCORPION_ANIM_IDLE; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.TargetState = SSCORPION_STATE_IDLE; - item->Animation.ActiveState = SSCORPION_STATE_IDLE; + SetAnimation(item, SSCORPION_ANIM_IDLE); } void SmallScorpionControl(short itemNumber) @@ -73,9 +69,9 @@ namespace TEN::Entities::TR4 auto* creature = GetCreatureInfo(item); short angle = 0; + short tilt = 0; short head = 0; short neck = 0; - short tilt = 0; short joint0 = 0; short joint1 = 0; short joint2 = 0; @@ -87,9 +83,7 @@ namespace TEN::Entities::TR4 if (item->Animation.ActiveState != SSCORPION_STATE_DEATH_1 && item->Animation.ActiveState != SSCORPION_STATE_DEATH_2) { - item->Animation.AnimNumber = Objects[ID_SMALL_SCORPION].animIndex + SSCORPION_ANIM_DEATH; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = SSCORPION_STATE_DEATH_1; + SetAnimation(item, SSCORPION_ANIM_DEATH); } } else @@ -118,6 +112,7 @@ namespace TEN::Entities::TR4 else if (AI.bite) { creature->MaxTurn = ANGLE(6.0f); + if (TestProbability(0.5f)) item->Animation.TargetState = SSCORPION_STATE_ATTACK_1; else diff --git a/TombEngine/Objects/TR4/Entity/tr4_troops.cpp b/TombEngine/Objects/TR4/Entity/tr4_troops.cpp index 2bd357c74..9d90ababd 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_troops.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_troops.cpp @@ -453,7 +453,7 @@ namespace TEN::Entities::TR4 break; case TROOP_STATE_FLASHED: - if (!FlashGrenadeAftershockTimer && TestProbability(0.008f)) + if (!FlashGrenadeAftershockTimer && TestProbability(1.0f / 128)) item->Animation.TargetState = TROOP_STATE_GUARD; break; diff --git a/TombEngine/Objects/TR4/Entity/tr4_von_croy.cpp b/TombEngine/Objects/TR4/Entity/tr4_von_croy.cpp index beb56cc43..4f40a648a 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_von_croy.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_von_croy.cpp @@ -770,10 +770,10 @@ namespace TEN::Entities::TR4 creature->MaxTurn = 0; ClampRotation(&item->Pose, AI.angle, ANGLE(6.0f)); - if ((enemy == NULL || enemy->Flags != NULL) || + if ((enemy == nullptr || enemy->Flags != 0) || item->Animation.FrameNumber <= g_Level.Anims[item->Animation.AnimNumber].frameBase + 21) { - if (creature->Flags == NULL && enemy != nullptr) + if (creature->Flags == 0 && enemy != nullptr) { if (item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 15 && item->Animation.FrameNumber < g_Level.Anims[item->Animation.AnimNumber].frameBase + 26) @@ -849,7 +849,7 @@ namespace TEN::Entities::TR4 item->Animation.TargetState = VON_CROY_STATE_WALK; item->Animation.RequiredState = VON_CROY_STATE_RUN; - item->ItemFlags[2] = NULL; + item->ItemFlags[2] = 0; //if (sVar3 == -1) goto LAB_0041a991; if (!flags) { @@ -878,38 +878,38 @@ namespace TEN::Entities::TR4 CreatureJoint(item, 2, joint2); CreatureJoint(item, 3, joint3); - if ((item->Animation.ActiveState < VON_CROY_STATE_JUMP) && (item->Animation.ActiveState != VON_CROY_STATE_MONKEY)) + if (item->Animation.ActiveState < VON_CROY_STATE_JUMP && + item->Animation.ActiveState != VON_CROY_STATE_MONKEY) { switch (CreatureVault(itemNumber, angle, 2, 260)) { - case VON_CROY_STATE_WALK: + case 2: item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + VON_CROY_ANIM_CLIMB_2_BLOCKS; item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; item->Animation.ActiveState = VON_CROY_STATE_CLIMB_2_BLOCKS; creature->MaxTurn = 0; break; - case VON_CROY_STATE_RUN: + case 3: item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + VON_CROY_ANIM_CLIMB_3_BLOCKS; item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; item->Animation.ActiveState = VON_CROY_STATE_CLIMB_3_BLOCKS; creature->MaxTurn = 0; break; - case VON_CROY_STATE_START_MONKEY: + case 4: item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + VON_CROY_ANIM_CLIMB_4_BLOCKS; item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; item->Animation.ActiveState = VON_CROY_STATE_CLIMB_4_BLOCKS; creature->MaxTurn = 0; break; - case VON_CROY_STATE_LOOK_BEFORE_JUMP: + case 7: item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + VON_CROY_ANIM_JUMP_TO_HANG; item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; item->Animation.ActiveState = VON_CROY_STATE_GRAB_LADDER; creature->MaxTurn = 0; break; - // I am not sure what negative states are (probably the inverse of the above), I will leave them alone - Kubsy 18/06/2022 case -7: item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + VON_CROY_ANIM_CLIMB_DOWN_2_SECTORS; item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; diff --git a/TombEngine/Objects/TR4/Entity/tr4_wild_boar.cpp b/TombEngine/Objects/TR4/Entity/tr4_wild_boar.cpp index 4aa33f130..82bcb8e3c 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_wild_boar.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_wild_boar.cpp @@ -18,14 +18,13 @@ using namespace TEN::Math::Random; namespace TEN::Entities::TR4 { constexpr auto WILD_BOAR_ATTACK_DAMAGE = 30; - constexpr auto WILD_BOAR_ATTACK_RANGE = SQUARE(CLICK(1)); const auto WildBoarBite = BiteInfo(Vector3::Zero, 14); enum WildBoarState { - BOAR_STATE_NONE = 0, + // No state 0. BOAR_STATE_IDLE = 1, BOAR_STATE_RUN_FORWARD = 2, BOAR_STATE_GRAZE = 3, @@ -51,11 +50,7 @@ namespace TEN::Entities::TR4 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[ID_WILD_BOAR].animIndex + BOAR_ANIM_IDLE; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = BOAR_STATE_IDLE; - item->Animation.TargetState = BOAR_STATE_IDLE; + SetAnimation(item, BOAR_ANIM_IDLE); } void WildBoarControl(short itemNumber) @@ -67,9 +62,9 @@ namespace TEN::Entities::TR4 auto* creature = GetCreatureInfo(item); short angle = 0; + short tilt = 0; short head = 0; short neck = 0; - short tilt = 0; short joint0 = 0; short joint1 = 0; short joint2 = 0; @@ -153,7 +148,7 @@ namespace TEN::Entities::TR4 if (AI.ahead && AI.distance) item->Animation.TargetState = BOAR_STATE_IDLE; - else if (TestProbability(0.008f)) + else if (TestProbability(1.0f / 128)) item->Animation.TargetState = BOAR_STATE_IDLE; break; @@ -192,11 +187,7 @@ namespace TEN::Entities::TR4 item->HitPoints = 0; if (item->Animation.ActiveState != BOAR_STATE_DEATH) - { - item->Animation.AnimNumber = Objects[ID_WILD_BOAR].animIndex + BOAR_ANIM_DEATH; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = BOAR_STATE_DEATH; - } + SetAnimation(item, BOAR_ANIM_DEATH); } CreatureJoint(item, 0, joint0); diff --git a/TombEngine/Objects/TR4/Trap/tr4_joby_spikes.cpp b/TombEngine/Objects/TR4/Trap/tr4_joby_spikes.cpp index 6bdf4f566..ea609102e 100644 --- a/TombEngine/Objects/TR4/Trap/tr4_joby_spikes.cpp +++ b/TombEngine/Objects/TR4/Trap/tr4_joby_spikes.cpp @@ -15,7 +15,7 @@ namespace TEN::Entities::TR4 { auto* item = &g_Level.Items[itemNumber]; - // Set bone mutators to 0 by default + // Set bone mutators to 0 by default. for (int i = 0; i < item->Animation.Mutator.size(); i++) item->Animation.Mutator[i].Scale.y = 0.0f; @@ -24,7 +24,7 @@ namespace TEN::Entities::TR4 auto probe = GetCollision(item); - // TODO: check this optimized division + // TODO: Check this optimized division. //v6 = 1321528399i64 * ((probe.Position.Floor - probe.Position.Ceiling) << 12); //item->itemFlags[3] = (HIDWORD(v6) >> 31) + (SHIDWORD(v6) >> 10); @@ -78,7 +78,7 @@ namespace TEN::Entities::TR4 item->Pose.Orientation.y += item->ItemFlags[0]; - // Update bone mutators + // Update bone mutators. if (item->ItemFlags[1]) { for (int i = 0; i < item->Animation.Mutator.size(); i++) diff --git a/TombEngine/Objects/TR4/Trap/tr4_stargate.cpp b/TombEngine/Objects/TR4/Trap/tr4_stargate.cpp index 515db8e47..46ffe6061 100644 --- a/TombEngine/Objects/TR4/Trap/tr4_stargate.cpp +++ b/TombEngine/Objects/TR4/Trap/tr4_stargate.cpp @@ -1,46 +1,45 @@ #include "framework.h" -#include "tr4_stargate.h" -#include "Specific/level.h" -#include "Game/control/control.h" -#include "Sound/sound.h" -#include "Game/collision/collide_room.h" -#include "Game/collision/collide_item.h" -#include "Game/collision/sphere.h" -#include "Game/Lara/lara.h" -#include "Game/effects/effects.h" -#include "Game/animation.h" -#include "Game/items.h" +#include "Objects/TR4/Trap/tr4_stargate.h" -namespace TEN::Entities::TR4 +#include "Game/animation.h" +#include "Game/collision/collide_item.h" +#include "Game/collision/collide_room.h" +#include "Game/collision/sphere.h" +#include "Game/control/control.h" +#include "Game/effects/effects.h" +#include "Game/items.h" +#include "Game/Lara/lara.h" +#include "Sound/sound.h" +#include "Specific/level.h" + +using std::vector; + +namespace TEN::Entities::Traps { - short StargateBounds[24] = + constexpr auto STARGATE_HARM_DAMAGE = 100; + + const vector StargateHarmJoints = { 9, 10, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25 }; + const vector StargateBounds = { - -512, 512, -1024, - -896, -96, 96, - -512, 512, -128, - 0, -96, 96, - -512, -384, -1024, - 0, -96, 96, - 384, 512, -1024, - 0, -96, 96 + Vector3i(-CLICK(2), CLICK(2), -SECTOR(2)), + Vector3i(-896, -96, 96), + Vector3i(-CLICK(2), CLICK(2), -128), + Vector3i(0, -96, 96), + Vector3i(-CLICK(2), -384, -SECTOR(2)), + Vector3i(0, -96, 96), + Vector3i(384, CLICK(2), -SECTOR(2)), + Vector3i(0, -96, 96) }; void StargateControl(short itemNumber) { auto* item = &g_Level.Items[itemNumber]; - item->ItemFlags[3] = 50; if (TriggerActive(item)) { - int touchBits = 0x036DB600; - item->ItemFlags[0] = short(touchBits & 0xFFFF); - item->ItemFlags[1] = short((touchBits >> 16) & 0xFFFF); - SoundEffect(SFX_TR4_STARGATE_SWIRL, &item->Pose); AnimateItem(item); } - else - item->ItemFlags[0] = item->ItemFlags[1] = 0; } void StargateCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll) @@ -50,67 +49,38 @@ namespace TEN::Entities::TR4 if (item->Status == ITEM_INVISIBLE) return; - if (TestBoundsCollide(item, laraItem, coll->Setup.Radius)) + // TODO: Border collision. + /*for (auto& bounds : StargateBounds) { - for (int i = 0; i < 8; i++) + GlobalCollisionBounds.X1 = bounds.x; + GlobalCollisionBounds.Y1 = bounds.y; + GlobalCollisionBounds.Z1 = bounds.z; + + if (TestWithGlobalCollisionBounds(item, laraItem, coll)) + ItemPushItem(item, laraItem, coll, 0, 2); + }*/ + + if (!TestBoundsCollide(item, laraItem, coll->Setup.Radius)) + return; + + if (TestCollision(item, laraItem) && + TriggerActive(item) && + item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 20 && // Hardcoded frame range. + item->Animation.FrameNumber < g_Level.Anims[item->Animation.AnimNumber].frameBase + 60) + { + // Blades deal damage cumulatively. + for (int i = 0; i < StargateHarmJoints.size(); i++) { - GlobalCollisionBounds.X1 = StargateBounds[3 * i + 0]; - GlobalCollisionBounds.Y1 = StargateBounds[3 * i + 1]; - GlobalCollisionBounds.Z1 = StargateBounds[3 * i + 2]; - - if (TestWithGlobalCollisionBounds(item, laraItem, coll)) - ItemPushItem(item, laraItem, coll, 0, 2); - } - - int result = TestCollision(item, laraItem); - if (result) - { - int flags = item->ItemFlags[0] | item->ItemFlags[1] << 16; - result &= flags; - - if (result) + if (item->TestBits(JointBitType::Touch, StargateHarmJoints[i])) { - int j = 0; - do - { - if (result & 1) - { - GlobalCollisionBounds.X1 = CreatureSpheres[j].x - CreatureSpheres[j].r - item->Pose.Position.x; - GlobalCollisionBounds.Y1 = CreatureSpheres[j].y - CreatureSpheres[j].r - item->Pose.Position.y; - GlobalCollisionBounds.Z1 = CreatureSpheres[j].z - CreatureSpheres[j].r - item->Pose.Position.z; - GlobalCollisionBounds.X2 = CreatureSpheres[j].x + CreatureSpheres[j].r - item->Pose.Position.x; - GlobalCollisionBounds.Y2 = CreatureSpheres[j].y + CreatureSpheres[j].r - item->Pose.Position.y; - GlobalCollisionBounds.Z2 = CreatureSpheres[j].z + CreatureSpheres[j].r - item->Pose.Position.z; - - int oldX = LaraItem->Pose.Position.x; - int oldY = LaraItem->Pose.Position.y; - int oldZ = LaraItem->Pose.Position.z; - - if (ItemPushItem(item, laraItem, coll, flags & 1, 2)) - { - if ((flags & 1) && - (oldX != LaraItem->Pose.Position.x || - oldY != LaraItem->Pose.Position.y || - oldZ != LaraItem->Pose.Position.z) && - TriggerActive(item)) - { - DoBloodSplat((GetRandomControl() & 0x3F) + laraItem->Pose.Position.x - 32, - (GetRandomControl() & 0x1F) + CreatureSpheres[j].y - 16, - (GetRandomControl() & 0x3F) + laraItem->Pose.Position.z - 32, - (GetRandomControl() & 3) + 2, - 2 * GetRandomControl(), - laraItem->RoomNumber); - - DoDamage(laraItem, 100); - } - } - } - - result /= 2; - j++; - flags /= 2; - - } while (result); + DoDamage(laraItem, STARGATE_HARM_DAMAGE); + DoBloodSplat( + (GetRandomControl() & 0x3F) + laraItem->Pose.Position.x - 32, + (GetRandomControl() & 0x1F) + CreatureSpheres[i].y - 16, + (GetRandomControl() & 0x3F) + laraItem->Pose.Position.z - 32, + (GetRandomControl() & 3) + 2, + GetRandomControl() * 2, + laraItem->RoomNumber); } } } diff --git a/TombEngine/Objects/TR4/Trap/tr4_stargate.h b/TombEngine/Objects/TR4/Trap/tr4_stargate.h index 7fe4566d3..0d64e613e 100644 --- a/TombEngine/Objects/TR4/Trap/tr4_stargate.h +++ b/TombEngine/Objects/TR4/Trap/tr4_stargate.h @@ -1,9 +1,9 @@ #pragma once -struct ItemInfo; struct CollisionInfo; +struct ItemInfo; -namespace TEN::Entities::TR4 +namespace TEN::Entities::Traps { void StargateControl(short itemNumber); void StargateCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll); diff --git a/TombEngine/Objects/TR4/Trap/tr4_teethspike.cpp b/TombEngine/Objects/TR4/Trap/tr4_teethspike.cpp index ad03fb4fb..ed5be1cff 100644 --- a/TombEngine/Objects/TR4/Trap/tr4_teethspike.cpp +++ b/TombEngine/Objects/TR4/Trap/tr4_teethspike.cpp @@ -13,8 +13,8 @@ namespace TEN::Entities::TR4 { - constexpr auto TEETH_SPIKE_HARM_CONSTANT = 8; - constexpr auto TEETH_SPIKE_HARM_EMERGING = 30; + constexpr auto TEETH_SPIKE_HARM_DAMAGE_CONSTANT = 8; + constexpr auto TEETH_SPIKE_HARM_DAMAGE_EMERGING = 30; constexpr auto TEETH_SPIKES_DEFAULT_INTERVAL = 64; constexpr auto TEETH_SPIKE_BOUNDS_TOLERANCE_RATIO = 0.95f; @@ -37,7 +37,7 @@ namespace TEN::Entities::TR4 auto spikeBox = TO_DX_BBOX(item->Pose, GetBoundsAccurate(item)); auto itemBox = TO_DX_BBOX(collidingItem->Pose, GetBoundsAccurate(collidingItem)); - // Make intersection a bit more forgiving by reducing spike bounds a bit. + // Make intersection more forgiving by slightly reducing spike bounds. spikeBox.Extents = spikeBox.Extents * TEETH_SPIKE_BOUNDS_TOLERANCE_RATIO; return spikeBox.Contains(itemBox); } @@ -93,16 +93,16 @@ namespace TEN::Entities::TR4 if ((item->ItemFlags[0] >= 1024 || LaraItem->Animation.IsAirborne) && (angle > PI * 0.25f && angle < PI * 0.75f)) { - if (LaraItem->Animation.Velocity.y > 6 || item->ItemFlags[0] > 1024) + if (LaraItem->Animation.Velocity.y > 6.0f || item->ItemFlags[0] > 1024) { LaraItem->HitPoints = -1; bloodCount = 20; } } // Spikes are emerging or already fully protruded (in latter case, only damage Lara if she runs). - else if ((item->TriggerFlags != 1) || LaraItem->Animation.Velocity.z >= 30) + else if ((item->TriggerFlags != 1) || LaraItem->Animation.Velocity.z >= 30.0f) { - int damage = item->ItemFlags[0] == 1024 ? TEETH_SPIKE_HARM_EMERGING : TEETH_SPIKE_HARM_CONSTANT; + int damage = item->ItemFlags[0] == 1024 ? TEETH_SPIKE_HARM_DAMAGE_EMERGING : TEETH_SPIKE_HARM_DAMAGE_CONSTANT; DoDamage(LaraItem, damage); bloodCount = (GetRandomControl() & 3) + 2; } @@ -114,15 +114,15 @@ namespace TEN::Entities::TR4 int yTop = laraBounds->Y1 + LaraItem->Pose.Position.y; int yBottom = laraBounds->Y2 + LaraItem->Pose.Position.y; + // Spikes are downward; move blood origin to top. if (angle < PI * 0.125f || angle > PI * 0.825f) { - // Spikes are downward; move blood origin to top. y1 = -bounds->Y2; y2 = -bounds->Y1; } + // Spikes are upward; leave origin as is. else { - // Spikes are upward; leave origin as is. y1 = bounds->Y1; y2 = bounds->Y2; } diff --git a/TombEngine/Objects/TR4/tr4_objects.cpp b/TombEngine/Objects/TR4/tr4_objects.cpp index 5116b5006..68c5c733c 100644 --- a/TombEngine/Objects/TR4/tr4_objects.cpp +++ b/TombEngine/Objects/TR4/tr4_objects.cpp @@ -9,7 +9,7 @@ #include "Specific/setup.h" #include "Specific/level.h" -// Entities +// Creatures #include "tr4_enemy_jeep.h" #include "tr4_ahmet.h" // OK #include "tr4_baddy.h" // OK @@ -77,8 +77,10 @@ #include "tr4_teethspike.h" // Vehicles -#include "Objects/TR4/Vehicles/motorbike.h" #include "Objects/TR4/Vehicles/jeep.h" +#include "Objects/TR4/Vehicles/motorbike.h" + +using namespace TEN::Entities::Traps; namespace TEN::Entities { @@ -100,7 +102,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_BIG_SCORPION]; @@ -119,7 +121,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveFlags = true; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_HAMMERHEAD]; @@ -139,7 +141,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->waterCreature = true; - obj->zoneType = ZONE_WATER; + obj->ZoneType = ZoneType::Water; } obj = &Objects[ID_WILD_BOAR]; @@ -158,7 +160,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 48 * 4] |= ROT_Z; g_Level.Bones[obj->boneIndex + 48 * 4] |= ROT_Y; @@ -182,7 +184,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 19 * 4] |= ROT_Y; } @@ -202,7 +204,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; } obj = &Objects[ID_AHMET]; @@ -221,7 +223,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 9 * 4] |= ROT_Y; } @@ -244,7 +246,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->meshSwapSlot = ID_MESHSWAP_BADDY1; - obj->zoneType = ZONE_HUMAN_JUMP_AND_MONKEY; + obj->ZoneType = ZoneType::HumanJumpAndMonkey; g_Level.Bones[obj->boneIndex + 28 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 28 * 4] |= ROT_X; @@ -270,7 +272,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->meshSwapSlot = ID_MESHSWAP_BADDY2; - obj->zoneType = ZONE_HUMAN_JUMP_AND_MONKEY; + obj->ZoneType = ZoneType::HumanJumpAndMonkey; g_Level.Bones[obj->boneIndex + 28 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 28 * 4] |= ROT_X; @@ -295,7 +297,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex] |= ROT_Y; g_Level.Bones[obj->boneIndex] |= ROT_X; @@ -319,7 +321,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->undead = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_X; @@ -344,7 +346,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->undead = true; - obj->zoneType = ZONE_SKELLY; + obj->ZoneType = ZoneType::Skeleton; } obj = &Objects[ID_KNIGHT_TEMPLAR]; @@ -363,7 +365,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveFlags = true; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X | ROT_Y; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_Y; @@ -386,7 +388,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->savePosition = true; obj->undead = false; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; } obj = &Objects[ID_SETHA]; @@ -406,7 +408,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->saveAnim = true; obj->undead = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_DEMIGOD1]; @@ -426,7 +428,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->saveAnim = true; obj->undead = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_X | ROT_Y | ROT_Z; g_Level.Bones[obj->boneIndex + 5 * 4] |= ROT_Y; @@ -448,7 +450,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveFlags = true; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_X | ROT_Y | ROT_Z; g_Level.Bones[obj->boneIndex + 5 * 4] |= ROT_Y; } @@ -469,7 +471,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveFlags = true; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_X | ROT_Y | ROT_Z; g_Level.Bones[obj->boneIndex + 5 * 4] |= ROT_Y; } @@ -483,7 +485,7 @@ namespace TEN::Entities obj->hitEffect = HIT_BLOOD; obj->nonLot = true; obj->savePosition = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_TROOPS]; @@ -502,7 +504,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex] |= ROT_X | ROT_Y; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_X | ROT_Y; @@ -525,7 +527,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->explodableMeshbits = 64; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 0] |= ROT_Y; g_Level.Bones[obj->boneIndex + 1 * 4] |= ROT_X; @@ -548,7 +550,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; } obj = &Objects[ID_GUIDE]; @@ -567,7 +569,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->meshSwapSlot = ID_MESHSWAP2; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X | ROT_Y; g_Level.Bones[obj->boneIndex + 20 * 4] |= ROT_X | ROT_Y; @@ -589,7 +591,7 @@ namespace TEN::Entities obj->saveAnim = true; obj->saveFlags = true; obj->waterCreature = true; - obj->zoneType = ZONE_WATER; + obj->ZoneType = ZoneType::Water; g_Level.Bones[obj->boneIndex] |= ROT_Y; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_Y; @@ -612,7 +614,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveAnim = true; obj->saveFlags = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_HORSE]; @@ -642,7 +644,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->savePosition = true; obj->saveMesh = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_BABOON_NORMAL]; @@ -661,7 +663,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_BABOON_INV]; @@ -680,7 +682,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; if (Objects[ID_BABOON_NORMAL].loaded) Objects[ID_BABOON_INV].animIndex = Objects[ID_BABOON_NORMAL].animIndex; @@ -702,7 +704,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; if (Objects[ID_BABOON_NORMAL].loaded) Objects[ID_BABOON_SILENT].animIndex = Objects[ID_BABOON_NORMAL].animIndex; @@ -725,7 +727,7 @@ namespace TEN::Entities obj->saveMesh = true; obj->savePosition = true; obj->undead = true; - obj->zoneType = ZONE_WATER; + obj->ZoneType = ZoneType::Water; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y | ROT_X; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_Y | ROT_X; } @@ -737,7 +739,7 @@ namespace TEN::Entities obj->control = TEN::Entities::TR4::LocustControl; obj->drawRoutine = NULL; obj->saveFlags = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_WRAITH1]; @@ -780,7 +782,7 @@ namespace TEN::Entities obj->control = TEN::Entities::TR4::BeetleSwarmControl; obj->drawRoutine = NULL; obj->saveFlags = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_SAS_DYING]; @@ -793,7 +795,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->savePosition = true; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_SAS_DRAG_BLOKE]; @@ -805,7 +807,7 @@ namespace TEN::Entities obj->saveFlags = true; obj->savePosition = true; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_ENEMY_JEEP]; @@ -823,7 +825,7 @@ namespace TEN::Entities obj->shadowType = ShadowMode::All; obj->radius = 512; obj->HitPoints = 40; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 4 * 8] |= ROT_X; g_Level.Bones[obj->boneIndex + 4 * 9] |= ROT_X; @@ -847,7 +849,7 @@ namespace TEN::Entities obj->savePosition = true; obj->saveHitpoints = true; obj->saveMesh = true; - obj->zoneType = ZONE_HUMAN_LONGJUMP_AND_MONKEY; + obj->ZoneType = ZoneType::HumanLongJumpAndMonkey; g_Level.Bones[obj->boneIndex + 4 * 6] |= ROT_X; g_Level.Bones[obj->boneIndex + 4 * 6] |= ROT_Y; @@ -1176,7 +1178,7 @@ namespace TEN::Entities obj->saveHitpoints = true; obj->saveFlags = true; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; } obj = &Objects[ID_TEETH_SPIKES]; diff --git a/TombEngine/Objects/TR5/Entity/tr5_autoguns.cpp b/TombEngine/Objects/TR5/Entity/tr5_autoguns.cpp index c516f87c3..2a78c7c9c 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_autoguns.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_autoguns.cpp @@ -1,19 +1,20 @@ #include "framework.h" -#include "tr5_autoguns.h" -#include "Game/collision/sphere.h" -#include "Game/Lara/lara.h" +#include "Objects/TR5/Entity/tr5_autoguns.h" + #include "Game/animation.h" +#include "Game/collision/sphere.h" #include "Game/control/los.h" #include "Game/effects/effects.h" #include "Game/effects/tomb4fx.h" +#include "Game/Lara/lara.h" +#include "Game/items.h" #include "Math/Math.h" #include "Specific/level.h" #include "Sound/sound.h" -#include "Game/items.h" -using namespace TEN::Math; +using namespace TEN::Math::Random; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseAutoGuns(short itemNumber) { @@ -95,7 +96,7 @@ namespace TEN::Entities::TR5 data[1] = item->ItemFlags[1]; data[2] += item->ItemFlags[2]; - if (abs(angle1) < 1024 && abs(angle2) < 1024 && los) + if (abs(angle1) < ANGLE(5.6f) && abs(angle2) < ANGLE(5.6f) && los) { SoundEffect(SFX_TR4_HK_FIRE, &item->Pose, SoundEnvironment::Land, 0.8f); @@ -105,10 +106,9 @@ namespace TEN::Entities::TR5 TriggerDynamicLight(pos1.x, pos1.y, pos1.z, 10, (GetRandomControl() & 0x1F) + 192, (GetRandomControl() & 0x1F) + 128, 0); - if (GetRandomControl() & 3) + if (TestProbability(0.75f)) { auto pos2 = GetLaraJointPosition(GetRandomControl() % 15); - DoBloodSplat(pos2.x, pos2.y, pos2.z, (GetRandomControl() & 3) + 3, 2 * GetRandomControl(), LaraItem->RoomNumber); DoDamage(LaraItem, 20); } diff --git a/TombEngine/Objects/TR5/Entity/tr5_autoguns.h b/TombEngine/Objects/TR5/Entity/tr5_autoguns.h index d9d344551..3c37772dd 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_autoguns.h +++ b/TombEngine/Objects/TR5/Entity/tr5_autoguns.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseAutoGuns(short itemNumber); void AutoGunsControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_brownbeast.cpp b/TombEngine/Objects/TR5/Entity/tr5_brownbeast.cpp index b7c71bb9c..4570bed74 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_brownbeast.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_brownbeast.cpp @@ -14,13 +14,16 @@ #include "Specific/level.h" using namespace TEN::Math::Random; +using std::vector; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { constexpr auto BROWN_BEAST_ATTACK_DAMAGE = 150; const auto BrownBeastBite1 = BiteInfo(Vector3::Zero, 16); const auto BrownBeastBite2 = BiteInfo(Vector3::Zero, 22); + const vector BrownBeastAttackJoints1 = { 14, 15, 16, 17 }; + const vector BrownBeastAttackJoints2 = { 20, 21, 22, 23 }; // TODO enum BrownBeastState @@ -39,11 +42,7 @@ namespace TEN::Entities::TR5 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.TargetState = 1; - item->Animation.ActiveState = 1; + SetAnimation(item, 0); } void ControlBrowsBeast(short itemNumber) @@ -99,6 +98,7 @@ namespace TEN::Entities::TR5 { case 1: creature->Flags = 0; + if (creature->Mood == MoodType::Attack) { if (distance <= pow(SECTOR(1), 2)) @@ -143,7 +143,7 @@ namespace TEN::Entities::TR5 if (creature->Flags) break; - if (item->TouchBits & 0x3C000) + if (item->TestBits(JointBitType::Touch, BrownBeastAttackJoints1)) { if (item->Animation.AnimNumber == Objects[ID_BROWN_BEAST].animIndex + 8) { @@ -157,7 +157,7 @@ namespace TEN::Entities::TR5 } } - if (item->Animation.AnimNumber == Objects[ID_BROWN_BEAST].animIndex + 2) + if (item->Animation.AnimNumber == (Objects[ID_BROWN_BEAST].animIndex + 2)) { if (item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 6 && item->Animation.FrameNumber < g_Level.Anims[item->Animation.AnimNumber].frameBase + 16) @@ -170,13 +170,13 @@ namespace TEN::Entities::TR5 } } - if (!(item->TouchBits & 0xF00000)) + if (!item->TestBits(JointBitType::Touch, BrownBeastAttackJoints2)) break; - if (item->Animation.AnimNumber == Objects[ID_BROWN_BEAST].animIndex + 8) + if (item->Animation.AnimNumber == (Objects[ID_BROWN_BEAST].animIndex + 8)) { - if (item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 13 && - item->Animation.FrameNumber < g_Level.Anims[item->Animation.AnimNumber].frameBase + 20) + if (item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 13) && + item->Animation.FrameNumber < (g_Level.Anims[item->Animation.AnimNumber].frameBase + 20)) { DoDamage(creature->Enemy, BROWN_BEAST_ATTACK_DAMAGE); CreatureEffect2(item, BrownBeastBite2, 20, item->Pose.Orientation.y, DoBloodSplat); @@ -185,10 +185,10 @@ namespace TEN::Entities::TR5 } } - if (item->Animation.AnimNumber == Objects[ID_BROWN_BEAST].animIndex + 2) + if (item->Animation.AnimNumber == (Objects[ID_BROWN_BEAST].animIndex + 2)) { - if (item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 33 && - item->Animation.FrameNumber < g_Level.Anims[item->Animation.AnimNumber].frameBase + 43) + if (item->Animation.FrameNumber > (g_Level.Anims[item->Animation.AnimNumber].frameBase + 33) && + item->Animation.FrameNumber < (g_Level.Anims[item->Animation.AnimNumber].frameBase + 43)) { DoDamage(creature->Enemy, BROWN_BEAST_ATTACK_DAMAGE); CreatureEffect2(item, BrownBeastBite2, 20, item->Pose.Orientation.y, DoBloodSplat); diff --git a/TombEngine/Objects/TR5/Entity/tr5_brownbeast.h b/TombEngine/Objects/TR5/Entity/tr5_brownbeast.h index aad8f18a9..fa5cab857 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_brownbeast.h +++ b/TombEngine/Objects/TR5/Entity/tr5_brownbeast.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseBrownBeast(short itemNumber); void ControlBrowsBeast(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_chef.cpp b/TombEngine/Objects/TR5/Entity/tr5_chef.cpp index d61157779..2085c9a1f 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_chef.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_chef.cpp @@ -1,18 +1,19 @@ #include "framework.h" -#include "tr5_chef.h" +#include "Objects/TR5/Entity/tr5_chef.h" + #include "Game/items.h" #include "Game/control/box.h" #include "Game/effects/effects.h" #include "Game/effects/tomb4fx.h" -#include "Game/people.h" -#include "Specific/setup.h" -#include "Specific/level.h" +#include "Game/itemdata/creature_info.h" #include "Game/Lara/lara.h" #include "Game/misc.h" +#include "Game/people.h" #include "Sound/sound.h" -#include "Game/itemdata/creature_info.h" +#include "Specific/level.h" +#include "Specific/setup.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { const auto ChefBite = BiteInfo(Vector3(0.0f, 200.0f, 0.0f), 13); diff --git a/TombEngine/Objects/TR5/Entity/tr5_chef.h b/TombEngine/Objects/TR5/Entity/tr5_chef.h index 46b2aaaf3..da801ab5d 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_chef.h +++ b/TombEngine/Objects/TR5/Entity/tr5_chef.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseChef(short itemNumber); void ControlChef(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_cyborg.cpp b/TombEngine/Objects/TR5/Entity/tr5_cyborg.cpp index 2f6da2087..c12a9e779 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_cyborg.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_cyborg.cpp @@ -19,7 +19,7 @@ using namespace TEN::Effects::Lara; using namespace TEN::Effects::Lightning; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { const auto CyborgGunBite = BiteInfo(Vector3(0.0f, 300.0f, 64.0f), 7); byte HitmanJoints[12] = { 15, 14, 13, 6, 5, 12, 7, 4, 10, 11, 19 }; @@ -124,11 +124,7 @@ namespace TEN::Entities::TR5 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 4; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.TargetState = CYBORG_STATE_IDLE; - item->Animation.ActiveState = CYBORG_STATE_IDLE; + SetAnimation(item, CYBORG_ANIM_IDLE); } static void TriggerHitmanSparks(int x, int y, int z, short xv, short yv, short zv) @@ -174,13 +170,13 @@ namespace TEN::Entities::TR5 if (CreatureActive(itemNumber)) { auto* item = &g_Level.Items[itemNumber]; - auto* creature = GetCreatureInfo(item); auto* object = &Objects[item->ObjectNumber]; + auto* creature = GetCreatureInfo(item); short angle = 0; - short joint2 = 0; - short joint1 = 0; short joint0 = 0; + short joint1 = 0; + short joint2 = 0; int x = item->Pose.Position.x; int z = item->Pose.Position.z; diff --git a/TombEngine/Objects/TR5/Entity/tr5_cyborg.h b/TombEngine/Objects/TR5/Entity/tr5_cyborg.h index b81f7a942..80ec07d97 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_cyborg.h +++ b/TombEngine/Objects/TR5/Entity/tr5_cyborg.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseCyborg(short itemNumber); void CyborgControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_doberman.cpp b/TombEngine/Objects/TR5/Entity/tr5_doberman.cpp index 9447b3418..9e9364639 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_doberman.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_doberman.cpp @@ -1,16 +1,19 @@ #include "framework.h" -#include "tr5_doberman.h" -#include "Game/control/box.h" -#include "Game/effects/effects.h" -#include "Specific/setup.h" -#include "Specific/level.h" -#include "Game/Lara/lara.h" -#include "Game/itemdata/creature_info.h" -#include "Game/control/control.h" -#include "Game/items.h" -#include "Game/misc.h" +#include "Objects/TR5/Entity/tr5_doberman.h" -namespace TEN::Entities::TR5 +#include "Game/control/box.h" +#include "Game/control/control.h" +#include "Game/effects/effects.h" +#include "Game/itemdata/creature_info.h" +#include "Game/items.h" +#include "Game/Lara/lara.h" +#include "Game/misc.h" +#include "Specific/level.h" +#include "Specific/setup.h" + +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR5 { const auto DobermanBite = BiteInfo(Vector3(0.0f, 30.0f, 141.0f), 20); @@ -75,196 +78,198 @@ namespace TEN::Entities::TR5 void DobermanControl(short itemNumber) { - if (CreatureActive(itemNumber)) + auto* item = &g_Level.Items[itemNumber]; + auto* creature = GetCreatureInfo(item); + + if (!CreatureActive(itemNumber)) + return; + + short angle = 0; + short tilt = 0; + short joint = 0; + + if (item->HitPoints > 0) { - short angle = 0; - short tilt = 0; - short joint = 0; + AI_INFO AI; + CreatureAIInfo(item, &AI); - auto* item = &g_Level.Items[itemNumber]; - auto* creature = GetCreatureInfo(item); + if (AI.ahead) + joint = AI.angle; - if (item->HitPoints > 0) + GetCreatureMood(item, &AI, false); + CreatureMood(item, &AI, false); + + angle = CreatureTurn(item, creature->MaxTurn); + + switch (item->Animation.ActiveState) { - AI_INFO AI; - CreatureAIInfo(item, &AI); + case DOBERMAN_STATE_WALK_FORWARD: + creature->MaxTurn = ANGLE(3.0f); - if (AI.ahead) - joint = AI.angle; - - GetCreatureMood(item, &AI, false); - CreatureMood(item, &AI, false); - - angle = CreatureTurn(item, creature->MaxTurn); - - switch (item->Animation.ActiveState) + if (creature->Mood != MoodType::Bored) + item->Animation.TargetState = DOBERMAN_STATE_RUN_FORWARD; + else { - case DOBERMAN_STATE_WALK_FORWARD: - creature->MaxTurn = ANGLE(3.0f); - - if (creature->Mood != MoodType::Bored) - item->Animation.TargetState = DOBERMAN_STATE_RUN_FORWARD; - else - { - int random = GetRandomControl(); - if (random < 768) - { - item->Animation.RequiredState = DOBERMAN_STATE_STAND_LOW_BITE_ATTACK; - item->Animation.TargetState = DOBERMAN_STATE_STOP; - break; - } - if (random < 1536) - { - item->Animation.RequiredState = DOBERMAN_STATE_SIT_IDLE; - item->Animation.TargetState = DOBERMAN_STATE_STOP; - break; - } - if (random < 2816) - { - item->Animation.TargetState = DOBERMAN_STATE_STOP; - break; - } - } - - break; - - case DOBERMAN_STATE_RUN_FORWARD: - tilt = angle; - creature->MaxTurn = ANGLE(6.0f); - - if (creature->Mood == MoodType::Bored) + if (TestProbability(0.025f)) { + item->Animation.RequiredState = DOBERMAN_STATE_STAND_LOW_BITE_ATTACK; item->Animation.TargetState = DOBERMAN_STATE_STOP; break; } - if (AI.distance < pow(768, 2)) - item->Animation.TargetState = DOBERMAN_STATE_JUMP_BITE_ATTACK; - - break; - - case DOBERMAN_STATE_STOP: - creature->MaxTurn = 0; - creature->Flags = 0; - if (creature->Mood != MoodType::Bored) + if (TestProbability(0.045f)) { - if (creature->Mood != MoodType::Escape && - AI.distance < pow(341, 2) && - AI.ahead) - { - item->Animation.TargetState = DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK; - } - else - item->Animation.TargetState = DOBERMAN_STATE_RUN_FORWARD; - } - else - { - if (item->Animation.RequiredState) - item->Animation.TargetState = item->Animation.RequiredState; - else - { - int random = GetRandomControl(); - if (random >= 768) - { - if (random >= 1536) - { - if (random < 9728) - item->Animation.TargetState = DOBERMAN_STATE_WALK_FORWARD; - } - else - item->Animation.TargetState = DOBERMAN_STATE_SIT_IDLE; - } - else - item->Animation.TargetState = DOBERMAN_STATE_STAND_LOW_BITE_ATTACK; - } - } - break; - - case DOBERMAN_STATE_STAND_LOW_BITE_ATTACK: - if (creature->Mood != MoodType::Bored || GetRandomControl() < 1280) + item->Animation.RequiredState = DOBERMAN_STATE_SIT_IDLE; item->Animation.TargetState = DOBERMAN_STATE_STOP; + break; + } - break; - - case DOBERMAN_STATE_SIT_IDLE: - if (creature->Mood != MoodType::Bored || GetRandomControl() < 256) + if (TestProbability(0.085f)) + { item->Animation.TargetState = DOBERMAN_STATE_STOP; - - break; - - case DOBERMAN_STATE_STAND_IDLE: - if (creature->Mood != MoodType::Bored || GetRandomControl() < 512) - item->Animation.TargetState = DOBERMAN_STATE_STOP; - - break; - - case DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK: - creature->MaxTurn = ANGLE(0.5f); - - if (creature->Flags != 1 && - AI.ahead && - item->TouchBits & 0x122000) - { - DoDamage(creature->Enemy, 30); - CreatureEffect(item, DobermanBite, DoBloodSplat); - creature->Flags = 1; + break; } + } - if (AI.distance <= pow(341, 2) || AI.distance >= pow(682, 2)) - item->Animation.TargetState = DOBERMAN_STATE_STOP; - else - item->Animation.TargetState = DOBERMAN_STATE_LEAP_BITE_ATTACK; + break; - break; + case DOBERMAN_STATE_RUN_FORWARD: + creature->MaxTurn = ANGLE(6.0f); + tilt = angle; - case DOBERMAN_STATE_JUMP_BITE_ATTACK: - if (creature->Flags != 2 && item->TouchBits & 0x122000) - { - DoDamage(creature->Enemy, 80); - CreatureEffect(item, DobermanBite, DoBloodSplat); - creature->Flags = 2; - } - - if (AI.distance >= pow(341, 2)) - { - if (AI.distance < pow(682, 2)) - item->Animation.TargetState = DOBERMAN_STATE_LEAP_BITE_ATTACK; - } - else - item->Animation.TargetState = DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK; - - break; - - case DOBERMAN_STATE_LEAP_BITE_ATTACK: - creature->MaxTurn = ANGLE(6.0f); - - if (creature->Flags != 3 && item->TouchBits & 0x122000) - { - DoDamage(creature->Enemy, 50); - CreatureEffect(item, DobermanBite, DoBloodSplat); - creature->Flags = 3; - } - if (AI.distance < pow(341, 2)) - item->Animation.TargetState = DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK; - - break; - - default: + if (creature->Mood == MoodType::Bored) + { + item->Animation.TargetState = DOBERMAN_STATE_STOP; break; } - } - else if (item->Animation.ActiveState != DOBERMAN_STATE_DEATH) - { - item->Animation.AnimNumber = Objects[ID_DOBERMAN].animIndex + DOBERMAN_ANIM_DEATH; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = DOBERMAN_STATE_DEATH; - } - CreatureTilt(item, tilt); - CreatureJoint(item, 0, 0); - CreatureJoint(item, 1, joint); - CreatureJoint(item, 2, 0); - CreatureAnimation(itemNumber, angle, tilt); + if (AI.distance < pow(768, 2)) + item->Animation.TargetState = DOBERMAN_STATE_JUMP_BITE_ATTACK; + + break; + + case DOBERMAN_STATE_STOP: + creature->MaxTurn = 0; + creature->Flags = 0; + + if (creature->Mood != MoodType::Bored) + { + if (creature->Mood != MoodType::Escape && + AI.distance < pow(341, 2) && + AI.ahead) + { + item->Animation.TargetState = DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK; + } + else + item->Animation.TargetState = DOBERMAN_STATE_RUN_FORWARD; + } + else + { + if (item->Animation.RequiredState) + item->Animation.TargetState = item->Animation.RequiredState; + else + { + if (TestProbability(0.975f)) + { + if (TestProbability(0.95f)) + { + if (TestProbability(0.3f)) + item->Animation.TargetState = DOBERMAN_STATE_WALK_FORWARD; + } + else + item->Animation.TargetState = DOBERMAN_STATE_SIT_IDLE; + } + else + item->Animation.TargetState = DOBERMAN_STATE_STAND_LOW_BITE_ATTACK; + } + } + + break; + + case DOBERMAN_STATE_STAND_LOW_BITE_ATTACK: + if (creature->Mood != MoodType::Bored || TestProbability(0.04f)) + item->Animation.TargetState = DOBERMAN_STATE_STOP; + + break; + + case DOBERMAN_STATE_SIT_IDLE: + if (creature->Mood != MoodType::Bored || TestProbability(1.0f / 128)) + item->Animation.TargetState = DOBERMAN_STATE_STOP; + + break; + + case DOBERMAN_STATE_STAND_IDLE: + if (creature->Mood != MoodType::Bored || TestProbability(1.0f / 64)) + item->Animation.TargetState = DOBERMAN_STATE_STOP; + + break; + + case DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK: + creature->MaxTurn = ANGLE(0.5f); + + if (creature->Flags != 1 && AI.ahead && + item->TouchBits & 0x122000) + { + DoDamage(creature->Enemy, 30); + CreatureEffect(item, DobermanBite, DoBloodSplat); + creature->Flags = 1; + } + + if (AI.distance <= pow(341, 2) || AI.distance >= pow(682, 2)) + item->Animation.TargetState = DOBERMAN_STATE_STOP; + else + item->Animation.TargetState = DOBERMAN_STATE_LEAP_BITE_ATTACK; + + break; + + case DOBERMAN_STATE_JUMP_BITE_ATTACK: + if (creature->Flags != 2 && item->TouchBits & 0x122000) + { + DoDamage(creature->Enemy, 80); + CreatureEffect(item, DobermanBite, DoBloodSplat); + creature->Flags = 2; + } + + if (AI.distance >= pow(341, 2)) + { + if (AI.distance < pow(682, 2)) + item->Animation.TargetState = DOBERMAN_STATE_LEAP_BITE_ATTACK; + } + else + item->Animation.TargetState = DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK; + + break; + + case DOBERMAN_STATE_LEAP_BITE_ATTACK: + creature->MaxTurn = ANGLE(6.0f); + + if (creature->Flags != 3 && item->TouchBits & 0x122000) + { + DoDamage(creature->Enemy, 50); + CreatureEffect(item, DobermanBite, DoBloodSplat); + creature->Flags = 3; + } + + if (AI.distance < pow(341, 2)) + item->Animation.TargetState = DOBERMAN_STATE_STAND_HIGH_BITE_ATTACK; + + break; + + default: + break; + } } + else if (item->Animation.ActiveState != DOBERMAN_STATE_DEATH) + { + item->Animation.AnimNumber = Objects[ID_DOBERMAN].animIndex + DOBERMAN_ANIM_DEATH; + item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; + item->Animation.ActiveState = DOBERMAN_STATE_DEATH; + } + + CreatureTilt(item, tilt); + CreatureJoint(item, 0, 0); + CreatureJoint(item, 1, joint); + CreatureJoint(item, 2, 0); + CreatureAnimation(itemNumber, angle, tilt); } } diff --git a/TombEngine/Objects/TR5/Entity/tr5_doberman.h b/TombEngine/Objects/TR5/Entity/tr5_doberman.h index 2edd5c50b..bba3b5fb1 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_doberman.h +++ b/TombEngine/Objects/TR5/Entity/tr5_doberman.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseDoberman(short itemNumber); void DobermanControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_dog.cpp b/TombEngine/Objects/TR5/Entity/tr5_dog.cpp index 6fa38a571..dec3abace 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_dog.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_dog.cpp @@ -11,7 +11,7 @@ #include "Game/items.h" #include "Game/misc.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { const auto DogBite = BiteInfo(Vector3(0.0f, 0.0f, 100.0f), 3); static BYTE DogAnims[] = { 20, 21, 22, 20 }; diff --git a/TombEngine/Objects/TR5/Entity/tr5_dog.h b/TombEngine/Objects/TR5/Entity/tr5_dog.h index 3021da3b5..82e278d2c 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_dog.h +++ b/TombEngine/Objects/TR5/Entity/tr5_dog.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseTr5Dog(short itemNumber); void Tr5DogControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_ghost.cpp b/TombEngine/Objects/TR5/Entity/tr5_ghost.cpp index af812e63f..52b543a91 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_ghost.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_ghost.cpp @@ -10,7 +10,7 @@ #include "Sound/sound.h" #include "Game/itemdata/creature_info.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { const auto InvisibleGhostBite = BiteInfo(Vector3::Zero, 17); diff --git a/TombEngine/Objects/TR5/Entity/tr5_ghost.h b/TombEngine/Objects/TR5/Entity/tr5_ghost.h index 40ef99ba3..62ccb4596 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_ghost.h +++ b/TombEngine/Objects/TR5/Entity/tr5_ghost.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseInvisibleGhost(short itemNumber); void InvisibleGhostControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_gladiator.cpp b/TombEngine/Objects/TR5/Entity/tr5_gladiator.cpp index d726be0dc..00767d698 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_gladiator.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_gladiator.cpp @@ -18,14 +18,14 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { constexpr auto GLADIATOR_ATTACK_DAMAGE = 120; // TODO: Ranges. - const vector GladiatorAttackJoints = { 13, 14 }; const auto GladiatorBite = BiteInfo(Vector3::Zero, 16); + const vector GladiatorAttackJoints = { 13, 14 }; enum GladiatorState { @@ -88,8 +88,8 @@ namespace TEN::Entities::TR5 auto* item = &g_Level.Items[itemNumber]; auto* creature = GetCreatureInfo(item); - short tilt = 0; short angle = 0; + short tilt = 0; short joint0 = 0; short joint1 = 0; short joint2 = 0; @@ -99,11 +99,7 @@ namespace TEN::Entities::TR5 item->HitPoints = 0; if (item->Animation.ActiveState != GLADIATOR_STATE_DEATH) - { - item->Animation.AnimNumber = Objects[ID_GLADIATOR].animIndex + GLADIATOR_ANIM_DEATH; - item->Animation.ActiveState = GLADIATOR_STATE_DEATH; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - } + SetAnimation(item, GLADIATOR_ANIM_DEATH); } else { @@ -116,21 +112,21 @@ namespace TEN::Entities::TR5 CreatureAIInfo(item, &AI); int unknown = true; - short rot; + short deltaAngle; int distance; if (creature->Enemy == LaraItem) { distance = AI.distance; - rot = AI.angle; + deltaAngle = AI.angle; } else { int dx = LaraItem->Pose.Position.x - item->Pose.Position.x; int dz = LaraItem->Pose.Position.z - item->Pose.Position.z; - rot = phd_atan(dz, dx) - item->Pose.Orientation.y; - if (rot <= -ANGLE(90.0f) || rot >= ANGLE(90.0f)) + deltaAngle = phd_atan(dz, dx) - item->Pose.Orientation.y; + if (deltaAngle <= -ANGLE(90.0f) || deltaAngle >= ANGLE(90.0f)) unknown = false; distance = pow(dx, 2) + pow(dz, 2); @@ -151,12 +147,12 @@ namespace TEN::Entities::TR5 switch (item->Animation.ActiveState) { case GLADIATOR_STATE_IDLE: - joint2 = rot; + joint2 = deltaAngle; creature->MaxTurn = (-(int)(creature->Mood != MoodType::Bored)) & 0x16C; creature->Flags = 0; if (item->AIBits & GUARD || - !(GetRandomControl() & 0x1F) && + TestProbability(1.0f / 30) && (AI.distance > pow(SECTOR(1), 2) || creature->Mood != MoodType::Attack)) { joint2 = AIGuard(creature); @@ -169,8 +165,7 @@ namespace TEN::Entities::TR5 { if (creature->Mood == MoodType::Escape) { - if (Lara.TargetEntity != item && - AI.ahead && !item->HitStatus) + if (Lara.TargetEntity != item && AI.ahead && !item->HitStatus) { item->Animation.TargetState = GLADIATOR_STATE_IDLE; break; @@ -179,13 +174,11 @@ namespace TEN::Entities::TR5 else { if (creature->Mood == MoodType::Bored || - item->AIBits & FOLLOW && - (creature->ReachedGoal || - distance > pow(SECTOR(2), 2))) + (item->AIBits & FOLLOW && (creature->ReachedGoal || distance > pow(SECTOR(2), 2)))) { if (item->Animation.RequiredState) item->Animation.TargetState = item->Animation.RequiredState; - else if (!(GetRandomControl() & 0x3F)) + else if (TestProbability(1.0f / 64)) item->Animation.TargetState = GLADIATOR_STATE_IDLE; break; @@ -194,7 +187,7 @@ namespace TEN::Entities::TR5 if (Lara.TargetEntity == item && unknown && distance < pow(SECTOR(1.5f), 2) && TestProbability(0.5f) && - (Lara.Control.Weapon.GunType == LaraWeaponType::Shotgun || !(GetRandomControl() & 0xF)) && + (Lara.Control.Weapon.GunType == LaraWeaponType::Shotgun || TestProbability(0.06f)) && item->MeshBits == -1) { item->Animation.TargetState = GLADIATOR_STATE_GUARD_START; @@ -218,7 +211,7 @@ namespace TEN::Entities::TR5 break; case GLADIATOR_STATE_WALK_FORWARD: - joint2 = rot; + joint2 = deltaAngle; creature->MaxTurn = creature->Mood != MoodType::Bored ? ANGLE(7.0f) : ANGLE(2.0f); creature->Flags = 0; @@ -242,7 +235,7 @@ namespace TEN::Entities::TR5 else if (!AI.ahead || AI.distance > pow(SECTOR(1.5f), 2)) item->Animation.TargetState = GLADIATOR_STATE_RUN_FORWARD; } - else if (!(GetRandomControl() & 0x3F)) + else if (TestProbability(1.0f / 64)) { item->Animation.TargetState = GLADIATOR_STATE_IDLE; break; @@ -308,8 +301,7 @@ namespace TEN::Entities::TR5 break; } } - else if (Lara.TargetEntity != item || - !(GetRandomControl() & 0x7F)) + else if (Lara.TargetEntity != item || TestProbability(1.0f / 128)) { item->Animation.TargetState = GLADIATOR_STATE_IDLE; break; diff --git a/TombEngine/Objects/TR5/Entity/tr5_gladiator.h b/TombEngine/Objects/TR5/Entity/tr5_gladiator.h index a28b30371..752637ef9 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_gladiator.h +++ b/TombEngine/Objects/TR5/Entity/tr5_gladiator.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseGladiator(short itemNumber); void ControlGladiator(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_guard.cpp b/TombEngine/Objects/TR5/Entity/tr5_guard.cpp index d6fadcd91..a54a7e0a4 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_guard.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_guard.cpp @@ -1,21 +1,24 @@ #include "framework.h" -#include "tr5_guard.h" -#include "Game/items.h" +#include "Objects/TR5/Entity/tr5_guard.h" + +#include "Game/animation.h" #include "Game/collision/collide_room.h" #include "Game/control/box.h" -#include "Game/people.h" +#include "Game/control/los.h" #include "Game/effects/effects.h" #include "Game/effects/tomb4fx.h" -#include "Game/control/los.h" -#include "Specific/setup.h" -#include "Game/animation.h" -#include "Specific/level.h" +#include "Game/itemdata/creature_info.h" +#include "Game/items.h" #include "Game/Lara/lara.h" #include "Game/misc.h" +#include "Game/people.h" #include "Sound/sound.h" -#include "Game/itemdata/creature_info.h" +#include "Specific/level.h" +#include "Specific/setup.h" -namespace TEN::Entities::TR5 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR5 { const auto SwatGunBite = BiteInfo(Vector3(80.0f, 200.0f, 13.0f), 0); const auto SniperGunBite = BiteInfo(Vector3(0.0f, 480.0f, 110.0f), 13); @@ -352,7 +355,7 @@ namespace TEN::Entities::TR5 if (item->ObjectNumber == ID_SWAT_PLUS) { item->ItemFlags[0]++; - if (item->ItemFlags[0] > 60 && !(GetRandomControl() & 0xF)) + if (item->ItemFlags[0] > 60 && TestProbability(0.06f)) { SoundEffect(SFX_TR5_BIO_BREATHE_OUT, &item->Pose); item->ItemFlags[0] = 0; @@ -837,7 +840,7 @@ namespace TEN::Entities::TR5 case GUARD_STATE_USE_COMPUTER: if ((item->ObjectNumber != ID_SCIENTIST || item != Lara.TargetEntity) && - (GetRandomControl() & 0x7F || item->TriggerFlags >= 10 || item->TriggerFlags == 9)) + (TestProbability(0.992f) || item->TriggerFlags >= 10 || item->TriggerFlags == 9)) { if (item->AIBits & GUARD) { @@ -857,7 +860,7 @@ namespace TEN::Entities::TR5 break; case GUARD_STATE_SURRENDER: - if (item != Lara.TargetEntity && !(GetRandomControl() & 0x3F)) + if (item != Lara.TargetEntity && TestProbability(1.0f / 64)) { if (item->TriggerFlags == 7 || item->TriggerFlags == 9) item->Animation.RequiredState = GUARD_STATE_USE_COMPUTER; @@ -1040,11 +1043,11 @@ namespace TEN::Entities::TR5 creature->Flags = 0; if (!TargetVisible(item, &AI) || item->HitStatus && - GetRandomControl() & 1) + TestProbability(0.5f)) { item->Animation.TargetState = SNIPER_STATE_COVER; } - else if (!(GetRandomControl() & 0x1F)) + else if (TestProbability(1.0f / 30)) item->Animation.TargetState = SNIPER_STATE_FIRE; break; diff --git a/TombEngine/Objects/TR5/Entity/tr5_guard.h b/TombEngine/Objects/TR5/Entity/tr5_guard.h index 847958397..68aa3e723 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_guard.h +++ b/TombEngine/Objects/TR5/Entity/tr5_guard.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseGuard(short itemNumber); void GuardControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_gunship.cpp b/TombEngine/Objects/TR5/Entity/tr5_gunship.cpp index 8c0c69c6b..ce955c7ba 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_gunship.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_gunship.cpp @@ -12,7 +12,7 @@ #include "Game/items.h" #include "Game/Lara/lara.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { int GunShipCounter = 0; diff --git a/TombEngine/Objects/TR5/Entity/tr5_gunship.h b/TombEngine/Objects/TR5/Entity/tr5_gunship.h index 60ba90808..9f862512a 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_gunship.h +++ b/TombEngine/Objects/TR5/Entity/tr5_gunship.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void ControlGunShip(short itemNumber); } diff --git a/TombEngine/Objects/TR5/Entity/tr5_hydra.cpp b/TombEngine/Objects/TR5/Entity/tr5_hydra.cpp index 1e97e23a7..bc76abe5f 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_hydra.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_hydra.cpp @@ -1,23 +1,23 @@ #include "framework.h" -#include "tr5_hydra.h" +#include "Objects/TR5/Entity/tr5_hydra.h" -#include "Game/items.h" +#include "Game/Lara/lara.h" +#include "Game/animation.h" #include "Game/collision/collide_room.h" #include "Game/control/box.h" #include "Game/effects/debris.h" #include "Game/effects/effects.h" -#include "Specific/setup.h" -#include "Game/animation.h" -#include "Specific/level.h" -#include "Game/Lara/lara.h" +#include "Game/itemdata/creature_info.h" +#include "Game/items.h" #include "Game/misc.h" #include "Math/Math.h" #include "Sound/sound.h" -#include "Game/itemdata/creature_info.h" +#include "Specific/level.h" +#include "Specific/setup.h" -using namespace TEN::Math; +using namespace TEN::Math::Random; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { const auto HydraBite = BiteInfo(Vector3::Zero, 11); @@ -106,7 +106,7 @@ namespace TEN::Entities::TR5 spark->flags = SP_EXPDEF | SP_ROTATE | SP_DEF | SP_SCALE; spark->rotAng = GetRandomControl() & 0xFFF; - if (GetRandomControl() & 1) + if (TestProbability(0.5f)) spark->rotAdd = -32 - (GetRandomControl() & 0x1F); else spark->rotAdd = (GetRandomControl() & 0x1F) + 32; @@ -230,11 +230,11 @@ namespace TEN::Entities::TR5 else if (item->TriggerFlags == 2) tilt = ANGLE(2.8f); - if (AI.distance >= pow(CLICK(7), 2) && GetRandomControl() & 0x1F) + if (AI.distance >= pow(CLICK(7), 2) && TestProbability(0.97f)) { - if (AI.distance >= pow(SECTOR(2), 2) && GetRandomControl() & 0x1F) + if (AI.distance >= pow(SECTOR(2), 2) && TestProbability(0.97f)) { - if (!(GetRandomControl() & 0xF)) + if (TestProbability(0.06f)) item->Animation.TargetState = HYDRA_STATE_AIM; } else @@ -293,7 +293,8 @@ namespace TEN::Entities::TR5 if (Lara.Control.Weapon.GunType == LaraWeaponType::Shotgun) damage *= 3; - if ((GetRandomControl() & 0xF) < damage && AI.distance < SQUARE(10240) && damage > 0) + if ((GetRandomControl() & 0xF) < damage && + AI.distance < SQUARE(SECTOR(10)) && damage > 0) { item->Animation.TargetState = 4; DoDamage(item, damage); diff --git a/TombEngine/Objects/TR5/Entity/tr5_hydra.h b/TombEngine/Objects/TR5/Entity/tr5_hydra.h index ed04619a8..f4814a079 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_hydra.h +++ b/TombEngine/Objects/TR5/Entity/tr5_hydra.h @@ -1,7 +1,7 @@ #pragma once #include "Math/Math.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseHydra(short itemNumber); void HydraControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_imp.cpp b/TombEngine/Objects/TR5/Entity/tr5_imp.cpp index cdb0da7b1..6a5aab733 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_imp.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_imp.cpp @@ -16,7 +16,7 @@ using namespace TEN::Entities::Generic; using namespace TEN::Math; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { const auto ImpBite = BiteInfo(Vector3(0.0f, 100.0f, 0.0f), 9); diff --git a/TombEngine/Objects/TR5/Entity/tr5_imp.h b/TombEngine/Objects/TR5/Entity/tr5_imp.h index f32d76ab6..2b3f5882e 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_imp.h +++ b/TombEngine/Objects/TR5/Entity/tr5_imp.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseImp(short itemNumber); void ImpControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.cpp b/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.cpp index 1cea7a9f8..e73250c6f 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.cpp @@ -1,19 +1,25 @@ #include "framework.h" -#include "tr5_lagoon_witch.h" -#include "Game/items.h" +#include "Objects/TR5/Entity/tr5_lagoon_witch.h" + #include "Game/control/box.h" #include "Game/effects/effects.h" #include "Game/effects/tomb4fx.h" #include "Game/gui.h" -#include "Specific/setup.h" -#include "Specific/level.h" -#include "Game/Lara/lara.h" #include "Game/itemdata/creature_info.h" +#include "Game/items.h" +#include "Game/Lara/lara.h" #include "Game/misc.h" +#include "Specific/level.h" +#include "Specific/setup.h" -namespace TEN::Entities::TR5 +using std::vector; + +namespace TEN::Entities::Creatures::TR5 { + constexpr auto LAGOON_WITCH_ATTACK_DAMAGE = 100; + const auto LagoonWitchBite = BiteInfo(Vector3::Zero, 7); + const vector LagoonWitchAttackJoints = { 6, 7, 8, 9, 14, 15, 16, 17 }; enum LagoonWitchState { @@ -34,11 +40,7 @@ namespace TEN::Entities::TR5 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 1; - item->Animation.TargetState = WITCH_STATE_IDLE; - item->Animation.ActiveState = WITCH_STATE_IDLE; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; + SetAnimation(item, 1); item->Pose.Position.y += CLICK(2); } @@ -53,17 +55,17 @@ namespace TEN::Entities::TR5 short joint2 = 0; auto* item = &g_Level.Items[itemNumber]; - auto* creature = GetCreatureInfo(item); auto* object = &Objects[item->ObjectNumber]; + auto* creature = GetCreatureInfo(item); if (item->HitPoints <= 0) { if (item->Animation.ActiveState != WITCH_STATE_DEATH) { - item->HitPoints = 0; item->Animation.ActiveState = WITCH_STATE_DEATH; item->Animation.AnimNumber = object->animIndex + WITCH_ANIM_DEATH; item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; + item->HitPoints = 0; } } else @@ -126,10 +128,10 @@ namespace TEN::Entities::TR5 creature->MaxTurn = ANGLE(2.0f); if (!creature->Flags && - item->TouchBits & 0x3C3C0 && + item->TestBits(JointBitType::Touch, LagoonWitchAttackJoints) && item->Animation.FrameNumber > g_Level.Anims[item->Animation.AnimNumber].frameBase + 29) { - DoDamage(creature->Enemy, 100); + DoDamage(creature->Enemy, LAGOON_WITCH_ATTACK_DAMAGE); CreatureEffect2(item, LagoonWitchBite, 10, item->Pose.Orientation.y, DoBloodSplat); creature->Flags = WITCH_STATE_SWIM; } @@ -148,7 +150,7 @@ namespace TEN::Entities::TR5 item->ItemFlags[3]++; creature->ReachedGoal = false; - creature->Enemy = 0; + creature->Enemy = nullptr; } } } diff --git a/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.h b/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.h index f4808d67e..b43431ba4 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.h +++ b/TombEngine/Objects/TR5/Entity/tr5_lagoon_witch.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseLagoonWitch(short itemNumber); void LagoonWitchControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_larson.cpp b/TombEngine/Objects/TR5/Entity/tr5_larson.cpp index ed6527209..97319ffab 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_larson.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_larson.cpp @@ -1,45 +1,45 @@ #include "framework.h" -#include "tr5_larson.h" -#include "Game/items.h" -#include "Game/control/box.h" -#include "Game/effects/effects.h" -#include "Game/people.h" -#include "Game/Lara/lara.h" -#include "Specific/setup.h" -#include "Specific/level.h" -#include "Game/itemdata/creature_info.h" -#include "Game/control/control.h" +#include "Objects/TR5/Entity/tr5_larson.h" + #include "Game/animation.h" +#include "Game/control/box.h" +#include "Game/control/control.h" +#include "Game/effects/effects.h" +#include "Game/itemdata/creature_info.h" +#include "Game/items.h" +#include "Game/Lara/lara.h" +#include "Game/misc.h" +#include "Game/people.h" +#include "Specific/level.h" +#include "Specific/setup.h" -namespace TEN::Entities::TR5 +using namespace TEN::Math::Random; + +namespace TEN::Entities::Creatures::TR5 { -#define STATE_TR5_LARSON_STOP 1 -#define STATE_TR5_LARSON_WALK 2 -#define STATE_TR5_LARSON_RUN 3 -#define STATE_TR5_LARSON_AIM 4 -#define STATE_TR5_LARSON_DIE 5 -#define STATE_TR5_LARSON_IDLE 6 -#define STATE_TR5_LARSON_ATTACK 7 + #define STATE_TR5_LARSON_STOP 1 + #define STATE_TR5_LARSON_WALK 2 + #define STATE_TR5_LARSON_RUN 3 + #define STATE_TR5_LARSON_AIM 4 + #define STATE_TR5_LARSON_DIE 5 + #define STATE_TR5_LARSON_IDLE 6 + #define STATE_TR5_LARSON_ATTACK 7 -#define ANIMATION_TR5_PIERRE_DIE 12 -#define ANIMATION_TR5_LARSON_DIE 15 + #define ANIMATION_TR5_PIERRE_DIE 12 + #define ANIMATION_TR5_LARSON_DIE 15 -#define TR5_LARSON_MIN_HP 40 + #define TR5_LARSON_MIN_HP 40 - const auto LarsonGun = BiteInfo(Vector3(-55, 200, 5), 14); - const auto PierreGun1 = BiteInfo(Vector3(60, 200, 0), 11); - const auto PierreGun2 = BiteInfo(Vector3(-57, 200, 0), 14); + const auto LarsonGun = BiteInfo(Vector3(-55.0f, 200.0f, 5.0f), 14); + const auto PierreGun1 = BiteInfo(Vector3(60.0f, 200.0f, 0.0f), 11); + const auto PierreGun2 = BiteInfo(Vector3(-57.0f, 200.0f, 0.0f), 14); - void InitialiseLarson(short itemNum) + void InitialiseLarson(short itemNumber) { - ItemInfo* item = &g_Level.Items[itemNum]; + auto* item = &g_Level.Items[itemNumber]; - ClearItem(itemNum); - - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.TargetState = STATE_TR5_LARSON_STOP; - item->Animation.ActiveState = STATE_TR5_LARSON_STOP; + ClearItem(itemNumber); + SetAnimation(item, 0); if (!item->TriggerFlags) return; @@ -47,22 +47,14 @@ namespace TEN::Entities::TR5 item->ItemFlags[3] = item->TriggerFlags; short rotY = item->Pose.Orientation.y; - if (rotY > ANGLE(22.5f) && rotY < 28672) - { + if (rotY > ANGLE(22.5f) && rotY < ANGLE(157.5f)) item->Pose.Position.x += STEPUP_HEIGHT; - } - else if (rotY < -ANGLE(22.5f) && rotY > -28672) - { + else if (rotY < ANGLE(-22.5f) && rotY > ANGLE(-157.5f)) item->Pose.Position.x -= STEPUP_HEIGHT; - } - else if (rotY < -20480 || rotY > 20480) - { + else if (rotY < ANGLE(-112.5f) || rotY > ANGLE(112.5f)) item->Pose.Position.z -= STEPUP_HEIGHT; - } - else if (rotY > -8192 || rotY < 8192) - { + else if (rotY > ANGLE(-45.0f) || rotY < ANGLE(45.0f)) item->Pose.Position.z += STEPUP_HEIGHT; - } } void LarsonControl(short itemNumber) @@ -70,23 +62,23 @@ namespace TEN::Entities::TR5 if (!CreatureActive(itemNumber)) return; - short tilt = 0; + auto* item = &g_Level.Items[itemNumber]; + auto* creature = GetCreatureInfo(item); + short angle = 0; + short tilt = 0; short joint0 = 0; short joint1 = 0; short joint2 = 0; - auto* item = &g_Level.Items[itemNumber]; - CreatureInfo* creature = (CreatureInfo*)item->Data; - - // In Streets of Rome when Larson HP are below 40 he runs way + // TODO: When Larson's HP is below 40, he runs away in Streets of Rome. Keeping block commented for reference. /*if (item->HitPoints <= TR5_LARSON_MIN_HP && !(item->flags & IFLAG_INVISIBLE)) { item->HitPoints = TR5_LARSON_MIN_HP; creature->flags++; }*/ - // Fire weapon effects + // Fire weapon effects. if (creature->FiredWeapon) { auto pos = GetJointPosition(item, LarsonGun.meshNum, Vector3i(LarsonGun.Position)); @@ -98,19 +90,20 @@ namespace TEN::Entities::TR5 { if (CurrentLevel == 2) { - item->ItemFlags[3] = 1; item->Animation.IsAirborne = false; - item->HitStatus = false; - item->Collidable = false; item->Status = ITEM_DEACTIVATED; + item->Collidable = false; + item->HitStatus = false; + item->ItemFlags[3] = 1; } else { item->Animation.IsAirborne = false; - item->HitStatus = false; - item->Collidable = false; item->Status = ITEM_ACTIVE; + item->Collidable = false; + item->HitStatus = false; } + item->TriggerFlags = 0; } @@ -121,30 +114,30 @@ namespace TEN::Entities::TR5 else creature->Enemy = LaraItem; - AI_INFO info; - CreatureAIInfo(item, &info); + AI_INFO AI; + CreatureAIInfo(item, &AI); - if (info.ahead) - joint2 = info.angle; + if (AI.ahead) + joint2 = AI.angle; - // FIXME: this should make Larson running away, but it's broken + // FIXME: This should make Larson run away, but it doesn't work. /*if (creature->flags) { item->HitPoints = 60; item->IsAirborne = false; - item->hitStatus = false; - item->collidable = false; - item->status = ITEM_DESACTIVATED; - creature->flags = 0; + item->HitStatus = false; + item->Collidable = false; + item->Status = ITEM_DESACTIVATED; + creature->Flags = 0; }*/ - GetCreatureMood(item, &info, true); - CreatureMood(item, &info, true); + GetCreatureMood(item, &AI, true); + CreatureMood(item, &AI, true); - if (info.distance < SQUARE(2048) - && LaraItem->Animation.Velocity.z > 20 - || item->HitStatus - || TargetVisible(item, &info) != 0) + if (AI.distance < SQUARE(SECTOR(2)) && + LaraItem->Animation.Velocity.z > 20.0f || + item->HitStatus || + TargetVisible(item, &AI) != 0) { item->Status &= ~ITEM_ACTIVE; creature->Alerted = true; @@ -155,40 +148,34 @@ namespace TEN::Entities::TR5 switch (item->Animation.ActiveState) { case STATE_TR5_LARSON_STOP: - joint0 = info.angle / 2; - joint2 = info.angle / 2; - if (info.ahead) - joint1 = info.xAngle; + joint0 = AI.angle / 2; + joint2 = AI.angle / 2; + + if (AI.ahead) + joint1 = AI.xAngle; if (item->Animation.RequiredState) - { item->Animation.TargetState = item->Animation.RequiredState; - } else if (item->AIBits & AMBUSH) - { item->Animation.TargetState = STATE_TR5_LARSON_RUN; - } - else if (Targetable(item, &info)) - { + else if (Targetable(item, &AI)) item->Animation.TargetState = STATE_TR5_LARSON_AIM; - } else { if (item->AIBits & GUARD || CurrentLevel == 2 || item->ItemFlags[3]) { - creature->MaxTurn = 0; item->Animation.TargetState = STATE_TR5_LARSON_STOP; - if (abs(info.angle) >= ANGLE(2)) + creature->MaxTurn = 0; + + if (abs(AI.angle) >= ANGLE(2.0f)) { - if (info.angle > 0) - item->Pose.Orientation.y += ANGLE(2); + if (AI.angle > 0) + item->Pose.Orientation.y += ANGLE(2.0f); else - item->Pose.Orientation.y -= ANGLE(2); + item->Pose.Orientation.y -= ANGLE(2.0f); } else - { - item->Pose.Orientation.y += info.angle; - } + item->Pose.Orientation.y += AI.angle; } else { @@ -200,175 +187,177 @@ namespace TEN::Entities::TR5 item->Animation.TargetState = STATE_TR5_LARSON_WALK; } else - { - item->Animation.TargetState = GetRandomControl() >= 96 ? 2 : 6; - } + item->Animation.TargetState = TestProbability(0.997f) ? 2 : 6; } } + break; case STATE_TR5_LARSON_WALK: - if (info.ahead) - joint2 = info.angle; + creature->MaxTurn = ANGLE(7.0f); - creature->MaxTurn = ANGLE(7); - if (creature->Mood == MoodType::Bored && GetRandomControl() < 96) + if (AI.ahead) + joint2 = AI.angle; + + if (creature->Mood == MoodType::Bored && TestProbability(1.0f / 340)) { - item->Animation.RequiredState = STATE_TR5_LARSON_IDLE; item->Animation.TargetState = STATE_TR5_LARSON_STOP; + item->Animation.RequiredState = STATE_TR5_LARSON_IDLE; break; } if (creature->Mood == MoodType::Escape || item->AIBits & AMBUSH) { - item->Animation.RequiredState = STATE_TR5_LARSON_RUN; item->Animation.TargetState = STATE_TR5_LARSON_STOP; + item->Animation.RequiredState = STATE_TR5_LARSON_RUN; } - else if (Targetable(item, &info)) + else if (Targetable(item, &AI)) { + item->Animation.TargetState = STATE_TR5_LARSON_STOP; item->Animation.RequiredState = STATE_TR5_LARSON_AIM; - item->Animation.TargetState = STATE_TR5_LARSON_STOP; } - else if (!info.ahead || info.distance > SQUARE(3072)) + else if (!AI.ahead || AI.distance > SQUARE(SECTOR(3))) { - item->Animation.RequiredState = STATE_TR5_LARSON_RUN; item->Animation.TargetState = STATE_TR5_LARSON_STOP; + item->Animation.RequiredState = STATE_TR5_LARSON_RUN; } + break; case STATE_TR5_LARSON_RUN: - if (info.ahead) - joint2 = info.angle; - creature->MaxTurn = ANGLE(11); + creature->MaxTurn = ANGLE(11.0f); tilt = angle / 2; + if (AI.ahead) + joint2 = AI.angle; + if (creature->ReachedGoal) - { item->Animation.TargetState = STATE_TR5_LARSON_STOP; - } else if (item->AIBits & AMBUSH) - { item->Animation.TargetState = STATE_TR5_LARSON_RUN; - } - else if (creature->Mood != MoodType::Bored || GetRandomControl() >= 96) + else if (creature->Mood != MoodType::Bored || TestProbability(0.997f)) { - if (Targetable(item, &info)) + if (Targetable(item, &AI)) { - item->Animation.RequiredState = STATE_TR5_LARSON_AIM; item->Animation.TargetState = STATE_TR5_LARSON_STOP; + item->Animation.RequiredState = STATE_TR5_LARSON_AIM; } - else if (info.ahead) + else if (AI.ahead) { - if (info.distance <= SQUARE(3072)) + if (AI.distance <= SQUARE(SECTOR(3))) { - item->Animation.RequiredState = STATE_TR5_LARSON_WALK; item->Animation.TargetState = STATE_TR5_LARSON_STOP; + item->Animation.RequiredState = STATE_TR5_LARSON_WALK; } } } else { - item->Animation.RequiredState = STATE_TR5_LARSON_IDLE; item->Animation.TargetState = STATE_TR5_LARSON_STOP; + item->Animation.RequiredState = STATE_TR5_LARSON_IDLE; } + break; case STATE_TR5_LARSON_AIM: - joint0 = info.angle / 2; - joint2 = info.angle / 2; - if (info.ahead) - joint1 = info.xAngle; creature->MaxTurn = 0; - if (abs(info.angle) >= ANGLE(2)) + joint0 = AI.angle / 2; + joint2 = AI.angle / 2; + + if (AI.ahead) + joint1 = AI.xAngle; + + if (abs(AI.angle) >= ANGLE(2.0f)) { - if (info.angle > 0) - item->Pose.Orientation.y += ANGLE(2); + if (AI.angle > 0) + item->Pose.Orientation.y += ANGLE(2.0f); else - item->Pose.Orientation.y -= ANGLE(2); + item->Pose.Orientation.y -= ANGLE(2.0f); } else - { - item->Pose.Orientation.y += info.angle; - } + item->Pose.Orientation.y += AI.angle; - if (Targetable(item, &info)) + if (Targetable(item, &AI)) item->Animation.TargetState = STATE_TR5_LARSON_ATTACK; else item->Animation.TargetState = STATE_TR5_LARSON_STOP; + break; case STATE_TR5_LARSON_IDLE: - joint0 = info.angle / 2; - joint2 = info.angle / 2; - if (info.ahead) - joint1 = info.xAngle; + joint0 = AI.angle / 2; + joint2 = AI.angle / 2; + + if (AI.ahead) + joint1 = AI.xAngle; if (creature->Mood != MoodType::Bored) - { item->Animation.TargetState = STATE_TR5_LARSON_STOP; - } else { - if (GetRandomControl() <= 96) + if (TestProbability(1.0f / 340)) { - item->Animation.RequiredState = STATE_TR5_LARSON_WALK; item->Animation.TargetState = STATE_TR5_LARSON_STOP; + item->Animation.RequiredState = STATE_TR5_LARSON_WALK; } } + break; case STATE_TR5_LARSON_ATTACK: - joint0 = info.angle / 2; - joint2 = info.angle / 2; - if (info.ahead) - joint1 = info.xAngle; creature->MaxTurn = 0; - if (abs(info.angle) >= ANGLE(2)) + joint0 = AI.angle / 2; + joint2 = AI.angle / 2; + + if (AI.ahead) + joint1 = AI.xAngle; + + if (abs(AI.angle) >= ANGLE(2.0f)) { - if (info.angle > 0) - item->Pose.Orientation.y += ANGLE(2); + if (AI.angle > 0) + item->Pose.Orientation.y += ANGLE(2.0f); else - item->Pose.Orientation.y -= ANGLE(2); + item->Pose.Orientation.y -= ANGLE(2.0f); } else - { - item->Pose.Orientation.y += info.angle; - } + item->Pose.Orientation.y += AI.angle; + if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase) { if (item->ObjectNumber == ID_PIERRE) { - ShotLara(item, &info, PierreGun1, joint0, 20); - ShotLara(item, &info, PierreGun2, joint0, 20); + ShotLara(item, &AI, PierreGun1, joint0, 20); + ShotLara(item, &AI, PierreGun2, joint0, 20); } else - { - ShotLara(item, &info, LarsonGun, joint0, 20); - } + ShotLara(item, &AI, LarsonGun, joint0, 20); + creature->FiredWeapon = 2; } - if (creature->Mood == MoodType::Escape && GetRandomControl() > 0x2000) + + if (creature->Mood == MoodType::Escape && TestProbability(0.75f)) item->Animation.RequiredState = STATE_TR5_LARSON_STOP; + break; default: break; - } } else if (item->Animation.ActiveState == STATE_TR5_LARSON_DIE) { // When Larson dies, it activates trigger at start position - if (item->ObjectNumber == ID_LARSON - && item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameEnd) + if (item->ObjectNumber == ID_LARSON && + item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameEnd) { short roomNumber = item->ItemFlags[2] & 0xFF; short floorHeight = item->ItemFlags[2] & 0xFF00; - ROOM_INFO* r = &g_Level.Rooms[roomNumber]; - int x = r->x + (creature->Tosspad / 256 & 0xFF) * SECTOR(1) + 512; - int y = r->minfloor + floorHeight; - int z = r->z + (creature->Tosspad & 0xFF) * SECTOR(1) + 512; + auto* room = &g_Level.Rooms[roomNumber]; + + int x = room->x + (creature->Tosspad / 256 & 0xFF) * SECTOR(1) + 512; + int y = room->minfloor + floorHeight; + int z = room->z + (creature->Tosspad & 0xFF) * SECTOR(1) + 512; TestTriggers(x, y, z, roomNumber, true); @@ -377,13 +366,14 @@ namespace TEN::Entities::TR5 } else { - // Die + // Death. if (item->ObjectNumber == ID_PIERRE) item->Animation.AnimNumber = Objects[ID_PIERRE].animIndex + ANIMATION_TR5_PIERRE_DIE; else item->Animation.AnimNumber = Objects[ID_LARSON].animIndex + ANIMATION_TR5_LARSON_DIE; - item->Animation.ActiveState = STATE_TR5_LARSON_DIE; + item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; + item->Animation.ActiveState = STATE_TR5_LARSON_DIE; } CreatureTilt(item, tilt); @@ -398,12 +388,12 @@ namespace TEN::Entities::TR5 { item->TargetState = STATE_TR5_LARSON_STOP; item->RequiredState = STATE_TR5_LARSON_STOP; - creature->reachedGoal = false; + creature->ReachedGoal = false; item->IsAirborne = false; - item->hitStatus = false; - item->collidable = false; - item->status = ITEM_NOT_ACTIVE; - item->triggerFlags = 0; + item->HitStatus = false; + item->Collidable = false; + item->Status = ITEM_NOT_ACTIVE; + item->TriggerFlags = 0; } else { diff --git a/TombEngine/Objects/TR5/Entity/tr5_larson.h b/TombEngine/Objects/TR5/Entity/tr5_larson.h index 15c75470b..4e86b61c9 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_larson.h +++ b/TombEngine/Objects/TR5/Entity/tr5_larson.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseLarson(short itemNumber); void LarsonControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_laser_head.cpp b/TombEngine/Objects/TR5/Entity/tr5_laser_head.cpp index c73ce7007..c117e40c7 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_laser_head.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_laser_head.cpp @@ -21,7 +21,7 @@ using namespace TEN::Effects::Lara; using namespace TEN::Effects::Lightning; using namespace TEN::Math; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { struct LaserHeadStruct { diff --git a/TombEngine/Objects/TR5/Entity/tr5_laser_head.h b/TombEngine/Objects/TR5/Entity/tr5_laser_head.h index 5990de0b3..abd3542b4 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_laser_head.h +++ b/TombEngine/Objects/TR5/Entity/tr5_laser_head.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseLaserHead(short itemNumber); void LaserHeadControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_laserhead_info.h b/TombEngine/Objects/TR5/Entity/tr5_laserhead_info.h index a0b038821..52adc215f 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_laserhead_info.h +++ b/TombEngine/Objects/TR5/Entity/tr5_laserhead_info.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { struct LaserHeadInfo { diff --git a/TombEngine/Objects/TR5/Entity/tr5_lion.cpp b/TombEngine/Objects/TR5/Entity/tr5_lion.cpp index f1f9b6f71..6e67cfd16 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_lion.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_lion.cpp @@ -16,16 +16,16 @@ using namespace TEN::Math::Random; using std::vector; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { constexpr auto LION_POUNCE_ATTACK_DAMAGE = 200; constexpr auto LION_BITE_ATTACK_DAMAGE = 60; constexpr auto LION_POUNCE_ATTACK_RANGE = SQUARE(SECTOR(1)); - const vector LionAttackJoints = { 3, 6, 21 }; const auto LionBite1 = BiteInfo(Vector3(2.0f, -10.0f, 250.0f), 21); const auto LionBite2 = BiteInfo(Vector3(-2.0f, -10.0f, 132.0f), 21); + const vector LionAttackJoints = { 3, 6, 21 }; enum LionState { @@ -142,7 +142,7 @@ namespace TEN::Entities::TR5 if (creature->Mood == MoodType::Bored) { - if (TestProbability(0.004f)) + if (TestProbability(1.0f / 256)) { item->Animation.TargetState = LION_STATE_IDLE; item->Animation.RequiredState = LION_STATE_ROAR; @@ -165,7 +165,7 @@ namespace TEN::Entities::TR5 item->Animation.TargetState = LION_STATE_IDLE; else if (creature->Mood != MoodType::Escape) { - if (TestProbability(0.004f)) + if (TestProbability(1.0f / 256)) { item->Animation.TargetState = LION_STATE_IDLE; item->Animation.RequiredState = LION_STATE_ROAR; @@ -181,9 +181,9 @@ namespace TEN::Entities::TR5 if (!item->Animation.RequiredState && item->TestBits(JointBitType::Touch, LionAttackJoints)) { - item->Animation.RequiredState = LION_STATE_IDLE; DoDamage(creature->Enemy, LION_POUNCE_ATTACK_DAMAGE); CreatureEffect2(item, LionBite1, 10, item->Pose.Orientation.y, DoBloodSplat); + item->Animation.RequiredState = LION_STATE_IDLE; } break; @@ -194,9 +194,9 @@ namespace TEN::Entities::TR5 if (!item->Animation.RequiredState && item->TestBits(JointBitType::Touch, LionAttackJoints)) { - item->Animation.RequiredState = LION_STATE_IDLE; DoDamage(creature->Enemy, LION_BITE_ATTACK_DAMAGE); CreatureEffect2(item, LionBite2, 10, item->Pose.Orientation.y, DoBloodSplat); + item->Animation.RequiredState = LION_STATE_IDLE; } break; diff --git a/TombEngine/Objects/TR5/Entity/tr5_lion.h b/TombEngine/Objects/TR5/Entity/tr5_lion.h index 85d223a2d..4218188f4 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_lion.h +++ b/TombEngine/Objects/TR5/Entity/tr5_lion.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseLion(short itemNumber); void LionControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_reaper.cpp b/TombEngine/Objects/TR5/Entity/tr5_reaper.cpp index f8f1ba0ac..4018b8e2a 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_reaper.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_reaper.cpp @@ -9,7 +9,7 @@ #include "Game/itemdata/creature_info.h" #include "Game/control/control.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseReaper(short itemNumber) { diff --git a/TombEngine/Objects/TR5/Entity/tr5_reaper.h b/TombEngine/Objects/TR5/Entity/tr5_reaper.h index 464d8dae5..cebde76ff 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_reaper.h +++ b/TombEngine/Objects/TR5/Entity/tr5_reaper.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseReaper(short itemNumber); void ReaperControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_roman_statue.cpp b/TombEngine/Objects/TR5/Entity/tr5_roman_statue.cpp index bc94f9b1e..843729799 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_roman_statue.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_roman_statue.cpp @@ -20,7 +20,7 @@ using namespace TEN::Effects::Lightning; using namespace TEN::Math; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { const auto RomanStatueBite = BiteInfo(Vector3::Zero, 15); diff --git a/TombEngine/Objects/TR5/Entity/tr5_roman_statue.h b/TombEngine/Objects/TR5/Entity/tr5_roman_statue.h index 21fc6b1c9..3cf7a045d 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_roman_statue.h +++ b/TombEngine/Objects/TR5/Entity/tr5_roman_statue.h @@ -1,7 +1,7 @@ #pragma once #include "Math/Math.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseRomanStatue(short itemNumber); void RomanStatueControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_submarine.cpp b/TombEngine/Objects/TR5/Entity/tr5_submarine.cpp index 3e3e7283c..c03b25be3 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_submarine.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_submarine.cpp @@ -1,27 +1,29 @@ #include "framework.h" -#include "tr5_submarine.h" -#include "Game/items.h" -#include "Game/control/box.h" -#include "Game/people.h" +#include "Objects/TR5/Entity/tr5_submarine.h" + +#include "Game/animation.h" #include "Game/collision/collide_item.h" #include "Game/collision/collide_room.h" +#include "Game/control/box.h" #include "Game/control/los.h" #include "Game/effects/effects.h" #include "Game/effects/tomb4fx.h" #include "Game/itemdata/creature_info.h" -#include "Game/animation.h" +#include "Game/items.h" #include "Game/Lara/lara.h" #include "Game/Lara/lara_one_gun.h" #include "Math/Math.h" -#include "Specific/setup.h" -#include "Specific/level.h" +#include "Game/misc.h" +#include "Game/people.h" #include "Sound/sound.h" +#include "Specific/level.h" +#include "Specific/setup.h" using namespace TEN::Math; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { - static void TriggerSubmarineSparks(short itemNumber) + void TriggerSubmarineSparks(short itemNumber) { auto* spark = GetFreeParticle(); @@ -53,7 +55,7 @@ namespace TEN::Entities::TR5 spark->dSize = spark->sSize = spark->size = (GetRandomControl() & 7) + 192; } - static void TriggerTorpedoBubbles(Vector3i* pos1, Vector3i* pos2, char factor) + void TriggerTorpedoBubbles(Vector3i* pos1, Vector3i* pos2, char factor) { auto* spark = GetFreeParticle(); @@ -86,7 +88,7 @@ namespace TEN::Entities::TR5 spark->dSize = spark->size * 2; } - static void TriggerTorpedoSparks2(Vector3i* pos1, Vector3i* pos2, char scale) + void TriggerTorpedoSparks2(Vector3i* pos1, Vector3i* pos2, char scale) { auto* spark = GetFreeParticle(); @@ -118,18 +120,18 @@ namespace TEN::Entities::TR5 spark->dSize = spark->size * 2; } - static void SubmarineAttack(ItemInfo* item) + void SubmarineAttack(ItemInfo* item) { short itemNumber = CreateItem(); + if (itemNumber == NO_ITEM) + return; - if (itemNumber != NO_ITEM) - { - auto* torpedoItem = &g_Level.Items[itemNumber]; + auto* torpedoItem = &g_Level.Items[itemNumber]; - SoundEffect(SFX_TR5_UNDERWATER_TORPEDO, &torpedoItem->Pose, SoundEnvironment::Always); + SoundEffect(SFX_TR5_UNDERWATER_TORPEDO, &torpedoItem->Pose, SoundEnvironment::Always); - torpedoItem->ObjectNumber = ID_TORPEDO; - torpedoItem->Color = Vector4(0.5f, 0.5f, 0.5f, 1.0f); + torpedoItem->ObjectNumber = ID_TORPEDO; + torpedoItem->Color = Vector4(0.5f, 0.5f, 0.5f, 1.0f); auto pos1 = Vector3i::Zero; auto pos2 = Vector3i::Zero; @@ -147,15 +149,15 @@ namespace TEN::Entities::TR5 (GetRandomControl() & 0x3FF) - 160 )); - TriggerTorpedoSparks2(&pos1, &pos2, 0); - } + TriggerTorpedoSparks2(&pos1, &pos2, 0); + } - torpedoItem->RoomNumber = item->RoomNumber; - GetFloor(pos1.x, pos1.y, pos1.z, &torpedoItem->RoomNumber); + torpedoItem->RoomNumber = item->RoomNumber; + GetFloor(pos1.x, pos1.y, pos1.z, &torpedoItem->RoomNumber); torpedoItem->Pose.Position = pos1; - InitialiseItem(itemNumber); + InitialiseItem(itemNumber); torpedoItem->Pose.Orientation.x = 0; torpedoItem->Pose.Orientation.y = item->Pose.Orientation.y; @@ -164,8 +166,7 @@ namespace TEN::Entities::TR5 torpedoItem->Animation.Velocity.z = 0.0f; torpedoItem->ItemFlags[0] = -1; - AddActiveItem(itemNumber); - } + AddActiveItem(itemNumber); } void InitialiseSubmarine(short itemNumber) @@ -173,10 +174,7 @@ namespace TEN::Entities::TR5 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.TargetState = 0; - item->Animation.ActiveState = 0; + SetAnimation(item, 0); if (!item->TriggerFlags) item->TriggerFlags = 120; @@ -188,14 +186,14 @@ namespace TEN::Entities::TR5 return; auto* item = &g_Level.Items[itemNumber]; - auto* creature = (CreatureInfo*)item->Data; + auto* creature = GetCreatureInfo(item); if (item->AIBits) GetAITarget(creature); else creature->Enemy = LaraItem; - AI_INFO AI, laraInfo; + AI_INFO AI, laraAI; CreatureAIInfo(item, &AI); GetCreatureMood(item, &AI, true); @@ -205,34 +203,34 @@ namespace TEN::Entities::TR5 if (creature->Enemy == LaraItem) { - laraInfo.angle = AI.angle; - laraInfo.distance = AI.distance; + laraAI.angle = AI.angle; + laraAI.distance = AI.distance; } else { int dx = LaraItem->Pose.Position.x - item->Pose.Position.x; int dz = LaraItem->Pose.Position.z - item->Pose.Position.z; - laraInfo.angle = phd_atan(dz, dx) - item->Pose.Orientation.y; - laraInfo.distance = pow(dx, 2) + pow(dz, 2); - laraInfo.ahead = true; + laraAI.angle = phd_atan(dz, dx) - item->Pose.Orientation.y; + laraAI.distance = pow(dx, 2) + pow(dz, 2); + laraAI.ahead = true; } int tilt = item->ItemFlags[0] + (angle / 2); - if (tilt > 2048) - tilt = 2048; - else if (tilt < -2048) - tilt = -2048; + if (tilt > ANGLE(11.25f)) + tilt = ANGLE(11.25f); + else if (tilt < ANGLE(-11.25f)) + tilt = ANGLE(-11.25f); item->ItemFlags[0] = tilt; - if (abs(tilt) >= 64) + if (abs(tilt) >= ANGLE(0.35f)) { if (tilt > 0) - item->ItemFlags[0] -= 64; + item->ItemFlags[0] -= ANGLE(0.35f); else - item->ItemFlags[0] += 64; + item->ItemFlags[0] += ANGLE(0.35f); } else item->ItemFlags[0] = 0; @@ -247,17 +245,17 @@ namespace TEN::Entities::TR5 auto* enemy = creature->Enemy; creature->Enemy = LaraItem; - if (Targetable(item, &laraInfo)) + if (Targetable(item, &laraAI)) { if (creature->Flags >= item->TriggerFlags && - laraInfo.angle > -ANGLE(90.0f) && - laraInfo.angle < ANGLE(90.0f)) + laraAI.angle > -ANGLE(90.0f) && + laraAI.angle < ANGLE(90.0f)) { SubmarineAttack(item); creature->Flags = 0; } - if (laraInfo.distance >= pow(SECTOR(3), 2)) + if (laraAI.distance >= pow(SECTOR(3), 2)) { item->Animation.TargetState = 1; SoundEffect(SFX_TR5_VEHICLE_DIVESUIT_LOOP, &item->Pose, SoundEnvironment::Always); @@ -268,15 +266,15 @@ namespace TEN::Entities::TR5 if (AI.distance < pow(SECTOR(1), 2)) { creature->MaxTurn = 0; - if (abs(laraInfo.angle) >= ANGLE(2.0f)) + if (abs(laraAI.angle) >= ANGLE(2.0f)) { - if (laraInfo.angle >= 0) + if (laraAI.angle >= 0) item->Pose.Orientation.y += ANGLE(2.0f); else item->Pose.Orientation.y -= ANGLE(2.0f); } else - item->Pose.Orientation.y += laraInfo.angle; + item->Pose.Orientation.y += laraAI.angle; } } else @@ -360,8 +358,8 @@ namespace TEN::Entities::TR5 if (TestEnvironment(ENV_FLAG_WATER, item->RoomNumber)) { - item->Animation.Velocity.z += (5 - item->Animation.Velocity.z) / 2; - item->Animation.Velocity.y+= (5 - item->Animation.Velocity.y) / 2; + item->Animation.Velocity.y += (5.0f - item->Animation.Velocity.y) / 2.0f; + item->Animation.Velocity.z += (5.0f - item->Animation.Velocity.z) / 2.0f; } else item->Animation.Velocity.y += GRAVITY; @@ -436,13 +434,13 @@ namespace TEN::Entities::TR5 auto orient = Geometry::GetOrientTowardPoint(item->Pose.Position.ToVector3(), pos.ToVector3()); - if (item->Animation.Velocity.z >= 48) + if (item->Animation.Velocity.z >= 48.0f) { - if (item->Animation.Velocity.z < 192) + if (item->Animation.Velocity.z < 192.0f) item->Animation.Velocity.z++; } else - item->Animation.Velocity.z += 4; + item->Animation.Velocity.z += 4.0f; item->ItemFlags[1]++; @@ -497,7 +495,7 @@ namespace TEN::Entities::TR5 item->Pose.Position.y > probe.Position.Ceiling && TestEnvironment(ENV_FLAG_WATER, probe.RoomNumber)) { - if (ItemNearLara(&item->Pose, 200)) + if (ItemNearLara(&item->Pose.Position, 200)) { LaraItem->HitStatus = true; KillItem(itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_submarine.h b/TombEngine/Objects/TR5/Entity/tr5_submarine.h index ab76d34ca..7a3db051e 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_submarine.h +++ b/TombEngine/Objects/TR5/Entity/tr5_submarine.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseSubmarine(short itemNumber); void SubmarineControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/Entity/tr5_willowwisp.cpp b/TombEngine/Objects/TR5/Entity/tr5_willowwisp.cpp index f2c8e6a04..d99d28674 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_willowwisp.cpp +++ b/TombEngine/Objects/TR5/Entity/tr5_willowwisp.cpp @@ -5,7 +5,7 @@ #include "Specific/level.h" #include "Specific/setup.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { enum WillowWispState { @@ -17,9 +17,6 @@ namespace TEN::Entities::TR5 auto* item = &g_Level.Items[itemNumber]; ClearItem(itemNumber); - item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex; - item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase; - item->Animation.ActiveState = WWISP_STATE_UNK; - item->Animation.TargetState = WWISP_STATE_UNK; + SetAnimation(item, 0); } } diff --git a/TombEngine/Objects/TR5/Entity/tr5_willowwisp.h b/TombEngine/Objects/TR5/Entity/tr5_willowwisp.h index 778c3ea29..6271a9c6f 100644 --- a/TombEngine/Objects/TR5/Entity/tr5_willowwisp.h +++ b/TombEngine/Objects/TR5/Entity/tr5_willowwisp.h @@ -1,6 +1,6 @@ #pragma once -namespace TEN::Entities::TR5 +namespace TEN::Entities::Creatures::TR5 { void InitialiseLightingGuide(short itemNumber); } diff --git a/TombEngine/Objects/TR5/Object/tr5_missile.cpp b/TombEngine/Objects/TR5/Object/tr5_missile.cpp index 33291c94b..ab6bed9e6 100644 --- a/TombEngine/Objects/TR5/Object/tr5_missile.cpp +++ b/TombEngine/Objects/TR5/Object/tr5_missile.cpp @@ -23,6 +23,7 @@ int DebrisFlags; void MissileControl(short itemNumber) { auto* fx = &EffectList[itemNumber]; + if (fx->flag1 == 2) { fx->pos.Orientation.z += 16 * fx->speed; @@ -119,9 +120,9 @@ void MissileControl(short itemNumber) { TriggerExplosionSparks(x, y, z, 3, -2, 2, fx->roomNumber); fx->pos.Position.y -= 64; - TriggerShockwave((PoseData*)fx, 48, 256, 64, 64, 128, 0, 24, 0, 1); + TriggerShockwave(&fx->pos, 48, 256, 64, 64, 128, 0, 24, 0, 1); fx->pos.Position.y -= 128; - TriggerShockwave((PoseData*)fx, 48, 256, 48, 64, 128, 0, 24, 0, 1); + TriggerShockwave(&fx->pos, 48, 256, 48, 64, 128, 0, 24, 0, 1); } else if (fx->flag1 == 2) { @@ -132,12 +133,12 @@ void MissileControl(short itemNumber) else { TriggerExplosionSparks(x, y, z, 3, -2, 0, fx->roomNumber); - TriggerShockwave((PoseData*)fx, 48, 240, 48, 0, 96, 128, 24, 0, 2); + TriggerShockwave(&fx->pos, 48, 240, 48, 0, 96, 128, 24, 0, 2); } KillEffect(itemNumber); } - else if (ItemNearLara((PoseData*)fx, 200)) + else if (ItemNearLara(&fx->pos.Position, 200)) { if (fx->flag1) { @@ -146,9 +147,9 @@ void MissileControl(short itemNumber) // ROMAN_GOD hit effect TriggerExplosionSparks(x, y, z, 3, -2, 2, fx->roomNumber); fx->pos.Position.y -= 64; - TriggerShockwave((PoseData*)fx, 48, 256, 64, 0, 128, 64, 24, 0, 1); + TriggerShockwave(&fx->pos, 48, 256, 64, 0, 128, 64, 24, 0, 1); fx->pos.Position.y -= 128; - TriggerShockwave((PoseData*)fx, 48, 256, 48, 0, 128, 64, 24, 0, 1); + TriggerShockwave(&fx->pos, 48, 256, 48, 0, 128, 64, 24, 0, 1); KillEffect(itemNumber); DoDamage(LaraItem, 200); } @@ -171,7 +172,7 @@ void MissileControl(short itemNumber) { // HYDRA hit effect TriggerExplosionSparks(x, y, z, 3, -2, 0, fx->roomNumber); - TriggerShockwave((PoseData*)fx, 48, 240, 48, 0, 96, 128, 24, 0, 0); + TriggerShockwave(&fx->pos, 48, 240, 48, 0, 96, 128, 24, 0, 0); if (LaraItem->HitPoints >= 500) DoDamage(LaraItem, 300); else @@ -186,8 +187,7 @@ void MissileControl(short itemNumber) if (GlobalCounter & 1) { - Vector3i pos = { x, y, z }; - + auto pos = Vector3i(x, y, z); int xv = x - fx->pos.Position.x; int yv = y - fx->pos.Position.y; int zv = z - fx->pos.Position.z; @@ -197,7 +197,7 @@ void MissileControl(short itemNumber) else { TriggerHydraMissileSparks(&pos, 4 * xv, 4 * yv, 4 * zv); - TriggerHydraMissileSparks((Vector3i*)&fx, 4 * xv, 4 * yv, 4 * zv); + TriggerHydraMissileSparks(&fx->pos.Position, 4 * xv, 4 * yv, 4 * zv); } } } diff --git a/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.cpp b/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.cpp index be2ce65b5..249c16a8d 100644 --- a/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.cpp +++ b/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.cpp @@ -1,21 +1,21 @@ #include "framework.h" #include "tr5_crowdove_switch.h" + +#include "Game/animation.h" +#include "Game/collision/collide_item.h" #include "Game/control/control.h" -#include "Specific/input.h" -#include "Specific/level.h" +#include "Game/effects/debris.h" +#include "Game/items.h" #include "Game/Lara/lara.h" #include "Game/Lara/lara_helpers.h" #include "Objects/Generic/Switches/generic_switch.h" #include "Sound/sound.h" -#include "Game/animation.h" -#include "Game/items.h" -#include "Game/collision/collide_item.h" -#include "Game/effects/debris.h" +#include "Specific/input.h" +#include "Specific/level.h" using namespace TEN::Input; -using namespace TEN::Entities::Switches; -namespace TEN::Entities::TR5 +namespace TEN::Entities::Switches { OBJECT_COLLISION_BOUNDS CrowDoveBounds = { diff --git a/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.h b/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.h index 8aeeea90f..c32c73df8 100644 --- a/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.h +++ b/TombEngine/Objects/TR5/Switch/tr5_crowdove_switch.h @@ -1,9 +1,8 @@ #pragma once - -#include "Game/items.h" #include "Game/collision/collide_room.h" +#include "Game/items.h" -namespace TEN::Entities::TR5 +namespace TEN::Entities::Switches { void InitialiseCrowDoveSwitch(short itemNumber); void CrowDoveSwitchControl(short itemNumber); diff --git a/TombEngine/Objects/TR5/tr5_objects.cpp b/TombEngine/Objects/TR5/tr5_objects.cpp index 1efa9b1dd..5c7b5261f 100644 --- a/TombEngine/Objects/TR5/tr5_objects.cpp +++ b/TombEngine/Objects/TR5/tr5_objects.cpp @@ -1,7 +1,20 @@ #include "framework.h" #include "Objects/TR5/tr5_objects.h" -/// Entities +#include "Game/collision/collide_item.h" +#include "Game/control/box.h" +#include "Game/itemdata/creature_info.h" +#include "Game/Lara/lara_flare.h" +#include "Game/Lara/lara_initialise.h" +#include "Game/Lara/lara_one_gun.h" +#include "Game/pickup/pickup.h" +#include "Objects/Generic/Object/objects.h" +#include "Objects/Generic/Switches/switch.h" +#include "Objects/Utils/object_helper.h" +#include "Specific/level.h" +#include "Specific/setup.h" + +// Creatures #include "tr5_autoguns.h" // OK #include "tr5_brownbeast.h" // OK #include "tr5_chef.h" // OK @@ -23,13 +36,13 @@ #include "tr5_submarine.h" // OK #include "tr5_willowwisp.h" // OK -/// Emitters +// Emitters #include "Objects/TR5/Emitter/tr5_rats_emitter.h" #include "Objects/TR5/Emitter/tr5_bats_emitter.h" #include "Objects/TR5/Emitter/tr5_spider_emitter.h" #include "tr5_smoke_emitter.h" -/// Objects +// Objects #include "Objects/TR5/Object/tr5_pushableblock.h" #include "tr5_twoblockplatform.h" #include "tr5_raisingcog.h" @@ -42,7 +55,7 @@ #include "tr5_missile.h" #include "tr5_genslot.h" -/// Traps +// Traps #include "tr5_ventilator.h" #include "tr5_deathslide.h" #include "Objects/Effects/tr5_electricity.h" @@ -55,24 +68,11 @@ // Switches #include "tr5_crowdove_switch.h" -/// shatter +// Shatters #include "Objects/TR5/Shatter/tr5_smashobject.h" -/// necessary import -#include "Game/collision/collide_item.h" -#include "Game/Lara/lara_one_gun.h" -#include "Game/Lara/lara_flare.h" -#include "Game/Lara/lara_initialise.h" -#include "Game/pickup/pickup.h" -#include "Specific/setup.h" -#include "Objects/Generic/Switches/switch.h" -#include "Objects/Generic/Object/objects.h" -#include "Specific/level.h" -/// register objects -#include "Objects/Utils/object_helper.h" -#include "Game/itemdata/creature_info.h" -#include "Game/control/box.h" -using namespace TEN::Entities::TR5; +using namespace TEN::Entities::Creatures::TR5; +using namespace TEN::Entities::Switches; static void StartEntity(ObjectInfo *obj) { @@ -105,7 +105,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -130,7 +130,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -157,7 +157,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -187,7 +187,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -218,7 +218,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -247,7 +247,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[Objects[69].boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[Objects[69].boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[Objects[69].boneIndex + 13 * 4] |= ROT_Y; @@ -278,7 +278,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -310,7 +310,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -334,7 +334,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveHitpoints = true; obj->savePosition = true; obj->waterCreature = true; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; obj->undead = true; g_Level.Bones[obj->boneIndex] |= ROT_X; g_Level.Bones[obj->boneIndex + 4] |= ROT_X; @@ -357,7 +357,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 4 * 6] |= ROT_Y; g_Level.Bones[obj->boneIndex + 4 * 6] |= ROT_X; @@ -381,7 +381,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 19 * 4] |= ROT_Y; } @@ -402,7 +402,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 19 * 4] |= ROT_Y; } @@ -422,7 +422,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 19 * 4] |= ROT_Y; } @@ -443,7 +443,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveHitpoints = true; obj->savePosition = true; obj->waterCreature = true; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; } obj = &Objects[ID_MAFIA2]; @@ -464,7 +464,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; obj->meshSwapSlot = ID_MESHSWAP_MAFIA2; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; @@ -490,7 +490,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_Y; @@ -514,7 +514,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 7 * 4] |= ROT_Y; @@ -539,7 +539,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveAnim = true; obj->saveHitpoints = true; obj->undead = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; obj->meshSwapSlot = ID_MESHSWAP_HITMAN; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; @@ -591,7 +591,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveAnim = true; obj->saveHitpoints = true; obj->undead = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex] |= ROT_Y; g_Level.Bones[obj->boneIndex] |= ROT_X; g_Level.Bones[obj->boneIndex + 4] |= ROT_Y; @@ -616,7 +616,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveAnim = true; obj->saveHitpoints = true; obj->undead = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 0] |= ROT_Y; g_Level.Bones[obj->boneIndex + 8 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 8 * 4] |= ROT_X; @@ -641,7 +641,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveAnim = true; obj->saveHitpoints = true; obj->meshSwapSlot = ID_MESHSWAP_IMP; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->meshIndex + 4 * 4] |= ROT_Z; g_Level.Bones[obj->meshIndex + 4 * 4] |= ROT_X; @@ -665,7 +665,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_FLYER; + obj->ZoneType = ZoneType::Flyer; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_Z; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 9 * 4] |= ROT_Z; @@ -689,7 +689,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveHitpoints = true; obj->savePosition = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_Z; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 9 * 4] |= ROT_Z; @@ -714,7 +714,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveHitpoints = true; obj->savePosition = true; obj->waterCreature = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_Z; g_Level.Bones[obj->boneIndex + 4 * 4] |= ROT_X; @@ -739,7 +739,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 8 * 4] |= ROT_Y; @@ -790,7 +790,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveFlags = true; obj->saveAnim = true; obj->saveHitpoints = true; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_Y; g_Level.Bones[obj->boneIndex + 6 * 4] |= ROT_X; g_Level.Bones[obj->boneIndex + 13 * 4] |= ROT_Y; @@ -817,7 +817,7 @@ static void StartEntity(ObjectInfo *obj) obj->saveAnim = true; obj->saveHitpoints = true; obj->meshSwapSlot = ID_MESHSWAP_ROMAN_GOD1 + i; - obj->zoneType = ZONE_HUMAN_CLASSIC; + obj->ZoneType = ZoneType::HumanClassic; g_Level.Bones[obj->boneIndex + 24] |= ROT_Y; g_Level.Bones[obj->boneIndex + 24] |= ROT_X; @@ -876,7 +876,7 @@ static void StartEntity(ObjectInfo *obj) obj->initialise = InitialiseSubmarine; obj->control = SubmarineControl; obj->saveAnim = true; - obj->zoneType = ZONE_BASIC; + obj->ZoneType = ZoneType::Basic; obj->hitEffect = HIT_RICOCHET; obj->shadowType = ShadowMode::All; obj->HitPoints = 100; diff --git a/TombEngine/Scripting/Include/ScriptInterfaceGame.h b/TombEngine/Scripting/Include/ScriptInterfaceGame.h index 010afc4eb..09748f5f9 100644 --- a/TombEngine/Scripting/Include/ScriptInterfaceGame.h +++ b/TombEngine/Scripting/Include/ScriptInterfaceGame.h @@ -24,7 +24,7 @@ struct FuncName std::string name; }; -using SavedVar = std::variant; +using SavedVar = std::variant; class ScriptInterfaceGame { public: diff --git a/TombEngine/Scripting/Internal/TEN/Logic/LevelFunc.h b/TombEngine/Scripting/Internal/TEN/Logic/LevelFunc.h index a525a8f0f..e7399e1ee 100644 --- a/TombEngine/Scripting/Internal/TEN/Logic/LevelFunc.h +++ b/TombEngine/Scripting/Internal/TEN/Logic/LevelFunc.h @@ -16,13 +16,13 @@ class LevelFunc { public: std::string m_funcName; LogicHandler* m_handler; - void Call(sol::variadic_args vs) + sol::protected_function_result Call(sol::variadic_args vs) { - m_handler->CallLevelFunc(m_funcName, vs); + return m_handler->CallLevelFunc(m_funcName, vs); } - void CallDT(float dt) + sol::protected_function_result CallDT(float dt) { - m_handler->CallLevelFunc(m_funcName, dt); + return m_handler->CallLevelFunc(m_funcName, dt); } static void Register(sol::table & parent) diff --git a/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.cpp b/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.cpp index d2bc2d41f..69c815e1a 100644 --- a/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.cpp +++ b/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.cpp @@ -180,7 +180,7 @@ sol::object LogicHandler::GetLevelFuncsMember(sol::table tab, std::string const& return sol::nil; } -void LogicHandler::CallLevelFunc(std::string const & name, float dt) +sol::protected_function_result LogicHandler::CallLevelFunc(std::string const & name, float dt) { sol::protected_function f = m_levelFuncs_luaFunctions[name]; auto r = f.call(dt); @@ -190,9 +190,11 @@ void LogicHandler::CallLevelFunc(std::string const & name, float dt) sol::error err = r; ScriptAssertF(false, "Could not execute function {}: {}", name, err.what()); } + + return r; } -void LogicHandler::CallLevelFunc(std::string const & name, sol::variadic_args va) +sol::protected_function_result LogicHandler::CallLevelFunc(std::string const & name, sol::variadic_args va) { sol::protected_function f = m_levelFuncs_luaFunctions[name]; auto r = f.call(va); @@ -201,6 +203,8 @@ void LogicHandler::CallLevelFunc(std::string const & name, sol::variadic_args va sol::error err = r; ScriptAssertF(false, "Could not execute function {}: {}", name, err.what()); } + + return r; } bool LogicHandler::SetLevelFuncsMember(sol::table tab, std::string const& luaName, sol::object value) @@ -350,9 +354,9 @@ void LogicHandler::SetVariables(std::vector const & vars) solTables[i][vars[first]] = vars[second]; } } - else if (std::holds_alternative(vars[second])) + else if (std::holds_alternative(vars[second])) { - auto theVec = Vec3{ std::get(vars[second]) }; + auto theVec = Vec3{ std::get(vars[second]) }; solTables[i][vars[first]] = theVec; } else if (std::holds_alternative(vars[second])) diff --git a/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.h b/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.h index 694c3cb44..24a4a74bf 100644 --- a/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.h +++ b/TombEngine/Scripting/Internal/TEN/Logic/LogicHandler.h @@ -64,8 +64,8 @@ private: public: LogicHandler(sol::state* lua, sol::table & parent); - void CallLevelFunc(std::string const &, sol::variadic_args); - void CallLevelFunc(std::string const &, float dt); + sol::protected_function_result CallLevelFunc(std::string const &, sol::variadic_args); + sol::protected_function_result CallLevelFunc(std::string const &, float dt); void FreeLevelScripts() override; diff --git a/TombEngine/Scripting/Internal/TEN/Misc/Miscellanous.cpp b/TombEngine/Scripting/Internal/TEN/Misc/Miscellanous.cpp index 8053c7e10..02f959c49 100644 --- a/TombEngine/Scripting/Internal/TEN/Misc/Miscellanous.cpp +++ b/TombEngine/Scripting/Internal/TEN/Misc/Miscellanous.cpp @@ -48,10 +48,16 @@ namespace Misc pos1.StoreInGameVector(vec1); vec1.roomNumber = roomNumber1; pos2.StoreInGameVector(vec2); - return LOS(&vec1, &vec2); + + MESH_INFO* mesh; + Vector3i vector; + return LOS(&vec1, &vec2) && (ObjectOnLOS2(&vec1, &vec2, &vector, &mesh) == NO_LOS_ITEM); } - + ///Vibrate game controller, if function is available and setting is on. + //@function Vibrate + //@tparam float strength Strength of the vibration + //@tparam float time __(default 0.3)__ Time of the vibration, in seconds static void Vibrate(float strength, sol::optional time) { Rumble(strength, time.value_or(0.3f), RumbleMode::Both); diff --git a/TombEngine/Scripting/Internal/TEN/Vec3/Vec3.h b/TombEngine/Scripting/Internal/TEN/Vec3/Vec3.h index 280298e85..4a3f01149 100644 --- a/TombEngine/Scripting/Internal/TEN/Vec3/Vec3.h +++ b/TombEngine/Scripting/Internal/TEN/Vec3/Vec3.h @@ -1,6 +1,6 @@ #pragma once -struct Vector3Int; +struct Vector3i; namespace sol { class state; diff --git a/TombEngine/Specific/setup.cpp b/TombEngine/Specific/setup.cpp index d30ba5659..d56cd088d 100644 --- a/TombEngine/Specific/setup.cpp +++ b/TombEngine/Specific/setup.cpp @@ -408,7 +408,7 @@ void InitialiseObjects() obj->usingDrawAnimatingItem = true; obj->semiTransparent = false; obj->undead = false; - obj->zoneType = ZONE_NULL; + obj->ZoneType = ZoneType::None; obj->biteOffset = -1; obj->meshSwapSlot = NO_ITEM; obj->isPickup = false; diff --git a/TombEngine/Specific/setup.h b/TombEngine/Specific/setup.h index 46dd723a3..29e28945c 100644 --- a/TombEngine/Specific/setup.h +++ b/TombEngine/Specific/setup.h @@ -4,9 +4,9 @@ #include "Specific/level.h" #include "Renderer/Renderer11Enums.h" -struct ItemInfo; +enum class ZoneType; struct CollisionInfo; -enum ZoneType : char; +struct ItemInfo; constexpr auto DEFAULT_RADIUS = 10; constexpr auto ROT_X = 0x0004; @@ -44,7 +44,7 @@ struct ObjectInfo std::function ceilingBorder; std::function drawRoutine; std::function collision; - ZoneType zoneType; + ZoneType ZoneType; int animIndex; short HitPoints; short pivotLength; diff --git a/TombEngine/Specific/trmath.cpp b/TombEngine/Specific/trmath.cpp new file mode 100644 index 000000000..a4b31a125 --- /dev/null +++ b/TombEngine/Specific/trmath.cpp @@ -0,0 +1,422 @@ +#include "framework.h" +#include "Specific/trmath.h" +#include "Specific/prng.h" +#include + +#include "Specific/prng.h" + +using namespace TEN::Math::Random; + +short ANGLE(float angle) +{ + return angle * 65536.0f / 360.0f; +} + +short FROM_DEGREES(float angle) +{ + return angle * 65536.0f / 360.0f; +} + +short FROM_RAD(float angle) +{ + return angle / RADIAN * 65536.0f / 360.0f; +} + +float TO_DEGREES(short angle) +{ + return lround(angle * 360.0f / 65536.0f); +} + +float TO_RAD(short angle) +{ + return angle * 360.0f / 65536.0f * RADIAN; +} + +const Vector3 GetRandomVector() +{ + auto vector = Vector3(GenerateFloat(-1, 1), GenerateFloat(-1, 1), GenerateFloat(-1, 1)); + vector.Normalize(); + return vector; +} + +const Vector3 GetRandomVectorInCone(const Vector3& direction, const float angleDegrees) +{ + float x = GenerateFloat(-angleDegrees, angleDegrees) * RADIAN; + float y = GenerateFloat(-angleDegrees, angleDegrees) * RADIAN; + float z = GenerateFloat(-angleDegrees, angleDegrees) * RADIAN; + auto matrix = Matrix::CreateRotationX(x) * Matrix::CreateRotationY(y) * Matrix::CreateRotationZ(z); + + auto result = direction.TransformNormal(direction, matrix); + result.Normalize(); + return result; +} + +float phd_sin(short a) +{ + return sin(TO_RAD(a)); +} + +float phd_cos(short a) +{ + return cos(TO_RAD(a)); +} + +int mGetAngle(int x1, int y1, int x2, int y2) +{ + return (65536 - phd_atan(x2 - x1, y2 - y1)) % 65536; +} + +int phd_atan(int x, int y) +{ + return FROM_RAD(atan2(y, x)); +} + +EulerAngles GetVectorAngles(int x, int y, int z) +{ + const float angle = atan2(x, z); + + auto vector = Vector3(x, y, z); + const auto matrix = Matrix::CreateRotationY(-angle); + Vector3::Transform(vector, matrix, vector); + + return EulerAngles( + FROM_RAD(-atan2(y, vector.z)), + FROM_RAD(angle), + 0 + ); +} + +EulerAngles GetOrientBetweenPoints(Vector3i origin, Vector3i target) +{ + return GetVectorAngles(target.x - origin.x, target.y - origin.y, target.z - origin.z); +} + +short GetShortestAngularDistance(short angleFrom, short angleTo) +{ + return short(angleTo - angleFrom); +} + +int phd_Distance(PoseData* first, PoseData* second) +{ + return (int)round(Vector3::Distance(first->Position.ToVector3(), second->Position.ToVector3())); +} + +void phd_RotBoundingBoxNoPersp(PoseData* pos, BOUNDING_BOX* bounds, BOUNDING_BOX* tbounds) +{ + auto world = Matrix::CreateFromYawPitchRoll( + TO_RAD(pos->Orientation.y), + TO_RAD(pos->Orientation.x), + TO_RAD(pos->Orientation.z) + ); + + auto bMin = Vector3(bounds->X1, bounds->Y1, bounds->Z1); + auto bMax = Vector3(bounds->X2, bounds->Y2, bounds->Z2); + + bMin = Vector3::Transform(bMin, world); + bMax = Vector3::Transform(bMax, world); + + tbounds->X1 = bMin.x; + tbounds->X2 = bMax.x; + tbounds->Y1 = bMin.y; + tbounds->Y2 = bMax.y; + tbounds->Z1 = bMin.z; + tbounds->Z2 = bMax.z; +} + +void InterpolateAngle(short angle, short* rotation, short* outAngle, int shift) +{ + int deltaAngle = angle - *rotation; + + if (deltaAngle < -ANGLE(180.0f)) + deltaAngle += ANGLE(360.0f); + else if (deltaAngle > ANGLE(180.0f)) + deltaAngle -= ANGLE(360.0f); + + if (outAngle) + *outAngle = static_cast(deltaAngle); + + *rotation += static_cast(deltaAngle >> shift); +} + +void GetMatrixFromTrAngle(Matrix* matrix, short* framePtr, int index) +{ + short* ptr = &framePtr[0]; + + ptr += 9; + for (int i = 0; i < index; i++) + ptr += ((*ptr & 0xc000) == 0 ? 2 : 1); + + int rot0 = *ptr++; + int frameMode = (rot0 & 0xc000); + + int rot1; + int rotX; + int rotY; + int rotZ; + + switch (frameMode) + { + case 0: + rot1 = *ptr++; + rotX = ((rot0 & 0x3ff0) >> 4); + rotY = (((rot1 & 0xfc00) >> 10) | ((rot0 & 0xf) << 6) & 0x3ff); + rotZ = ((rot1) & 0x3ff); + + *matrix = Matrix::CreateFromYawPitchRoll(rotY * (360.0f / 1024.0f) * RADIAN, + rotX * (360.0f / 1024.0f) * RADIAN, + rotZ * (360.0f / 1024.0f) * RADIAN); + break; + + case 0x4000: + *matrix = Matrix::CreateRotationX((rot0 & 0xfff) * (360.0f / 4096.0f) * RADIAN); + break; + + case 0x8000: + *matrix = Matrix::CreateRotationY((rot0 & 0xfff) * (360.0f / 4096.0f) * RADIAN); + break; + + case 0xc000: + *matrix = Matrix::CreateRotationZ((rot0 & 0xfff) * (360.0f / 4096.0f) * RADIAN); + break; + } +} + +BoundingOrientedBox TO_DX_BBOX(PoseData pos, BOUNDING_BOX* box) +{ + auto boxCentre = Vector3((box->X2 + box->X1) / 2.0f, (box->Y2 + box->Y1) / 2.0f, (box->Z2 + box->Z1) / 2.0f); + auto boxExtent = Vector3((box->X2 - box->X1) / 2.0f, (box->Y2 - box->Y1) / 2.0f, (box->Z2 - box->Z1) / 2.0f); + auto rotation = Quaternion::CreateFromYawPitchRoll(TO_RAD(pos.Orientation.y), TO_RAD(pos.Orientation.x), TO_RAD(pos.Orientation.z)); + + BoundingOrientedBox result; + BoundingOrientedBox(boxCentre, boxExtent, Vector4::UnitY).Transform(result, 1, rotation, pos.Position.ToVector3()); + return result; +} + +__int64 FP_Mul(__int64 a, __int64 b) +{ + return (int)((((__int64)a * (__int64)b)) >> FP_SHIFT); +} + +__int64 FP_Div(__int64 a, __int64 b) +{ + return (int)(((a) / (b >> 8)) << 8); +} + +void FP_VectorMul(Vector3i* v, int scale, Vector3i* result) +{ + result->x = FP_FromFixed(v->x * scale); + result->y = FP_FromFixed(v->y * scale); + result->z = FP_FromFixed(v->z * scale); +} + +int FP_DotProduct(Vector3i* a, Vector3i* b) +{ + return ((a->x * b->x) + (a->y * b->y) + (a->z * b->z)) >> W2V_SHIFT; +} + +void FP_CrossProduct(Vector3i* a, Vector3i* b, Vector3i* result) +{ + result->x = ((a->y * b->z) - (a->z * b->y)) >> W2V_SHIFT; + result->y = ((a->z * b->x) - (a->x * b->z)) >> W2V_SHIFT; + result->z = ((a->x * b->y) - (a->y * b->x)) >> W2V_SHIFT; +} + +void FP_GetMatrixAngles(MATRIX3D* m, short* angles) +{ + short yaw = phd_atan(m->m22, m->m02); + short pitch = phd_atan(sqrt((m->m22 * m->m22) + (m->m02 * m->m02)), m->m12); + + int sy = phd_sin(yaw); + int cy = phd_cos(yaw); + short roll = phd_atan(((cy * m->m00) - (sy * m->m20)), ((sy * m->m21) - (cy * m->m01))); + + if ((m->m12 >= 0 && pitch > 0) || + (m->m12 < 0 && pitch < 0)) + { + pitch = -pitch; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = roll; +} + +__int64 FP_ToFixed(__int64 value) +{ + return (value << FP_SHIFT); +} + +__int64 FP_FromFixed(__int64 value) +{ + return (value >> FP_SHIFT); +} + +Vector3i* FP_Normalise(Vector3i* v) +{ + long a = v->x >> FP_SHIFT; + long b = v->y >> FP_SHIFT; + long c = v->z >> FP_SHIFT; + + if (a == 0 && b == 0 && c == 0) + return v; + + a = a * a; + b = b * b; + c = c * c; + long d = (a + b + c); + long e = sqrt(abs(d)); + + e <<= FP_SHIFT; + + long mod = FP_Div(FP_ONE << 8, e); + mod >>= 8; + + v->x = FP_Mul(v->x, mod); + v->y = FP_Mul(v->y, mod); + v->z = FP_Mul(v->z, mod); + + return v; +} + +const float Lerp(float v0, float v1, float t) +{ + return (1.0f - t) * v0 + t * v1; +} + +const float Smoothstep(float edge0, float edge1, float x) +{ + x = std::clamp(x, edge0, edge1); + + // Don't process if input value is the same as one of edges + if (x == edge0) + return edge0; + else if (x == edge1) + return edge1; + + // Scale, bias and saturate x to 0..1 range + x = std::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + + // Evaluate polynomial + return x * x * x * (x * (x * 6 - 15) + 10); +} + +const float Smoothstep(float x) +{ + return Smoothstep(0.0f, 1.0f, x); +} + +const float Luma(Vector3& color) +{ + // Use Rec.709 trichromat formula to get perceptive luma value + return (float)((color.x * 0.2126f) + (color.y * 0.7152f) + (color.z * 0.0722f)); +} + +const Vector4 Screen(Vector4& ambient, Vector4& tint) +{ + auto result = Screen(Vector3(ambient.x, ambient.y, ambient.z), Vector3(tint.x, tint.y, tint.z)); + return Vector4(result.x, result.y, result.z, ambient.w * tint.w); +} + +const Vector3 Screen(Vector3& ambient, Vector3& tint) +{ + auto luma = Luma(tint); + + auto multiplicative = ambient * tint; + auto additive = ambient + tint; + + auto R = (float)Lerp(multiplicative.x, additive.x, luma); + auto G = (float)Lerp(multiplicative.y, additive.y, luma); + auto B = (float)Lerp(multiplicative.z, additive.z, luma); + + return Vector3(R, G, B); +} + +Vector3 TranslateVector(Vector3& vector, short angle, float forward, float down, float right) +{ + if (forward == 0.0f && down == 0.0f && right == 0.0f) + return vector; + + float sinAngle = phd_sin(angle); + float cosAngle = phd_cos(angle); + + return Vector3( + vector.x + (forward * sinAngle) + (right * cosAngle), + vector.y + down, + vector.z + (forward * cosAngle) - (right * sinAngle) + ); +} + +Vector3i TranslateVector(Vector3i& vector, short angle, float forward, float down, float right) +{ + auto newVector = TranslateVector(vector.ToVector3(), angle, forward, down, right); + return Vector3i( + (int)round(newVector.x), + (int)round(newVector.y), + (int)round(newVector.z) + ); +} + +Vector3 TranslateVector(Vector3& vector, EulerAngles& orient, float distance) +{ + if (distance == 0.0f) + return vector; + + float sinX = phd_sin(orient.x); + float cosX = phd_cos(orient.x); + float sinY = phd_sin(orient.y); + float cosY = phd_cos(orient.y); + + return Vector3( + vector.x + distance * (sinY * cosX), + vector.y - distance * sinX, + vector.z + distance * (cosY * cosX) + ); +} + +Vector3i TranslateVector(Vector3i& vector, EulerAngles& orient, float distance) +{ + auto newVector = TranslateVector(vector.ToVector3(), orient, distance); + return Vector3i( + (int)round(newVector.x), + (int)round(newVector.y), + (int)round(newVector.z) + ); +} + +Vector3 TranslateVector(Vector3& vector, Vector3& direction, float distance) +{ + direction.Normalize(); + vector += direction * distance; + return vector; +} + +Vector3i TranslateVector(Vector3i& vector, Vector3& direction, float distance) +{ + auto newVector = TranslateVector(vector.ToVector3(), direction, distance); + return Vector3i( + (int)round(newVector.x), + (int)round(newVector.y), + (int)round(newVector.z) + ); +} + +bool IsPointInFront(const PoseData& pose, const Vector3& target) +{ + return IsPointInFront(pose.Position.ToVector3(), target, pose.Orientation); +} + +bool IsPointInFront(const Vector3& origin, const Vector3& target, const EulerAngles& orient) +{ + float sinY = phd_sin(orient.y); + float cosY = phd_cos(orient.y); + + // The heading angle (Y only) direction vector: X = +sinY, Y = 0, Z = +cosY + auto headingDirection = Vector3(sinY, 0.0f, cosY); + auto targetDirection = target - origin; + + float dot = headingDirection.Dot(targetDirection); + if (dot > 0.0f) + return true; + + return false; +}