diff options
Diffstat (limited to 'src/peds/Ped.cpp')
-rw-r--r-- | src/peds/Ped.cpp | 309 |
1 files changed, 280 insertions, 29 deletions
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 3524f8f6..33b31066 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -48,7 +48,6 @@ WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); } -WRAPPER int32 CPed::ProcessEntityCollision(CEntity*, CColPoint*) { EAXJMP(0x4CBB30); } WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); } WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); } @@ -68,7 +67,10 @@ WRAPPER void CPed::SetEnterCar(CVehicle*, uint32) { EAXJMP(0x4E0920); } WRAPPER bool CPed::WarpPedToNearEntityOffScreen(CEntity*) { EAXJMP(0x4E5570); } WRAPPER void CPed::SetExitCar(CVehicle*, uint32) { EAXJMP(0x4E1010); } +#define FEET_OFFSET 1.04f + #define NEW_WALK_AROUND_ALGORITHM +#define CANCELLABLE_CAR_ENTER CPed *gapTempPedList[50]; uint16 gnNumTempPedList; @@ -512,17 +514,17 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bObstacleShowedUpDuringKillObjective = false; bDuckAndCover = false; - m_ped_flagG1 = false; + bStillOnValidPoly = false; m_ped_flagG2 = true; m_ped_flagG4 = false; bStartWanderPathOnFoot = false; - m_ped_flagG10 = false; + bOnBoat = false; bBusJacked = false; bGonnaKillTheCarJacker = false; bFadeOut = false; bKnockedUpIntoAir = false; - m_ped_flagH2 = false; + bHitSteepSlope = false; m_ped_flagH4 = false; bClearObjective = false; m_ped_flagH10 = false; @@ -1891,7 +1893,7 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) bool stillGettingInOut = false; if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) - stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || m_ped_flagG10; + stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || bOnBoat; if (!stillGettingInOut) { m_fRotationCur = m_fRotationDest; @@ -2429,6 +2431,7 @@ CPed::CanPedJumpThis(CEntity *unused, CVector *damageNormal = nil) return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); } #else +bool CPed::CanPedJumpThis(CEntity *unused) { CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); @@ -3310,7 +3313,7 @@ CPed::CheckIfInTheAir(void) bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, nil); if (!foundGround && m_nPedState != PED_JUMP) { - pos.z -= 1.04f; + pos.z -= FEET_OFFSET; if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) foundGround = true; } @@ -9976,8 +9979,8 @@ CPed::ProcessControl(void) offsetToCheck = GetPosition(); offsetToCheck.z += 0.5f; - if (CWorld::ProcessVerticalLine(offsetToCheck, GetPosition().z - 1.04f, foundCol, foundEnt, true, true, false, true, false, false, false)) { - GetPosition().z = 1.04f + foundCol.point.z; + if (CWorld::ProcessVerticalLine(offsetToCheck, GetPosition().z - FEET_OFFSET, foundCol, foundEnt, true, true, false, true, false, false, false)) { + GetPosition().z = FEET_OFFSET + foundCol.point.z; GetMatrix().UpdateRW(); SetLanding(); bIsStanding = true; @@ -11802,7 +11805,7 @@ CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) ped->ReplaceWeaponWhenExitingVehicle(); - ped->m_ped_flagG10 = false; + ped->bOnBoat = false; if (ped->bBusJacked) { ped->SetFall(1500, ANIM_KO_SKID_BACK, false); ped->bBusJacked = false; @@ -13518,8 +13521,7 @@ LocalPosForWalkAround(CVector2D colMin, CVector2D colMax, int walkAround) { case 7: return CVector(colMin.x, colMin.y, 0.0f); default: - // case 9: - return CVector(0.0f, 0.0f, 0.0f); // just a placeholder, supposed to be -GetForward(); + return CVector(0.0f, 0.0f, 0.0f); } } #endif @@ -13588,11 +13590,11 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) objUpsideDown = false; } float oldRotDest = m_fRotationDest; +#ifndef NEW_WALK_AROUND_ALGORITHM float angleToFaceObjCenter = (objColCenter - GetPosition()).Heading(); float angleDiffBtwObjCenterAndForward = CGeneral::LimitRadianAngle(dirToSet - angleToFaceObjCenter); - - // What is the purpose of using this? float objTopRightHeading = Atan2(adjustedColMax.x - adjustedColMin.x, adjustedColMax.y - adjustedColMin.y); +#endif if (IsPlayer()) { if (FindPlayerPed()->m_fMoveSpeed <= 0.0f) @@ -13641,7 +13643,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) collidingThingChanged = false; } else { #else - CVector cornerToGo; + CVector cornerToGo = CVector(10.0f, 10.0f, 10.0f); int dirToGo; m_walkAroundType = 0; #endif @@ -13669,10 +13671,10 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) else { CVector tl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMax.y, 0.0f) - GetPosition(); cornerToGo = tl; - dirToGo = GetLocalDirection(tl); if (objIsSeekTarget && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { m_walkAroundType = 1; } else { + dirToGo = GetLocalDirection(tl); if (dirToGo == 1) m_walkAroundType = 0; // ALL of the next turns will be right turn else if (dirToGo == 3) @@ -13703,10 +13705,10 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) CVector tr = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMax.y, 0.0f) - GetPosition(); if (tr.Magnitude2D() < cornerToGo.Magnitude2D()) { cornerToGo = tr; - dirToGo = GetLocalDirection(tr); if (objIsSeekTarget && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { m_walkAroundType = 2; } else { + dirToGo = GetLocalDirection(tr); if (dirToGo == 1) m_walkAroundType = 2; // ALL of the next turns will be right turn else if (dirToGo == 3) @@ -13738,10 +13740,10 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) CVector br = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMin.y, 0.0f) - GetPosition(); if (br.Magnitude2D() < cornerToGo.Magnitude2D()) { cornerToGo = br; - dirToGo = GetLocalDirection(br); if (objIsSeekTarget && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { m_walkAroundType = 5; } else { + dirToGo = GetLocalDirection(br); if (dirToGo == 1) m_walkAroundType = 4; // ALL of the next turns will be right turn else if (dirToGo == 3) @@ -13773,10 +13775,10 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) CVector bl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMin.y, 0.0f) - GetPosition(); if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) { cornerToGo = bl; - dirToGo = GetLocalDirection(bl); if (objIsSeekTarget && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { m_walkAroundType = 6; } else { + dirToGo = GetLocalDirection(bl); if (dirToGo == 1) m_walkAroundType = 6; // ALL of the next turns will be right turn else if (dirToGo == 3) @@ -13786,7 +13788,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) } #else } -#endif + if (entityOnTopLeftOfObj && entityOnTopRightOfObj && entityOnBottomRightOfObj && entityOnBottomLeftOfObj) { collidingThingChanged = false; entityOnTopLeftOfObj = 0; @@ -13795,7 +13797,6 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) entityOnBottomRightOfObj = 0; } -#ifndef NEW_WALK_AROUND_ALGORITHM if (!collidingThingChanged) { m_walkAroundType = 0; } else { @@ -13879,15 +13880,25 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) nextWalkAround = 7; } - if (CGeneral::GetRandomNumber() & 1){ - bool nextRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, nextWalkAround), - true, true, true, true, true, true, false); - if(nextRouteIsClear) - m_walkAroundType = nextWalkAround; - } else { - bool currentRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType), + CVector nextPosToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, nextWalkAround); + bool nextRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), nextPosToHead, true, true, true, true, true, true, false); + + if(nextRouteIsClear) + m_walkAroundType = nextWalkAround; + else { + CVector posToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType); + bool currentRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), posToHead, true, true, true, true, true, true, false); - if (!currentRouteIsClear) { + + /* Either; + * - Some obstacle came in and it's impossible to reach current destination + * - We reached to the destination, but since next route is not clear, we're turning around us + */ + if (!currentRouteIsClear || + ((posToHead - GetPosition()).Magnitude2D() < 0.8f && + !CWorld::GetIsLineOfSightClear(GetPosition() + GetForward(), nextPosToHead, + true, true, true, true, true, true, false))) { + // Change both target and direction (involves changing even/oddness) if (m_walkAroundType % 2 == 0) { m_walkAroundType -= 2; @@ -13897,7 +13908,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) m_walkAroundType += 1; } else { m_walkAroundType += 2; - if (m_walkAroundType > 6) + if (m_walkAroundType > 7) m_walkAroundType = 0; else m_walkAroundType -= 1; @@ -14030,6 +14041,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) m_actionY = localPosToHead.y; localPosToHead -= GetPosition(); m_fRotationDest = CGeneral::LimitRadianAngle(localPosToHead.Heading()); + if (m_fRotationDest != m_fRotationCur && bHitSomethingLastFrame) { if (m_fRotationDest == oldRotDest) { m_fRotationDest = oldRotDest; @@ -14047,6 +14059,243 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 280.0f * dist * checkIntervalInTime; } +int32 +CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) +{ + bool collidedWithBoat = false; + bool belowTorsoCollided = false; + float gravityEffect = -0.15f * CTimer::GetTimeStep(); + CColPoint intersectionPoint; + CColLine ourLine; + + CColModel *ourCol = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); + CColModel *hisCol = CModelInfo::GetModelInfo(collidingEnt->m_modelIndex)->GetColModel(); + + if (!bUsesCollision) + return false; + + if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) + collidedWithBoat = true; + + if (!field_EF && !m_phy_flagA80 +#ifdef VC_PED_PORTS + && !collidingEnt->IsPed() +#endif + ) { + if (!bCollisionProcessed) { +#ifdef VC_PED_PORTS + m_pCurrentPhysSurface = nil; +#endif + if (bIsStanding) { + bIsStanding = false; + m_ped_flagA2 = true; + } + bCollisionProcessed = true; + m_fCollisionSpeed += m_vecMoveSpeed.Magnitude2D() * CTimer::GetTimeStep(); + bStillOnValidPoly = false; + if (IsPlayer() || m_fCollisionSpeed >= 1.0f + && (m_fCollisionSpeed >= 2.0f || m_nPedState != PED_WANDER_PATH)) { + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + bHitSteepSlope = false; + } else { + CVector pos = GetPosition(); + float potentialGroundZ = GetPosition().z - FEET_OFFSET; + if (m_ped_flagA2) { + pos.z += -0.25f; + potentialGroundZ += gravityEffect; + } + if (CCollision::IsStoredPolyStillValidVerticalLine(pos, potentialGroundZ, intersectionPoint, &m_collPoly)) { + bStillOnValidPoly = true; + // VC conditionally sets GetPosition().z here with nonexisting flag in III + GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; + m_vecMoveSpeed.z = 0.0f; + bIsStanding = true; + } else { + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + bHitSteepSlope = false; + } + } + } + + if (!bStillOnValidPoly) { + CVector potentialCenter = GetPosition(); + potentialCenter.z = GetPosition().z - 0.52f; + + // 0.52f should be a ped's approx. radius + float totalRadiusWhenCollided = collidingEnt->GetBoundRadius() + 0.52f - gravityEffect; + if (m_ped_flagA2) { + if (collidedWithBoat) { + potentialCenter.z += 2.0f * gravityEffect; + totalRadiusWhenCollided += Abs(gravityEffect); + } else { + potentialCenter.z += gravityEffect; + } + } + if (sq(totalRadiusWhenCollided) > (potentialCenter - collidingEnt->GetBoundCentre()).MagnitudeSqr()) { + ourLine.p0 = GetPosition(); + ourLine.p1 = GetPosition(); + ourLine.p1.z = GetPosition().z - FEET_OFFSET; + if (m_ped_flagA2) { + ourLine.p1.z = ourLine.p1.z + gravityEffect; + ourLine.p0.z = ourLine.p0.z + -0.25f; + } + float minDist = 1.0f; + belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, + intersectionPoint, minDist, false, &m_collPoly); + + if (collidedWithBoat && m_ped_flagA2 && !belowTorsoCollided) { + ourLine.p0.z = ourLine.p1.z; + ourLine.p1.z = ourLine.p1.z + gravityEffect; + belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, + intersectionPoint, minDist, false, &m_collPoly); + } + if (belowTorsoCollided) { +#ifndef VC_PED_PORTS + if (!collidingEnt->IsPed()) { +#endif + if (!bIsStanding + || FEET_OFFSET + intersectionPoint.point.z > GetPosition().z + || collidedWithBoat && 3.12f + intersectionPoint.point.z > GetPosition().z) { + + if (!collidingEnt->IsVehicle() && !collidingEnt->IsObject()) { + m_pCurSurface = collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); + m_ped_flagH10 = false; + bOnBoat = false; + } else { + m_pCurrentPhysSurface = collidingEnt; + collidingEnt->RegisterReference((CEntity**)m_pCurrentPhysSurface); + m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition(); + m_pCurSurface = collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); + m_collPoly.valid = false; + if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) { + bOnBoat = true; + } else { + bOnBoat = false; + } + } + // VC conditionally sets GetPosition().z here with nonexisting flag in III + GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; + m_nSurfaceTouched = intersectionPoint.surfaceB; + if (m_nSurfaceTouched == SURFACE_STONE) { + bHitSteepSlope = true; + m_vecDamageNormal = intersectionPoint.normal; + } + } +#ifdef VC_PED_PORTS + float upperSpeedLimit = 0.33f; + float lowerSpeedLimit = -0.25f; + float speed = m_vecMoveSpeed.Magnitude2D(); + if (m_nPedState == PED_IDLE) { + upperSpeedLimit *= 2.0f; + lowerSpeedLimit *= 1.5f; + } + if (m_ped_flagA2 + || (speed <= upperSpeedLimit /* || (bfFlagsL >> 5) & 1 */) && m_vecMoveSpeed.z >= lowerSpeedLimit + || m_pCollidingEntity == collidingEnt) { + + if (!m_ped_flagA2 && RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL) + && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { + InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 15.0f, PEDPIECE_TORSO, 2); + } + } else { + float damage = 100.0f * max(speed - 0.25f, 0.0f); + float damage2 = damage; + if (m_vecMoveSpeed.z < -0.25f) + damage += (-0.25f - m_vecMoveSpeed.z) * 150.0f; + + uint8 dir = 2; // from backward + if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f + || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { + CVector2D offset = -m_vecMoveSpeed; + dir = GetLocalDirection(offset); + } + InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, damage, PEDPIECE_TORSO, dir); + if (IsPlayer() && damage2 > 5.0f) + Say(SOUND_PED_LAND); + } +#else + float speedSqr = m_vecMoveSpeed.MagnitudeSqr(); + if (m_ped_flagA2 + || m_vecMoveSpeed.z >= -0.25f && speedSqr <= 0.25f) { + if (!m_ped_flagA2 && RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL) + && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { + InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 15.0f, PEDPIECE_TORSO, 2); + } + } else { + if (speedSqr == 0.0f) + speedSqr = sq(m_vecMoveSpeed.z); + + uint8 dir = 2; // from backward + if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f + || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { + CVector2D offset = -m_vecMoveSpeed; + dir = GetLocalDirection(offset); + } + InflictDamage(collidingEnt, WEAPONTYPE_FALL_DAMAGE, 350.0f * sq(speedSqr), PEDPIECE_TORSO, dir); + } +#endif + m_vecMoveSpeed.z = 0.0f; + bIsStanding = true; +#ifndef VC_PED_PORTS + } else { + bOnBoat = false; + } +#endif + } else { + bOnBoat = false; + } + } + } + } + + int ourCollidedSpheres = CCollision::ProcessColModels(GetMatrix(), *ourCol, collidingEnt->GetMatrix(), *hisCol, collidingPoints, nil, nil); + if (ourCollidedSpheres > 0 || belowTorsoCollided) { + AddCollisionRecord(collidingEnt); + if (!collidingEnt->IsBuilding()) + ((CPhysical*)collidingEnt)->AddCollisionRecord(this); + + if (ourCollidedSpheres > 0 && (collidingEnt->IsBuilding() || collidingEnt->bIsStatic)) { + bHasHitWall = true; + } + } + if (collidingEnt->IsBuilding() || collidingEnt->bIsStatic) { + + if (m_ped_flagA2) { + CVector sphereNormal; + float normalLength; + for(int sphere = 0; sphere < ourCollidedSpheres; sphere++) { + sphereNormal = collidingPoints[sphere].normal; +#ifdef VC_PED_PORTS + if (sphereNormal.z >= -1.0f || !IsPlayer()) { +#endif + normalLength = sphereNormal.Magnitude2D(); + if (normalLength != 0.0f) { + sphereNormal.x = sphereNormal.x / normalLength; + sphereNormal.y = sphereNormal.y / normalLength; + } +#ifdef VC_PED_PORTS + } else { + float speed = m_vecMoveSpeed.Magnitude2D(); + sphereNormal.x = -m_vecMoveSpeed.x / max(0.001f, speed); + sphereNormal.y = -m_vecMoveSpeed.y / max(0.001f, speed); + GetPosition().z -= 0.05f; + // VC sets bKnockedUpIntoAir here + } +#endif + sphereNormal.Normalise(); + collidingPoints[sphere].normal = sphereNormal; + if (collidingPoints[sphere].surfaceB == SURFACE_STONE) + bHitSteepSlope = true; + } + } + } + return ourCollidedSpheres; +} + class CPed_ : public CPed { public: @@ -14060,6 +14309,7 @@ public: void Teleport_(CVector pos) { CPed::Teleport(pos); } void ProcessControl_(void) { CPed::ProcessControl(); } void Render_(void) { CPed::Render(); } + int32 ProcessEntityCollision_(CEntity *collidingEnt, CColPoint *collidingPoints) { return CPed::ProcessEntityCollision(collidingEnt, collidingPoints); } }; STARTPATCHES @@ -14072,6 +14322,7 @@ STARTPATCHES InjectHook(0x4D3E70, &CPed_::Teleport_, PATCH_JUMP); InjectHook(0x4C8910, &CPed_::ProcessControl_, PATCH_JUMP); InjectHook(0x4D03F0, &CPed_::Render_, PATCH_JUMP); + InjectHook(0x4CBB30, &CPed_::ProcessEntityCollision_, PATCH_JUMP); InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP); InjectHook(0x4C6AA0, &CPed::AimGun, PATCH_JUMP); |