5204 lines
172 KiB
C++
5204 lines
172 KiB
C++
// File header
|
|
#include "Task/Weapons/TaskProjectile.h"
|
|
|
|
// Game headers
|
|
#include "animation/MovePed.h"
|
|
#include "Camera/CamInterface.h"
|
|
#include "camera/gameplay/GameplayDirector.h"
|
|
#include "debug/DebugScene.h"
|
|
#include "Event/EventDamage.h"
|
|
#include "Event/Events.h"
|
|
#include "fwscene/stores/framefilterdictionarystore.h"
|
|
#include "grcore/debugdraw.h"
|
|
#include "Network/General/NetworkPendingProjectiles.h"
|
|
#include "network/Objects/Entities/NetObjPlayer.h"
|
|
#include "Peds/Ped.h"
|
|
#include "Peds/PedIntelligence.h"
|
|
#include "Peds/Ped.h"
|
|
#include "physics/WorldProbe/worldprobe.h"
|
|
#include "scene/world/GameWorld.h"
|
|
#include "script/script_hud.h"
|
|
#include "Task/Combat/Cover/TaskCover.h"
|
|
#include "Task/Combat/TaskCombat.h"
|
|
#include "Task/Default/TaskPlayer.h"
|
|
#include "Task/Motion/Locomotion/TaskCombatRoll.h"
|
|
#include "Task/Motion/Locomotion/TaskLocomotion.h"
|
|
#include "Task/Motion/Locomotion/TaskMotionAiming.h"
|
|
#include "Task/Motion/Locomotion/TaskMotionPed.h"
|
|
#include "Task/Motion/TaskMotionBase.h"
|
|
#include "Task/Movement/TaskSlideToCoord.h"
|
|
#include "Task/Weapons/TaskBomb.h"
|
|
#include "Task/Weapons/TaskSwapWeapon.h"
|
|
#include "Task/Weapons/TaskWeaponBlocked.h"
|
|
#include "Task/Weapons/Gun/TaskAimGunOnFoot.h"
|
|
#include "Weapons/projectiles/Projectile.h"
|
|
#include "Weapons/projectiles/ProjectileManager.h"
|
|
#include "Weapons/ThrownWeaponInfo.h"
|
|
#include "Weapons/Weapon.h"
|
|
#include "camera/gameplay/aim/FirstPersonShooterCamera.h"
|
|
|
|
// Macro to disable optimizations if set
|
|
AI_OPTIMISATIONS()
|
|
AI_WEAPON_OPTIMISATIONS()
|
|
|
|
// Constants
|
|
const float PLAYER_DEFAULT_PROJECTILE_VELOCITY = 33.0f;
|
|
const float AI_DEFAULT_PROJECTILE_VELOCITY = 17.0f;
|
|
const float PED_AIM_OFFSET_Z = 0.05f;
|
|
const float MIN_PROJECTILE_VELOCITY = 10.0f;
|
|
const float MIN_PROJECTILE_DISTANCE = 5.0f;
|
|
const float MAX_PROJECTILE_DISTANCE = 25.0f;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CThrowProjectileHelper
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
bool CThrowProjectileHelper::CalculateAimTrajectory(CPed* pPed, const Vector3& vStart, const Vector3& vTarget, const Vector3& vTargetVelocity, Vector3& vTrajectory)
|
|
{
|
|
const int NUMBER_TRAJECTORY_ATTEMPTS = 3;
|
|
|
|
float fProjectileVelocity = GetProjectileVelocity(pPed);
|
|
|
|
Vector3 vTargetPos(vTarget);
|
|
vTargetPos.z += PED_AIM_OFFSET_Z;
|
|
|
|
// Work out how far the target will have moved before the projectile hits, and add that onto the target pos
|
|
float fDistToTarget = (vTargetPos - vStart).Mag();
|
|
|
|
// Scale the velocity based on the target distance
|
|
float fProportion = Clamp((fDistToTarget - MIN_PROJECTILE_DISTANCE)/(MAX_PROJECTILE_DISTANCE - MIN_PROJECTILE_DISTANCE), 0.0f, 1.0f);
|
|
fProjectileVelocity = MIN_PROJECTILE_VELOCITY + ((fProjectileVelocity-MIN_PROJECTILE_VELOCITY)*fProportion);
|
|
|
|
// Start with a lower speed and try to adjust to hit the target avoiding any collisions
|
|
float fSpeed = fProjectileVelocity * 1.2f;
|
|
bool bValidTrajectoryFound = false;
|
|
|
|
float fTime = fDistToTarget / fProjectileVelocity;
|
|
Vector3 vAdjustedTarget = vTargetPos + ( vTargetVelocity * fTime );
|
|
|
|
// Try NUMBER_TRAJECTORY_ATTEMPTS times to avoid hitting anything
|
|
for(int i = 0; i < NUMBER_TRAJECTORY_ATTEMPTS; i++)
|
|
{
|
|
// Calculate the trajectory needed to hit the target with the desired speed
|
|
float fTime = CalculateAimTrajectoryWithSpeed(vStart, vAdjustedTarget, fSpeed, vTrajectory);
|
|
|
|
Vector3 vHalfwayPos = vStart + (vTrajectory * fTime * 0.5f) + (Vector3(0.0f, 0.0f, GRAVITY * 0.5f) * rage::square(fTime * 0.5f));
|
|
|
|
// Check the trajectory for collisions, if a collision occurs, try adjusting the speed
|
|
WorldProbe::CShapeTestProbeDesc probeDesc;
|
|
probeDesc.SetStartAndEnd(vStart, vHalfwayPos);
|
|
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES);
|
|
if(WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc))
|
|
{
|
|
if (pPed->GetIsInInterior())
|
|
// favour faster (lower) throws if indoors
|
|
fSpeed += fProjectileVelocity * 0.2f;
|
|
else
|
|
fSpeed -= fProjectileVelocity * 0.2f;
|
|
|
|
continue;
|
|
}
|
|
|
|
bValidTrajectoryFound = true;
|
|
break;
|
|
}
|
|
|
|
return bValidTrajectoryFound;
|
|
}
|
|
|
|
Vector3 CThrowProjectileHelper::GetPedThrowPosition(CPed* pPed, const fwMvClipId &clipId)
|
|
{
|
|
Vector3 vPos = GetThrowClipOffset(pPed, clipId);
|
|
vPos = pPed->TransformIntoWorldSpace(vPos);
|
|
|
|
#if __DEV
|
|
static bool RENDER_POSITION = false;
|
|
if(RENDER_POSITION)
|
|
{
|
|
grcDebugDraw::Sphere(vPos, 0.3f, Color_green, true);
|
|
}
|
|
#endif
|
|
|
|
return vPos;
|
|
}
|
|
|
|
float CThrowProjectileHelper::GetProjectileVelocity(CPed* pPed)
|
|
{
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
const CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon && pWeapon->GetWeaponInfo()->GetIsThrownWeapon())
|
|
{
|
|
return pWeapon->GetWeaponInfo()->GetProjectileForce();
|
|
}
|
|
|
|
if(pPed->IsAPlayerPed())
|
|
{
|
|
return PLAYER_DEFAULT_PROJECTILE_VELOCITY;
|
|
}
|
|
|
|
return AI_DEFAULT_PROJECTILE_VELOCITY;
|
|
}
|
|
|
|
bool CThrowProjectileHelper::IsPlayerPriming(const CPed* pPed)
|
|
{
|
|
bool bUseFPSAimIK = false;
|
|
#if FPS_MODE_SUPPORTED
|
|
bUseFPSAimIK = pPed->GetEquippedWeaponInfo() ? pPed->GetEquippedWeaponInfo()->GetUseFPSAimIK() : false;
|
|
#endif
|
|
|
|
if(pPed->IsLocalPlayer() FPS_MODE_SUPPORTED_ONLY( && (!bUseFPSAimIK || !pPed->IsFirstPersonShooterModeEnabledForPlayer(false))))
|
|
{
|
|
const CControl* pControl = pPed->GetControlFromPlayer();
|
|
if( pControl )
|
|
{
|
|
//const u8 PLAYER_FIRE_PROJECTILE_BOUNDARY = 190;
|
|
const float PLAYER_FIRE_PROJECTILE_BOUNDARY = 0.745f;
|
|
const float fAttackValue = MAX(pControl->GetPedAttack2().GetNorm(), pControl->GetPedAttack().GetNorm());
|
|
return fAttackValue >= PLAYER_FIRE_PROJECTILE_BOUNDARY;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CThrowProjectileHelper::IsPlayerRolling(const CPed* pPed)
|
|
{
|
|
if(pPed->IsLocalPlayer() && pPed->GetMotionData()->GetIsStrafing() && !pPed->GetMotionData()->GetIsStill())
|
|
{
|
|
const CControl* pControl = pPed->GetControlFromPlayer();
|
|
if( pControl )
|
|
{
|
|
return pControl->GetPedJump().IsPressed() && pPed->GetPedIntelligence()->GetCanCombatRoll();
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CThrowProjectileHelper::IsPlayerFiring(const CPed* pPed)
|
|
{
|
|
if(pPed->IsLocalPlayer() )
|
|
{
|
|
const CControl* pControl = pPed->GetControlFromPlayer();
|
|
if( pControl )
|
|
{
|
|
//const u8 PLAYER_FIRE_PROJECTILE_BOUNDARY = 190;
|
|
//@@: location CTHROWPROJECTILEHELPER_ISPLAYER_FIRING
|
|
const float PLAYER_FIRE_PROJECTILE_BOUNDARY = 0.745f;
|
|
const float fAttackValue = MAX(pControl->GetPedAttack2().GetNorm(), pControl->GetPedAttack().GetNorm());
|
|
return fAttackValue <= PLAYER_FIRE_PROJECTILE_BOUNDARY;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CThrowProjectileHelper::IsPlayerFirePressed(const CPed* pPed)
|
|
{
|
|
if(pPed->IsLocalPlayer() )
|
|
{
|
|
const CControl* pControl = pPed->GetControlFromPlayer();
|
|
if( pControl )
|
|
{
|
|
const float PLAYER_FIRE_PROJECTILE_BOUNDARY = 0.745f;
|
|
return pControl->GetPedAttack2().IsPressed(PLAYER_FIRE_PROJECTILE_BOUNDARY) || pControl->GetPedAttack().IsPressed(PLAYER_FIRE_PROJECTILE_BOUNDARY);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CThrowProjectileHelper::HasHeldProjectileTooLong(CPed* pPed, float fTimeHeld)
|
|
{
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
const CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon)
|
|
{
|
|
const CWeaponInfo* pWeaponInfo = pWeapon->GetWeaponInfo();
|
|
if(pWeaponInfo)
|
|
{
|
|
const float fFuseTime = pWeaponInfo->GetProjectileFuseTime();
|
|
if (fFuseTime > 0.0f)
|
|
return fTimeHeld > fFuseTime;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CThrowProjectileHelper::SetWeaponSlotAfterFiring(CPed* pPed)
|
|
{
|
|
Assert(pPed);
|
|
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
if(pPed->GetWeaponManager()->GetEquippedWeaponInfo() && pPed->GetWeaponManager()->GetEquippedWeaponInfo()->GetIsThrownWeapon()
|
|
#if 0 // CS
|
|
|| (pPed->GetWeaponManager()->GetEquippedWeaponHash() == WEAPONSLOT_SPECIAL && pPed->GetWeaponManager()->GetChosenWeaponType() == WEAPONTYPE_OBJECT)
|
|
#endif // 0
|
|
)
|
|
{
|
|
int nAmmo = pPed->GetInventory()->GetWeaponAmmo(pPed->GetWeaponManager()->GetEquippedWeaponInfo());
|
|
|
|
if(nAmmo == 0)
|
|
{
|
|
// Out of ammo - swap weapon
|
|
const CWeaponInfo* pWeaponInfo = pPed->GetWeaponManager()->GetEquippedWeaponInfo();
|
|
pPed->GetWeaponManager()->DropWeapon(pWeaponInfo->GetHash(), true);
|
|
|
|
// Don't equip a weapon if the dropped weapon was non lethal
|
|
if(pWeaponInfo && !pWeaponInfo->GetDontSwapWeaponIfNoAmmo())
|
|
{
|
|
if (pWeaponInfo->GetSwapToUnarmedWhenOutOfThrownAmmo())
|
|
{
|
|
pPed->GetWeaponManager()->EquipWeapon(pPed->GetDefaultUnarmedWeaponHash());
|
|
}
|
|
else
|
|
{
|
|
pPed->GetWeaponManager()->EquipBestWeapon();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Still have some ammo left - draw a new projectile
|
|
pPed->GetWeaponManager()->EquipWeapon(pPed->GetWeaponManager()->GetEquippedWeaponHash());
|
|
}
|
|
}
|
|
}
|
|
|
|
dev_float VERTICAL_DIFFERENCE_MULTIPLIER = 2.0f;
|
|
|
|
float CThrowProjectileHelper::CalculateAimTrajectoryWithSpeed(const Vector3& vStart, const Vector3& vTarget, const float fSpeed, Vector3& vTrajectory)
|
|
{
|
|
vTrajectory = vTarget - vStart;
|
|
|
|
const float f2dVelocity = fSpeed;
|
|
const float f2dDistance = vTrajectory.XYMag();
|
|
const float fTime = f2dDistance / f2dVelocity;
|
|
const float fHeightChange = -GRAVITY * rage::square(fTime);
|
|
const float fVerticalVelocity = (fHeightChange) + (vTrajectory.z*VERTICAL_DIFFERENCE_MULTIPLIER);
|
|
|
|
vTrajectory.z = 0.0f;
|
|
vTrajectory.Normalize();
|
|
vTrajectory.Scale(f2dVelocity);
|
|
vTrajectory.z += fVerticalVelocity;
|
|
|
|
return fTime;
|
|
}
|
|
|
|
Vector3 CThrowProjectileHelper::GetThrowClipOffset(CPed* UNUSED_PARAM(pPed), const fwMvClipId &clipId) // DEV_ONLY(pPed)
|
|
{
|
|
static fwMvClipId s_WeaponThrowLongClipId("grenade_throw_overarm",0x1C10DF01);
|
|
static fwMvClipId s_WeaponThrowShortClipId("grenade_throw_short",0x2E8019FC);
|
|
|
|
static Vector3 svShortAnimOffset(0.308427393f, -0.265351206f, 1.00279045f);
|
|
static Vector3 svLongAnimOffset (0.390442640f, -0.0503886044f, 0.148556828f);
|
|
//static bool bShortCalculated = false;
|
|
//static bool bLongCalculated = false;
|
|
|
|
//bool bCalculated = false;
|
|
Vector3* pvOffset = NULL;
|
|
|
|
if(clipId == s_WeaponThrowShortClipId)
|
|
{
|
|
//bCalculated = bShortCalculated;
|
|
pvOffset = &svShortAnimOffset;
|
|
//bShortCalculated = true;
|
|
}
|
|
else if(clipId == s_WeaponThrowLongClipId)
|
|
{
|
|
//bCalculated = bLongCalculated;
|
|
pvOffset = &svLongAnimOffset;
|
|
//bLongCalculated = true;
|
|
}
|
|
else
|
|
{
|
|
pvOffset = &svShortAnimOffset;
|
|
return *pvOffset;
|
|
}
|
|
|
|
Assert(pvOffset);
|
|
return *pvOffset;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CTaskAimAndThrowProjectile
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const fwMvRequestId CTaskAimAndThrowProjectile::ms_StartPrime("Prime",0x4CC8E30C);
|
|
const fwMvRequestId CTaskAimAndThrowProjectile::ms_StartReload("Reload",0x5DA46B68);
|
|
const fwMvRequestId CTaskAimAndThrowProjectile::ms_StartFinish("Finish",0xCB6420E3);
|
|
const fwMvRequestId CTaskAimAndThrowProjectile::ms_StartOutro("Outro",0x5D40B28D);
|
|
const fwMvRequestId CTaskAimAndThrowProjectile::ms_StartHold("Hold",0x981F195B);
|
|
const fwMvRequestId CTaskAimAndThrowProjectile::ms_StartDropPrime("DropPrime",0xB928EA79);
|
|
//FPS mode
|
|
const fwMvRequestId CTaskAimAndThrowProjectile::ms_FPSFidget("FPSFidget", 0xCCE4A656);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_UsingFPSMode("FPSMode",0x50E5C59C);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_HasBreatheHighAdditives("HasBreatheHighAdditives",0xD5ECF3B5);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_HasBwdAdditive("HasBwdAdditive",0x33F3E71E);
|
|
//End FPS Mode
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_SkipPullPinId("SkipPullPin",0x239DF644);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_DropProjectileFlagId("DropProjectileFlag",0x3C3CEA90);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_DoDropId("DoDrop",0x81362756);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_SkipIntroId("SkipIntro",0x4D7836E0);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_OverhandOnlyId("OverhandOnly",0xAD95CA85);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_UseThrowPlaceId("UseThrowPlace",0xBA541D80);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_UseDropUnderhandId("DropUnderhand",0xAC294D26);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_NoStaticDropId("NoStaticDrop",0x62bd6f70);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_IsRollingId("IsRolling",0x153c3a80);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_PitchPhase("PitchPhase",0xDA36894E);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_ThrowPitchPhase("ThrowPitchPhase",0xA472A004);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_ThrowPhase("ThrowPhase",0x9D46658E);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_ReloadPhase("ReloadPhase",0x24823469);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_TransitionPhase("TransitionPhase",0x5DD0E7EB);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_StrafeSpeed("StrafeSpeed",0x59A5FA46);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_DesiredStrafeSpeed("DesiredStrafeSpeed",0x8e945f2d);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_StrafeDirectionId("StrafeDirection",0xCF6AA9C6);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_GaitAdditive("GaitAdditive",0x31E5933F);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_GaitAdditiveTransPhase("GaitAdditiveTransPhase",0xDA38C1ED);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_ShadowWeight("ShadowWeight",0x243D1D53);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_PullPinPhase("PullPinPhase",0x182B6AA5);
|
|
//FPS Mode
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_AimingLeanAdditiveWeight("AimingLeanAdditiveWeight", 0x8F882A7);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_AimingBreathingAdditiveWeight("AimingBreathingAdditiveWeight", 0x4BCEE31D);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_UseGripClip("UseGripClip",0x72838804);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_StrafeSpeed_AdditiveId("StrafeSpeed_Additive",0xb4f01ffa);
|
|
const fwMvFloatId CTaskAimAndThrowProjectile::ms_StrafeDirection_AdditiveId("StrafeDirection_Additive",0xf72f7955);
|
|
//End FPS Mode
|
|
const fwMvBooleanId CTaskAimAndThrowProjectile::ms_ThrowCompleteEvent("ThrowComplete",0x4BFCEDBF);
|
|
const fwMvBooleanId CTaskAimAndThrowProjectile::ms_ReloadCompleteEvent("ReloadComplete",0x1CA52CBF);
|
|
const fwMvBooleanId CTaskAimAndThrowProjectile::ms_EnterIntroEvent("OnEnterIntro",0xE312777C);
|
|
const fwMvBooleanId CTaskAimAndThrowProjectile::ms_EnterHoldEvent("OnEnterHold",0xD7DF049F);
|
|
const fwMvBooleanId CTaskAimAndThrowProjectile::ms_EnterOutroEvent("OnEnterOutro",0x4CBE6874);
|
|
const fwMvBooleanId CTaskAimAndThrowProjectile::ms_ReloadEvent("OnEnterReload",0xB2573ED7);
|
|
//FPS Mode
|
|
const fwMvBooleanId CTaskAimAndThrowProjectile::ms_FPSReachPin("FPSReachPin",0x177D7851);
|
|
//End FPS Mode
|
|
const fwMvClipSetVarId CTaskAimAndThrowProjectile::ms_StreamedClipSet("StreamedClipSet",0x83D4FC68);
|
|
const fwMvFilterId CTaskAimAndThrowProjectile::ms_GripFilterId("GripFilter",0x57C40DEC);
|
|
const fwMvFilterId CTaskAimAndThrowProjectile::ms_FrameFilterId("FrameFilter",0x4BED5890);
|
|
const fwMvFilterId CTaskAimAndThrowProjectile::ms_PullPinFilterId("PullPinFilter",0x5BD0DFA8);
|
|
float CTaskAimAndThrowProjectile::m_sfThrowingMainMoverCapsuleRadius = 0.55f; //0.65f; retuned B* 493871
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_AimGunThrowId("IsAiming",0x9d10c0bd);
|
|
const fwMvFlagId CTaskAimAndThrowProjectile::ms_FPSCookingProjectile("FPSCookingProjectile",0xC45C0ACF);
|
|
|
|
CTaskAimAndThrowProjectile::Tunables CTaskAimAndThrowProjectile::sm_Tunables;
|
|
IMPLEMENT_WEAPON_TASK_TUNABLES(CTaskAimAndThrowProjectile, 0xf2077a8f);
|
|
|
|
CTaskAimAndThrowProjectile::CTaskAimAndThrowProjectile(const CWeaponTarget& targeting, CEntity* pIgnoreCollisionEntity, bool bCreateInvincibileProjectile
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
, bool bAimGunAndThrow, int iAmmoInClip, u32 uAimAndThrowWeaponHash, bool bProjectileThrownFromDPadInput
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
)
|
|
: m_target(targeting)
|
|
, m_pIgnoreCollisionEntity(pIgnoreCollisionEntity)
|
|
, m_bFire(false)
|
|
, m_bHasThrownProjectile(false)
|
|
, m_bPriming(false)
|
|
, m_bDropProjectile(false)
|
|
, m_bDropUnderhand(false)
|
|
, m_bForceStandingThrow(false)
|
|
, m_bFalseAiming(false)
|
|
, m_fTimeMoving(0.0f)
|
|
, m_fBlockAimingIndependentMoverTime(0.0f)
|
|
, m_fCurrentPitch(0.5f)
|
|
, m_fDesiredPitch(0.5f)
|
|
, m_fDesiredThrowPitch(0.5f)
|
|
, m_fThrowPitch(0.5f)
|
|
, m_fThrowPhase(0.5f)
|
|
, m_fReloadPhase(0.9f)
|
|
, m_fInterruptPhase(0.75f)
|
|
, m_fStrafeSpeed(-1.0f)
|
|
, m_fStrafeDirection(0.5f)
|
|
, m_fStrafeDirectionSignal(0)
|
|
, m_fCurrentShadowWeight(1.0f)
|
|
, m_pFrameFilter(NULL)
|
|
, m_pGripFrameFilter(NULL)
|
|
, m_pPullPinFilter(NULL)
|
|
, m_bIsAiming(false)
|
|
, m_bIsFiring(false)
|
|
, m_bHasCachedWeaponValues(false)
|
|
, m_bCanBePlaced(false)
|
|
, m_bPrimedButPlacing(false)
|
|
, m_bThrowPlace(false)
|
|
, m_bHasNoPullPin(false)
|
|
, m_bPinPulled(false)
|
|
, m_bWaitingToDie(false)
|
|
, m_bMoveTreeIsDropMode(false)
|
|
, m_bAllowPriming(false)
|
|
, m_bWasAiming(false)
|
|
, m_bHasTargetPosition(false)
|
|
, m_bPlayFPSTransition(false)
|
|
, m_bSkipFPSOutroState(false)
|
|
, m_bPlayFPSRNGIntro(false)
|
|
, m_bPlayFPSPullPinIntro(false)
|
|
, m_bPlayFPSFidget(false)
|
|
, m_bMoveFPSFidgetEnded(false)
|
|
, m_bFPSReachPinOnIntro(false)
|
|
, m_bFPSWantsToThrowWhenReady(false)
|
|
, m_bFPSUseAimIKForWeapon(false)
|
|
, m_pFPSWeaponMoveNetworkHelper(NULL)
|
|
, m_bFPSPlayingUnholsterIntro(false)
|
|
, m_bCreateInvincibileProjectile(bCreateInvincibileProjectile)
|
|
, m_LastLocalRollToken(0)
|
|
, m_LastCloneRollToken(0)
|
|
, m_vTargetPosition(VEC3_ZERO)
|
|
, m_vLastProjectilePos(VEC3_ZERO)
|
|
, m_NetworkDefId(fwMvNetworkDefId((u32)0))
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
, m_bAimGunAndThrow(bAimGunAndThrow)
|
|
, m_pTempWeaponObject(NULL)
|
|
, m_iBackupWeaponClipAmmo(iAmmoInClip)
|
|
, m_uAimAndThrowWeaponHash(uAimAndThrowWeaponHash)
|
|
, m_bProjectileThrownFromDPadInput(bProjectileThrownFromDPadInput)
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
, m_fFPSStateToTransitionBlendTime(-1.0f)
|
|
, m_fFPSTransitionToStateBlendTime(-1.0f)
|
|
, m_fStrafeSpeedAdditive(0.f)
|
|
, m_fStrafeDirectionAdditive(0.f)
|
|
, m_fFPSTaskNetworkBlendDuration(-1.0f)
|
|
, m_fFPSTaskNetworkBlendTimer(0.f)
|
|
, m_fFPSDropThrowSwitchTimer(-1.0f)
|
|
{
|
|
SetInternalTaskType(CTaskTypes::TASK_AIM_AND_THROW_PROJECTILE);
|
|
}
|
|
|
|
CTaskAimAndThrowProjectile::~CTaskAimAndThrowProjectile()
|
|
{
|
|
}
|
|
|
|
bool CTaskAimAndThrowProjectile::ProcessPostPreRender()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
|
|
if(!pPed->IsNetworkClone())
|
|
{
|
|
bool bFPSMode = false;
|
|
#if FPS_MODE_SUPPORTED
|
|
bFPSMode = pPed->IsFirstPersonShooterModeEnabledForPlayer(false);
|
|
bool pFPSPopPitch = bFPSMode && (pPed->GetMotionData()->GetWasFPSUnholster() || !pPed->GetMotionData()->GetWasUsingFPSMode());
|
|
#endif
|
|
UpdateAiming(pPed FPS_MODE_SUPPORTED_ONLY(, pFPSPopPitch));
|
|
if(!bFPSMode)
|
|
{
|
|
ProcessThrowProjectile();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// update MoVE params
|
|
if(m_MoveNetworkHelper.IsNetworkActive())
|
|
{
|
|
m_MoveNetworkHelper.SetFloat(ms_PitchPhase, m_fCurrentPitch);
|
|
m_MoveNetworkHelper.SetFloat(ms_ThrowPitchPhase, m_fThrowPitch);
|
|
if(m_bHasTargetPosition)
|
|
pPed->GetIkManager().PointGunAtPosition(m_vTargetPosition, -1.0f);
|
|
else
|
|
pPed->GetIkManager().PointGunInDirection(pPed->GetCurrentHeading(), 0.0f);
|
|
}
|
|
}
|
|
|
|
// update MoVE params
|
|
if (m_MoveNetworkHelper.IsNetworkActive())
|
|
{
|
|
if(m_pFrameFilter)
|
|
m_MoveNetworkHelper.SetFilter(m_pFrameFilter, ms_FrameFilterId);
|
|
|
|
if(m_pGripFrameFilter)
|
|
m_MoveNetworkHelper.SetFilter(m_pGripFrameFilter, ms_GripFilterId);
|
|
|
|
if(m_pPullPinFilter)
|
|
m_MoveNetworkHelper.SetFilter(m_pPullPinFilter, ms_PullPinFilterId);
|
|
|
|
if(!sm_Tunables.m_bEnableGaitAdditive)
|
|
m_MoveNetworkHelper.SetFloat(ms_GaitAdditive, 0.0f);
|
|
else
|
|
{
|
|
float gaitAdditivePhase = m_MoveNetworkHelper.GetFloat(ms_GaitAdditiveTransPhase);
|
|
if (gaitAdditivePhase >= 0.0f)
|
|
m_MoveNetworkHelper.SetFloat(ms_GaitAdditive, 1.0f-gaitAdditivePhase);
|
|
}
|
|
|
|
// update gait info:
|
|
Vector2 vDesiredMBR = pPed->GetMotionData()->GetGaitReducedDesiredMoveBlendRatio();
|
|
float fDesiredStrafeSpeed = vDesiredMBR.Mag() / MOVEBLENDRATIO_SPRINT;
|
|
|
|
Vector2 vCurrentMBR = pPed->GetMotionData()->GetCurrentMoveBlendRatio();
|
|
m_fStrafeSpeed = vCurrentMBR.Mag() / MOVEBLENDRATIO_SPRINT;
|
|
|
|
//Time moving is used to help determine if one should do a moving throw
|
|
if (m_fStrafeSpeed >= 0.3f)
|
|
m_fTimeMoving += fwTimer::GetTimeStep();
|
|
else
|
|
m_fTimeMoving = 0;
|
|
|
|
if (!pPed->IsStrafing() || (GetState()==State_ThrowProjectile && m_bForceStandingThrow))
|
|
{
|
|
m_fStrafeSpeed = 0.0f;
|
|
fDesiredStrafeSpeed = 0.0f;
|
|
}
|
|
|
|
m_MoveNetworkHelper.SetFloat(ms_StrafeSpeed, m_fStrafeSpeed);
|
|
m_MoveNetworkHelper.SetFloat(ms_DesiredStrafeSpeed, fDesiredStrafeSpeed);
|
|
|
|
static dev_float m_sfShadowWeightApproachRate = 3.0f;
|
|
if (m_bMoveTreeIsDropMode)
|
|
Approach(m_fCurrentShadowWeight, 0.0f, m_sfShadowWeightApproachRate, fwTimer::GetTimeStep());
|
|
else
|
|
Approach(m_fCurrentShadowWeight, 1.0f, m_sfShadowWeightApproachRate, fwTimer::GetTimeStep());
|
|
m_MoveNetworkHelper.SetFloat(ms_ShadowWeight, m_fCurrentShadowWeight);
|
|
|
|
|
|
m_fStrafeDirection = fwAngle::LimitRadianAngleSafe( atan2( vCurrentMBR.y, vCurrentMBR.x ) - HALF_PI );
|
|
float fStrafeSignal = CTaskMotionBasicLocomotion::ConvertRadianToSignal(m_fStrafeDirection);
|
|
static dev_float STRAFE_DIRECTION_APPROACH_RATE = 3.0f;
|
|
if (fabs(fStrafeSignal - m_fStrafeDirectionSignal)>0.5f)
|
|
{
|
|
if (m_fStrafeDirectionSignal > 0.5f)
|
|
{
|
|
m_fStrafeDirectionSignal -= 1.0f;
|
|
Approach(m_fStrafeDirectionSignal, fStrafeSignal, STRAFE_DIRECTION_APPROACH_RATE, fwTimer::GetTimeStep());
|
|
if (m_fStrafeDirectionSignal < 0)
|
|
m_fStrafeDirectionSignal +=1.0f;
|
|
} else
|
|
{
|
|
m_fStrafeDirectionSignal += 1.0f;
|
|
Approach(m_fStrafeDirectionSignal, fStrafeSignal, STRAFE_DIRECTION_APPROACH_RATE, fwTimer::GetTimeStep());
|
|
if (m_fStrafeDirectionSignal > 1.0f)
|
|
m_fStrafeDirectionSignal -=1.0f;
|
|
}
|
|
}
|
|
else
|
|
Approach(m_fStrafeDirectionSignal, fStrafeSignal, STRAFE_DIRECTION_APPROACH_RATE, fwTimer::GetTimeStep());
|
|
m_MoveNetworkHelper.SetFloat(ms_StrafeDirectionId, m_fStrafeDirectionSignal);
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false, true) && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
m_MoveNetworkHelper.SetFloat(ms_AimingLeanAdditiveWeight, 1.0f);
|
|
m_MoveNetworkHelper.SetFloat(ms_AimingBreathingAdditiveWeight, 1.0f);
|
|
|
|
m_MoveNetworkHelper.SetFloat(ms_StrafeSpeed_AdditiveId, m_fStrafeSpeedAdditive);
|
|
m_MoveNetworkHelper.SetFloat(ms_StrafeDirection_AdditiveId, CTaskMotionBase::ConvertRadianToSignal(m_fStrafeDirectionAdditive));
|
|
|
|
if(m_pFPSWeaponMoveNetworkHelper && m_pFPSWeaponMoveNetworkHelper->IsNetworkActive())
|
|
{
|
|
m_pFPSWeaponMoveNetworkHelper->SetFloat(ms_AimingLeanAdditiveWeight, 1.0f);
|
|
m_pFPSWeaponMoveNetworkHelper->SetFloat(ms_AimingBreathingAdditiveWeight, 1.0f);
|
|
|
|
m_pFPSWeaponMoveNetworkHelper->SetFloat(ms_StrafeSpeed, m_fStrafeSpeed);
|
|
m_pFPSWeaponMoveNetworkHelper->SetFloat(ms_StrafeDirectionId, m_fStrafeDirectionSignal);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
m_bWasAiming = IsAiming(pPed);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CTaskAimAndThrowProjectile::ProcessPostPreRenderAfterAttachments()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
if(!pPed->IsNetworkClone())
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false))
|
|
{
|
|
ProcessThrowProjectile();
|
|
}
|
|
#endif // FPS_MODE_SUPPORTED
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::ProcessThrowProjectile()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
|
|
Vector3 vStartOverride(VEC3_ZERO);
|
|
bool bOverrideStartPos = false;
|
|
bool bAimGunThrowInCoverInFPS = false;
|
|
#if FPS_MODE_SUPPORTED
|
|
bAimGunThrowInCoverInFPS = m_bAimGunAndThrow && pPed->GetIsInCover() && pPed->IsFirstPersonShooterModeEnabledForPlayer(false);
|
|
#endif //FPS_MODE_SUPPORTED
|
|
if (GetState()== State_ThrowProjectile && !m_bHasThrownProjectile && !bAimGunThrowInCoverInFPS)
|
|
{
|
|
CObject* pProjectile = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
if (pProjectile)
|
|
{
|
|
Vector3 vStart = m_vLastProjectilePos;
|
|
Vector3 vEnd = VEC3V_TO_VECTOR3(pProjectile->GetTransform().GetPosition());
|
|
if (!vStart.IsZero())
|
|
{
|
|
Vector3 vDir = vEnd-vStart;
|
|
Vector3 vDot = vEnd - VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()); vDot.z=0; vDot.Normalize();
|
|
Vector3 vNorm = VEC3V_TO_VECTOR3(pPed->GetTransform().GetForward());
|
|
vNorm.z=0; vNorm.Normalize();
|
|
if ( vDot.Dot(vNorm) >0 )
|
|
{
|
|
vEnd.AddScaled(vDir, 0.5f);
|
|
WorldProbe::CShapeTestCapsuleDesc capsuleDesc;
|
|
capsuleDesc.SetCapsule(vStart, vEnd, 0.025f);
|
|
capsuleDesc.SetIncludeFlags( (ArchetypeFlags::GTA_ALL_TYPES_WEAPON & ~ArchetypeFlags::GTA_PROJECTILE_TYPE & ~ArchetypeFlags::GTA_RIVER_TYPE) );
|
|
capsuleDesc.SetTypeFlags( ArchetypeFlags::GTA_WEAPON_TEST );
|
|
capsuleDesc.SetExcludeEntity(pPed);
|
|
capsuleDesc.SetIsDirected(true);
|
|
#if __BANK
|
|
char szDebugText[128];
|
|
formatf( szDebugText, "OVERRIDE_COLLISION_SPHERE_START" );
|
|
CTask::ms_debugDraw.AddSphere( RCC_VEC3V(vStart), 0.025f, Color_yellow, 2, atStringHash(szDebugText), false );
|
|
formatf( szDebugText, "OVERRIDE_COLLISION_SPHERE_END" );
|
|
CTask::ms_debugDraw.AddSphere( RCC_VEC3V(vEnd), 0.025f, Color_yellow4, 2, atStringHash(szDebugText), false );
|
|
formatf( szDebugText, "OVERRIDE_COLLISION_ARROW" );
|
|
CTask::ms_debugDraw.AddArrow( RCC_VEC3V(vStart), RCC_VEC3V(vEnd), 0.025f, Color_pink, 2, atStringHash(szDebugText) );
|
|
#endif
|
|
if(WorldProbe::GetShapeTestManager()->SubmitTest(capsuleDesc))
|
|
{
|
|
m_bFire = true;
|
|
bOverrideStartPos = true;
|
|
vStartOverride = m_vLastProjectilePos;
|
|
}
|
|
|
|
}
|
|
}
|
|
m_vLastProjectilePos = vEnd;
|
|
}
|
|
}
|
|
// throw the projectile
|
|
if(m_bFire)
|
|
{
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon)
|
|
{
|
|
m_bFire = false;
|
|
ThrowProjectileNow(pPed, pWeapon, bOverrideStartPos ? &vStartOverride : NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::UpdateAdditives()
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
float fDesiredStrafeSpeed = m_fStrafeSpeed;
|
|
|
|
if (GetPed()->IsFirstPersonShooterModeEnabledForPlayer(false, true))
|
|
{
|
|
TUNE_GROUP_BOOL(FIRST_PERSON_TUNE, REMAP_MBR_TO_ANALOGUE_CONTROL, true);
|
|
if(REMAP_MBR_TO_ANALOGUE_CONTROL)
|
|
{
|
|
if(fDesiredStrafeSpeed > 0.5f)
|
|
{
|
|
fDesiredStrafeSpeed = 0.66f;
|
|
}
|
|
else if(fDesiredStrafeSpeed > 0.f)
|
|
{
|
|
fDesiredStrafeSpeed = 0.33f;
|
|
}
|
|
else
|
|
{
|
|
fDesiredStrafeSpeed = 0.f;
|
|
}
|
|
|
|
CTaskMotionAiming* pTaskMotionAiming = static_cast<CTaskMotionAiming*>(GetPed()->GetPedIntelligence()->FindTaskActiveMotionByType(CTaskTypes::TASK_MOTION_AIMING));
|
|
if(pTaskMotionAiming)
|
|
{
|
|
if(pTaskMotionAiming->GetState() == CTaskMotionAiming::State_StandingIdle || pTaskMotionAiming->GetState() == CTaskMotionAiming::State_StopStrafing)
|
|
{
|
|
fDesiredStrafeSpeed = 0.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE, ADDITIVE_SPEED_LERP_RATE_DEC, 2.f, 0.f, 100.f, 0.01f);
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE, ADDITIVE_SPEED_LERP_RATE_ACC, 1.7f, 0.f, 100.f, 0.01f);
|
|
|
|
float fLerpRate = fDesiredStrafeSpeed >= m_fStrafeSpeedAdditive ? ADDITIVE_SPEED_LERP_RATE_ACC : ADDITIVE_SPEED_LERP_RATE_DEC;
|
|
Approach(m_fStrafeSpeedAdditive, fDesiredStrafeSpeed, fLerpRate, GetTimeStep());
|
|
|
|
static dev_float ADD_DIR_LERP_RATE = 3.f;
|
|
CTaskMotionBase::InterpValue(m_fStrafeDirectionAdditive, m_fStrafeDirection, ADD_DIR_LERP_RATE, true, GetTimeStep());
|
|
m_fStrafeDirectionAdditive = fwAngle::LimitRadianAngle(m_fStrafeDirectionAdditive);
|
|
}
|
|
#endif // FPS_MODE_SUPPORTED
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::GetOverriddenGameplayCameraSettings(tGameplayCameraSettings& settings) const
|
|
{
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
// If we're throwing a projectile whilst aiming, use the gun camera settings
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
CTaskGun *pTaskGun = static_cast<CTaskGun*>(GetPed()->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_GUN));
|
|
if (pTaskGun)
|
|
{
|
|
pTaskGun->GetOverriddenGameplayCameraSettings(settings);
|
|
return;
|
|
}
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
// force the camera to stay put!
|
|
if(GetState() == State_PlaceProjectile || m_bMoveTreeIsDropMode || GetState() == State_StreamingClips )
|
|
{
|
|
settings.m_CameraHash = ATSTRINGHASH("INVALID_CAMERA", 0x05aad591b);
|
|
}
|
|
else
|
|
{
|
|
//force default as the aim button may not necssarily be down, B* 1054819
|
|
const CWeaponInfo* weaponInfo = camGameplayDirector::ComputeWeaponInfoForPed(*GetPed());
|
|
if (weaponInfo)
|
|
settings.m_CameraHash = weaponInfo->GetDefaultCameraHash();
|
|
}
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::CleanUp()
|
|
{
|
|
CNetObjPed *netObjPed = static_cast<CNetObjPed *>(GetPed()->GetNetworkObject());
|
|
if(netObjPed)
|
|
{ //Make sure this is not left set
|
|
netObjPed->SetTaskOverridingPropsWeapons(false);
|
|
}
|
|
|
|
if (m_bPriming)
|
|
{//turn off priming FX and reset timer
|
|
CWeapon* pWeapon = GetPed()->GetWeaponManager()->GetEquippedWeapon();
|
|
if (pWeapon)
|
|
{
|
|
if (pWeapon->GetWeaponInfo()->GetDropWhenCooked())
|
|
pWeapon->CancelCookTimer();
|
|
}
|
|
SetPriming(GetPed(), false);
|
|
}
|
|
|
|
float fBlendDuration = SLOW_BLEND_DURATION;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(GetPed()->IsLocalPlayer() && GetPed()->GetMotionData()->GetWasUsingFPSMode() && !GetPed()->GetMotionData()->GetUsingFPSMode())
|
|
{
|
|
fBlendDuration = INSTANT_BLEND_DURATION;
|
|
}
|
|
else if(GetPed()->IsFirstPersonShooterModeEnabledForPlayer(false) && GetPed()->GetPlayerInfo() && !(GetPed()->GetPlayerInfo()->IsSprintAimBreakOutOver()))
|
|
{
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fBlendOutAimToSprint, 0.5f, 0.0f, 1.0f, 0.01f);
|
|
fBlendDuration = fBlendOutAimToSprint;
|
|
}
|
|
#endif
|
|
|
|
GetPed()->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, fBlendDuration, CMovePed::Task_TagSyncTransition);
|
|
//clear projectile strafe clipset
|
|
CTaskMotionBase* pTask = GetPed()->GetPrimaryMotionTask();
|
|
taskAssert(pTask!=NULL);
|
|
if (pTask)
|
|
{
|
|
m_StrafeClipSetRequestHelper.Release();
|
|
pTask->ResetStrafeClipSet();
|
|
}
|
|
|
|
if(m_NetworkDefId == CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectileThrow)
|
|
{
|
|
CTaskMotionBase* pMotionTask = GetPed()->GetPrimaryMotionTask();
|
|
if(pMotionTask && pMotionTask->GetTaskType() == CTaskTypes::TASK_MOTION_PED)
|
|
{
|
|
CTaskMotionPed* pMotionPedTask = static_cast<CTaskMotionPed*>(pMotionTask);
|
|
pMotionPedTask->SetDoAimingIndependentMover(false);
|
|
}
|
|
}
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
// Clean-up the temporary weapon object in the peds hand
|
|
if (GetPed()->GetPedConfigFlag(CPED_CONFIG_FLAG_ThrowingGrenadeWhileAiming) && m_pTempWeaponObject)
|
|
{
|
|
GetPed()->GetPedIntelligence()->SetDoneAimGrenadeThrow();
|
|
CTaskAimGunOnFoot::RestorePreviousWeapon(GetPed(), m_pTempWeaponObject.Get(), m_iBackupWeaponClipAmmo);
|
|
}
|
|
// Only set this flag as false if we have broken out unexpectedly (else we want to restore weapons/play settle anims through CTaskAimGunOnFoot::ProcessGrenadeThrowFromGunAim)
|
|
else if (GetPed()->GetPedConfigFlag(CPED_CONFIG_FLAG_ThrowingGrenadeWhileAiming))
|
|
{
|
|
GetPed()->GetPedIntelligence()->SetDoneAimGrenadeThrow();
|
|
GetPed()->SetPedConfigFlag(CPED_CONFIG_FLAG_ThrowingGrenadeWhileAiming, false);
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::UpdateAiming(CPed* pPed, bool popIt)
|
|
{
|
|
if (m_MoveNetworkHelper.IsNetworkActive())
|
|
{
|
|
//////////////////////////////////////
|
|
// Calculate and send MoVE parameters
|
|
//////////////////////////////////////
|
|
|
|
//////////////////////////////////
|
|
//// COMPUTE AIM PITCH SIGNAL ////
|
|
//////////////////////////////////
|
|
|
|
float fSweepPitchMin = 0;
|
|
float fSweepPitchMax = QUARTER_PI;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
fSweepPitchMin = -PI/3.0f;
|
|
fSweepPitchMax = PI/3.0f;
|
|
}
|
|
#endif
|
|
|
|
const float fThrowPitchMin = -QUARTER_PI;
|
|
|
|
// Calculate the aim vector (this determines the heading and pitch angles to point the anims in the correct direction)
|
|
Vector3 vStart(ORIGIN);
|
|
Vector3 vEnd(ORIGIN);
|
|
//CalculateAimVector(pPed, vStart, vEnd); // Based on camera direction
|
|
if (pPed->IsLocalPlayer())
|
|
{
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
const CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if (pWeapon)
|
|
{
|
|
float fWeaponRange = pWeapon->GetRange();
|
|
|
|
CPed * pPlayer = CGameWorld::FindLocalPlayer();
|
|
CControl *pControl = pPlayer->GetControlFromPlayer();
|
|
if (pControl->GetPedTargetIsUp(ioValue::ANALOG_BUTTON_DOWN_THRESHOLD))
|
|
{
|
|
CEntity* pLockOnTarget = pPlayer->GetPlayerInfo()->GetTargeting().GetLockOnTarget();
|
|
if (pLockOnTarget)
|
|
{
|
|
vStart = camInterface::GetPos();
|
|
vEnd = VEC3V_TO_VECTOR3(pLockOnTarget->GetTransform().GetPosition());
|
|
Assert(vEnd.FiniteElements()); // Attempting to track down an INF (B*682884)
|
|
|
|
return; //?? does nothing
|
|
}
|
|
}
|
|
|
|
const camFrame& aimFrame = camInterface::GetPlayerControlCamAimFrame();
|
|
vStart = aimFrame.GetPosition();
|
|
Vector3 vecAim = aimFrame.GetFront();
|
|
vecAim.Normalize();
|
|
vEnd = vStart + (fWeaponRange * vecAim);
|
|
Assert(vEnd.FiniteElements()); // Attempting to track down an INF (B*682884)
|
|
|
|
// Compute desired pitch angle value
|
|
float fDesiredPitch = CTaskAimGun::CalculateDesiredPitch(pPed, vStart, vEnd);
|
|
|
|
// Map the angle to the range 0.0->1.0
|
|
m_fDesiredPitch = CTaskAimGun::ConvertRadianToSignal(fDesiredPitch, fSweepPitchMin, fSweepPitchMax, false);
|
|
m_fDesiredThrowPitch = CTaskAimGun::ConvertRadianToSignal(fDesiredPitch, fThrowPitchMin, fSweepPitchMax, false);
|
|
|
|
static dev_float s_fMinPitchForPlacedProjectileThrow = 0.25f;
|
|
if (m_bCanBePlaced) //placed weapons can switch from hold to prime B* 1041752
|
|
{
|
|
CPlayerPedTargeting &playerTargeting = pPed->GetPlayerInfo()->GetTargeting();
|
|
Vector3 vTarget;
|
|
if (playerTargeting.GetLockOnTarget())
|
|
vTarget = playerTargeting.GetLockonTargetPos();
|
|
else
|
|
vTarget = playerTargeting.GetClosestFreeAimTargetPos();
|
|
vTarget.Subtract(VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()));
|
|
float fTargetDist2 = vTarget.XYMag2();
|
|
static dev_float s_fMinThrowPlaceDistance2 = 3.5f*3.5f;
|
|
static dev_float s_fMinForcePlaceDistance2 = 1.0f*1.0f;
|
|
if (fTargetDist2 < s_fMinForcePlaceDistance2)
|
|
{
|
|
m_bThrowPlace = false;
|
|
m_bPrimedButPlacing = true;
|
|
}
|
|
else if (fTargetDist2 < s_fMinThrowPlaceDistance2 || m_fThrowPitch < s_fMinPitchForPlacedProjectileThrow)
|
|
{
|
|
m_bThrowPlace = true;
|
|
m_bPrimedButPlacing = false;
|
|
}
|
|
else
|
|
{
|
|
m_bThrowPlace = m_bPrimedButPlacing = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vStart = pPed->GetBonePositionCached((eAnimBoneTag)BONETAG_R_HAND);
|
|
if (m_target.GetIsValid())
|
|
{
|
|
m_target.GetPosition(vEnd);
|
|
Assert(vEnd.FiniteElements()); // Attempting to track down an INF (B*682884)
|
|
}
|
|
else
|
|
vEnd.Zero(); //?
|
|
|
|
// Compute desired pitch angle value
|
|
float fDesiredPitch = CTaskAimGun::CalculateDesiredPitch(pPed, vStart, vEnd);
|
|
|
|
// Map the angle to the range 0.0->1.0
|
|
m_fDesiredPitch = CTaskAimGun::ConvertRadianToSignal(fDesiredPitch, fSweepPitchMin, fSweepPitchMax, false);
|
|
m_fDesiredThrowPitch = CTaskAimGun::ConvertRadianToSignal(fDesiredPitch, fThrowPitchMin, fSweepPitchMax, false);
|
|
|
|
}
|
|
|
|
// Compute the final signal value
|
|
static float PitchChangeRate = 1.0f; //TODO
|
|
|
|
if (popIt)
|
|
{
|
|
m_fCurrentPitch = m_fDesiredPitch;
|
|
m_fThrowPitch = m_fDesiredThrowPitch;
|
|
}
|
|
else
|
|
{
|
|
bool bUseDesiredPitch = false;
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
bUseDesiredPitch = m_bAimGunAndThrow;
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
if ((GetState() != State_ThrowProjectile || m_bHasThrownProjectile) && !bUseDesiredPitch)
|
|
m_fThrowPitch = CTaskAimGun::SmoothInput(m_fThrowPitch, m_fDesiredThrowPitch, PitchChangeRate);
|
|
else if (bUseDesiredPitch)
|
|
m_fThrowPitch = m_fDesiredThrowPitch;
|
|
m_fCurrentPitch = CTaskAimGun::SmoothInput(m_fCurrentPitch, m_fDesiredPitch, PitchChangeRate);
|
|
}
|
|
|
|
// Send the signal
|
|
m_MoveNetworkHelper.SetFloat(ms_PitchPhase, m_fCurrentPitch);
|
|
m_MoveNetworkHelper.SetFloat(ms_ThrowPitchPhase, m_fThrowPitch);
|
|
//Displayf("AimPhase: %f, Desired: %f >>> PitchPhase: %f, Desired: %f", m_fCurrentHeading, fDesiredYaw*RtoD, m_fCurrentPitch, fDesiredPitch*RtoD);
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(m_bFPSUseAimIKForWeapon && pPed->IsFirstPersonShooterModeEnabledForPlayer(false))
|
|
{
|
|
if(m_pFPSWeaponMoveNetworkHelper && m_pFPSWeaponMoveNetworkHelper->IsNetworkActive())
|
|
{
|
|
m_pFPSWeaponMoveNetworkHelper->SetFloat(ms_PitchPhase, m_fCurrentPitch);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//Torso IK:
|
|
if (IsAiming(pPed))
|
|
{
|
|
m_bHasTargetPosition = !vEnd.IsZero();
|
|
if(m_bHasTargetPosition)
|
|
{
|
|
m_vTargetPosition = vEnd;
|
|
pPed->GetIkManager().PointGunAtPosition(vEnd, -1.0f);
|
|
}
|
|
else
|
|
pPed->GetIkManager().PointGunInDirection(pPed->GetCurrentHeading(), 0.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
dev_float TIME_TO_THROW_LONG = 0.33f;
|
|
|
|
bool CTaskAimAndThrowProjectile::ShouldUseProjectileStrafeClipSet()
|
|
{
|
|
return GUN_PROJECTILE_THROW_ONLY(!m_bAimGunAndThrow) FPS_MODE_SUPPORTED_ONLY(&& !GetPed()->IsFirstPersonShooterModeEnabledForPlayer(false));
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::Start_OnUpdate(CPed* pPed)
|
|
{
|
|
m_bAllowPriming = true;
|
|
|
|
if(pPed && pPed->IsLocalPlayer() && pPed->GetWeaponManager())
|
|
{
|
|
const CWeaponInfo* pWeaponInfo = pPed->GetWeaponManager()->GetEquippedWeapon() ? pPed->GetWeaponManager()->GetEquippedWeapon()->GetWeaponInfo() : NULL;
|
|
if(pWeaponInfo && pWeaponInfo->GetDropWhenCooked() && pPed->GetPedResetFlag(CPED_RESET_FLAG_StartProjectileTaskWithPrimingDisabled))
|
|
{
|
|
m_bAllowPriming = false;
|
|
}
|
|
}
|
|
|
|
SetState(State_StreamingClips);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::StreamingClips_OnEnter(CPed* UNUSED_PARAM(pPed))
|
|
{
|
|
m_iClipSet = CLIP_SET_ID_INVALID;
|
|
m_iStreamedClipSet = CLIP_SET_ID_INVALID;
|
|
|
|
//load filters
|
|
m_pFrameFilter = g_FrameFilterDictionaryStore.FindFrameFilter(CMovePed::s_UpperBodyFilterHashId);
|
|
|
|
static fwMvFilterId s_GripFilterHashId("Grip_R_Only_Filter",0xB455BA3A);
|
|
m_pGripFrameFilter = g_FrameFilterDictionaryStore.FindFrameFilter(s_GripFilterHashId);
|
|
|
|
static fwMvFilterId s_PullPinFilterHashId("BothArms_NoSpine_filter",0x6C2DD2B3);
|
|
m_pPullPinFilter = g_FrameFilterDictionaryStore.FindFrameFilter(s_PullPinFilterHashId);
|
|
|
|
//Set projectile strafe clipset
|
|
CTaskMotionBase* pTask = GetPed()->GetPrimaryMotionTask();
|
|
taskAssert(pTask!=NULL);
|
|
if (pTask && ShouldUseProjectileStrafeClipSet())
|
|
{
|
|
m_StrafeClipSetRequestHelper.Request(pTask->GetDefaultAimingStrafingClipSet(false));
|
|
}
|
|
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::StreamingClips_OnUpdate(CPed* pPed)
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
bool bUseFPSModeBehaviour = pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon;
|
|
bool bRNGTransitionOnStart = false;
|
|
//If we are in starting up the task without having the drop/or throw flags, we want to make sure we play a transition first
|
|
if(bUseFPSModeBehaviour && pPed->GetMotionData()->GetIsFPSRNG() && !m_bDropProjectile && !m_bFPSWantsToThrowWhenReady && !m_bPlayFPSTransition)
|
|
{
|
|
HandleFPSStateUpdate();
|
|
|
|
if(m_bAllowPriming)
|
|
{
|
|
m_bPlayFPSTransition = true;
|
|
bRNGTransitionOnStart = true;
|
|
}
|
|
}
|
|
|
|
// B*2313574: Block camera switching when in State_StreamingClips (we already block when in State_Holding as task doesn't support being restarted).
|
|
if(pPed->GetPlayerInfo())
|
|
{
|
|
if(!pPed->IsFirstPersonShooterModeEnabledForPlayer(false) || !pPed->GetMotionData()->GetIsFPSIdle())
|
|
{
|
|
pPed->SetPlayerResetFlag(CPlayerResetFlags::PRF_DISABLE_CAMERA_VIEW_MODE_CYCLE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (m_iClipSet == CLIP_SET_ID_INVALID)
|
|
{
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon)
|
|
{
|
|
const CWeaponInfo* pWeaponInfo = pWeapon->GetWeaponInfo();
|
|
if (!pWeaponInfo || (!pWeaponInfo->GetIsThrownWeapon() GUN_PROJECTILE_THROW_ONLY(&& !m_bAimGunAndThrow)))
|
|
{
|
|
if(!pPed->IsNetworkClone())
|
|
{
|
|
SetState(State_Finish);
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
|
|
// If we're doing a gun grenade throw use the backup weapon clipset info
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
// Only create the dummy weapon object once.
|
|
if (!m_pTempWeaponObject)
|
|
{
|
|
CreateDummyWeaponObject(pPed, pWeapon, pWeaponInfo);
|
|
}
|
|
u32 uBackupWeaponHash = pPed->GetWeaponManager()->GetBackupWeapon();
|
|
const CWeaponInfo *pBackupWeaponInfo = CWeaponInfoManager::GetInfo<CWeaponInfo>(uBackupWeaponHash);
|
|
|
|
if (pBackupWeaponInfo)
|
|
{
|
|
pWeaponInfo = pBackupWeaponInfo;
|
|
m_iClipSet = pWeaponInfo->GetAimGrenadeThrowClipsetId(*pPed);
|
|
}
|
|
}
|
|
else
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
{
|
|
FPSStreamingFlags fpsStreamingFlags = FPS_StreamDefault;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
if(!m_bAllowPriming)
|
|
{
|
|
if(pPed->GetMotionData()->GetIsFPSRNG())
|
|
{
|
|
if(IsAiming(pPed))
|
|
{
|
|
fpsStreamingFlags = FPS_StreamLT;
|
|
}
|
|
else
|
|
{
|
|
fpsStreamingFlags = FPS_StreamIdle;
|
|
}
|
|
}
|
|
|
|
}
|
|
else if(m_bDropProjectile)
|
|
{
|
|
fpsStreamingFlags = FPS_StreamIdle;
|
|
}
|
|
else if(m_bFPSWantsToThrowWhenReady)
|
|
{
|
|
fpsStreamingFlags = FPS_StreamRNG;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
m_iClipSet = pWeaponInfo->GetAppropriateWeaponClipSetId(pPed, fpsStreamingFlags);
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
//bool bSkipFPSTransition = true;
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
//If the fidget just ended or we want to switch FPS states (play a transition), do not grab the fidget clipset this update
|
|
if(m_bMoveFPSFidgetEnded || m_bPlayFPSTransition)
|
|
{
|
|
bool bFidgetConfigFlag = pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile);
|
|
pPed->SetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile, false);
|
|
m_iClipSet = pWeaponInfo->GetAppropriateWeaponClipSetId(pPed, fpsStreamingFlags);
|
|
pPed->SetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile, bFidgetConfigFlag);
|
|
}
|
|
|
|
if(pPed->GetMotionData()->GetWasFPSUnholster())
|
|
{
|
|
m_bPlayFPSTransition = true;
|
|
}
|
|
|
|
bool bPlayUnholsterTransition = !pPed->GetPedResetFlag(CPED_RESET_FLAG_ForceSkipFPSAimIntro) &&
|
|
!bRNGTransitionOnStart &&
|
|
(pPed->GetPedResetFlag(CPED_RESET_FLAG_WasFPSJumpingWithProjectile) || pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_WasPlayingFPSGetup) ||
|
|
pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_WasPlayingFPSMeleeActionResult) ||
|
|
(GetPreviousState() == State_CombatRoll && !m_bFPSWantsToThrowWhenReady && !m_bDropProjectile) ||
|
|
(GetPreviousState() == State_ThrowProjectile && (pPed->GetMotionData()->GetIsFPSIdle() || !m_bAllowPriming)));
|
|
|
|
if(bPlayUnholsterTransition)
|
|
{
|
|
m_bPlayFPSTransition = true;
|
|
}
|
|
|
|
if(pWeapon->GetIsCooking())
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
}
|
|
|
|
|
|
if(m_bPlayFPSTransition)
|
|
{
|
|
bool bJustThrownProjectileWhileAiming = GetPreviousState() == State_ThrowProjectile && IsAiming(pPed);
|
|
bool bJustThrownProjectileRTOnly = GetPreviousState() == State_ThrowProjectile && !IsAiming(pPed) && pPed->GetMotionData()->GetIsFPSRNG() && m_bAllowPriming;
|
|
|
|
fwMvClipSetId clipsetId;
|
|
|
|
FPSStreamingFlags fpsTransitionSet = FPS_StreamDefault;
|
|
CPedMotionData::eFPSState prevFPSStateOverride = CPedMotionData::FPS_MAX;
|
|
CPedMotionData::eFPSState currFPSStateOverride = CPedMotionData::FPS_MAX;
|
|
m_bPlayFPSPullPinIntro = false;
|
|
m_bPlayFPSRNGIntro = false;
|
|
m_bFPSPlayingUnholsterIntro = false;
|
|
|
|
if(!m_bAllowPriming)
|
|
{
|
|
if(pPed->GetMotionData()->GetIsFPSRNG())
|
|
{
|
|
if(IsAiming(pPed))
|
|
{
|
|
fpsTransitionSet = FPS_StreamLT;
|
|
if(!m_bWasAiming)
|
|
{
|
|
prevFPSStateOverride = CPedMotionData::FPS_IDLE;
|
|
}
|
|
currFPSStateOverride = CPedMotionData::FPS_LT;
|
|
|
|
}
|
|
else
|
|
{
|
|
fpsTransitionSet = FPS_StreamIdle;
|
|
if(m_bWasAiming)
|
|
{
|
|
prevFPSStateOverride = CPedMotionData::FPS_LT;
|
|
}
|
|
currFPSStateOverride = CPedMotionData::FPS_IDLE;
|
|
}
|
|
}
|
|
}
|
|
else if(bJustThrownProjectileWhileAiming)
|
|
{
|
|
fpsTransitionSet = FPS_StreamLT;
|
|
prevFPSStateOverride = CPedMotionData::FPS_IDLE;
|
|
currFPSStateOverride = CPedMotionData::FPS_LT;
|
|
}
|
|
else if(m_bDropProjectile || bJustThrownProjectileRTOnly)
|
|
{
|
|
if(bJustThrownProjectileRTOnly)
|
|
{
|
|
m_bDropProjectile = true;
|
|
}
|
|
|
|
fpsTransitionSet = FPS_StreamRNG;
|
|
prevFPSStateOverride = CPedMotionData::FPS_IDLE;
|
|
currFPSStateOverride = CPedMotionData::FPS_RNG;
|
|
}
|
|
else if(m_bFPSWantsToThrowWhenReady)
|
|
{
|
|
fpsTransitionSet = FPS_StreamRNG;
|
|
prevFPSStateOverride = CPedMotionData::FPS_LT;
|
|
currFPSStateOverride = CPedMotionData::FPS_RNG;
|
|
}
|
|
|
|
if(bPlayUnholsterTransition)
|
|
{
|
|
prevFPSStateOverride = CPedMotionData::FPS_UNHOLSTER;
|
|
}
|
|
|
|
clipsetId = pWeaponInfo->GetAppropriateFPSTransitionClipsetId(*pPed, prevFPSStateOverride, fpsTransitionSet);
|
|
|
|
if(clipsetId != CLIP_SET_ID_INVALID)
|
|
{
|
|
m_fFPSStateToTransitionBlendTime = SelectFPSBlendTime(pPed, true, prevFPSStateOverride, currFPSStateOverride);
|
|
m_fFPSTransitionToStateBlendTime = SelectFPSBlendTime(pPed, false, prevFPSStateOverride, currFPSStateOverride);
|
|
|
|
if(((m_bFPSWantsToThrowWhenReady || pPed->GetMotionData()->GetIsFPSRNG()) && !bJustThrownProjectileWhileAiming && m_bAllowPriming) || m_bDropProjectile)
|
|
{
|
|
m_bPlayFPSRNGIntro = true;
|
|
}
|
|
else if(prevFPSStateOverride == CPedMotionData::FPS_UNHOLSTER || pPed->GetMotionData()->GetWasFPSUnholster())
|
|
{
|
|
m_bFPSPlayingUnholsterIntro = true;
|
|
}
|
|
//If we have just thrown the projectile, we should pull the pin first and not just skip ahead to the throwing/dropping
|
|
else if(pPed->GetMotionData()->GetIsFPSLT() || bJustThrownProjectileWhileAiming)
|
|
{
|
|
m_bPlayFPSPullPinIntro = true;
|
|
}
|
|
|
|
m_iClipSet = clipsetId;
|
|
}
|
|
else
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
}
|
|
}
|
|
|
|
|
|
bool bCreatedNetworkHelperThisUpdate = false;
|
|
CWeapon* pWeapon = (GetPed()->GetWeaponManager()) ? GetPed()->GetWeaponManager()->GetEquippedWeapon() : NULL;
|
|
const CWeaponInfo* pWeaponInfo = pWeapon->GetWeaponInfo();
|
|
if(pWeapon && pWeaponInfo && pWeaponInfo->GetHasFPSProjectileWeaponAnims() && !m_pFPSWeaponMoveNetworkHelper)
|
|
{
|
|
if(!pWeapon->GetFPSMoveNetworkHelper())
|
|
{
|
|
pWeapon->CreateFPSMoveNetworkHelper();
|
|
bCreatedNetworkHelperThisUpdate = true;
|
|
}
|
|
m_pFPSWeaponMoveNetworkHelper = pWeapon->GetFPSMoveNetworkHelper();
|
|
}
|
|
|
|
if(m_pFPSWeaponMoveNetworkHelper)
|
|
{
|
|
if(pWeapon)
|
|
{
|
|
pWeapon->CreateFPSWeaponNetworkPlayer();
|
|
if(m_pFPSWeaponMoveNetworkHelper->IsNetworkActive())
|
|
{
|
|
static fwMvRequestId s_WeaponHoldRequest("WeaponHolding",0x43D07274);
|
|
static fwMvRequestId s_WeaponIntroRequest("WeaponIntro",0x7DC2F8E9);
|
|
static fwMvRequestId s_WeaponPullPinRequest("PullPin",0x76E39996);
|
|
|
|
static const fwMvClipId s_weaponHoldClipId("w_settle_med",0x150399A9);
|
|
static const fwMvClipId s_weaponIntroClipId("w_aim_trans_med",0xEF3589E7);
|
|
static const fwMvClipId s_weaponFidgetClipId("w_fidget_med_loop", 0x73C669F1);
|
|
|
|
if(m_iClipSet != CLIP_SET_ID_INVALID)
|
|
{
|
|
m_pFPSWeaponMoveNetworkHelper->SetClipSet(m_iClipSet);
|
|
|
|
if(m_bPlayFPSTransition && fwAnimManager::GetClipIfExistsBySetId(m_iClipSet, s_weaponIntroClipId))
|
|
{
|
|
m_pFPSWeaponMoveNetworkHelper->SendRequest(s_WeaponIntroRequest);
|
|
}
|
|
else if(fwAnimManager::GetClipIfExistsBySetId(m_iClipSet, s_weaponHoldClipId))
|
|
{
|
|
m_pFPSWeaponMoveNetworkHelper->SendRequest(s_WeaponHoldRequest);
|
|
if(m_bDropProjectile && !m_bPlayFPSTransition)
|
|
{
|
|
m_pFPSWeaponMoveNetworkHelper->SendRequest(s_WeaponPullPinRequest);
|
|
}
|
|
}
|
|
if(m_bPlayFPSFidget && pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile) && fwAnimManager::GetClipIfExistsBySetId(m_iClipSet, s_weaponFidgetClipId))
|
|
{
|
|
m_pFPSWeaponMoveNetworkHelper->SendRequest(s_WeaponHoldRequest);
|
|
m_pFPSWeaponMoveNetworkHelper->SendRequest(ms_FPSFidget);
|
|
}
|
|
}
|
|
|
|
if(bCreatedNetworkHelperThisUpdate && pPed->GetWeaponManager())
|
|
{
|
|
CObject* pWeaponObj = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
if(pWeaponObj)
|
|
{
|
|
pWeaponObj->ForcePostCameraAnimUpdate(true, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
m_iStreamedClipSet = pWeaponInfo->GetAppropriateReloadWeaponClipSetId(pPed); //TODO: defer this streaming until later
|
|
}
|
|
else if(!pPed->IsNetworkClone())
|
|
{
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
if (m_ClipSetRequestHelper.Request(m_iClipSet) && m_StreamedClipSetRequestHelper.Request(m_iStreamedClipSet))
|
|
{
|
|
if (pPed->IsNetworkClone())
|
|
{
|
|
if (GetStateFromNetwork() == State_PlaceProjectile)
|
|
{
|
|
SetState(State_PlaceProjectile);
|
|
}
|
|
}
|
|
else if(!IsAiming(pPed) FPS_MODE_SUPPORTED_ONLY(|| (bUseFPSModeBehaviour && GetPreviousState() == State_Blocked)))
|
|
{
|
|
bool bFPSRNGRelease = false;
|
|
bool bFPSRNG = false;
|
|
#if FPS_MODE_SUPPORTED
|
|
// We may want to place a projectile so we enter this logic to check. We should not handle dropping here as that is handled by HandleFPSStateUpdate()
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
bFPSRNG = pPed->GetMotionData()->GetIsFPSRNG();
|
|
bFPSRNGRelease = !bFPSRNG && pPed->GetMotionData()->GetWasFPSRNG();
|
|
}
|
|
|
|
#endif
|
|
if (m_bCanBePlaced && (m_bPriming || CThrowProjectileHelper::IsPlayerPriming(pPed) || bFPSRNGRelease))
|
|
{
|
|
if(!bFPSRNGRelease)
|
|
{
|
|
SetPriming(pPed, true);
|
|
m_bDropProjectile = true;
|
|
}
|
|
|
|
if(IsFiring(pPed))
|
|
{
|
|
// Switch to move to state
|
|
if(CanPlaceProjectile(pPed))
|
|
{
|
|
SetState(State_PlaceProjectile);
|
|
m_bDropProjectile = false;
|
|
m_bFPSWantsToThrowWhenReady = false;
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
else
|
|
return FSM_Continue;
|
|
}
|
|
else if (CThrowProjectileHelper::IsPlayerPriming(pPed) && m_bAllowPriming FPS_MODE_SUPPORTED_ONLY( && !bFPSRNG))
|
|
m_bDropProjectile = true;
|
|
else
|
|
{
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon && pWeapon->GetIsCooking() FPS_MODE_SUPPORTED_ONLY( && !bFPSRNG))
|
|
{
|
|
m_bDropProjectile = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NetworkInterface::UseFirstPersonIdleMovementForRemotePlayer(*pPed))
|
|
{
|
|
SetState(State_CloneIdle);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectile);
|
|
|
|
|
|
float fBlendDuration = SLOW_BLEND_DURATION;
|
|
#if FPS_MODE_SUPPORTED
|
|
if(bUseFPSModeBehaviour && m_fFPSStateToTransitionBlendTime >= 0.0f && m_fFPSTransitionToStateBlendTime >= 0.0f)
|
|
{
|
|
if(m_bPlayFPSTransition)
|
|
{
|
|
fBlendDuration = m_fFPSStateToTransitionBlendTime;
|
|
}
|
|
else
|
|
{
|
|
fBlendDuration = m_fFPSTransitionToStateBlendTime;
|
|
m_fFPSStateToTransitionBlendTime = -1.0f;
|
|
m_fFPSTransitionToStateBlendTime = -1.0f;
|
|
}
|
|
}
|
|
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
const CTaskMotionPed* pPedMotionTask = static_cast<const CTaskMotionPed*>(GetPed()->GetPedIntelligence()->FindTaskActiveMotionByType(CTaskTypes::TASK_MOTION_PED));
|
|
|
|
if(!pPed->GetMotionData()->GetWasUsingFPSMode())
|
|
{
|
|
fBlendDuration = INSTANT_BLEND_DURATION;
|
|
} // B* 2101014: Slow blend duration for blending in fidgets, makes it look better
|
|
else if(m_bPlayFPSFidget)
|
|
{
|
|
const float fFidgetBlendInDuration = 0.4f;
|
|
fBlendDuration = fFidgetBlendInDuration;
|
|
}
|
|
else if(pPedMotionTask && pPedMotionTask->GetFPSPreviouslySprinting())
|
|
{
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fAimBlendInAfterSprint, 0.35f, 0.0f, 1.0f, 0.01f);
|
|
fBlendDuration = fAimBlendInAfterSprint;
|
|
}
|
|
|
|
m_fFPSTaskNetworkBlendDuration = fBlendDuration;
|
|
m_fFPSTaskNetworkBlendTimer = 0.0f;
|
|
|
|
if(GetPreviousState() == State_CombatRoll || GetPreviousState() == State_ThrowProjectile || GetPreviousState() == State_PlaceProjectile)
|
|
{
|
|
fBlendDuration *= 0.7f; //Speed up the blend a bit
|
|
//We DON't want to pause transition playback until the network has fully blended in
|
|
m_fFPSTaskNetworkBlendTimer = fBlendDuration;
|
|
}
|
|
}
|
|
#endif
|
|
CreateNetworkPlayer(networkDefId);
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, fBlendDuration, CMovePed::Task_TagSyncContinuous);
|
|
m_MoveNetworkHelper.SetClipSet(m_iClipSet);
|
|
m_MoveNetworkHelper.SetClipSet(m_iStreamedClipSet, ms_StreamedClipSet); //TODO: defer this streaming until later
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
m_MoveNetworkHelper.SetFlag(true, ms_UsingFPSMode);
|
|
m_MoveNetworkHelper.SetFloat(ms_AimingLeanAdditiveWeight, 1.0f);
|
|
m_MoveNetworkHelper.SetFloat(ms_AimingBreathingAdditiveWeight, 1.0f);
|
|
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetCookWhileAiming() &&
|
|
(pWeapon->GetDamageType() == DAMAGE_TYPE_EXPLOSIVE) && m_bDropProjectile && !m_bPlayFPSTransition)
|
|
{
|
|
m_MoveNetworkHelper.SetFlag(true, ms_FPSCookingProjectile);
|
|
}
|
|
|
|
if(!pPed->GetMotionData()->GetWasUsingFPSMode() && pPed->GetPedResetFlag(CPED_RESET_FLAG_ForcePreCameraAnimUpdate))
|
|
{
|
|
ProcessPostPreRender();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if (!IsAiming(pPed) && IsPriming(pPed))
|
|
m_bMoveTreeIsDropMode = true;
|
|
|
|
if (IsAiming(pPed) && !IsPriming(pPed))
|
|
m_bFalseAiming = true;
|
|
|
|
static fwMvFilterId s_RightArmHashId("RightArm_NoSpine_filter",0x72BC0F25);
|
|
m_pFrameFilter = g_FrameFilterDictionaryStore.FindFrameFilter(m_bMoveTreeIsDropMode ? s_RightArmHashId : CMovePed::s_UpperBodyFilterHashId);
|
|
|
|
SetGripClip();
|
|
|
|
if(pWeapon)
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
Vector3 vTargetPos(0.01f, 0.01f, 0.01f);
|
|
if(CTaskWeaponBlocked::IsWeaponBlocked(pPed, vTargetPos) && GetPreviousState() != State_Blocked && !m_bAimGunAndThrow)
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
SetState(State_Blocked);
|
|
return FSM_Continue;
|
|
}
|
|
else if(m_bPlayFPSTransition == false && !m_bAimGunAndThrow)
|
|
{
|
|
m_MoveNetworkHelper.SetFlag(true, ms_SkipIntroId);
|
|
m_bPlayFPSTransition = false;
|
|
SetState(State_HoldingProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
#endif
|
|
// in case the last projectile blew up in my hands
|
|
if(pWeapon->GetNeedsToReload(true))
|
|
{
|
|
pPed->GetWeaponManager()->DestroyEquippedWeaponObject();
|
|
pPed->GetWeaponManager()->CreateEquippedWeaponObject();
|
|
}
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
//Throw automatically if we are coming directly from the aim gun task
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
SetState(State_Intro);
|
|
}
|
|
else
|
|
SetState(State_Finish);
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::Intro_OnEnter(CPed* pPed)
|
|
{
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
CNetObjPed* pNetObjPed = static_cast<CNetObjPed*>(pPed->GetNetworkObject());
|
|
if (pNetObjPed)
|
|
{
|
|
// make sure the ped is holding the correct weapon first
|
|
pNetObjPed->SetTaskOverridingPropsWeapons(false);
|
|
pNetObjPed->UpdateCachedWeaponInfo(true);
|
|
|
|
pNetObjPed->SetTaskOverridingPropsWeapons(true);
|
|
}
|
|
}
|
|
|
|
m_bPriming = false;
|
|
m_bIsFiring = false;
|
|
|
|
m_MoveNetworkHelper.WaitForTargetState(ms_EnterIntroEvent);
|
|
}
|
|
|
|
dev_float ReachPinPhaseBeforeWallBlock = 0.567f;
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::Intro_OnUpdate(CPed* pPed)
|
|
{
|
|
if(!m_MoveNetworkHelper.IsInTargetState())
|
|
return FSM_Continue;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(HandleFPSStateUpdate() && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
SetState(State_StreamingClips);
|
|
return FSM_Continue;
|
|
}
|
|
#endif
|
|
|
|
float fPhase = m_MoveNetworkHelper.GetFloat(ms_TransitionPhase);
|
|
static dev_float sf_IntroPhaseOut = 0.8f;
|
|
|
|
bool bFPSReleaseOnReachPin = false;
|
|
bool bFPSAimIntroTransition = false;
|
|
bool bUseFPSModeBehaviour = pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
Vector3 vTargetPos(0.1f, 0.1f, 0.1f);
|
|
bool bIsFPSBlocked = CTaskWeaponBlocked::IsWeaponBlocked(pPed, vTargetPos);
|
|
if(bIsFPSBlocked)
|
|
{
|
|
if (fPhase >= ReachPinPhaseBeforeWallBlock)
|
|
{
|
|
if(m_bFPSUseAimIKForWeapon && (m_bFPSWantsToThrowWhenReady || m_bDropProjectile))
|
|
{
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon && !pWeapon->GetIsCooking() && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetCookWhileAiming()) //don't pre cook weapons that won't show in UI
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
}
|
|
|
|
// Our weapon is blocked, so don't go into aiming or firing
|
|
SetState(State_Blocked);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
m_bFPSReachPinOnIntro |= m_MoveNetworkHelper.GetBoolean(ms_FPSReachPin);
|
|
bFPSReleaseOnReachPin = m_bFPSReachPinOnIntro && (m_bFPSWantsToThrowWhenReady || (m_bDropProjectile && !pPed->GetMotionData()->GetIsFPSRNG()));
|
|
bFPSAimIntroTransition = m_MoveNetworkHelper.GetBoolean(CTaskMotionAiming::ms_FPSAimIntroTransitionId);
|
|
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fProjectileIntroPlayRate, 1.0f, 0.0f, 5.0f, 0.1f);
|
|
float fIntroPlayRate = fProjectileIntroPlayRate;
|
|
bool bTaskNetworkBlendedIn = m_fFPSTaskNetworkBlendTimer > m_fFPSTaskNetworkBlendDuration;
|
|
|
|
if(!bTaskNetworkBlendedIn && m_bFPSPlayingUnholsterIntro)
|
|
{
|
|
fIntroPlayRate = 0.0f;
|
|
}
|
|
|
|
m_MoveNetworkHelper.SetFloat(CTaskAimGunOnFoot::ms_FPSIntroPlayRate, fIntroPlayRate);
|
|
}
|
|
#endif
|
|
|
|
if (fPhase >= sf_IntroPhaseOut || bFPSReleaseOnReachPin || bFPSAimIntroTransition)
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(m_bPlayFPSTransition && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
//Restart again to change clipsets
|
|
m_bPlayFPSTransition = false;
|
|
|
|
if(m_bPlayFPSPullPinIntro && m_bFPSWantsToThrowWhenReady)
|
|
{
|
|
m_bPlayFPSTransition = true;
|
|
}
|
|
|
|
SetState(State_StreamingClips);
|
|
return FSM_Continue;
|
|
}
|
|
#endif
|
|
m_MoveNetworkHelper.SendRequest(ms_StartHold);
|
|
SetState(State_HoldingProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if (CThrowProjectileHelper::IsPlayerRolling(pPed))
|
|
{
|
|
SetState(State_CombatRoll);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if (pPed->IsNetworkClone() && GetStateFromNetwork() == State_PlaceProjectile)
|
|
{
|
|
SetState(State_PlaceProjectile);
|
|
}
|
|
|
|
//Head IK
|
|
if (GetPed()->IsLocalPlayer() FPS_MODE_SUPPORTED_ONLY(&& !bUseFPSModeBehaviour))
|
|
GetPed()->GetIkManager().LookAt(0, NULL, 1000, BONETAG_INVALID, NULL, LF_USE_CAMERA_FOCUS|LF_WHILE_NOT_IN_FOV, 500, 500, CIkManager::IK_LOOKAT_HIGH);
|
|
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
bool bFPSUseModeBehaviour = m_bFPSUseAimIKForWeapon && pPed->IsFirstPersonShooterModeEnabledForPlayer(false);
|
|
#endif
|
|
|
|
bool bProceed = m_bDropProjectile && m_bAllowPriming;
|
|
|
|
if (!pPed->IsNetworkClone())
|
|
{
|
|
bProceed |= (CThrowProjectileHelper::IsPlayerPriming(pPed) && m_bAllowPriming) || (pWeapon && pWeapon->GetIsCooking());
|
|
}
|
|
|
|
if (bProceed FPS_MODE_SUPPORTED_ONLY(&& !bFPSUseModeBehaviour))
|
|
{
|
|
if (!pPed->IsNetworkClone())
|
|
{
|
|
// start priming
|
|
SetPriming(pPed, true);
|
|
|
|
// weapon manager verified in PreProcessFSM
|
|
if (pWeapon && pWeapon->GetWeaponInfo()->GetCookWhileAiming())
|
|
{
|
|
if(!pWeapon->GetIsCooking())
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
else
|
|
m_bPinPulled = true;
|
|
}
|
|
}
|
|
|
|
m_MoveNetworkHelper.SetFlag(m_bDropProjectile, ms_DropProjectileFlagId);
|
|
m_MoveNetworkHelper.SetFlag(m_bPinPulled, ms_SkipPullPinId);
|
|
if (m_bDropProjectile)
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_StartDropPrime);
|
|
m_bPinPulled = true;
|
|
SetState(State_HoldingProjectile);
|
|
}
|
|
else
|
|
{
|
|
if (m_bPrimedButPlacing)
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_StartHold);
|
|
SetState(State_HoldingProjectile);
|
|
}
|
|
else
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_StartPrime);
|
|
if (!m_bPinPulled)
|
|
{
|
|
m_bPinPulled = true;
|
|
SetState(State_PullPin);
|
|
}
|
|
else
|
|
{
|
|
SetState(State_HoldingProjectile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
void CTaskAimAndThrowProjectile::Intro_OnExit(CPed *pPed)
|
|
{
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
m_bPlayFPSPullPinIntro = false;
|
|
m_bFPSReachPinOnIntro = false;
|
|
m_bPlayFPSRNGIntro = false;
|
|
m_bFPSPlayingUnholsterIntro = false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::PullPin_OnUpdate()
|
|
{
|
|
float fPinPhase = 0.0f;
|
|
m_MoveNetworkHelper.GetFloat(ms_PullPinPhase, fPinPhase);
|
|
if (fPinPhase >= 0.8f)
|
|
{
|
|
if (m_fThrowPitch < sm_Tunables.m_fMinHoldThrowPitch)
|
|
m_MoveNetworkHelper.SendRequest(ms_StartHold);
|
|
else
|
|
m_MoveNetworkHelper.SendRequest(ms_StartPrime);
|
|
m_MoveNetworkHelper.SetFlag(m_bPinPulled, ms_SkipPullPinId);
|
|
SetState(State_HoldingProjectile);
|
|
}
|
|
|
|
if (CThrowProjectileHelper::IsPlayerRolling(GetPed()))
|
|
{
|
|
SetState(State_CombatRoll);
|
|
return FSM_Continue;
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::HoldingProjectile_OnEnter(CPed* FPS_MODE_SUPPORTED_ONLY(pPed))
|
|
{
|
|
if (GetPreviousState() != State_CombatRoll)
|
|
m_MoveNetworkHelper.WaitForTargetState(ms_EnterHoldEvent);
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(m_bPlayFPSFidget && pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile))
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_FPSFidget);
|
|
}
|
|
else
|
|
{
|
|
m_bPlayFPSFidget = false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::HoldingProjectile_OnUpdate(CPed* pPed)
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->GetPlayerInfo())
|
|
{
|
|
if(!pPed->IsFirstPersonShooterModeEnabledForPlayer(false) || !pPed->GetMotionData()->GetIsFPSIdle())
|
|
{
|
|
pPed->SetPlayerResetFlag(CPlayerResetFlags::PRF_DISABLE_CAMERA_VIEW_MODE_CYCLE);
|
|
}
|
|
}
|
|
#endif // FPS_MODE_SUPPORTED
|
|
|
|
if(!m_MoveNetworkHelper.IsInTargetState())
|
|
return FSM_Continue;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(HandleFPSStateUpdate() && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
SetState(State_StreamingClips);
|
|
return FSM_Continue;
|
|
}
|
|
else if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
bool bFPSRestart = false;
|
|
|
|
if((pPed->GetMotionData()->GetIsFPSIdle() || pPed->GetMotionData()->GetIsFPSLT()) && !m_bFPSWantsToThrowWhenReady &&
|
|
!m_bDropProjectile && pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile) && !m_bPlayFPSFidget)
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
m_bPlayFPSFidget = true;
|
|
bFPSRestart = true;
|
|
}
|
|
|
|
m_bMoveFPSFidgetEnded |= m_MoveNetworkHelper.GetBoolean(CTaskAimGunOnFoot::ms_FidgetClipEndedId);
|
|
|
|
//Continue for a frame after fidget ends so that TaskMotionPed can check the "clip ended" tag
|
|
if(m_bPlayFPSFidget && m_bMoveFPSFidgetEnded)
|
|
{
|
|
return FSM_Continue;
|
|
}
|
|
else if (m_bPlayFPSFidget && !pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile))
|
|
{
|
|
m_bPlayFPSFidget = false;
|
|
bFPSRestart = true;
|
|
}
|
|
|
|
if(bFPSRestart)
|
|
{
|
|
SetState(State_StreamingClips);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
Vector3 vTargetPos(0.1f, 0.1f, 0.1f);
|
|
bool bIsBlocked = CTaskWeaponBlocked::IsWeaponBlocked(pPed, vTargetPos);
|
|
if(bIsBlocked)
|
|
{
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(m_bFPSUseAimIKForWeapon && (m_bFPSWantsToThrowWhenReady || m_bDropProjectile))
|
|
{
|
|
if(pWeapon && !pWeapon->GetIsCooking() && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetCookWhileAiming()) //don't pre cook weapons that won't show in UI
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
|
|
// Our weapon is blocked, so don't go into aiming or firing
|
|
|
|
m_bPlayFPSFidget = false;
|
|
SetState(State_Blocked);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(!pPed->IsPlayer())
|
|
{
|
|
// just throw at target
|
|
SetState(State_ThrowProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
// weapon manager verified in PreProcessFSM
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
|
|
//Emulate left trigger if started this way
|
|
static dev_float s_fMinHoldTime = 0.0f;
|
|
if (m_bFalseAiming && GetTimeInState() > s_fMinHoldTime)
|
|
m_bFalseAiming = false;
|
|
|
|
if (CThrowProjectileHelper::IsPlayerRolling(pPed))
|
|
{
|
|
SetState(State_CombatRoll);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
bool bReadyToThrow = m_bPriming;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if (!bReadyToThrow && pPed->IsFirstPersonShooterModeEnabledForPlayer(false, true))
|
|
{
|
|
if (pPed->IsNetworkClone())
|
|
{
|
|
bReadyToThrow = (m_bDropProjectile || m_bIsFiring);
|
|
}
|
|
else
|
|
{
|
|
bReadyToThrow = m_bFPSUseAimIKForWeapon && (m_bDropProjectile || m_bFPSWantsToThrowWhenReady);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (bReadyToThrow)
|
|
{
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_TemporarilyBlockWeaponSwitching, true );
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(m_bFPSUseAimIKForWeapon && (m_bFPSWantsToThrowWhenReady || m_bDropProjectile))
|
|
{
|
|
if(pWeapon && !pWeapon->GetIsCooking() && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetCookWhileAiming()) //don't pre cook weapons that won't show in UI
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
#endif
|
|
|
|
// check for drop
|
|
if(m_bDropProjectile)
|
|
{
|
|
if(IsFiring(pPed))
|
|
{
|
|
// Check to see if this is placeable
|
|
if((pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetFlag(CWeaponInfoFlags::PlacedOnly)) || (m_bCanBePlaced && CanPlaceProjectile(pPed)))
|
|
{
|
|
// Switch to move to state
|
|
SetState(State_PlaceProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
SetState(State_ThrowProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
ProjectileInfo* pProjectileInfo = CNetworkPendingProjectiles::GetProjectile(pPed, GetNetSequenceID(), false);
|
|
if(pProjectileInfo)
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
if(IsAiming(pPed) FPS_MODE_SUPPORTED_ONLY(&& (!m_bFPSUseAimIKForWeapon || !pPed->IsFirstPersonShooterModeEnabledForPlayer(false))))
|
|
{
|
|
m_MoveNetworkHelper.SetFlag(false, ms_DropProjectileFlagId);
|
|
if (!m_bMoveTreeIsDropMode)
|
|
{
|
|
if (m_bPrimedButPlacing || ((pWeapon && pWeapon->GetWeaponInfo()->GetFlag(CWeaponInfoFlags::PlacedOnly)) || m_fThrowPitch < sm_Tunables.m_fMinHoldThrowPitch))
|
|
m_MoveNetworkHelper.SendRequest(ms_StartHold);
|
|
else
|
|
m_MoveNetworkHelper.SendRequest(ms_StartPrime);
|
|
m_MoveNetworkHelper.SetFlag(m_bPinPulled, ms_SkipPullPinId);
|
|
}
|
|
else
|
|
{
|
|
HoldPrimeMoveNetworkRestart(pPed, true);
|
|
}
|
|
|
|
m_bDropProjectile = false;
|
|
}
|
|
m_MoveNetworkHelper.SetFloat(ms_ShadowWeight, 1.0f);
|
|
|
|
// only valid on local players
|
|
if(!pPed->IsNetworkClone())
|
|
{
|
|
if(pWeapon)
|
|
{
|
|
Assert(pWeapon->GetWeaponInfo());
|
|
if(pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetProjectileFuseTime() > 0.0f && pWeapon->GetCookTimeLeft(pPed, fwTimer::GetTimeInMilliseconds()) <= 0)
|
|
{
|
|
if (pWeapon->GetWeaponInfo()->GetDropWhenCooked())
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
m_bAllowPriming = false;
|
|
m_bDropProjectile = true;
|
|
return FSM_Continue;
|
|
}
|
|
else
|
|
{
|
|
ThrowProjectileNow(pPed, pWeapon);
|
|
m_bWaitingToDie = true;
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
}
|
|
|
|
}
|
|
}
|
|
else if (!m_bWaitingToDie)
|
|
{
|
|
// The equipped weapon (which existed when this sequence started) has been taken away. bail...
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
bool bSwitchedOutOfRNG = false;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
bSwitchedOutOfRNG = pPed->GetMotionData()->GetWasFPSRNG() && !pPed->GetMotionData()->GetIsFPSRNG();
|
|
}
|
|
#endif
|
|
// player is firing, move to thrown
|
|
if(IsFiring(pPed) || bSwitchedOutOfRNG)
|
|
{
|
|
if (m_bPrimedButPlacing && CanPlaceProjectile(pPed))
|
|
{
|
|
// just place
|
|
SetState(State_PlaceProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
else if(!pPed->IsNetworkClone())
|
|
{
|
|
//Test for placed-only weapons
|
|
if (pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetFlag(CWeaponInfoFlags::PlacedOnly))
|
|
{
|
|
SetState(State_PlaceProjectile);
|
|
}
|
|
else
|
|
{
|
|
m_bIsFiring = true;
|
|
|
|
//make sure I'm facing forward
|
|
static dev_float s_fMaxHeadingDelta = PI*0.25f;
|
|
const float fCurrentHeading = fwAngle::LimitRadianAngleSafe(pPed->GetCurrentHeading());
|
|
const float fDesiredHeading = fwAngle::LimitRadianAngleSafe(pPed->GetDesiredHeading());
|
|
const float fHeadingDelta = SubtractAngleShorter(fDesiredHeading, fCurrentHeading);
|
|
|
|
if (fabs(fHeadingDelta) < s_fMaxHeadingDelta)
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ProjectileInfo* pProjectileInfo = CNetworkPendingProjectiles::GetProjectile(pPed, GetNetSequenceID(), false);
|
|
if(pProjectileInfo)
|
|
{
|
|
if (pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetFlag(CWeaponInfoFlags::PlacedOnly))
|
|
{
|
|
SetState(State_PlaceProjectile);
|
|
}
|
|
}
|
|
|
|
if(GetStateFromNetwork() == State_ThrowProjectile)
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(!pPed->IsNetworkClone() && CThrowProjectileHelper::IsPlayerPriming(pPed) && m_bAllowPriming) //Not priming but should
|
|
{
|
|
// start priming
|
|
SetPriming(pPed, true);
|
|
|
|
if(pWeapon && !pWeapon->GetIsCooking() && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetCookWhileAiming()) //don't pre cook weapons that won't show in UI
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
|
|
if(CPlayerInfo::IsAiming() || (m_bFalseAiming && !m_bDropProjectile))
|
|
{
|
|
if (m_bPrimedButPlacing)
|
|
m_MoveNetworkHelper.SendRequest(ms_StartHold);
|
|
else
|
|
{
|
|
if (m_bPinPulled && ((pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetFlag(CWeaponInfoFlags::PlacedOnly)) || m_fThrowPitch < sm_Tunables.m_fMinHoldThrowPitch))
|
|
m_MoveNetworkHelper.SendRequest(ms_StartHold);
|
|
else
|
|
m_MoveNetworkHelper.SendRequest(ms_StartPrime);
|
|
|
|
if (!m_bPinPulled)
|
|
{
|
|
SetState(State_PullPin);
|
|
}
|
|
m_MoveNetworkHelper.SetFlag(false, ms_DropProjectileFlagId);
|
|
m_MoveNetworkHelper.SetFlag(m_bPinPulled, ms_SkipPullPinId);
|
|
m_bPinPulled = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bDropProjectile = true;
|
|
}
|
|
}
|
|
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if (NetworkInterface::UseFirstPersonIdleMovementForRemotePlayer(*pPed))
|
|
{
|
|
SetState(State_CloneIdle);
|
|
return FSM_Continue;
|
|
}
|
|
#endif
|
|
|
|
// catch the early out case, tracked below for local peds
|
|
if(GetStateFromNetwork() == State_Finish)
|
|
{
|
|
SetState(State_Finish);
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
}
|
|
// catch the place projectile state
|
|
else if(GetStateFromNetwork() == State_PlaceProjectile || GetStateFromNetwork() == State_Outro)
|
|
SetState(GetStateFromNetwork());
|
|
}
|
|
else
|
|
{
|
|
const CWeaponInfo* pWeaponInfo = pPed->GetWeaponManager()->GetEquippedWeaponInfo();
|
|
if((!IsAiming(pPed) && GetState() == State_HoldingProjectile) || (pWeaponInfo && !pWeaponInfo->GetIsThrownWeapon()))
|
|
{
|
|
if(IsPriming(pPed) && m_bAllowPriming && (!m_bCanBePlaced || pPed->GetMotionData()->GetDesiredMbrY() >= MOVEBLENDRATIO_WALK))
|
|
{
|
|
if ( GetTimeInState() > s_fMinHoldTime)
|
|
{
|
|
if (!m_bMoveTreeIsDropMode)
|
|
HoldPrimeMoveNetworkRestart(pPed, false);
|
|
m_bDropProjectile = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!m_bFalseAiming FPS_MODE_SUPPORTED_ONLY ( && (!m_bFPSUseAimIKForWeapon || !pPed->IsFirstPersonShooterModeEnabledForPlayer(false))))
|
|
{
|
|
SetState(State_Outro);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pPed->GetWeaponManager()->GetRequiresWeaponSwitch())
|
|
{
|
|
SetState(State_Outro);
|
|
}
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::HoldPrimeMoveNetworkRestart(CPed* pPed, bool bHoldToPrime)
|
|
{
|
|
pPed->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, NORMAL_BLEND_DURATION);
|
|
fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectile);
|
|
CreateNetworkPlayer(networkDefId);
|
|
m_MoveNetworkHelper.SetFlag(true, ms_SkipIntroId);
|
|
m_MoveNetworkHelper.SetFlag(m_bPinPulled, ms_SkipPullPinId);
|
|
if (bHoldToPrime)
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_StartPrime);
|
|
if (!m_bPinPulled)
|
|
{
|
|
SetState(State_PullPin);
|
|
}
|
|
m_bPinPulled = true;
|
|
m_bMoveTreeIsDropMode = false;
|
|
}
|
|
else
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_StartHold);
|
|
m_bMoveTreeIsDropMode = true;
|
|
}
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, SLOW_BLEND_DURATION, CMovePed::Task_TagSyncContinuous);
|
|
m_MoveNetworkHelper.SetClipSet(m_iClipSet);
|
|
m_MoveNetworkHelper.SetClipSet(m_iStreamedClipSet, ms_StreamedClipSet);
|
|
|
|
static fwMvFilterId s_RightArmHashId("RightArm_NoSpine_filter",0x72BC0F25);
|
|
m_pFrameFilter = g_FrameFilterDictionaryStore.FindFrameFilter(bHoldToPrime ? CMovePed::s_UpperBodyFilterHashId : s_RightArmHashId);
|
|
if(m_pFrameFilter)
|
|
m_MoveNetworkHelper.SetFilter(m_pFrameFilter, ms_FrameFilterId);
|
|
|
|
SetGripClip();
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::SetPriming(CPed* pPed, bool bPrime)
|
|
{
|
|
m_bPriming = bPrime;
|
|
CProjectile* pProjectile = static_cast<CProjectile*>(pPed->GetWeaponManager()->GetEquippedWeaponObject());
|
|
if (pProjectile)
|
|
pProjectile->SetPrimed(bPrime);
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::SetGripClip()
|
|
{
|
|
//See if grip anim exists
|
|
static fwMvFlagId sUseGripClip("UseGripClip",0x72838804);
|
|
const fwClipSet *pClipSet = m_MoveNetworkHelper.GetClipSet();
|
|
|
|
bool bSetGripClip = true;
|
|
#if FPS_MODE_SUPPORTED
|
|
if(m_bFPSUseAimIKForWeapon && GetPed()->IsFirstPersonShooterModeEnabledForPlayer(false))
|
|
{
|
|
bSetGripClip = false;
|
|
if(GetState() == State_ThrowProjectile)
|
|
{
|
|
m_MoveNetworkHelper.SetFlag(false, sUseGripClip);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(bSetGripClip)
|
|
{
|
|
if (pClipSet && pClipSet->GetClip(fwMvClipId("grip",0x6FAD1258)) != NULL)
|
|
m_MoveNetworkHelper.SetFlag(true, sUseGripClip);
|
|
else
|
|
m_MoveNetworkHelper.SetFlag(false, sUseGripClip);
|
|
}
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::ThrowProjectile_OnEnter(CPed* pPed)
|
|
{
|
|
m_bHasThrownProjectile = false;
|
|
m_bHasReloaded = false;
|
|
m_vLastProjectilePos.Zero();
|
|
bool bOverHandOnly = m_bCanBePlaced;
|
|
#if FPS_MODE_SUPPORTED
|
|
m_bFPSWantsToThrowWhenReady = false;
|
|
m_fFPSDropThrowSwitchTimer = -1.0f;
|
|
#endif
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
float fTargetDist2 = 0;
|
|
Vector3 vTarget(Vector3::ZeroType);
|
|
if(pWeapon)
|
|
{
|
|
if(pWeapon->GetWeaponInfo()->GetCookWhileAiming())
|
|
pPed->GetPedAudioEntity()->HandleAnimEventFlag("GRENADE_PULL_PIN");
|
|
|
|
if( !m_bCanBePlaced && pPed->IsLocalPlayer()) //if target is too close, just drop it
|
|
{
|
|
CPlayerPedTargeting &playerTargeting = pPed->GetPlayerInfo()->GetTargeting();
|
|
if (playerTargeting.GetLockOnTarget())
|
|
vTarget = playerTargeting.GetLockonTargetPos();
|
|
else
|
|
vTarget = playerTargeting.GetClosestFreeAimTargetPos();
|
|
|
|
#if __BANK
|
|
CTask::ms_debugDraw.AddSphere(RCC_VEC3V(vTarget), 0.3f, Color_green, 1000);
|
|
#endif
|
|
vTarget.Subtract(VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()));
|
|
fTargetDist2 = vTarget.XYMag2();
|
|
|
|
static dev_float s_fMinThrowDistance2 = 1.5f*1.5f;
|
|
if (fTargetDist2 < s_fMinThrowDistance2 && !pWeapon->GetWeaponInfo()->GetThrowOnly())
|
|
m_bDropProjectile = true;
|
|
}
|
|
}
|
|
|
|
m_bForceStandingThrow = false;
|
|
if (pPed->IsLocalPlayer())
|
|
{
|
|
//Ground check, if missing play throw while standing still
|
|
static dev_float s_fForwardGroundProbeDepth = 2.5f;
|
|
Vector3 vTestStart = VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition());
|
|
Vector3 vDirection = VEC3V_TO_VECTOR3(pPed->GetTransform().GetForward());
|
|
vDirection.RotateZ(m_fStrafeDirection);
|
|
vTestStart.AddScaled(vDirection, s_fForwardGroundProbeDepth);
|
|
|
|
//vTestStart.z += 0.5f;
|
|
static dev_float s_fDownGroundProbeDepth = 2.0f;
|
|
Vector3 vTestEnd = vTestStart;
|
|
vTestEnd.z -= s_fDownGroundProbeDepth;
|
|
#if __BANK
|
|
CTask::ms_debugDraw.AddLine(RCC_VEC3V(vTestStart), RCC_VEC3V(vTestEnd), Color_yellow, 0);
|
|
#endif
|
|
|
|
WorldProbe::CShapeTestHitPoint probeIsect;
|
|
WorldProbe::CShapeTestResults probeResult(probeIsect);
|
|
WorldProbe::CShapeTestProbeDesc probeDesc;
|
|
probeDesc.SetStartAndEnd(vTestStart, vTestEnd);
|
|
probeDesc.SetResultsStructure(&probeResult);
|
|
probeDesc.SetExcludeEntity(pPed);
|
|
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES|ArchetypeFlags::GTA_VEHICLE_TYPE|ArchetypeFlags::GTA_OBJECT_TYPE);
|
|
probeDesc.SetContext(WorldProbe::LOS_GeneralAI);
|
|
|
|
if(!WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc, WorldProbe::PERFORM_SYNCHRONOUS_TEST))
|
|
{
|
|
m_bForceStandingThrow = true;
|
|
}
|
|
}
|
|
|
|
pPed->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, NORMAL_BLEND_DURATION);
|
|
fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectileThrow);
|
|
CreateNetworkPlayer(networkDefId);
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
// Disable projectile drop from AimGunAndThrow
|
|
if (m_bAimGunAndThrow && m_bDropProjectile)
|
|
{
|
|
m_bDropProjectile = false;
|
|
}
|
|
|
|
if (m_bAimGunAndThrow && m_bThrowPlace)
|
|
{
|
|
m_bThrowPlace = false;
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
if (m_bDropProjectile)
|
|
{
|
|
static fwMvFilterId s_UpperNoLeftArmPartialHeadHashId("UpperbodyFeathered_NoLeftArm_PartialHead_filter",0x7D55CA4B);
|
|
|
|
fwMvFilterId userFilterId = s_UpperNoLeftArmPartialHeadHashId;
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false))
|
|
{
|
|
static const fwMvFilterId s_RootUpperbodyFilterHashId("RootUpperbody_filter",0x503C54E9);
|
|
userFilterId = s_RootUpperbodyFilterHashId;
|
|
}
|
|
#endif
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, NORMAL_BLEND_DURATION, CMovePed::Task_None, userFilterId);
|
|
}
|
|
else
|
|
{
|
|
float fBlend = NORMAL_BLEND_DURATION;
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
fBlend = SLOW_BLEND_DURATION;
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, fBlend);
|
|
}
|
|
m_MoveNetworkHelper.SetClipSet(m_iClipSet);
|
|
m_MoveNetworkHelper.SetClipSet(m_iStreamedClipSet, ms_StreamedClipSet);
|
|
|
|
SetGripClip();
|
|
|
|
//if throwing over sf_MinUnderHandDistance2, don't try and underhand it.
|
|
static dev_float sf_MinUnderHandDistance2 = 7.0f*7.0f;
|
|
if (fTargetDist2 >= sf_MinUnderHandDistance2)
|
|
bOverHandOnly = true;
|
|
|
|
// If we're set to do an underhand throw, do a probe test to check that there isn't anything blocking between the ped and the target position
|
|
if (pPed->IsLocalPlayer() && !bOverHandOnly && m_fThrowPitch <= 0.4f && vTarget.IsNonZero())
|
|
{
|
|
//Ground check, if missing play throw while standing still
|
|
Vector3 vTestStart = VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition());
|
|
|
|
// Scale the target position back slightly so we don't register a collision with the terrain/object at the target position
|
|
Vector3 vTargetPosition = vTarget;
|
|
vTargetPosition.Scale(0.8f);
|
|
vTargetPosition = vTestStart + vTargetPosition;
|
|
|
|
// Start the probe slightly lower down than the peds centre, around thigh-height.
|
|
static dev_float fStartOffset = 0.25f;
|
|
vTestStart.z -= fStartOffset;
|
|
|
|
#if __BANK
|
|
CTask::ms_debugDraw.AddLine(RCC_VEC3V(vTestStart), RCC_VEC3V(vTargetPosition), Color_yellow, 0);
|
|
#endif
|
|
|
|
WorldProbe::CShapeTestHitPoint probeIsect;
|
|
WorldProbe::CShapeTestResults probeResult(probeIsect);
|
|
WorldProbe::CShapeTestProbeDesc probeDesc;
|
|
probeDesc.SetStartAndEnd(vTestStart, vTarget);
|
|
probeDesc.SetResultsStructure(&probeResult);
|
|
probeDesc.SetExcludeEntity(pPed);
|
|
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES|ArchetypeFlags::GTA_VEHICLE_TYPE|ArchetypeFlags::GTA_OBJECT_TYPE);
|
|
probeDesc.SetContext(WorldProbe::LOS_GeneralAI);
|
|
|
|
if(WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc, WorldProbe::PERFORM_SYNCHRONOUS_TEST))
|
|
{
|
|
// We have a collision, force an over hand throw
|
|
bOverHandOnly = true;
|
|
|
|
#if __BANK
|
|
if (probeResult.GetNumHits() > 0)
|
|
{
|
|
CTask::ms_debugDraw.AddSphere(RCC_VEC3V(probeResult[0].GetHitPosition()), 0.2f, Color_red, 1000);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
m_MoveNetworkHelper.SetFlag(bOverHandOnly, ms_OverhandOnlyId);
|
|
m_MoveNetworkHelper.SetFlag(m_bThrowPlace, ms_UseThrowPlaceId);
|
|
m_MoveNetworkHelper.SetFlag(m_bDropProjectile, ms_DoDropId);
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
m_MoveNetworkHelper.SetFlag(m_bAimGunAndThrow, ms_AimGunThrowId);
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
m_MoveNetworkHelper.SetFloat(ms_ThrowPitchPhase, m_fThrowPitch);
|
|
if (m_bDropProjectile)
|
|
{
|
|
// static fwMvFilterId s_UpperNoLeftArmPartialHeadHashId("UpperbodyFeathered_NoLeftArm_PartialHead_filter",0x7D55CA4B);
|
|
// m_pFrameFilter = g_FrameFilterDictionaryStore.FindFrameFilter(s_UpperNoLeftArmPartialHeadHashId);
|
|
// if(m_pFrameFilter)
|
|
// m_MoveNetworkHelper.SetFilter(m_pFrameFilter, ms_FrameFilterId);
|
|
m_pFrameFilter = NULL;
|
|
|
|
bool bThrowOnly = pWeapon && pWeapon->GetWeaponInfo()->GetThrowOnly();
|
|
if (bThrowOnly)
|
|
{
|
|
m_bDropUnderhand = (pPed->GetMotionData()->GetDesiredMbrY() == MOVEBLENDRATIO_STILL || (pWeapon && pWeapon->GetWeaponHash() == WEAPONTYPE_DLC_SNOWBALL) FPS_MODE_SUPPORTED_ONLY(|| pPed->IsFirstPersonShooterModeEnabledForPlayer(false))) &&
|
|
pWeapon && pWeapon->GetWeaponInfo()->GetDropForwardVelocity()!=0.0f;
|
|
}
|
|
else
|
|
m_bDropUnderhand = false;
|
|
m_MoveNetworkHelper.SetFlag(bThrowOnly, ms_NoStaticDropId);
|
|
m_MoveNetworkHelper.SetFlag(m_bDropUnderhand, ms_UseDropUnderhandId);
|
|
|
|
}
|
|
else
|
|
{
|
|
m_pFrameFilter = g_FrameFilterDictionaryStore.FindFrameFilter(CMovePed::s_UpperBodyFilterHashId);
|
|
m_MoveNetworkHelper.SetFilter(m_pFrameFilter, ms_FrameFilterId);
|
|
}
|
|
Vector2 vCurrentMBR = pPed->GetMotionData()->GetCurrentMoveBlendRatio();
|
|
float fStrafeSpeed = vCurrentMBR.Mag() / MOVEBLENDRATIO_SPRINT;
|
|
static dev_float sf_MinMovingTimeForMovingThrow = 0.5f;
|
|
if ((m_bForceStandingThrow || !pPed->IsStrafing() || m_fTimeMoving <= sf_MinMovingTimeForMovingThrow) GUN_PROJECTILE_THROW_ONLY(&& !m_bAimGunAndThrow))
|
|
fStrafeSpeed = 0;
|
|
m_MoveNetworkHelper.SetFloat(ms_StrafeSpeed, fStrafeSpeed);
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::ThrowProjectile_OnUpdate(CPed* pPed)
|
|
{
|
|
static const fwMvClipId s_ThrowClip("ThrowClip",0xC4C387F);
|
|
|
|
// Grab a pointer to the peds weapon, this should always be valid for a local ped
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(!pPed->IsNetworkClone() && !m_bHasThrownProjectile && !pWeapon)
|
|
{
|
|
taskDebugf1("CTaskAimAndThrowProjectile::ThrowProjectile_OnUpdate: FSM_Quit - !m_bHasThrownProjectile && !pWeapon. Previous State: %d", GetPreviousState());
|
|
return FSM_Quit; //weapon where?
|
|
}
|
|
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_ThrowingProjectile, true );
|
|
|
|
const crClip* pClip = m_MoveNetworkHelper.GetClip(s_ThrowClip);
|
|
if (pClip)
|
|
{
|
|
CClipEventTags::FindEventPhase(pClip, CClipEventTags::Interruptible, m_fInterruptPhase);
|
|
}
|
|
|
|
|
|
if (pPed->IsNetworkClone() && !m_bHasThrownProjectile)
|
|
{
|
|
//Clones check and wait here for the synced projectile and throw as soon as they see it
|
|
if(CNetworkPendingProjectiles::GetProjectile(GetPed(), GetNetSequenceID(), false))
|
|
{
|
|
//Clones throw as soon as they see a projectile synced
|
|
ThrowProjectileNow(pPed, pWeapon);
|
|
}
|
|
else
|
|
{
|
|
if(GetStateFromNetwork()==State_Finish)
|
|
{
|
|
SetState(State_Finish);
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
float fPhase = m_MoveNetworkHelper.GetFloat(ms_ThrowPhase);
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
// If we're throwing from gun aim, set the grenade to be visible once we've reached the specified threshold in the anim
|
|
bool bClipPastVisibilityPhase = false;
|
|
|
|
float fVisibilityPhase = -1.0f;
|
|
if (pClip)
|
|
{
|
|
CClipEventTags::FindEventPhase<crPropertyAttributeBool>(pClip, CClipEventTags::Object, CClipEventTags::Create, true, fVisibilityPhase);
|
|
}
|
|
|
|
// Check if we have a specified tag in the throw clip
|
|
if (fVisibilityPhase != -1.0f)
|
|
{
|
|
bClipPastVisibilityPhase = fPhase >= fVisibilityPhase;
|
|
}
|
|
else
|
|
{
|
|
// We don't have a tag, use this as the visibility threshold
|
|
static dev_float fThrowPhaseThreshold = 0.35f;
|
|
bClipPastVisibilityPhase = fPhase >= fThrowPhaseThreshold;
|
|
}
|
|
|
|
if (bClipPastVisibilityPhase)
|
|
{
|
|
CObject* pGrenadeObject = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
if (pGrenadeObject)
|
|
{
|
|
pGrenadeObject->SetIsVisibleForModule(SETISVISIBLE_MODULE_GAMEPLAY, true, true);
|
|
}
|
|
}
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
if(m_MoveNetworkHelper.GetBoolean(ms_ThrowCompleteEvent) || m_MoveNetworkHelper.GetBoolean(ms_ReloadEvent) || fPhase>=m_fInterruptPhase)
|
|
{
|
|
if (!m_bHasThrownProjectile)
|
|
{
|
|
ThrowProjectileNow(pPed, pWeapon);
|
|
}
|
|
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
// aim gun thrown projectile tasks are run locally so shouldn't wait for the network state on the owner
|
|
if(m_bAimGunAndThrow)
|
|
{
|
|
SetState(State_Finish);
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
if(GetStateFromNetwork() != State_ThrowProjectile && GetStateFromNetwork() > State_Intro)
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false,true) && m_pFrameFilter == NULL)
|
|
{
|
|
pPed->GetWeaponManager()->CreateEquippedWeaponObject();
|
|
SetState(State_StreamingClips);
|
|
return FSM_Continue;
|
|
}
|
|
#endif
|
|
if(GetStateFromNetwork() == State_Finish)
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
|
|
if(GetStateFromNetwork()!=State_PullPin)
|
|
{
|
|
SetState(GetStateFromNetwork());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bIsOutOfAmmo = pPed->GetInventory()->GetIsWeaponOutOfAmmo(pPed->GetWeaponManager()->GetEquippedWeaponInfo());
|
|
if(bIsOutOfAmmo)
|
|
{
|
|
// Out of ammo - swap weapon
|
|
CThrowProjectileHelper::SetWeaponSlotAfterFiring(pPed);
|
|
|
|
// Quit if not a thrown weapon
|
|
const CWeaponInfo* pEquippedWeaponInfo = pPed->GetWeaponManager()->GetEquippedWeaponInfo();
|
|
if(pEquippedWeaponInfo && pEquippedWeaponInfo->GetIsThrownWeapon())
|
|
{
|
|
bIsOutOfAmmo = pPed->GetInventory()->GetIsWeaponOutOfAmmo(pEquippedWeaponInfo);
|
|
}
|
|
|
|
if(bIsOutOfAmmo)
|
|
{
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
if(pPed->GetWeaponManager()->GetRequiresWeaponSwitch())
|
|
{
|
|
if(!m_bHasReloaded)
|
|
{
|
|
if(!bIsOutOfAmmo GUN_PROJECTILE_THROW_ONLY(&& !m_bAimGunAndThrow))
|
|
{
|
|
m_bHasReloaded = true;
|
|
pPed->GetWeaponManager()->CreateEquippedWeaponObject();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon && !m_bAimGunAndThrow)
|
|
{
|
|
// Restart
|
|
m_bDropProjectile = false;
|
|
HandleFPSStateUpdate();
|
|
m_bPlayFPSTransition = true;
|
|
SetState(State_StreamingClips);
|
|
return FSM_Continue;
|
|
}
|
|
#endif
|
|
|
|
if (m_bDropProjectile)
|
|
{
|
|
SetState(State_Finish);
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if(pPed->IsPlayer())
|
|
{
|
|
m_bPriming = false;
|
|
m_bIsFiring = false;
|
|
m_bPinPulled = m_bHasNoPullPin;
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
m_bAimGunAndThrow = false;
|
|
pPed->GetPedIntelligence()->SetDoneAimGrenadeThrow();
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
else
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
{
|
|
SetState(State_HoldingProjectile);
|
|
}
|
|
}
|
|
else
|
|
SetState(State_Finish); //AI only toss once, for now (?)
|
|
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
else if(m_bHasThrownProjectile && m_MoveNetworkHelper.GetClip(s_ThrowClip) == NULL && pPed->IsNetworkClone())
|
|
{
|
|
if(GetStateFromNetwork() != State_ThrowProjectile && GetStateFromNetwork() > State_Intro)
|
|
{
|
|
if(GetStateFromNetwork() == State_Finish)
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
SetState(GetStateFromNetwork());
|
|
}
|
|
}
|
|
|
|
if(!m_bHasThrownProjectile)
|
|
{
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_TemporarilyBlockWeaponSwitching, true );
|
|
if(pClip)
|
|
CClipEventTags::FindEventPhase(pClip, CClipEventTags::Fire, m_fThrowPhase);
|
|
|
|
// When the fire anim event happens, throw the projectile
|
|
if(fPhase >= m_fThrowPhase)
|
|
{
|
|
if(!pPed->IsNetworkClone())
|
|
m_bFire = true;
|
|
else
|
|
{
|
|
if(CNetworkPendingProjectiles::GetProjectile(pPed, GetNetSequenceID(), false))
|
|
{
|
|
ThrowProjectileNow(pPed, pWeapon);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (pClip)
|
|
{
|
|
CClipEventTags::FindEventPhase<crPropertyAttributeBool>(pClip, CClipEventTags::Object, CClipEventTags::Create, true, m_fReloadPhase);
|
|
}
|
|
|
|
// When the reload anim event happens, create the projectile
|
|
if(!m_bHasReloaded && fPhase >= m_fReloadPhase && !pPed->IsNetworkClone() GUN_PROJECTILE_THROW_ONLY(&& !m_bAimGunAndThrow))
|
|
{
|
|
if(!pPed->GetInventory()->GetIsWeaponOutOfAmmo(pPed->GetWeaponManager()->GetEquippedWeaponInfo()))
|
|
{
|
|
m_bHasReloaded = true;
|
|
pPed->GetWeaponManager()->CreateEquippedWeaponObject();
|
|
}
|
|
}
|
|
|
|
if (CThrowProjectileHelper::IsPlayerRolling(pPed) && !m_bAimGunAndThrow)
|
|
{
|
|
m_bPriming = false;
|
|
m_bIsFiring = false;
|
|
m_bPinPulled = m_bHasNoPullPin;
|
|
SetState(State_CombatRoll);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if(GetPed()->IsFirstPersonShooterModeEnabledForPlayer(false))
|
|
{
|
|
const CClipEventTags::CCameraShakeTag* pCamShake = static_cast<const CClipEventTags::CCameraShakeTag*>(m_MoveNetworkHelper.GetNetworkPlayer()->GetProperty(CClipEventTags::CameraShake));
|
|
if (pCamShake)
|
|
{
|
|
if(pCamShake->GetShakeRefHash() != 0)
|
|
{
|
|
camInterface::GetGameplayDirector().GetFirstPersonShooterCamera()->Shake( pCamShake->GetShakeRefHash() );
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return FSM_Continue;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::ThrowProjectile_OnExit(CPed* pPed)
|
|
{
|
|
if (GetState() == State_HoldingProjectile)
|
|
{
|
|
float fBlendOutDuration = NORMAL_BLEND_DURATION;
|
|
pPed->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, fBlendOutDuration, CMovePed::Task_TagSyncTransition);
|
|
m_fBlockAimingIndependentMoverTime = fBlendOutDuration;
|
|
|
|
fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectile);
|
|
CreateNetworkPlayer(networkDefId);
|
|
m_MoveNetworkHelper.SetFlag(true, ms_SkipIntroId);
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, SLOW_BLEND_DURATION, CMovePed::Task_TagSyncContinuous);
|
|
m_MoveNetworkHelper.SetClipSet(m_iClipSet);
|
|
m_MoveNetworkHelper.SetClipSet(m_iStreamedClipSet, ms_StreamedClipSet);
|
|
|
|
SetGripClip();
|
|
|
|
if (m_bHasThrownProjectile && pPed->IsNetworkClone())
|
|
{
|
|
pPed->GetWeaponManager()->CreateEquippedWeaponObject();
|
|
}
|
|
}
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
m_pFPSWeaponMoveNetworkHelper = NULL;
|
|
#endif
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::StatePlaceProjectile_OnEnter(CPed* UNUSED_PARAM(pPed))
|
|
{
|
|
SetNewTask(rage_new CTaskBomb());
|
|
GetPed()->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, SLOW_BLEND_DURATION);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::StatePlaceProjectile_OnUpdate(CPed* pPed)
|
|
{
|
|
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
bool bUseFPSModeBehaviour = pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon;
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
pPed->SetPedResetFlag(CPED_RESET_FLAG_FPSPlacingProjectile, true);
|
|
}
|
|
|
|
if(!bUseFPSModeBehaviour)
|
|
#endif
|
|
{
|
|
GetPed()->SetIsStrafing(false);
|
|
}
|
|
|
|
if (GetIsFlagSet(aiTaskFlags::SubTaskFinished))
|
|
{
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
if(GetStateFromNetwork() != State_PlaceProjectile)
|
|
{
|
|
if(GetStateFromNetwork() == State_Finish && m_MoveNetworkHelper.IsNetworkActive())
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
SetState(GetStateFromNetwork());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nAmmo = pPed->GetInventory()->GetWeaponAmmo( pPed->GetWeaponManager()->GetEquippedWeaponInfo() );
|
|
if( pPed->GetWeaponManager()->GetRequiresWeaponSwitch() )
|
|
{
|
|
if( nAmmo == 0 )
|
|
pPed->GetWeaponManager()->EquipBestWeapon();
|
|
else if (m_MoveNetworkHelper.IsNetworkActive())
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
// Out of ammo - swap weapon
|
|
if( nAmmo == 0 )
|
|
{
|
|
if (m_MoveNetworkHelper.IsNetworkActive())
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
// Otherwise just reload (now through swap weapon)
|
|
SetState(State_Finish);
|
|
//SetState(State_Reload);
|
|
}
|
|
}
|
|
#if FPS_MODE_SUPPORTED
|
|
else if(bUseFPSModeBehaviour)
|
|
{
|
|
CTask* pSubTask = GetSubTask();
|
|
if(pSubTask && pSubTask->GetSubTask() && pSubTask->GetTaskType() == CTaskTypes::TASK_BOMB &&
|
|
pSubTask->GetSubTask()->GetTaskType() == CTaskTypes::TASK_SLIDE_TO_COORD)
|
|
{
|
|
const CClipHelper* pClipHelper = ((CTaskSlideToCoord*) (pSubTask->GetSubTask()))->GetSubTaskClip();
|
|
if(pClipHelper && pClipHelper->IsEvent( CClipEventTags::Interruptible ))
|
|
{
|
|
Vector3 vTargetPos(0.01f, 0.01f, 0.01f);
|
|
if(CTaskWeaponBlocked::IsWeaponBlocked( pPed, vTargetPos))
|
|
{
|
|
SetState(State_Blocked);
|
|
}
|
|
else
|
|
{
|
|
SetState(State_Finish);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void CTaskAimAndThrowProjectile::CombatRoll_OnEnter(CPed* pPed)
|
|
{
|
|
// increment the roll token to stop clone peds doing too many rolls on remote machines
|
|
if(!GetPed()->IsNetworkClone())
|
|
{
|
|
m_LastLocalRollToken++;
|
|
m_LastLocalRollToken%=MAX_ROLL_TOKEN;
|
|
}
|
|
else
|
|
{
|
|
m_LastCloneRollToken = m_LastLocalRollToken;
|
|
}
|
|
|
|
pPed->GetMotionData()->SetCombatRoll(true);
|
|
|
|
pPed->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, NORMAL_BLEND_DURATION);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::CombatRoll_OnUpdate(CPed* pPed)
|
|
{
|
|
if(!pPed->GetMotionData()->GetCombatRoll())
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false))
|
|
{
|
|
// Update FPS state at the end of combat roll.
|
|
HandleFPSStateUpdate();
|
|
m_bPlayFPSTransition = true;
|
|
SetState(State_StreamingClips);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
SetState(State_HoldingProjectile);
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if (m_MoveNetworkHelper.HasNetworkExpired())
|
|
{
|
|
CTask* pTask = pPed->GetPedIntelligence()->FindTaskActiveMotionByType(CTaskTypes::TASK_COMBAT_ROLL);
|
|
if (pTask)
|
|
{
|
|
if (static_cast<CTaskCombatRoll*>(pTask)->GetIsLanding())
|
|
{
|
|
fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectile);
|
|
CreateNetworkPlayer(networkDefId);
|
|
m_MoveNetworkHelper.SetFlag(true, ms_SkipIntroId);
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, REALLY_SLOW_BLEND_DURATION, CMovePed::Task_TagSyncContinuous);
|
|
m_MoveNetworkHelper.SetClipSet(m_iClipSet);
|
|
m_MoveNetworkHelper.SetClipSet(m_iStreamedClipSet, ms_StreamedClipSet);
|
|
|
|
SetGripClip();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void CTaskAimAndThrowProjectile::Reload_OnEnter(CPed* pPed)
|
|
{
|
|
//DEPRECATED
|
|
pPed->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, NORMAL_BLEND_DURATION);
|
|
//fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectileReload);
|
|
//CreateNetworkPlayer(networkDefId);
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, SLOW_BLEND_DURATION, CMovePed::Task_TagSyncContinuous);
|
|
m_MoveNetworkHelper.SetClipSet(m_iClipSet);
|
|
m_MoveNetworkHelper.SetClipSet(m_iStreamedClipSet, ms_StreamedClipSet);
|
|
|
|
SetGripClip();
|
|
|
|
m_bHasReloaded = false;
|
|
m_MoveNetworkHelper.WaitForTargetState(ms_ReloadEvent);
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::Reload_OnUpdate(CPed* pPed)
|
|
{
|
|
if(!m_MoveNetworkHelper.IsInTargetState())
|
|
return FSM_Continue;
|
|
|
|
// Doing this in Reload_OnEnter is always a frame early
|
|
static const fwMvClipId s_ReloadClip("ReloadClip",0x7F6D7B74);
|
|
const crClip* pClip = m_MoveNetworkHelper.GetClip(s_ReloadClip);
|
|
if (pClip)
|
|
{
|
|
CClipEventTags::FindEventPhase<crPropertyAttributeBool>(pClip, CClipEventTags::Object, CClipEventTags::Create, true, m_fReloadPhase);
|
|
}
|
|
|
|
// When the reload anim event happens, create the projectile
|
|
float fPhase = m_MoveNetworkHelper.GetFloat(ms_ReloadPhase);
|
|
if(!m_bHasReloaded && fPhase >= m_fReloadPhase && !pPed->IsNetworkClone())
|
|
{
|
|
pPed->GetWeaponManager()->CreateEquippedWeaponObject();
|
|
}
|
|
|
|
if(m_MoveNetworkHelper.GetBoolean(ms_ReloadCompleteEvent))
|
|
{
|
|
if(pPed->IsPlayer())
|
|
{
|
|
m_bPriming = false;
|
|
m_bIsFiring = false;
|
|
SetState(State_HoldingProjectile);
|
|
}
|
|
else
|
|
SetState(State_Finish); //AI only toss once, for now (?)
|
|
}
|
|
|
|
// catch an exit on the owner
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
if(GetStateFromNetwork() == State_Finish)
|
|
{
|
|
SetState(State_Finish);
|
|
m_MoveNetworkHelper.SendRequest(ms_StartFinish);
|
|
}
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::Reload_OnExit(CPed* pPed)
|
|
{
|
|
if (GetState() == State_HoldingProjectile)
|
|
{
|
|
pPed->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, NORMAL_BLEND_DURATION);
|
|
fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectile);
|
|
CreateNetworkPlayer(networkDefId);
|
|
m_MoveNetworkHelper.SetFlag(true, ms_SkipIntroId);
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, SLOW_BLEND_DURATION, CMovePed::Task_TagSyncContinuous);
|
|
m_MoveNetworkHelper.SetClipSet(m_iClipSet);
|
|
m_MoveNetworkHelper.SetClipSet(m_iStreamedClipSet, ms_StreamedClipSet);
|
|
|
|
SetGripClip();
|
|
}
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::CloneIdle_OnEnter(CPed* pPed)
|
|
{
|
|
if (m_MoveNetworkHelper.GetNetworkPlayer())
|
|
{
|
|
pPed->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, SLOW_BLEND_DURATION);
|
|
}
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::CloneIdle_OnUpdate(CPed* pPed)
|
|
{
|
|
if (!NetworkInterface::UseFirstPersonIdleMovementForRemotePlayer(*pPed))
|
|
{
|
|
SetState(State_StreamingClips);
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::Outro_OnEnter(CPed* UNUSED_PARAM(pPed))
|
|
{
|
|
m_MoveNetworkHelper.WaitForTargetState(ms_EnterOutroEvent);
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::Outro_OnUpdate(CPed* pPed)
|
|
{
|
|
//standing delays the animation for the strafe longer outro B* 942701
|
|
static dev_float s_fStandOutroDelay = 0.5f;
|
|
if (pPed->GetMotionData()->GetCurrentMbrY() == MOVEBLENDRATIO_STILL && GetTimeInState()<s_fStandOutroDelay && !pPed->GetWeaponManager()->GetRequiresWeaponSwitch())
|
|
return FSM_Continue;
|
|
m_MoveNetworkHelper.SendRequest(ms_StartOutro);
|
|
|
|
if(!m_MoveNetworkHelper.IsInTargetState())
|
|
return FSM_Continue;
|
|
|
|
float fPhase = m_MoveNetworkHelper.GetFloat(ms_TransitionPhase);
|
|
static dev_float sf_OutroPhaseOut = 0.8f;
|
|
if (fPhase >= sf_OutroPhaseOut)
|
|
{
|
|
SetState(State_Finish);
|
|
}
|
|
|
|
if(!pPed->IsNetworkClone() && m_bCanBePlaced && !IsAiming(pPed) && (m_bPriming || CThrowProjectileHelper::IsPlayerPriming(pPed)))
|
|
{
|
|
// hold up on any animation to make sure the player doesn't want to just place
|
|
SetPriming(pPed, true);
|
|
if (IsFiring(pPed) && CanPlaceProjectile(pPed))
|
|
{
|
|
// Switch to move to state
|
|
SetState(State_PlaceProjectile);
|
|
}
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
|
|
dev_float ROLL_ANIM_SCALE = 0.5f;
|
|
dev_float MIN_COVER_THROW_HEIGHT_RELATIVE_TO_PED = 0.65f;
|
|
|
|
void CTaskAimAndThrowProjectile::ThrowProjectileNow(CPed* pPed, CWeapon* pWeapon, Vector3 *pvOverrideStartPosition)
|
|
{
|
|
if(!pPed->IsNetworkClone())
|
|
{
|
|
Assert(pWeapon);
|
|
Assert(pWeapon->GetWeaponInfo());
|
|
}
|
|
Assert(pPed->GetWeaponManager());
|
|
|
|
// time to throw the projectile
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
CProjectileManager::FireOrPlacePendingProjectile(pPed, GetNetSequenceID());
|
|
|
|
// Ensure object is removed
|
|
pPed->GetWeaponManager()->DestroyEquippedWeaponObject();
|
|
}
|
|
else
|
|
{
|
|
Assert(pPed->GetWeaponManager());
|
|
CObject* pProjOverride = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
|
|
// Calculate the launch position
|
|
const s32 nBoneIndex = GUN_PROJECTILE_THROW_ONLY(m_bAimGunAndThrow ? pPed->GetBoneIndexFromBoneTag(BONETAG_L_PH_HAND) :) pPed->GetBoneIndexFromBoneTag(BONETAG_R_HAND);
|
|
|
|
Assert(nBoneIndex != BONETAG_INVALID);
|
|
|
|
//Get an up-to-date position before throwing (saves us from calling pProjOverride->ProcessAttachment()).
|
|
Matrix34 matOffset;
|
|
matOffset.Identity();
|
|
Matrix34 matUpdated;
|
|
bool bUseMatUpdated = false;
|
|
fwAttachmentEntityExtension* pExtension = pProjOverride ? pProjOverride->GetAttachmentExtension() : NULL;
|
|
if (pExtension)
|
|
{
|
|
Matrix34 matParent;
|
|
pPed->GetGlobalMtx(nBoneIndex, matParent);
|
|
matOffset.FromQuaternion(pExtension->GetAttachQuat());
|
|
matOffset.d = pExtension->GetAttachOffset();
|
|
matUpdated.Dot(matOffset, matParent);
|
|
bUseMatUpdated = true;
|
|
}
|
|
|
|
Matrix34 weaponMat;
|
|
if (bUseMatUpdated)
|
|
weaponMat = matUpdated;
|
|
else if( pProjOverride)
|
|
weaponMat = MAT34V_TO_MATRIX34(pProjOverride->GetMatrix());
|
|
else
|
|
pPed->GetGlobalMtx(nBoneIndex, weaponMat);
|
|
|
|
Vector3 vStart(Vector3::ZeroType);
|
|
Vector3 vEnd(Vector3::ZeroType);
|
|
if (pvOverrideStartPosition!=NULL)
|
|
vStart = *pvOverrideStartPosition;
|
|
else if (pPed->IsLocalPlayer())
|
|
{
|
|
const camFrame& aimFrame = camInterface::GetPlayerControlCamAimFrame();
|
|
vStart = aimFrame.GetPosition();
|
|
Vector3 vShot = aimFrame.GetFront();
|
|
// Move source of gunshot vector along to the gun muzzle so can't hit anything behind the gun.
|
|
f32 fShotDot = vShot.Dot(weaponMat.d - vStart);
|
|
vStart += fShotDot * vShot;
|
|
}
|
|
else
|
|
{
|
|
vStart = GUN_PROJECTILE_THROW_ONLY(m_bAimGunAndThrow ? pPed->GetBonePositionCached((eAnimBoneTag)BONETAG_L_PH_HAND) :) pPed->GetBonePositionCached((eAnimBoneTag)BONETAG_R_HAND);
|
|
}
|
|
|
|
//If this is a drop..
|
|
if( m_bDropProjectile )
|
|
{
|
|
Vector3 trajectory;
|
|
if (!pWeapon->GetWeaponInfo()->GetThrowOnly())
|
|
{
|
|
trajectory.Zero();
|
|
}
|
|
else if( m_bDropUnderhand )
|
|
{
|
|
trajectory = VEC3V_TO_VECTOR3(pPed->GetTransform().GetB()) * pWeapon->GetWeaponInfo()->GetDropForwardVelocity();
|
|
}
|
|
else
|
|
{
|
|
trajectory = VEC3V_TO_VECTOR3(pPed->GetTransform().GetB()) * -(pWeapon->GetWeaponInfo()->GetDropForwardVelocity() * 0.5f);
|
|
}
|
|
vEnd = weaponMat.d + trajectory;
|
|
vStart = weaponMat.d;
|
|
}
|
|
else
|
|
{
|
|
bool bValidTargetPosition = false;
|
|
if( pPed->IsLocalPlayer() && pPed->GetPlayerInfo() && !pPed->GetPlayerInfo()->AreControlsDisabled() )
|
|
{
|
|
// First check for the more precise reading, the camera aim at position
|
|
const CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
const CObject* pWeaponObject = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
if( pWeaponObject )
|
|
{
|
|
Vector3 vStartTemp( Vector3::ZeroType );
|
|
bValidTargetPosition = pWeapon->CalcFireVecFromAimCamera( pPed->GetIsInVehicle() ? static_cast<CEntity*>(pPed->GetMyVehicle()) : pPed, weaponMat, vStartTemp, vEnd );
|
|
}
|
|
}
|
|
|
|
// Now scale up to weapon range
|
|
if( !bValidTargetPosition && m_target.GetIsValid() )
|
|
bValidTargetPosition = m_target.GetPositionWithFiringOffsets( pPed, vEnd );
|
|
}
|
|
|
|
float fOverrideLifeTime = -1.0f;
|
|
|
|
if(!pWeapon->GetIsCooking()) //NOW everything cooks that can
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
if (pWeapon->GetWeaponInfo()->GetProjectileFuseTime() > 0.0f)
|
|
fOverrideLifeTime = Max(0.0f, pWeapon->GetCookTimeLeft(pPed, fwTimer::GetTimeInMilliseconds()));
|
|
|
|
//if( m_bDropProjectile ) removed per B* 1296215
|
|
// fOverrideLifeTime *= 2.0f; //dropped projectiles get more time.
|
|
|
|
// Throw the projectile
|
|
#if __BANK
|
|
CTask::ms_debugDraw.AddSphere(RCC_VEC3V(vEnd), 0.1f, Color_orange, 1000);
|
|
#endif
|
|
CWeapon::sFireParams params(pPed, weaponMat, &vStart, &vEnd);
|
|
params.fOverrideLifeTime = fOverrideLifeTime;
|
|
params.fDesiredTargetDistance = vStart.Dist( vEnd );
|
|
params.pIgnoreCollisionEntity = m_pIgnoreCollisionEntity;
|
|
if (m_pIgnoreCollisionEntity)
|
|
{
|
|
params.pIgnoreDamageEntity = m_pIgnoreCollisionEntity;
|
|
params.bIgnoreDamageEntityAttachParent = true;
|
|
}
|
|
|
|
if (m_bDropProjectile)
|
|
{
|
|
if (pWeapon && (pWeapon->GetWeaponHash()!=ATSTRINGHASH("WEAPON_MOLOTOV", 0x24B17070) &&
|
|
pWeapon->GetWeaponHash()!=ATSTRINGHASH("WEAPON_FLARE", 0x497facc3)))
|
|
{
|
|
params.iFireFlags.SetFlag(CWeapon::FF_DisableProjectileTrail);
|
|
}
|
|
}
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
// Only set the "bProjectileCreatedFromGrenadeThrow" flag if we threw from using the DPad input as this temporarily blocks bomb detonation until it is released.
|
|
params.bProjectileCreatedFromGrenadeThrow = m_bAimGunAndThrow && m_bProjectileThrownFromDPadInput;
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
pWeapon->Fire(params);
|
|
// Ensure object is removed
|
|
pPed->GetWeaponManager()->DestroyEquippedWeaponObject();
|
|
}
|
|
|
|
m_bHasThrownProjectile = true;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::Blocked_OnEnter(CPed* UNUSED_PARAM(pPed))
|
|
{
|
|
SetNewTask( rage_new CTaskWeaponBlocked( CWeaponController::WCT_Player ) );
|
|
return;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::Blocked_OnUpdate(CPed *pPed)
|
|
{
|
|
|
|
if( GetIsFlagSet( aiTaskFlags::SubTaskFinished ) )
|
|
{
|
|
SetState(State_StreamingClips);
|
|
}
|
|
else
|
|
{
|
|
bool bUseFPSModeBehaviour = pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon;
|
|
|
|
Vector3 vTargetPos(0.01f, 0.01f, 0.01f);
|
|
if(!CTaskWeaponBlocked::IsWeaponBlocked( pPed, vTargetPos))
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
HandleFPSStateUpdate();
|
|
CWeapon* pWeapon = pPed->GetWeaponManager() ? pPed->GetWeaponManager()->GetEquippedWeapon() : NULL;
|
|
//Play a "to RNG" transition only if we want to cook the weapon after exiting the block state
|
|
if(pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetCookWhileAiming() &&
|
|
!pWeapon->GetIsCooking() && (m_bFPSWantsToThrowWhenReady || m_bDropProjectile))
|
|
{
|
|
m_bPlayFPSTransition = true;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
SetState(State_StreamingClips);
|
|
}
|
|
else if(bUseFPSModeBehaviour && m_bCanBePlaced && !pPed->GetPedResetFlag(CPED_RESET_FLAG_InAirDefenceSphere))
|
|
{
|
|
#if FPS_MODE_SUPPORTED
|
|
if(!pPed->GetMotionData()->GetIsFPSRNG() && pPed->GetMotionData()->GetWasFPSRNG() && CanPlaceProjectile(pPed))
|
|
{
|
|
HandleFPSStateUpdate();
|
|
m_bPlayFPSTransition = false;
|
|
SetState(State_StreamingClips);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
|
|
void CTaskAimAndThrowProjectile::UpdateTarget(CPed* pPed)
|
|
{
|
|
if(pPed && pPed->IsPlayer())
|
|
{
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
if(static_cast<CNetObjPlayer*>(pPed->GetNetworkObject())->HasValidTarget())
|
|
{
|
|
m_target.SetPosition(pPed->GetWeaponManager()->GetWeaponAimPosition());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_target.Update(pPed);
|
|
|
|
Vector3 vTargetPosition;
|
|
if(m_target.GetIsValid() && m_target.GetPositionWithFiringOffsets(pPed, vTargetPosition))
|
|
{
|
|
pPed->GetWeaponManager()->SetWeaponAimPosition(vTargetPosition);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::DoAbort(const AbortPriority UNUSED_PARAM(iPriority), const aiEvent* pEvent)
|
|
{
|
|
CPed *pPed = GetPed(); //Get the ped ptr.
|
|
|
|
if(pEvent && ((CEvent*)pEvent)->GetEventType() == EVENT_DAMAGE && GetState() == State_HoldingProjectile)
|
|
{
|
|
// Drop Molotov's of holding it ready to fir. Drop them straight down.
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetDamageType() == DAMAGE_TYPE_FIRE)
|
|
{
|
|
m_bDropProjectile = true;
|
|
ThrowProjectileNow(pPed,pWeapon, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CTaskAimAndThrowProjectile::HasValidWeapon(CPed* pPed) const
|
|
{
|
|
const CWeaponInfo* pWeaponInfo = pPed->GetWeaponManager()->GetEquippedWeaponInfo();
|
|
if(!pWeaponInfo)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Allow any weapon to be valid if we are throwing a grenade while aiming (we already filter the weapon types before setting this flag)
|
|
if (pPed->GetPedResetFlag(CPED_RESET_FLAG_IsThrowingProjectileWhileAiming))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(!pWeaponInfo->GetIsThrownWeapon())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::CreateNetworkPlayer(fwMvNetworkDefId networkDefId)
|
|
{
|
|
m_MoveNetworkHelper.CreateNetworkPlayer(GetPed(), networkDefId);
|
|
m_NetworkDefId = networkDefId;
|
|
}
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
void CTaskAimAndThrowProjectile::CreateDummyWeaponObject(CPed *pPed, CWeapon *pWeapon, const CWeaponInfo *pWeaponInfo)
|
|
{
|
|
if (pPed && pWeapon && pWeaponInfo)
|
|
{
|
|
// Create a temp weapon object to attach to the peds hand
|
|
m_pTempWeaponObject = pPed->GetWeaponManager()->DropWeapon(pPed->GetWeaponManager()->GetEquippedWeaponHash(), false, false, true);
|
|
if (m_pTempWeaponObject)
|
|
{
|
|
s32 iPedBoneIndex = pPed->GetBoneIndexFromBoneTag(BONETAG_R_PH_HAND);
|
|
// Get the object bone
|
|
s32 iObjectBoneIndex = -1;
|
|
CWeaponModelInfo* pWeaponModelInfo = m_pTempWeaponObject->GetBaseModelInfo() ? static_cast<CWeaponModelInfo*>(m_pTempWeaponObject->GetBaseModelInfo()) : NULL;
|
|
if(pWeaponModelInfo)
|
|
{
|
|
iObjectBoneIndex = pWeaponModelInfo->GetBoneIndex(WEAPON_GRIP_R);
|
|
CPedEquippedWeapon::AttachObjects(pPed, m_pTempWeaponObject, iPedBoneIndex, iObjectBoneIndex);
|
|
}
|
|
}
|
|
|
|
// Equip & create the grenade
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
if(pPed->GetInventory() && !pPed->GetInventory()->GetWeapon(m_uAimAndThrowWeaponHash))
|
|
{
|
|
pPed->GetInventory()->AddWeapon(m_uAimAndThrowWeaponHash);
|
|
}
|
|
|
|
pPed->GetWeaponManager()->EquipWeapon(m_uAimAndThrowWeaponHash, -1, true, false, CPedEquippedWeapon::AP_LeftHand);
|
|
}
|
|
else
|
|
{
|
|
pPed->GetWeaponManager()->EquipWeapon(m_uAimAndThrowWeaponHash, -1, true, false, CPedEquippedWeapon::AP_LeftHand);
|
|
}
|
|
|
|
// Make the grenade invisible (gets set to visible again once we have reached a certain point in the throw animation).
|
|
CObject *pGrenadeObject = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
if (pGrenadeObject)
|
|
{
|
|
pGrenadeObject->SetIsVisibleForModule(SETISVISIBLE_MODULE_GAMEPLAY, false, true);
|
|
}
|
|
|
|
// Update the pWeapon/pWeaponInfo
|
|
pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
pWeaponInfo = pWeapon ? pWeapon->GetWeaponInfo() : NULL;
|
|
}
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
bool CTaskAimAndThrowProjectile::HandleFPSStateUpdate()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
bool rVal = false;
|
|
|
|
if(pPed->IsLocalPlayer())
|
|
{
|
|
bool bUseFPSMode = pPed->IsFirstPersonShooterModeEnabledForPlayer(false);
|
|
|
|
if(m_MoveNetworkHelper.IsNetworkActive() && m_bFPSUseAimIKForWeapon)
|
|
{
|
|
m_MoveNetworkHelper.SetFlag(bUseFPSMode, ms_UsingFPSMode);
|
|
}
|
|
|
|
if(bUseFPSMode)
|
|
{
|
|
CPedMotionData* pMotionData = pPed->GetMotionData();
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fDropThrowSwitchDelay, 0.5f, 0.0, 2.0f, 0.01f);
|
|
bool bDropThrowSwitch = m_fFPSDropThrowSwitchTimer >= fDropThrowSwitchDelay || m_fFPSDropThrowSwitchTimer < 0.0f;
|
|
bool bNonInterruptibleIntro = m_bPlayFPSRNGIntro || m_bPlayFPSPullPinIntro;
|
|
|
|
if(!m_bAllowPriming)
|
|
{
|
|
bool bSwitchedAimingState = m_bWasAiming != IsAiming(pPed);
|
|
if(bSwitchedAimingState)
|
|
{
|
|
m_bPlayFPSTransition = true;
|
|
rVal = true;
|
|
}
|
|
}
|
|
else if(pPed->GetMotionData()->GetIsFPSRNG() && m_bAllowPriming)
|
|
{
|
|
if(!m_bFPSWantsToThrowWhenReady && !m_bDropProjectile)
|
|
{
|
|
if(IsAiming(pPed) || m_bPlayFPSPullPinIntro)
|
|
{
|
|
m_bFPSWantsToThrowWhenReady = true;
|
|
}
|
|
else
|
|
{
|
|
m_bDropProjectile = true;
|
|
}
|
|
|
|
// We just switched to RNG and aren't already playig a RNG intro (if we are, don't interrupt it)
|
|
if(!pPed->GetMotionData()->GetWasFPSRNG() && !bNonInterruptibleIntro)
|
|
{
|
|
if(!m_bCanBePlaced)
|
|
{
|
|
m_bPlayFPSTransition = true;
|
|
}
|
|
|
|
m_fFPSDropThrowSwitchTimer = 0.0f;
|
|
m_bPlayFPSFidget = false;
|
|
rVal = true;
|
|
}
|
|
}
|
|
else if(!bNonInterruptibleIntro && bDropThrowSwitch)
|
|
{
|
|
if(IsAiming(pPed))
|
|
{
|
|
if(m_bDropProjectile)
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
m_bDropProjectile = false;
|
|
m_bFPSWantsToThrowWhenReady = true;
|
|
m_fFPSDropThrowSwitchTimer = 0.0f;
|
|
rVal = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!m_bDropProjectile)
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
m_bDropProjectile = true;
|
|
m_bFPSWantsToThrowWhenReady = false;
|
|
m_fFPSDropThrowSwitchTimer = 0.0f;
|
|
rVal = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(m_bDropProjectile && IsFiring(pPed) && m_bCanBePlaced && CanPlaceProjectile(pPed))
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
rVal = true;
|
|
}
|
|
|
|
if(GetState() != State_ThrowProjectile && GetState() != State_StreamingClips &&
|
|
!m_bDropProjectile && !m_bFPSWantsToThrowWhenReady &&
|
|
pMotionData && (pMotionData->GetFPSState() != pMotionData->GetPreviousFPSState() || pMotionData->GetToggledStealthWhileFPSIdle()) && !pMotionData->GetWasFPSRNG())
|
|
{
|
|
//Restart task
|
|
m_bPlayFPSTransition = true;
|
|
rVal = true;
|
|
}
|
|
}
|
|
|
|
// In this case, the unholster transition may already be playing so we want to skip this
|
|
/*if(!m_bWasInFPSMode && bUseFPSMode && !m_bPlayFPSTransition)
|
|
{
|
|
//m_bSkipFPSOutroState = true;
|
|
m_bPlayFPSTransition = true;
|
|
rVal = true;
|
|
}
|
|
else if(m_bWasInFPSMode && !bUseFPSMode)
|
|
{
|
|
m_bPlayFPSTransition = false;
|
|
rVal = true;
|
|
}
|
|
|
|
m_bWasInFPSMode = bUseFPSMode;*/
|
|
}
|
|
|
|
return rVal;
|
|
}
|
|
#endif
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::ProcessPreFSM()
|
|
{
|
|
CPed *pPed = GetPed(); //Get the ped ptr.
|
|
|
|
CPedWeaponManager* pWM = pPed->GetWeaponManager();
|
|
if(!weaponVerifyf(pWM, "CTaskAimAndThrowProjectile :: Player has no weapon manager!"))
|
|
return FSM_Quit;
|
|
|
|
if(!pPed->IsNetworkClone() && !HasValidWeapon(pPed))
|
|
{
|
|
taskDebugf1("CTaskAimAndThrowProjectile::ProcessPreFSM: FSM_Quit - !HasValidWeapon. Previous State: %d", GetPreviousState());
|
|
return FSM_Quit;
|
|
}
|
|
|
|
// Update the heading
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_SyncDesiredHeadingToCurrentHeading, false );
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_IsAiming, true );
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_ProcessPostPreRender, true );
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_ProcessPostPreRenderAfterAttachments, true );
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
bool bFPSMode = pPed->IsFirstPersonShooterModeEnabledForPlayer(false);
|
|
|
|
if(!m_bFPSUseAimIKForWeapon && bFPSMode && pPed->GetEquippedWeaponInfo() && pPed->GetEquippedWeaponInfo()->GetUseFPSAimIK())
|
|
{
|
|
m_bFPSUseAimIKForWeapon = true;
|
|
}
|
|
|
|
bool bUseFPSModeBehaviour = bFPSMode && m_bFPSUseAimIKForWeapon;
|
|
|
|
if(bUseFPSModeBehaviour && m_fFPSTaskNetworkBlendDuration >= 0.0f && m_fFPSTaskNetworkBlendTimer <= m_fFPSTaskNetworkBlendDuration)
|
|
{
|
|
m_fFPSTaskNetworkBlendTimer += fwTimer::GetTimeStep();
|
|
}
|
|
|
|
if(bUseFPSModeBehaviour && m_fFPSDropThrowSwitchTimer >= 0.0f)
|
|
{
|
|
m_fFPSDropThrowSwitchTimer += fwTimer::GetTimeStep();
|
|
}
|
|
|
|
bool bJustSwitchedToFPSMode = bFPSMode && !pPed->GetMotionData()->GetWasUsingFPSMode();
|
|
|
|
bool bTaskNetworkBlendedIn = m_fFPSTaskNetworkBlendTimer > m_fFPSTaskNetworkBlendDuration;
|
|
if(bUseFPSModeBehaviour && (!m_bFPSPlayingUnholsterIntro || bTaskNetworkBlendedIn) &&
|
|
(bJustSwitchedToFPSMode || m_bPlayFPSPullPinIntro || pPed->GetMotionData()->GetIsFPSRNG() || GetState() == State_HoldingProjectile || GetState() == State_Intro || GetState() == State_ThrowProjectile || GetState() == State_Blocked))
|
|
{
|
|
pPed->SetPedResetFlag(CPED_RESET_FLAG_FPSAllowAimIKForThrownProjectile, true);
|
|
}
|
|
|
|
if (bUseFPSModeBehaviour && GetState() == State_PlaceProjectile)
|
|
{
|
|
pPed->SetPedResetFlag(CPED_RESET_FLAG_DisableFPSArmIK, true);
|
|
}
|
|
|
|
if(bUseFPSModeBehaviour && !pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_PlayFPSIdleFidgetsForProjectile))
|
|
{
|
|
m_bMoveFPSFidgetEnded = false;
|
|
}
|
|
#endif
|
|
|
|
CWeapon* pWeapon = pWM->GetEquippedWeapon();
|
|
bool bAttackTriggerHeld = pPed->IsLocalPlayer() && CThrowProjectileHelper::IsPlayerPriming(pPed);
|
|
#if FPS_MODE_SUPPORTED
|
|
if(bUseFPSModeBehaviour)
|
|
{
|
|
bAttackTriggerHeld |= pPed->GetMotionData()->GetIsFPSRNG();
|
|
}
|
|
#endif
|
|
|
|
if(pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->GetIsThrownWeapon() && !bAttackTriggerHeld)
|
|
{
|
|
m_bAllowPriming = true;
|
|
}
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
pPed->SetPedResetFlag(CPED_RESET_FLAG_IsThrowingProjectileWhileAiming, true);
|
|
|
|
// If the player releases the grenade throw DPad input, unflag it so we can detonate the projectile instantly.
|
|
CControl *pControl = pPed->GetControlFromPlayer();
|
|
if (m_bProjectileThrownFromDPadInput && pControl && pControl->GetPedThrowGrenade().IsReleased())
|
|
{
|
|
m_bProjectileThrownFromDPadInput = false;
|
|
}
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
|
|
// cache weapon attributes
|
|
if(!m_bHasCachedWeaponValues)
|
|
{
|
|
bool bHasCached = true;
|
|
|
|
if(pWeapon)
|
|
{
|
|
// check to see if this is placeable
|
|
const CWeaponInfo* pWeaponInfo = pWeapon->GetWeaponInfo();
|
|
if(pWeaponInfo)
|
|
{
|
|
m_bCanBePlaced = pWeaponInfo->GetProjectileCanBePlaced();
|
|
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
if (m_bAimGunAndThrow)
|
|
{
|
|
m_bCanBePlaced = false;
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
const CAmmoInfo* pAmmoInfo = pWeaponInfo->GetAmmoInfo();
|
|
if(pAmmoInfo && pAmmoInfo->GetIsClassId(CAmmoProjectileInfo::GetStaticClassId()))
|
|
{
|
|
m_bPinPulled = m_bHasNoPullPin = static_cast<const CAmmoProjectileInfo*>(pAmmoInfo)->GetNoPullPin() || pWeapon->GetIsCooking();
|
|
}
|
|
else
|
|
{
|
|
bHasCached = false;
|
|
}
|
|
}
|
|
else
|
|
bHasCached = false;
|
|
}
|
|
else
|
|
bHasCached = false;
|
|
|
|
m_bHasCachedWeaponValues = bHasCached;
|
|
}
|
|
|
|
// force target update
|
|
UpdateTarget(pPed);
|
|
|
|
s32 nCurrentState = GetState();
|
|
if (pPed->IsLocalPlayer())
|
|
{
|
|
if(!pPed->GetUsingRagdoll() && !pPed->GetPlayerInfo()->AreControlsDisabled())
|
|
{
|
|
if( nCurrentState != State_PlaceProjectile && /*nCurrentState != State_StreamingClips && */!m_bDropProjectile)
|
|
{
|
|
const camFrame& frame = camInterface::GetPlayerControlCamAimFrame();
|
|
float aimHeading = frame.ComputeHeading();
|
|
#if FPS_MODE_SUPPORTED
|
|
if(pPed->IsFirstPersonShooterModeEnabledForPlayer(false, false, true, true))
|
|
{
|
|
aimHeading = camInterface::GetPlayerControlCamHeading(*pPed);
|
|
}
|
|
#endif
|
|
aimHeading = fwAngle::LimitRadianAngle(aimHeading);
|
|
pPed->SetDesiredHeading(aimHeading);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bool bClonedPlayer = pPed->IsNetworkClone() && pPed->IsPlayer();
|
|
|
|
if (m_target.GetIsValid() && !bClonedPlayer)
|
|
{
|
|
Vector3 vTargetPos;
|
|
m_target.GetPosition(vTargetPos);
|
|
pPed->SetDesiredHeading(vTargetPos);
|
|
}
|
|
}
|
|
|
|
// B*2027357: Don't adjust the capsule size for the non-aiming holding projectile state in first person mode.
|
|
// In first person mode, the holding projectile state is run even if the ped isn't actually aiming unlike third-person.
|
|
// Therefore the holding projectile state while not aiming is analogous to the non-aiming state in third-person and should therefore have the same behavior as that.
|
|
bool bAdjustCapsuleForHolding = true;
|
|
if(pPed->IsLocalPlayer() && pPed->IsFirstPersonShooterModeEnabledForPlayer() && !IsAiming(pPed))
|
|
bAdjustCapsuleForHolding = false;
|
|
|
|
if( (nCurrentState == State_HoldingProjectile && bAdjustCapsuleForHolding) ||
|
|
nCurrentState == State_ThrowProjectile ||
|
|
nCurrentState == State_Reload )
|
|
{
|
|
if (!pPed->GetPedResetFlag(CPED_RESET_FLAG_IsNearDoor)) //not near doors!
|
|
pPed->SetDesiredMainMoverCapsuleRadius( CTaskAimAndThrowProjectile::m_sfThrowingMainMoverCapsuleRadius );
|
|
}
|
|
|
|
if (CTaskAimGun::ms_bUseTorsoIk)
|
|
{
|
|
// Pitch handled via animation
|
|
m_ikInfo.SetDisablePitchFixUp(true);
|
|
|
|
//TUNE_GROUP_FLOAT(NEW_GUN_TASK, SPINE_MATRIX_INTERP_RATE, 4.0f, 0.0f, 1000.0f, 0.1f);
|
|
m_ikInfo.SetSpineMatrixInterpRate(4.0f);
|
|
|
|
// Apply the Ik
|
|
m_ikInfo.ApplyIkInfo(pPed);
|
|
}
|
|
|
|
m_fBlockAimingIndependentMoverTime -= GetTimeStep();
|
|
if(m_fBlockAimingIndependentMoverTime >= 0.f)
|
|
{
|
|
CTaskMotionBase* pMotionTask = pPed->GetPrimaryMotionTask();
|
|
if(pMotionTask && pMotionTask->GetTaskType() == CTaskTypes::TASK_MOTION_PED)
|
|
{
|
|
CTaskMotionPed* pMotionPedTask = static_cast<CTaskMotionPed*>(pMotionTask);
|
|
pMotionPedTask->SetDoAimingIndependentMover(true);
|
|
}
|
|
}
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
bool bFPSLTorRNG = pPed->GetMotionData() && (pPed->GetMotionData()->GetIsFPSLT() || pPed->GetMotionData()->GetIsFPSRNG());
|
|
//Don't do sprint/aim breakout if swimming
|
|
if(pPed->IsLocalPlayer() && bUseFPSModeBehaviour && !pPed->GetIsSwimming() && !bFPSLTorRNG && !pPed->IsFirstPersonShooterModeEnabledForPlayer() && !m_bFPSWantsToThrowWhenReady && !m_bDropProjectile)
|
|
{
|
|
bool bHitSprintMBR = false;
|
|
const Vector2 &desiredMBR = pPed->GetMotionData()->GetDesiredMoveBlendRatio();
|
|
if(abs(desiredMBR.x) > 0.01f)
|
|
{
|
|
bHitSprintMBR = pPed->GetMotionData()->GetIsSprinting(desiredMBR.Mag());
|
|
}
|
|
else
|
|
{
|
|
bHitSprintMBR = pPed->GetMotionData()->GetIsSprinting(desiredMBR.y);
|
|
}
|
|
|
|
float fSprintResult = pPed->GetPlayerInfo()->ControlButtonSprint(CPlayerInfo::SPRINT_ON_FOOT, true);
|
|
|
|
static dev_float s_fSprintResultThreshold = 1.25f;
|
|
|
|
bool bSprinting = bHitSprintMBR && (fSprintResult >= s_fSprintResultThreshold);
|
|
|
|
if(bSprinting && GetState() != State_ThrowProjectile && GetState() != State_StreamingClips && GetState() != State_Blocked
|
|
#if FPS_MODE_SUPPORTED
|
|
&& !pPed->GetPedResetFlag(CPED_RESET_FLAG_WeaponBlockedInFPSMode)
|
|
#endif // FPS_MODE_SUPPORTED
|
|
)
|
|
{
|
|
pPed->GetPlayerInfo()->SprintAimBreakOut();
|
|
taskDebugf1("CTaskAimAndThrowProjectile::ProcessPreFSM: FSM_Quit - bSprinting. Previous State: %d", GetPreviousState());
|
|
return FSM_Quit;
|
|
}
|
|
}
|
|
|
|
UpdateAdditives();
|
|
|
|
#endif // FPS_MODE_SUPPORTED
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::UpdateFSM( const s32 iState, const FSM_Event iEvent )
|
|
{
|
|
CPed *pPed = GetPed(); //Get the ped ptr.
|
|
|
|
FSM_Begin
|
|
FSM_State(State_Start)
|
|
FSM_OnUpdate
|
|
Start_OnUpdate(pPed);
|
|
|
|
// Task start
|
|
FSM_State(State_StreamingClips)
|
|
FSM_OnEnter
|
|
StreamingClips_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return StreamingClips_OnUpdate(pPed);
|
|
|
|
// Task intro
|
|
FSM_State(State_Intro)
|
|
FSM_OnEnter
|
|
Intro_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return Intro_OnUpdate(pPed);
|
|
#if FPS_MODE_SUPPORTED
|
|
FSM_OnExit
|
|
Intro_OnExit(pPed);
|
|
#endif
|
|
// Pull Pin
|
|
FSM_State(State_PullPin)
|
|
FSM_OnUpdate
|
|
return PullPin_OnUpdate();
|
|
|
|
// Holding Projectile
|
|
FSM_State(State_HoldingProjectile)
|
|
FSM_OnEnter
|
|
HoldingProjectile_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return HoldingProjectile_OnUpdate(pPed);
|
|
|
|
// Throw Projectile
|
|
FSM_State(State_ThrowProjectile)
|
|
FSM_OnEnter
|
|
ThrowProjectile_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return ThrowProjectile_OnUpdate(pPed);
|
|
FSM_OnExit
|
|
ThrowProjectile_OnExit(pPed);
|
|
|
|
// Place Projectile
|
|
FSM_State(State_PlaceProjectile)
|
|
FSM_OnEnter
|
|
StatePlaceProjectile_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return StatePlaceProjectile_OnUpdate(pPed);
|
|
|
|
FSM_State(State_CombatRoll)
|
|
FSM_OnEnter
|
|
CombatRoll_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return CombatRoll_OnUpdate(pPed);
|
|
|
|
// Reload Projectile
|
|
FSM_State(State_Reload)
|
|
FSM_OnEnter
|
|
Reload_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return Reload_OnUpdate(pPed);
|
|
FSM_OnExit
|
|
Reload_OnExit(pPed);
|
|
|
|
// Task intro
|
|
FSM_State(State_CloneIdle)
|
|
FSM_OnEnter
|
|
CloneIdle_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return CloneIdle_OnUpdate(pPed);
|
|
|
|
// Task intro
|
|
FSM_State(State_Outro)
|
|
FSM_OnEnter
|
|
Outro_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return Outro_OnUpdate(pPed);
|
|
|
|
// Weapon blocked
|
|
FSM_State(State_Blocked)
|
|
FSM_OnEnter
|
|
Blocked_OnEnter(pPed);
|
|
FSM_OnUpdate
|
|
return Blocked_OnUpdate(pPed);
|
|
|
|
// Finish
|
|
FSM_State(State_Finish)
|
|
FSM_OnUpdate
|
|
return FSM_Quit;
|
|
FSM_End
|
|
}
|
|
|
|
CTask::FSM_Return CTaskAimAndThrowProjectile::ProcessPostFSM()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
|
|
if (m_bCreateInvincibileProjectile)
|
|
{
|
|
CPedWeaponManager* pWeaponManager = pPed->GetWeaponManager();
|
|
CObject* pWeaponObj = pWeaponManager ? pWeaponManager->GetEquippedWeaponObject() : NULL;
|
|
|
|
if (pWeaponObj && !pWeaponObj->m_nPhysicalFlags.bNotDamagedByAnything)
|
|
{
|
|
pWeaponObj->m_nPhysicalFlags.bNotDamagedByAnything = true;
|
|
}
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
bool CTaskAimAndThrowProjectile::IsAiming(CPed* FPS_MODE_SUPPORTED_ONLY(pPed))
|
|
{
|
|
bool bUseFPSAimIK = false;
|
|
#if FPS_MODE_SUPPORTED
|
|
bUseFPSAimIK = pPed->GetEquippedWeaponInfo() ? pPed->GetEquippedWeaponInfo()->GetUseFPSAimIK() : false;
|
|
#endif
|
|
|
|
return CPlayerInfo::IsAiming(false) || m_bIsAiming FPS_MODE_SUPPORTED_ONLY(|| (pPed->IsFirstPersonShooterModeEnabledForPlayer() && !bUseFPSAimIK));
|
|
}
|
|
|
|
bool CTaskAimAndThrowProjectile::IsPriming(CPed* pPed)
|
|
{
|
|
return CThrowProjectileHelper::IsPlayerPriming(pPed) || m_bPriming;
|
|
}
|
|
|
|
// Note: this function was written assuming the logic CTaskAimAndThrowProjectile::IsFiring() passes
|
|
bool CTaskAimAndThrowProjectile::CanPlaceProjectile( CPed* pPed )
|
|
{
|
|
// Check the current ground normal slope
|
|
Vector3 vGroundNormal = pPed->GetGroundNormal();
|
|
if( vGroundNormal.z < CTaskBomb::ms_fMaxPlantGroundNormalZ )
|
|
return false;
|
|
|
|
static dev_float sfProbeRadius = 0.1f;
|
|
|
|
// Fill in the descriptor for the batch test.
|
|
WorldProbe::CShapeTestCapsuleDesc capsuleDesc;
|
|
WorldProbe::CShapeTestSingleResult capsuleResult;
|
|
|
|
u32 nIncludeFlags = (ArchetypeFlags::GTA_ALL_TYPES_WEAPON & ~ArchetypeFlags::GTA_PROJECTILE_TYPE & ~ArchetypeFlags::GTA_PED_TYPE & ~ArchetypeFlags::GTA_RIVER_TYPE);
|
|
u32 nTypeFlags = ArchetypeFlags::GTA_WEAPON_TEST;
|
|
|
|
float fDesiredHeading = pPed->GetDesiredHeading();
|
|
Vec3V vPedForward( -rage::Sinf( fDesiredHeading ), rage::Cosf( fDesiredHeading ), 0.0f );
|
|
vPedForward = NormalizeSafe( vPedForward, pPed->GetTransform().GetB() );
|
|
|
|
bool bFoundTarget = false;
|
|
float fZOffset = -0.3f;
|
|
|
|
Vec3V vPedPositionFlat = pPed->GetTransform().GetPosition();
|
|
vPedPositionFlat.SetZf( 0.0f );
|
|
|
|
Vec3V vStart( VEC3_ZERO );
|
|
Vec3V vEnd( VEC3_ZERO );
|
|
|
|
const int nNumProbes = 3;
|
|
Vec3V vHitPositions[nNumProbes];
|
|
Vec3V vHitNormals[nNumProbes];
|
|
ScalarV fFlatDistSq[nNumProbes];
|
|
ScalarV fShortestFlatDistSq( 10000.0f );
|
|
|
|
// Walk through each probe and determine the overall distance to the closest surface (in the desired direction)
|
|
for( int i = 0; i < nNumProbes; ++i )
|
|
{
|
|
fFlatDistSq[i].Setf( 10000.0f );
|
|
|
|
vStart = pPed->GetTransform().GetPosition();
|
|
vStart.SetZf( vStart.GetZf() + fZOffset );
|
|
vEnd = vStart + Scale( vPedForward, ScalarV( CTaskBomb::ms_fVerticalProbeDistance ) );
|
|
|
|
#if __BANK
|
|
char szDebugText[128];
|
|
formatf( szDebugText, "BOMB_COLLISION_SPHERE_START_%d", i );
|
|
CTask::ms_debugDraw.AddSphere( vStart, sfProbeRadius, Color_green, 2, atStringHash(szDebugText), false );
|
|
formatf( szDebugText, "BOMB_COLLISION_SPHERE_END_%d", i );
|
|
CTask::ms_debugDraw.AddSphere( vEnd, sfProbeRadius, Color_green4, 2, atStringHash(szDebugText), false );
|
|
formatf( szDebugText, "BOMB_COLLISION_ARROW_%d", i );
|
|
CTask::ms_debugDraw.AddArrow( vStart, vEnd, sfProbeRadius, Color_blue, 2, atStringHash(szDebugText) );
|
|
#endif // __BANK
|
|
|
|
capsuleResult.Reset();
|
|
capsuleDesc.SetResultsStructure( &capsuleResult );
|
|
capsuleDesc.SetCapsule( VEC3V_TO_VECTOR3( vStart ), VEC3V_TO_VECTOR3( vEnd ), sfProbeRadius );
|
|
capsuleDesc.SetExcludeEntity( pPed );
|
|
capsuleDesc.SetIncludeFlags( nIncludeFlags );
|
|
capsuleDesc.SetTypeFlags( nTypeFlags );
|
|
capsuleDesc.SetIsDirected( true );
|
|
capsuleDesc.SetTreatPolyhedralBoundsAsPrimitives( false );
|
|
|
|
if( WorldProbe::GetShapeTestManager()->SubmitTest( capsuleDesc ) )
|
|
{
|
|
if( !CPhysics::GetEntityFromInst( capsuleResult[0].GetHitInst() ) )
|
|
continue;
|
|
#if __BANK
|
|
char szDebugText[128];
|
|
formatf( szDebugText, "BOMB_COLLISION_SPHERE_%d", i );
|
|
CTask::ms_debugDraw.AddSphere( capsuleResult[0].GetHitPositionV(), 0.05f, Color_red, 2, atStringHash(szDebugText), false );
|
|
#endif // __BANK
|
|
|
|
bFoundTarget = true;
|
|
vHitPositions[i] = capsuleResult[0].GetHitPositionV();
|
|
vHitNormals[i] = capsuleResult[0].GetHitNormalV();
|
|
|
|
Vec3V vHitPositionFlat = capsuleResult[0].GetHitPositionV();
|
|
vHitPositionFlat.SetZf( 0.0f );
|
|
fFlatDistSq[i] = MagSquared( vHitPositionFlat - vPedPositionFlat );
|
|
|
|
// Determine if this is the shortest flat distance
|
|
if( IsTrue( IsLessThan( fFlatDistSq[i], fShortestFlatDistSq ) ) )
|
|
fShortestFlatDistSq = fFlatDistSq[i];
|
|
}
|
|
|
|
fZOffset += 0.3f;
|
|
}
|
|
|
|
// If we found a target we need to analyze the shortest distance
|
|
if( bFoundTarget )
|
|
{
|
|
static dev_float sfFlatDistanceThreshold = 0.15f;
|
|
|
|
// If the shortest distance is within a designated threshold then we should allow the plant
|
|
if( IsTrue( IsClose( fShortestFlatDistSq, fFlatDistSq[1], ScalarV( sfFlatDistanceThreshold ) ) ) )
|
|
return true;
|
|
}
|
|
|
|
// Disable ground plants on uphill slopes to prevent hand clipping into ground
|
|
bool bDisableGroundPlantOnUphillSlopes = (vGroundNormal.Dot(VEC3V_TO_VECTOR3(pPed->GetTransform().GetForward())) < 0.) && vGroundNormal.z < CTaskBomb::ms_fUphillMaxPlantGroundNormalZ;
|
|
|
|
// Otherwise, if we didn't find an intended surface and are still then allow the ground plant
|
|
if( !bFoundTarget && pPed->GetMotionData()->GetCurrentMoveBlendRatio().Mag2() <= rage::square( MBR_WALK_BOUNDARY ) && !bDisableGroundPlantOnUphillSlopes )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CTaskAimAndThrowProjectile::IsFiring(CPed* pPed)
|
|
{
|
|
bool bRNGifFPS = false;
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
bRNGifFPS = pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && m_bFPSUseAimIKForWeapon && pPed->GetMotionData() && pPed->GetMotionData()->GetIsFPSRNG();
|
|
#endif
|
|
return (CThrowProjectileHelper::IsPlayerFiring(pPed) || m_bIsFiring) && !bRNGifFPS;
|
|
}
|
|
|
|
CTaskInfo* CTaskAimAndThrowProjectile::CreateQueriableState() const
|
|
{
|
|
bool bHasAimTarget = false;
|
|
Vector3 vAimTarget = VEC3_ZERO;
|
|
|
|
if(m_target.GetIsValid())
|
|
{
|
|
bHasAimTarget = true;
|
|
m_target.GetPosition(vAimTarget);
|
|
}
|
|
|
|
bool bValidTarget = m_bHasTargetPosition && GetState() == State_HoldingProjectile;
|
|
return rage_new CClonedAimAndThrowProjectileInfo(m_pIgnoreCollisionEntity, GetState(), m_bPriming, CPlayerInfo::IsAiming(), m_bIsFiring, m_bDropProjectile, m_bThrowPlace,
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
m_bAimGunAndThrow, m_uAimAndThrowWeaponHash,
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
m_fThrowPitch, m_fCurrentPitch, bValidTarget, m_vTargetPosition, bHasAimTarget, m_LastLocalRollToken, vAimTarget);
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::ReadQueriableState(CClonedFSMTaskInfo* pTaskInfo)
|
|
{
|
|
Assert(pTaskInfo->GetTaskInfoType() == CTaskInfo::INFO_TYPE_AIM_PROJECTILE);
|
|
CTaskFSMClone::ReadQueriableState(pTaskInfo);
|
|
|
|
CClonedAimAndThrowProjectileInfo* pThisInfo = static_cast<CClonedAimAndThrowProjectileInfo*>(pTaskInfo);
|
|
|
|
m_bPriming = pThisInfo->IsPriming();
|
|
m_bIsAiming = pThisInfo->IsAiming();
|
|
m_bIsFiring = pThisInfo->IsFiring();
|
|
m_bDropProjectile = pThisInfo->IsDropping();
|
|
m_bThrowPlace = pThisInfo->IsThrowPlace();
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
m_bAimGunAndThrow = pThisInfo->IsAimGunAndThrow();
|
|
m_uAimAndThrowWeaponHash = pThisInfo->GetAimAndThrowWeaponHash();
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
m_fThrowPitch = pThisInfo->GetThrowPitch();
|
|
m_fCurrentPitch = pThisInfo->GetCurrentPitch();
|
|
m_bHasTargetPosition = pThisInfo->HasTargetPosition();
|
|
m_LastLocalRollToken = pThisInfo->GetRollToken();
|
|
m_vTargetPosition = pThisInfo->GetTargetPosition();
|
|
m_uAimAndThrowWeaponHash = pThisInfo->GetAimAndThrowWeaponHash();
|
|
m_pIgnoreCollisionEntity = pThisInfo->GetIgnoreCollisionEntity();
|
|
|
|
if(pThisInfo->HasAimTarget())
|
|
m_target.SetPosition(pThisInfo->GetAimTarget());
|
|
}
|
|
|
|
void CTaskAimAndThrowProjectile::OnCloneTaskNoLongerRunningOnOwner()
|
|
{
|
|
SetStateFromNetwork(State_Finish);
|
|
}
|
|
|
|
CTaskAimAndThrowProjectile::FSM_Return CTaskAimAndThrowProjectile::UpdateClonedFSM(const s32 iState, const FSM_Event iEvent)
|
|
{
|
|
if(iState != State_Finish)
|
|
{
|
|
if(iEvent == OnUpdate)
|
|
{
|
|
// Add a catch that stops us trying to switch states and create (and apply) a move network player to a ped that's just been blown up...
|
|
if(GetPed() && GetPed()->GetUsingRagdoll())
|
|
{
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
s32 iStateFromNetwork = GetStateFromNetwork();
|
|
|
|
// if the network state is telling us to finish...
|
|
if(iStateFromNetwork != GetState() && iStateFromNetwork == State_Finish && GetState() != State_ThrowProjectile GUN_PROJECTILE_THROW_ONLY(&& !m_bAimGunAndThrow))
|
|
{
|
|
SetState(iStateFromNetwork);
|
|
}
|
|
|
|
if(iStateFromNetwork == State_CombatRoll)
|
|
{
|
|
const unsigned WRAP_THRESHOLD = MAX_ROLL_TOKEN / 2;
|
|
if(m_LastCloneRollToken < m_LastLocalRollToken || ((m_LastCloneRollToken - m_LastLocalRollToken) > WRAP_THRESHOLD))
|
|
{
|
|
SetState(iStateFromNetwork);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return UpdateFSM(iState, iEvent);
|
|
}
|
|
|
|
CTaskFSMClone* CTaskAimAndThrowProjectile::CreateTaskForClonePed(CPed* UNUSED_PARAM(pPed))
|
|
{
|
|
return rage_new CTaskAimAndThrowProjectile(m_target, m_pIgnoreCollisionEntity);
|
|
}
|
|
|
|
CTaskFSMClone* CTaskAimAndThrowProjectile::CreateTaskForLocalPed(CPed* pPed)
|
|
{
|
|
return CreateTaskForClonePed(pPed);
|
|
}
|
|
|
|
#if !__FINAL
|
|
const char * CTaskAimAndThrowProjectile::GetStaticStateName( s32 iState )
|
|
{
|
|
Assert(iState>=State_Start&&iState<=State_Finish);
|
|
static const char* aStateNames[] =
|
|
{
|
|
"State_Start",
|
|
"State_StreamingClips",
|
|
"State_Intro",
|
|
"State_PullPin",
|
|
"State_HoldingProjectile",
|
|
"State_ThrowProjectile",
|
|
"State_PlaceProjectile",
|
|
"State_CombatRoll",
|
|
"State_Reload",
|
|
"State_CloneIdle",
|
|
"State_Outro",
|
|
"State_Blocked",
|
|
"State_Finish"
|
|
};
|
|
|
|
return aStateNames[iState];
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CClonedAimAndThrowProjectileInfo
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CClonedAimAndThrowProjectileInfo::CClonedAimAndThrowProjectileInfo(CEntity* pIgnoreCollisionEntity, const u32 state, bool bPriming, bool bAiming, bool bFiring, bool bDropping, bool bThrowPlace,
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
bool bAimGunAndThrow, u32 uAimAndThrowWeaponHash,
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
float fThrowPitch, float fCurrentPitch, bool bHasTargetVector, const Vector3& vTarget, bool bHasAimTarget, u8 rollToken, const Vector3& vAimTarget)
|
|
: m_bIsPriming(bPriming)
|
|
, m_bIsAiming(bAiming)
|
|
, m_bIsFiring(bFiring)
|
|
, m_bIsDropping(bDropping)
|
|
, m_bThrowPlace(bThrowPlace)
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
, m_bAimGunAndThrow(bAimGunAndThrow)
|
|
, m_uAimAndThrowWeaponHash(uAimAndThrowWeaponHash)
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
, m_RollToken(rollToken)
|
|
, m_fThrowPitch(fThrowPitch)
|
|
, m_fCurrentPitch(fCurrentPitch)
|
|
, m_bHasTargetPosition(bHasTargetVector)
|
|
, m_vTargetPosition(vTarget)
|
|
, m_bHasAimTarget(bHasAimTarget)
|
|
, m_vAimTarget(vAimTarget)
|
|
, m_IgnoreCollisionEntity(pIgnoreCollisionEntity)
|
|
{
|
|
CSerialisedFSMTaskInfo::SetStatusFromMainTaskState(state);
|
|
}
|
|
|
|
CTaskFSMClone* CClonedAimAndThrowProjectileInfo::CreateCloneFSMTask()
|
|
{
|
|
#if ENABLE_GUN_PROJECTILE_THROW
|
|
// aim guns and throws are always created locally
|
|
if(m_bAimGunAndThrow)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif //ENABLE_GUN_PROJECTILE_THROW
|
|
|
|
CWeaponTarget tTarget;
|
|
if(m_bHasAimTarget)
|
|
tTarget.SetPosition(m_vAimTarget);
|
|
|
|
return rage_new CTaskAimAndThrowProjectile(tTarget, m_IgnoreCollisionEntity.GetEntity());
|
|
}
|
|
|
|
CTaskFSMClone* CClonedAimAndThrowProjectileInfo::CreateLocalTask(fwEntity* UNUSED_PARAM(pEntity))
|
|
{
|
|
return CreateCloneFSMTask();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CClonedThrowProjectileInfo
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CClonedThrowProjectileInfo::CClonedThrowProjectileInfo(const u32 state, bool bHasTarget, const Vector3& vTarget, const fwMvClipSetId& clipsetId, const fwMvClipId& introClipId, const fwMvClipId& baseClipId, const fwMvClipId& throwLongClipId, const fwMvClipId& throwShortClipId, const u32 weaponNameHash, const bool rightHand)
|
|
: m_bHasTargetPosition(bHasTarget)
|
|
, m_vTargetPosition(vTarget)
|
|
, m_clipSetId(clipsetId)
|
|
, m_IntroClipId(introClipId)
|
|
, m_BaseClipId(baseClipId)
|
|
, m_ThrowLongClipId(throwLongClipId)
|
|
, m_ThrowShortClipId(throwShortClipId)
|
|
, m_WeaponNameHash(weaponNameHash)
|
|
, m_bRightHand(rightHand)
|
|
{
|
|
CSerialisedFSMTaskInfo::SetStatusFromMainTaskState(state);
|
|
}
|
|
|
|
CTaskFSMClone *CClonedThrowProjectileInfo::CreateCloneFSMTask()
|
|
{
|
|
CWeaponTarget tTarget;
|
|
if(m_bHasTargetPosition)
|
|
tTarget.SetPosition(m_vTargetPosition);
|
|
|
|
return rage_new CTaskThrowProjectile(tTarget, false);
|
|
}
|
|
|
|
CTaskFSMClone* CClonedThrowProjectileInfo::CreateLocalTask(fwEntity* UNUSED_PARAM(pEntity))
|
|
{
|
|
return CreateCloneFSMTask();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CTaskThrowProjectile
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
const fwMvRequestId CTaskThrowProjectile::ms_StartThrow("Throw",0xCDEC4431);
|
|
const fwMvRequestId CTaskThrowProjectile::ms_StartPrime("Prime",0x4CC8E30C);
|
|
const fwMvRequestId CTaskThrowProjectile::ms_TurnRight("TurnRight",0xFC128324);
|
|
const fwMvRequestId CTaskThrowProjectile::ms_TurnLeft("TurnLeft",0x5EF76E0C);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvIntroClip("IntroClip",0x4139FEC0);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvPrimeClip("PrimeClip",0xB7DB17D8);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvThrowClip("ThrowClip",0xC4C387F);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvThrowFaceCoverClip("ThrowClipFaceCover",0x1d3819b3);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvTurnLeftClip("TurnLeftClip",0xF4BD0E1F);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvTurnRightClip("TurnRightClip",0xBB79BF56);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvThrowShortClip("ThrowShortClip",0xCD4A3700);
|
|
const fwMvClipId CTaskThrowProjectile::ms_MvThrowShortFaceCoverClip("ThrowShortClipFaceCover",0x54e9685b);
|
|
const fwMvBooleanId CTaskThrowProjectile::ms_IntroCompleteEvent("IntroComplete",0x44A36F76);
|
|
const fwMvBooleanId CTaskThrowProjectile::ms_ThrowCompleteEvent("ThrowComplete",0x4BFCEDBF);
|
|
const fwMvBooleanId CTaskThrowProjectile::ms_EnterPrimeEvent("EnterPrime",0x8C99CF04);
|
|
const fwMvFloatId CTaskThrowProjectile::ms_ThrowPhase("ThrowPhase",0x9D46658E);
|
|
const fwMvFloatId CTaskThrowProjectile::ms_TurnPhase("TurnPhase",0x9B1DE516);
|
|
const fwMvFloatId CTaskThrowProjectile::ms_ThrowDirection("ThrowDirection",0x1C45680E);
|
|
|
|
CTaskThrowProjectile::CTaskThrowProjectile(const CWeaponTarget& targeting, const bool bRotateToFaceTarget, const fwMvClipSetId &clipSetId)
|
|
: m_target(targeting)
|
|
, m_clipSetId(clipSetId)
|
|
, m_bRotateToFaceTarget(bRotateToFaceTarget)
|
|
, m_bHasThrownProjectile(false)
|
|
, m_bPriming(false)
|
|
, m_IntroClipId(CLIP_ID_INVALID)
|
|
, m_BaseClipId(CLIP_ID_INVALID)
|
|
, m_ThrowLongClipId(CLIP_ID_INVALID)
|
|
, m_ThrowLongFaceCoverClipId(CLIP_ID_INVALID)
|
|
, m_ThrowShortClipId(CLIP_ID_INVALID)
|
|
, m_ThrowShortFaceCoverClipId(CLIP_ID_INVALID)
|
|
, m_pRightTurnClip(NULL)
|
|
, m_pLeftTurnClip(NULL)
|
|
, m_fThrowPhase(0.5f)
|
|
, m_iTurnTimer(0)
|
|
, m_bFire(false)
|
|
, m_bTurning(false)
|
|
{
|
|
SetInternalTaskType(CTaskTypes::TASK_THROW_PROJECTILE);
|
|
}
|
|
|
|
CTaskThrowProjectile::~CTaskThrowProjectile()
|
|
{
|
|
}
|
|
|
|
void CTaskThrowProjectile::CleanUp()
|
|
{
|
|
GetPed()->GetMovePed().ClearTaskNetwork(m_MoveNetworkHelper, NORMAL_BLEND_DURATION);
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::ProcessPreFSM()
|
|
{
|
|
CPed *pPed = GetPed();
|
|
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_IsAiming, true );
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_ProcessPostPreRender, true );
|
|
|
|
// Force the do nothing motion state so we don't get any underlying motion coming through
|
|
pPed->ForceMotionStateThisFrame(CPedMotionStates::MotionState_AnimatedVelocity);
|
|
|
|
if(!weaponVerifyf(pPed->GetWeaponManager(), "Weapon Manager is NULL!"))
|
|
return FSM_Continue;
|
|
|
|
if(!pPed->IsNetworkClone() && GetState()!=State_ThrowProjectile)
|
|
{
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(!pWeapon || !pWeapon->GetWeaponInfo()->GetIsThrownWeapon())
|
|
{
|
|
if(pPed->GetIsInCover())
|
|
{
|
|
TUNE_GROUP_FLOAT(COVER_TUNE, PROJECTILE_BLEND_OUT_DURATION, 1.0f, 0.0f, 10.0f, 0.01f);
|
|
StopClip(PROJECTILE_BLEND_OUT_DURATION);
|
|
}
|
|
return FSM_Quit;
|
|
}
|
|
}
|
|
|
|
// update target
|
|
if(pPed && pPed->IsPlayer())
|
|
{
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
if(static_cast<CNetObjPlayer*>(pPed->GetNetworkObject())->HasValidTarget())
|
|
{
|
|
m_target.SetPosition(pPed->GetWeaponManager()->GetWeaponAimPosition());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_target.Update(pPed);
|
|
|
|
Vector3 vTargetPosition;
|
|
if(m_target.GetIsValid() && m_target.GetPositionWithFiringOffsets(pPed, vTargetPosition))
|
|
{
|
|
pPed->GetWeaponManager()->SetWeaponAimPosition(vTargetPosition);
|
|
}
|
|
}
|
|
}
|
|
return FSM_Continue;
|
|
}
|
|
|
|
bool CTaskThrowProjectile::ProcessPostPreRender()
|
|
{
|
|
if (m_bFire)
|
|
{
|
|
CPed* pPed = GetPed();
|
|
// grab a pointer to the peds weapon, this should always be valid for a local ped, its an exit condition in ProcessPreFSM
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if (pWeapon)
|
|
{
|
|
taskFatalAssertf(pWeapon, "Valid weapon expected!");
|
|
|
|
// Calculate the launch position
|
|
const s32 nBoneIndex = pPed->GetBoneIndexFromBoneTag(BONETAG_R_HAND);
|
|
Assert(nBoneIndex != BONETAG_INVALID);
|
|
|
|
Matrix34 weaponMat;
|
|
CObject* pWeaponObject = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
if( pWeaponObject )
|
|
{
|
|
weaponMat = MAT34V_TO_MATRIX34(pWeaponObject->GetMatrix());
|
|
}
|
|
else
|
|
{
|
|
pPed->GetGlobalMtx(nBoneIndex, weaponMat);
|
|
}
|
|
|
|
// Initialize start and end positions to zero
|
|
Vector3 vStart(Vector3::ZeroType);
|
|
Vector3 vEnd(Vector3::ZeroType);
|
|
|
|
// Player ped
|
|
if( pPed->IsLocalPlayer() )
|
|
{
|
|
// Use camera aim
|
|
const camFrame& aimFrame = camInterface::GetPlayerControlCamAimFrame();
|
|
vStart = aimFrame.GetPosition();
|
|
Vector3 vShot = aimFrame.GetFront();
|
|
f32 fShotDot = vShot.Dot(weaponMat.d - vStart);
|
|
vStart += fShotDot * vShot;
|
|
|
|
bool bValidTargetPosition = false;
|
|
if( !pPed->GetPlayerInfo() || !pPed->GetPlayerInfo()->AreControlsDisabled() )
|
|
{
|
|
// First check for the more precise reading, the camera aim at position
|
|
if( pWeaponObject )
|
|
{
|
|
Vector3 vStartTemp( Vector3::ZeroType );
|
|
bValidTargetPosition = pWeapon->CalcFireVecFromAimCamera( pPed->GetIsInVehicle() ? static_cast<CEntity*>(pPed->GetMyVehicle()) : pPed, weaponMat, vStartTemp, vEnd );
|
|
}
|
|
}
|
|
|
|
// B*1983883: If we're throwing from cover and aim vector from camera isn't colliding with the cover, but the projectile is going to,
|
|
// then offset it slightly by the height difference (within reason).
|
|
float fOffsetZ = 0.0f;
|
|
if (OffsetProjectileIfNecessaryInCover(pPed, aimFrame.GetPosition(), vEnd, weaponMat.d, vEnd, weaponMat, fOffsetZ))
|
|
{
|
|
weaponMat.d.z += fOffsetZ;
|
|
}
|
|
|
|
// Now scale up to weapon range
|
|
if( !bValidTargetPosition && m_target.GetIsValid() )
|
|
{
|
|
bValidTargetPosition = m_target.GetPositionWithFiringOffsets( pPed, vEnd );
|
|
}
|
|
}
|
|
else // AI Ped
|
|
{
|
|
// Compute vStart
|
|
vStart = pPed->GetBonePositionCached((eAnimBoneTag)BONETAG_R_HAND);
|
|
|
|
// Compute vEnd
|
|
if(m_target.GetIsValid())
|
|
{
|
|
m_target.GetPosition(vEnd);
|
|
Assert(vEnd.FiniteElements()); // Attempting to track down an INF (B*682884)
|
|
}
|
|
}
|
|
|
|
float fOverrideLifeTime = -1.0f;
|
|
if(!pWeapon->GetIsCooking())
|
|
{
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
}
|
|
if (pWeapon->GetWeaponInfo()->GetProjectileFuseTime() > 0.0f)
|
|
{
|
|
fOverrideLifeTime = Max( 0.0f, pWeapon->GetCookTimeLeft(pPed, fwTimer::GetTimeInMilliseconds()) );
|
|
}
|
|
|
|
// Throw the projectile
|
|
CWeapon::sFireParams params(pPed, weaponMat, &vStart, &vEnd);
|
|
params.fOverrideLifeTime = fOverrideLifeTime;
|
|
params.fDesiredTargetDistance = vStart.Dist( vEnd );
|
|
if(pWeapon->Fire(params))
|
|
{
|
|
// Ensure object is removed
|
|
pPed->GetWeaponManager()->DestroyEquippedWeaponObject();
|
|
}
|
|
m_bFire = false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::UpdateFSM( const s32 iState, const FSM_Event iEvent )
|
|
{
|
|
FSM_Begin
|
|
// Task start
|
|
FSM_State(State_Start)
|
|
FSM_OnUpdate
|
|
Start_OnUpdate();
|
|
|
|
FSM_State(State_Intro)
|
|
FSM_OnEnter
|
|
return Intro_OnEnter();
|
|
FSM_OnUpdate
|
|
return Intro_OnUpdate();
|
|
|
|
FSM_State(State_HoldingProjectile)
|
|
FSM_OnEnter
|
|
return HoldingProjectile_OnEnter();
|
|
FSM_OnUpdate
|
|
return HoldingProjectile_OnUpdate();
|
|
|
|
FSM_State(State_ThrowProjectile)
|
|
FSM_OnEnter
|
|
return ThrowProjectile_OnEnter();
|
|
FSM_OnUpdate
|
|
return ThrowProjectile_OnUpdate();
|
|
|
|
// Finish
|
|
FSM_State(State_Finish)
|
|
FSM_OnUpdate
|
|
return FSM_Quit;
|
|
FSM_End
|
|
}
|
|
|
|
CTaskInfo* CTaskThrowProjectile::CreateQueriableState() const
|
|
{
|
|
bool bHasAimTarget = false;
|
|
Vector3 vAimTarget = VEC3_ZERO;
|
|
|
|
if(m_target.GetIsValid())
|
|
{
|
|
bHasAimTarget = true;
|
|
m_target.GetPosition(vAimTarget);
|
|
}
|
|
|
|
const CPed* pPed = GetPed();
|
|
u32 uWeaponNameHash = 0;
|
|
bool bRightHand = true;
|
|
const CPedWeaponManager* pWeaponManager = pPed ? pPed->GetWeaponManager() : NULL;
|
|
if (pWeaponManager && pWeaponManager->GetPedEquippedWeapon())
|
|
{
|
|
uWeaponNameHash = pWeaponManager->GetEquippedWeaponHash();
|
|
bRightHand = pWeaponManager->GetPedEquippedWeapon()->GetAttachPoint() == CPedEquippedWeapon::AP_RightHand ? true : false;
|
|
}
|
|
|
|
const fwMvClipSetId cloneClipSetId = pPed ? CTaskInCover::ms_Tunables.GetThrowProjectileClipSetIdForPed(*pPed, true) : m_clipSetId;
|
|
return rage_new CClonedThrowProjectileInfo(GetState(), bHasAimTarget, vAimTarget, cloneClipSetId, m_IntroClipId, m_BaseClipId, m_ThrowLongClipId, m_ThrowShortClipId, uWeaponNameHash, bRightHand);
|
|
}
|
|
|
|
void CTaskThrowProjectile::ReadQueriableState(CClonedFSMTaskInfo* pTaskInfo)
|
|
{
|
|
Assert(pTaskInfo->GetTaskInfoType() == CTaskInfo::INFO_TYPE_THROW_PROJECTILE);
|
|
CTaskFSMClone::ReadQueriableState(pTaskInfo);
|
|
|
|
CClonedThrowProjectileInfo* pThisInfo = static_cast<CClonedThrowProjectileInfo*>(pTaskInfo);
|
|
|
|
m_clipSetId = pThisInfo->GetThrowClipSetId();
|
|
m_IntroClipId = pThisInfo->GetIntroClipId();
|
|
if (GetState() != State_HoldingProjectile || m_BaseClipId == CLIP_ID_INVALID) // We set this locally during the hold state
|
|
{
|
|
m_BaseClipId = pThisInfo->GetBaseClipId();
|
|
}
|
|
m_ThrowLongClipId = pThisInfo->GetThrowLongClipId();
|
|
m_ThrowShortClipId = pThisInfo->GetThrowShortClipId();
|
|
|
|
m_WeaponNameHash = pThisInfo->GetWeaponNameHash();
|
|
m_bRightHand = pThisInfo->GetRightHand();
|
|
|
|
if(pThisInfo->HasTargetPosition())
|
|
m_target.SetPosition(pThisInfo->GetTargetPosition());
|
|
}
|
|
|
|
void CTaskThrowProjectile::OnCloneTaskNoLongerRunningOnOwner()
|
|
{
|
|
SetStateFromNetwork(State_Finish);
|
|
}
|
|
|
|
CTaskThrowProjectile::FSM_Return CTaskThrowProjectile::UpdateClonedFSM(const s32 iState, const FSM_Event iEvent)
|
|
{
|
|
if(iState != State_Finish)
|
|
{
|
|
if(iEvent == OnUpdate)
|
|
{
|
|
// if the network state is telling us to finish...
|
|
s32 iStateFromNetwork = GetStateFromNetwork();
|
|
if(iStateFromNetwork != GetState() && iStateFromNetwork == State_Finish)
|
|
{
|
|
SetState(iStateFromNetwork);
|
|
}
|
|
}
|
|
}
|
|
|
|
return UpdateFSM(iState, iEvent);
|
|
}
|
|
|
|
CTaskFSMClone* CTaskThrowProjectile::CreateTaskForClonePed(CPed* UNUSED_PARAM(pPed))
|
|
{
|
|
return rage_new CTaskThrowProjectile(m_target, m_bRotateToFaceTarget);
|
|
}
|
|
|
|
CTaskFSMClone* CTaskThrowProjectile::CreateTaskForLocalPed(CPed* pPed)
|
|
{
|
|
return CreateTaskForClonePed(pPed);;
|
|
}
|
|
|
|
#if !__FINAL
|
|
const char * CTaskThrowProjectile::GetStaticStateName( s32 iState )
|
|
{
|
|
Assert(iState>=State_Start&&iState<=State_Finish);
|
|
static const char* aStateNames[] =
|
|
{
|
|
"State_Start",
|
|
"State_Intro",
|
|
"State_HoldingProjectile",
|
|
"State_ThrowProjectile",
|
|
"State_Finish"
|
|
};
|
|
|
|
return aStateNames[iState];
|
|
}
|
|
#endif
|
|
|
|
void CTaskThrowProjectile::DoAbort(const AbortPriority UNUSED_PARAM(iPriority), const aiEvent* pEvent)
|
|
{
|
|
CPed *pPed = GetPed(); //Get the ped ptr.
|
|
|
|
if(pEvent && ((CEvent*)pEvent)->GetEventType() == EVENT_DAMAGE)
|
|
{
|
|
// DROP WEAPON IF SHOT IN THE MIDDLE OF THROWING!
|
|
// drop the weapon straight down, should be pretty effective.
|
|
// Calculate the launch position
|
|
const s32 nBoneIndex = pPed->GetBoneIndexFromBoneTag(BONETAG_R_HAND);
|
|
Assert(nBoneIndex != BONETAG_INVALID);
|
|
|
|
Matrix34 boneMat;
|
|
pPed->GetGlobalMtx(nBoneIndex, boneMat);
|
|
|
|
// Fire the weapon, note the target position is this peds so it should just drop
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon && pWeapon->GetWeaponInfo()->GetIsThrownWeapon())
|
|
{
|
|
float fOverrideLifeTime = -1.0f;
|
|
if (pWeapon->GetWeaponInfo()->GetProjectileFuseTime() > 0.0f)
|
|
fOverrideLifeTime = Max(0.0f, pWeapon->GetCookTimeLeft(pPed, fwTimer::GetTimeInMilliseconds()));
|
|
|
|
Vector3 v = VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition());
|
|
CWeapon::sFireParams params(pPed, boneMat, NULL, &v);
|
|
params.fOverrideLifeTime = fOverrideLifeTime;
|
|
if(pWeapon->Fire(params))
|
|
{
|
|
pPed->GetWeaponManager()->DestroyEquippedWeaponObject();
|
|
}
|
|
}
|
|
}
|
|
|
|
// We are going to abort, so blend out the animation
|
|
StopClip(NORMAL_BLEND_OUT_DELTA);
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::Start_OnUpdate()
|
|
{
|
|
CPed *pPed = GetPed(); //Get the ped ptr.
|
|
|
|
if (NetworkInterface::IsGameInProgress() && pPed->IsNetworkClone())
|
|
{
|
|
const CTaskCover* pCoverTask = static_cast<const CTaskCover *>(pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_COVER));
|
|
if( (pCoverTask && !pCoverTask->IsWeaponClipSetLoaded()) || (pPed->GetWeaponManager()->GetEquippedWeaponObject()==NULL) )
|
|
{
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if(!CTaskCover::RequestCoverClipSetReturnIfLoaded(m_clipSetId))
|
|
{
|
|
return FSM_Continue;
|
|
}
|
|
|
|
const CWeaponInfo* pWeaponInfo = pPed->GetWeaponManager()->GetEquippedWeaponInfo();
|
|
if(!pWeaponInfo || !pWeaponInfo->GetIsThrownWeapon())
|
|
{
|
|
CNetObjPed* pNetObjPed = static_cast<CNetObjPed*>(pPed->GetNetworkObject());
|
|
if (pNetObjPed)
|
|
{
|
|
//Change flag so that we can equip the weapon here
|
|
pNetObjPed->SetTaskOverridingPropsWeapons(true);
|
|
|
|
//Ensure the weapon is in the remote peds inventory
|
|
if (!pPed->GetInventory()->GetWeapon(m_WeaponNameHash))
|
|
pPed->GetInventory()->AddWeapon(m_WeaponNameHash);
|
|
|
|
//Equip the new weapon
|
|
pPed->GetWeaponManager()->EquipWeapon(m_WeaponNameHash,-1,true,false,m_bRightHand ? CPedEquippedWeapon::AP_RightHand : CPedEquippedWeapon::AP_LeftHand);
|
|
|
|
//Change the flag back so we can equip weapons going forward through the basic replication means
|
|
pNetObjPed->SetTaskOverridingPropsWeapons(false);
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
u32 desiredWeapon = pPed->GetWeaponManager()->GetEquippedWeaponHash();
|
|
u32 currentWeapon = pPed->GetWeaponManager()->GetEquippedWeapon() ? GetPed()->GetWeaponManager()->GetEquippedWeapon()->GetWeaponInfo()->GetHash() : 0;
|
|
|
|
// wait if the player is holding the wrong weapon object, that does not correspond to the hash of the weapon he should be holding
|
|
if (desiredWeapon != currentWeapon)
|
|
{
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
fwMvNetworkDefId networkDefId(CClipNetworkMoveInfo::ms_NetworkTaskAimAndThrowProjectileCover);
|
|
m_MoveNetworkHelper.CreateNetworkPlayer(pPed, networkDefId);
|
|
static dev_float sf_BlendInDuration = FAST_BLEND_DURATION;
|
|
pPed->GetMovePed().SetTaskNetwork(m_MoveNetworkHelper, sf_BlendInDuration, CMovePed::Task_TagSyncContinuous);
|
|
m_MoveNetworkHelper.SetClipSet(m_clipSetId);
|
|
taskAssert(m_IntroClipId != CLIP_ID_INVALID);
|
|
const crClip* pIntroClip = fwClipSetManager::GetClip(m_clipSetId, m_IntroClipId);
|
|
if (taskVerifyf(pIntroClip, "NULL Clip"))
|
|
{
|
|
m_MoveNetworkHelper.SetClip(pIntroClip, ms_MvIntroClip);
|
|
}
|
|
|
|
//See if grip anim exists TODO
|
|
// static fwMvFlagId sUseGripClip("UseGripClip",0x72838804);
|
|
// fwClipSet *pClipSet = m_MoveNetworkHelper.GetClipSet();
|
|
// if (pClipSet && pClipSet->GetClip(fwMvClipId("grip",0x6FAD1258)) != NULL)
|
|
// m_MoveNetworkHelper.SetFlag(true, sUseGripClip);
|
|
// else
|
|
// m_MoveNetworkHelper.SetFlag(false, sUseGripClip);
|
|
|
|
if (GetParent() && GetParent()->GetTaskType() == CTaskTypes::TASK_IN_COVER)
|
|
{
|
|
SetState(State_Intro);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
weaponAssertf(0, "Should only arrive here via TASK_IN_COVER!");
|
|
return FSM_Quit;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::Intro_OnEnter()
|
|
{
|
|
return FSM_Continue;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::Intro_OnUpdate()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
|
|
// We will need our update every frame for the throw
|
|
pPed->GetPedAiLod().SetBlockedLodFlag(CPedAILod::AL_LodTimesliceIntelligenceUpdate|CPedAILod::AL_LodTimesliceAnimUpdate);
|
|
if(m_MoveNetworkHelper.GetBoolean(ms_IntroCompleteEvent))
|
|
{
|
|
SetState(State_HoldingProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if (CThrowProjectileHelper::IsPlayerFiring(pPed))
|
|
{
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon)
|
|
{
|
|
// check to see if this is placeable
|
|
const CWeaponInfo* pWeaponInfo = pWeapon->GetWeaponInfo();
|
|
if(pWeaponInfo)
|
|
{
|
|
const CAmmoInfo* pAmmoInfo = pWeaponInfo->GetAmmoInfo();
|
|
if(pAmmoInfo && pAmmoInfo->GetIsClassId(CAmmoProjectileInfo::GetStaticClassId()))
|
|
{
|
|
if (static_cast<const CAmmoProjectileInfo*>(pAmmoInfo)->GetNoPullPin())
|
|
{
|
|
SetState(State_HoldingProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::HoldingProjectile_OnEnter()
|
|
{
|
|
taskAssert(m_BaseClipId != CLIP_ID_INVALID);
|
|
const crClip* pBaseClip = fwClipSetManager::GetClip(m_clipSetId, m_BaseClipId);
|
|
m_MoveNetworkHelper.SendRequest(ms_StartPrime);
|
|
if (taskVerifyf(pBaseClip, "NULL Clip"))
|
|
{
|
|
m_MoveNetworkHelper.SetClip(pBaseClip, ms_MvPrimeClip);
|
|
}
|
|
|
|
m_MoveNetworkHelper.WaitForTargetState(ms_EnterPrimeEvent);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::HoldingProjectile_OnUpdate()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
|
|
// We will need our update every frame for the throw
|
|
pPed->GetPedAiLod().SetBlockedLodFlag(CPedAILod::AL_LodTimesliceIntelligenceUpdate|CPedAILod::AL_LodTimesliceAnimUpdate);
|
|
if (m_bTurning)
|
|
{
|
|
const crClip* pBaseClip = fwClipSetManager::GetClip(m_clipSetId, m_BaseClipId);
|
|
if (taskVerifyf(pBaseClip, "NULL Clip"))
|
|
{
|
|
m_MoveNetworkHelper.SetClip(pBaseClip, ms_MvPrimeClip);
|
|
}
|
|
|
|
float fClipPhase = m_MoveNetworkHelper.GetFloat(ms_TurnPhase);
|
|
if (fClipPhase>=1.0f || fClipPhase<0)
|
|
m_bTurning = false;
|
|
if (!m_bTurnSwappedAnims && fClipPhase >=0.6f)
|
|
{
|
|
fwMvClipSetId clipSetId = CLIP_SET_ID_INVALID;
|
|
fwMvClipId introClipId = CLIP_ID_INVALID;
|
|
fwMvClipId baseClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwLongClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwShortClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwLongFaceCoverClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwShortFaceCoverClipId = CLIP_ID_INVALID;
|
|
|
|
CTask* pTask = pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_IN_COVER);
|
|
Assert(pTask);
|
|
if (CTaskInCover::GetThrownProjectileClipSetAndClipIds(pPed, static_cast<CTaskInCover*>(pTask), clipSetId, introClipId, baseClipId, throwLongClipId, throwShortClipId, throwLongFaceCoverClipId, throwShortFaceCoverClipId, static_cast<CTaskInCover*>(pTask)->IsCoverFlagSet(CTaskCover::CF_TooHighCoverPoint)))
|
|
{
|
|
SetClipSetId(clipSetId);
|
|
SetClipIds(introClipId, baseClipId, throwLongClipId, throwShortClipId, throwLongFaceCoverClipId, throwShortFaceCoverClipId);
|
|
}
|
|
m_bTurnSwappedAnims = true;
|
|
}
|
|
if (!pPed->IsNetworkClone() && fClipPhase>=0)
|
|
{
|
|
bool bFacingLeft = GetPed()->GetPedResetFlag(CPED_RESET_FLAG_InCoverFacingLeft);
|
|
Vector3 vCoverDirection = VEC3V_TO_VECTOR3(pPed->GetCoverPoint()->GetCoverDirectionVector());
|
|
vCoverDirection.RotateZ(bFacingLeft ? HALF_PI : -HALF_PI);
|
|
float fGoalHeading = fwAngle::LimitRadianAngle(rage::Atan2f(-vCoverDirection.x, vCoverDirection.y)) + (bFacingLeft ? 0.01f : -0.01f); //extra fudge so SubtractAngleShorter chooses a good direction
|
|
vCoverDirection.RotateZ(PI);
|
|
float fInitHeading = fwAngle::LimitRadianAngle(rage::Atan2f(-vCoverDirection.x, vCoverDirection.y));
|
|
fGoalHeading = fInitHeading + (SubtractAngleShorter(fGoalHeading, fInitHeading) * Min(fClipPhase * 1.5f, 1.0f));
|
|
float fCorrection = GetPed()->GetCurrentHeading();
|
|
fCorrection = SubtractAngleShorter(fGoalHeading, fCorrection);
|
|
pPed->SetPedResetFlag(CPED_RESET_FLAG_SyncDesiredHeadingToCurrentHeading, false);
|
|
pPed->GetMotionData()->SetExtraHeadingChangeThisFrame(fCorrection);
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if(!m_MoveNetworkHelper.IsInTargetState())
|
|
{
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
if(GetStateFromNetwork() == State_Finish)
|
|
SetState(State_Finish);
|
|
else
|
|
{
|
|
ProjectileInfo* pProjectileInfo = CNetworkPendingProjectiles::GetProjectile(pPed, GetNetSequenceID(), false);
|
|
if(pProjectileInfo)
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
else if (CanTriggerTurn(pPed))
|
|
{
|
|
const bool bFacingLeft = pPed->GetPedResetFlag(CPED_RESET_FLAG_InCoverFacingLeft);
|
|
TriggerTurn(pPed, bFacingLeft);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CanTriggerTurn(pPed))
|
|
{
|
|
//Check for turn
|
|
bool bFacingLeft = GetPed()->GetPedResetFlag(CPED_RESET_FLAG_InCoverFacingLeft);
|
|
// Compute aim heading
|
|
Vector3 vAimHeading;
|
|
// Player ped
|
|
if( pPed->IsLocalPlayer() )
|
|
{
|
|
const camFrame& aimFrame = camInterface::GetPlayerControlCamAimFrame();
|
|
vAimHeading = aimFrame.GetFront();
|
|
}
|
|
else // AI ped
|
|
{
|
|
Vector3 vTargetPosition;
|
|
m_target.GetPosition(vTargetPosition);
|
|
vAimHeading = vTargetPosition - VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition());
|
|
}
|
|
vAimHeading.z=0; vAimHeading.Normalize();
|
|
Vector3 vNormal = VEC3V_TO_VECTOR3(GetPed()->GetTransform().GetForward());
|
|
vNormal.z=0; vNormal.Normalize();
|
|
float fTheta = vAimHeading.FastAngle(vNormal);
|
|
Vector3 vRight = VEC3V_TO_VECTOR3(GetPed()->GetTransform().GetRight()); vRight.z=0; vRight.Normalize();
|
|
float fDot = vAimHeading.Dot(vRight);
|
|
if ((!bFacingLeft && fDot > 0) || (bFacingLeft && fDot < 0))
|
|
fTheta = -fTheta;
|
|
//static dev_float s_fMinTossAngle = -105.0f*DtoR;
|
|
//static dev_float s_fMaxTossAngle = 135.0f*DtoR;
|
|
TUNE_GROUP_FLOAT(PROJECTILE_BUG, MinTossAngle, -105.0f, -180.0f, 180.0f, 1.0f);
|
|
TUNE_GROUP_FLOAT(PROJECTILE_BUG, MaxTossAngle, 135.0f, -180.0f, 180.0f, 1.0f);
|
|
const float s_fMinTossAngle = MinTossAngle * DtoR;
|
|
const float s_fMaxTossAngle = MaxTossAngle * DtoR;
|
|
|
|
if (fTheta < s_fMinTossAngle || fTheta > s_fMaxTossAngle)
|
|
{
|
|
TriggerTurn(pPed, bFacingLeft);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
|
|
if( !pPed->IsLocalPlayer() )
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if(CThrowProjectileHelper::IsPlayerFiring(pPed))
|
|
{
|
|
SetState(State_ThrowProjectile);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
weaponAssert(pPed->GetWeaponManager());
|
|
CWeapon* pWeapon = pPed->GetWeaponManager()->GetEquippedWeapon();
|
|
if(pWeapon)
|
|
{
|
|
if(!m_bPriming && CThrowProjectileHelper::IsPlayerPriming(pPed))
|
|
{
|
|
m_bPriming = true;
|
|
CProjectile* pProjectile = static_cast<CProjectile*>(pPed->GetWeaponManager()->GetEquippedWeaponObject());
|
|
if (pProjectile)
|
|
pProjectile->SetPrimed(true);
|
|
u32 nCurrentTime = fwTimer::GetTimeInMilliseconds();
|
|
if(!pWeapon->GetIsCooking() && pWeapon->GetWeaponInfo()->GetCookWhileAiming())
|
|
pWeapon->StartCookTimer(nCurrentTime);
|
|
}
|
|
|
|
if(pWeapon->GetIsCooking() && pWeapon->GetWeaponInfo()->GetProjectileFuseTime() > 0.0f && pWeapon->GetCookTimeLeft(pPed, fwTimer::GetTimeInMilliseconds()) <= 0)
|
|
{
|
|
DropProjectile(pPed, pWeapon);
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::ThrowProjectile_OnEnter()
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_StartThrow);
|
|
taskAssert(m_ThrowLongClipId != CLIP_ID_INVALID);
|
|
const crClip* pThrowClip = fwClipSetManager::GetClip(m_clipSetId, m_ThrowLongClipId);
|
|
if (taskVerifyf(pThrowClip, "NULL Clip"))
|
|
{
|
|
m_MoveNetworkHelper.SetClip(pThrowClip, ms_MvThrowClip);
|
|
}
|
|
pThrowClip = fwClipSetManager::GetClip(m_clipSetId, m_ThrowShortClipId);
|
|
if (taskVerifyf(pThrowClip, "NULL short throw Clip"))
|
|
{
|
|
m_MoveNetworkHelper.SetClip(pThrowClip, ms_MvThrowShortClip);
|
|
}
|
|
|
|
const CPed* pPed = GetPed();
|
|
#if FPS_MODE_SUPPORTED
|
|
if (pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && pPed->GetIsInCover())
|
|
{
|
|
m_MoveNetworkHelper.SetFlag(true, CTaskMotionInCover::ms_IsFirstPersonFlagId);
|
|
taskAssert(m_ThrowLongFaceCoverClipId != CLIP_ID_INVALID);
|
|
const crClip* pFaceCoverThrowClip = fwClipSetManager::GetClip(m_clipSetId, m_ThrowLongFaceCoverClipId);
|
|
m_MoveNetworkHelper.SetClip(pFaceCoverThrowClip, ms_MvThrowFaceCoverClip);
|
|
|
|
taskAssert(m_ThrowShortFaceCoverClipId != CLIP_ID_INVALID);
|
|
pFaceCoverThrowClip = fwClipSetManager::GetClip(m_clipSetId, m_ThrowShortFaceCoverClipId);
|
|
m_MoveNetworkHelper.SetClip(pFaceCoverThrowClip, ms_MvThrowShortFaceCoverClip);
|
|
}
|
|
#endif // FPS_MODE_SUPPORTED
|
|
|
|
#if __DEV
|
|
if (CClipEventTags::CountEvent<crPropertyAttributeInt>(pThrowClip, CClipEventTags::Fire, CClipEventTags::Index, 1)==0)
|
|
{
|
|
// no fire event - BAD
|
|
Assertf(0, "Animation has no AEF_FIRE_1 event");
|
|
}
|
|
#endif // __DEV
|
|
if(pThrowClip)
|
|
CClipEventTags::FindEventPhase(pThrowClip, CClipEventTags::Fire, m_fThrowPhase);
|
|
|
|
//compute throw direction
|
|
bool bFacingLeft = GetPed()->GetPedResetFlag(CPED_RESET_FLAG_InCoverFacingLeft);
|
|
|
|
|
|
// Compute aim heading
|
|
Vector3 vAimHeading;
|
|
|
|
// Player ped
|
|
if( pPed->IsLocalPlayer() )
|
|
{
|
|
const camFrame& aimFrame = camInterface::GetPlayerControlCamAimFrame();
|
|
vAimHeading = aimFrame.GetFront();
|
|
}
|
|
else // AI ped
|
|
{
|
|
Vector3 vTargetPosition;
|
|
if( !m_target.GetPosition(vTargetPosition) )
|
|
{
|
|
return FSM_Quit;
|
|
}
|
|
vAimHeading = vTargetPosition - VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition());
|
|
}
|
|
vAimHeading.z=0; vAimHeading.Normalize();
|
|
Vector3 vNormal = VEC3V_TO_VECTOR3(GetPed()->GetTransform().GetForward());
|
|
vNormal.z=0; vNormal.Normalize();
|
|
float fTheta = vAimHeading.FastAngle(vNormal);
|
|
Vector3 vRight = VEC3V_TO_VECTOR3(GetPed()->GetTransform().GetRight()); vRight.z=0; vRight.Normalize();
|
|
float fDot = vAimHeading.Dot(vRight);
|
|
if ((!bFacingLeft && fDot > 0) || (bFacingLeft && fDot < 0))
|
|
fTheta = -fTheta;
|
|
static dev_float s_fMinTossAngle = -45.0f*DtoR;
|
|
static dev_float s_fMaxTossAngle = 135.0f*DtoR;
|
|
float fDirection = Clamp((fTheta - s_fMinTossAngle)/(s_fMaxTossAngle-s_fMinTossAngle), 0.0f, 1.0f);
|
|
//Displayf("Angle = %f, direction = %f", fTheta*RtoD, fDirection);
|
|
m_MoveNetworkHelper.SetFloat(ms_ThrowDirection, fDirection);
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
CTask::FSM_Return CTaskThrowProjectile::ThrowProjectile_OnUpdate()
|
|
{
|
|
CPed* pPed = GetPed();
|
|
|
|
#if FPS_MODE_SUPPORTED
|
|
if (pPed->IsFirstPersonShooterModeEnabledForPlayer(false) && pPed->GetIsInCover())
|
|
{
|
|
const float fCamHeading = CTaskCover::ComputeMvCamHeadingForPed(*pPed);
|
|
m_MoveNetworkHelper.SetFloat(CTaskMotionInCover::ms_CamHeadingId, pPed->GetPedResetFlag(CPED_RESET_FLAG_InCoverFacingLeft) ? fCamHeading : 1.0f - fCamHeading);
|
|
}
|
|
#endif // FPS_MODE_SUPPORTED
|
|
|
|
// We will need our update every frame for the throw
|
|
pPed->GetPedAiLod().SetBlockedLodFlag(CPedAILod::AL_LodTimesliceIntelligenceUpdate|CPedAILod::AL_LodTimesliceAnimUpdate);
|
|
|
|
// if crossed fire time then fire weapon
|
|
float fPhase = m_MoveNetworkHelper.GetFloat(ms_ThrowPhase);
|
|
if(!m_bHasThrownProjectile && fPhase >= m_fThrowPhase)
|
|
{
|
|
if(pPed->IsNetworkClone())
|
|
{
|
|
CProjectileManager::FireOrPlacePendingProjectile(pPed, GetNetSequenceID());
|
|
}
|
|
else
|
|
{
|
|
m_bFire = true;
|
|
}
|
|
|
|
m_bHasThrownProjectile = true;
|
|
}
|
|
|
|
if( m_bRotateToFaceTarget && pPed->IsLocalPlayer() )
|
|
{
|
|
pPed->SetPedResetFlag( CPED_RESET_FLAG_SyncDesiredHeadingToCurrentHeading, false );
|
|
|
|
float fCamOrient = camInterface::GetPlayerControlCamHeading(*pPed);
|
|
pPed->SetDesiredHeading( fCamOrient );
|
|
}
|
|
|
|
// Animation finished....
|
|
if(m_MoveNetworkHelper.GetBoolean(ms_ThrowCompleteEvent))
|
|
{
|
|
|
|
int nAmmo = pPed->GetInventory()->GetWeaponAmmo(pPed->GetWeaponManager()->GetEquippedWeaponInfo());
|
|
if(nAmmo == 0)
|
|
{
|
|
// Out of ammo - swap weapon
|
|
CThrowProjectileHelper::SetWeaponSlotAfterFiring(pPed);
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
if(pPed->GetWeaponManager()->GetRequiresWeaponSwitch())
|
|
{
|
|
if(!pPed->IsNetworkClone())
|
|
{
|
|
pPed->GetWeaponManager()->CreateEquippedWeaponObject();
|
|
}
|
|
}
|
|
|
|
SetState(State_Finish);
|
|
return FSM_Continue;
|
|
}
|
|
|
|
return FSM_Continue;
|
|
}
|
|
|
|
bool CTaskThrowProjectile::CanTriggerTurn(CPed* pPed)
|
|
{
|
|
if (pPed->IsNetworkClone())
|
|
{
|
|
TUNE_GROUP_FLOAT(COVER_PROJECTILE_BUG, MIN_DELTA_TO_TRIGGER_TURN_CLONE, 0.25f, 0.0f, 3.0f, 0.01f);
|
|
const float fCurrentHeading = pPed->GetCurrentHeading();
|
|
const float fDesiredHeading = pPed->GetDesiredHeading();
|
|
const float fDelta = fwAngle::LimitRadianAngle(fCurrentHeading - fDesiredHeading);
|
|
if (Abs(fDelta) < MIN_DELTA_TO_TRIGGER_TURN_CLONE)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static dev_s32 s_iTurnDelay = 1000;
|
|
return (m_iTurnTimer + s_iTurnDelay) < fwTimer::GetTimeInMilliseconds();
|
|
}
|
|
|
|
void CTaskThrowProjectile::TriggerTurn(CPed* pPed, bool bFacingLeft)
|
|
{
|
|
CTask* pTask = pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_COVER);
|
|
if (!taskVerifyf(pTask, "Frame : %i, %s Ped %s couldn't find active cover task", fwTimer::GetFrameCount(), pPed->IsNetworkClone() ? "CLONE" : "LOCAL", pPed->GetDebugName()))
|
|
return;
|
|
|
|
if (bFacingLeft)
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_TurnRight);
|
|
static_cast<CTaskCover*>(pTask)->ClearCoverFlag(CTaskCover::CF_FacingLeft);
|
|
}
|
|
else
|
|
{
|
|
m_MoveNetworkHelper.SendRequest(ms_TurnLeft);
|
|
static_cast<CTaskCover*>(pTask)->SetCoverFlag(CTaskCover::CF_FacingLeft);
|
|
}
|
|
|
|
//temporary until a real asset is available(?)
|
|
fwMvClipSetId clipSetId = CLIP_SET_ID_INVALID;
|
|
fwMvClipId introClipId = CLIP_ID_INVALID;
|
|
fwMvClipId baseClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwLongClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwShortClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwLongFaceCoverClipId = CLIP_ID_INVALID;
|
|
fwMvClipId throwShortFaceCoverClipId = CLIP_ID_INVALID;
|
|
|
|
pTask = pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_IN_COVER);
|
|
if (!taskVerifyf(pTask, "Frame : %i, %s Ped %s couldn't find active in cover task", fwTimer::GetFrameCount(), pPed->IsNetworkClone() ? "CLONE" : "LOCAL", pPed->GetDebugName()))
|
|
return;
|
|
|
|
if (CTaskInCover::GetThrownProjectileClipSetAndClipIds(pPed, static_cast<CTaskInCover*>(pTask), clipSetId, introClipId, baseClipId, throwLongClipId, throwShortClipId, throwLongFaceCoverClipId, throwShortFaceCoverClipId, static_cast<CTaskInCover*>(pTask)->IsCoverFlagSet(CTaskCover::CF_TooHighCoverPoint)))
|
|
{
|
|
if (bFacingLeft)
|
|
{
|
|
m_pRightTurnClip = fwClipSetManager::GetClip(clipSetId, baseClipId);
|
|
m_MoveNetworkHelper.SetClip(m_pRightTurnClip, ms_MvTurnRightClip);
|
|
}
|
|
else
|
|
{
|
|
m_pLeftTurnClip = fwClipSetManager::GetClip(clipSetId, baseClipId);
|
|
m_MoveNetworkHelper.SetClip(m_pLeftTurnClip, ms_MvTurnLeftClip);
|
|
}
|
|
}
|
|
|
|
m_iTurnTimer = fwTimer::GetTimeInMilliseconds();
|
|
m_MoveNetworkHelper.WaitForTargetState(ms_EnterPrimeEvent);
|
|
m_bTurning = true;
|
|
m_bTurnSwappedAnims = false;
|
|
}
|
|
|
|
void CTaskThrowProjectile::DropProjectile(CPed* pPed , CWeapon* pWeapon)
|
|
{
|
|
CObject* pProjOverride = pPed->GetWeaponManager()->GetEquippedWeaponObject();
|
|
|
|
Matrix34 weaponMat;
|
|
if (pProjOverride && pWeapon)
|
|
{
|
|
// Calculate the launch position
|
|
weaponMat = MAT34V_TO_MATRIX34(pProjOverride->GetMatrix());
|
|
|
|
Vector3 vStart = weaponMat.d;
|
|
Vector3 vEnd(Vector3::ZeroType);
|
|
|
|
Vector3 trajectory;
|
|
static dev_float BACKWARDS_FIRE_VELOCITY = -8.0f;
|
|
// Always throw it backwards if it will generate fire on impact.
|
|
if( pWeapon->GetWeaponInfo()->GetDamageType() == DAMAGE_TYPE_FIRE )
|
|
{
|
|
trajectory = VEC3V_TO_VECTOR3(pPed->GetTransform().GetB()) * BACKWARDS_FIRE_VELOCITY;
|
|
}
|
|
else
|
|
{
|
|
trajectory = -ZAXIS;
|
|
}
|
|
vEnd = weaponMat.d + trajectory;
|
|
vStart = weaponMat.d;
|
|
|
|
float fOverrideLifeTime = -1.0f;
|
|
if(!pWeapon->GetIsCooking())
|
|
pWeapon->StartCookTimer(fwTimer::GetTimeInMilliseconds());
|
|
if (pWeapon->GetWeaponInfo()->GetProjectileFuseTime() > 0.0f)
|
|
fOverrideLifeTime = Max(0.0f, pWeapon->GetCookTimeLeft(pPed, fwTimer::GetTimeInMilliseconds()));
|
|
|
|
// Throw the projectile
|
|
CWeapon::sFireParams params(pPed, weaponMat, &vStart, &vEnd);
|
|
params.fOverrideLifeTime = fOverrideLifeTime;
|
|
params.fDesiredTargetDistance = vStart.Dist( vEnd );
|
|
if(pWeapon->Fire(params))
|
|
{
|
|
// Ensure object is removed
|
|
pPed->GetWeaponManager()->DestroyEquippedWeaponObject();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CTaskThrowProjectile::OffsetProjectileIfNecessaryInCover(const CPed *pPed, const Vector3 vTestStartCam, const Vector3 vTestEndCam, const Vector3 vTestStartThrow, const Vector3 vTestEndThrow, const Matrix34 weaponMat, float &fOffsetZ)
|
|
{
|
|
// B*1983883: If we're throwing from cover and aim vector from camera isn't colliding with the cover, but the projectile is going to,
|
|
// then offset it slightly by the height difference (within reason). Called from CTaskThrowProjectile::ProcessPostPreRender if we're about to release the projectile.
|
|
if (pPed->GetIsInCover())
|
|
{
|
|
CCoverPoint *pCoverPoint = pPed->GetCoverPoint();
|
|
// Only do this if cover point is of "low" height; ie we can throw over it.
|
|
if (pCoverPoint && pCoverPoint->GetHeight() == CCoverPoint::COVHEIGHT_LOW)
|
|
{
|
|
CEntity *pCoverEntity = pPed->GetPlayerInfo() ? pPed->GetPlayerInfo()->ms_DynamicCoverHelper.GetCoverEntryEntity() : NULL;
|
|
if (pCoverEntity && pCoverEntity->GetBaseModelInfo())
|
|
{
|
|
// Probe test along camera aim vector.
|
|
bool bHitCoverFromCamera = false;
|
|
|
|
WorldProbe::CShapeTestHitPoint probeIsectCam;
|
|
WorldProbe::CShapeTestResults probeResultCam(probeIsectCam);
|
|
WorldProbe::CShapeTestProbeDesc probeDescCam;
|
|
probeDescCam.SetStartAndEnd(vTestStartCam, vTestEndCam);
|
|
probeDescCam.SetResultsStructure(&probeResultCam);
|
|
probeDescCam.SetExcludeEntity(pPed);
|
|
probeDescCam.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES|ArchetypeFlags::GTA_VEHICLE_TYPE|ArchetypeFlags::GTA_OBJECT_TYPE);
|
|
probeDescCam.SetContext(WorldProbe::LOS_GeneralAI);
|
|
|
|
if(WorldProbe::GetShapeTestManager()->SubmitTest(probeDescCam, WorldProbe::PERFORM_SYNCHRONOUS_TEST))
|
|
{
|
|
for (int i = 0; i < probeResultCam.GetNumHits(); i++)
|
|
{
|
|
if (pCoverEntity == probeResultCam[i].GetHitEntity())
|
|
{
|
|
// We've hit the cover entity from the camera vector.
|
|
bHitCoverFromCamera = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bHitCoverFromCamera)
|
|
{
|
|
// We haven't hit cover from the camera vector, so do a probe test from projectile position to end position.
|
|
bool bHitCoverFromThrow = false;
|
|
|
|
WorldProbe::CShapeTestHitPoint probeIsectThrow;
|
|
WorldProbe::CShapeTestResults probeResultThrow(probeIsectThrow);
|
|
WorldProbe::CShapeTestProbeDesc probeDescThrow;
|
|
probeDescThrow.SetStartAndEnd(vTestStartThrow, vTestEndThrow);
|
|
probeDescThrow.SetResultsStructure(&probeResultThrow);
|
|
probeDescThrow.SetExcludeEntity(pPed);
|
|
probeDescThrow.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES|ArchetypeFlags::GTA_VEHICLE_TYPE|ArchetypeFlags::GTA_OBJECT_TYPE);
|
|
probeDescThrow.SetContext(WorldProbe::LOS_GeneralAI);
|
|
|
|
if(WorldProbe::GetShapeTestManager()->SubmitTest(probeDescThrow, WorldProbe::PERFORM_SYNCHRONOUS_TEST))
|
|
{
|
|
for (int i = 0; i < probeResultThrow.GetNumHits(); i++)
|
|
{
|
|
if (pCoverEntity == probeResultThrow[i].GetHitEntity())
|
|
{
|
|
// We've hit the cover entity from the throw vector.
|
|
bHitCoverFromThrow = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We didn't hit the cover from the aim vector, but we did from the throw vector,
|
|
// so try and offset the projectile slightly based on the cover height.
|
|
if (bHitCoverFromThrow)
|
|
{
|
|
// Calculate height difference between cover and projectile.
|
|
const float fLocalCoverHeight = pCoverEntity->GetBoundingBoxMax().z - pCoverEntity->GetBoundingBoxMin().z;
|
|
float fCoverHeight = pCoverEntity->GetTransform().GetPosition().GetZf() + fLocalCoverHeight;
|
|
float fProjectileHeight = weaponMat.d.z;
|
|
|
|
float fHeightOffset = Abs(fCoverHeight - fProjectileHeight);
|
|
|
|
// Clamp the change so we don't get a crazy pop.
|
|
static dev_float fMaxHeightOffset = 0.2f;
|
|
fHeightOffset = Clamp(fHeightOffset, 0.0f, fMaxHeightOffset);
|
|
|
|
// Set the weapon matrix Z offset variable.
|
|
fOffsetZ = fHeightOffset;
|
|
return true;
|
|
}
|
|
#if __BANK
|
|
static dev_bool bEnableOffsetDebugRender = false;
|
|
if (bEnableOffsetDebugRender)
|
|
{
|
|
CTask::ms_debugDraw.AddLine(RCC_VEC3V(vTestStartCam), RCC_VEC3V(vTestEndCam), Color_yellow, 0);
|
|
CTask::ms_debugDraw.AddLine(RCC_VEC3V(vTestStartThrow), RCC_VEC3V(vTestEndThrow), Color_blue, 0);
|
|
CTask::ms_debugDraw.AddSphere( RCC_VEC3V(weaponMat.d), 0.025f, Color_CornflowerBlue);
|
|
}
|
|
#endif // __BANK
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
float CTaskAimAndThrowProjectile::SelectFPSBlendTime(CPed *pPed, bool bStateToTransition, CPedMotionData::eFPSState prevFPSStateOverride, CPedMotionData::eFPSState currFPSStateOverride)
|
|
{
|
|
float fBlendTime = 0.2f;
|
|
|
|
//Idle_To_RNG
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fIdle_To_IdleToRNG_BlendTime, 0.09f, 0.0f, 2.0f, 0.01f);
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fIdleToRNG_To_RNG_BlendTime, 0.15f, 0.0f, 2.0f, 0.01f);
|
|
|
|
//Idle_To_LT
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fIdle_To_IdleToLT_BlendTime, 0.15f, 0.0f, 2.0f, 0.01f);
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fIdleToLT_To_LT_BlendTime, 0.15f, 0.0f, 2.0f, 0.01f);
|
|
|
|
//LT_To_Idle
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fLT_To_LTToIdle_BlendTime, 0.15f, 0.0f, 2.0f, 0.01f);
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fLTToIdle_To_Idle_BlendTime, 0.25f, 0.0f, 2.0f, 0.01f);
|
|
|
|
//LT_To_RNG
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fLT_To_LTToRNG_BlendTime, 0.09f, 0.0f, 2.0f, 0.01f);
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fLTToRNG_To_RNG_BlendTime, 0.15f, 0.0f, 2.0f, 0.01f);
|
|
|
|
//Unholster_To_Idle
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fUnholster_To_UnholsterToIdle_BlendTime, 0.15f, 0.0f, 2.0f, 0.01f);
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fUnholsterToIdle_To_Idle_BlendTime, 0.3f, 0.0f, 2.0f, 0.01f);
|
|
|
|
//Unholster_To_LT
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fUnholster_To_UnholsterToLT_BlendTime, 0.15f, 0.0f, 2.0f, 0.01f);
|
|
TUNE_GROUP_FLOAT(FIRST_PERSON_TUNE_PROJECTILE, fUnholsterToLT_To_LT_BlendTime, 0.3f, 0.0f, 2.0f, 0.01f);
|
|
|
|
int iCurrState = (prevFPSStateOverride != CPedMotionData::FPS_MAX) ? currFPSStateOverride : pPed->GetMotionData()->GetFPSState();
|
|
int iPrevState = (currFPSStateOverride != CPedMotionData::FPS_MAX) ? prevFPSStateOverride : pPed->GetMotionData()->GetPreviousFPSState();
|
|
|
|
if(iPrevState == CPedMotionData::FPS_IDLE && iCurrState == CPedMotionData::FPS_RNG)
|
|
{
|
|
fBlendTime = (bStateToTransition) ? fIdle_To_IdleToRNG_BlendTime : fIdleToRNG_To_RNG_BlendTime;
|
|
}
|
|
else if(iPrevState == CPedMotionData::FPS_IDLE && iCurrState == CPedMotionData::FPS_LT)
|
|
{
|
|
fBlendTime = (bStateToTransition) ? fIdle_To_IdleToLT_BlendTime : fIdleToLT_To_LT_BlendTime;
|
|
}
|
|
else if(iPrevState == CPedMotionData::FPS_LT && iCurrState == CPedMotionData::FPS_IDLE)
|
|
{
|
|
fBlendTime = (bStateToTransition) ? fLT_To_LTToIdle_BlendTime : fLTToIdle_To_Idle_BlendTime;
|
|
}
|
|
else if(iPrevState == CPedMotionData::FPS_LT && iCurrState == CPedMotionData::FPS_RNG)
|
|
{
|
|
fBlendTime = (bStateToTransition) ? fLT_To_LTToRNG_BlendTime : fLTToRNG_To_RNG_BlendTime;
|
|
}
|
|
else if(iPrevState == CPedMotionData::FPS_UNHOLSTER && iCurrState == CPedMotionData::FPS_IDLE)
|
|
{
|
|
fBlendTime = (bStateToTransition) ? fUnholster_To_UnholsterToIdle_BlendTime : fUnholsterToIdle_To_Idle_BlendTime;
|
|
}
|
|
else if(iPrevState == CPedMotionData::FPS_UNHOLSTER && iCurrState == CPedMotionData::FPS_LT)
|
|
{
|
|
fBlendTime = (bStateToTransition) ? fUnholster_To_UnholsterToLT_BlendTime : fUnholsterToLT_To_LT_BlendTime;
|
|
}
|
|
|
|
return fBlendTime;
|
|
}
|