mirror of
https://git.rip/DMCA_FUCKER/re3.git
synced 2024-11-13 06:39:16 +00:00
4178 lines
138 KiB
C++
4178 lines
138 KiB
C++
#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_WEAPON_FIRE);
|
|
}
|
|
|
|
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_WEAPON_FIRE);
|
|
}
|
|
|
|
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_WEAPON_FIRE);
|
|
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_WEAPON_FIRE);
|
|
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);
|
|
} else 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);
|
|
}
|
|
}
|
|
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
|
|
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_ATTACK, 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_IDLE, 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_WEAPON_FIRE, 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);
|
|
} 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 {
|
|
if (m_curFightMove == FIGHTMOVE_BACKKICK)
|
|
animAssoc->speed = 1.15f;
|
|
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;
|
|
} 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_HITBODY;
|
|
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:
|
|
if (unk <= 5)
|
|
m_curFightMove = FIGHTMOVE_HITHEAD;
|
|
else
|
|
m_curFightMove = FIGHTMOVE_HITBIGSTEP;
|
|
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:
|
|
if (unk <= 5)
|
|
m_curFightMove = FIGHTMOVE_HITCHEST;
|
|
else
|
|
m_curFightMove = FIGHTMOVE_HITBIGSTEP;
|
|
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 = 0;
|
|
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) {
|
|
if (m_curFightMove == FIGHTMOVE_BACKKICK)
|
|
animAssoc->speed = 1.15f;
|
|
else
|
|
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;
|
|
}
|
|
}
|
|
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) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
} else if (distToVictim < 0.95f && m_nPedState == PED_FIGHT) {
|
|
choosenMove = FIGHTMOVE_KNEE;
|
|
|
|
} else if (distToVictim < 1.4f) {
|
|
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;
|
|
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
|
|
case 0:
|
|
choosenMove = FIGHTMOVE_PUNCHJAB;
|
|
break;
|
|
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)
|
|
{
|
|
// 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);
|
|
}
|
|
|
|
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) {
|
|
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_WEAPON_FIRE);
|
|
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_WEAPON_RELOAD);
|
|
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);
|
|
}
|
|
}
|