This repository has been archived by the owner. It is now read-only.
Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Merge pull request #700 from Sergeanur/VC/Stinger
Stinger done
- Loading branch information
Showing
with
277 additions
and 0 deletions.
- +232 −0 src/objects/Stinger.cpp
- +40 −0 src/objects/Stinger.h
- +4 −0 src/peds/CopPed.cpp
- +1 −0 src/peds/CopPed.h
There are no files selected for viewing
| @@ -0,0 +1,232 @@ | ||
| #include "common.h" | ||
| #include "Stinger.h" | ||
| #include "CopPed.h" | ||
| #include "ModelIndices.h" | ||
| #include "RpAnimBlend.h" | ||
| #include "World.h" | ||
| #include "Automobile.h" | ||
| #include "Bike.h" | ||
| #include "Particle.h" | ||
| #include "AnimBlendAssociation.h" | ||
| #include "General.h" | ||
|
|
||
| uint32 NumOfStingerSegments; | ||
|
|
||
| /* -- CStingerSegment -- */ | ||
|
|
||
| CStingerSegment::CStingerSegment() | ||
| { | ||
| m_fMass = 1.0f; | ||
| m_fTurnMass = 1.0f; | ||
| m_fAirResistance = 0.99999f; | ||
| m_fElasticity = 0.75f; | ||
| m_fBuoyancy = GRAVITY * m_fMass * 0.1f; | ||
| bExplosionProof = true; | ||
| SetModelIndex(MI_PLC_STINGER); | ||
| ObjectCreatedBy = ESCALATOR_OBJECT; | ||
| NumOfStingerSegments++; | ||
| } | ||
|
|
||
| CStingerSegment::~CStingerSegment() | ||
| { | ||
| NumOfStingerSegments--; | ||
| } | ||
|
|
||
| /* -- CStinger -- */ | ||
|
|
||
| CStinger::CStinger() | ||
| { | ||
| bIsDeployed = false; | ||
| } | ||
|
|
||
| void | ||
| CStinger::Init(CPed *pPed) | ||
| { | ||
| int32 i; | ||
|
|
||
| pOwner = pPed; | ||
| for (i = 0; i < NUM_STINGER_SEGMENTS; i++) { | ||
| pSpikes[i] = new CStingerSegment; | ||
| pSpikes[i]->bUsesCollision = false; | ||
| } | ||
| bIsDeployed = true; | ||
| m_vPos = pPed->GetPosition(); | ||
| m_fMax_Z = Atan2(-pPed->GetForward().x, pPed->GetForward().y) + HALFPI; | ||
|
|
||
| for (i = 0; i < NUM_STINGER_SEGMENTS; i++) { | ||
| pSpikes[i]->SetOrientation(0.0f, 0.0f, Atan2(-pPed->GetForward().x, pPed->GetForward().y)); | ||
| pSpikes[i]->SetPosition(m_vPos); | ||
| } | ||
|
|
||
| CVector2D fwd2d(pPed->GetForward().x, pPed->GetForward().y); | ||
|
|
||
| for (i = 0; i < ARRAY_SIZE(m_vPositions); i++) | ||
| m_vPositions[i] = fwd2d * Sin(DEGTORAD(i)); | ||
|
|
||
| m_nSpikeState = STINGERSTATE_NONE; | ||
| m_nTimeOfDeploy = CTimer::GetTimeInMilliseconds(); | ||
| } | ||
|
|
||
| void | ||
| CStinger::Remove() | ||
| { | ||
| if (!bIsDeployed) return; | ||
|
|
||
| for (int32 i = 0; i < NUM_STINGER_SEGMENTS; i++) { | ||
| CStingerSegment *spikeSegment = pSpikes[i]; | ||
| if (spikeSegment->m_entryInfoList.first != nil) | ||
| spikeSegment->bRemoveFromWorld = true; | ||
| else | ||
| delete spikeSegment; | ||
| } | ||
| bIsDeployed = false; | ||
| } | ||
|
|
||
| void | ||
| CStinger::Deploy(CPed *pPed) | ||
| { | ||
| if (NumOfStingerSegments < NUM_STINGER_SEGMENTS*2 && !pPed->bInVehicle && pPed->IsPedInControl()) { | ||
| if (!bIsDeployed && RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_WEAPON_THROWU) == nil) { | ||
| Init(pPed); | ||
| pPed->SetPedState(PED_DEPLOY_STINGER); | ||
| CAnimManager::AddAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROWU); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void | ||
| CStinger::CheckForBurstTyres() | ||
| { | ||
| const CVector firstPos = pSpikes[0]->GetPosition(); | ||
| const CVector lastPos = pSpikes[NUM_STINGER_SEGMENTS - 1]->GetPosition(); | ||
| float dist = (lastPos - firstPos).Magnitude(); | ||
| if (dist > 0.1f) return; | ||
|
|
||
| CVehicle *vehsInRange[16]; | ||
| int16 numObjects; | ||
| CEntity entity; | ||
|
|
||
| CWorld::FindObjectsInRange((lastPos + firstPos) / 2.0f, | ||
| dist, true, &numObjects, 15, (CEntity**)vehsInRange, | ||
| false, true, false, false, false); | ||
|
|
||
| for (int32 i = 0; i < numObjects; i++) { | ||
| CAutomobile *pAutomobile = nil; | ||
| CBike *pBike = nil; | ||
|
|
||
| if (vehsInRange[i]->IsCar()) | ||
| pAutomobile = (CAutomobile*)vehsInRange[i]; | ||
| else if (vehsInRange[i]->IsBike()) | ||
| pBike = (CBike*)vehsInRange[i]; | ||
|
|
||
| if (pAutomobile == nil && pBike == nil) continue; | ||
|
|
||
| int wheelId = 0; | ||
| float wheelScaleSq = sq(((CVehicleModelInfo*)CModelInfo::GetModelInfo(vehsInRange[i]->GetModelIndex()))->m_wheelScale); | ||
|
|
||
| for (; wheelId < 4; wheelId++) { | ||
| if ((pAutomobile != nil && pAutomobile->m_aSuspensionSpringRatioPrev[wheelId] < 1.0f) || | ||
| (pBike != nil && pBike->m_aSuspensionSpringRatioPrev[wheelId] < 1.0f)) | ||
| break; | ||
| } | ||
|
|
||
| if (wheelId >= 4) continue; | ||
|
|
||
| CVector vecWheelPos; | ||
| if (pAutomobile != nil) | ||
| vecWheelPos = pAutomobile->m_aWheelColPoints[wheelId].point; | ||
| else if (pBike != nil) | ||
| vecWheelPos = pBike->m_aWheelColPoints[wheelId].point; | ||
|
|
||
| for (int32 spike = 0; spike < NUM_STINGER_SEGMENTS; spike++) { | ||
| if ((pSpikes[spike]->GetPosition() - vecWheelPos).Magnitude() < wheelScaleSq) { | ||
| if (pBike) { | ||
| if (wheelId < 2) | ||
| vehsInRange[i]->BurstTyre(CAR_PIECE_WHEEL_LF, true); | ||
| else | ||
| vehsInRange[i]->BurstTyre(CAR_PIECE_WHEEL_LR, true); | ||
| } else { | ||
| switch (wheelId) { | ||
| case 0: vehsInRange[i]->BurstTyre(CAR_PIECE_WHEEL_LF, true); break; | ||
| case 1: vehsInRange[i]->BurstTyre(CAR_PIECE_WHEEL_LR, true); break; | ||
| case 2: vehsInRange[i]->BurstTyre(CAR_PIECE_WHEEL_RF, true); break; | ||
| case 3: vehsInRange[i]->BurstTyre(CAR_PIECE_WHEEL_RR, true); break; | ||
| } | ||
| } | ||
| vecWheelPos.z += 0.15f; // BUG? doesn't that break the burst of other tires? | ||
| for (int j = 0; j < 4; j++) | ||
| CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, vecWheelPos, vehsInRange[i]->GetRight() * 0.1f); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void | ||
| CStinger::Process() | ||
| { | ||
| switch (m_nSpikeState) | ||
| { | ||
| case STINGERSTATE_NONE: | ||
| if (pOwner != nil | ||
| && !pOwner->bInVehicle | ||
| && pOwner->GetPedState() == PED_DEPLOY_STINGER | ||
| && RpAnimBlendClumpGetAssociation(pOwner->GetClump(), ANIM_WEAPON_THROWU)->currentTime > 0.39f) | ||
| { | ||
| m_nSpikeState = STINGERSTATE_DEPLOYING; | ||
| for (int i = 0; i < NUM_STINGER_SEGMENTS; i++) | ||
| CWorld::Add(pSpikes[i]); | ||
| pOwner->SetIdle(); | ||
| } | ||
| break; | ||
| case STINGERSTATE_DEPLOYED: | ||
| if (pOwner != nil && pOwner->m_nPedType == PEDTYPE_COP) | ||
| ((CCopPed*)pOwner)->m_bThrowsSpikeTrap = false; | ||
| break; | ||
| case STINGERSTATE_UNDEPLOYING: | ||
| if (CTimer::GetTimeInMilliseconds() > m_nTimeOfDeploy + 2500) | ||
| m_nSpikeState = STINGERSTATE_REMOVE; | ||
| // no break | ||
| case STINGERSTATE_DEPLOYING: | ||
| if (m_nSpikeState == STINGERSTATE_DEPLOYING && CTimer::GetTimeInMilliseconds() > m_nTimeOfDeploy + 2500) | ||
| m_nSpikeState = STINGERSTATE_DEPLOYED; | ||
| else { | ||
| float progress = (CTimer::GetTimeInMilliseconds() - m_nTimeOfDeploy) / 2500.0f; | ||
| if (m_nSpikeState != STINGERSTATE_DEPLOYING) | ||
| progress = 1.0f - progress; | ||
|
|
||
| float degangle = progress * ARRAY_SIZE(m_vPositions); | ||
| float angle1 = m_fMax_Z + DEGTORAD(degangle); | ||
| float angle2 = m_fMax_Z - DEGTORAD(degangle); | ||
| int pos = clamp(degangle, 0, ARRAY_SIZE(m_vPositions)-1); | ||
|
|
||
| CVector2D pos2d = m_vPositions[pos]; | ||
| CVector pos3d = m_vPos; | ||
| CColPoint colPoint; | ||
| CEntity *pEntity; | ||
| if (CWorld::ProcessVerticalLine(CVector(pos3d.x, pos3d.y, pos3d.z - 10.0f), pos3d.z, colPoint, pEntity, true, false, false, false, true, false, nil)) | ||
| pos3d.z = colPoint.point.z + 0.15f; | ||
|
|
||
| angle1 = CGeneral::LimitRadianAngle(angle1); | ||
| angle2 = CGeneral::LimitRadianAngle(angle2); | ||
|
|
||
| for (int spike = 0; spike < NUM_STINGER_SEGMENTS; spike++) { | ||
| if (CWorld::TestSphereAgainstWorld(pos3d + CVector(pos2d.x, pos2d.y, 0.6f), 0.3f, nil, true, false, false, true, false, false)) | ||
| pos2d = CVector2D(0.0f, 0.0f); | ||
|
|
||
| if (spike % 2 == 0) { | ||
| pSpikes[spike]->SetOrientation(0.0f, 0.0f, angle1); | ||
| pos3d.x += pos2d.x; | ||
| pos3d.y += pos2d.y; | ||
| } else { | ||
| pSpikes[spike]->SetOrientation(0.0f, 0.0f, angle2); | ||
| } | ||
| pSpikes[spike]->SetPosition(pos3d); | ||
| } | ||
| } | ||
| break; | ||
| case STINGERSTATE_REMOVE: | ||
| Remove(); | ||
| break; | ||
| } | ||
| CheckForBurstTyres(); | ||
| } |
| @@ -0,0 +1,40 @@ | ||
| #pragma once | ||
|
|
||
| #include "Object.h" | ||
|
|
||
| class CStingerSegment : public CObject | ||
| { | ||
| public: | ||
| CStingerSegment(); | ||
| ~CStingerSegment(); | ||
| }; | ||
|
|
||
| #define NUM_STINGER_SEGMENTS (12) | ||
|
|
||
| class CStinger | ||
| { | ||
| enum { | ||
| STINGERSTATE_NONE = 0, | ||
| STINGERSTATE_DEPLOYING, | ||
| STINGERSTATE_DEPLOYED, | ||
| STINGERSTATE_UNDEPLOYING, | ||
| STINGERSTATE_REMOVE, | ||
| }; | ||
|
|
||
| bool bIsDeployed; | ||
| uint32 m_nTimeOfDeploy; | ||
| CVector m_vPos; | ||
| float m_fMax_Z; | ||
| float m_fMin_Z; | ||
| CVector2D m_vPositions[60]; | ||
| CStingerSegment *pSpikes[NUM_STINGER_SEGMENTS]; | ||
| class CPed *pOwner; | ||
| uint8 m_nSpikeState; | ||
| public: | ||
| CStinger(); | ||
| void Init(CPed *pPed); | ||
| void Remove(); | ||
| void Deploy(CPed *pPed); | ||
| void CheckForBurstTyres(); | ||
| void Process(); | ||
| }; |