#include "common.h" #include "main.h" #include "RpAnimBlend.h" #include "AnimBlendClumpData.h" #include "AnimBlendAssociation.h" #include "Camera.h" #include "CarCtrl.h" #include "Darkel.h" #include "DMAudio.h" #include "FileMgr.h" #include "General.h" #include "Object.h" #include "Pad.h" #include "Particle.h" #include "Ped.h" #include "PlayerPed.h" #include "Stats.h" #include "TempColModels.h" #include "VisibilityPlugins.h" #include "Vehicle.h" #include "Automobile.h" #include "WaterLevel.h" #include "World.h" #include "Bike.h" #include "Glass.h" #include "SpecialFX.h" uint16 nPlayerInComboMove; RpClump* flyingClumpTemp; FightMove tFightMoves[NUM_FIGHTMOVES] = { /* { ANIM_STD_NUM, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_PUNCH, 0.2f, 8.f/30.f, 0.0f, 0.3f, 1.0f, HITLEVEL_HIGH, 1, 0 }, { ANIM_STD_FIGHT_IDLE, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_FIGHT_SHUFFLE_F, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_FIGHT_KNEE, 4.f/30.f, 0.2f, 0.0f, 0.6f, 1.0f, HITLEVEL_LOW, 2, 0 }, { ANIM_STD_FIGHT_LHOOK, 8.f/30.f, 10.f/30.f, 0.0f, 0.4f, 1.0f, HITLEVEL_HIGH, 3, 0 }, { ANIM_STD_FIGHT_JAB, 4.f/30.f, 0.2f, 0.0f, 0.7f, 1.0f, HITLEVEL_HIGH, 3, 0 }, { ANIM_STD_FIGHT_PUNCH, 4.f/30.f, 7.f/30.f, 10.f/30.f, 0.4f, 1.0f, HITLEVEL_HIGH, 1, 0 }, { ANIM_STD_FIGHT_LONGKICK, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_MEDIUM, 4, 0 }, { ANIM_STD_FIGHT_ROUNDHOUSE, 8.f/30.f, 10.f/30.f, 0.0f, 0.6f, 1.0f, HITLEVEL_MEDIUM, 4, 0 }, { ANIM_STD_FIGHT_KICK, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_HIGH, 2, 0 }, { ANIM_STD_FIGHT_HEAD, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_MEDIUM, 2, 0 }, { ANIM_STD_FIGHT_BKICK_L, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_LOW, 2, 0 }, { ANIM_STD_FIGHT_BKICK_L, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_LOW, 2, 0 }, { ANIM_STD_FIGHT_ELBOW_L, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_MEDIUM, 2, 0 }, { ANIM_STD_FIGHT_BKICK_R, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_MEDIUM, 2, 0 }, { ANIM_STD_FIGHT_ELBOW_R, 8.f/30.f, 10.f/30.f, 0.0f, 0.5f, 1.0f, HITLEVEL_HIGH, 2, 0 }, { ANIM_STD_KICKGROUND, 10.f/30.f, 14.f/30.f, 0.0f, 0.4f, 1.0f, HITLEVEL_GROUND, 1, 0 }, { ANIM_STD_HIT_FRONT, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_BACK, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_RIGHT, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_LEFT, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_BODYBLOW, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_CHEST, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_WALK, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_FLOOR, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_STD_HIT_BEHIND, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 }, { ANIM_ATTACK_1, 4.f/30.f, 7.f/30.f, 10.f/30.f, 0.4f, 1.0f, HITLEVEL_HIGH, 1, 0 }, { ANIM_ATTACK_2, 4.f/30.f, 7.f/30.f, 10.f/30.f, 0.4f, 1.0f, HITLEVEL_HIGH, 1, 0 }, { ANIM_ATTACK_3, 4.f / 30.f, 7.f / 30.f, 10.f / 30.f, 0.4f, 1.0f, HITLEVEL_HIGH, 1, 0 }, { ANIM_STD_FIGHT_2IDLE, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, HITLEVEL_NULL, 0, 0 } */ }; static PedOnGroundState CheckForPedsOnGroundToAttack(CPed *attacker, CPed **pedOnGround) { PedOnGroundState stateToReturn; float angleToFace; CPed *currentPed = nil; PedState currentPedState; CPed *pedOnTheFloor = nil; CPed *deadPed = nil; CPed *pedBelow = nil; bool foundDead = false; bool foundOnTheFloor = false; bool foundBelow = false; float angleDiff; float distance; if (!CGame::nastyGame) return NO_PED; for (int currentPedId = 0; currentPedId < attacker->m_numNearPeds; currentPedId++) { currentPed = attacker->m_nearPeds[currentPedId]; CVector posDifference = currentPed->GetPosition() - attacker->GetPosition(); distance = posDifference.Magnitude(); if (distance < 2.0f) { angleToFace = CGeneral::GetRadianAngleBetweenPoints( currentPed->GetPosition().x, currentPed->GetPosition().y, attacker->GetPosition().x, attacker->GetPosition().y); angleToFace = CGeneral::LimitRadianAngle(angleToFace); attacker->m_fRotationCur = CGeneral::LimitRadianAngle(attacker->m_fRotationCur); angleDiff = Abs(angleToFace - attacker->m_fRotationCur); if (angleDiff > PI) angleDiff = 2 * PI - angleDiff; currentPedState = currentPed->m_nPedState; if (currentPed->OnGroundOrGettingUp()) { if (distance < 2.0f && angleDiff < DEGTORAD(65.0f)) { if (currentPedState == PED_DEAD) { foundDead = 1; if (!deadPed) deadPed = currentPed; } else if (!currentPed->IsPedHeadAbovePos(-0.6f)) { foundOnTheFloor = 1; if (!pedOnTheFloor) pedOnTheFloor = currentPed; } } } else if ((distance < 0.8f && angleDiff < DEGTORAD(75.0f)) || (distance < 1.3f && angleDiff < DEGTORAD(55.0f)) || (distance < 1.7f && angleDiff < DEGTORAD(35.0f)) || (distance < 2.0f && angleDiff < DEGTORAD(30.0f))) { // Either this condition or below one was probably returning 4 early in development. See Fight(). foundBelow = 1; pedBelow = currentPed; break; } else { if (angleDiff < DEGTORAD(75.0f)) { foundBelow = 1; if (!pedBelow) pedBelow = currentPed; } } } } if (foundOnTheFloor) { currentPed = pedOnTheFloor; stateToReturn = PED_ON_THE_FLOOR; } else if (foundDead) { currentPed = deadPed; stateToReturn = PED_DEAD_ON_THE_FLOOR; } else if (foundBelow) { currentPed = pedBelow; stateToReturn = PED_IN_FRONT_OF_ATTACKER; } else { currentPed = nil; stateToReturn = NO_PED; } if (pedOnGround) *pedOnGround = currentPed; return stateToReturn; } void CPed::SetPointGunAt(CEntity *to) { if (to) { SetLookFlag(to, true, true); SetAimFlag(to); SetLookTimer(INT32_MAX); } CWeaponInfo* curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); if (m_nPedState == PED_AIM_GUN || (bIsDucking && !IsPlayer()) || m_nWaitState == WAITSTATE_PLAYANIM_DUCK || curWeapon->m_AnimToPlay == ASSOCGRP_STD) return; if (m_nPedState != PED_ATTACK) SetStoredState(); SetPedState(PED_AIM_GUN); bIsPointingGunAt = true; SetMoveState(PEDMOVE_STILL); CAnimBlendAssociation *aimAssoc; if (bCrouchWhenShooting && bIsDucking && GetCrouchFireAnim(curWeapon)) { aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchFireAnim(curWeapon)); } else { aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ATTACK_1); } if (!aimAssoc || aimAssoc->blendDelta < 0.0f) { if (bCrouchWhenShooting && bIsDucking && GetCrouchFireAnim(curWeapon)) { aimAssoc = CAnimManager::BlendAnimation(GetClump(), curWeapon->m_AnimToPlay, GetCrouchFireAnim(curWeapon), 4.0f); } else { aimAssoc = CAnimManager::AddAnimation(GetClump(), curWeapon->m_AnimToPlay, ANIM_ATTACK_1); } aimAssoc->blendAmount = 0.0f; aimAssoc->blendDelta = 8.0f; } if (to && !IsPlayer()) Say(SOUND_PED_ATTACK); } void CPed::PointGunAt(void) { CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); float animLoopStart = weaponInfo->m_fAnimLoopStart; CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ATTACK_1); if (!weaponAssoc || weaponAssoc->blendDelta < 0.0f) { if (weaponInfo->IsFlagSet(WEAPONFLAG_CROUCHFIRE)) { weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchFireAnim(weaponInfo)); animLoopStart = weaponInfo->m_fAnim2LoopStart; } } if (weaponAssoc && weaponAssoc->currentTime > animLoopStart * 0.4f) { weaponAssoc->SetCurrentTime(animLoopStart); weaponAssoc->flags &= ~ASSOC_RUNNING; if (bIsDucking) m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; if (weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM)) m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; else m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; } } void CPed::ClearPointGunAt(void) { CAnimBlendAssociation *animAssoc; CWeaponInfo *weaponInfo; ClearLookFlag(); ClearAimFlag(); bIsPointingGunAt = false; if (m_nPedState == PED_AIM_GUN || m_nPedState == PED_ATTACK) { SetPedState(PED_IDLE); RestorePreviousState(); } weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ATTACK_1); if (!animAssoc || animAssoc->blendDelta < 0.0f) { if (weaponInfo->IsFlagSet(WEAPONFLAG_CROUCHFIRE)) { animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchFireAnim(weaponInfo)); } } if (animAssoc) { animAssoc->flags |= ASSOC_DELETEFADEDOUT; animAssoc->blendDelta = -4.0f; } } void CPed::SetAttack(CEntity *victim) { CPed *victimPed = nil; CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); CAnimBlendAssociation *animAssoc; if (victim && victim->IsPed()) victimPed = (CPed*)victim; if (m_attackTimer > CTimer::GetTimeInMilliseconds() || m_nWaitState == WAITSTATE_SURPRISE || (bIsDucking && !bCrouchWhenShooting)) return; if (curWeapon->IsFlagSet(WEAPONFLAG_RELOAD) && (RpAnimBlendClumpGetAssociation(GetClump(), GetReloadAnim(curWeapon)) || RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchReloadAnim(curWeapon)))) { if (!IsPlayer() || m_nPedState != PED_ATTACK || ((CPlayerPed*)this)->m_bHaveTargetSelected) bIsAttacking = false; else bIsAttacking = true; return; } if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED || curWeapon->IsFlagSet(WEAPONFLAG_FIGHTMODE) || GetWeapon()->m_eWeaponType == WEAPONTYPE_BRASSKNUCKLE) { if (IsPlayer() || (m_nPedState != PED_FIGHT && m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL && !(m_pedStats->m_flags & STAT_SHOPPING_BAGS) && curWeapon->IsFlagSet(WEAPONFLAG_PARTIALATTACK))) { if (m_nPedState != PED_ATTACK) { SetPedState(PED_ATTACK); bIsAttacking = false; CAnimBlendAssociation *animAssoc = CAnimManager::BlendAnimation(GetClump(), curWeapon->m_AnimToPlay, ANIM_MELEE_ATTACK_START, 8.0f); animAssoc->SetRun(); if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) animAssoc->SetCurrentTime(0.0f); animAssoc->SetFinishCallback(FinishedAttackCB, this); } } else { StartFightAttack(CGeneral::GetRandomNumber()); } return; } if (curWeapon->IsFlagSet(WEAPONFLAG_PARTIALATTACK) && (IsPlayer() && ((CPlayerPed*)this)->m_fMoveSpeed >= 1.0f || m_nMoveState == PEDMOVE_WALK || m_nMoveState == PEDMOVE_RUN)) { if (m_nPedState != PED_ATTACK) { SetPedState(PED_ATTACK); bIsAttacking = false; CAnimBlendAssociation* animAssoc = CAnimManager::BlendAnimation(GetClump(), curWeapon->m_AnimToPlay, ANIM_MELEE_ATTACK_START, 8.0f); animAssoc->SetRun(); if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) animAssoc->SetCurrentTime(0.0f); animAssoc->SetFinishCallback(FinishedAttackCB, this); } return; } if (m_pSeekTarget) m_pSeekTarget->CleanUpOldReference(&m_pSeekTarget); m_pSeekTarget = victim; if (m_pSeekTarget) m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); if (curWeapon->IsFlagSet(WEAPONFLAG_CANAIM)) { CVector aimPos = GetRight() * 0.1f + GetForward() * 0.2f + GetPosition(); aimPos += GetUp() * 0.35f; CEntity *obstacle = CWorld::TestSphereAgainstWorld(aimPos, 0.2f, nil, true, false, false, true, false, false); if (obstacle) { if(gaTempSphereColPoints[0].surfaceB != SURFACE_TRANSPARENT_CLOTH && gaTempSphereColPoints[0].surfaceB != SURFACE_METAL_CHAIN_FENCE && gaTempSphereColPoints[0].surfaceB != SURFACE_WOOD_BENCH && gaTempSphereColPoints[0].surfaceB != SURFACE_SCAFFOLD_POLE) { if (!IsPlayer()) { bObstacleShowedUpDuringKillObjective = true; m_shootTimer = 0; SetAttackTimer(1500); m_shotTime = CTimer::GetTimeInMilliseconds(); } return; } } m_pLookTarget = victim; if (victim) { m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); } if (m_pLookTarget) { SetAimFlag(m_pLookTarget); #ifdef FREE_CAM } else if (this != FindPlayerPed() || !((CPlayerPed*)this)->m_bFreeAimActive) { #else } else { #endif if (this == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam()) { SetAimFlag(m_fRotationCur); ((CPlayerPed*)this)->m_fFPSMoveHeading = TheCamera.Find3rdPersonQuickAimPitch(); } else if (curWeapon->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM)) { SetAimFlag(m_fRotationCur); } } } #ifdef FIX_BUGS // fix aiming for flamethrower and minigun while using PC controls else if (curWeapon->m_AnimToPlay == ASSOCGRP_FLAMETHROWER && TheCamera.Cams[0].Using3rdPersonMouseCam() && this == FindPlayerPed()) { SetAimFlag(m_fRotationCur); ((CPlayerPed*)this)->m_fFPSMoveHeading = TheCamera.Find3rdPersonQuickAimPitch(); } #endif if (m_nPedState == PED_ATTACK) { bIsAttacking = true; return; } if (IsPlayer() || (!victimPed || victimPed->IsPedInControl())) { if (IsPlayer()) CPad::GetPad(0)->ResetAverageWeapon(); uint8 pointBlankStatus; if ((curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER) && 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 && (pointBlankStatus = CheckForPointBlankPeds(victimPed)) != NO_POINT_BLANK_PED) { ClearAimFlag(); // This condition is pointless if (pointBlankStatus == POINT_BLANK_FOR_WANTED_PED || !victimPed && (IsPlayer() || !m_carInObjective)) StartFightAttack(200); } else { if (!curWeapon->IsFlagSet(WEAPONFLAG_CANAIM)) m_pSeekTarget = nil; if (m_nPedState != PED_AIM_GUN) SetStoredState(); SetPedState(PED_ATTACK); SetMoveState(PEDMOVE_NONE); if (bCrouchWhenShooting && bIsDucking && curWeapon->IsFlagSet(WEAPONFLAG_CROUCHFIRE)) { CAnimBlendAssociation* curMoveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchFireAnim(curWeapon)); if (curMoveAssoc) { if (strcmp(CAnimManager::GetAnimAssociation(curWeapon->m_AnimToPlay, GetCrouchFireAnim(curWeapon))->hierarchy->name, curMoveAssoc->hierarchy->name) != 0) { delete curMoveAssoc; } } animAssoc = CAnimManager::BlendAnimation(GetClump(), curWeapon->m_AnimToPlay, GetCrouchFireAnim(curWeapon), 8.0f); } else { float animDelta = 8.0f; if (curWeapon->m_eWeaponFire == WEAPON_FIRE_MELEE) animDelta = 1000.0f; AnimationId fireAnim; if (curWeapon->IsFlagSet(WEAPONFLAG_THROW)) fireAnim = ANIM_THROWABLE_START_THROW; else if (CGame::nastyGame && (curWeapon->IsFlagSet(WEAPONFLAG_GROUND_2ND) || curWeapon->IsFlagSet(WEAPONFLAG_GROUND_3RD))) { PedOnGroundState pedOnGround = CheckForPedsOnGroundToAttack(this, nil); if (pedOnGround > PED_IN_FRONT_OF_ATTACKER || pedOnGround == NO_PED && bIsStanding && m_pCurSurface && m_pCurSurface->IsVehicle()) { fireAnim = GetFireAnimGround(curWeapon, false); } else { fireAnim = GetFireAnimNotDucking(curWeapon); } } else { fireAnim = GetFireAnimNotDucking(curWeapon); } CAnimBlendAssociation* curFireAssoc = RpAnimBlendClumpGetAssociation(GetClump(), fireAnim); if (curFireAssoc) { if (strcmp(CAnimManager::GetAnimAssociation(curWeapon->m_AnimToPlay, fireAnim)->hierarchy->name, curFireAssoc->hierarchy->name) != 0) { delete curFireAssoc; } } animAssoc = CAnimManager::BlendAnimation(GetClump(), curWeapon->m_AnimToPlay, fireAnim, animDelta); } animAssoc->SetRun(); if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) animAssoc->SetCurrentTime(0.0f); animAssoc->SetFinishCallback(FinishedAttackCB, this); } return; } if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && victimPed->m_nPedState == PED_GETUP) SetWaitState(WAITSTATE_SURPRISE, nil); SetLookFlag(victim, true, true); SetLookTimer(100); } void CPed::ClearAttack(void) { if (m_nPedState != PED_ATTACK || (bIsDucking && !IsPlayer()) || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) return; if (FindPlayerPed() == this && TheCamera.Using1stPersonWeaponMode()) { SetPointGunAt(nil); } else if (bIsPointingGunAt) { if (m_pLookTarget) SetPointGunAt(m_pLookTarget); else ClearPointGunAt(); } else if (m_objective != OBJECTIVE_NONE) { SetIdle(); } else { RestorePreviousState(); } } void CPed::ClearAttackByRemovingAnim(void) { if (m_nPedState != PED_ATTACK) return; CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetPrimaryFireAnim(weapon)); if (!weaponAssoc) { if (GetCrouchFireAnim(weapon)) weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchFireAnim(weapon)); } if (!weaponAssoc) { if(GetFinishingAttackAnim(weapon)) weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetFinishingAttackAnim(weapon)); } if (!weaponAssoc) { if(GetSecondFireAnim(weapon)) weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetSecondFireAnim(weapon)); } if (!weaponAssoc) { if(Get3rdFireAnim(weapon)) weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), Get3rdFireAnim(weapon)); } if (weaponAssoc) { weaponAssoc->blendDelta = -8.0f; weaponAssoc->flags &= ~ASSOC_RUNNING; weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; weaponAssoc->SetDeleteCallback(FinishedAttackCB, this); } else { ClearAttack(); } } void CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) { CAnimBlendAssociation *newAnim, *reloadAnimAssoc = nil; CPed *ped = (CPed*)arg; CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType); if (ped->m_nPedState != PED_ATTACK) { if (ped->bIsDucking && ped->IsPedInControl()) { if (GetCrouchReloadAnim(currentWeapon)) { reloadAnimAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), GetCrouchReloadAnim(currentWeapon)); } if (GetCrouchFireAnim(currentWeapon) && attackAssoc) { if (attackAssoc->animId == GetCrouchFireAnim(currentWeapon) && !reloadAnimAssoc) { newAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_STD_DUCK_WEAPON, 8.0f); newAnim->SetCurrentTime(newAnim->hierarchy->totalLength); newAnim->flags &= ~ASSOC_RUNNING; } } } } else if (attackAssoc && attackAssoc->animId == ANIM_THROWABLE_START_THROW && currentWeapon->m_AnimToPlay == ASSOCGRP_THROW) { if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->m_bHaveTargetSelected) && ped->IsPlayer()) { attackAssoc->blendDelta = -1000.0f; newAnim = CAnimManager::AddAnimation(ped->GetClump(), currentWeapon->m_AnimToPlay, ANIM_THROWABLE_THROWU); } else { attackAssoc->blendDelta = -1000.0; newAnim = CAnimManager::AddAnimation(ped->GetClump(), currentWeapon->m_AnimToPlay, ANIM_THROWABLE_THROW); } newAnim->SetFinishCallback(FinishedAttackCB, ped); } else if (ped->bIsDucking && ped->bCrouchWhenShooting) { if (GetCrouchReloadAnim(currentWeapon)) { reloadAnimAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), GetCrouchReloadAnim(currentWeapon)); } if (GetCrouchFireAnim(currentWeapon) && attackAssoc) { if (attackAssoc->animId == GetCrouchFireAnim(currentWeapon) && !reloadAnimAssoc) { newAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_STD_DUCK_WEAPON, 8.0f); newAnim->SetCurrentTime(newAnim->hierarchy->totalLength); newAnim->flags &= ~ASSOC_RUNNING; } } if (!ped->bIsAttacking) ped->ClearAttack(); } else if (GetSecondFireAnim(currentWeapon) && ped->bIsAttacking && currentWeapon->m_AnimToPlay != ASSOCGRP_THROW) { AnimationId groundAnim = GetFireAnimGround(currentWeapon); CAnimBlendAssociation *groundAnimAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), groundAnim); if (!(groundAnimAssoc && (groundAnimAssoc->blendAmount > 0.95f || groundAnimAssoc->blendDelta > 0.0f))) { if (attackAssoc && attackAssoc->animId == ANIM_MELEE_ATTACK) { newAnim = CAnimManager::BlendAnimation( ped->GetClump(), currentWeapon->m_AnimToPlay, GetSecondFireAnim(currentWeapon), 8.0f); } else { newAnim = CAnimManager::BlendAnimation( ped->GetClump(), currentWeapon->m_AnimToPlay, ANIM_MELEE_ATTACK, 8.0f); } newAnim->SetFinishCallback(FinishedAttackCB, ped); } } else { if (attackAssoc && attackAssoc->animId == ANIM_MELEE_ATTACK && currentWeapon->m_AnimToPlay == ASSOCGRP_UNARMED) { attackAssoc->blendDelta = -8.0f; attackAssoc->flags |= ASSOC_DELETEFADEDOUT; ped->ClearAttack(); return; } if (attackAssoc) { if (currentWeapon->m_AnimToPlay == ASSOCGRP_THROW) { if ((attackAssoc->animId == ANIM_THROWABLE_THROW || attackAssoc->animId == ANIM_THROWABLE_THROWU) && ped->GetWeapon()->m_nAmmoTotal > 0) { ped->RemoveWeaponModel(currentWeapon->m_nModelId); ped->AddWeaponModel(currentWeapon->m_nModelId); } } } if (!ped->bIsAttacking) ped->ClearAttack(); } } void CPed::FinishedReloadCB(CAnimBlendAssociation *reloadAssoc, void *arg) { CPed *ped = (CPed*)arg; CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType); if (ped->DyingOrDead()) return; if (ped->bIsDucking && ped->bCrouchWhenShooting) { CAnimBlendAssociation *crouchFireAssoc = nil; if (weapon->IsFlagSet(WEAPONFLAG_CROUCHFIRE)) { crouchFireAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), GetCrouchFireAnim(weapon)); } if (weapon->IsFlagSet(WEAPONFLAG_RELOAD) && reloadAssoc) { if (reloadAssoc->animId == GetCrouchReloadAnim(weapon) && !crouchFireAssoc) { CAnimBlendAssociation *crouchAssoc = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_STD_DUCK_WEAPON, 8.0f); crouchAssoc->SetCurrentTime(crouchAssoc->hierarchy->totalLength); crouchAssoc->flags &= ~ASSOC_RUNNING; } } } else if (weapon->IsFlagSet(WEAPONFLAG_RELOAD_LOOP2START) && ped->bIsAttacking) { CAnimBlendAssociation *fireAssoc = CAnimManager::BlendAnimation(ped->GetClump(), weapon->m_AnimToPlay, GetPrimaryFireAnim(weapon), 8.0f); fireAssoc->SetFinishCallback(FinishedAttackCB, ped); fireAssoc->SetRun(); if (fireAssoc->currentTime == reloadAssoc->hierarchy->totalLength) fireAssoc->SetCurrentTime(Max(weapon->m_fAnimLoopStart - 0.04f, 0.0f)); else if (fireAssoc->currentTime < weapon->m_fAnimLoopStart) fireAssoc->SetCurrentTime(Max(weapon->m_fAnimLoopStart - 0.04f, 0.0f)); } } uint8 CPed::CheckForPointBlankPeds(CPed *pedToVerify) { float pbDistance = 1.1f; if (GetWeapon()->IsType2Handed()) pbDistance = 1.6f; for (int i = 0; i < m_numNearPeds; i++) { CPed *nearPed = m_nearPeds[i]; if (!pedToVerify || pedToVerify == nearPed) { CVector diff = nearPed->GetPosition() - GetPosition(); if (diff.MagnitudeSqr() < SQR(pbDistance)) { float neededAngle = CGeneral::GetRadianAngleBetweenPoints( nearPed->GetPosition().x, nearPed->GetPosition().y, GetPosition().x, GetPosition().y); neededAngle = CGeneral::LimitRadianAngle(neededAngle); m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); float neededTurn = Abs(neededAngle - m_fRotationCur); if (neededTurn > PI) neededTurn = 2*PI - neededTurn; PedState nearPedState = nearPed->m_nPedState; if (nearPedState == PED_FALL || nearPedState == PED_GETUP || nearPedState == PED_DIE || nearPedState == PED_DEAD || nearPedState == PED_DIVE_AWAY) return NO_POINT_BLANK_PED; if (neededTurn < CAN_SEE_ENTITY_ANGLE_THRESHOLD) { if (pedToVerify == nearPed) return POINT_BLANK_FOR_WANTED_PED; else return POINT_BLANK_FOR_SOMEONE_ELSE; } } } } return NO_POINT_BLANK_PED; } void CPed::Attack(void) { CAnimBlendAssociation *weaponAnimAssoc; int32 weaponAnim; float weaponAnimTime; float animLoopEnd; CWeaponInfo *ourWeapon; bool attackShouldContinue; CAnimBlendAssociation *reloadAnimAssoc; CAnimBlendAssociation *throwAssoc; float delayBetweenAnimAndFire; float animLoopStart; CVector firePos; ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); weaponAnimAssoc = nil; attackShouldContinue = !!bIsAttacking; reloadAnimAssoc = nil; throwAssoc = nil; animLoopStart = ourWeapon->m_fAnimLoopStart; animLoopEnd = ourWeapon->m_fAnimLoopEnd; delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire; weaponAnim = ourWeapon->m_AnimToPlay; if (bIsDucking) { if(GetCrouchFireAnim(ourWeapon) && bCrouchWhenShooting) { weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchFireAnim(ourWeapon)); if (weaponAnimAssoc) { animLoopStart = ourWeapon->m_fAnim2LoopStart; animLoopEnd = ourWeapon->m_fAnim2LoopEnd; delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; } } } else if (m_nPedType == PEDTYPE_COP && Get3rdFireAnim(ourWeapon)){ weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), Get3rdFireAnim(ourWeapon)); if (weaponAnimAssoc) { animLoopStart = 11.f/30.f; animLoopEnd = 19.f/30.f; delayBetweenAnimAndFire = 14.f/30.f; } } else { weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetPrimaryFireAnim(ourWeapon)); } if (GetReloadAnim(ourWeapon)) { reloadAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetReloadAnim(ourWeapon)); } if (GetCrouchReloadAnim(ourWeapon) && !reloadAnimAssoc) { reloadAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetCrouchReloadAnim(ourWeapon)); } if ( reloadAnimAssoc && reloadAnimAssoc->IsRunning() ) { if (!IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) ClearAttack(); return; } if ( reloadAnimAssoc ) { reloadAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; if ( reloadAnimAssoc->blendDelta >= 0.0f ) reloadAnimAssoc->blendDelta = -8.0f; } if (GetThrowAnim(ourWeapon)) { throwAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetThrowAnim(ourWeapon)); } if ( CTimer::GetTimeInMilliseconds() < m_shootTimer ) attackShouldContinue = true; bool meleeAttackStarted = false; if ( !weaponAnimAssoc ) { if (GetMeleeStartAnim(ourWeapon)) { weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetMeleeStartAnim(ourWeapon)); if ( weaponAnimAssoc ) { if ( IsPlayer() ) meleeAttackStarted = true; switch ( ourWeapon->m_AnimToPlay ) { case ASSOCGRP_UNARMED: case ASSOCGRP_SCREWDRIVER: case ASSOCGRP_KNIFE: case ASSOCGRP_BASEBALLBAT: case ASSOCGRP_GOLFCLUB: case ASSOCGRP_CHAINSAW: delayBetweenAnimAndFire = 0.2f; animLoopStart = 0.1f; break; default: break; } animLoopEnd = 99.9f; } } } if (!weaponAnimAssoc) { if (GetSecondFireAnim(ourWeapon)) { weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetSecondFireAnim(ourWeapon)); if (weaponAnimAssoc) { animLoopStart = ourWeapon->m_fAnim2LoopStart; animLoopEnd = ourWeapon->m_fAnim2LoopEnd; delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; } } } if (!weaponAnimAssoc) { weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), GetFireAnimGround(ourWeapon)); if (weaponAnimAssoc) { animLoopStart = ourWeapon->m_fAnim2LoopStart; animLoopEnd = ourWeapon->m_fAnim2LoopEnd; delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; } } if (!weaponAnimAssoc) { if (!throwAssoc) { if (attackShouldContinue) { if (ourWeapon->m_eWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) { if (bCrouchWhenShooting && bIsDucking && GetCrouchFireAnim(ourWeapon)) { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ourWeapon->m_AnimToPlay, GetCrouchFireAnim(ourWeapon), 8.0f); } else if(GetSecondFireAnim(ourWeapon) && CGeneral::GetRandomNumber() & 1){ weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ourWeapon->m_AnimToPlay, GetSecondFireAnim(ourWeapon), 8.0f); } else if(!CGame::nastyGame || ourWeapon->m_eWeaponFire != WEAPON_FIRE_MELEE || !GetFireAnimGround(ourWeapon, false) || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ourWeapon->m_AnimToPlay, GetFireAnimNotDucking(ourWeapon), 8.0f); } else { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ourWeapon->m_AnimToPlay, GetFireAnimGround(ourWeapon, false), 8.0f); } weaponAnimAssoc->SetFinishCallback(FinishedAttackCB, this); weaponAnimAssoc->SetRun(); if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) weaponAnimAssoc->SetCurrentTime(0.0f); if (IsPlayer()) { ((CPlayerPed*)this)->m_fAttackButtonCounter = 0.0f; ((CPlayerPed*)this)->m_bHaveTargetSelected = false; } } } else FinishedAttackCB(nil, this); } return; } if (meleeAttackStarted && IsPlayer()) { if (((CPlayerPed*)this)->m_bHaveTargetSelected || ((CPlayerPed*)this)->m_fMoveSpeed < 0.5f) { weaponAnimAssoc->SetRun(); } else { if (weaponAnimAssoc->currentTime > animLoopStart && weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= animLoopStart) weaponAnimAssoc->flags &= ~ASSOC_RUNNING; } } float animStart = animLoopStart * 0.4f; weaponAnimTime = weaponAnimAssoc->currentTime; if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { if (!bIsDucking && !GetFireAnimNotDucking(ourWeapon) && ourWeapon->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM)) m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; else #ifdef FREE_CAM if (!IsPlayer() || !((CPlayerPed*)this)->m_bFreeAimActive) #endif m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; } if (GetWeapon()->m_eWeaponType != WEAPONTYPE_CHAINSAW || !meleeAttackStarted && delayBetweenAnimAndFire - 0.5f >= weaponAnimAssoc->currentTime || weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire) { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_CHAINSAW) { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_CHAINSAW_IDLE, 0.0f); } else if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { if (weaponAnimAssoc->speed < 1.0f) weaponAnimAssoc->speed = 1.0f; } else { firePos = ourWeapon->m_vecFireOffset; if(ourWeapon->m_AnimToPlay != ASSOCGRP_BASEBALLBAT && ourWeapon->m_AnimToPlay != ASSOCGRP_GOLFCLUB) { if (ourWeapon->m_eWeaponFire != WEAPON_FIRE_MELEE) { TransformToNode(firePos, (weaponAnimAssoc->animId == ANIM_MELEE_ATTACK_2ND && ourWeapon->m_AnimToPlay == ASSOCGRP_UNARMED) ? PED_FOOTR : PED_HANDR); } else { firePos = GetMatrix() * firePos; } } else { if (weaponAnimAssoc->animId == ANIM_MELEE_ATTACK_2ND) firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; firePos = GetMatrix() * firePos; } GetWeapon()->Fire(this, &firePos); if (GetWeapon()->m_eWeaponType == WEAPONTYPE_MOLOTOV || GetWeapon()->m_eWeaponType == WEAPONTYPE_GRENADE || GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE || GetWeapon()->m_eWeaponType == WEAPONTYPE_TEARGAS) { RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nModelId); } if (GetWeapon()->m_nAmmoTotal == 0 && ourWeapon->m_eWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { SelectGunIfArmed(); } if (GetWeapon()->m_eWeaponState == WEAPONSTATE_MELEE_MADECONTACT) { int damagerType = ENTITY_TYPE_NOTHING; if (m_pDamageEntity && (m_fDamageImpulse == 0.0f || !m_pDamageEntity->IsBuilding())) { damagerType = m_pDamageEntity->GetType(); } switch (ourWeapon->m_AnimToPlay) { case ASSOCGRP_UNARMED: if (weaponAnimAssoc->animId == ANIM_MELEE_ATTACK || weaponAnimAssoc->animId == ANIM_MELEE_ATTACK_START) DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_46, (damagerType | (GetWeapon()->m_eWeaponType << 8))); break; case ASSOCGRP_KNIFE: case ASSOCGRP_BASEBALLBAT: case ASSOCGRP_GOLFCLUB: case ASSOCGRP_CHAINSAW: DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, (damagerType | (GetWeapon()->m_eWeaponType << 8))); break; default: break; } if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) { weaponAnimAssoc->callbackType = 0; } } attackShouldContinue = false; } } else { CVector firePos = ourWeapon->m_vecFireOffset; if (weaponAnimAssoc->animId == ANIM_MELEE_ATTACK_2ND) firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; firePos = GetMatrix() * firePos; GetWeapon()->Fire(this, &firePos); if (GetWeapon()->m_eWeaponState == WEAPONSTATE_MELEE_MADECONTACT) { int damagerType = ENTITY_TYPE_PED; if (m_pDamageEntity) damagerType = m_pDamageEntity->GetType(); DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_CHAINSAW_MADECONTACT, (float)damagerType); if (IsPlayer()) { CPad::GetPad(0)->StartShake(240, 180); } } else { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_CHAINSAW_ATTACK, 0.0f); if (IsPlayer()) { CPad::GetPad(0)->StartShake(240, 90); } } attackShouldContinue = false; } if (ourWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT && ourWeapon->m_AnimToPlay == ASSOCGRP_SHOTGUN) { weaponAnimTime = weaponAnimAssoc->currentTime; if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { firePos = ourWeapon->m_vecFireOffset; TransformToNode(firePos, PED_HANDR); CVector gunshellPos( firePos.x - 0.6f * GetForward().x, firePos.y - 0.6f * GetForward().y, firePos.z - 0.15f * GetUp().z ); CVector2D gunshellRot( GetRight().x, GetRight().y ); gunshellRot.Normalise(); GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); } } if (IsPlayer()) { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT || GetWeapon()->m_eWeaponType == WEAPONTYPE_GOLFCLUB || GetWeapon()->m_eWeaponType == WEAPONTYPE_KATANA) { float loopEndWithDelay = animLoopEnd; if (loopEndWithDelay >= 98.0f) loopEndWithDelay = (14.0f / 30.0f) + delayBetweenAnimAndFire; if (weaponAnimAssoc->flags & ASSOC_RUNNING) { if (weaponAnimAssoc->currentTime >= animLoopStart && weaponAnimAssoc->currentTime <= loopEndWithDelay) CSpecialFX::AddWeaponStreak(GetWeapon()->m_eWeaponType); } } } // Anim breakout on running if (IsPlayer()) { if (CPad::GetPad(0)->GetSprint()) { if (!attackShouldContinue && weaponAnimAssoc->currentTime > ourWeapon->m_fAnimBreakout) { weaponAnimAssoc->blendDelta = -4.0f; FinishedAttackCB(nil, this); return; } } } weaponAnimTime = weaponAnimAssoc->currentTime; // Anim loop end, either start the loop again or finish the attack if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeapon->m_eWeaponFire != WEAPON_FIRE_PROJECTILE) { if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING) { if (GetReloadAnim(ourWeapon) && !reloadAnimAssoc) { if (!CWorld::Players[CWorld::PlayerInFocus].m_bFastReload) { CAnimBlendAssociation *newReloadAssoc = CAnimManager::BlendAnimation( GetClump(), ourWeapon->m_AnimToPlay, bIsDucking && GetCrouchReloadAnim(ourWeapon) ? GetCrouchReloadAnim(ourWeapon) : GetReloadAnim(ourWeapon), 8.0f); newReloadAssoc->SetFinishCallback(FinishedReloadCB, this); } ClearLookFlag(); ClearAimFlag(); bIsAttacking = false; bIsPointingGunAt = false; m_shootTimer = CTimer::GetTimeInMilliseconds(); DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, GetWeapon()->m_eWeaponType); return; } } if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd && (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) && (GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING || GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN)) { PedOnGroundState pedOnGroundState; if (ourWeapon->m_eWeaponFire == WEAPON_FIRE_MELEE && (CGame::nastyGame && ((pedOnGroundState = CheckForPedsOnGroundToAttack(this, nil)) > PED_IN_FRONT_OF_ATTACKER) || GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && pedOnGroundState == NO_PED && bIsStanding && m_pCurSurface && m_pCurSurface->IsVehicle())) { AnimationId fireAnim = GetFireAnimGround(ourWeapon, false); if (weaponAnimAssoc->animId == fireAnim) weaponAnimAssoc->SetCurrentTime(0.1f); else { if (GetFireAnimGround(ourWeapon, false)) { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ourWeapon->m_AnimToPlay, fireAnim, 8.0f); } else { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_KICKGROUND, 8.0f); } } weaponAnimAssoc->SetFinishCallback(FinishedAttackCB, this); } else if (GetSecondFireAnim(ourWeapon)) { if (weaponAnimAssoc->animId == GetSecondFireAnim(ourWeapon)) { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ourWeapon->m_AnimToPlay, ANIM_ATTACK_1, 8.0f); } else { weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ourWeapon->m_AnimToPlay, GetSecondFireAnim(ourWeapon), 8.0f); } weaponAnimAssoc->SetFinishCallback(FinishedAttackCB, this); } else { weaponAnimAssoc->SetCurrentTime(animLoopStart); weaponAnimAssoc->SetRun(); } } else if (IsPlayer() && m_pPointGunAt && bIsAimingGun && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { weaponAnimAssoc->SetCurrentTime(animLoopEnd); weaponAnimAssoc->flags &= ~ASSOC_RUNNING; SetPointGunAt(m_pPointGunAt); #ifdef FREE_CAM } else if (IsPlayer() && ((CPlayerPed*)this)->m_bFreeAimActive && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { float limitedCam = CGeneral::LimitRadianAngle(-TheCamera.Orientation); SetLookFlag(limitedCam, true, true); SetAimFlag(limitedCam); SetLookTimer(INT32_MAX); SetPointGunAt(nil); ((CPlayerPed*)this)->m_fFPSMoveHeading = TheCamera.Find3rdPersonQuickAimPitch(); #endif } else { ClearAimFlag(); // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep < animLoopEnd) DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, GetWeapon()->m_eWeaponType); // Fun fact: removing this part leds to reloading flamethrower if (GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; weaponAnimAssoc->flags &= ~ASSOC_RUNNING; weaponAnimAssoc->blendDelta = -4.0f; } } } if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) attackShouldContinue = false; bIsAttacking = attackShouldContinue; } void CPed::StartFightAttack(uint8 buttonPressure) { if (!IsPedInControl() || (m_attackTimer > CTimer::GetTimeInMilliseconds() && buttonPressure != 0)) return; if (m_nPedState == PED_FIGHT) { m_fightButtonPressure = buttonPressure; return; } if (m_nPedState != PED_AIM_GUN) SetStoredState(); if (m_nWaitState != WAITSTATE_FALSE) { ClearWaitState(); RestoreHeadingRate(); } CAnimBlendAssociation* animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUNSTOP1); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUNSTOP2); if (animAssoc) { RestoreHeadingRate(); } SetMoveState(PEDMOVE_NONE); m_nStoredMoveState = PEDMOVE_NONE; bool fightWithWeapon = false; CAnimBlendAssociation *fightIdleAssoc; CWeaponInfo* weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { if (GetFightIdleWithMeleeAnim(weaponInfo)) { fightIdleAssoc = CAnimManager::BlendAnimation(GetClump(), weaponInfo->m_AnimToPlay, GetFightIdleWithMeleeAnim(weaponInfo), 1000.0f); fightWithWeapon = true; } else { fightIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_FIGHT_IDLE, 1000.0f); } } else { fightIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_FIGHT_IDLE, 1000.0f); } m_lastFightMove = FIGHTMOVE_IDLE; m_curFightMove = IsPlayer() ? ChooseAttackPlayer(buttonPressure, fightWithWeapon) : ChooseAttackAI(buttonPressure, fightWithWeapon); SetPedState(PED_FIGHT); m_fightButtonPressure = 0; if (m_curFightMove > FIGHTMOVE_NULL && m_curFightMove != FIGHTMOVE_IDLE) { animAssoc = CAnimManager::BlendAnimation(GetClump(), m_curFightMove < FIGHTMOVE_MELEE1 ? ASSOCGRP_STD : weaponInfo->m_AnimToPlay, tFightMoves[m_curFightMove].animId, 8.0f); if (weaponInfo->m_AnimToPlay == ASSOCGRP_KNIFE && m_curFightMove >= FIGHTMOVE_MELEE1) { switch (GetWeapon()->m_eWeaponType) { case WEAPONTYPE_SCREWDRIVER: case WEAPONTYPE_KNIFE: animAssoc->speed = 1.05f; break; case WEAPONTYPE_GOLFCLUB: case WEAPONTYPE_NIGHTSTICK: case WEAPONTYPE_BASEBALLBAT: case WEAPONTYPE_HAMMER: case WEAPONTYPE_KATANA: animAssoc->speed = 0.8f; break; case WEAPONTYPE_CLEAVER: case WEAPONTYPE_MACHETE: animAssoc->speed = 0.9f; break; } } else { animAssoc->speed = 0.8f; } if (IsPlayer()) animAssoc->SetCurrentTime(0.08f); animAssoc->SetFinishCallback(FinishFightMoveCB, this); } else { m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; } m_fightState = FIGHTSTATE_NO_MOVE; m_takeAStepAfterAttack = false; bIsAttacking = true; if (IsPlayer()) nPlayerInComboMove = 0; } void CPed::StartFightDefend(uint8 direction, uint8 hitLevel, uint8 unk) { if (m_nPedState == PED_DEAD) { if (CGame::nastyGame) { if (hitLevel == HITLEVEL_GROUND) { CAnimBlendAssociation *floorHitAssoc; if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) { floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR_FRONT, 8.0f); } else { floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[FIGHTMOVE_HITONFLOOR].animId, 8.0f); } if (floorHitAssoc) { floorHitAssoc->SetCurrentTime(0.0f); floorHitAssoc->SetRun(); floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; } } if (CGame::nastyGame) { CVector headPos = GetNodePosition(PED_HEAD); for(int i = 0; i < 4; ++i) { CVector bloodDir(0.0f, 0.0f, 0.1f); CVector bloodPos = headPos - 0.2f * GetForward(); CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, bloodDir, nil, 0.0f, 0, 0, 0, 0); } } } } else if (m_nPedState == PED_FALL) { if (hitLevel == HITLEVEL_GROUND && !IsPedHeadAbovePos(-0.3f)) { CAnimBlendAssociation *floorHitAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL) ? CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR_FRONT, 8.0f) : CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR, 8.0f); if (floorHitAssoc) { floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; floorHitAssoc->flags |= ASSOC_DELETEFADEDOUT; } } } else if (IsPedInControl()) { if ((IsPlayer() && m_nPedState != PED_FIGHT && ((CPlayerPed*)this)->m_fMoveSpeed > 1.0f) || (!IsPlayer() && m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE)) { if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 1) && CGeneral::GetRandomNumber() & 7) { if (IsPlayer() || CGeneral::GetRandomNumber() & 1) { AnimationId shotAnim; switch (direction) { case 1: shotAnim = ANIM_STD_HITBYGUN_LEFT; break; case 2: shotAnim = ANIM_STD_HITBYGUN_BACK; break; case 3: shotAnim = ANIM_STD_HITBYGUN_RIGHT; break; default: shotAnim = ANIM_STD_HITBYGUN_FRONT; break; } CAnimBlendAssociation *shotAssoc = RpAnimBlendClumpGetAssociation(GetClump(), shotAnim); if (!shotAssoc || shotAssoc->blendDelta < 0.0f) shotAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, shotAnim, 8.0f); shotAssoc->SetCurrentTime(0.0f); shotAssoc->SetRun(); shotAssoc->flags |= ASSOC_FADEOUTWHENDONE; } else { int time = CGeneral::GetRandomNumberInRange(1000, 3000); SetWaitState(WAITSTATE_PLAYANIM_DUCK, &time); } } else { bool fall = true; AnimationId hitAnim; switch (direction) { case 1: hitAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 2: if (CGeneral::GetRandomNumber() & 1) { fall = false; hitAnim = ANIM_STD_HIT_BACK; } else { hitAnim = ANIM_STD_HIGHIMPACT_BACK; } break; case 3: hitAnim = ANIM_STD_HIGHIMPACT_RIGHT; break; default: if (hitLevel == HITLEVEL_LOW) { hitAnim = ANIM_STD_KO_SHOT_STOMACH; /* LCS: removed } else if (CGeneral::GetRandomNumber() & 1) { fall = false; hitAnim = ANIM_STD_HIT_WALK; } else if (CGeneral::GetRandomNumber() & 1) { fall = false; hitAnim = ANIM_STD_HIT_HEAD; */ } else { hitAnim = ANIM_STD_KO_SHOT_FACE; } break; } if (fall) { SetFall(500, hitAnim, false); } else { CAnimBlendAssociation *hitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), hitAnim); if (!hitAssoc || hitAssoc->blendDelta < 0.0f) hitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, hitAnim, 8.0f); hitAssoc->SetCurrentTime(0.0f); hitAssoc->SetRun(); hitAssoc->flags |= ASSOC_FADEOUTWHENDONE; } } Say(SOUND_PED_DEFEND); } else { Say(SOUND_PED_DEFEND); switch (hitLevel) { case HITLEVEL_GROUND: m_curFightMove = FIGHTMOVE_HITONFLOOR; break; case HITLEVEL_LOW: if (direction == 2 && (!IsPlayer() || ((CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f))) { SetFall(1000, ANIM_STD_HIGHIMPACT_BACK, false); Say(SOUND_PED_DEFEND); return; } else if (direction != 2 && !IsPlayer() && (CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f) { SetFall(1000, ANIM_STD_KO_SHOT_STOMACH, false); Say(SOUND_PED_DEFEND); return; } m_curFightMove = FIGHTMOVE_HITFRONT; // LCS break; case HITLEVEL_HIGH: switch (direction) { case 1: m_curFightMove = FIGHTMOVE_HITLEFT; break; case 2: m_curFightMove = FIGHTMOVE_HITBACK; break; case 3: m_curFightMove = FIGHTMOVE_HITRIGHT; break; default: // LCS: removed //if (unk <= 5) // m_curFightMove = FIGHTMOVE_HITHEAD; //else // m_curFightMove = FIGHTMOVE_HITBIGSTEP; m_curFightMove = FIGHTMOVE_HITFRONT; break; } break; default: switch (direction) { case 1: m_curFightMove = FIGHTMOVE_HITLEFT; break; case 2: m_curFightMove = FIGHTMOVE_HITBACK; break; case 3: m_curFightMove = FIGHTMOVE_HITRIGHT; break; default: // LCS: removed //if (unk <= 5) // m_curFightMove = FIGHTMOVE_HITCHEST; //else // m_curFightMove = FIGHTMOVE_HITBIGSTEP; m_curFightMove = FIGHTMOVE_HITFRONT; break; } break; } if (m_nPedState == PED_GETUP && !IsPedHeadAbovePos(0.0f)) m_curFightMove = FIGHTMOVE_HITONFLOOR; if (m_nPedState == PED_FIGHT) { CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); moveAssoc->SetCurrentTime(0.0f); moveAssoc->SetFinishCallback(FinishFightMoveCB, this); if (IsPlayer()) moveAssoc->speed = 1.2f; m_takeAStepAfterAttack = false; m_fightButtonPressure = 0; } else if (IsPlayer() && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && GetWeapon()->m_eWeaponType != WEAPONTYPE_BRASSKNUCKLE && !CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->IsFlagSet(WEAPONFLAG_FIGHTMODE)) { CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); moveAssoc->SetCurrentTime(0.0f); moveAssoc->speed = 1.2f; } else { if (m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK) SetStoredState(); if (m_nWaitState != WAITSTATE_FALSE) { ClearWaitState(); RestoreHeadingRate(); } SetPedState(PED_FIGHT); m_fightButtonPressure = 0; m_lastFightMove = FIGHTMOVE_IDLE; RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT); CAnimBlendAssociation *walkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_STARTWALK); if (walkStartAssoc) { walkStartAssoc->flags |= ASSOC_DELETEFADEDOUT; walkStartAssoc->blendDelta = -1000.0f; } CAnimBlendAssociation *walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUNSTOP1); if (!walkStopAssoc) walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_RUNSTOP2); if (walkStopAssoc) { walkStopAssoc->flags |= ASSOC_DELETEFADEDOUT; walkStopAssoc->blendDelta = -1000.0f; RestoreHeadingRate(); } SetMoveState(PEDMOVE_NONE); m_nStoredMoveState = PEDMOVE_NONE; CAnimBlendAssociation *fightIdleAssoc; if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); if (GetFightIdleWithMeleeAnim(weaponInfo)) { fightIdleAssoc = CAnimManager::AddAnimation(GetClump(), weaponInfo->m_AnimToPlay, GetFightIdleWithMeleeAnim(weaponInfo)); } else { fightIdleAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_FIGHT_IDLE); } } else { fightIdleAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_FIGHT_IDLE); } fightIdleAssoc->blendAmount = 1.0f; CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); moveAssoc->SetFinishCallback(FinishFightMoveCB, this); m_fightState = FIGHTSTATE_NO_MOVE; m_takeAStepAfterAttack = false; bIsAttacking = true; } if (m_pedInObjective && m_pedInObjective->IsPlayer() && !IsPlayer()) ((CPlayerPed*)m_pedInObjective)->RemovePedFromMeleeList(this); } } } void CPed::Fight(void) { CAnimBlendAssociation *currentAssoc, *animAssoc; bool fightWithWeapon = false; eWeaponType weapon = GetWeapon()->m_eWeaponType; CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(weapon); if (weaponInfo->IsFlagSet(WEAPONFLAG_FIGHTMODE) && weapon != WEAPONTYPE_UNARMED) { fightWithWeapon = true; tFightMoves[FIGHTMOVE_MELEE1].startFireTime = weaponInfo->m_fAnimFrameFire; tFightMoves[FIGHTMOVE_MELEE1].endFireTime = weaponInfo->m_fAnimLoopEnd; tFightMoves[FIGHTMOVE_MELEE2].startFireTime = weaponInfo->m_fAnim2FrameFire; tFightMoves[FIGHTMOVE_MELEE2].endFireTime = weaponInfo->m_fAnim2LoopEnd; tFightMoves[FIGHTMOVE_MELEE3].startFireTime = weaponInfo->m_fAnim2FrameFire; tFightMoves[FIGHTMOVE_MELEE3].endFireTime = weaponInfo->m_fAnim2LoopEnd; } switch (m_curFightMove) { case FIGHTMOVE_NULL: return; case FIGHTMOVE_IDLE2NORM: m_curFightMove = FIGHTMOVE_NULL; RestorePreviousState(); // FIX: Uninitialized currentAssoc = nil; break; case FIGHTMOVE_IDLE: currentAssoc = nil; break; default: currentAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId); break; } if (m_curFightMove == FIGHTMOVE_SHUFFLE_F && !currentAssoc) currentAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_FIGHT_SHUFFLE_B); if (IsPlayer() && currentAssoc && weapon == WEAPONTYPE_KATANA) { if (m_curFightMove == FIGHTMOVE_MELEE1 || m_curFightMove == FIGHTMOVE_MELEE2) { static float streakDelay = 0.2f; if (tFightMoves[m_curFightMove].startFireTime - streakDelay < currentAssoc->currentTime && streakDelay + tFightMoves[m_curFightMove].endFireTime > currentAssoc->currentTime) { CSpecialFX::AddWeaponStreak(GetWeapon()->m_eWeaponType); } } } if (!bIsAttacking && IsPlayer()) { if (currentAssoc) { currentAssoc->blendDelta = -1000.0f; currentAssoc->flags |= ASSOC_DELETEFADEDOUT; currentAssoc->flags &= ~ASSOC_RUNNING; } if (m_takeAStepAfterAttack) EndFight(ENDFIGHT_WITH_A_STEP); else EndFight(ENDFIGHT_FAST); } else if (currentAssoc && m_fightState > FIGHTSTATE_MOVE_FINISHED) { float animTime = currentAssoc->currentTime; FightMove &curMove = tFightMoves[m_curFightMove]; if (curMove.hitLevel != HITLEVEL_NULL && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightState >= FIGHTSTATE_NO_MOVE) { if (animTime > curMove.startFireTime && animTime - currentAssoc->timeStep < curMove.startFireTime && (IsPlayer() || weapon != WEAPONTYPE_UNARMED)) { DMAudio.PlayOneShot(m_audioEntityId, SOUND_MELEE_ATTACK_START, weapon << 8); } CVector touchingNodePos(0.0f, 0.0f, 0.0f); switch (m_curFightMove) { // case FIGHTMOVE_KNEE: // TransformToNode(touchingNodePos, PED_LOWERLEGR); // break; // case FIGHTMOVE_PUNCHHOOK: // case FIGHTMOVE_PUNCHJAB: // TransformToNode(touchingNodePos, PED_HANDL); // break; case FIGHTMOVE_LONGKICK: case FIGHTMOVE_ROUNDHOUSE: // case FIGHTMOVE_FWDLEFT: // case FIGHTMOVE_BACKRIGHT: case FIGHTMOVE_GROUNDKICK: TransformToNode(touchingNodePos, PED_FOOTR); break; case FIGHTMOVE_FWDRIGHT: TransformToNode(touchingNodePos, PED_HEAD); break; // case FIGHTMOVE_BACKKICK: // case FIGHTMOVE_BACKFLIP: // TransformToNode(touchingNodePos, PED_FOOTL); // break; // case FIGHTMOVE_BACKLEFT: // TransformToNode(touchingNodePos, PED_UPPERARML); // break; default: TransformToNode(touchingNodePos, PED_HANDR); break; } FightStrike(touchingNodePos, fightWithWeapon); m_fightButtonPressure = 0; return; } if (curMove.hitLevel != HITLEVEL_NULL) { if (animTime > curMove.endFireTime && weaponInfo->m_AnimToPlay != ASSOCGRP_KNIFE) { if (IsPlayer()) currentAssoc->speed = 1.0f; else currentAssoc->speed = 0.8f; } if (IsPlayer() && !nPlayerInComboMove && !fightWithWeapon) { if (curMove.comboFollowOnTime > 0.0f && m_fightButtonPressure != 0 && animTime > curMove.comboFollowOnTime) { m_lastFightMove = m_curFightMove; // Notice that it increases fight move index, because we're in combo! animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[++m_curFightMove].animId, 8.0f); animAssoc->SetFinishCallback(FinishFightMoveCB, this); animAssoc->SetCurrentTime(0.1f * animAssoc->hierarchy->totalLength); animAssoc->speed = 0.8f; m_fightButtonPressure = 0; nPlayerInComboMove = 1; } } } } else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && GetWeapon()->m_eWeaponType != WEAPONTYPE_BRASSKNUCKLE && !fightWithWeapon) { EndFight(ENDFIGHT_FAST); } else if (m_fightButtonPressure != 0) { if (!IsPlayer()) Say(SOUND_PED_ATTACK); if (m_curFightMove != FIGHTMOVE_IDLE) m_lastFightMove = m_curFightMove; m_curFightMove = IsPlayer() ? ChooseAttackPlayer(m_fightButtonPressure, fightWithWeapon) : ChooseAttackAI(m_fightButtonPressure, fightWithWeapon); if (m_curFightMove != FIGHTMOVE_IDLE) { animAssoc = CAnimManager::BlendAnimation(GetClump(), m_curFightMove < FIGHTMOVE_MELEE1 ? ASSOCGRP_STD : weaponInfo->m_AnimToPlay, tFightMoves[m_curFightMove].animId, 8.0f); if (weaponInfo->m_AnimToPlay != ASSOCGRP_KNIFE || m_curFightMove < FIGHTMOVE_MELEE1) { animAssoc->speed = 0.8f; } else { switch (GetWeapon()->m_eWeaponType) { case WEAPONTYPE_SCREWDRIVER: case WEAPONTYPE_KNIFE: animAssoc->speed = 1.05f; break; case WEAPONTYPE_GOLFCLUB: case WEAPONTYPE_NIGHTSTICK: case WEAPONTYPE_BASEBALLBAT: case WEAPONTYPE_HAMMER: case WEAPONTYPE_KATANA: animAssoc->speed = 0.8f; break; case WEAPONTYPE_CLEAVER: case WEAPONTYPE_MACHETE: animAssoc->speed = 0.9f; break; } } if (m_fightState == FIGHTSTATE_MOVE_FINISHED && animAssoc->currentTime != 0.0f) { animAssoc->SetRun(); if (!IsPlayer()) animAssoc->SetCurrentTime(0.0f); } if (IsPlayer()) animAssoc->SetCurrentTime(0.08f); animAssoc->SetFinishCallback(FinishFightMoveCB, this); m_fightButtonPressure = 0; } m_fightState = FIGHTSTATE_NO_MOVE; } else if (m_takeAStepAfterAttack && m_curFightMove != FIGHTMOVE_SHUFFLE_F #ifndef FIX_BUGS && CheckForPedsOnGroundToAttack(this, nil) == 4) { #else && CheckForPedsOnGroundToAttack(this, nil) == PED_IN_FRONT_OF_ATTACKER) { #endif m_lastFightMove = m_curFightMove; m_curFightMove = FIGHTMOVE_SHUFFLE_F; animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId); if (animAssoc) { animAssoc->SetCurrentTime(0.0f); animAssoc->blendDelta = 4.0f; animAssoc->SetRun(); } else { animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 32.0f); } animAssoc->SetFinishCallback(FinishFightMoveCB, this); m_fightState = FIGHTSTATE_NO_MOVE; m_fightButtonPressure = 0; m_takeAStepAfterAttack = false; } else if (m_takeAStepAfterAttack) { EndFight(ENDFIGHT_FAST); } else if (m_curFightMove == FIGHTMOVE_IDLE) { if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { EndFight(ENDFIGHT_NORMAL); } } else { m_lastFightMove = m_curFightMove; m_curFightMove = FIGHTMOVE_IDLE; if (IsPlayer()) m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500; else m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; } } int32 CPed::ChooseAttackAI(uint8 buttonPressure, bool fightWithWeapon) { eWeaponType weapon = GetWeapon()->m_eWeaponType; CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(weapon); if (!fightWithWeapon && weapon != WEAPONTYPE_UNARMED && weapon != WEAPONTYPE_BRASSKNUCKLE) { return FIGHTMOVE_PUNCH; } if (!m_pedInObjective) return FIGHTMOVE_IDLE; if (buttonPressure == 0) return FIGHTMOVE_IDLE; uint16 pedFeatures = m_pedStats->m_flags; bool punchOnly = !!(pedFeatures & STAT_PUNCH_ONLY); bool canRoundhouse = !!(pedFeatures & STAT_CAN_ROUNDHOUSE); bool canKneeHead = !!(pedFeatures & STAT_CAN_KNEE_HEAD); bool canKick = !!(pedFeatures & STAT_CAN_KICK); bool hasShoppingBags = !!(pedFeatures & STAT_SHOPPING_BAGS); CVector distVec(m_pedInObjective->GetPosition() - GetPosition()); float dist = distVec.Magnitude(); m_fRotationDest = CGeneral::LimitRadianAngle(distVec.Heading()); m_fRotationCur = m_fRotationDest; if (fightWithWeapon) { if (m_pedInObjective->OnGroundOrGettingUp()) { if (CGame::nastyGame && dist < 1.2f && !m_pedInObjective->IsPlayer() && (m_pedInObjective->m_nPedState == PED_DEAD || !m_pedInObjective->IsPedHeadAbovePos(-0.3f))) { if (weaponInfo->IsFlagSet(WEAPONFLAG_GROUND_2ND)) return FIGHTMOVE_MELEE2; if (weaponInfo->IsFlagSet(WEAPONFLAG_GROUND_3RD)) return FIGHTMOVE_MELEE3; return FIGHTMOVE_GROUNDKICK; } else { return FIGHTMOVE_IDLE; } } if (dist < 2.f) { if (m_curFightMove == FIGHTMOVE_MELEE1) { if (GetSecondFireAnim(weaponInfo)) return FIGHTMOVE_MELEE2; } if (m_curFightMove == FIGHTMOVE_MELEE2) { if (GetFinishingAttackAnim(weaponInfo)) return FIGHTMOVE_MELEE3; } return FIGHTMOVE_MELEE1; } return FIGHTMOVE_SHUFFLE_F; } if (!hasShoppingBags) { if (punchOnly) { if (dist < 1.4f) return FIGHTMOVE_PUNCH; } else { if (m_pedInObjective->OnGroundOrGettingUp()) { if (CGame::nastyGame && dist < 1.2f && !m_pedInObjective->IsPlayer() && (m_pedInObjective->m_nPedState == PED_DEAD || !m_pedInObjective->IsPedHeadAbovePos(-0.3f))) { return FIGHTMOVE_GROUNDKICK; } else { return FIGHTMOVE_IDLE; } } // LCS: removed //if (dist < 0.95f && canKneeHead) // return FIGHTMOVE_KNEE; if (dist < 1.4f) return FIGHTMOVE_PUNCH; if (dist < 2.f && canKick) { int nextMove = FIGHTMOVE_LONGKICK; if (canRoundhouse && CGeneral::GetRandomNumber() & 1) nextMove = FIGHTMOVE_ROUNDHOUSE; return nextMove; } } return FIGHTMOVE_SHUFFLE_F; } if (dist < 2.f) return FIGHTMOVE_ROUNDHOUSE; else return FIGHTMOVE_SHUFFLE_F; } int32 CPed::ChooseAttackPlayer(uint8 buttonPressure, bool fightWithWeapon) { CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); const float maxAttackDist = 2.7f; float weaponAttackDist = 2.0f; CPed *victimPed = nil; CPed *walkUpTo = nil; CPed *groundAttackDeadPed = nil; CPed *groundAttackAlivePed = nil; if (fightWithWeapon) weaponAttackDist = weaponInfo->m_fRange; bool willWalkUp = false; PedFightMoves choosenMove = FIGHTMOVE_IDLE; int numPedsWeCanReach = 0; if (m_takeAStepAfterAttack) willWalkUp = true; float groundAttackDeadAngle, groundAttackAliveAngle, walkAngle, victimAngle, distToVictim; for (int i = 0; i < m_numNearPeds; ++i) { CPed *nearPed = m_nearPeds[i]; CVector distVec(nearPed->GetPosition() - GetPosition()); float dist = distVec.Magnitude(); if (dist < maxAttackDist) { float nearPedAngle = CGeneral::LimitRadianAngle(distVec.Heading()); m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); float neededTurn = Abs(nearPedAngle - m_fRotationCur); if (neededTurn > PI) neededTurn = TWOPI - neededTurn; if (!nearPed->OnGroundOrGettingUp() && nearPed->m_nWaitState != WAITSTATE_SUN_BATHE_IDLE) { if (!willWalkUp || neededTurn <= DEGTORAD(45.0f)) { if (neededTurn <= DEGTORAD(30.0f) || nearPed->m_pedInObjective == this && (nearPed->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || nearPed->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS)) { if (dist < weaponAttackDist) { if (!victimPed || nearPed->m_attackTimer < victimPed->m_attackTimer && nearPed->m_attackTimer > CTimer::GetTimeInMilliseconds() - 100) { victimPed = nearPed; victimAngle = nearPedAngle; distToVictim = dist; } ++numPedsWeCanReach; } else { if (neededTurn < DEGTORAD(30.0f)) { walkUpTo = nearPed; walkAngle = nearPedAngle; } } } } } else if (CGame::nastyGame && dist < 1.2f && neededTurn < DEGTORAD(55.0f)) { if (!nearPed->DyingOrDead() || groundAttackDeadPed) { if (!nearPed->IsPedHeadAbovePos(-0.3f)) { groundAttackAlivePed = nearPed; groundAttackAliveAngle = nearPedAngle; } } else { groundAttackDeadPed = nearPed; groundAttackDeadAngle = nearPedAngle; } ++numPedsWeCanReach; } else if (dist > 1.4f && dist < maxAttackDist && neededTurn < DEGTORAD(30.0f)) { if (!walkUpTo) { walkUpTo = nearPed; walkAngle = nearPedAngle; } #ifdef FIX_BUGS if(dist < 2.1f) #endif ++numPedsWeCanReach; } } } if (victimPed) { float adjustedAngleDiff = victimAngle - m_fRotationCur + DEGTORAD(30.0f); if (adjustedAngleDiff < 0.0f) adjustedAngleDiff += TWOPI; int16 dir = Floor(adjustedAngleDiff / DEGTORAD(60.0f)); // Just focus on who we're fighting with, don't care peds on ground if (numPedsWeCanReach < 2 || fightWithWeapon) { float angleDiff = Abs(victimAngle - m_fRotationCur); if (angleDiff > PI) angleDiff = TWOPI - angleDiff; if (angleDiff < DEGTORAD(60.0f)) dir = 0; // forward } int16 randVal = CGeneral::GetRandomNumber() & 3; switch (dir) { case 0: // forward if (fightWithWeapon) { // LCS: removed //if (distToVictim < 0.95f - 0.2f && m_nPedState == PED_FIGHT) { // choosenMove = FIGHTMOVE_KNEE; //} else { if (GetWeapon()->m_eWeaponType == WEAPONTYPE_CLEAVER) { if (distToVictim < 0.85f * weaponInfo->m_fRange) choosenMove = FIGHTMOVE_MELEE1; else choosenMove = FIGHTMOVE_SHUFFLE_F; } else { float weaponRange = weaponInfo->m_fRange; if (distToVictim < 0.75f * weaponRange && GetWeapon()->m_eWeaponType != WEAPONTYPE_SCREWDRIVER) { if (m_lastFightMove == FIGHTMOVE_MELEE1 && GetFinishingAttackAnim(weaponInfo)) { choosenMove = FIGHTMOVE_MELEE2; } else if (m_lastFightMove == FIGHTMOVE_MELEE2 && GetFinishingAttackAnim(weaponInfo)) { choosenMove = FIGHTMOVE_MELEE3; } else { choosenMove = FIGHTMOVE_MELEE1; } } else if (distToVictim < weaponRange && GetFinishingAttackAnim(weaponInfo)) { choosenMove = FIGHTMOVE_MELEE3; } else { choosenMove = FIGHTMOVE_SHUFFLE_F; } } } // LCS: removed //} else if (distToVictim < 0.95f && m_nPedState == PED_FIGHT) { // choosenMove = FIGHTMOVE_KNEE; } else if (distToVictim < 1.4f) { // LCS: removed /*if (m_curFightMove == FIGHTMOVE_PUNCHJAB) { choosenMove = FIGHTMOVE_PUNCH; } else*/ if (m_curFightMove != FIGHTMOVE_PUNCH || randVal != 1) { //if (randVal == 2) choosenMove = FIGHTMOVE_PUNCH; //else // choosenMove = FIGHTMOVE_PUNCHJAB; } else { choosenMove = FIGHTMOVE_LONGKICK; } } else { choosenMove = FIGHTMOVE_LONGKICK; } break; /* LCS: removed case 1: choosenMove = FIGHTMOVE_FWDLEFT; break; case 2: choosenMove = FIGHTMOVE_BACKLEFT; break; case 3: choosenMove = FIGHTMOVE_BACKKICK; break; case 4: choosenMove = FIGHTMOVE_BACKRIGHT; break; */ default: choosenMove = FIGHTMOVE_FWDRIGHT; break; } // forward if (dir == 0) { m_fRotationDest = CGeneral::LimitRadianAngle(victimAngle); } else { m_fRotationDest = victimAngle - dir * DEGTORAD(60.0f); m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); } m_fRotationCur = m_fRotationDest; Say(SOUND_PED_ATTACK); } else if (groundAttackAlivePed || groundAttackDeadPed) { if (fightWithWeapon && weaponInfo->IsFlagSet(WEAPONFLAG_GROUND_2ND)) { choosenMove = FIGHTMOVE_MELEE2; } else if (fightWithWeapon && weaponInfo->IsFlagSet(WEAPONFLAG_GROUND_3RD)) { choosenMove = FIGHTMOVE_MELEE3; } else { choosenMove = FIGHTMOVE_GROUNDKICK; } if (groundAttackAlivePed) m_fRotationDest = groundAttackAliveAngle; else m_fRotationDest = groundAttackDeadAngle; m_fRotationCur = m_fRotationDest; m_lookTimer = 0; if (groundAttackAlivePed) SetLookFlag(groundAttackAlivePed, 1, 0); else SetLookFlag(groundAttackDeadPed, 1, 0); SetLookTimer(1500u); } else if (walkUpTo) { choosenMove = FIGHTMOVE_SHUFFLE_F; m_fRotationCur = m_fRotationDest = walkAngle; m_lookTimer = 0; SetLookFlag(walkUpTo, true); SetLookTimer(1500); } else if (fightWithWeapon) { // No enemy, fight with space if (GetWeapon()->m_eWeaponType == WEAPONTYPE_SCREWDRIVER) { choosenMove = FIGHTMOVE_MELEE3; } else { if (m_lastFightMove == FIGHTMOVE_MELEE1 && GetFinishingAttackAnim(weaponInfo)) { choosenMove = FIGHTMOVE_MELEE2; } else if (m_lastFightMove == FIGHTMOVE_MELEE2 && GetFinishingAttackAnim(weaponInfo)) { choosenMove = FIGHTMOVE_MELEE3; } else { choosenMove = FIGHTMOVE_MELEE1; } } } else { // Max number GetRandomNumberInRange returns is max-1 #ifdef FIX_BUGS switch (CGeneral::GetRandomNumberInRange(0,4)) { #else switch (CGeneral::GetRandomNumberInRange(0,3)) { #endif // LCS: hack hack // case 0: // choosenMove = FIGHTMOVE_PUNCHJAB; // break; default: case 1: choosenMove = FIGHTMOVE_PUNCH; break; case 2: choosenMove = FIGHTMOVE_LONGKICK; break; // case 3: // choosenMove = FIGHTMOVE_KNEE; // break; // default: // break; } } return choosenMove; } void CPed::EndFight(uint8 endType) { if (m_nPedState != PED_FIGHT) return; m_curFightMove = FIGHTMOVE_NULL; RestorePreviousState(); CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_FIGHT_IDLE); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_MELEE_IDLE_FIGHTMODE); if (animAssoc) animAssoc->flags |= ASSOC_DELETEFADEDOUT; switch (endType) { case ENDFIGHT_NORMAL: CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 8.0f); CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_FIGHT_2IDLE, 8.0f); break; case ENDFIGHT_WITH_A_STEP: CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 1.0f); CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_STARTWALK, 8.0f); break; case ENDFIGHT_FAST: CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 8.0f); CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_FIGHT_2IDLE, 8.0f)->speed = 2.0f; break; default: break; } m_nWaitTimer = 0; } void CPed::PlayHitSound(CPed *hitTo) { #if 0 // LCS: temporarily removed // That was very complicated to reverse for me... // First index is our fight move ID (from 1 to 17, total 17), second is the one of we fight with (from 18 to 27, total 10). enum { S37 = SOUND_FIGHT_37, S38 = SOUND_FIGHT_38, S39 = SOUND_FIGHT_39, S40 = SOUND_FIGHT_40, S41 = SOUND_FIGHT_41, S42 = SOUND_FIGHT_42, S43 = SOUND_FIGHT_43, S44 = SOUND_FIGHT_44, S45 = SOUND_FIGHT_45, S46 = SOUND_FIGHT_46, S47 = SOUND_FIGHT_47, S48 = SOUND_FIGHT_48, NO_SND = SOUND_NO_SOUND }; const uint16 hitSoundsByFightMoves[17][10] = { { S37, S46, S41, S41, S46, S46, S40, S41, S43, S40 }, { NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND }, { NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND, NO_SND }, { S46, S46, S46, S46, S37, S47, S37, S38, S43, S38 }, { S46, S46, S46, S46, S46, S46, S40, S41, S43, S46 }, { S46, S46, S46, S46, S46, S46, S40, S41, S43, S40 }, { S46, S46, S46, S46, S46, S46, S40, S41, S43, S40 }, { S46, S46, S37, S46, S37, S47, S40, S47, S43, S37 }, { S46, S46, S46, S46, S46, S46, S43, S44, S43, S43 }, { S37, S46, S46, S46, S38, S47, S40, S38, S43, S46 }, { S46, S37, S46, S37, S39, S46, S40, S39, S43, S37 }, { S46, S37, S46, S46, S38, S47, S40, S38, S43, S46 }, { S37, S37, S46, S46, S38, S47, S48, S38, S43, S37 }, { S46, S46, S46, S46, S37, S46, S40, S38, S43, S46 }, { S46, S46, S46, S37, S39, S46, S40, S39, S43, S46 }, { S37, S46, S46, S46, S37, S46, S40, S37, S43, S46 }, { S43, S43, S43, S43, S43, S43, S43, S43, S43, S43 } }; eWeaponType weapon = GetWeapon()->m_eWeaponType; CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(weapon); if (weaponInfo->m_AnimToPlay == ASSOCGRP_KNIFE) { if (m_curFightMove >= FIGHTMOVE_MELEE1) { if (m_curFightMove == FIGHTMOVE_MELEE3) { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, (weapon << 8) | ENTITY_TYPE_PED); } else { DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_KNIFE_ATTACK, (weapon << 8) | ENTITY_TYPE_PED); } return; } } // This is why first dimension is between FightMove 1 and 17. if (m_curFightMove <= FIGHTMOVE_NULL || m_curFightMove >= FIGHTMOVE_HITFRONT) return; uint16 soundId; // And this is why second dimension is between 18 and 27. if (hitTo->m_curFightMove > FIGHTMOVE_GROUNDKICK && hitTo->m_curFightMove < FIGHTMOVE_IDLE2NORM) { soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][hitTo->m_curFightMove - FIGHTMOVE_HITFRONT]; } else { if (hitTo->m_nPedState == PED_DEAD || hitTo->UseGroundColModel()) { soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITONFLOOR - FIGHTMOVE_HITFRONT]; } else { soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITFRONT - FIGHTMOVE_HITFRONT]; } } if (soundId != NO_SND) DMAudio.PlayOneShot(m_audioEntityId, soundId, (weapon << 8) | ENTITY_TYPE_PED); #endif } bool CPed::FightStrike(CVector &touchedNodePos, bool fightWithWeapon) { CColModel *hisCol; CVector attackDistance; float maxDistanceToBeat; CPed *nearPed; CVector extendedTouchPoint; CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); float radius = tFightMoves[m_curFightMove].strikeRadius; if (fightWithWeapon) radius = weaponInfo->m_fRadius; if (m_fightState == FIGHTSTATE_JUST_ATTACKED) return false; if (this == FindPlayerPed() && fightWithWeapon && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) CGlass::BreakGlassPhysically(touchedNodePos, radius); for (int i = 0; i < m_numNearPeds; i++) { int8 pedFound = 0; nearPed = m_nearPeds[i]; if (!fightWithWeapon && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && GetWeapon()->m_eWeaponType != WEAPONTYPE_BRASSKNUCKLE) maxDistanceToBeat = nearPed->GetBoundRadius() + radius + 0.1f; else maxDistanceToBeat = nearPed->GetBoundRadius() + radius; if ((nearPed->bUsesCollision || nearPed->m_nPedState == PED_DEAD) && (m_pedInObjective != FindPlayerPed() || nearPed == FindPlayerPed())) { CVector nearPedCentre; // Have to animate a skinned clump because the initial col model is useless hisCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(nearPed->GetModelIndex()))->AnimatePedColModelSkinnedWorld(nearPed->GetClump()); nearPed->GetBoundCentre(nearPedCentre); CVector potentialAttackDistance = nearPedCentre - touchedNodePos; // He can beat us if (sq(maxDistanceToBeat) > potentialAttackDistance.MagnitudeSqr()) { for (int j = 0; j < hisCol->numSpheres; j++) { attackDistance = hisCol->spheres[j].center; attackDistance -= touchedNodePos; CColSphere *hisPieces = hisCol->spheres; maxDistanceToBeat = hisPieces[j].radius + radius; // We can beat him too if (sq(maxDistanceToBeat) > attackDistance.MagnitudeSqr()) { FightHitPed(nearPed, touchedNodePos, attackDistance, hisPieces[j].piece); pedFound = 1; break; } } } if (!pedFound && !fightWithWeapon) { extendedTouchPoint = touchedNodePos - GetPosition(); if (DotProduct(touchedNodePos - GetPosition(), nearPed->GetPosition() - GetPosition()) > 0.f) { if (m_curFightMove == FIGHTMOVE_GROUNDKICK) { extendedTouchPoint += tFightMoves[FIGHTMOVE_GROUNDKICK].extendReachMultiplier * GetForward(); } else { extendedTouchPoint.x *= tFightMoves[m_curFightMove].extendReachMultiplier; extendedTouchPoint.y *= tFightMoves[m_curFightMove].extendReachMultiplier; } pedFound = -1; extendedTouchPoint += GetPosition(); } } if (pedFound == -1) { CVector nearPedCentre = nearPed->GetBoundCentre(); if (sq(maxDistanceToBeat) > (nearPedCentre - extendedTouchPoint).MagnitudeSqr()) { for (int j = 0; j < hisCol->numSpheres; j++) { attackDistance = hisCol->spheres[j].center; attackDistance -= extendedTouchPoint; CColSphere* hisPieces = hisCol->spheres; float maxDistanceToBeat2 = hisPieces[j].radius + tFightMoves[m_curFightMove].strikeRadius; // We can beat him too if (sq(maxDistanceToBeat2) > attackDistance.MagnitudeSqr()) { FightHitPed(nearPed, extendedTouchPoint, attackDistance, hisPieces[j].piece); break; } } } } } } if (m_fightState == FIGHTSTATE_NO_MOVE) m_fightState = FIGHTSTATE_1; m_vecHitLastPos = touchedNodePos; return false; } void CPed::FightHitPed(CPed *victim, CVector &touchPoint, CVector &dir, int16 piece) { if (victim->IsPlayer() && victim->m_nPedState == PED_GETUP) return; CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); bool fightingWithWeapon = false; int damageMult = tFightMoves[m_curFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1; if (weaponInfo->IsFlagSet(WEAPONFLAG_FIGHTMODE)) { fightingWithWeapon = true; if (m_curFightMove >= FIGHTMOVE_MELEE1) { damageMult = weaponInfo->m_nDamage; if (m_curFightMove == FIGHTMOVE_MELEE3 && GetWeapon()->m_eWeaponType != WEAPONTYPE_SCREWDRIVER) damageMult *= 5; } } if (IsPlayer()) { if (((CPlayerPed*)this)->m_bAdrenalineActive) damageMult = 20; } else if (!fightingWithWeapon) { damageMult *= m_pedStats->m_attackStrength; } float oldVictimHealth = victim->m_fHealth; CVector bloodPos = 0.5f * dir + touchPoint; CVector2D diff(GetPosition() - victim->GetPosition()); int direction = victim->GetLocalDirection(diff); bool brassKnucklePunch = false; if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BRASSKNUCKLE) { // LCS: removed if (/*m_curFightMove == FIGHTMOVE_PUNCHHOOK || m_curFightMove == FIGHTMOVE_PUNCHJAB || m_curFightMove == FIGHTMOVE_BACKLEFT || m_curFightMove == FIGHTMOVE_STDPUNCH ||*/ m_curFightMove == FIGHTMOVE_PUNCH) { brassKnucklePunch = true; damageMult *= 1.5f; } } victim->ReactToAttack(this); // Mostly unused. if > 5, ANIM_HIT_BIGSTEP will be run, that's it. int unk2; if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && GetWeapon()->m_eWeaponType != WEAPONTYPE_BRASSKNUCKLE && !victim->IsPlayer() && !fightingWithWeapon) unk2 = 101; else unk2 = damageMult; victim->StartFightDefend(direction, tFightMoves[m_curFightMove].hitLevel, unk2); PlayHitSound(victim); m_fightState = FIGHTSTATE_JUST_ATTACKED; RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId)->speed = 0.6f; if (!victim->DyingOrDead()) { if(fightingWithWeapon) victim->InflictDamage(this, GetWeapon()->m_eWeaponType, damageMult, (ePedPieceTypes)piece, direction); else victim->InflictDamage(this, WEAPONTYPE_UNARMED, damageMult * 3.0f, (ePedPieceTypes)piece, direction); } if (CGame::nastyGame && weaponInfo->m_AnimToPlay == ASSOCGRP_KNIFE && m_curFightMove >= FIGHTMOVE_MELEE1 && victim->GetIsOnScreen()) { static float particleRightLen = 0.05f; static float particleUpLen = 0.05f; // Just for particles. We will restore it below. dir /= (20.0f * dir.Magnitude()); if (m_curFightMove == FIGHTMOVE_MELEE1) { float rightMult = -particleRightLen; dir += particleUpLen * GetUp() + rightMult * GetRight(); } else if (m_curFightMove == FIGHTMOVE_MELEE2) { float upMult = 2.0f * particleUpLen; dir += particleRightLen * GetRight() + upMult * GetUp(); } CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, dir, nil, 0.0f, 0, 0, 0, 0); CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, dir, nil, 0.0f, 0, 0, 0, 0); if (IsPlayer()) { CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, dir, nil, 0.0f, 0, 0, 0, 0); CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, dir, nil, 0.0f, 0, 0, 0, 0); } if (!(CGeneral::GetRandomNumber() & 3)) { CParticle::AddParticle(PARTICLE_TEST, bloodPos, dir, nil, 0.0f, 0, 0, 0, 0); } } else if (CGame::nastyGame && (tFightMoves[m_curFightMove].hitLevel > HITLEVEL_MEDIUM || fightingWithWeapon) && victim->GetIsOnScreen()) { // Just for particles. We will restore it below. dir /= (10.0f * dir.Magnitude()); for (int i = 0; i < 4; i++) { CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir, nil, 0.0f, 0, 0, 0, 0); } } eWeaponType weaponType = GetWeapon()->m_eWeaponType; if (!fightingWithWeapon) { if (!victim->OnGround()) { float curVictimHealth = victim->m_fHealth; if (curVictimHealth > 0.0f && (curVictimHealth < 30.0f && oldVictimHealth > 30.0f || weaponType != WEAPONTYPE_UNARMED && weaponType != WEAPONTYPE_BRASSKNUCKLE && IsPlayer() || victim->m_pedStats->m_flags & STAT_ONE_HIT_KNOCKDOWN || brassKnucklePunch)) { victim->SetFall(0, (AnimationId)(direction + ANIM_STD_HIGHIMPACT_FRONT), 0); if (victim->m_nPedState == PED_FALL) victim->bIsStanding = false; } } } if (victim->m_nPedState == PED_DIE || !victim->bIsStanding) { dir = victim->GetPosition() - GetPosition(); dir.Normalise(); dir.z = 1.0f; victim->bIsStanding = false; float moveMult; if (fightingWithWeapon) { moveMult = Min(damageMult * 0.02f, 1.0f); } else if (m_curFightMove == FIGHTMOVE_GROUNDKICK) { moveMult = Min(damageMult * 0.6f, 4.0f); } else { if (victim->m_nPedState != PED_DIE || damageMult >= 20) { moveMult = damageMult; } else { moveMult = Min(damageMult * 2.0f, 14.0f); } } victim->ApplyMoveForce(moveMult * 0.6 * dir); } if (weaponType != WEAPONTYPE_KNIFE && weaponType != WEAPONTYPE_MACHETE && weaponType != WEAPONTYPE_KATANA && weaponType != WEAPONTYPE_CHAINSAW) { if (victim->m_nPedType == PEDTYPE_COP) CEventList::RegisterEvent(EVENT_ASSAULT_POLICE, EVENT_ENTITY_PED, victim, this, 2000); else CEventList::RegisterEvent(EVENT_ASSAULT, EVENT_ENTITY_PED, victim, this, 2000); } else { if (victim->m_nPedType == PEDTYPE_COP) CEventList::RegisterEvent(EVENT_ASSAULT_NASTYWEAPON_POLICE, EVENT_ENTITY_PED, victim, this, 2000); else CEventList::RegisterEvent(EVENT_ASSAULT_NASTYWEAPON, EVENT_ENTITY_PED, victim, this, 2000); } } void CPed::FinishFightMoveCB(CAnimBlendAssociation *animAssoc, void *arg) { CPed *ped = (CPed*)arg; if (tFightMoves[ped->m_curFightMove].animId == animAssoc->animId) { ped->m_fightState = FIGHTSTATE_MOVE_FINISHED; animAssoc->blendDelta = -1000.0f; } } void CPed::LoadFightData(void) { float startFireTime, endFireTime, comboFollowOnTime, strikeRadius, extendReachMultiplier; int damage, flags; char line[256], moveName[32], animName[32], hitLevel; int moveId = 0; CAnimBlendAssociation *animAssoc; size_t bp, buflen; int lp, linelen; buflen = CFileMgr::LoadFile("DATA\\fistfite.dat", work_buff, sizeof(work_buff), "r"); for (bp = 0; bp < buflen; ) { // read file line by line for (linelen = 0; work_buff[bp] != '\n' && bp < buflen; bp++) { line[linelen++] = work_buff[bp]; } bp++; line[linelen] = '\0'; // skip white space for (lp = 0; line[lp] <= ' ' && line[lp] != '\0'; lp++); if (line[lp] == '\0' || line[lp] == '#') continue; sscanf( &line[lp], "%s %f %f %f %f %f %c %s %d %d", moveName, &startFireTime, &endFireTime, &comboFollowOnTime, &strikeRadius, &extendReachMultiplier, &hitLevel, animName, &damage, &flags); if (strncmp(moveName, "ENDWEAPONDATA", 13) == 0) return; tFightMoves[moveId].startFireTime = startFireTime / 30.0f; tFightMoves[moveId].endFireTime = endFireTime / 30.0f; tFightMoves[moveId].comboFollowOnTime = comboFollowOnTime / 30.0f; tFightMoves[moveId].strikeRadius = strikeRadius; tFightMoves[moveId].extendReachMultiplier = extendReachMultiplier; tFightMoves[moveId].damage = damage; tFightMoves[moveId].flags = flags; switch (hitLevel) { case 'G': tFightMoves[moveId].hitLevel = HITLEVEL_GROUND; break; case 'H': tFightMoves[moveId].hitLevel = HITLEVEL_HIGH; break; case 'L': tFightMoves[moveId].hitLevel = HITLEVEL_LOW; break; case 'M': tFightMoves[moveId].hitLevel = HITLEVEL_MEDIUM; break; case 'N': tFightMoves[moveId].hitLevel = HITLEVEL_NULL; break; default: break; } if (strcmp(animName, "default") != 0) { if (strcmp(animName, "null") != 0) { animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animName); tFightMoves[moveId].animId = (AnimationId)animAssoc->animId; } else { tFightMoves[moveId].animId = ANIM_STD_WALK; } } moveId++; } } void CPed::SetInvestigateEvent(eEventType event, CVector2D pos, float distanceToCountDone, uint16 time, float angle) { if (!IsPedInControl() || CharCreatedBy == MISSION_CHAR) return; SetStoredState(); bFindNewNodeAfterStateRestore = false; SetPedState(PED_INVESTIGATE); m_chatTimer = CTimer::GetTimeInMilliseconds() + time; m_eventType = event; m_eventOrThreat = pos; m_distanceToCountSeekDone = distanceToCountDone; m_fAngleToEvent = angle; if (m_eventType >= EVENT_ICECREAM) m_lookTimer = 0; else CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_HANDSCOWER, 4.0f); } void CPed::InvestigateEvent(void) { CAnimBlendAssociation *animAssoc; AnimationId animToPlay; AssocGroupId animGroup; if (m_nWaitState == WAITSTATE_TURN180) return; if (CTimer::GetTimeInMilliseconds() > m_chatTimer) { if (m_chatTimer) { if (m_eventType < EVENT_UNK) SetWaitState(WAITSTATE_TURN180, nil); m_chatTimer = 0; } else { ClearInvestigateEvent(); } return; } CVector2D vecDist = m_eventOrThreat - GetPosition(); float distSqr = vecDist.MagnitudeSqr(); if (sq(m_distanceToCountSeekDone) >= distSqr) { m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(vecDist.x, vecDist.y, 0.0f, 0.0f); SetMoveState(PEDMOVE_STILL); switch (m_eventType) { case EVENT_DEAD_PED: case EVENT_HIT_AND_RUN: case EVENT_HIT_AND_RUN_COP: if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_ROADCROSS); if (animAssoc) { animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; if (m_pEventEntity) SetLookFlag(m_pEventEntity, true); SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); } else if (CGeneral::GetRandomNumber() & 3) { ClearLookFlag(); CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_ROADCROSS, 4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); Say(SOUND_PED_CHAT_EVENT); } else { ClearInvestigateEvent(); } } break; case EVENT_FIRE: case EVENT_EXPLOSION: if (bHasACamera && CTimer::GetTimeInMilliseconds() > m_lookTimer) { animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE_CAM); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE); if (animAssoc && animAssoc->animId == ANIM_STD_IDLE_CAM) { CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, 4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); } else if (CGeneral::GetRandomNumber() & 3) { CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_IDLE_CAM, 4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(2500, 5000)); if (!CGame::germanGame) Say(SOUND_PED_CHAT_EVENT); } else { m_chatTimer = 0; } } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE_HBHB); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_XPRESS_SCRATCH); if (animAssoc && animAssoc->animId == ANIM_STD_IDLE) { if (CGeneral::GetRandomNumber() & 1) animToPlay = ANIM_STD_IDLE_HBHB; else animToPlay = ANIM_STD_XPRESS_SCRATCH; CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); } else if (animAssoc && animAssoc->animId == ANIM_STD_IDLE_HBHB) { animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; if (CGeneral::GetRandomNumber() & 1) { animToPlay = ANIM_STD_IDLE; animGroup = m_animGroup; } else { animToPlay = ANIM_STD_XPRESS_SCRATCH; animGroup = ASSOCGRP_STD; } CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); } else { if (CGeneral::GetRandomNumber() & 1) { animToPlay = ANIM_STD_IDLE; animGroup = m_animGroup; } else { animToPlay = ANIM_STD_IDLE_HBHB; animGroup = ASSOCGRP_STD; } CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); } if (!CGame::germanGame) Say(SOUND_PED_CHAT_EVENT); } break; case EVENT_ICECREAM: case EVENT_SHOPSTALL: m_fRotationDest = m_fAngleToEvent; if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { if (m_lookTimer) { animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_ROADCROSS); if (animAssoc) { animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; if (m_eventType == EVENT_ICECREAM) animToPlay = ANIM_STD_CHAT; else animToPlay = ANIM_STD_XPRESS_SCRATCH; CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay,4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); } else { animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CHAT); if (animAssoc) { animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; ClearInvestigateEvent(); } else { animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_XPRESS_SCRATCH); if (animAssoc) { animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; } ClearInvestigateEvent(); } } } else { CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_ROADCROSS, 4.0f); SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); } } break; default: return; } } else { m_vecSeekPos.x = m_eventOrThreat.x; m_vecSeekPos.y = m_eventOrThreat.y; m_vecSeekPos.z = GetPosition().z; Seek(); if (m_eventType < EVENT_ICECREAM) { if (sq(5.0f + m_distanceToCountSeekDone) < distSqr) { SetMoveState(PEDMOVE_RUN); return; } } if (m_eventType <= EVENT_EXPLOSION || m_eventType >= EVENT_SHOPSTALL) { SetMoveState(PEDMOVE_WALK); return; } if (distSqr > sq(1.2f)) { SetMoveState(PEDMOVE_WALK); return; } bool willStandStill = false; for (int i = 0; i < m_numNearPeds; i++) { if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < sq(0.4f)) { SetMoveState(PEDMOVE_STILL); willStandStill = true; break; } } if (!willStandStill) SetMoveState(PEDMOVE_WALK); } } void CPed::ClearInvestigateEvent(void) { CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_ROADCROSS); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_XPRESS_SCRATCH); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_IDLE_HBHB); if (!animAssoc) animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CHAT); if (animAssoc) { animAssoc->blendDelta = -8.0f; animAssoc->flags |= ASSOC_DELETEFADEDOUT; } if (m_eventType > EVENT_EXPLOSION) m_chatTimer = CTimer::GetTimeInMilliseconds() + 15000; bGonnaInvestigateEvent = false; m_pEventEntity = nil; ClearLookFlag(); RestorePreviousState(); if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) SetMoveState(PEDMOVE_WALK); } bool CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPieceTypes pedPiece, uint8 direction) { CPlayerPed *player = FindPlayerPed(); float dieDelta = 4.0f; float dieSpeed = 0.0f; AnimationId dieAnim = ANIM_STD_KO_FRONT; bool headShot = false; bool willLinger = false; int random; if (damagedBy == FindPlayerPed() && damagedBy != this && damage > 3.0f) ++CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel; if (player == this) { if (!player->m_bCanBeDamaged) return false; if (damagedBy && damagedBy->IsPed() && ((CPed*)damagedBy)->m_nPedType == PEDTYPE_GANG7) return false; if ((method == WEAPONTYPE_FLAMETHROWER || method == WEAPONTYPE_MOLOTOV) && CWorld::Players[CWorld::PlayerInFocus].m_bFireproof) return false; player->AnnoyPlayerPed(false); } if (DyingOrDead()) return false; if (method == WEAPONTYPE_DROWNING && !bDrownsInWater) return false; if (!bUsesCollision && (!bInVehicle || m_nPedState != PED_DRIVING) && method != WEAPONTYPE_DROWNING) return false; if (bOnlyDamagedByPlayer && damagedBy != player && damagedBy != FindPlayerVehicle() && method != WEAPONTYPE_DROWNING && method != WEAPONTYPE_EXPLOSION) return false; float healthImpact; if (IsPlayer()) healthImpact = damage * 0.33f; else healthImpact = damage * m_pedStats->m_defendWeakness; if (!IsPlayer() && (method == WEAPONTYPE_SCREWDRIVER || method == WEAPONTYPE_KNIFE || (method >= WEAPONTYPE_CLEAVER && method <= WEAPONTYPE_CHAINSAW))) m_bleedCounter = 200; bool detectDieAnim = true; if (m_nPedState == PED_GETUP) { if (!IsPedHeadAbovePos(-0.3f)) { if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) dieAnim = ANIM_STD_HIT_FLOOR_FRONT; else dieAnim = ANIM_STD_HIT_FLOOR; dieDelta *= 2.0f; dieSpeed = 0.5f; detectDieAnim = false; } } else if (m_nPedState == PED_FALL) { CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_PARTIAL); if (!fallAssoc || fallAssoc->IsRunning()) { if (fallAssoc && fallAssoc->blendDelta >= 0.0f) dieAnim = ANIM_STD_NUM; else dieAnim = ANIM_STD_KO_FRONT; } else { if (fallAssoc->flags & ASSOC_FRONTAL) dieAnim = ANIM_STD_HIT_FLOOR_FRONT; else dieAnim = ANIM_STD_HIT_FLOOR; dieDelta *= 2.0f; dieSpeed = 0.5f; } detectDieAnim = false; } if (detectDieAnim) { switch (method) { case WEAPONTYPE_UNARMED: case WEAPONTYPE_BRASSKNUCKLE: if (bMeleeProof) return false; if (m_nPedState == PED_FALL) { if (IsPedHeadAbovePos(-0.3f)) { dieAnim = ANIM_STD_NUM; } else { if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) dieAnim = ANIM_STD_HIT_FLOOR_FRONT; else dieAnim = ANIM_STD_HIT_FLOOR; dieDelta = dieDelta * 2.0f; dieSpeed = 0.5f; } } else { switch (direction) { case 0: dieAnim = ANIM_STD_HIGHIMPACT_FRONT; break; case 1: dieAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 2: dieAnim = ANIM_STD_HIGHIMPACT_BACK; break; case 3: dieAnim = ANIM_STD_HIGHIMPACT_RIGHT; break; default: break; } } break; case WEAPONTYPE_SCREWDRIVER: case WEAPONTYPE_GOLFCLUB: case WEAPONTYPE_NIGHTSTICK: case WEAPONTYPE_KNIFE: case WEAPONTYPE_BASEBALLBAT: case WEAPONTYPE_HAMMER: case WEAPONTYPE_CLEAVER: case WEAPONTYPE_MACHETE: case WEAPONTYPE_KATANA: case WEAPONTYPE_CHAINSAW: if (bMeleeProof) return false; if (method != WEAPONTYPE_KATANA || damagedBy != FindPlayerPed() || FindPlayerPed()->m_nPedState != PED_FIGHT || FindPlayerPed()->m_curFightMove != FIGHTMOVE_MELEE1 && FindPlayerPed()->m_curFightMove != FIGHTMOVE_MELEE2 || CGeneral::GetRandomNumber() & 3) { if (m_nPedState == PED_FALL) { if (IsPedHeadAbovePos(-0.3f)) { dieAnim = ANIM_STD_NUM; } else { if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) dieAnim = ANIM_STD_HIT_FLOOR_FRONT; else dieAnim = ANIM_STD_HIT_FLOOR; dieDelta = dieDelta * 2.0f; dieSpeed = 0.5f; } } else if (damagedBy != FindPlayerPed() || FindPlayerPed()->m_curFightMove != FIGHTMOVE_MELEE2) { if (damagedBy != FindPlayerPed() || FindPlayerPed()->m_curFightMove != FIGHTMOVE_MELEE3) { switch (direction) { case 0: dieAnim = ANIM_STD_HIGHIMPACT_FRONT; break; case 1: dieAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 2: dieAnim = ANIM_STD_HIGHIMPACT_BACK; break; case 3: dieAnim = ANIM_STD_HIGHIMPACT_RIGHT; break; default: break; } } else { dieAnim = ANIM_STD_KO_SHOT_STOMACH; } } else { dieAnim = ANIM_STD_KO_SHOT_FACE; } } else { dieAnim = ANIM_STD_KO_SHOT_FACE; RemoveBodyPart(PED_HEAD, direction); headShot = true; willLinger = true; } break; case WEAPONTYPE_COLT45: case WEAPONTYPE_SHOTGUN: case WEAPONTYPE_STUBBY_SHOTGUN: case WEAPONTYPE_SPAS12_SHOTGUN: case WEAPONTYPE_TEC9: case WEAPONTYPE_UZI: case WEAPONTYPE_SILENCED_INGRAM: case WEAPONTYPE_MP5: case WEAPONTYPE_M4: case WEAPONTYPE_RUGER: case WEAPONTYPE_SNIPERRIFLE: case WEAPONTYPE_LASERSCOPE: case WEAPONTYPE_M60: case WEAPONTYPE_MINIGUN: case WEAPONTYPE_UZI_DRIVEBY: if (bBulletProof) return false; bool dontRemoveLimb; if (IsPlayer() || bNoCriticalHits) dontRemoveLimb = true; else if (method != WEAPONTYPE_M4 && method != WEAPONTYPE_RUGER && method != WEAPONTYPE_SNIPERRIFLE && method != WEAPONTYPE_LASERSCOPE) { if (method == WEAPONTYPE_SHOTGUN) dontRemoveLimb = CGeneral::GetRandomNumber() & 7; else dontRemoveLimb = CGeneral::GetRandomNumber() & 15; } else dontRemoveLimb = false; if (dontRemoveLimb) { if (method == WEAPONTYPE_SHOTGUN) { switch (direction) { case 0: dieAnim = ANIM_STD_HIGHIMPACT_FRONT; break; case 1: dieAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 2: dieAnim = ANIM_STD_HIGHIMPACT_BACK; break; case 3: dieAnim = ANIM_STD_HIGHIMPACT_RIGHT; break; default: break; } } else dieAnim = ANIM_STD_KO_FRONT; willLinger = false; } else { switch (pedPiece) { case PEDPIECE_TORSO: willLinger = false; dieAnim = ANIM_STD_KO_FRONT; break; case PEDPIECE_MID: willLinger = false; dieAnim = ANIM_STD_KO_SHOT_STOMACH; break; case PEDPIECE_LEFTARM: dieAnim = ANIM_STD_KO_SHOT_ARM_L; RemoveBodyPart(PED_UPPERARML, direction); willLinger = true; break; case PEDPIECE_RIGHTARM: dieAnim = ANIM_STD_KO_SHOT_ARM_R; RemoveBodyPart(PED_UPPERARMR, direction); willLinger = true; break; case PEDPIECE_LEFTLEG: dieAnim = ANIM_STD_KO_SHOT_LEG_L; RemoveBodyPart(PED_UPPERLEGL, direction); willLinger = true; break; case PEDPIECE_RIGHTLEG: dieAnim = ANIM_STD_KO_SHOT_LEG_R; RemoveBodyPart(PED_UPPERLEGR, direction); willLinger = true; break; case PEDPIECE_HEAD: dieAnim = ANIM_STD_KO_SHOT_FACE; RemoveBodyPart(PED_HEAD, direction); headShot = true; willLinger = true; break; default: break; } } break; case WEAPONTYPE_GRENADE: case WEAPONTYPE_ROCKETLAUNCHER: case WEAPONTYPE_EXPLOSION: if (bExplosionProof) return false; if (CGame::nastyGame && !IsPlayer() && !bInVehicle && 1.0f + healthImpact > m_fArmour + m_fHealth) { random = CGeneral::GetRandomNumber(); if (random & 1) RemoveBodyPart(PED_UPPERARML, direction); if (random & 2) RemoveBodyPart(PED_UPPERLEGR, direction); if (random & 4) RemoveBodyPart(PED_HEAD, direction); if (random & 8) RemoveBodyPart(PED_UPPERARMR, direction); if (random & 0x10) RemoveBodyPart(PED_UPPERLEGL, direction); if (bBodyPartJustCameOff) willLinger = true; } // fall through case WEAPONTYPE_MOLOTOV: if (bExplosionProof) return false; switch (direction) { case 0: dieAnim = ANIM_STD_HIGHIMPACT_FRONT; break; case 1: dieAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 2: dieAnim = ANIM_STD_HIGHIMPACT_BACK; break; case 3: dieAnim = ANIM_STD_HIGHIMPACT_RIGHT; break; default: break; } break; case WEAPONTYPE_FLAMETHROWER: if (bFireProof) return false; dieAnim = ANIM_STD_KO_FRONT; break; case WEAPONTYPE_RAMMEDBYCAR: case WEAPONTYPE_RUNOVERBYCAR: if (bCollisionProof) return false; random = CGeneral::GetRandomNumber() & 3; switch (random) { case 0: if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) && (pedPiece != PEDPIECE_MID || random != 1)) { if (pedPiece == PEDPIECE_RIGHTARM && random > 1 || pedPiece == PEDPIECE_MID && random == 2) dieAnim = ANIM_STD_HIGHIMPACT_RIGHT; else dieAnim = ANIM_STD_HIGHIMPACT_FRONT; } else dieAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 1: if (m_nPedState == PED_DIVE_AWAY) dieAnim = ANIM_STD_SPINFORWARD_LEFT; else dieAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 2: if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) && (pedPiece != PEDPIECE_MID || random != 1)) { if ((pedPiece != PEDPIECE_RIGHTARM || random <= 1) && (pedPiece != PEDPIECE_MID || random != 2)) { dieAnim = ANIM_STD_HIGHIMPACT_BACK; } else { dieAnim = ANIM_STD_SPINFORWARD_RIGHT; } } else dieAnim = ANIM_STD_SPINFORWARD_LEFT; break; case 3: if (m_nPedState == PED_DIVE_AWAY) dieAnim = ANIM_STD_SPINFORWARD_RIGHT; else dieAnim = ANIM_STD_HIGHIMPACT_RIGHT; break; default: break; } if (damagedBy && pedPiece != PEDPIECE_TORSO) { CVehicle *vehicle = (CVehicle*)damagedBy; if (method == WEAPONTYPE_RAMMEDBYCAR) { float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); dieDelta = 8.0f * vehSpeed + 4.0f; } else { float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); dieDelta = 12.0f * vehSpeed + 4.0f; dieSpeed = 16.0f * vehSpeed + 1.0f; } } break; case WEAPONTYPE_DROWNING: dieAnim = ANIM_STD_DROWN; break; case WEAPONTYPE_FALL: if (bCollisionProof) return false; switch (direction) { case 0: dieAnim = ANIM_STD_HIGHIMPACT_FRONT; break; case 1: dieAnim = ANIM_STD_HIGHIMPACT_LEFT; break; case 2: dieAnim = ANIM_STD_HIGHIMPACT_BACK; break; case 3: dieAnim = ANIM_STD_HIGHIMPACT_RIGHT; break; default: break; } break; default: break; } } if (m_fArmour != 0.0f && method != WEAPONTYPE_DROWNING) { if (player == this) CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds(); if (healthImpact < m_fArmour) { m_fArmour = m_fArmour - healthImpact; healthImpact = 0.0f; } else { healthImpact = healthImpact - m_fArmour; m_fArmour = 0.0f; } } if (healthImpact != 0.0f) { if (player == this) CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss = CTimer::GetTimeInMilliseconds(); m_lastWepDam = method; m_lastDamEntity = damagedBy; } if (method == WEAPONTYPE_FALL) { if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_ROLLOUT_LHS)) { if (m_fHealth >= 1.0 && m_fHealth - healthImpact < 5.0f) { m_fHealth = Min(m_fHealth, 5.0f); return false; } } } if (m_fHealth - healthImpact >= 1.0f && !willLinger) { m_fHealth -= healthImpact; return false; } if (bInVehicle) { if (method != WEAPONTYPE_DROWNING) { if (m_pMyVehicle) { CVehicle* pVehicle = m_pMyVehicle; bool bDone = false; if (m_pMyVehicle->IsBike()) { m_fHealth = 0.0f; ((CBike*)m_pMyVehicle)->KnockOffRider(method, direction, this, false); bDone = true; } else { if (m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR) { if (m_pMyVehicle->pDriver == this) { if (m_pMyVehicle->GetStatus() == STATUS_SIMPLE) { m_pMyVehicle->SetStatus(STATUS_PHYSICS); CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); } m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; m_pMyVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKESTRAIGHT; m_pMyVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000; } } if (m_pMyVehicle->CanPedExitCar(true)) { SetObjective(OBJECTIVE_LEAVE_CAR_AND_DIE, m_pMyVehicle); } else { m_fHealth = 0.0f; if (m_pMyVehicle && m_pMyVehicle->pDriver == this) { SetRadioStation(); m_pMyVehicle->SetStatus(STATUS_ABANDONED); } SetDie(dieAnim, dieDelta, dieSpeed); if (damagedBy == FindPlayerPed() && damagedBy != this) { CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel += 10; CWorld::Players[CWorld::PlayerInFocus].m_fMediaAttention += 5.f; } } } for (int i = 0; i < ARRAY_SIZE(pVehicle->pPassengers); i++) { CPed* passenger = pVehicle->pPassengers[i]; if (passenger && passenger != this && damagedBy) passenger->ReactToAttack(damagedBy); } CPed *driverOfVeh = pVehicle->pDriver; if (driverOfVeh && driverOfVeh != this && damagedBy) driverOfVeh->ReactToAttack(damagedBy); if (damagedBy == FindPlayerPed() || damagedBy && damagedBy == FindPlayerVehicle()) { CDarkel::RegisterKillByPlayer(this, method, headShot); m_threatEntity = FindPlayerPed(); } else { CDarkel::RegisterKillNotByPlayer(this, method); } if (bDone) return true; } m_fHealth = 1.0f; return false; } m_fHealth = 0.0f; if (player == this) m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED); SetDie(ANIM_STD_NUM, 4.0f, 0.0f); return true; } else { m_fHealth = 0.0f; SetDie(dieAnim, dieDelta, dieSpeed); if (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) { CDarkel::RegisterKillByPlayer(this, method, headShot); CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel += 10; CWorld::Players[CWorld::PlayerInFocus].m_fMediaAttention += 5.f; m_threatEntity = player; } else { CDarkel::RegisterKillNotByPlayer(this, method); } if (method == WEAPONTYPE_DROWNING) { bIsInTheAir = false; if (FindPlayerPed() == this) CStats::TimesDrowned++; } return true; } } static RwObject* SetPedAtomicVisibilityCB(RwObject* object, void* data) { if (data == nil) RpAtomicSetFlags((RpAtomic*)object, 0); return object; } static RwFrame* RecurseFrameChildrenVisibilityCB(RwFrame* frame, void* data) { RwFrameForAllObjects(frame, SetPedAtomicVisibilityCB, data); RwFrameForAllChildren(frame, RecurseFrameChildrenVisibilityCB, nil); return frame; } static RwObject* CloneAtomicToFrameCB(RwObject *frame, void *data) { RpAtomic *newAtomic = RpAtomicClone((RpAtomic*)frame); RpAtomicSetFrame(newAtomic, (RwFrame*)data); RpClumpAddAtomic(flyingClumpTemp, newAtomic); CVisibilityPlugins::SetAtomicRenderCallback(newAtomic, nil); return frame; } static RwFrame* RecurseFrameChildrenToCloneCB(RwFrame *frame, void *data) { RwFrame *newFrame = RwFrameCreate(); RwFrameAddChild((RwFrame*)data, newFrame); RwFrameTransform(newFrame, RwFrameGetMatrix(frame), rwCOMBINEREPLACE); RwFrameForAllObjects(frame, CloneAtomicToFrameCB, newFrame); RwFrameForAllChildren(frame, RecurseFrameChildrenToCloneCB, newFrame); return newFrame; } void CPed::RemoveBodyPart(PedNode nodeId, int8 direction) { RwFrame *frame; CVector pos; frame = m_pFrames[nodeId]->frame; if (frame) { if (CGame::nastyGame) { if (CEntity::GetIsOnScreen()) { m_pedIK.GetComponentPosition(pos, nodeId); CParticle::AddParticle(PARTICLE_TEST, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.1f, 0, 0, 0, 0); for (int i = 0; i < 16; i++) { CParticle::AddParticle(PARTICLE_BLOOD_SMALL, pos, CVector(0.0f, 0.0f, 0.03f), nil, 0.0f, 0, 0, 0, 0); } } bBodyPartJustCameOff = true; m_bodyPartBleeding = nodeId; } } else { printf("Trying to remove ped component"); } } CObject* CPed::SpawnFlyingComponent(int pedNode, int8 direction) { // VC doesn't have detachable limbs :shrug: return nil; } // III leftover and unused void CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) { CVector pos2 = CVector( pos.x, pos.y, pos.z + 0.1f ); if (!IsPlayer() || evenOnPlayer) { ++CStats::HeadsPopped; // BUG: This condition will always return true. Even fixing it won't work, because these states are unused. // if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { SetDie(); // } bBodyPartJustCameOff = true; m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; RemoveBodyPart(PED_HEAD, 0); CParticle::AddParticle(PARTICLE_TEST, pos2, CVector(0.0f, 0.0f, 0.0f), nil, 0.2f, 0, 0, 0, 0); if (CEntity::GetIsOnScreen()) { for(int i=0; i < 32; i++) { CParticle::AddParticle(PARTICLE_BLOOD_SMALL, pos2, CVector(0.0f, 0.0f, 0.03f), nil, 0.0f, 0, 0, 0, 0); } for (int i = 0; i < 16; i++) { CParticle::AddParticle(PARTICLE_DEBRIS2, pos2, CVector(0.0f, 0.0f, 0.01f), nil, 0.0f, 0, 0, 0, 0); } } } } bool CPed::IsPedHeadAbovePos(float zOffset) { return zOffset + GetPosition().z < GetNodePosition(PED_HEAD).z; } bool CPed::PlacePedOnDryLand(void) { float waterLevel = 0.0f; CEntity *foundEnt = nil; CColPoint foundCol; float foundColZ; CWaterLevel::GetWaterLevelNoWaves(GetPosition().x, GetPosition().y, GetPosition().z, &waterLevel); CVector potentialGround = GetPosition(); potentialGround.z = waterLevel; if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false)) return false; CVector potentialGroundDist = gaTempSphereColPoints[0].point - GetPosition(); potentialGroundDist.z = 0.0f; potentialGroundDist.Normalise(); CVector posToCheck = 0.5f * potentialGroundDist + gaTempSphereColPoints[0].point; posToCheck.z = 3.0f + waterLevel; if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) { foundColZ = foundCol.point.z; if (foundColZ >= waterLevel) { posToCheck.z = 0.8f + foundColZ; SetPosition(posToCheck); bIsStanding = true; bWasStanding = true; return true; } } posToCheck = 5.0f * potentialGroundDist + GetPosition(); posToCheck.z = 3.0f + waterLevel; if (!CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) return false; foundColZ = foundCol.point.z; if (foundColZ < waterLevel) return false; posToCheck.z = 0.8f + foundColZ; SetPosition(posToCheck); bIsStanding = true; bWasStanding = true; return true; } void CPed::CollideWithPed(CPed *collideWith) { CAnimBlendAssociation *animAssoc; AnimationId animToPlay; bool weAreMissionChar = CharCreatedBy == MISSION_CHAR; bool heIsMissionChar = collideWith->CharCreatedBy == MISSION_CHAR; CVector posDiff = collideWith->GetPosition() - GetPosition(); int waitTime = 0; if (weAreMissionChar || !collideWith->IsPlayer() || collideWith->m_nPedState != PED_MAKE_CALL) { if (m_nWaitState == WAITSTATE_SUN_BATHE_IDLE) { SetGetUp(); return; } if (collideWith->m_nWaitState == WAITSTATE_SUN_BATHE_IDLE) { collideWith->SetGetUp(); return; } bool weDontLookToHim = DotProduct(posDiff, GetForward()) > 0.0f; bool heLooksToUs = DotProduct(posDiff, collideWith->GetForward()) < 0.0f; if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { if ((!IsPlayer() || ((CPlayerPed*)this)->m_fMoveSpeed <= 1.8f) && (IsPlayer() || heIsMissionChar && weAreMissionChar || m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT || m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && m_pedInObjective == collideWith || collideWith->m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && collideWith->m_pedInObjective == this )) { if (m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT) { if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { if (heIsMissionChar || !weAreMissionChar && collideWith->m_nMoveState != PEDMOVE_STILL) { if (weAreMissionChar && (m_nPedState == PED_SEEK_POS || m_nPedState == PED_SEEK_ENTITY)) { if (collideWith->m_nMoveState != PEDMOVE_STILL && (!collideWith->IsPlayer() || collideWith->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled())) { float seekPosDist = (GetPosition() - m_vecSeekPos).MagnitudeSqr2D(); float heAndSeekPosDist = (collideWith->GetPosition() - m_vecSeekPos).MagnitudeSqr2D(); if (seekPosDist <= heAndSeekPosDist) { waitTime = 1000; collideWith->SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime); collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime; } else { waitTime = 500; SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime); m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime; } } else if (collideWith->m_nMoveState == PEDMOVE_STILL) { SetDirectionToWalkAroundObject(collideWith); } } else { if (FindPlayerPed() != m_pedInObjective || m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT || collideWith == m_pedInObjective) { if (weAreMissionChar || m_pedStats->m_fear <= 100 - collideWith->m_pedStats->m_temper || (collideWith->IsPlayer() || collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL) && (!collideWith->IsPlayer() || ((CPlayerPed*)collideWith)->m_fMoveSpeed <= 1.0f)) { SetDirectionToWalkAroundObject(collideWith); if (!weAreMissionChar) Say(SOUND_PED_CHAT); } else { SetEvasiveStep(collideWith, 2); } } else if (collideWith->m_nMoveState != PEDMOVE_STILL && GetWeapon()->IsTypeMelee() && collideWith->m_pedInObjective == m_pedInObjective) { int colliderIndexAtPlayersKillList = -1; int ourIndexAtPlayersKillList = -1; for (int i = 0; i < ARRAY_SIZE(((CPlayerPed*)m_pedInObjective)->m_pMeleeList); i++) { CPed *pedInKillList = ((CPlayerPed*)m_pedInObjective)->m_pMeleeList[i]; if (pedInKillList == this) { ourIndexAtPlayersKillList = i; } else if (pedInKillList == collideWith) { colliderIndexAtPlayersKillList = i; } } bool weAreCloserToTargetThenCollider = false; if ((GetPosition() - m_vecSeekPos).MagnitudeSqr2D() < (collideWith->GetPosition() - m_vecSeekPos).MagnitudeSqr2D()) weAreCloserToTargetThenCollider = true; if (ourIndexAtPlayersKillList > 0 && !weAreCloserToTargetThenCollider) { if (colliderIndexAtPlayersKillList > 0) { int time = 300; SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &time); m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + time; } else if (collideWith->m_pedInObjective == FindPlayerPed()) { ((CPlayerPed*)m_pedInObjective)->RemovePedFromMeleeList(this); int time = 500; SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &time); m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + time; } } else if (!weAreCloserToTargetThenCollider) { int time = 300; SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &time); m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + time; } } else { SetDirectionToWalkAroundObject(collideWith); } } } else { if (m_pedStats->m_temper <= m_pedStats->m_fear || GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED || weAreMissionChar || collideWith->m_nPedType == PEDTYPE_CIVFEMALE || collideWith->m_nPedType == m_nPedType || collideWith->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { SetDirectionToWalkAroundObject(collideWith); Say(SOUND_PED_CHAT); } else { TurnBody(); SetAttack(collideWith); m_fRotationCur = 0.3f + m_fRotationCur; m_fRotationDest = m_fRotationCur; } m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(250, 450); } } } else { if (m_pedInObjective && (collideWith == m_pedInObjective || collideWith->m_pedInObjective == m_pedInObjective) && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { if (heLooksToUs) { SetEvasiveStep(collideWith, 1); m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; } } else if (weDontLookToHim && IsPedInControl()) { if (m_pedStats != collideWith->m_pedStats) { if (collideWith->m_pedStats->m_fear <= 100 - m_pedStats->m_temper || collideWith->IsPlayer() || CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) { if (collideWith->IsPlayer()) { // He's on our right side if (DotProduct(posDiff,GetRight()) <= 0.0f) m_fRotationCur -= m_headingRate; else m_fRotationCur += m_headingRate; } else { // He's on our right side if (DotProduct(posDiff, collideWith->GetRight()) <= 0.0f) collideWith->m_fRotationCur -= collideWith->m_headingRate; else collideWith->m_fRotationCur += collideWith->m_headingRate; } } else { SetLookFlag(collideWith, false); TurnBody(); animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_PARTIAL_PUNCH, 8.0f); animAssoc->flags |= ASSOC_FADEOUTWHENDONE; m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000; if (!heIsMissionChar) { CVector2D posDiff2D(posDiff); int direction = collideWith->GetLocalDirection(posDiff2D); collideWith->StartFightDefend(direction, HITLEVEL_HIGH, 5); } } } } } } else if (collideWith->m_pedStats->m_defendWeakness <= 1.5f || heIsMissionChar || m_pedStats->m_defendWeakness <= collideWith->m_pedStats->m_defendWeakness) { // He looks us and we're not at his right side if (heLooksToUs && DotProduct(posDiff,collideWith->GetRight()) > 0.0f) { CVector moveForce = GetRight(); moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) animToPlay = ANIM_STD_HIT_LEFT; else animToPlay = ANIM_STD_HITBYGUN_LEFT; } else if (heLooksToUs) { CVector moveForce = GetRight() * -1.0f; moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) animToPlay = ANIM_STD_HIT_RIGHT; else animToPlay = ANIM_STD_HITBYGUN_RIGHT; } else { if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) animToPlay = ANIM_STD_HIT_BACK; else animToPlay = ANIM_STD_HITBYGUN_BACK; } if (collideWith->IsPedInControl() && CTimer::GetTimeInMilliseconds() > collideWith->m_nPedStateTimer) { animAssoc = CAnimManager::BlendAnimation(collideWith->GetClump(), ASSOCGRP_STD, animToPlay, 8.0f); animAssoc->flags |= ASSOC_FADEOUTWHENDONE; collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 1000; if (m_nPedState == PED_ATTACK) DMAudio.PlayOneShot(m_audioEntityId, SOUND_49, 0.0f); } } else { // We're at his right side if (DotProduct(posDiff, collideWith->GetRight()) <= 0.0f) { CVector moveForce = GetRight() * -1.0f; moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (heLooksToUs) animToPlay = ANIM_STD_HIGHIMPACT_RIGHT; else animToPlay = ANIM_STD_SPINFORWARD_RIGHT; } else { CVector moveForce = GetRight(); moveForce.z += 0.1f; ApplyMoveForce(moveForce); if (heLooksToUs) animToPlay = ANIM_STD_HIGHIMPACT_LEFT; else animToPlay = ANIM_STD_SPINFORWARD_LEFT; } if (m_nPedState == PED_ATTACK && collideWith->IsPedInControl()) DMAudio.PlayOneShot(m_audioEntityId, SOUND_49, 0.0f); collideWith->SetFall(3000, animToPlay, 0); } } else { if (!IsPedInControl()) return; if (collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL) return; if (m_nPedType != collideWith->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) { if (!weAreMissionChar && heLooksToUs && m_pedStats->m_fear > 100 - collideWith->m_pedStats->m_temper) { if (CGeneral::GetRandomNumber() & 1 && CTimer::GetTimeInMilliseconds() < m_nPedStateTimer){ SetEvasiveStep(collideWith, 2); m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; } else if (collideWith->m_nMoveState > PEDMOVE_WALK) { waitTime = 2000; SetWaitState(WAITSTATE_PLAYANIM_DUCK, &waitTime); } } } else if (heLooksToUs && collideWith->m_nPedState != PED_STEP_AWAY && m_nPedState != PED_STEP_AWAY && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { SetEvasiveStep(collideWith, 1); m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; } } if (IsPlayer()) { SetLookFlag(collideWith, true); SetLookTimer(800); } } else { bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; SetFindPathAndFlee(collideWith, 5000, !isRunning); } } void CPed::KillPedWithCar(CVehicle *car, float impulse) { CVehicleModelInfo *vehModel; CColModel *vehColModel; uint8 damageDir; PedNode nodeToDamage; eWeaponType killMethod; if (m_nPedState == PED_FALL || m_nPedState == PED_DIE) { if (!m_pCollidingEntity || car->GetStatus() == STATUS_PLAYER) m_pCollidingEntity = car; return; } if (m_nPedState == PED_DEAD) return; if (m_pCurSurface) { if (m_pCurSurface->IsVehicle() && (((CVehicle*)m_pCurSurface)->IsBoat()|| IsPlayer())) return; } CVector distVec = GetPosition() - car->GetPosition(); if ((impulse > 12.0f || car->GetModelIndex() == MI_TRAIN) && !IsPlayer()) { nodeToDamage = PED_TORSO; killMethod = WEAPONTYPE_RAMMEDBYCAR; uint8 randVal = CGeneral::GetRandomNumber() & 3; if (car == FindPlayerVehicle()) { float carSpeed = car->m_vecMoveSpeed.Magnitude(); uint8 shakeFreq; if (100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f <= 250.0f) { shakeFreq = 100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f; } else { shakeFreq = 250.0f; } CPad::GetPad(0)->StartShake(40000 / shakeFreq, shakeFreq); } bIsStanding = false; damageDir = GetLocalDirection(-m_vecMoveSpeed); vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(car->GetModelIndex()); vehColModel = vehModel->GetColModel(); float carRightAndDistDotProd = DotProduct(distVec, car->GetRight()); if (car->GetModelIndex() == MI_TRAIN) { killMethod = WEAPONTYPE_RUNOVERBYCAR; nodeToDamage = PED_HEAD; m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; m_vecMoveSpeed.z = 0.0f; if (damageDir == 1 || damageDir == 3) damageDir = 2; if (CGame::nastyGame) DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); // Car doesn't look to us } else if (DotProduct(car->m_vecMoveSpeed, car->GetForward()) >= 0.0f){ if (0.99f * vehColModel->boundingBox.max.x < Abs(carRightAndDistDotProd)) { // We're at the right of the car if (carRightAndDistDotProd <= 0.0f) nodeToDamage = PED_UPPERARML; else nodeToDamage = PED_UPPERARMR; if (Abs(DotProduct(distVec, car->GetForward())) < 0.85f * vehColModel->boundingBox.max.y) { killMethod = WEAPONTYPE_RUNOVERBYCAR; m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; m_vecMoveSpeed.z = 0.0f; if (damageDir == 1 || damageDir == 3) damageDir = 2; if (CGame::nastyGame) DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); } } else { float carFrontAndDistDotProd = DotProduct(distVec, car->GetForward()); // carFrontAndDistDotProd <= 0.0 car looks to us if ((carFrontAndDistDotProd <= 0.1 || randVal <= 1) && randVal != 0) { killMethod = WEAPONTYPE_RUNOVERBYCAR; nodeToDamage = PED_HEAD; m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; m_vecMoveSpeed.z = 0.0f; if (damageDir == 1 || damageDir == 3) damageDir = 2; if (CGame::nastyGame) DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); } else { nodeToDamage = PED_MID; float vehColMaxY = vehColModel->boundingBox.max.y; float vehColMinY = vehColModel->boundingBox.min.y; float vehColMaxZ = vehColModel->boundingBox.max.z; float carFrontZ = car->GetForward().z; float carHighestZ, carLength; if (carFrontZ < -0.2f) { // Highest point of car's back carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMinY, vehColMaxZ)).z; carLength = vehColMaxY - vehColMinY; } else if (carFrontZ > 0.1f) { // Highest point of car's front carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; float highestZDist = carHighestZ - GetPosition().z; if (highestZDist > 0.0f) { GetMatrix().GetPosition().z += 0.5f * highestZDist; carHighestZ += highestZDist * 0.25f; } carLength = vehColMaxY; } else { // Highest point of car's front carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; carLength = vehColMaxY; } float pedJumpSpeedToReachHighestZ = (carHighestZ - GetPosition().z) / (carLength / car->m_vecMoveSpeed.Magnitude()); // TODO: What are we doing down here? float unknown = ((CGeneral::GetRandomNumber() % 256) * 0.002 + 1.5) * pedJumpSpeedToReachHighestZ; // After this point distVec isn't really distVec. distVec = car->m_vecMoveSpeed; distVec.Normalise(); distVec *= 0.2 * unknown; if (damageDir != 1 && damageDir != 3) distVec.z += unknown; else distVec.z += 1.5f * unknown; m_vecMoveSpeed = distVec; damageDir += 2; if (damageDir > 3) damageDir = damageDir - 4; if (car->IsCar()) { CObject *bonnet = ((CAutomobile*)car)->RemoveBonnetInPedCollision(); if (bonnet) { if (CGeneral::GetRandomNumber() & 1) { bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(0.1f, 0.0f, 0.5f)); } else { bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(-0.1f, 0.0f, 0.5f)); } CVector forceDir = car->GetUp() * 10.0f; bonnet->ApplyTurnForce(forceDir, car->GetForward()); } } } } } if (car->pDriver) { CEventList::RegisterEvent((m_nPedType == PEDTYPE_COP ? EVENT_HIT_AND_RUN_COP : EVENT_HIT_AND_RUN), EVENT_ENTITY_PED, this, car->pDriver, 1000); } ePedPieceTypes pieceToDamage; switch (nodeToDamage) { case PED_HEAD: pieceToDamage = PEDPIECE_HEAD; break; case PED_UPPERARML: pieceToDamage = PEDPIECE_LEFTARM; break; case PED_UPPERARMR: pieceToDamage = PEDPIECE_RIGHTARM; break; default: pieceToDamage = PEDPIECE_MID; break; } InflictDamage(car, killMethod, 1000.0f, pieceToDamage, damageDir); if (DyingOrDead() && bIsPedDieAnimPlaying && !m_pCollidingEntity) { m_pCollidingEntity = car; } if (nodeToDamage == PED_MID) bKnockedUpIntoAir = true; else bKnockedUpIntoAir = false; distVec.Normalise(); distVec *= Min(car->m_fMass / 1400.0f, 1.0f); car->ApplyMoveForce(distVec * -100.0f); Say(SOUND_PED_DEFEND); } else if (m_vecDamageNormal.z < -0.8f && impulse > 3.0f || impulse > 6.0f && (!IsPlayer() || impulse > 10.0f)) { bIsStanding = false; uint8 fallDirection = GetLocalDirection(-car->m_vecMoveSpeed); float damage; if (IsPlayer() && car->GetModelIndex() == MI_TRAIN) damage = 150.0f; else damage = 30.0f; InflictDamage(car, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, fallDirection); SetFall(1000, (AnimationId)(fallDirection + ANIM_STD_HIGHIMPACT_FRONT), true); if (OnGround() && !m_pCollidingEntity && (!IsPlayer() || bHasHitWall || car->GetModelIndex() == MI_TRAIN || m_vecDamageNormal.z < -0.8f)) { m_pCollidingEntity = car; } bKnockedUpIntoAir = false; if (car->GetModelIndex() != MI_TRAIN && !bHasHitWall) { m_vecMoveSpeed = car->m_vecMoveSpeed * 0.75f; } m_vecMoveSpeed.z = 0.0f; distVec.Normalise(); distVec *= Min(car->m_fMass / 1400.0f, 1.0f); car->ApplyMoveForce(distVec * -60.0f); Say(SOUND_PED_DEFEND); } if (IsGangMember()) { CPed *driver = car->pDriver; if (driver && driver->IsPlayer() #ifdef FIX_BUGS && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats) && (!m_leader || m_leader != driver) #endif ) { RegisterThreatWithGangPeds(driver); } } } void CPed::DriveVehicle(void) { if (bOffscreen) return; CVehicle *veh = m_pMyVehicle; if (veh->IsBike()) { CBike *bike = (CBike*)veh; float blendDelta = 1.0f; float targetUDLean = 0.0f; CAnimBlendAssociation *leftAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_LEFT); CAnimBlendAssociation *rightAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_RIGHT); CAnimBlendAssociation *stillAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_READY); CAnimBlendAssociation *fwdAssoc, *backAssoc; if (IsPlayer()) { fwdAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_LEANF); backAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_LEANB); } CAnimBlendAssociation *walkbackAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_WALKBACK); CAnimBlendAssociation *drivebyAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_DRIVEBY_LHS); if (!drivebyAssoc) drivebyAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_DRIVEBY_RHS); if (!drivebyAssoc) drivebyAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_BIKE_DRIVEBY_FORWARD); float velocityFwdDotProd = DotProduct(bike->m_vecMoveSpeed, bike->GetForward()); if (m_vecTurnSpeed.MagnitudeSqr() > 0.09f) { bike->KnockOffRider(WEAPONTYPE_FALL, 2, this, false); if (bike->pPassengers[0]) bike->KnockOffRider(WEAPONTYPE_FALL, 2, bike->pPassengers[0], false); return; } if (!drivebyAssoc && Abs(velocityFwdDotProd) < 0.02f) { if (!stillAssoc || stillAssoc->blendAmount < 1.0 && stillAssoc->blendDelta <= 0.0) { stillAssoc = CAnimManager::BlendAnimation(GetClump(), bike->m_bikeAnimType, ANIM_BIKE_READY, 2.0f); } } else { if (velocityFwdDotProd >= 0.0f) { if (stillAssoc && stillAssoc->blendDelta >= 0.0f) stillAssoc->blendDelta = -4.0f; if (walkbackAssoc && walkbackAssoc->blendDelta >= 0.0f) walkbackAssoc->blendDelta = -4.0f; } else { float maxReverseSpeed = bike->pHandling->Transmission.fMaxReverseVelocity; if (3.5f * maxReverseSpeed > velocityFwdDotProd && (bike->m_nWheelsOnGround || bike->GetUp().z < -0.5f)) { bike->KnockOffRider(WEAPONTYPE_FALL, 2, this, false); if (bike->pPassengers[0]) bike->KnockOffRider(WEAPONTYPE_FALL, 2, bike->pPassengers[0], false); return; } if (bike->m_fGasPedal >= 0.0 || velocityFwdDotProd <= maxReverseSpeed * 1.5) { if (IsPlayer() && velocityFwdDotProd < maxReverseSpeed * 1.5) targetUDLean = -1.0f; if (stillAssoc && stillAssoc->blendDelta >= 0.0f) stillAssoc->blendDelta = -4.0f; if (walkbackAssoc && walkbackAssoc->blendDelta >= 0.0f) { walkbackAssoc->blendDelta = -4.0f; } } else if (!walkbackAssoc || walkbackAssoc->blendAmount < 1.0f && walkbackAssoc->blendDelta <= 0.0f) { walkbackAssoc = CAnimManager::BlendAnimation(GetClump(), bike->m_bikeAnimType, ANIM_BIKE_WALKBACK, 4.0f); } } } if (stillAssoc) blendDelta -= Min(1.0f, CTimer::GetTimeStepNonClipped() * 0.02f * stillAssoc->blendDelta + stillAssoc->blendAmount); if (drivebyAssoc) blendDelta -= Min(blendDelta, CTimer::GetTimeStepNonClipped() * 0.02f * drivebyAssoc->blendDelta + drivebyAssoc->blendAmount); if (walkbackAssoc) blendDelta -= Min(blendDelta, CTimer::GetTimeStepNonClipped() * 0.02f * walkbackAssoc->blendDelta + walkbackAssoc->blendAmount); float targetLRLean, timeBlend, neededAngForWheelie, stoppieAng; // Smooth the lean amount if (targetUDLean == -1.0f) { targetLRLean = 0.0f; timeBlend = Pow(0.86f, CTimer::GetTimeStep()); } else { targetLRLean = Clamp(bike->m_fLeanLRAngle / bike->pBikeHandling->fFullAnimLean, -1.0f, 1.0f); timeBlend = Pow(0.86f, CTimer::GetTimeStep()); } bike->m_fPedLeanAmountLR = bike->m_fPedLeanAmountLR * timeBlend + (1.0 - timeBlend) * targetLRLean; if (!IsPlayer()) { targetUDLean = 0.0f; } else if (targetUDLean > -1.0f) { targetUDLean = bike->m_fLeanInput; bike->bWheelieCam = false; neededAngForWheelie = 1.0f; if (bike->m_aWheelTimer[0] != 0.0f || bike->m_aWheelTimer[1] != 0.0f || bike->GetForward().z <= 0.0f || (0.0f == bike->m_aWheelTimer[2] && 0.0f == bike->m_aWheelTimer[3])) { if (0.0f == bike->m_aWheelTimer[2] && 0.0f == bike->m_aWheelTimer[3] && (bike->GetForward().z < 0.0f && (bike->m_aWheelTimer[0] != 0.0f || bike->m_aWheelTimer[1] != 0.0f))) { stoppieAng = bike->pBikeHandling->fStoppieAng; if (stoppieAng - bike->GetForward().z > 0.6f * stoppieAng) bike->bWheelieCam = true; } } else { float wheelieAng = bike->pBikeHandling->fWheelieAng; neededAngForWheelie = wheelieAng - bike->GetForward().z; if (neededAngForWheelie < wheelieAng / 2.f) bike->bWheelieCam = true; } if (neededAngForWheelie >= 0.15f) { if (bike->m_fBrakePedal <= 0.5f || velocityFwdDotProd <= 0.01f) { if (bike->m_fGasPedal > 0.5f && targetUDLean <= 0.0f && 0.3f * bike->pHandling->Transmission.fMaxCruiseVelocity > velocityFwdDotProd) { targetUDLean = Min(0.1f, targetUDLean); } } else { targetUDLean = Max(0.1f, targetUDLean); } } else { targetUDLean = Max(0.25f, targetUDLean); } float targetLRLeanABS = Abs(targetLRLean); if (targetLRLeanABS > 0.3f) { // Yes, UD targetUDLean *= Max(0.0f, 1.0f - (targetLRLeanABS - 0.3f) * 50.f / 13.f); } } if (IsPlayer()) { float timeBlend = Pow(0.89f, CTimer::GetTimeStep()); bike->m_fPedLeanAmountUD = (timeBlend * bike->m_fPedLeanAmountUD) + ((1.0f - timeBlend) * targetUDLean); } else { bike->m_fPedLeanAmountUD = 0.0f; } float fwdBackLeanAmount, leftRightLeanAmount; if (Abs(bike->m_fPedLeanAmountLR) <= 0.56f && IsPlayer()) { if (Abs(bike->m_fPedLeanAmountUD) <= 0.56f) { CVector2D smoothedLean(bike->m_fPedLeanAmountLR, bike->m_fPedLeanAmountUD); float smoothLeanMag = smoothedLean.Magnitude(); if (smoothLeanMag <= 0.01f) { fwdBackLeanAmount = Abs(smoothedLean.y); leftRightLeanAmount = Abs(smoothedLean.x); } else { fwdBackLeanAmount = Abs(smoothedLean.y / smoothLeanMag); leftRightLeanAmount = Abs(smoothedLean.x / smoothLeanMag); } } else { fwdBackLeanAmount = 1.0f; leftRightLeanAmount = 0.0f; } } else { fwdBackLeanAmount = 0.0f; leftRightLeanAmount = 1.0f; } float fwdBackBlend = fwdBackLeanAmount * blendDelta; float leftRightBlend = leftRightLeanAmount * blendDelta; if (IsPlayer()) { if (!fwdAssoc) fwdAssoc = CAnimManager::AddAnimation(GetClump(), bike->m_bikeAnimType, ANIM_BIKE_LEANF); if (!backAssoc) backAssoc = CAnimManager::AddAnimation(GetClump(), bike->m_bikeAnimType, ANIM_BIKE_LEANB); if (bike->m_fPedLeanAmountUD < 0.0f) { backAssoc->blendAmount = fwdBackBlend; backAssoc->SetCurrentTime(-(bike->m_fPedLeanAmountUD * backAssoc->hierarchy->totalLength)); backAssoc->flags &= ~ASSOC_RUNNING; fwdAssoc->blendAmount = 0.0f; } else { fwdAssoc->blendAmount = fwdBackBlend; fwdAssoc->SetCurrentTime(bike->m_fPedLeanAmountUD* fwdAssoc->hierarchy->totalLength); fwdAssoc->flags &= ~ASSOC_RUNNING; backAssoc->blendAmount = 0.0f; } } if (!leftAssoc) leftAssoc = CAnimManager::AddAnimation(GetClump(), bike->m_bikeAnimType, ANIM_BIKE_LEFT); if (!rightAssoc) rightAssoc = CAnimManager::AddAnimation(GetClump(), bike->m_bikeAnimType, ANIM_BIKE_RIGHT); if (bike->m_fPedLeanAmountLR < 0.0f) { leftAssoc->blendAmount = leftRightBlend; leftAssoc->SetCurrentTime(-(bike->m_fPedLeanAmountLR * leftAssoc->hierarchy->totalLength)); leftAssoc->flags &= ~ASSOC_RUNNING; rightAssoc->blendAmount = 0.0f; } else { rightAssoc->blendAmount = leftRightBlend; rightAssoc->SetCurrentTime(bike->m_fPedLeanAmountLR* rightAssoc->hierarchy->totalLength); rightAssoc->flags &= ~ASSOC_RUNNING; leftAssoc->blendAmount = 0.0f; } if (velocityFwdDotProd > 0.3f) { RwV3d Xaxis = { 1.0f, 0.0f, 0.0f }; RwV3d Yaxis = { 0.0f, 1.0f, 0.0f }; RtQuatRotate(&m_pFrames[PED_HEAD]->hanimFrame->q, &Xaxis, CGeneral::GetRandomNumberInRange(-6.0f * velocityFwdDotProd, 6.0f * velocityFwdDotProd), rwCOMBINEPOSTCONCAT); RtQuatRotate(&m_pFrames[PED_HEAD]->hanimFrame->q, &Yaxis, CGeneral::GetRandomNumberInRange(-6.0f * velocityFwdDotProd, 6.0f * velocityFwdDotProd), rwCOMBINEPOSTCONCAT); bDontAcceptIKLookAts = true; } return; } if (!IsPlayer()) return; float steerAngle = m_pMyVehicle->m_fSteerAngle; CAnimBlendAssociation* lDriveAssoc; CAnimBlendAssociation* rDriveAssoc; CAnimBlendAssociation* lbAssoc; CAnimBlendAssociation* sitAssoc; if (m_pMyVehicle->IsBoat() && !(m_pMyVehicle->pHandling->Flags & HANDLING_SIT_IN_BOAT)) { sitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_BOAT_DRIVE); if (!sitAssoc || sitAssoc->blendAmount < 1.0f) { return; } lDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_BOAT_DRIVE_LEFT); rDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_BOAT_DRIVE_RIGHT); lbAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_BOAT_LOOKBEHIND); } else if (m_pMyVehicle->bLowVehicle) { sitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_SIT_LO); if (!sitAssoc || sitAssoc->blendAmount < 1.0f) { return; } lDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVE_LEFT_LO); lbAssoc = nil; rDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVE_RIGHT_LO); } else { sitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_SIT); if (!sitAssoc || sitAssoc->blendAmount < 1.0f) { return; } lDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVE_LEFT); rDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVE_RIGHT); lbAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_LOOKBEHIND); } if (lbAssoc && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON && TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_LEFT) { lbAssoc->blendDelta = -1000.0f; } CAnimBlendAssociation* driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVEBY_LEFT); if (!driveByAssoc) driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVEBY_RIGHT); if (!driveByAssoc) driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVEBY_LEFT_LO); if (!driveByAssoc) driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_CAR_DRIVEBY_RIGHT_LO); if (m_pMyVehicle->bLowVehicle || m_pMyVehicle->m_fGasPedal >= 0.0f || driveByAssoc || m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI || m_pMyVehicle->GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE) { if (steerAngle == 0.0f || driveByAssoc) { if (lDriveAssoc) lDriveAssoc->blendAmount = 0.0f; if (rDriveAssoc) rDriveAssoc->blendAmount = 0.0f; } else if (steerAngle <= 0.0f) { if (lDriveAssoc) lDriveAssoc->blendAmount = 0.0f; if (rDriveAssoc) rDriveAssoc->blendAmount = Clamp(steerAngle * -100.0f / 61.0f, 0.0f, 1.0f); else if (m_pMyVehicle->IsBoat() && !(m_pMyVehicle->pHandling->Flags & HANDLING_SIT_IN_BOAT)) CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_BOAT_DRIVE_RIGHT); else if (m_pMyVehicle->bLowVehicle) CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_CAR_DRIVE_RIGHT_LO); else CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_CAR_DRIVE_RIGHT); } else { if (rDriveAssoc) rDriveAssoc->blendAmount = 0.0f; if (lDriveAssoc) lDriveAssoc->blendAmount = Clamp(steerAngle * 100.0f / 61.0f, 0.0f, 1.0f); else if (m_pMyVehicle->IsBoat() && !(m_pMyVehicle->pHandling->Flags & HANDLING_SIT_IN_BOAT)) CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_BOAT_DRIVE_LEFT); else if (m_pMyVehicle->bLowVehicle) CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_CAR_DRIVE_LEFT_LO); else CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_CAR_DRIVE_LEFT); } if (lbAssoc) lbAssoc->blendDelta = -4.0f; } else { if ((TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON || TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking != LOOKING_LEFT) && (!lbAssoc || lbAssoc->blendAmount < 1.0f && lbAssoc->blendDelta <= 0.0f)) { if (m_pMyVehicle->IsBoat() && !(m_pMyVehicle->pHandling->Flags & HANDLING_SIT_IN_BOAT)) CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_BOAT_LOOKBEHIND, 4.0f); else CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_CAR_LOOKBEHIND, 4.0f); } } } void CPed::RemoveWeaponAnims(int unused, float animDelta) { CAnimBlendAssociation *weaponAssoc; //CWeaponInfo::GetWeaponInfo(unused); weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ATTACK_1); if (weaponAssoc) { weaponAssoc->blendDelta = animDelta; weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; } weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_FIRE_2ND); if (weaponAssoc) { weaponAssoc->blendDelta = animDelta; weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; } weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_FIRE_3RD); if (weaponAssoc) { weaponAssoc->blendDelta = animDelta; weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; } weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ATTACK_EXTRA1); if (weaponAssoc) { weaponAssoc->blendDelta = animDelta; weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; } weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_MELEE_IDLE_FIGHTMODE); if (weaponAssoc) { weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; if (weaponAssoc->flags & ASSOC_PARTIAL) weaponAssoc->blendDelta = animDelta; else CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_STD_IDLE, -animDelta); } }