#include "common.h" #include "RwHelper.h" #include "PlayerPed.h" #include "Wanted.h" #include "Fire.h" #include "DMAudio.h" #include "Pad.h" #include "Camera.h" #include "WeaponEffects.h" #include "ModelIndices.h" #include "World.h" #include "RpAnimBlend.h" #include "AnimBlendAssociation.h" #include "General.h" #include "Pools.h" #include "Darkel.h" #include "CarCtrl.h" #include "MBlur.h" #include "Streaming.h" #include "Population.h" #include "Script.h" #include "Replay.h" #include "PedPlacement.h" #include "VarConsole.h" #include "SaveBuf.h" #define PAD_MOVE_TO_GAME_WORLD_MOVE 60.0f bool CPlayerPed::bDontAllowWeaponChange; #ifndef MASTER bool CPlayerPed::bDebugPlayerInfo; #endif const uint32 CPlayerPed::nSaveStructSize = #ifdef COMPATIBLE_SAVES 1752; #else sizeof(CPlayerPed); #endif int32 idleAnimBlockIndex; CPad* GetPadFromPlayer(CPlayerPed*) { return CPad::GetPad(0); } CPlayerPed::~CPlayerPed() { delete m_pWanted; } CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1) { m_fMoveSpeed = 0.0f; SetModelIndex(MI_PLAYER); #ifdef FIX_BUGS m_fCurrentStamina = m_fMaxStamina = 150.0f; #endif SetInitialState(); m_pWanted = new CWanted(); m_pWanted->Initialise(); m_pArrestingCop = nil; m_currentWeapon = WEAPONTYPE_UNARMED; m_nSelectedWepSlot = WEAPONSLOT_UNARMED; m_nSpeedTimer = 0; m_bSpeedTimerFlag = false; SetWeaponLockOnTarget(nil); SetPedState(PED_IDLE); #ifndef FIX_BUGS m_fCurrentStamina = m_fMaxStamina = 150.0f; #endif m_fStaminaProgress = 0.0f; m_nEvadeAmount = 0; m_pEvadingFrom = nil; m_nHitAnimDelayTimer = 0; m_fAttackButtonCounter = 0.0f; m_bHaveTargetSelected = false; m_bHasLockOnTarget = false; m_bCanBeDamaged = true; m_bNoPosForMeleeAttack = false; m_fWalkAngle = 0.0f; m_fFPSMoveHeading = 0.0f; m_pMinigunTopAtomic = nil; m_fGunSpinSpeed = 0.0; m_fGunSpinAngle = 0.0; m_nPadDownPressedInMilliseconds = 0; m_nTargettableObjects[0] = m_nTargettableObjects[1] = m_nTargettableObjects[2] = m_nTargettableObjects[3] = -1; unk1 = false; for (int i = 0; i < 6; i++) { m_vecSafePos[i] = CVector(0.0f, 0.0f, 0.0f); m_pPedAtSafePos[i] = nil; m_pMeleeList[i] = nil; } m_nAttackDirToCheck = 0; m_nLastBusFareCollected = 0; idleAnimBlockIndex = CAnimManager::GetAnimationBlockIndex("playidles"); } void CPlayerPed::ClearWeaponTarget() { if (m_nPedType == PEDTYPE_PLAYER1) { SetWeaponLockOnTarget(nil); TheCamera.ClearPlayerWeaponMode(); CWeaponEffects::ClearCrossHair(); } ClearPointGunAt(); } void CPlayerPed::SetWantedLevel(int32 level) { m_pWanted->SetWantedLevel(level); } void CPlayerPed::SetWantedLevelNoDrop(int32 level) { m_pWanted->SetWantedLevelNoDrop(level); } void CPlayerPed::MakeObjectTargettable(int32 handle) { for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) { if (CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]) == nil) { m_nTargettableObjects[i] = handle; return; } } } // I don't know the actual purpose of parameter void CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity) { if (m_pedStats->m_temper < 52) { m_pedStats->m_temper++; } else if (annoyedByPassingEntity && m_pedStats->m_temper < 55) { m_pedStats->m_temper++; } else if (annoyedByPassingEntity) { m_pedStats->m_temper = 46; } } void CPlayerPed::ClearAdrenaline(void) { if (m_bAdrenalineActive && m_nAdrenalineTime != 0) { m_nAdrenalineTime = 0; CTimer::SetTimeScale(1.0f); } } CPlayerInfo * CPlayerPed::GetPlayerInfoForThisPlayerPed() { if (CWorld::Players[0].m_pPed == this) return &CWorld::Players[0]; return nil; } void CPlayerPed::SetupPlayerPed(int32 index) { CPlayerPed *player = new CPlayerPed(); CWorld::Players[index].m_pPed = player; #ifdef FIX_BUGS player->RegisterReference((CEntity**)&CWorld::Players[index].m_pPed); #endif player->SetOrientation(0.0f, 0.0f, 0.0f); CWorld::Add(player); player->m_wepAccuracy = 100; #ifndef MASTER VarConsole.Add("Debug PlayerPed", &CPlayerPed::bDebugPlayerInfo, true); VarConsole.Add("Tweak Vehicle Handling", &CVehicle::m_bDisplayHandlingInfo, true); #endif } void CPlayerPed::DeactivatePlayerPed(int32 index) { CWorld::Remove(CWorld::Players[index].m_pPed); } void CPlayerPed::ReactivatePlayerPed(int32 index) { CWorld::Add(CWorld::Players[index].m_pPed); } void CPlayerPed::UseSprintEnergy(void) { if (m_fCurrentStamina > -150.0f && !CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint && !m_bAdrenalineActive) { m_fCurrentStamina = m_fCurrentStamina - CTimer::GetTimeStep(); m_fStaminaProgress = m_fStaminaProgress + CTimer::GetTimeStep(); } if (m_fStaminaProgress >= 500.0f) { m_fStaminaProgress = 0; if (m_fMaxStamina < 1000.0f) m_fMaxStamina += 10.0f; } } void CPlayerPed::MakeChangesForNewWeapon(eWeaponType weapon) { if (m_nPedState == PED_SNIPER_MODE) { RestorePreviousState(); TheCamera.ClearPlayerWeaponMode(); } SetCurrentWeapon(weapon); m_nSelectedWepSlot = m_currentWeapon; GetWeapon()->m_nAmmoInClip = Min(GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition); if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_CANAIM)) ClearWeaponTarget(); // WEAPONTYPE_SNIPERRIFLE? Wut? CAnimBlendAssociation* weaponAnim = RpAnimBlendClumpGetAssociation(GetClump(), GetPrimaryFireAnim(CWeaponInfo::GetWeaponInfo(WEAPONTYPE_SNIPERRIFLE))); if (weaponAnim) { weaponAnim->SetRun(); weaponAnim->flags |= ASSOC_FADEOUTWHENDONE; } TheCamera.ClearPlayerWeaponMode(); } void CPlayerPed::MakeChangesForNewWeapon(int32 slot) { if(slot != -1) MakeChangesForNewWeapon(m_weapons[slot].m_eWeaponType); } void CPlayerPed::ReApplyMoveAnims(void) { static AnimationId moveAnims[] = { ANIM_STD_WALK, ANIM_STD_RUN, ANIM_STD_RUNFAST, ANIM_STD_IDLE, ANIM_STD_STARTWALK }; for(int i = 0; i < ARRAY_SIZE(moveAnims); i++) { CAnimBlendAssociation *curMoveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), moveAnims[i]); if (curMoveAssoc) { if (CGeneral::faststrcmp(CAnimManager::GetAnimAssociation(m_animGroup, moveAnims[i])->hierarchy->name, curMoveAssoc->hierarchy->name)) { CAnimBlendAssociation *newMoveAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, moveAnims[i]); newMoveAssoc->blendDelta = curMoveAssoc->blendDelta; newMoveAssoc->blendAmount = curMoveAssoc->blendAmount; curMoveAssoc->blendDelta = -1000.0f; curMoveAssoc->flags |= ASSOC_DELETEFADEDOUT; } } } } void CPlayerPed::SetInitialState(void) { m_nDrunkenness = 0; m_nFadeDrunkenness = 0; CMBlur::ClearDrunkBlur(); m_nDrunkCountdown = 0; m_bAdrenalineActive = false; m_nAdrenalineTime = 0; CTimer::SetTimeScale(1.0f); m_pSeekTarget = nil; m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); m_fleeFromPos = CVector2D(0.0f, 0.0f); m_fleeFrom = nil; m_fleeTimer = 0; m_objective = OBJECTIVE_NONE; m_prevObjective = OBJECTIVE_NONE; bUsesCollision = true; ClearAimFlag(); ClearLookFlag(); bIsPointingGunAt = false; bRenderPedInCar = true; if (m_pFire) m_pFire->Extinguish(); RpAnimBlendClumpRemoveAllAssociations(GetClump()); SetPedState(PED_IDLE); SetMoveState(PEDMOVE_STILL); m_nLastPedState = PED_NONE; m_animGroup = ASSOCGRP_PLAYER; m_fMoveSpeed = 0.0f; m_nSelectedWepSlot = WEAPONSLOT_UNARMED; m_nEvadeAmount = 0; m_pEvadingFrom = nil; bIsPedDieAnimPlaying = false; SetRealMoveAnim(); m_bCanBeDamaged = true; m_pedStats->m_temper = 50; m_fWalkAngle = 0.0f; if (m_attachedTo && !bUsesCollision) bUsesCollision = true; m_attachedTo = nil; m_attachWepAmmo = 0; } void CPlayerPed::SetRealMoveAnim(void) { CAnimBlendAssociation *curWalkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_WALK); CAnimBlendAssociation *curRunAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUN); CAnimBlendAssociation *curSprintAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUNFAST); CAnimBlendAssociation *curWalkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_STARTWALK); CAnimBlendAssociation *curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE); CAnimBlendAssociation *curRunStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUNSTOP1); CAnimBlendAssociation *curRunStopRAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUNSTOP2); if (bResetWalkAnims) { if (curWalkAssoc) curWalkAssoc->SetCurrentTime(0.0f); if (curRunAssoc) curRunAssoc->SetCurrentTime(0.0f); if (curSprintAssoc) curSprintAssoc->SetCurrentTime(0.0f); bResetWalkAnims = false; } if (!curIdleAssoc) curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE_TIRED); if (!curIdleAssoc) curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_FIGHT_IDLE); if (!curIdleAssoc) curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_MELEE_IDLE_FIGHTMODE); if (!((curRunStopAssoc && curRunStopAssoc->IsRunning()) || (curRunStopRAssoc && curRunStopRAssoc->IsRunning()))) { if (curRunStopAssoc && curRunStopAssoc->blendDelta >= 0.0f || curRunStopRAssoc && curRunStopRAssoc->blendDelta >= 0.0f) { if (curRunStopAssoc) { curRunStopAssoc->flags |= ASSOC_DELETEFADEDOUT; curRunStopAssoc->blendAmount = 1.0f; curRunStopAssoc->blendDelta = -8.0f; } else if (curRunStopRAssoc) { curRunStopRAssoc->flags |= ASSOC_DELETEFADEDOUT; curRunStopRAssoc->blendAmount = 1.0f; curRunStopRAssoc->blendDelta = -8.0f; } RestoreHeadingRate(); if (!curIdleAssoc) { if (m_fCurrentStamina < 0.0f && !bIsAimingGun && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.5f, nil, true, false, false, false, false, false)) { curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_IDLE_TIRED, 8.0f); } else { curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 8.0f); } m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000); } curIdleAssoc->blendAmount = 0.0f; curIdleAssoc->blendDelta = 8.0f; } else if (m_fMoveSpeed == 0.0f && !curSprintAssoc) { if (!curIdleAssoc) { if (m_fCurrentStamina < 0.0f && !bIsAimingGun && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.5f, nil, true, false, false, false, false, false)) { curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_IDLE_TIRED, 4.0f); } else { curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 4.0f); } m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000); } if ((m_fCurrentStamina > 0.0f || bIsAimingGun) && curIdleAssoc->animId == ANIM_STD_IDLE_TIRED) { CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 4.0f); } else if (m_nPedState != PED_FIGHT) { if (m_fCurrentStamina < 0.0f && !bIsAimingGun && curIdleAssoc->animId != ANIM_STD_IDLE_TIRED && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.5f, nil, true, false, false, false, false, false)) { CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_IDLE_TIRED, 4.0f); } else if (curIdleAssoc->animId != ANIM_STD_IDLE) { CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 4.0f); } } m_nMoveState = PEDMOVE_STILL; } else { if (curIdleAssoc) { if (curWalkStartAssoc) { curWalkStartAssoc->blendAmount = 1.0f; curWalkStartAssoc->blendDelta = 0.0f; } else { curWalkStartAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_STD_STARTWALK); } if (curWalkAssoc) curWalkAssoc->SetCurrentTime(0.0f); if (curRunAssoc) curRunAssoc->SetCurrentTime(0.0f); delete curIdleAssoc; delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE_TIRED); CAnimBlendAssociation *fightIdleAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_FIGHT_IDLE); if (!fightIdleAnim) fightIdleAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_MELEE_IDLE_FIGHTMODE); delete fightIdleAnim; delete curSprintAssoc; curSprintAssoc = nil; m_nMoveState = PEDMOVE_WALK; } if (curRunStopAssoc) { delete curRunStopAssoc; RestoreHeadingRate(); } if (curRunStopRAssoc) { delete curRunStopRAssoc; RestoreHeadingRate(); } if (!curWalkAssoc) { curWalkAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_STD_WALK); curWalkAssoc->blendAmount = 0.0f; } if (!curRunAssoc) { curRunAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_STD_RUN); curRunAssoc->blendAmount = 0.0f; } if (curWalkStartAssoc && !(curWalkStartAssoc->IsRunning())) { delete curWalkStartAssoc; curWalkStartAssoc = nil; curWalkAssoc->SetRun(); curRunAssoc->SetRun(); } if (m_nMoveState == PEDMOVE_SPRINT) { if (m_fCurrentStamina < 0.0f && (m_fCurrentStamina <= -150.0f || !curSprintAssoc || curSprintAssoc->blendDelta < 0.0f)) m_nMoveState = PEDMOVE_STILL; if (curWalkStartAssoc) m_nMoveState = PEDMOVE_STILL; } if (curSprintAssoc && (m_nMoveState != PEDMOVE_SPRINT || m_fMoveSpeed < 0.4f)) { // Stop sprinting in various conditions if (curSprintAssoc->blendAmount == 0.0f) { curSprintAssoc->blendDelta = -1000.0f; curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT; } else if (curSprintAssoc->blendDelta >= 0.0f || curSprintAssoc->blendAmount >= 0.8f) { if (m_fMoveSpeed < 0.4f) { AnimationId runStopAnim; if (curSprintAssoc->GetProgress() < 0.5) // double runStopAnim = ANIM_STD_RUNSTOP1; else runStopAnim = ANIM_STD_RUNSTOP2; CAnimBlendAssociation* newRunStopAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, runStopAnim); newRunStopAssoc->blendAmount = 1.0f; newRunStopAssoc->SetDeleteCallback(RestoreHeadingRateCB, this); m_headingRate = 0.0f; curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT; curSprintAssoc->blendDelta = -1000.0f; curWalkAssoc->flags &= ~ASSOC_RUNNING; curWalkAssoc->blendAmount = 0.0f; curWalkAssoc->blendDelta = 0.0f; curRunAssoc->flags &= ~ASSOC_RUNNING; curRunAssoc->blendAmount = 0.0f; curRunAssoc->blendDelta = 0.0f; } else if (curSprintAssoc->blendDelta >= 0.0f) { // this condition is absent on mobile // Stop sprinting when tired curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT; curSprintAssoc->blendDelta = -1.0f; curRunAssoc->blendDelta = 1.0f; } } else if (m_fMoveSpeed < 1.0f) { curSprintAssoc->blendDelta = -8.0f; curRunAssoc->blendDelta = 8.0f; } } else if (curWalkStartAssoc) { // Walk start and walk/run shouldn't run at the same time curWalkAssoc->flags &= ~ASSOC_RUNNING; curRunAssoc->flags &= ~ASSOC_RUNNING; curWalkAssoc->blendAmount = 0.0f; curRunAssoc->blendAmount = 0.0f; } else if (m_nMoveState == PEDMOVE_SPRINT) { if (curSprintAssoc) { // We have anim, do it if (curSprintAssoc->blendDelta < 0.0f) { curSprintAssoc->blendDelta = 2.0f; curRunAssoc->blendDelta = -2.0f; } } else { // Transition between run-sprint curWalkAssoc->blendAmount = 0.0f; curRunAssoc->blendAmount = 1.0f; curSprintAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_RUNFAST, 2.0f); } UseSprintEnergy(); } else { if (m_fMoveSpeed < 1.0f) { curWalkAssoc->blendAmount = 1.0f; curRunAssoc->blendAmount = 0.0f; m_nMoveState = PEDMOVE_WALK; } else if (m_fMoveSpeed < 2.0f) { curWalkAssoc->blendAmount = 2.0f - m_fMoveSpeed; curRunAssoc->blendAmount = m_fMoveSpeed - 1.0f; m_nMoveState = PEDMOVE_RUN; } else { curWalkAssoc->blendAmount = 0.0f; curRunAssoc->blendAmount = 1.0f; m_nMoveState = PEDMOVE_RUN; } curWalkAssoc->blendDelta = 0.0f; curRunAssoc->blendDelta = 0.0f; } } } if (m_bAdrenalineActive) { if (CTimer::GetTimeInMilliseconds() > m_nAdrenalineTime) { m_bAdrenalineActive = false; CTimer::SetTimeScale(1.0f); if (curWalkStartAssoc) curWalkStartAssoc->speed = 1.0f; if (curWalkAssoc) curWalkAssoc->speed = 1.0f; if (curRunAssoc) curRunAssoc->speed = 1.0f; if (curSprintAssoc) curSprintAssoc->speed = 1.0f; } else { CTimer::SetTimeScale(1.0f / 3); if (curWalkStartAssoc) curWalkStartAssoc->speed = 2.0f; if (curWalkAssoc) curWalkAssoc->speed = 2.0f; if (curRunAssoc) curRunAssoc->speed = 2.0f; if (curSprintAssoc) curSprintAssoc->speed = 2.0f; } } else if (curSprintAssoc) { if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIXED) { curSprintAssoc->speed = 0.7f; } else curSprintAssoc->speed = 1.0f; } } void CPlayerPed::RestoreSprintEnergy(float restoreSpeed) { if (m_fCurrentStamina < m_fMaxStamina) m_fCurrentStamina += restoreSpeed * CTimer::GetTimeStep() * 0.5f; } float CPlayerPed::DoWeaponSmoothSpray(void) { if (m_nPedState == PED_ATTACK && !m_pPointGunAt) { CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); switch (GetWeapon()->m_eWeaponType) { case WEAPONTYPE_GOLFCLUB: case WEAPONTYPE_NIGHTSTICK: case WEAPONTYPE_BASEBALLBAT: if (GetFireAnimGround(weaponInfo, false) && RpAnimBlendClumpGetAssociation(GetClump(), GetFireAnimGround(weaponInfo, false))) return PI / 176.f; else return -1.0f; case WEAPONTYPE_CHAINSAW: if (GetMeleeStartAnim(weaponInfo) && RpAnimBlendClumpGetAssociation(GetClump(), GetMeleeStartAnim(weaponInfo))) return PI / 128.0f; else if (GetFireAnimGround(weaponInfo, false) && RpAnimBlendClumpGetAssociation(GetClump(), GetFireAnimGround(weaponInfo, false))) return PI / 176.f; else return PI / 80.f; case WEAPONTYPE_PYTHON: return PI / 112.f; case WEAPONTYPE_SHOTGUN: case WEAPONTYPE_SPAS12_SHOTGUN: case WEAPONTYPE_STUBBY_SHOTGUN: return PI / 112.f; case WEAPONTYPE_UZI: case WEAPONTYPE_MP5: return PI / 112.f; case WEAPONTYPE_M4: case WEAPONTYPE_RUGER: return PI / 112.f; case WEAPONTYPE_FLAMETHROWER: return PI / 80.f; case WEAPONTYPE_M60: case WEAPONTYPE_MINIGUN: case WEAPONTYPE_HELICANNON: return PI / 176.f; default: return -1.0f; } } else if (bIsDucking) return PI / 112.f; else return -1.0f; } void CPlayerPed::DoStuffToGoOnFire(void) { if (m_nPedState == PED_SNIPER_MODE) TheCamera.ClearPlayerWeaponMode(); } bool CPlayerPed::DoesTargetHaveToBeBroken(CVector target, CWeapon *weaponUsed) { CVector distVec = target - GetPosition(); if (distVec.Magnitude() > CWeaponInfo::GetWeaponInfo(weaponUsed->m_eWeaponType)->m_fRange) return true; return false; } // Cancels landing anim while running & jumping? I think void CPlayerPed::RunningLand(CPad *padUsed) { CAnimBlendAssociation *landAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_FALL_LAND); if (landAssoc && landAssoc->currentTime == 0.0f && m_fMoveSpeed > 1.5f && padUsed && (padUsed->GetPedWalkLeftRight() != 0.0f || padUsed->GetPedWalkUpDown() != 0.0f)) { landAssoc->blendDelta = -1000.0f; landAssoc->flags |= ASSOC_DELETEFADEDOUT; CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_JUMP_LAND)->SetFinishCallback(FinishJumpCB, this); if (m_nPedState == PED_JUMP) RestorePreviousState(); } } bool CPlayerPed::IsThisPedAnAimingPriority(CPed *suspect) { if (!suspect->bIsPlayerFriend) return true; if (suspect->m_pPointGunAt == this) return true; switch (suspect->m_objective) { case OBJECTIVE_KILL_CHAR_ON_FOOT: case OBJECTIVE_KILL_CHAR_ANY_MEANS: if (suspect->m_pedInObjective == this) return true; break; default: break; } return suspect->m_nPedState == PED_ABSEIL; } void CPlayerPed::PlayerControlSniper(CPad *padUsed) { ProcessWeaponSwitch(padUsed); TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f; if (padUsed->DuckJustDown() && !bIsDucking && m_nMoveState != PEDMOVE_SPRINT) { bCrouchWhenShooting = true; SetDuck(60000, true); } else if (bIsDucking && (padUsed->DuckJustDown() || m_nMoveState == PEDMOVE_SPRINT)) { ClearDuck(true); bCrouchWhenShooting = false; } if (!padUsed->GetTarget() && !m_attachedTo) { RestorePreviousState(); TheCamera.ClearPlayerWeaponMode(); return; } int firingRate = GetWeapon()->m_eWeaponType == WEAPONTYPE_LASERSCOPE ? 333 : 266; if (padUsed->WeaponJustDown() && CTimer::GetTimeInMilliseconds() > GetWeapon()->m_nTimer) { CVector firePos(0.0f, 0.0f, 0.6f); firePos = GetMatrix() * firePos; GetWeapon()->Fire(this, &firePos); m_nPadDownPressedInMilliseconds = CTimer::GetTimeInMilliseconds(); } else if (CTimer::GetTimeInMilliseconds() > m_nPadDownPressedInMilliseconds + firingRate && CTimer::GetTimeInMilliseconds() - CTimer::GetTimeStepInMilliseconds() < m_nPadDownPressedInMilliseconds + firingRate && padUsed->GetWeapon()) { if (GetWeapon()->m_nAmmoTotal > 0) { DMAudio.PlayFrontEndSound(SOUND_WEAPON_AK47_BULLET_ECHO, GetWeapon()->m_eWeaponType); } } GetWeapon()->Update(m_audioEntityId, nil); } // I think R* also used goto in here. void CPlayerPed::ProcessWeaponSwitch(CPad *padUsed) { if (CDarkel::FrenzyOnGoing() || m_attachedTo) goto switchDetectDone; if (!m_pPointGunAt && !bDontAllowWeaponChange && GetWeapon()->m_eWeaponType != WEAPONTYPE_DETONATOR) { if (padUsed->CycleWeaponRightJustDown()) { if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON_RUNABOUT && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER_RUNABOUT && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER_RUNABOUT && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_CAMERA) { for (m_nSelectedWepSlot = m_currentWeapon + 1; m_nSelectedWepSlot < TOTAL_WEAPON_SLOTS; ++m_nSelectedWepSlot) { if (HasWeaponSlot(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) { goto spentAmmoCheck; } } m_nSelectedWepSlot = 0; } } else if (padUsed->CycleWeaponLeftJustDown()) { if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_CAMERA) { // I don't know what kind of loop that was m_nSelectedWepSlot = m_currentWeapon - 1; do { if (m_nSelectedWepSlot < 0) m_nSelectedWepSlot = TOTAL_WEAPON_SLOTS - 1; if (m_nSelectedWepSlot == WEAPONSLOT_UNARMED) break; if (HasWeaponSlot(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) break; --m_nSelectedWepSlot; } while (m_nSelectedWepSlot != WEAPONSLOT_UNARMED); } } } spentAmmoCheck: if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_eWeaponFire != WEAPON_FIRE_MELEE && (!padUsed->GetWeapon() || GetWeapon()->m_eWeaponType != WEAPONTYPE_MINIGUN)) { if (GetWeapon()->m_nAmmoTotal <= 0) { if (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_SNIPER || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_ROCKETLAUNCHER) return; if (GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR && GetWeapon(WEAPONSLOT_PROJECTILE).m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE) m_nSelectedWepSlot = WEAPONSLOT_PROJECTILE; else m_nSelectedWepSlot = m_currentWeapon - 1; for (; m_nSelectedWepSlot >= WEAPONSLOT_UNARMED; --m_nSelectedWepSlot) { // BUG: m_nSelectedWepSlot and GetWeapon(..) takes slot in VC but they compared them against weapon types in whole condition! jeez #ifdef FIX_BUGS if (m_nSelectedWepSlot == WEAPONSLOT_MELEE || GetWeapon(m_nSelectedWepSlot).m_nAmmoTotal > 0 && m_nSelectedWepSlot != WEAPONSLOT_PROJECTILE) { #else if (m_nSelectedWepSlot == WEAPONTYPE_BASEBALLBAT && GetWeapon(WEAPONTYPE_BASEBALLBAT).m_eWeaponType == WEAPONTYPE_BASEBALLBAT || GetWeapon(m_nSelectedWepSlot).m_nAmmoTotal > 0 && m_nSelectedWepSlot != WEAPONTYPE_MOLOTOV && m_nSelectedWepSlot != WEAPONTYPE_GRENADE && m_nSelectedWepSlot != WEAPONTYPE_TEARGAS) { #endif goto switchDetectDone; } } m_nSelectedWepSlot = WEAPONSLOT_UNARMED; } } switchDetectDone: if (m_nSelectedWepSlot != m_currentWeapon) { if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN && m_nPedState != PED_FIGHT) { RemoveWeaponAnims(m_currentWeapon, -1000.0f); MakeChangesForNewWeapon(m_nSelectedWepSlot); } } } void CPlayerPed::PlayerControlM16(CPad *padUsed) { ProcessWeaponSwitch(padUsed); TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f; if (padUsed->DuckJustDown() && !bIsDucking && m_nMoveState != PEDMOVE_SPRINT) { bCrouchWhenShooting = true; SetDuck(60000, true); } else if (bIsDucking && (padUsed->DuckJustDown() || m_nMoveState == PEDMOVE_SPRINT)) { ClearDuck(true); bCrouchWhenShooting = false; } if (!padUsed->GetTarget() && !m_attachedTo) { RestorePreviousState(); TheCamera.ClearPlayerWeaponMode(); } if (padUsed->GetWeapon() && CTimer::GetTimeInMilliseconds() > GetWeapon()->m_nTimer) { if (GetWeapon()->m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) { DMAudio.PlayFrontEndSound(SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM, 0.f); GetWeapon()->m_nTimer = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nFiringRate + CTimer::GetTimeInMilliseconds(); } else { CVector firePos(0.0f, 0.0f, 0.6f); firePos = GetMatrix() * firePos; GetWeapon()->Fire(this, &firePos); m_nPadDownPressedInMilliseconds = CTimer::GetTimeInMilliseconds(); } } else if (CTimer::GetTimeInMilliseconds() > GetWeapon()->m_nTimer && CTimer::GetTimeInMilliseconds() - CTimer::GetTimeStepInMilliseconds() < GetWeapon()->m_nTimer && GetWeapon()->m_eWeaponState != WEAPONSTATE_OUT_OF_AMMO) { DMAudio.PlayFrontEndSound(SOUND_WEAPON_AK47_BULLET_ECHO, GetWeapon()->m_eWeaponType); } GetWeapon()->Update(m_audioEntityId, nil); } void CPlayerPed::PlayerControlFighter(CPad *padUsed) { float leftRight = padUsed->GetPedWalkLeftRight(); float upDown = padUsed->GetPedWalkUpDown(); float padMove = CVector2D(leftRight, upDown).Magnitude(); if (padMove > 0.0f) { m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown) - TheCamera.Orientation; m_takeAStepAfterAttack = padMove > 2 * PAD_MOVE_TO_GAME_WORLD_MOVE; if (padUsed->GetSprint() && padMove > 1 * PAD_MOVE_TO_GAME_WORLD_MOVE) bIsAttacking = false; } if (!CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_HEAVY) && padUsed->JumpJustDown()) { if (m_nEvadeAmount != 0 && m_pEvadingFrom) { SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1); m_nEvadeAmount = 0; m_pEvadingFrom = nil; } else { SetJump(); } } } void CPlayerPed::PlayerControl1stPersonRunAround(CPad *padUsed) { float leftRight = padUsed->GetPedWalkLeftRight(); float upDown = padUsed->GetPedWalkUpDown(); float padMove = CVector2D(leftRight, upDown).Magnitude(); float padMoveInGameUnit = padMove / PAD_MOVE_TO_GAME_WORLD_MOVE; if (padMoveInGameUnit > 0.0f) { m_fRotationDest = CGeneral::LimitRadianAngle(TheCamera.Orientation); m_fMoveSpeed = Min(padMoveInGameUnit, 0.07f * CTimer::GetTimeStep() + m_fMoveSpeed); } else { m_fMoveSpeed = 0.0f; } if (m_nPedState == PED_JUMP) { if (bIsInTheAir) { if (bUsesCollision && !bHitSteepSlope && (!bHitSomethingLastFrame || m_vecDamageNormal.z > 0.6f) && m_fDistanceTravelled < CTimer::GetTimeStepInSeconds() && m_vecMoveSpeed.MagnitudeSqr() < 0.01f) { float angleSin = Sin(m_fRotationCur); // originally sin(DEGTORAD(RADTODEG(m_fRotationCur))) o_O float angleCos = Cos(m_fRotationCur); ApplyMoveForce(-angleSin * 3.0f, 3.0f * angleCos, 0.05f); } } else if (bIsLanding) { m_fMoveSpeed = 0.0f; } } if (m_nPedState == PED_ANSWER_MOBILE) { SetRealMoveAnim(); return; } if (!CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_HEAVY) && padUsed->GetSprint()) { m_nMoveState = PEDMOVE_SPRINT; } if (m_nPedState != PED_FIGHT) SetRealMoveAnim(); if (!bIsInTheAir && !(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_HEAVY)) && padUsed->JumpJustDown() && m_nPedState != PED_JUMP) { ClearAttack(); ClearWeaponTarget(); if (m_nEvadeAmount != 0 && m_pEvadingFrom) { SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1); m_nEvadeAmount = 0; m_pEvadingFrom = nil; } else { SetJump(); } } // FIX: Fact that PlayIdleAnimations only called through PlayerControlZelda was making it visible to only Classic control players. This isn't fair! #ifdef FIX_BUGS if (m_nPedState != PED_FIGHT) PlayIdleAnimations(padUsed); #endif } void CPlayerPed::KeepAreaAroundPlayerClear(void) { BuildPedLists(); for (int i = 0; i < m_numNearPeds; ++i) { CPed *nearPed = m_nearPeds[i]; if (nearPed->CharCreatedBy == RANDOM_CHAR && nearPed->m_nPedState != PED_DRIVING && !nearPed->DyingOrDead()) { if (nearPed->GetIsOnScreen()) { if (nearPed->m_objective == OBJECTIVE_NONE) { nearPed->SetFindPathAndFlee(this, 5000, true); } else { if (nearPed->EnteringCar()) nearPed->QuitEnteringCar(); nearPed->ClearObjective(); } } else { nearPed->FlagToDestroyWhenNextProcessed(); } } } CVector playerPos = (InVehicle() ? m_pMyVehicle->GetPosition() : GetPosition()); CVector pos = GetPosition(); int16 lastVehicle; CEntity *vehicles[8]; CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); for (int i = 0; i < lastVehicle; i++) { CVehicle *veh = (CVehicle*)vehicles[i]; if (veh->VehicleCreatedBy != MISSION_VEHICLE) { if (veh->GetStatus() != STATUS_PLAYER && veh->GetStatus() != STATUS_PLAYER_DISABLED) { if ((veh->GetPosition() - playerPos).MagnitudeSqr() > 25.0f) { veh->AutoPilot.m_nTempAction = TEMPACT_WAIT; veh->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 5000; } else { if (DotProduct2D(playerPos - veh->GetPosition(), veh->GetForward()) > 0.0f) veh->AutoPilot.m_nTempAction = TEMPACT_REVERSE; else veh->AutoPilot.m_nTempAction = TEMPACT_GOFORWARD; veh->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000; } CCarCtrl::PossiblyRemoveVehicle(veh); } } } } void CPlayerPed::EvaluateNeighbouringTarget(CEntity *candidate, CEntity **targetPtr, float *lastCloseness, float distLimit, float angleOffset, bool lookToLeft, bool priority) { // priority param is unused CVector distVec = candidate->GetPosition() - GetPosition(); if (distVec.Magnitude2D() <= distLimit) { if (!DoesTargetHaveToBeBroken(candidate->GetPosition(), GetWeapon())) { float angleBetweenUs = CGeneral::GetATanOfXY(candidate->GetPosition().x - TheCamera.GetPosition().x, candidate->GetPosition().y - TheCamera.GetPosition().y); angleBetweenUs = CGeneral::LimitAngle(angleBetweenUs - angleOffset); float closeness; if (lookToLeft) { closeness = angleBetweenUs > 0.0f ? -Abs(angleBetweenUs) : -100000.0f; } else { closeness = angleBetweenUs > 0.0f ? -100000.0f : -Abs(angleBetweenUs); } if (closeness > *lastCloseness) { *targetPtr = candidate; *lastCloseness = closeness; } } } } void CPlayerPed::EvaluateTarget(CEntity *candidate, CEntity **targetPtr, float *lastCloseness, float distLimit, float angleOffset, bool priority) { CVector distVec = candidate->GetPosition() - GetPosition(); float dist = distVec.Magnitude2D(); if (dist <= distLimit) { if (!DoesTargetHaveToBeBroken(candidate->GetPosition(), GetWeapon())) { float angleBetweenUs = CGeneral::GetATanOfXY(distVec.x, distVec.y); angleBetweenUs = CGeneral::LimitAngle(angleBetweenUs - angleOffset); float closeness = -dist - 5.0f * Abs(angleBetweenUs); if (priority) { closeness += 30.0f; } if (closeness > *lastCloseness) { *targetPtr = candidate; *lastCloseness = closeness; } } } } bool CPlayerPed::CanIKReachThisTarget(CVector target, CWeapon* weapon, bool zRotImportant) { float angleToFace = CGeneral::GetRadianAngleBetweenPoints(target.x, target.y, GetPosition().x, GetPosition().y); float angleDiff = CGeneral::LimitRadianAngle(angleToFace - m_fRotationCur); return (!zRotImportant || CWeaponInfo::GetWeaponInfo(weapon->m_eWeaponType)->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM) || Abs(angleDiff) <= HALFPI) && (CWeaponInfo::GetWeaponInfo(weapon->m_eWeaponType)->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM) || Abs(target.z - GetPosition().z) <= (target - GetPosition()).Magnitude2D()); } void CPlayerPed::RotatePlayerToTrackTarget(void) { if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM)) return; float angleToFace = CGeneral::GetRadianAngleBetweenPoints( m_pPointGunAt->GetPosition().x, m_pPointGunAt->GetPosition().y, GetPosition().x, GetPosition().y); float angleDiff = CGeneral::LimitRadianAngle(m_fRotationCur - angleToFace); if (angleDiff < -DEGTORAD(25.0f)) { m_fRotationCur -= angleDiff + DEGTORAD(25.0f); m_fRotationDest -= angleDiff + DEGTORAD(25.0f); } else if (angleDiff > DEGTORAD(25.0f)) { m_fRotationCur -= angleDiff - DEGTORAD(25.0f); m_fRotationDest -= angleDiff - DEGTORAD(25.0f); } } bool CPlayerPed::FindNextWeaponLockOnTarget(CEntity *previousTarget, bool lookToLeft) { CEntity *nextTarget = nil; float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange; // nextTarget = nil; // duplicate float lastCloseness = -10000.0f; // CGeneral::GetATanOfXY(GetForward().x, GetForward().y); // unused CVector distVec = previousTarget->GetPosition() - GetPosition(); float referenceBeta = CGeneral::GetATanOfXY(distVec.x, distVec.y); for (int h = CPools::GetPedPool()->GetSize() - 1; h >= 0; h--) { CPed *pedToCheck = CPools::GetPedPool()->GetSlot(h); if (pedToCheck) { if (pedToCheck != this && pedToCheck != previousTarget) { if (!pedToCheck->DyingOrDead() #ifndef AIMING_VEHICLE_OCCUPANTS // Mobile thing && (!pedToCheck->bInVehicle || (pedToCheck->m_pMyVehicle && pedToCheck->m_pMyVehicle->IsBike())) #endif && pedToCheck->m_leader != this && !pedToCheck->bNeverEverTargetThisPed && OurPedCanSeeThisOne(pedToCheck) && CanIKReachThisTarget(pedToCheck->GetPosition(), GetWeapon(), true)) { EvaluateNeighbouringTarget(pedToCheck, &nextTarget, &lastCloseness, weaponRange, referenceBeta, lookToLeft, IsThisPedAnAimingPriority(pedToCheck)); } } } } for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) { CObject *obj = CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]); if (obj && !obj->bHasBeenDamaged && CanIKReachThisTarget(obj->GetPosition(), GetWeapon(), true)) EvaluateNeighbouringTarget(obj, &nextTarget, &lastCloseness, weaponRange, referenceBeta, lookToLeft, true); } if (!nextTarget) return false; SetWeaponLockOnTarget(nextTarget); bDontAllowWeaponChange = true; SetPointGunAt(nextTarget); return true; } bool CPlayerPed::FindWeaponLockOnTarget(void) { CEntity *nextTarget = nil; float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange; if (m_pPointGunAt) { CVector distVec = m_pPointGunAt->GetPosition() - GetPosition(); if (distVec.Magnitude2D() > weaponRange) { SetWeaponLockOnTarget(nil); return false; } else { return true; } } // nextTarget = nil; // duplicate float lastCloseness = -10000.0f; float referenceBeta = CGeneral::GetATanOfXY(GetForward().x, GetForward().y); for (int h = CPools::GetPedPool()->GetSize() - 1; h >= 0; h--) { CPed *pedToCheck = CPools::GetPedPool()->GetSlot(h); if (pedToCheck) { if (pedToCheck != this) { if (!pedToCheck->DyingOrDead() #ifndef AIMING_VEHICLE_OCCUPANTS // Mobile thing && (!pedToCheck->bInVehicle || (pedToCheck->m_pMyVehicle && pedToCheck->m_pMyVehicle->IsBike())) #endif && pedToCheck->m_leader != this && !pedToCheck->bNeverEverTargetThisPed && OurPedCanSeeThisOne(pedToCheck) && CanIKReachThisTarget(pedToCheck->GetPosition(), GetWeapon(), true)) { EvaluateTarget(pedToCheck, &nextTarget, &lastCloseness, weaponRange, referenceBeta, IsThisPedAnAimingPriority(pedToCheck)); } } } } for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) { CObject *obj = CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]); if (obj && !obj->bHasBeenDamaged && CanIKReachThisTarget(obj->GetPosition(), GetWeapon(), true)) EvaluateTarget(obj, &nextTarget, &lastCloseness, weaponRange, referenceBeta, true); } if (!nextTarget) return false; SetWeaponLockOnTarget(nextTarget); bDontAllowWeaponChange = true; SetPointGunAt(nextTarget); Say(SOUND_PED_AIMING); return true; } void CPlayerPed::ProcessAnimGroups(void) { AssocGroupId groupToSet; //#ifdef PC_PLAYER_CONTROLS #if 0 // chainsaw anims missing in LCS if ((m_fWalkAngle <= -DEGTORAD(50.0f) || m_fWalkAngle >= DEGTORAD(50.0f)) && TheCamera.Cams[TheCamera.ActiveCam].Using3rdPersonMouseCam() && CanStrafeOrMouseControl()) { if (m_fWalkAngle >= -DEGTORAD(130.0f) && m_fWalkAngle <= DEGTORAD(130.0f)) { if (m_fWalkAngle > 0.0f) { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) groupToSet = ASSOCGRP_ROCKETLEFT; else if (GetWeapon()->m_eWeaponType == WEAPONTYPE_CHAINSAW || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER || GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN) groupToSet = ASSOCGRP_CHAINSAWLEFT; else groupToSet = ASSOCGRP_PLAYERLEFT; } else { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) groupToSet = ASSOCGRP_ROCKETRIGHT; else if (GetWeapon()->m_eWeaponType == WEAPONTYPE_CHAINSAW || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER || GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN) groupToSet = ASSOCGRP_CHAINSAWRIGHT; else groupToSet = ASSOCGRP_PLAYERRIGHT; } } else { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) groupToSet = ASSOCGRP_ROCKETBACK; else if (GetWeapon()->m_eWeaponType == WEAPONTYPE_CHAINSAW || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER || GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN) groupToSet = ASSOCGRP_CHAINSAWBACK; else groupToSet = ASSOCGRP_PLAYERBACK; } } else #endif { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) { groupToSet = ASSOCGRP_PLAYERROCKET; } else { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT || GetWeapon()->m_eWeaponType == WEAPONTYPE_MACHETE) groupToSet = ASSOCGRP_PLAYERBBBAT; else if (GetWeapon()->m_eWeaponType == WEAPONTYPE_CHAINSAW || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER || GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN) groupToSet = ASSOCGRP_PLAYERCHAINSAW; else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_COLT45 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UZI // I hope this is a inlined function... && GetWeapon()->m_eWeaponType != WEAPONTYPE_PYTHON && GetWeapon()->m_eWeaponType != WEAPONTYPE_TEC9 && GetWeapon()->m_eWeaponType != WEAPONTYPE_SILENCED_INGRAM && GetWeapon()->m_eWeaponType != WEAPONTYPE_MP5 && GetWeapon()->m_eWeaponType != WEAPONTYPE_GOLFCLUB && GetWeapon()->m_eWeaponType != WEAPONTYPE_KATANA && GetWeapon()->m_eWeaponType != WEAPONTYPE_CAMERA) { if (!GetWeapon()->IsType2Handed()) { groupToSet = ASSOCGRP_PLAYER; } else { groupToSet = ASSOCGRP_PLAYER2ARMED; } } else { groupToSet = ASSOCGRP_PLAYER1ARMED; } } } if (m_animGroup != groupToSet) { m_animGroup = groupToSet; ReApplyMoveAnims(); } } void CPlayerPed::ProcessPlayerWeapon(CPad *padUsed) { CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); if (m_bHasLockOnTarget && !m_pPointGunAt) { TheCamera.ClearPlayerWeaponMode(); CWeaponEffects::ClearCrossHair(); ClearPointGunAt(); } if (padUsed->DuckJustDown() && !bIsDucking && m_nMoveState != PEDMOVE_SPRINT) { bCrouchWhenShooting = true; SetDuck(60000, true); } else if (bIsDucking && (padUsed->DuckJustDown() || m_nMoveState == PEDMOVE_SPRINT || padUsed->GetSprint() || padUsed->JumpJustDown() || padUsed->ExitVehicleJustDown())) { ClearDuck(true); bCrouchWhenShooting = false; } if(weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM)) m_wepAccuracy = 95; else m_wepAccuracy = 100; if (!m_pFire) { eWeaponType weapon = GetWeapon()->m_eWeaponType; if (weapon == WEAPONTYPE_ROCKETLAUNCHER || weapon == WEAPONTYPE_SNIPERRIFLE || weapon == WEAPONTYPE_LASERSCOPE || weapon == WEAPONTYPE_M4 || weapon == WEAPONTYPE_RUGER || weapon == WEAPONTYPE_M60 || weapon == WEAPONTYPE_CAMERA) { if (padUsed->TargetJustDown() || TheCamera.m_bJustJumpedOutOf1stPersonBecauseOfTarget) { #ifdef FREE_CAM if (CCamera::bFreeCam && TheCamera.Cams[0].Using3rdPersonMouseCam()) { m_fRotationCur = CGeneral::LimitRadianAngle(-TheCamera.Orientation); SetHeading(m_fRotationCur); } #endif if (weapon == WEAPONTYPE_ROCKETLAUNCHER) TheCamera.SetNewPlayerWeaponMode(CCam::MODE_ROCKETLAUNCHER, 0, 0); else if (weapon == WEAPONTYPE_SNIPERRIFLE || weapon == WEAPONTYPE_LASERSCOPE) TheCamera.SetNewPlayerWeaponMode(CCam::MODE_SNIPER, 0, 0); else if (weapon == WEAPONTYPE_CAMERA) TheCamera.SetNewPlayerWeaponMode(CCam::MODE_CAMERA, 0, 0); else TheCamera.SetNewPlayerWeaponMode(CCam::MODE_M16_1STPERSON, 0, 0); m_fMoveSpeed = 0.0f; CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_IDLE, 1000.0f); SetPedState(PED_SNIPER_MODE); return; } if (!TheCamera.Using1stPersonWeaponMode()) if (weapon == WEAPONTYPE_ROCKETLAUNCHER || weapon == WEAPONTYPE_SNIPERRIFLE || weapon == WEAPONTYPE_LASERSCOPE || weapon == WEAPONTYPE_CAMERA) return; } } if (padUsed->GetWeapon() && m_nMoveState != PEDMOVE_SPRINT) { if (m_nSelectedWepSlot == m_currentWeapon) { if (m_pPointGunAt) { if (m_nPedState == PED_ATTACK) { m_fAttackButtonCounter *= Pow(0.94f, CTimer::GetTimeStep()); } else { m_fAttackButtonCounter = 0.0f; } SetAttack(m_pPointGunAt); } else { if (m_nPedState == PED_ATTACK) { if (padUsed->WeaponJustDown()) { m_bHaveTargetSelected = true; } else if (!m_bHaveTargetSelected) { m_fAttackButtonCounter += CTimer::GetTimeStepNonClipped(); } } else { m_fAttackButtonCounter = 0.0f; m_bHaveTargetSelected = false; } if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && GetWeapon()->m_eWeaponType != WEAPONTYPE_BRASSKNUCKLE && !weaponInfo->IsFlagSet(WEAPONFLAG_FIGHTMODE)) { if (GetWeapon()->m_eWeaponType != WEAPONTYPE_DETONATOR && GetWeapon()->m_eWeaponType != WEAPONTYPE_DETONATOR_GRENADE || padUsed->WeaponJustDown()) SetAttack(nil); } else if (padUsed->WeaponJustDown()) { if (m_fMoveSpeed < 1.0f || m_nPedState == PED_FIGHT) StartFightAttack(padUsed->GetWeapon()); else SetAttack(nil); } } } } else { m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; if (m_nPedState == PED_ATTACK) { m_bHaveTargetSelected = true; bIsAttacking = false; } } #ifdef FREE_CAM static int8 changedHeadingRate = 0; static int8 pointedGun = 0; if (changedHeadingRate == 2) changedHeadingRate = 1; if (pointedGun == 2) pointedGun = 1; // Rotate player/arm when shooting. We don't have auto-rotation anymore if (CCamera::m_bUseMouse3rdPerson && CCamera::bFreeCam && m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT) { #define CAN_AIM_WITH_ARM (weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM) && !bIsDucking && !bCrouchWhenShooting) // Weapons except throwable and melee ones if (weaponInfo->m_nWeaponSlot > 2) { if ((padUsed->GetTarget() && CAN_AIM_WITH_ARM) || padUsed->GetWeapon()) { float limitedCam = CGeneral::LimitRadianAngle(-TheCamera.Orientation); // On this one we can rotate arm. if (CAN_AIM_WITH_ARM) { if (!padUsed->GetWeapon()) { // making this State != ATTACK still stops it after attack. Re-start it immediately! SetPointGunAt(nil); bIsPointingGunAt = false; // to not stop after attack } pointedGun = 2; SetLookFlag(limitedCam, true); SetAimFlag(limitedCam); SetLookTimer(INT32_MAX); // removing this makes head move for real, but I experinced some bugs. } else { m_fRotationDest = limitedCam; changedHeadingRate = 2; m_headingRate = 12.5f; // Anim. fix for shotgun, ak47 and m16 (we must finish rot. it quickly) if (weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM) && padUsed->WeaponJustDown()) { m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); float limitedRotDest = m_fRotationDest; if (m_fRotationCur - PI > m_fRotationDest) { limitedRotDest += 2 * PI; } else if (PI + m_fRotationCur < m_fRotationDest) { limitedRotDest -= 2 * PI; } m_fRotationCur += (limitedRotDest - m_fRotationCur) / 2; } } } } #undef CAN_AIM_WITH_ARM } if (changedHeadingRate == 1) { changedHeadingRate = 0; RestoreHeadingRate(); } if (pointedGun == 1 && m_nPedState != PED_ATTACK) { pointedGun = 0; ClearPointGunAt(); } #endif if (padUsed->GetTarget() && m_nSelectedWepSlot == m_currentWeapon && m_nMoveState != PEDMOVE_SPRINT && !TheCamera.Using1stPersonWeaponMode() && weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM)) { if (m_pPointGunAt) { // what?? if (!m_pPointGunAt #ifdef FREE_CAM || (!CCamera::bFreeCam && CCamera::m_bUseMouse3rdPerson) #else || CCamera::m_bUseMouse3rdPerson #endif ) { ClearWeaponTarget(); return; } if (m_pPointGunAt->IsPed() && ( #ifndef AIMING_VEHICLE_OCCUPANTS (((CPed*)m_pPointGunAt)->bInVehicle && (!((CPed*)m_pPointGunAt)->m_pMyVehicle || !((CPed*)m_pPointGunAt)->m_pMyVehicle->IsBike())) || #endif !CGame::nastyGame && ((CPed*)m_pPointGunAt)->DyingOrDead())) { ClearWeaponTarget(); return; } if (CPlayerPed::DoesTargetHaveToBeBroken(m_pPointGunAt->GetPosition(), GetWeapon()) || (!bCanPointGunAtTarget && !weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM))) { // this line isn't on Mobile, idk why ClearWeaponTarget(); return; } if (m_pPointGunAt) { RotatePlayerToTrackTarget(); } if (m_pPointGunAt) { if (padUsed->ShiftTargetLeftJustDown()) FindNextWeaponLockOnTarget(m_pPointGunAt, true); if (padUsed->ShiftTargetRightJustDown()) FindNextWeaponLockOnTarget(m_pPointGunAt, false); } TheCamera.SetNewPlayerWeaponMode(CCam::MODE_SYPHON, 0, 0); TheCamera.UpdateAimingCoors(m_pPointGunAt->GetPosition()); } else if (!CCamera::m_bUseMouse3rdPerson) { if (padUsed->TargetJustDown() || TheCamera.m_bJustJumpedOutOf1stPersonBecauseOfTarget) FindWeaponLockOnTarget(); } } else if (m_pPointGunAt) { ClearWeaponTarget(); } if (m_pPointGunAt) { CVector markPos; if (m_pPointGunAt->IsPed()) { ((CPed*)m_pPointGunAt)->m_pedIK.GetComponentPosition(markPos, PED_MID); } else { markPos = m_pPointGunAt->GetPosition(); } if (bCanPointGunAtTarget) { CWeaponEffects::MarkTarget(markPos, 64, 0, 0, 255, 0.8f); } else { CWeaponEffects::MarkTarget(markPos, 64, 32, 0, 255, 0.8f); } } m_bHasLockOnTarget = m_pPointGunAt != nil; } bool CPlayerPed::MovementDisabledBecauseOfTargeting(void) { return m_pPointGunAt && !CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM); } void CPlayerPed::PlayerControlZelda(CPad *padUsed) { float smoothSprayRate = DoWeaponSmoothSpray(); float camOrientation = TheCamera.Orientation; float leftRight = padUsed->GetPedWalkLeftRight(); float upDown = padUsed->GetPedWalkUpDown(); float padMoveInGameUnit; bool smoothSprayWithoutMove = false; if (MovementDisabledBecauseOfTargeting()) { upDown = 0.0f; leftRight = 0.0f; } if (smoothSprayRate > 0.0f && upDown > 0.0f) { padMoveInGameUnit = 0.0f; smoothSprayWithoutMove = true; } else { padMoveInGameUnit = CVector2D(leftRight, upDown).Magnitude() / PAD_MOVE_TO_GAME_WORLD_MOVE; } if (padMoveInGameUnit > 0.0f || smoothSprayWithoutMove) { float padHeading = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); float neededTurn = CGeneral::LimitRadianAngle(padHeading - camOrientation); if (smoothSprayRate > 0.0f) { m_fRotationDest = m_fRotationCur - leftRight / 128.0f * smoothSprayRate * CTimer::GetTimeStep(); } else { m_fRotationDest = neededTurn; } float maxAcc = 0.07f * CTimer::GetTimeStep(); m_fMoveSpeed = Min(padMoveInGameUnit, m_fMoveSpeed + maxAcc); } else { m_fMoveSpeed = 0.0f; } if (m_nPedState == PED_JUMP) { if (bIsInTheAir) { if (bUsesCollision && !bHitSteepSlope && (!bHitSomethingLastFrame || m_vecDamageNormal.z > 0.6f) && m_fDistanceTravelled < CTimer::GetTimeStepInSeconds() && m_vecMoveSpeed.MagnitudeSqr() < 0.01f) { float angleSin = Sin(m_fRotationCur); // originally sin(DEGTORAD(RADTODEG(m_fRotationCur))) o_O float angleCos = Cos(m_fRotationCur); ApplyMoveForce(-angleSin * 3.0f, 3.0f * angleCos, 0.05f); } } else if (bIsLanding) { m_fMoveSpeed = 0.0f; } } if (m_nPedState == PED_ANSWER_MOBILE) { SetRealMoveAnim(); return; } if (!CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_HEAVY) && padUsed->GetSprint()) { if (!m_pCurrentPhysSurface || (!m_pCurrentPhysSurface->bInfiniteMass || m_pCurrentPhysSurface->m_phy_flagA08)) m_nMoveState = PEDMOVE_SPRINT; } if (m_nPedState != PED_FIGHT) SetRealMoveAnim(); if (!bIsInTheAir && !CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_HEAVY) && padUsed->JumpJustDown() && m_nPedState != PED_JUMP) { ClearAttack(); ClearWeaponTarget(); if (m_nEvadeAmount != 0 && m_pEvadingFrom) { SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1); m_nEvadeAmount = 0; m_pEvadingFrom = nil; } else { SetJump(); } } PlayIdleAnimations(padUsed); } // Finds nice positions for peds to duck and shoot player. And it's inside PlayerPed, this is treachery! void CPlayerPed::FindNewAttackPoints(void) { for (int i=0; im_nPedState == PED_DEAD || safeNeighbour->m_pedInObjective != this) { m_vecSafePos[i].x = 0.0f; m_vecSafePos[i].y = 0.0f; m_vecSafePos[i].z = 0.0f; m_pPedAtSafePos[i] = nil; } } else { m_vecSafePos[i].x = 0.0f; m_vecSafePos[i].y = 0.0f; m_vecSafePos[i].z = 0.0f; } } CEntity *entities[6]; int16 numEnts; float rightMult, fwdMult; CWorld::FindObjectsInRange(GetPosition(), 18.0f, true, &numEnts, 6, entities, true, false, false, true, false); for (int i = 0; i < numEnts; ++i) { CEntity *ent = entities[i]; int16 mi = ent->GetModelIndex(); if (!ent->IsObject() || ((CObject*)ent)->m_nSpecialCollisionResponseCases == COLLRESPONSE_FENCEPART) if (!IsTreeModel(mi)) continue; if (mi == MI_TRAFFICLIGHTS) { rightMult = 2.957f; fwdMult = 0.147f; } else if (mi == MI_SINGLESTREETLIGHTS1) { rightMult = 0.744f; fwdMult = 0.0f; } else if (mi == MI_SINGLESTREETLIGHTS2) { rightMult = 0.043f; fwdMult = 0.0f; } else if (mi == MI_SINGLESTREETLIGHTS3) { rightMult = 1.143f; fwdMult = 0.145f; } else if (mi == MI_DOUBLESTREETLIGHTS) { rightMult = 0.744f; fwdMult = 0.0f; } else if (mi == MI_LAMPPOST1) { rightMult = 0.744f; fwdMult = 0.0f; } else if (mi == MI_TRAFFICLIGHT01) { rightMult = 2.957f; fwdMult = 0.147f; } else if (mi == MI_LITTLEHA_POLICE) { rightMult = 0.0f; fwdMult = 0.0f; } else if (mi == MI_PARKBENCH) { rightMult = 0.0f; fwdMult = 0.0f; } else if (IsTreeModel(mi)) { rightMult = 0.0f; fwdMult = 0.0f; } else continue; CVector entAttackPoint(rightMult * ent->GetRight().x + fwdMult * ent->GetForward().x + ent->GetPosition().x, rightMult * ent->GetRight().y + fwdMult * ent->GetForward().y + ent->GetPosition().y, ent->GetPosition().z); CVector attackerPos = GetPosition() - entAttackPoint; // for now it's dist, not attackerPos CVector dirTowardsUs = attackerPos; dirTowardsUs.Normalise(); dirTowardsUs *= 2.0f; attackerPos = entAttackPoint - dirTowardsUs; // to make cop farther from us CPedPlacement::FindZCoorForPed(&attackerPos); if (CPedPlacement::IsPositionClearForPed(attackerPos)) m_vecSafePos[i] = attackerPos; } } void CPlayerPed::ProcessControl(void) { // Mobile has some debug/abandoned cheat thing in here: "gbFrankenTommy" if (m_nEvadeAmount != 0) --m_nEvadeAmount; if (m_nEvadeAmount == 0) m_pEvadingFrom = nil; if (m_pWanted->GetWantedLevel() > 0) FindNewAttackPoints(); UpdateMeleeAttackers(); if (m_pCurrentPhysSurface && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) { bTryingToReachDryLand = true; } else if (!(((uint8)CTimer::GetFrameCounter() + m_randomSeed) & 0xF)) { CVehicle *nearVeh = (CVehicle*)CWorld::TestSphereAgainstWorld(GetPosition(), 7.0f, nil, false, true, false, false, false, false); if (nearVeh && nearVeh->IsBoat()) bTryingToReachDryLand = true; else bTryingToReachDryLand = false; } if (m_nFadeDrunkenness) { if (m_nDrunkenness - 1 > 0) { --m_nDrunkenness; } else { m_nDrunkenness = 0; CMBlur::ClearDrunkBlur(); m_nFadeDrunkenness = 0; } } if (m_nDrunkenness != 0) { CMBlur::SetDrunkBlur(m_nDrunkenness / 255.f); } CPed::ProcessControl(); SetNearbyPedsToInteractWithPlayer(); if (bWasPostponed) return; CPad *padUsed = GetPadFromPlayer(this); m_pWanted->Update(); PruneReferences(); if (GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN) { CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); CAnimBlendAssociation *fireAnim = RpAnimBlendClumpGetAssociation(GetClump(), GetPrimaryFireAnim(weaponInfo)); if (fireAnim && fireAnim->currentTime - fireAnim->timeStep < weaponInfo->m_fAnimLoopEnd && m_nPedState == PED_ATTACK) { if (m_fGunSpinSpeed < 0.45f) { m_fGunSpinSpeed = Min(0.45f, m_fGunSpinSpeed + CTimer::GetTimeStep() * 0.013f); } if (padUsed->GetWeapon() && GetWeapon()->m_nAmmoTotal > 0 && fireAnim->currentTime >= weaponInfo->m_fAnimLoopStart) { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_MINIGUN_ATTACK, 0.0f); } else { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_MINIGUN_2, m_fGunSpinSpeed * (20.f / 9)); } } else { if (m_fGunSpinSpeed > 0.0f) { if (m_fGunSpinSpeed >= 0.45f) { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_MINIGUN_3, 0.0f); } m_fGunSpinSpeed = Max(0.0f, m_fGunSpinSpeed - CTimer::GetTimeStep() * 0.003f); } } } if (GetWeapon()->m_eWeaponType == WEAPONTYPE_CHAINSAW && m_nPedState != PED_ATTACK && !bInVehicle) { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_CHAINSAW_IDLE, 0.0f); } if (m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT) RestoreSprintEnergy(1.0f); else if (m_nMoveState == PEDMOVE_RUN) RestoreSprintEnergy(0.3f); if (m_nPedState == PED_DEAD) { ClearWeaponTarget(); return; } if (m_nPedState == PED_DIE) { ClearWeaponTarget(); if (CTimer::GetTimeInMilliseconds() > m_bloodyFootprintCountOrDeathTime + 4000) SetDead(); return; } if (m_nPedState == PED_DRIVING && m_objective != OBJECTIVE_LEAVE_CAR) { if (!CReplay::IsPlayingBack() || m_pMyVehicle) { if (m_pMyVehicle->IsCar() && ((CAutomobile*)m_pMyVehicle)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) == DOOR_STATUS_SWINGING) { CAnimBlendAssociation *rollDoorAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LHS); if (m_pMyVehicle->m_nGettingOutFlags & CAR_DOOR_FLAG_LF || rollDoorAssoc || (rollDoorAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LO_LHS))) { if (rollDoorAssoc) m_pMyVehicle->ProcessOpenDoor(CAR_DOOR_LF, ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LHS, rollDoorAssoc->currentTime); } else { // These comparisons are wrong, they return uint16 if (padUsed && (padUsed->GetAccelerate() != 0.0f || padUsed->GetSteeringLeftRight() != 0.0f || padUsed->GetBrake() != 0.0f)) { if (rollDoorAssoc) m_pMyVehicle->ProcessOpenDoor(CAR_DOOR_LF, ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LHS, rollDoorAssoc->currentTime); } else { m_pMyVehicle->m_nGettingOutFlags |= CAR_DOOR_FLAG_LF; if (m_pMyVehicle->bLowVehicle) rollDoorAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LO_LHS); else rollDoorAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LHS); rollDoorAssoc->SetFinishCallback(PedAnimDoorCloseRollingCB, this); } } } } return; } if (m_objective == OBJECTIVE_NONE) m_nMoveState = PEDMOVE_STILL; if (bIsLanding) RunningLand(padUsed); if (padUsed && padUsed->WeaponJustDown() && !TheCamera.Using1stPersonWeaponMode()) { // ...Really? eWeaponType playerWeapon = FindPlayerPed()->GetWeapon()->m_eWeaponType; if (playerWeapon == WEAPONTYPE_SNIPERRIFLE || playerWeapon == WEAPONTYPE_LASERSCOPE) { DMAudio.PlayFrontEndSound(SOUND_WEAPON_SNIPER_SHOT_NO_ZOOM, 0); } else if (playerWeapon == WEAPONTYPE_ROCKETLAUNCHER) { DMAudio.PlayFrontEndSound(SOUND_WEAPON_ROCKET_SHOT_NO_ZOOM, 0); } } switch (m_nPedState) { case PED_NONE: case PED_IDLE: case PED_FLEE_POS: case PED_FLEE_ENTITY: case PED_ATTACK: case PED_FIGHT: case PED_AIM_GUN: case PED_ANSWER_MOBILE: if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_BLOCK) && !m_attachedTo) { if (TheCamera.Using1stPersonWeaponMode()) { if (padUsed) PlayerControlSniper(padUsed); } else if (TheCamera.Cams[0].Using3rdPersonMouseCam() #ifdef FREE_CAM && !CCamera::bFreeCam #endif ) { if (padUsed) PlayerControl1stPersonRunAround(padUsed); } else if (m_nPedState == PED_FIGHT) { if (padUsed) PlayerControlFighter(padUsed); } else if (padUsed) { PlayerControlZelda(padUsed); } } if (IsPedInControl() && m_nPedState != PED_ANSWER_MOBILE && padUsed) ProcessPlayerWeapon(padUsed); break; case PED_SEEK_ENTITY: m_vecSeekPos = m_pSeekTarget->GetPosition(); // fall through case PED_SEEK_POS: switch (m_nMoveState) { case PEDMOVE_WALK: m_fMoveSpeed = 1.0f; break; case PEDMOVE_RUN: m_fMoveSpeed = 1.8f; break; case PEDMOVE_SPRINT: m_fMoveSpeed = 2.5f; break; default: m_fMoveSpeed = 0.0f; break; } SetRealMoveAnim(); if (Seek()) { RestorePreviousState(); SetMoveState(PEDMOVE_STILL); } break; case PED_SNIPER_MODE: if (GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || GetWeapon()->m_eWeaponType == WEAPONTYPE_LASERSCOPE) { if (padUsed) PlayerControlSniper(padUsed); } else if (padUsed) { PlayerControlM16(padUsed); } break; case PED_SEEK_CAR: case PED_SEEK_IN_BOAT: if (bVehEnterDoorIsBlocked || bKindaStayInSamePlace) { m_fMoveSpeed = 0.0f; } else { m_fMoveSpeed = Min(2.0f, 2.0f * (m_vecSeekPos - GetPosition()).Magnitude2D()); } if (padUsed && !padUsed->ArePlayerControlsDisabled()) { if (padUsed->GetTarget() || padUsed->GetLeftStickXJustDown() || padUsed->GetLeftStickYJustDown() || padUsed->GetDPadUpJustDown() || padUsed->GetDPadDownJustDown() || padUsed->GetDPadLeftJustDown() || padUsed->GetDPadRightJustDown()) { RestorePreviousState(); if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { RestorePreviousObjective(); } } } if (padUsed && padUsed->GetSprint()) m_nMoveState = PEDMOVE_SPRINT; SetRealMoveAnim(); break; case PED_JUMP: if (padUsed) PlayerControlZelda(padUsed); if (bIsLanding) break; // This has been added later it seems return; case PED_FALL: case PED_GETUP: case PED_ENTER_TRAIN: case PED_EXIT_TRAIN: case PED_CARJACK: case PED_DRAG_FROM_CAR: case PED_ENTER_CAR: case PED_STEAL_CAR: case PED_EXIT_CAR: ClearWeaponTarget(); break; case PED_ARRESTED: if (m_nLastPedState == PED_DRAG_FROM_CAR && m_pVehicleAnim) BeingDraggedFromCar(); break; default: break; } if (padUsed && IsPedShootable() && m_nPedState != PED_ANSWER_MOBILE && m_nLastPedState != PED_ANSWER_MOBILE) { ProcessWeaponSwitch(padUsed); GetWeapon()->Update(m_audioEntityId, this); } ProcessAnimGroups(); if (padUsed) { if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FOLLOWPED && TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_BEHIND) { m_lookTimer = 0; float camAngle = CGeneral::LimitRadianAngle(TheCamera.Cams[TheCamera.ActiveCam].Front.Heading()); float angleBetweenPlayerAndCam = Abs(camAngle - m_fRotationCur); if (m_nPedState != PED_ATTACK && angleBetweenPlayerAndCam > DEGTORAD(30.0f) && angleBetweenPlayerAndCam < DEGTORAD(330.0f)) { if (angleBetweenPlayerAndCam > DEGTORAD(150.0f) && angleBetweenPlayerAndCam < DEGTORAD(210.0f)) { float rightTurnAngle = CGeneral::LimitRadianAngle(m_fRotationCur - DEGTORAD(150.0f)); float leftTurnAngle = CGeneral::LimitRadianAngle(DEGTORAD(150.0f) + m_fRotationCur); if (m_fLookDirection == 999999.0f || bIsDucking) camAngle = rightTurnAngle; else if (Abs(rightTurnAngle - m_fLookDirection) < Abs(leftTurnAngle - m_fLookDirection)) camAngle = rightTurnAngle; else camAngle = leftTurnAngle; } SetLookFlag(camAngle, true); SetLookTimer(CTimer::GetTimeStepInMilliseconds() * 5.0f); } else { ClearLookFlag(); } } } if (m_nMoveState == PEDMOVE_SPRINT && bIsLooking) { ClearLookFlag(); SetLookTimer(250); } if (m_vecMoveSpeed.Magnitude2D() < 0.1f) { if (m_nSpeedTimer) { if (CTimer::GetTimeInMilliseconds() > m_nSpeedTimer) m_bSpeedTimerFlag = true; } else { m_nSpeedTimer = CTimer::GetTimeInMilliseconds() + 500; } } else { m_nSpeedTimer = 0; m_bSpeedTimerFlag = false; } if (bDontAllowWeaponChange && FindPlayerPed() == this) { if (!CPad::GetPad(0)->GetTarget()) bDontAllowWeaponChange = false; } if (m_nPedState != PED_SNIPER_MODE && (GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING || m_nPedState == PED_ATTACK)) m_nPadDownPressedInMilliseconds = CTimer::GetTimeInMilliseconds(); if (!bIsVisible) UpdateRpHAnim(); } bool CPlayerPed::DoesPlayerWantNewWeapon(eWeaponType weapon, bool onlyIfSlotIsEmpty) { // GetPadFromPlayer(); // unused uint32 slot = CWeaponInfo::GetWeaponInfo(weapon)->m_nWeaponSlot; if (!HasWeaponSlot(slot) || GetWeapon(slot).m_eWeaponType == weapon) return true; if (onlyIfSlotIsEmpty) return false; // Check if he's using that slot right now. return m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN || slot != m_currentWeapon; } void CPlayerPed::PlayIdleAnimations(CPad *padUsed) { CAnimBlendAssociation* assoc; if (TheCamera.m_WideScreenOn || bIsDucking) return; struct animAndGroup { AnimationId animId; AssocGroupId groupId; }; const animAndGroup idleAnims[] = { {ANIM_PLAYER_IDLE1, ASSOCGRP_PLAYER_IDLE}, {ANIM_PLAYER_IDLE2, ASSOCGRP_PLAYER_IDLE}, {ANIM_PLAYER_IDLE3, ASSOCGRP_PLAYER_IDLE}, {ANIM_PLAYER_IDLE4, ASSOCGRP_PLAYER_IDLE}, {ANIM_STD_XPRESS_SCRATCH, ASSOCGRP_STD}, }; static int32 lastTime = 0; static int32 lastAnim = -1; bool hasIdleAnim = false; CAnimBlock *idleAnimBlock = CAnimManager::GetAnimationBlock(idleAnimBlockIndex); uint32 sinceLastInput = padUsed->InputHowLongAgo(); if (sinceLastInput <= 30000) { if (idleAnimBlock->isLoaded) { for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { if (assoc->flags & ASSOC_IDLE) { hasIdleAnim = true; assoc->blendDelta = -8.0f; } } if (!hasIdleAnim) CStreaming::RemoveAnim(idleAnimBlockIndex); } else { lastTime = 0; } } else { CStreaming::RequestAnim(idleAnimBlockIndex, STREAMFLAGS_DONT_REMOVE); if (idleAnimBlock->isLoaded) { for(CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { int firstIdle = idleAnimBlock->firstIndex; int index = assoc->hierarchy - CAnimManager::GetAnimation(0); if (index >= firstIdle && index < firstIdle + idleAnimBlock->numAnims) { hasIdleAnim = true; break; } } if (!hasIdleAnim && !bIsLooking && !bIsRestoringLook && sinceLastInput - lastTime > 25000) { int anim; do anim = CGeneral::GetRandomNumberInRange(0, ARRAY_SIZE(idleAnims)); while (lastAnim == anim); assoc = CAnimManager::BlendAnimation(GetClump(), idleAnims[anim].groupId, idleAnims[anim].animId, 8.0f); assoc->flags |= ASSOC_IDLE; lastAnim = anim; lastTime = sinceLastInput; } } } } void CPlayerPed::SetNearbyPedsToInteractWithPlayer(void) { if (CGame::noProstitutes) return; for (int i = 0; i < m_numNearPeds; ++i) { CPed *nearPed = m_nearPeds[i]; if (nearPed && nearPed->m_objectiveTimer < CTimer::GetTimeInMilliseconds() && !CTheScripts::IsPlayerOnAMission()) { int mi = nearPed->GetModelIndex(); if (CPopulation::CanSolicitPlayerOnFoot(mi)) { CVector distToMe = nearPed->GetPosition() - GetPosition(); CVector dirToMe = GetPosition() - nearPed->GetPosition(); dirToMe.Normalise(); if (DotProduct(dirToMe, nearPed->GetForward()) > 0.707 && DotProduct(GetForward(), nearPed->GetForward()) < -0.707 // those are double && distToMe.MagnitudeSqr() < 9.0f && nearPed->m_objective == OBJECTIVE_NONE) { nearPed->SetObjective(OBJECTIVE_SOLICIT_FOOT, this); nearPed->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; nearPed->Say(SOUND_PED_SOLICIT); } } else if (CPopulation::CanSolicitPlayerInCar(mi)) { if (InVehicle() && m_pMyVehicle->IsVehicleNormal()) { if (m_pMyVehicle->IsCar()) { CVector distToVeh = nearPed->GetPosition() - m_pMyVehicle->GetPosition(); if (distToVeh.MagnitudeSqr() < 25.0f && m_pMyVehicle->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil) && nearPed->m_objective == OBJECTIVE_NONE) { nearPed->SetObjective(OBJECTIVE_SOLICIT_VEHICLE, m_pMyVehicle); } } } } } } } void CPlayerPed::UpdateMeleeAttackers(void) { CVector attackCoord; if (((CTimer::GetFrameCounter() + m_randomSeed + 7) & 3) == 0) { GetMeleeAttackCoords(attackCoord, m_nAttackDirToCheck, 2.0f); // Check if there is any vehicle/building inbetween us and m_nAttackDirToCheck. Peds will be able to attack us from those available directions. if (CWorld::GetIsLineOfSightClear(GetPosition(), attackCoord, true, true, false, true, false, false, false) && !CWorld::TestSphereAgainstWorld(attackCoord, 0.4f, m_pMeleeList[m_nAttackDirToCheck], true, true, false, true, false, false)) { if (m_pMeleeList[m_nAttackDirToCheck] == this) m_pMeleeList[m_nAttackDirToCheck] = nil; // mark it as available } else { m_pMeleeList[m_nAttackDirToCheck] = this; // slot not available. useful for m_bNoPosForMeleeAttack } if (++m_nAttackDirToCheck >= ARRAY_SIZE(m_pMeleeList)) m_nAttackDirToCheck = 0; } // 6 directions for (int i = 0; i < ARRAY_SIZE(m_pMeleeList); ++i) { CPed *victim = m_pMeleeList[i]; if (victim && victim != this) { if (victim->m_nPedState != PED_DEAD && victim->m_pedInObjective == this) { if (victim->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || victim->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || victim->m_objective == OBJECTIVE_KILL_CHAR_ON_BOAT) { GetMeleeAttackCoords(attackCoord, i, 2.0f); if ((attackCoord - GetPosition()).MagnitudeSqr() > 12.25f) m_pMeleeList[i] = nil; } else { m_pMeleeList[i] = nil; } } else { m_pMeleeList[i] = nil; } } } m_bNoPosForMeleeAttack = m_pMeleeList[0] == this && m_pMeleeList[1] == this && m_pMeleeList[2] == this #ifdef FIX_BUGS && m_pMeleeList[3] == this #endif && m_pMeleeList[4] == this && m_pMeleeList[5] == this; } void CPlayerPed::RemovePedFromMeleeList(CPed *ped) { int i = 0; for (; m_pMeleeList[i] != ped; i++) { if (i >= ARRAY_SIZE(m_pMeleeList)) return; } m_pMeleeList[i] = nil; ped->m_attackTimer = 0; } void CPlayerPed::GetMeleeAttackCoords(CVector& coords, int8 dir, float dist) { coords = GetPosition(); switch (dir) { case 0: coords.y += dist; break; case 1: coords.x += Sqrt(3.f / 4.f) * dist; coords.y += 0.5f * dist; break; case 2: coords.x += Sqrt(3.f / 4.f) * dist; coords.y -= 0.5f * dist; break; case 3: coords.y -= dist; break; case 4: coords.x -= Sqrt(3.f / 4.f) * dist; coords.y -= 0.5f * dist; break; case 5: coords.x -= Sqrt(3.f / 4.f) * dist; coords.y += 0.5f * dist; break; default: break; } } int32 CPlayerPed::FindMeleeAttackPoint(CPed *victim, CVector &dist, uint32 &endOfAttackOut) { endOfAttackOut = 0; bool thereIsAnEmptySlot = false; int dirToAttack = -1; for (int i = 0; i < ARRAY_SIZE(m_pMeleeList); i++) { CPed* pedAtThisDir = m_pMeleeList[i]; if (pedAtThisDir) { if (pedAtThisDir == victim) { dirToAttack = i; } else { if (pedAtThisDir->m_attackTimer > endOfAttackOut) endOfAttackOut = pedAtThisDir->m_attackTimer; } } else { thereIsAnEmptySlot = true; } } // We don't have victim ped in our melee list if (dirToAttack == -1 && thereIsAnEmptySlot) { float angle = Atan2(-dist.x, -dist.y); float adjustedAngle = angle + DEGTORAD(30.0f); if (adjustedAngle < 0.f) adjustedAngle += TWOPI; int wantedDir = Floor(adjustedAngle / DEGTORAD(60.0f)); // And we have another ped at the direction of victim ped, so store victim to next empty direction to it's real direction. (Bollocks) if (m_pMeleeList[wantedDir]) { int closestDirToPreferred = -99; int preferredDir = wantedDir; for (int i = 0; i < ARRAY_SIZE(m_pMeleeList); i++) { if (!m_pMeleeList[i]) { if (Abs(i - preferredDir) < Abs(closestDirToPreferred - preferredDir)) closestDirToPreferred = i; } } if (closestDirToPreferred > 0) dirToAttack = closestDirToPreferred; } else { // Luckily the direction of victim ped is already empty, good dirToAttack = wantedDir; } if (dirToAttack != -1) { m_pMeleeList[dirToAttack] = victim; victim->RegisterReference((CEntity**) &m_pMeleeList[dirToAttack]); if (endOfAttackOut > CTimer::GetTimeInMilliseconds()) victim->m_attackTimer = endOfAttackOut + CGeneral::GetRandomNumberInRange(1000, 2000); else victim->m_attackTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(500, 1000); } } return dirToAttack; } #ifdef COMPATIBLE_SAVES #define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); SkipSaveBuf(buf, sizeof(data)); #define CopyToBuf(buf, data) memcpy(buf, &data, sizeof(data)); SkipSaveBuf(buf, sizeof(data)); void CPlayerPed::Save(uint8*& buf) { CPed::Save(buf); SkipSaveBuf(buf, 16); CopyToBuf(buf, m_fMaxStamina); SkipSaveBuf(buf, 28); CopyToBuf(buf, m_nTargettableObjects[0]); CopyToBuf(buf, m_nTargettableObjects[1]); CopyToBuf(buf, m_nTargettableObjects[2]); CopyToBuf(buf, m_nTargettableObjects[3]); SkipSaveBuf(buf, 164); } void CPlayerPed::Load(uint8*& buf) { CPed::Load(buf); SkipSaveBuf(buf, 16); CopyFromBuf(buf, m_fMaxStamina); SkipSaveBuf(buf, 28); CopyFromBuf(buf, m_nTargettableObjects[0]); CopyFromBuf(buf, m_nTargettableObjects[1]); CopyFromBuf(buf, m_nTargettableObjects[2]); CopyFromBuf(buf, m_nTargettableObjects[3]); SkipSaveBuf(buf, 164); } #undef CopyFromBuf #undef CopyToBuf #endif