2020-11-19 20:12:20 +01:00
|
|
|
#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"
|
|
|
|
|
|
|
|
uint16 nPlayerInComboMove;
|
|
|
|
|
|
|
|
RpClump *flyingClumpTemp;
|
|
|
|
|
|
|
|
// This is beta fistfite.dat array. Not used anymore since they're being fetched from fistfite.dat.
|
|
|
|
FightMove tFightMoves[NUM_FIGHTMOVES] = {
|
|
|
|
{NUM_ANIMS, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_PUNCH_R, 0.2f, 8.0f / 30.0f, 0.0f, 0.3f, HITLEVEL_HIGH, 1, 0},
|
|
|
|
{ANIM_FIGHT_IDLE, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_FIGHT_SH_F, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_FIGHT_KNEE, 4.0f / 30.0f, 0.2f, 0.0f, 0.6f, HITLEVEL_LOW, 2, 0},
|
|
|
|
{ANIM_FIGHT_HEAD, 4.0f / 30.0f, 0.2f, 0.0f, 0.7f, HITLEVEL_HIGH, 3, 0},
|
|
|
|
{ANIM_FIGHT_PUNCH, 4.0f / 30.0f, 7.0f / 30.0f, 10.0f / 30.0f, 0.4f, HITLEVEL_HIGH, 1, 0},
|
|
|
|
{ANIM_FIGHT_LHOOK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.4f, HITLEVEL_HIGH, 3, 0},
|
|
|
|
{ANIM_FIGHT_KICK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.5, HITLEVEL_MEDIUM, 2, 0},
|
|
|
|
{ANIM_FIGHT_LONGKICK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.5, HITLEVEL_MEDIUM, 4, 0},
|
|
|
|
{ANIM_FIGHT_ROUNDHOUSE, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.6f, HITLEVEL_MEDIUM, 4, 0},
|
|
|
|
{ANIM_FIGHT_BODYBLOW, 5.0f / 30.0f, 7.0f / 30.0f, 0.0f, 0.35f, HITLEVEL_LOW, 2, 0},
|
|
|
|
{ANIM_KICK_FLOOR, 10.0f / 30.0f, 14.0f / 30.0f, 0.0f, 0.4f, HITLEVEL_GROUND, 1, 0},
|
|
|
|
{ANIM_HIT_FRONT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_BACK, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_RIGHT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_LEFT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_BODYBLOW, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_CHEST, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_WALK, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_FLOOR_HIT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_HIT_BEHIND, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0},
|
|
|
|
{ANIM_FIGHT2_IDLE, 0.0f, 0.0f, 0.0f, 0.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);
|
|
|
|
SetAimFlag(to);
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
SetLookTimer(INT32_MAX);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_nPedState != PED_ATTACK)
|
|
|
|
SetStoredState();
|
|
|
|
|
2020-12-15 04:11:02 +01:00
|
|
|
SetPedState(PED_AIM_GUN);
|
2020-11-19 20:12:20 +01:00
|
|
|
bIsPointingGunAt = true;
|
|
|
|
CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
|
|
|
SetMoveState(PEDMOVE_NONE);
|
|
|
|
|
|
|
|
CAnimBlendAssociation *aimAssoc;
|
|
|
|
|
|
|
|
if (bCrouchWhenShooting)
|
|
|
|
aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_Anim2ToPlay);
|
|
|
|
else
|
|
|
|
aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_AnimToPlay);
|
|
|
|
|
|
|
|
if (!aimAssoc || aimAssoc->blendDelta < 0.0f) {
|
|
|
|
if (bCrouchWhenShooting)
|
|
|
|
aimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f);
|
|
|
|
else
|
|
|
|
aimAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay);
|
|
|
|
|
|
|
|
aimAssoc->blendAmount = 0.0f;
|
|
|
|
aimAssoc->blendDelta = 8.0f;
|
|
|
|
}
|
|
|
|
if (to)
|
|
|
|
Say(SOUND_PED_ATTACK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::PointGunAt(void)
|
|
|
|
{
|
|
|
|
CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
|
|
|
CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay);
|
|
|
|
if (!weaponAssoc || weaponAssoc->blendDelta < 0.0f)
|
|
|
|
weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay);
|
|
|
|
|
|
|
|
if (weaponAssoc && weaponAssoc->currentTime > weaponInfo->m_fAnimLoopStart) {
|
|
|
|
weaponAssoc->SetCurrentTime(weaponInfo->m_fAnimLoopStart);
|
|
|
|
weaponAssoc->flags &= ~ASSOC_RUNNING;
|
|
|
|
|
2020-12-26 13:21:45 +01:00
|
|
|
if (weaponInfo->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM))
|
2020-11-19 20:12:20 +01:00
|
|
|
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;
|
|
|
|
#ifndef VC_PED_PORTS
|
|
|
|
if (m_nPedState == PED_AIM_GUN) {
|
|
|
|
RestorePreviousState();
|
|
|
|
#else
|
|
|
|
if (m_nPedState == PED_AIM_GUN || m_nPedState == PED_ATTACK) {
|
2020-12-15 04:11:02 +01:00
|
|
|
SetPedState(PED_IDLE);
|
2020-11-19 20:12:20 +01:00
|
|
|
RestorePreviousState();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay);
|
|
|
|
if (!animAssoc || animAssoc->blendDelta < 0.0f) {
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay);
|
|
|
|
}
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
animAssoc->blendDelta = -4.0f;
|
|
|
|
}
|
|
|
|
#ifndef VC_PED_PORTS
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::SetAttack(CEntity *victim)
|
|
|
|
{
|
|
|
|
CPed *victimPed = nil;
|
|
|
|
if (victim && victim->IsPed())
|
|
|
|
victimPed = (CPed*)victim;
|
|
|
|
|
|
|
|
CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED);
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->blendDelta = -1000.0f;
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_attackTimer > CTimer::GetTimeInMilliseconds() || m_nWaitState == WAITSTATE_SURPRISE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HGUN_RELOAD)) {
|
|
|
|
bIsAttacking = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD)) {
|
|
|
|
if (!IsPlayer() || m_nPedState != PED_ATTACK || ((CPlayerPed*)this)->m_bHaveTargetSelected)
|
|
|
|
bIsAttacking = false;
|
|
|
|
else
|
|
|
|
bIsAttacking = true;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
|
|
|
if (curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT && !IsPlayer()) {
|
|
|
|
if (GetWeapon()->HitsGround(this, nil, victim))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) {
|
|
|
|
if (IsPlayer() ||
|
|
|
|
(m_nPedState != PED_FIGHT && m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL && !(m_pedStats->m_flags & STAT_SHOPPING_BAGS))) {
|
|
|
|
|
|
|
|
if (m_nPedState != PED_ATTACK) {
|
2020-12-15 04:11:02 +01:00
|
|
|
SetPedState(PED_ATTACK);
|
2020-11-19 20:12:20 +01:00
|
|
|
bIsAttacking = false;
|
|
|
|
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, 8.0f);
|
|
|
|
animAssoc->SetRun();
|
|
|
|
if (animAssoc->currentTime == animAssoc->hierarchy->totalLength)
|
|
|
|
animAssoc->SetCurrentTime(0.0f);
|
|
|
|
|
|
|
|
animAssoc->SetFinishCallback(FinishedAttackCB, this);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
StartFightAttack(CGeneral::GetRandomNumber() % 256);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pSeekTarget = victim;
|
|
|
|
if (m_pSeekTarget)
|
|
|
|
m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget);
|
|
|
|
|
2020-12-26 13:21:45 +01:00
|
|
|
if (curWeapon->IsFlagSet(WEAPONFLAG_CANAIM)) {
|
2020-11-19 20:12:20 +01:00
|
|
|
CVector aimPos = GetRight() * 0.1f + GetForward() * 0.2f + GetPosition();
|
|
|
|
CEntity *obstacle = CWorld::TestSphereAgainstWorld(aimPos, 0.2f, nil, true, false, false, true, false, false);
|
|
|
|
if (obstacle)
|
|
|
|
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 {
|
|
|
|
SetAimFlag(m_fRotationCur);
|
|
|
|
|
|
|
|
if (FindPlayerPed() == this && TheCamera.Cams[0].Using3rdPersonMouseCam())
|
|
|
|
((CPlayerPed*)this)->m_fFPSMoveHeading = TheCamera.Find3rdPersonQuickAimPitch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_nPedState == PED_ATTACK) {
|
|
|
|
bIsAttacking = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsPlayer() || !victimPed || victimPed->IsPedInControl()) {
|
|
|
|
if (IsPlayer())
|
|
|
|
CPad::GetPad(0)->ResetAverageWeapon();
|
|
|
|
|
2020-12-07 00:36:40 +01:00
|
|
|
uint8 pointBlankStatus;
|
2020-11-19 20:12:20 +01:00
|
|
|
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)
|
|
|
|
StartFightAttack(200);
|
|
|
|
} else {
|
2020-12-26 13:21:45 +01:00
|
|
|
if (!curWeapon->IsFlagSet(WEAPONFLAG_CANAIM))
|
2020-11-19 20:12:20 +01:00
|
|
|
m_pSeekTarget = nil;
|
|
|
|
|
|
|
|
if (m_nPedState != PED_AIM_GUN)
|
|
|
|
SetStoredState();
|
|
|
|
|
2020-12-15 04:11:02 +01:00
|
|
|
SetPedState(PED_ATTACK);
|
2020-11-19 20:12:20 +01:00
|
|
|
SetMoveState(PEDMOVE_NONE);
|
|
|
|
if (bCrouchWhenShooting) {
|
|
|
|
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f);
|
|
|
|
} else {
|
|
|
|
float animDelta = 8.0f;
|
|
|
|
if (curWeapon->m_eWeaponFire == WEAPON_FIRE_MELEE)
|
|
|
|
animDelta = 1000.0f;
|
|
|
|
|
|
|
|
if (GetWeapon()->m_eWeaponType != WEAPONTYPE_BASEBALLBAT
|
|
|
|
|| CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) {
|
|
|
|
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, animDelta);
|
|
|
|
} else {
|
|
|
|
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 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, false);
|
|
|
|
SetLookTimer(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::ClearAttack(void)
|
|
|
|
{
|
|
|
|
if (m_nPedState != PED_ATTACK || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
// VC uses CCamera::Using1stPersonWeaponMode
|
|
|
|
if (FindPlayerPed() == this && (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_SNIPER ||
|
|
|
|
TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_ROCKETLAUNCHER)) {
|
|
|
|
SetPointGunAt(nil);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
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 || bIsDucking)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
|
|
|
CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_AnimToPlay);
|
|
|
|
if (!weaponAssoc) {
|
|
|
|
weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_Anim2ToPlay);
|
|
|
|
|
2020-12-26 13:21:45 +01:00
|
|
|
if (!weaponAssoc && weapon->IsFlagSet(WEAPONFLAG_THROW))
|
2020-11-19 20:12:20 +01:00
|
|
|
weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU);
|
|
|
|
|
|
|
|
if (!weaponAssoc) {
|
|
|
|
ClearAttack();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
weaponAssoc->blendDelta = -8.0f;
|
|
|
|
weaponAssoc->flags &= ~ASSOC_RUNNING;
|
|
|
|
weaponAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
weaponAssoc->SetDeleteCallback(FinishedAttackCB, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg)
|
|
|
|
{
|
|
|
|
CWeaponInfo *currentWeapon;
|
|
|
|
CAnimBlendAssociation *newAnim;
|
|
|
|
CPed *ped = (CPed*)arg;
|
|
|
|
|
|
|
|
if (attackAssoc) {
|
|
|
|
switch (attackAssoc->animId) {
|
|
|
|
case ANIM_WEAPON_START_THROW:
|
|
|
|
// what?!
|
|
|
|
if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->m_bHaveTargetSelected) && ped->IsPlayer()) {
|
|
|
|
attackAssoc->blendDelta = -1000.0f;
|
|
|
|
newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROWU);
|
|
|
|
} else {
|
|
|
|
attackAssoc->blendDelta = -1000.0f;
|
|
|
|
newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROW);
|
|
|
|
}
|
|
|
|
|
|
|
|
newAnim->SetFinishCallback(FinishedAttackCB, ped);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case ANIM_FIGHT_PPUNCH:
|
|
|
|
attackAssoc->blendDelta = -8.0f;
|
|
|
|
attackAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
ped->ClearAttack();
|
|
|
|
return;
|
|
|
|
|
|
|
|
case ANIM_WEAPON_THROW:
|
|
|
|
case ANIM_WEAPON_THROWU:
|
|
|
|
if (ped->GetWeapon()->m_nAmmoTotal > 0) {
|
|
|
|
currentWeapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType);
|
|
|
|
ped->AddWeaponModel(currentWeapon->m_nModelId);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ped->bIsAttacking)
|
|
|
|
ped->ClearAttack();
|
|
|
|
}
|
|
|
|
|
2020-12-07 00:36:40 +01:00
|
|
|
uint8
|
2020-11-19 20:12:20 +01:00
|
|
|
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.Magnitude() < 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;
|
|
|
|
|
|
|
|
if (nearPed->OnGroundOrGettingUp() || nearPed->m_nPedState == 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 animStart;
|
|
|
|
eWeaponType ourWeaponType;
|
|
|
|
float weaponAnimTime;
|
|
|
|
eWeaponFire ourWeaponFire;
|
|
|
|
float animLoopEnd;
|
|
|
|
CWeaponInfo *ourWeapon;
|
|
|
|
bool attackShouldContinue;
|
|
|
|
AnimationId reloadAnim;
|
|
|
|
CAnimBlendAssociation *reloadAnimAssoc;
|
|
|
|
float delayBetweenAnimAndFire;
|
|
|
|
CVector firePos;
|
|
|
|
|
|
|
|
ourWeaponType = GetWeapon()->m_eWeaponType;
|
|
|
|
ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType);
|
|
|
|
ourWeaponFire = ourWeapon->m_eWeaponFire;
|
|
|
|
weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay);
|
|
|
|
attackShouldContinue = bIsAttacking;
|
|
|
|
reloadAnimAssoc = nil;
|
|
|
|
reloadAnim = NUM_ANIMS;
|
|
|
|
delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire;
|
|
|
|
weaponAnim = ourWeapon->m_AnimToPlay;
|
|
|
|
|
|
|
|
if (weaponAnim == ANIM_WEAPON_HGUN_BODY)
|
|
|
|
reloadAnim = ANIM_HGUN_RELOAD;
|
|
|
|
else if (weaponAnim == ANIM_WEAPON_AK_BODY)
|
|
|
|
reloadAnim = ANIM_AK_RELOAD;
|
|
|
|
|
|
|
|
if (reloadAnim != NUM_ANIMS)
|
|
|
|
reloadAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), reloadAnim);
|
|
|
|
|
|
|
|
if (bIsDucking)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (reloadAnimAssoc) {
|
|
|
|
if (!IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected)
|
|
|
|
ClearAttack();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CTimer::GetTimeInMilliseconds() < m_shootTimer)
|
|
|
|
attackShouldContinue = true;
|
|
|
|
|
|
|
|
if (!weaponAnimAssoc) {
|
|
|
|
weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_Anim2ToPlay);
|
|
|
|
delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire;
|
|
|
|
|
|
|
|
// Long throw granade, molotov
|
2020-12-26 13:21:45 +01:00
|
|
|
if (!weaponAnimAssoc && ourWeapon->IsFlagSet(WEAPONFLAG_THROW)) {
|
2020-11-19 20:12:20 +01:00
|
|
|
weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU);
|
|
|
|
delayBetweenAnimAndFire = 0.2f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!weaponAnimAssoc) {
|
|
|
|
if (attackShouldContinue) {
|
|
|
|
if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) {
|
|
|
|
if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) {
|
|
|
|
weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
animStart = ourWeapon->m_fAnimLoopStart;
|
|
|
|
weaponAnimTime = weaponAnimAssoc->currentTime;
|
|
|
|
if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) {
|
2020-12-26 13:21:45 +01:00
|
|
|
if (ourWeapon->IsFlagSet(WEAPONFLAG_CANAIM_WITHARM))
|
2020-11-19 20:12:20 +01:00
|
|
|
m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM;
|
|
|
|
else
|
|
|
|
m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) {
|
|
|
|
if (weaponAnimAssoc->speed < 1.0f)
|
|
|
|
weaponAnimAssoc->speed = 1.0f;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
firePos = ourWeapon->m_vecFireOffset;
|
|
|
|
if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) {
|
|
|
|
if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay)
|
|
|
|
firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f;
|
|
|
|
|
|
|
|
firePos = GetMatrix() * firePos;
|
|
|
|
} else if (ourWeaponType != WEAPONTYPE_UNARMED) {
|
|
|
|
TransformToNode(firePos, weaponAnimAssoc->animId == ANIM_KICK_FLOOR ? PED_FOOTR : PED_HANDR);
|
|
|
|
} else {
|
|
|
|
firePos = GetMatrix() * firePos;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetWeapon()->Fire(this, &firePos);
|
|
|
|
|
|
|
|
if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) {
|
|
|
|
RemoveWeaponModel(ourWeapon->m_nModelId);
|
|
|
|
}
|
|
|
|
if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) {
|
|
|
|
SelectGunIfArmed();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) {
|
|
|
|
// If reloading just began, start the animation
|
|
|
|
// Last condition will always return true, even IDA hides it
|
|
|
|
if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS /* && !reloadAnimAssoc*/) {
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, reloadAnim, 8.0f);
|
|
|
|
ClearLookFlag();
|
|
|
|
ClearAimFlag();
|
|
|
|
bIsAttacking = false;
|
|
|
|
bIsPointingGunAt = false;
|
|
|
|
m_shootTimer = CTimer::GetTimeInMilliseconds();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) {
|
|
|
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f);
|
|
|
|
} else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) {
|
|
|
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
weaponAnimAssoc->speed = 0.5f;
|
|
|
|
|
|
|
|
if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) {
|
|
|
|
weaponAnimAssoc->callbackType = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
attackShouldContinue = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ourWeaponType == WEAPONTYPE_SHOTGUN) {
|
|
|
|
weaponAnimTime = weaponAnimAssoc->currentTime;
|
|
|
|
firePos = ourWeapon->m_vecFireOffset;
|
|
|
|
|
|
|
|
if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
if (IsPlayer()) {
|
|
|
|
if (CPad::GetPad(0)->GetSprint()) {
|
|
|
|
// animBreakout is a member of WeaponInfo in VC, so it's me that added the below line.
|
|
|
|
float animBreakOut = ((ourWeaponType == WEAPONTYPE_FLAMETHROWER || ourWeaponType == WEAPONTYPE_UZI || ourWeaponType == WEAPONTYPE_SHOTGUN) ? 25 / 30.0f : 99 / 30.0f);
|
|
|
|
if (!attackShouldContinue && weaponAnimAssoc->currentTime > animBreakOut) {
|
|
|
|
weaponAnimAssoc->blendDelta = -4.0f;
|
|
|
|
FinishedAttackCB(nil, this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
animLoopEnd = ourWeapon->m_fAnimLoopEnd;
|
|
|
|
if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay)
|
|
|
|
animLoopEnd = 3.4f/6.0f;
|
|
|
|
|
|
|
|
weaponAnimTime = weaponAnimAssoc->currentTime;
|
|
|
|
|
|
|
|
// Anim loop end, either start the loop again or finish the attack
|
|
|
|
if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) {
|
|
|
|
|
|
|
|
if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd
|
|
|
|
&& (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer)
|
|
|
|
&& GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) {
|
|
|
|
|
|
|
|
weaponAnim = weaponAnimAssoc->animId;
|
|
|
|
if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) {
|
|
|
|
if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) {
|
|
|
|
weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart);
|
|
|
|
} else {
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (weaponAnim == ourWeapon->m_Anim2ToPlay)
|
|
|
|
weaponAnimAssoc->SetCurrentTime(0.1f);
|
|
|
|
else
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
|
|
|
|
}
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
} else if (IsPlayer() && m_pPointGunAt && bIsAimingGun && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) {
|
|
|
|
weaponAnimAssoc->SetCurrentTime(ourWeapon->m_fAnimLoopEnd);
|
|
|
|
weaponAnimAssoc->flags &= ~ASSOC_RUNNING;
|
|
|
|
SetPointGunAt(m_pPointGunAt);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
ClearAimFlag();
|
|
|
|
|
|
|
|
// Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading)
|
|
|
|
if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) {
|
|
|
|
switch (ourWeaponType) {
|
|
|
|
case WEAPONTYPE_UZI:
|
|
|
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f);
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_AK47:
|
|
|
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f);
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_M16:
|
|
|
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fun fact: removing this part leds to reloading flamethrower
|
|
|
|
if (ourWeaponType == 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())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_nPedState == PED_FIGHT) {
|
|
|
|
m_fightButtonPressure = buttonPressure;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nPedState != PED_AIM_GUN)
|
|
|
|
SetStoredState();
|
|
|
|
|
|
|
|
if (m_nWaitState != WAITSTATE_FALSE) {
|
|
|
|
m_nWaitState = WAITSTATE_FALSE;
|
|
|
|
RestoreHeadingRate();
|
|
|
|
}
|
|
|
|
|
2020-12-15 04:11:02 +01:00
|
|
|
SetPedState(PED_FIGHT);
|
2020-11-19 20:12:20 +01:00
|
|
|
m_fightButtonPressure = 0;
|
|
|
|
RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT);
|
|
|
|
CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
|
|
|
|
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
animAssoc->blendDelta = -1000.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
|
|
|
|
if (!animAssoc)
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
|
|
|
|
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
animAssoc->blendDelta = -1000.0f;
|
|
|
|
RestoreHeadingRate();
|
|
|
|
}
|
|
|
|
|
|
|
|
SetMoveState(PEDMOVE_NONE);
|
|
|
|
m_nStoredMoveState = PEDMOVE_NONE;
|
|
|
|
|
|
|
|
CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f;
|
|
|
|
|
|
|
|
CPed *pedOnGround = nil;
|
|
|
|
if (IsPlayer() && CheckForPedsOnGroundToAttack(this, &pedOnGround) > PED_IN_FRONT_OF_ATTACKER) {
|
|
|
|
m_curFightMove = FIGHTMOVE_GROUNDKICK;
|
|
|
|
} else if (m_pedStats->m_flags & STAT_SHOPPING_BAGS) {
|
|
|
|
m_curFightMove = FIGHTMOVE_ROUNDHOUSE;
|
|
|
|
} else {
|
|
|
|
m_curFightMove = FIGHTMOVE_STDPUNCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pedOnGround && IsPlayer()) {
|
|
|
|
m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(
|
|
|
|
pedOnGround->GetPosition().x, pedOnGround->GetPosition().y,
|
|
|
|
GetPosition().x, GetPosition().y);
|
|
|
|
|
|
|
|
m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest);
|
|
|
|
m_fRotationCur = m_fRotationDest;
|
|
|
|
m_lookTimer = 0;
|
|
|
|
SetLookFlag(pedOnGround, true);
|
|
|
|
SetLookTimer(1500);
|
|
|
|
}
|
|
|
|
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f);
|
|
|
|
animAssoc->SetFinishCallback(FinishFightMoveCB, this);
|
|
|
|
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_FLOOR_HIT_F, 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_FLOOR_HIT_F, 8.0f) :
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT, 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)) {
|
|
|
|
#ifndef VC_PED_PORTS
|
|
|
|
if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 3) && CGeneral::GetRandomNumber() & 7) {
|
|
|
|
if (IsPlayer() || CGeneral::GetRandomNumber() & 3) {
|
|
|
|
#else
|
|
|
|
if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 1) && CGeneral::GetRandomNumber() & 7) {
|
|
|
|
if (IsPlayer() || CGeneral::GetRandomNumber() & 1) {
|
|
|
|
#endif
|
|
|
|
AnimationId shotAnim;
|
|
|
|
switch (direction) {
|
|
|
|
case 1:
|
|
|
|
shotAnim = ANIM_SHOT_LEFT_PARTIAL;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
shotAnim = ANIM_SHOT_BACK_PARTIAL;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
shotAnim = ANIM_SHOT_RIGHT_PARTIAL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
shotAnim = ANIM_SHOT_FRONT_PARTIAL;
|
|
|
|
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 {
|
|
|
|
#ifndef VC_PED_PORTS
|
|
|
|
switch (direction) {
|
|
|
|
case 1:
|
|
|
|
SetFall(500, ANIM_KO_SPIN_R, false);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
SetFall(500, ANIM_KO_SKID_BACK, false);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
SetFall(500, ANIM_KO_SPIN_L, false);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SetFall(500, ANIM_KO_SHOT_STOM, false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
bool fall = true;
|
|
|
|
AnimationId hitAnim;
|
|
|
|
switch (direction) {
|
|
|
|
case 1:
|
|
|
|
hitAnim = ANIM_KO_SPIN_R;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (CGeneral::GetRandomNumber() & 1) {
|
|
|
|
fall = false;
|
|
|
|
hitAnim = ANIM_HIT_BACK;
|
|
|
|
} else {
|
|
|
|
hitAnim = ANIM_KO_SKID_BACK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
hitAnim = ANIM_KO_SPIN_L;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (hitLevel == HITLEVEL_LOW) {
|
|
|
|
hitAnim = ANIM_KO_SHOT_STOM;
|
|
|
|
} else if (CGeneral::GetRandomNumber() & 1) {
|
|
|
|
fall = false;
|
|
|
|
hitAnim = ANIM_HIT_WALK;
|
|
|
|
} else if (CGeneral::GetRandomNumber() & 1) {
|
|
|
|
fall = false;
|
|
|
|
hitAnim = ANIM_HIT_HEAD;
|
|
|
|
} else {
|
|
|
|
hitAnim = ANIM_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;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
Say(SOUND_PED_DEFEND);
|
|
|
|
} else {
|
|
|
|
Say(SOUND_PED_DEFEND);
|
|
|
|
switch (hitLevel) {
|
|
|
|
case HITLEVEL_GROUND:
|
|
|
|
m_curFightMove = FIGHTMOVE_HITONFLOOR;
|
|
|
|
break;
|
|
|
|
case HITLEVEL_LOW:
|
|
|
|
#ifndef VC_PED_PORTS
|
|
|
|
if (direction == 2) {
|
|
|
|
SetFall(1000, ANIM_KO_SKID_BACK, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (direction == 2 && (!IsPlayer() || ((CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f))) {
|
|
|
|
SetFall(1000, ANIM_KO_SKID_BACK, false);
|
|
|
|
return;
|
|
|
|
} else if (direction != 2 && !IsPlayer() && (CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f) {
|
|
|
|
SetFall(1000, ANIM_KO_SHOT_STOM, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
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.3f;
|
|
|
|
|
|
|
|
m_takeAStepAfterAttack = 0;
|
|
|
|
m_fightButtonPressure = 0;
|
|
|
|
} else if (IsPlayer() && m_currentWeapon != WEAPONTYPE_UNARMED) {
|
|
|
|
CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f);
|
|
|
|
moveAssoc->SetCurrentTime(0.0f);
|
|
|
|
moveAssoc->speed = 1.3f;
|
|
|
|
} else {
|
|
|
|
if (m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK)
|
|
|
|
SetStoredState();
|
|
|
|
|
|
|
|
if (m_nWaitState != WAITSTATE_FALSE) {
|
|
|
|
m_nWaitState = WAITSTATE_FALSE;
|
|
|
|
RestoreHeadingRate();
|
|
|
|
}
|
2020-12-15 04:11:02 +01:00
|
|
|
SetPedState(PED_FIGHT);
|
2020-11-19 20:12:20 +01:00
|
|
|
m_fightButtonPressure = 0;
|
|
|
|
RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT);
|
|
|
|
CAnimBlendAssociation *walkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
|
|
|
|
if (walkStartAssoc) {
|
|
|
|
walkStartAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
walkStartAssoc->blendDelta = -1000.0f;
|
|
|
|
}
|
|
|
|
CAnimBlendAssociation *walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
|
|
|
|
if (!walkStopAssoc)
|
|
|
|
walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
|
|
|
|
if (walkStopAssoc) {
|
|
|
|
walkStopAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
walkStopAssoc->blendDelta = -1000.0f;
|
|
|
|
RestoreHeadingRate();
|
|
|
|
}
|
|
|
|
SetMoveState(PEDMOVE_NONE);
|
|
|
|
m_nStoredMoveState = PEDMOVE_NONE;
|
|
|
|
CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::Fight(void)
|
|
|
|
{
|
|
|
|
CAnimBlendAssociation *currentAssoc, *animAssoc;
|
|
|
|
bool hasShoppingBags, punchOnly, canKick, canKneeHead, canRoundhouse;
|
|
|
|
float angleToFace, nextAngle;
|
|
|
|
bool goForward = false;
|
|
|
|
int nextFightMove;
|
|
|
|
|
|
|
|
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 (!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) {
|
|
|
|
|
|
|
|
CVector touchingNodePos(0.0f, 0.0f, 0.0f);
|
|
|
|
|
|
|
|
switch (m_curFightMove) {
|
|
|
|
case FIGHTMOVE_STDPUNCH:
|
|
|
|
case FIGHTMOVE_PUNCHHOOK:
|
|
|
|
case FIGHTMOVE_BODYBLOW:
|
|
|
|
TransformToNode(touchingNodePos, PED_HANDR);
|
|
|
|
break;
|
|
|
|
case FIGHTMOVE_IDLE:
|
|
|
|
case FIGHTMOVE_SHUFFLE_F:
|
|
|
|
break;
|
|
|
|
case FIGHTMOVE_KNEE:
|
|
|
|
TransformToNode(touchingNodePos, PED_LOWERLEGR);
|
|
|
|
break;
|
|
|
|
case FIGHTMOVE_HEADBUTT:
|
|
|
|
TransformToNode(touchingNodePos, PED_HEAD);
|
|
|
|
break;
|
|
|
|
case FIGHTMOVE_PUNCHJAB:
|
|
|
|
TransformToNode(touchingNodePos, PED_HANDL);
|
|
|
|
break;
|
|
|
|
case FIGHTMOVE_KICK:
|
|
|
|
case FIGHTMOVE_LONGKICK:
|
|
|
|
case FIGHTMOVE_ROUNDHOUSE:
|
|
|
|
case FIGHTMOVE_GROUNDKICK:
|
|
|
|
TransformToNode(touchingNodePos, PED_FOOTR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_curFightMove == FIGHTMOVE_PUNCHJAB) {
|
|
|
|
touchingNodePos += 0.1f * GetForward();
|
|
|
|
} else if (m_curFightMove == FIGHTMOVE_PUNCHHOOK) {
|
|
|
|
touchingNodePos += 0.22f * GetForward();
|
|
|
|
}
|
|
|
|
FightStrike(touchingNodePos);
|
|
|
|
m_fightButtonPressure = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (curMove.hitLevel != HITLEVEL_NULL) {
|
|
|
|
if (animTime > curMove.endFireTime) {
|
|
|
|
if (IsPlayer())
|
|
|
|
currentAssoc->speed = 1.0f;
|
|
|
|
else
|
|
|
|
currentAssoc->speed = 0.8f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsPlayer() && !nPlayerInComboMove) {
|
|
|
|
if (curMove.comboFollowOnTime > 0.0f && m_fightButtonPressure != 0 && animTime > curMove.comboFollowOnTime) {
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
m_fightButtonPressure = 0;
|
|
|
|
nPlayerInComboMove = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (curMove.startFireTime > 0.0f && m_curFightMove != FIGHTMOVE_SHUFFLE_F && animTime > curMove.startFireTime) {
|
|
|
|
if (IsPlayer())
|
|
|
|
currentAssoc->speed = 1.3f;
|
|
|
|
else
|
|
|
|
currentAssoc->speed = 0.8f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) {
|
|
|
|
EndFight(ENDFIGHT_FAST);
|
|
|
|
|
|
|
|
} else if (m_fightButtonPressure != 0) {
|
|
|
|
bool canAffectMultiplePeople = true;
|
|
|
|
nextAngle = m_fRotationCur;
|
|
|
|
bool kickGround = false;
|
|
|
|
float angleForGroundKick = 0.0f;
|
|
|
|
CPed *pedOnGround = nil;
|
|
|
|
|
|
|
|
Say(SOUND_PED_ATTACK);
|
|
|
|
|
|
|
|
if (IsPlayer()) {
|
|
|
|
canRoundhouse = false;
|
|
|
|
punchOnly = false;
|
|
|
|
canKick = true;
|
|
|
|
nextFightMove = (m_fightButtonPressure > 190 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE);
|
|
|
|
hasShoppingBags = false;
|
|
|
|
canKneeHead = true;
|
|
|
|
nPlayerInComboMove = 0;
|
|
|
|
} else {
|
|
|
|
nextFightMove = (m_fightButtonPressure > 120 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE);
|
|
|
|
uint16 pedFeatures = m_pedStats->m_flags;
|
|
|
|
punchOnly = pedFeatures & STAT_PUNCH_ONLY;
|
|
|
|
canRoundhouse = pedFeatures & STAT_CAN_ROUNDHOUSE;
|
|
|
|
canKneeHead = pedFeatures & STAT_CAN_KNEE_HEAD;
|
|
|
|
canKick = pedFeatures & STAT_CAN_KICK;
|
|
|
|
hasShoppingBags = pedFeatures & STAT_SHOPPING_BAGS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attack isn't scripted, find the victim
|
|
|
|
if (IsPlayer() || !m_pedInObjective) {
|
|
|
|
|
|
|
|
for (int i = 0; i < m_numNearPeds; i++) {
|
|
|
|
|
|
|
|
CPed *nearPed = m_nearPeds[i];
|
|
|
|
float nearPedDist = (nearPed->GetPosition() - GetPosition()).Magnitude();
|
|
|
|
if (nearPedDist < 3.0f) {
|
|
|
|
float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
|
|
|
|
nearPed->GetPosition().x, nearPed->GetPosition().y,
|
|
|
|
GetPosition().x, GetPosition().y);
|
|
|
|
|
|
|
|
nextAngle = CGeneral::LimitRadianAngle(angleToFace);
|
|
|
|
m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
|
|
|
|
|
|
|
|
float neededTurn = Abs(nextAngle - m_fRotationCur);
|
|
|
|
if (neededTurn > PI)
|
|
|
|
neededTurn = TWOPI - neededTurn;
|
|
|
|
|
|
|
|
if (!nearPed->OnGroundOrGettingUp()) {
|
|
|
|
|
|
|
|
if (nearPedDist < 0.8f && neededTurn < DEGTORAD(75.0f) && canKneeHead) {
|
|
|
|
canAffectMultiplePeople = false;
|
|
|
|
} else if (nearPedDist >= 1.3f || neededTurn >= DEGTORAD(55.0f) || hasShoppingBags) {
|
|
|
|
|
|
|
|
if (nearPedDist < 1.7f
|
|
|
|
&& neededTurn < DEGTORAD(35.0f)
|
|
|
|
&& (canKick || hasShoppingBags)) {
|
|
|
|
|
|
|
|
nextFightMove = FIGHTMOVE_KICK;
|
|
|
|
if (hasShoppingBags) {
|
|
|
|
nextFightMove = FIGHTMOVE_ROUNDHOUSE;
|
|
|
|
} else if (canRoundhouse && CGeneral::GetRandomNumber() & 1) {
|
|
|
|
nextFightMove = FIGHTMOVE_ROUNDHOUSE;
|
|
|
|
}
|
|
|
|
canAffectMultiplePeople = false;
|
|
|
|
} else if (nearPedDist < 2.0f && neededTurn < DEGTORAD(30.0f) && canKick) {
|
|
|
|
canAffectMultiplePeople = false;
|
|
|
|
nextFightMove = FIGHTMOVE_LONGKICK;
|
|
|
|
} else if (neededTurn < DEGTORAD(30.0f)) {
|
|
|
|
goForward = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nextFightMove += 2; // Makes it 6 or 7
|
|
|
|
if (punchOnly)
|
|
|
|
nextFightMove = FIGHTMOVE_PUNCHJAB;
|
|
|
|
|
|
|
|
canAffectMultiplePeople = false;
|
|
|
|
}
|
|
|
|
} else if (!CGame::nastyGame
|
|
|
|
|| nearPedDist >= 1.3f
|
|
|
|
|| neededTurn >= DEGTORAD(55.0f)
|
|
|
|
|| punchOnly) {
|
|
|
|
|
|
|
|
if (nearPedDist > 0.8f
|
|
|
|
&& nearPedDist < 3.0f
|
|
|
|
&& neededTurn < DEGTORAD(30.0f)) {
|
|
|
|
goForward = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (nearPed->m_nPedState != PED_DEAD || pedOnGround) {
|
|
|
|
if (!nearPed->IsPedHeadAbovePos(-0.3f)) {
|
|
|
|
canAffectMultiplePeople = false;
|
|
|
|
nextFightMove = FIGHTMOVE_GROUNDKICK;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
pedOnGround = nearPed;
|
|
|
|
kickGround = true;
|
|
|
|
angleForGroundKick = nextAngle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!canAffectMultiplePeople) {
|
|
|
|
m_fRotationDest = nextAngle;
|
|
|
|
if (IsPlayer()) {
|
|
|
|
m_fRotationCur = m_fRotationDest;
|
|
|
|
m_lookTimer = 0;
|
|
|
|
SetLookFlag(nearPed, true);
|
|
|
|
SetLookTimer(1500);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Because we're in a scripted fight with some particular ped.
|
|
|
|
canAffectMultiplePeople = false;
|
|
|
|
|
|
|
|
float fightingPedDist = (m_pedInObjective->GetPosition() - GetPosition()).Magnitude();
|
|
|
|
if (hasShoppingBags) {
|
|
|
|
if (fightingPedDist >= 1.7f)
|
|
|
|
nextFightMove = FIGHTMOVE_SHUFFLE_F;
|
|
|
|
else
|
|
|
|
nextFightMove = FIGHTMOVE_ROUNDHOUSE;
|
|
|
|
|
|
|
|
} else if (punchOnly) {
|
|
|
|
if (fightingPedDist >= 1.3f)
|
|
|
|
nextFightMove = FIGHTMOVE_SHUFFLE_F;
|
|
|
|
else
|
|
|
|
nextFightMove = FIGHTMOVE_PUNCHJAB;
|
|
|
|
|
|
|
|
} else if (fightingPedDist >= 3.0f) {
|
|
|
|
nextFightMove = FIGHTMOVE_STDPUNCH;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
angleToFace = CGeneral::GetRadianAngleBetweenPoints(
|
|
|
|
m_pedInObjective->GetPosition().x,
|
|
|
|
m_pedInObjective->GetPosition().y,
|
|
|
|
GetPosition().x,
|
|
|
|
GetPosition().y);
|
|
|
|
|
|
|
|
nextAngle = CGeneral::LimitRadianAngle(angleToFace);
|
|
|
|
m_fRotationDest = nextAngle;
|
|
|
|
m_fRotationCur = m_fRotationDest;
|
|
|
|
if (!m_pedInObjective->OnGroundOrGettingUp()) {
|
|
|
|
|
|
|
|
if (fightingPedDist >= 0.8f || !canKneeHead) {
|
|
|
|
|
|
|
|
if (fightingPedDist >= 1.3f) {
|
|
|
|
|
|
|
|
if (fightingPedDist < 1.7f && canKick) {
|
|
|
|
nextFightMove = FIGHTMOVE_KICK;
|
|
|
|
if (canRoundhouse && CGeneral::GetRandomNumber() & 1)
|
|
|
|
nextFightMove = FIGHTMOVE_ROUNDHOUSE;
|
|
|
|
|
|
|
|
} else if (fightingPedDist < 2.0f && canKick) {
|
|
|
|
nextFightMove += 5; // Makes it 9 or 10
|
|
|
|
|
|
|
|
} else {
|
|
|
|
nextFightMove = FIGHTMOVE_SHUFFLE_F;
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nextFightMove += 2; // Makes it 6 or 7
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!CGame::nastyGame
|
|
|
|
|| fightingPedDist >= 1.3f
|
|
|
|
|| m_pedInObjective->IsPlayer()
|
|
|
|
|| m_pedInObjective->m_nPedState != PED_DEAD && m_pedInObjective->IsPedHeadAbovePos(-0.3f)) {
|
|
|
|
nextFightMove = FIGHTMOVE_IDLE;
|
|
|
|
} else {
|
|
|
|
nextFightMove = FIGHTMOVE_GROUNDKICK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canAffectMultiplePeople) {
|
|
|
|
if (kickGround && IsPlayer()) {
|
|
|
|
m_fRotationDest = angleForGroundKick;
|
|
|
|
nextFightMove = FIGHTMOVE_GROUNDKICK;
|
|
|
|
m_fRotationCur = m_fRotationDest;
|
|
|
|
m_lookTimer = 0;
|
|
|
|
SetLookFlag(pedOnGround, true);
|
|
|
|
SetLookTimer(1500);
|
|
|
|
} else if (goForward) {
|
|
|
|
nextFightMove = FIGHTMOVE_SHUFFLE_F;
|
|
|
|
} else {
|
|
|
|
nextFightMove = FIGHTMOVE_STDPUNCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nextFightMove != FIGHTMOVE_IDLE) {
|
|
|
|
m_curFightMove = nextFightMove;
|
|
|
|
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f);
|
|
|
|
|
|
|
|
animAssoc->SetFinishCallback(FinishFightMoveCB, this);
|
|
|
|
if (m_fightState == FIGHTSTATE_MOVE_FINISHED && animAssoc->currentTime != 0.0f) {
|
|
|
|
animAssoc->SetCurrentTime(0.0f);
|
|
|
|
animAssoc->SetRun();
|
|
|
|
}
|
|
|
|
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_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_curFightMove = FIGHTMOVE_IDLE;
|
|
|
|
if (IsPlayer())
|
|
|
|
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500;
|
|
|
|
else
|
|
|
|
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::EndFight(uint8 endType)
|
|
|
|
{
|
|
|
|
if (m_nPedState != PED_FIGHT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_curFightMove = FIGHTMOVE_NULL;
|
|
|
|
RestorePreviousState();
|
|
|
|
CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
|
|
|
|
if (animAssoc)
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
|
|
|
|
switch (endType) {
|
|
|
|
case ENDFIGHT_NORMAL:
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 8.0f);
|
|
|
|
break;
|
|
|
|
case ENDFIGHT_WITH_A_STEP:
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 1.0f);
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_WALK_START, 8.0f);
|
|
|
|
break;
|
|
|
|
case ENDFIGHT_FAST:
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 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 12, total 12), second is the one of we fight with (from 13 to 22, total 10).
|
|
|
|
enum {
|
|
|
|
S33 = SOUND_FIGHT_PUNCH_33,
|
|
|
|
S34 = SOUND_FIGHT_KICK_34,
|
|
|
|
S35 = SOUND_FIGHT_HEADBUTT_35,
|
|
|
|
S36 = SOUND_FIGHT_PUNCH_36,
|
|
|
|
S37 = SOUND_FIGHT_PUNCH_37,
|
|
|
|
S38 = SOUND_FIGHT_CLOSE_PUNCH_38,
|
|
|
|
S39 = SOUND_FIGHT_PUNCH_39,
|
|
|
|
S40 = SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 ,
|
|
|
|
S41 = SOUND_FIGHT_PUNCH_41,
|
|
|
|
S42 = SOUND_FIGHT_PUNCH_FROM_BEHIND_42,
|
|
|
|
S43 = SOUND_FIGHT_KNEE_OR_KICK_43,
|
|
|
|
S44 = SOUND_FIGHT_KICK_44,
|
|
|
|
NO_SND = SOUND_NO_SOUND
|
|
|
|
};
|
|
|
|
uint16 hitSoundsByFightMoves[12][10] = {
|
|
|
|
{S39,S42,S43,S43,S39,S39,S39,S39,S39,S42},
|
|
|
|
{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},
|
|
|
|
{S39,S39,S39,S39,S33,S43,S39,S39,S39,S39},
|
|
|
|
{S39,S39,S39,S39,S35,S39,S38,S38,S39,S39},
|
|
|
|
{S39,S39,S39,S39,S33,S39,S41,S36,S39,S39},
|
|
|
|
{S39,S39,S39,S39,S37,S40,S38,S38,S39,S39},
|
|
|
|
{S39,S39,S39,S39,S34,S43,S44,S37,S39,S39},
|
|
|
|
{S39,S39,S39,S39,S34,S43,S44,S37,S39,S39},
|
|
|
|
{S39,S39,S39,S39,S34,S43,S44,S37,S39,S40},
|
|
|
|
{S39,S39,S39,S39,S33,S39,S41,S37,S39,S40},
|
|
|
|
{S39,S39,S39,S39,S39,S39,S39,S39,S33,S33}
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is why first dimension is between FightMove 1 and 12.
|
|
|
|
if (m_curFightMove == FIGHTMOVE_NULL || m_curFightMove >= FIGHTMOVE_HITFRONT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint16 soundId;
|
|
|
|
|
|
|
|
// And this is why second dimension is between 13 and 22.
|
|
|
|
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, 0.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CPed::FightStrike(CVector &touchedNodePos)
|
|
|
|
{
|
|
|
|
CColModel *ourCol;
|
|
|
|
CVector attackDistance;
|
|
|
|
ePedPieceTypes closestPedPiece = PEDPIECE_TORSO;
|
|
|
|
float maxDistanceToBeBeaten;
|
|
|
|
CPed *nearPed;
|
|
|
|
int state = m_fightState;
|
|
|
|
bool pedFound = false;
|
|
|
|
|
|
|
|
if (state == FIGHTSTATE_JUST_ATTACKED)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Pointless code
|
|
|
|
if (state > FIGHTSTATE_NO_MOVE)
|
|
|
|
attackDistance = touchedNodePos - m_vecHitLastPos;
|
|
|
|
|
|
|
|
for (int i = 0; i < m_numNearPeds; i++) {
|
|
|
|
nearPed = m_nearPeds[i];
|
|
|
|
if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
|
|
|
|
maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_curFightMove].strikeRadius + 0.1f;
|
|
|
|
else
|
|
|
|
maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_curFightMove].strikeRadius;
|
|
|
|
|
|
|
|
if (nearPed->bUsesCollision || nearPed->m_nPedState == PED_DEAD) {
|
|
|
|
CVector nearPedCentre;
|
|
|
|
nearPed->GetBoundCentre(nearPedCentre);
|
|
|
|
CVector potentialAttackDistance = nearPedCentre - touchedNodePos;
|
|
|
|
|
|
|
|
// He can beat us
|
|
|
|
if (sq(maxDistanceToBeBeaten) > potentialAttackDistance.MagnitudeSqr()) {
|
|
|
|
|
|
|
|
#ifdef PED_SKIN
|
|
|
|
// Have to animate a skinned clump because the initial col model is useless
|
|
|
|
if(IsClumpSkinned(GetClump()))
|
|
|
|
ourCol = ((CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()))->AnimatePedColModelSkinned(GetClump());
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
if (nearPed->OnGround() || !nearPed->IsPedHeadAbovePos(-0.3f)) {
|
|
|
|
ourCol = &CTempColModels::ms_colModelPedGroundHit;
|
|
|
|
} else {
|
|
|
|
#ifdef ANIMATE_PED_COL_MODEL
|
|
|
|
ourCol = CPedModelInfo::AnimatePedColModel(((CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()))->GetHitColModel(),
|
|
|
|
RpClumpGetFrame(GetClump()));
|
|
|
|
#else
|
|
|
|
ourCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->GetHitColModel();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 0; j < ourCol->numSpheres; j++) {
|
|
|
|
attackDistance = nearPed->GetPosition() + ourCol->spheres[j].center;
|
|
|
|
attackDistance -= touchedNodePos;
|
|
|
|
CColSphere *ourPieces = ourCol->spheres;
|
|
|
|
float maxDistanceToBeat = ourPieces[j].radius + tFightMoves[m_curFightMove].strikeRadius;
|
|
|
|
|
|
|
|
// We can beat him too
|
|
|
|
if (sq(maxDistanceToBeat) > attackDistance.MagnitudeSqr()) {
|
|
|
|
pedFound = true;
|
|
|
|
closestPedPiece = (ePedPieceTypes) ourPieces[j].piece;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pedFound)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pedFound) {
|
|
|
|
if (nearPed->IsPlayer() && nearPed->m_nPedState == PED_GETUP)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
float oldVictimHealth = nearPed->m_fHealth;
|
|
|
|
CVector bloodPos = 0.5f * attackDistance + touchedNodePos;
|
|
|
|
int damageMult = tFightMoves[m_curFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1;
|
|
|
|
|
|
|
|
CVector2D diff (GetPosition() - nearPed->GetPosition());
|
|
|
|
int direction = nearPed->GetLocalDirection(diff);
|
|
|
|
if (IsPlayer()) {
|
|
|
|
if (((CPlayerPed*)this)->m_bAdrenalineActive)
|
|
|
|
damageMult = 20;
|
|
|
|
} else {
|
|
|
|
damageMult *= m_pedStats->m_attackStrength;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change direction if we used kick.
|
|
|
|
if (m_curFightMove == FIGHTMOVE_KICK) {
|
|
|
|
if (CGeneral::GetRandomNumber() & 1) {
|
|
|
|
direction++;
|
|
|
|
if (direction > 3)
|
|
|
|
direction -= 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nearPed->ReactToAttack(this);
|
|
|
|
|
|
|
|
// Mostly unused. if > 5, ANIM_HIT_WALK will be run, that's it.
|
|
|
|
int unk2;
|
|
|
|
if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !nearPed->IsPlayer())
|
|
|
|
unk2 = 101;
|
|
|
|
else
|
|
|
|
unk2 = damageMult;
|
|
|
|
|
|
|
|
nearPed->StartFightDefend(direction, tFightMoves[m_curFightMove].hitLevel, unk2);
|
|
|
|
PlayHitSound(nearPed);
|
|
|
|
m_fightState = FIGHTSTATE_JUST_ATTACKED;
|
|
|
|
RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId)->speed = 0.6f;
|
|
|
|
if (!nearPed->DyingOrDead()) {
|
|
|
|
nearPed->InflictDamage(this, WEAPONTYPE_UNARMED, damageMult * 3.0f, closestPedPiece, direction);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CGame::nastyGame
|
|
|
|
&& tFightMoves[m_curFightMove].hitLevel > HITLEVEL_MEDIUM
|
|
|
|
&& nearPed->m_nPedState == PED_DIE
|
|
|
|
&& nearPed->GetIsOnScreen()) {
|
|
|
|
|
|
|
|
// Just for blood particle. We will restore it below.
|
|
|
|
attackDistance /= (10.0f * attackDistance.Magnitude());
|
|
|
|
for(int i=0; i<4; i++) {
|
|
|
|
CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, attackDistance, nil, 0.0f, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!nearPed->OnGround()) {
|
|
|
|
float curVictimHealth = nearPed->m_fHealth;
|
|
|
|
if (curVictimHealth > 0.0f
|
|
|
|
&& (curVictimHealth < 40.0f && oldVictimHealth > 40.0f && !nearPed->IsPlayer()
|
|
|
|
|| nearPed->m_fHealth < 20.0f && oldVictimHealth > 20.0f
|
|
|
|
|| GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && IsPlayer()
|
|
|
|
|| nearPed->m_pedStats->m_flags & STAT_ONE_HIT_KNOCKDOWN)) {
|
|
|
|
|
|
|
|
nearPed->SetFall(0, (AnimationId)(direction + ANIM_KO_SKID_FRONT), 0);
|
|
|
|
if (nearPed->m_nPedState == PED_FALL)
|
|
|
|
nearPed->bIsStanding = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nearPed->m_nPedState == PED_DIE || !nearPed->bIsStanding) {
|
|
|
|
attackDistance = nearPed->GetPosition() - GetPosition();
|
|
|
|
attackDistance.Normalise();
|
|
|
|
attackDistance.z = 1.0f;
|
|
|
|
nearPed->bIsStanding = false;
|
|
|
|
|
|
|
|
float moveMult;
|
|
|
|
if (m_curFightMove == FIGHTMOVE_GROUNDKICK) {
|
|
|
|
moveMult = Min(damageMult * 0.6f, 4.0f);
|
|
|
|
} else {
|
|
|
|
if (nearPed->m_nPedState != PED_DIE || damageMult >= 20) {
|
|
|
|
moveMult = damageMult;
|
|
|
|
} else {
|
|
|
|
moveMult = Min(damageMult * 2.0f, 14.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nearPed->ApplyMoveForce(moveMult * 0.6f * attackDistance);
|
|
|
|
}
|
|
|
|
CEventList::RegisterEvent(nearPed->m_nPedType == PEDTYPE_COP ? EVENT_ASSAULT_POLICE : EVENT_ASSAULT, EVENT_ENTITY_PED, nearPed, this, 2000);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fightState == FIGHTSTATE_NO_MOVE)
|
|
|
|
m_fightState = FIGHTSTATE_1;
|
|
|
|
|
2020-12-18 01:57:54 +01:00
|
|
|
m_vecHitLastPos = touchedNodePos;
|
2020-11-19 20:12:20 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
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 %c %s %d %d",
|
|
|
|
moveName,
|
|
|
|
&startFireTime,
|
|
|
|
&endFireTime,
|
|
|
|
&comboFollowOnTime,
|
|
|
|
&strikeRadius,
|
|
|
|
&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].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;
|
|
|
|
}
|
|
|
|
|
2020-12-25 14:18:13 +01:00
|
|
|
if (strcmp(animName, "null") != 0) {
|
2020-11-19 20:12:20 +01:00
|
|
|
animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animName);
|
|
|
|
tFightMoves[moveId].animId = (AnimationId)animAssoc->animId;
|
|
|
|
} else {
|
|
|
|
tFightMoves[moveId].animId = ANIM_WALK;
|
|
|
|
}
|
|
|
|
moveId++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::SetInvestigateEvent(eEventType event, CVector2D pos, float distanceToCountDone, uint16 time, float angle)
|
|
|
|
{
|
|
|
|
if (!IsPedInControl() || CharCreatedBy == MISSION_CHAR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SetStoredState();
|
|
|
|
bFindNewNodeAfterStateRestore = false;
|
2020-12-15 04:11:02 +01:00
|
|
|
SetPedState(PED_INVESTIGATE);
|
2020-11-19 20:12:20 +01:00
|
|
|
m_standardTimer = 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_HANDSCOWER, 4.0f);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::InvestigateEvent(void)
|
|
|
|
{
|
|
|
|
CAnimBlendAssociation *animAssoc;
|
|
|
|
AnimationId animToPlay;
|
|
|
|
AssocGroupId animGroup;
|
|
|
|
|
|
|
|
if (m_nWaitState == WAITSTATE_TURN180)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (CTimer::GetTimeInMilliseconds() > m_standardTimer) {
|
|
|
|
|
|
|
|
if (m_standardTimer) {
|
|
|
|
if (m_eventType < EVENT_ASSAULT_NASTYWEAPON)
|
|
|
|
SetWaitState(WAITSTATE_TURN180, nil);
|
|
|
|
|
|
|
|
m_standardTimer = 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_ROAD_CROSS);
|
|
|
|
|
|
|
|
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_ROAD_CROSS, 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_IDLE_CAM);
|
|
|
|
if (!animAssoc)
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
|
|
|
|
|
|
|
|
if (animAssoc && animAssoc->animId == ANIM_IDLE_CAM) {
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
|
|
|
|
SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500));
|
|
|
|
|
|
|
|
} else if (CGeneral::GetRandomNumber() & 3) {
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CAM, 4.0f);
|
|
|
|
SetLookTimer(CGeneral::GetRandomNumberInRange(2500, 5000));
|
|
|
|
Say(SOUND_PED_CHAT_EVENT);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
m_standardTimer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) {
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
|
|
|
|
if (!animAssoc)
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB);
|
|
|
|
|
|
|
|
if (!animAssoc)
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH);
|
|
|
|
|
|
|
|
if (animAssoc && animAssoc->animId == ANIM_IDLE_STANCE) {
|
|
|
|
if (CGeneral::GetRandomNumber() & 1)
|
|
|
|
animToPlay = ANIM_IDLE_HBHB;
|
|
|
|
else
|
|
|
|
animToPlay = ANIM_XPRESS_SCRATCH;
|
|
|
|
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f);
|
|
|
|
SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000));
|
|
|
|
|
|
|
|
} else if (animAssoc && animAssoc->animId == ANIM_IDLE_HBHB) {
|
|
|
|
animAssoc->blendDelta = -8.0f;
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
if (CGeneral::GetRandomNumber() & 1) {
|
|
|
|
animToPlay = ANIM_IDLE_STANCE;
|
|
|
|
animGroup = m_animGroup;
|
|
|
|
} else {
|
|
|
|
animToPlay = ANIM_XPRESS_SCRATCH;
|
|
|
|
animGroup = ASSOCGRP_STD;
|
|
|
|
}
|
|
|
|
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f);
|
|
|
|
SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (CGeneral::GetRandomNumber() & 1) {
|
|
|
|
animToPlay = ANIM_IDLE_STANCE;
|
|
|
|
animGroup = m_animGroup;
|
|
|
|
} else {
|
|
|
|
animToPlay = ANIM_IDLE_HBHB;
|
|
|
|
animGroup = ASSOCGRP_STD;
|
|
|
|
}
|
|
|
|
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f);
|
|
|
|
SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500));
|
|
|
|
}
|
|
|
|
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_ROAD_CROSS);
|
|
|
|
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->blendDelta = -8.0f;
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
if (m_eventType == EVENT_ICECREAM)
|
|
|
|
animToPlay = ANIM_IDLE_CHAT;
|
|
|
|
else
|
|
|
|
animToPlay = ANIM_XPRESS_SCRATCH;
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay,4.0f);
|
|
|
|
SetLookTimer(CGeneral::GetRandomNumberInRange(2000, 5000));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT);
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->blendDelta = -8.0f;
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
ClearInvestigateEvent();
|
|
|
|
} else {
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH);
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->blendDelta = -8.0f;
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
}
|
|
|
|
ClearInvestigateEvent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < m_numNearPeds; i++) {
|
|
|
|
if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < sq(0.4f)) {
|
|
|
|
SetMoveState(PEDMOVE_STILL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetMoveState(PEDMOVE_WALK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CPed::ClearInvestigateEvent(void)
|
|
|
|
{
|
|
|
|
CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS);
|
|
|
|
if (!animAssoc)
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH);
|
|
|
|
if (!animAssoc)
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB);
|
|
|
|
if (!animAssoc)
|
|
|
|
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT);
|
|
|
|
if (animAssoc) {
|
|
|
|
animAssoc->blendDelta = -8.0f;
|
|
|
|
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
|
|
|
|
}
|
|
|
|
if (m_eventType > EVENT_EXPLOSION)
|
|
|
|
m_standardTimer = 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_KO_SHOT_FRONT1;
|
|
|
|
bool headShot = false;
|
|
|
|
bool willLinger = false;
|
|
|
|
int random;
|
|
|
|
|
|
|
|
if (player == this) {
|
|
|
|
if (!player->m_bCanBeDamaged)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
player->AnnoyPlayerPed(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DyingOrDead())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!bUsesCollision && 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;
|
|
|
|
|
|
|
|
bool detectDieAnim = true;
|
|
|
|
if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) {
|
|
|
|
if (!IsPedHeadAbovePos(-0.3f)) {
|
|
|
|
if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL))
|
|
|
|
dieAnim = ANIM_FLOOR_HIT_F;
|
|
|
|
else
|
|
|
|
dieAnim = ANIM_FLOOR_HIT;
|
|
|
|
dieDelta *= 2.0f;
|
|
|
|
dieSpeed = 0.5f;
|
|
|
|
detectDieAnim = false;
|
|
|
|
} else if (m_nPedState == PED_FALL) {
|
|
|
|
dieAnim = NUM_ANIMS;
|
|
|
|
detectDieAnim = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (detectDieAnim) {
|
|
|
|
switch (method) {
|
|
|
|
case WEAPONTYPE_UNARMED:
|
|
|
|
if (bMeleeProof)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (m_nPedState == PED_FALL) {
|
|
|
|
if (IsPedHeadAbovePos(-0.3f)) {
|
|
|
|
dieAnim = NUM_ANIMS;
|
|
|
|
} else {
|
|
|
|
if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL))
|
|
|
|
dieAnim = ANIM_FLOOR_HIT_F;
|
|
|
|
else
|
|
|
|
dieAnim = ANIM_FLOOR_HIT;
|
|
|
|
dieDelta = dieDelta * 2.0f;
|
|
|
|
dieSpeed = 0.5f;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (direction) {
|
|
|
|
case 0:
|
|
|
|
dieAnim = ANIM_KO_SKID_FRONT;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
dieAnim = ANIM_KO_SPIN_R;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
dieAnim = ANIM_KO_SKID_BACK;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
dieAnim = ANIM_KO_SPIN_L;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_BASEBALLBAT:
|
|
|
|
if (bMeleeProof)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (m_nPedState == PED_FALL) {
|
|
|
|
if (IsPedHeadAbovePos(-0.3f)) {
|
|
|
|
dieAnim = NUM_ANIMS;
|
|
|
|
} else {
|
|
|
|
if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL))
|
|
|
|
dieAnim = ANIM_FLOOR_HIT_F;
|
|
|
|
else
|
|
|
|
dieAnim = ANIM_FLOOR_HIT;
|
|
|
|
dieDelta = dieDelta * 2.0f;
|
|
|
|
dieSpeed = 0.5f;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (direction) {
|
|
|
|
case 0:
|
|
|
|
dieAnim = ANIM_KO_SKID_FRONT;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
dieAnim = ANIM_KO_SPIN_R;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
dieAnim = ANIM_KO_SKID_BACK;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
dieAnim = ANIM_KO_SPIN_L;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_COLT45:
|
|
|
|
case WEAPONTYPE_UZI:
|
|
|
|
case WEAPONTYPE_SHOTGUN:
|
|
|
|
case WEAPONTYPE_AK47:
|
|
|
|
case WEAPONTYPE_M16:
|
|
|
|
case WEAPONTYPE_SNIPERRIFLE:
|
|
|
|
if (bBulletProof)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool dontRemoveLimb;
|
|
|
|
if (IsPlayer() || bNoCriticalHits)
|
|
|
|
dontRemoveLimb = true;
|
|
|
|
else {
|
|
|
|
switch (method) {
|
|
|
|
case WEAPONTYPE_SNIPERRIFLE:
|
|
|
|
dontRemoveLimb = false;
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_M16:
|
|
|
|
dontRemoveLimb = false;
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_SHOTGUN:
|
|
|
|
dontRemoveLimb = CGeneral::GetRandomNumber() & 7;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dontRemoveLimb = CGeneral::GetRandomNumber() & 15;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dontRemoveLimb) {
|
|
|
|
if (method == WEAPONTYPE_SHOTGUN) {
|
|
|
|
switch (direction) {
|
|
|
|
case 0:
|
|
|
|
dieAnim = ANIM_KO_SKID_FRONT;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
dieAnim = ANIM_KO_SPIN_R;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
dieAnim = ANIM_KO_SKID_BACK;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
dieAnim = ANIM_KO_SPIN_L;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
dieAnim = ANIM_KO_SHOT_FRONT1;
|
|
|
|
|
|
|
|
willLinger = false;
|
|
|
|
} else {
|
|
|
|
switch (pedPiece) {
|
|
|
|
case PEDPIECE_TORSO:
|
|
|
|
willLinger = false;
|
|
|
|
dieAnim = ANIM_KO_SHOT_FRONT1;
|
|
|
|
break;
|
|
|
|
case PEDPIECE_MID:
|
|
|
|
willLinger = false;
|
|
|
|
dieAnim = ANIM_KO_SHOT_STOM;
|
|
|
|
break;
|
|
|
|
case PEDPIECE_LEFTARM:
|
|
|
|
dieAnim = ANIM_KO_SHOT_ARML;
|
|
|
|
RemoveBodyPart(PED_UPPERARML, direction);
|
|
|
|
willLinger = true;
|
|
|
|
break;
|
|
|
|
case PEDPIECE_RIGHTARM:
|
|
|
|
dieAnim = ANIM_KO_SHOT_ARMR;
|
|
|
|
RemoveBodyPart(PED_UPPERARMR, direction);
|
|
|
|
willLinger = true;
|
|
|
|
break;
|
|
|
|
case PEDPIECE_LEFTLEG:
|
|
|
|
dieAnim = ANIM_KO_SHOT_LEGL;
|
|
|
|
RemoveBodyPart(PED_UPPERLEGL, direction);
|
|
|
|
willLinger = true;
|
|
|
|
break;
|
|
|
|
case PEDPIECE_RIGHTLEG:
|
|
|
|
dieAnim = ANIM_KO_SHOT_LEGR;
|
|
|
|
RemoveBodyPart(PED_UPPERLEGR, direction);
|
|
|
|
willLinger = true;
|
|
|
|
break;
|
|
|
|
case PEDPIECE_HEAD:
|
|
|
|
dieAnim = ANIM_KO_SHOT_FACE;
|
|
|
|
RemoveBodyPart(PED_HEAD, direction);
|
|
|
|
headShot = true;
|
|
|
|
willLinger = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_ROCKETLAUNCHER:
|
|
|
|
case WEAPONTYPE_GRENADE:
|
|
|
|
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_KO_SKID_FRONT;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
dieAnim = ANIM_KO_SPIN_R;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
dieAnim = ANIM_KO_SKID_BACK;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
dieAnim = ANIM_KO_SPIN_L;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_FLAMETHROWER:
|
|
|
|
if (bFireProof)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dieAnim = ANIM_KO_SHOT_FRONT1;
|
|
|
|
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_KO_SPIN_L;
|
|
|
|
else
|
|
|
|
dieAnim = ANIM_KO_SKID_FRONT;
|
|
|
|
} else
|
|
|
|
dieAnim = ANIM_KO_SPIN_R;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (m_nPedState == PED_DIVE_AWAY)
|
|
|
|
dieAnim = ANIM_KD_LEFT;
|
|
|
|
else
|
|
|
|
dieAnim = ANIM_KO_SPIN_R;
|
|
|
|
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_KO_SKID_BACK;
|
|
|
|
} else {
|
|
|
|
dieAnim = ANIM_KD_RIGHT;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
dieAnim = ANIM_KD_LEFT;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (m_nPedState == PED_DIVE_AWAY)
|
|
|
|
dieAnim = ANIM_KD_RIGHT;
|
|
|
|
else
|
|
|
|
dieAnim = ANIM_KO_SPIN_L;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (damagedBy) {
|
|
|
|
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_DROWN;
|
|
|
|
break;
|
|
|
|
case WEAPONTYPE_FALL:
|
|
|
|
if (bCollisionProof)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (direction) {
|
|
|
|
case 0:
|
|
|
|
dieAnim = ANIM_KO_SKID_FRONT;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
dieAnim = ANIM_KO_SPIN_R;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
dieAnim = ANIM_KO_SKID_BACK;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
dieAnim = ANIM_KO_SPIN_L;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fHealth - healthImpact >= 1.0f && !willLinger) {
|
|
|
|
m_fHealth -= healthImpact;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bInVehicle) {
|
|
|
|
if (method != WEAPONTYPE_DROWNING) {
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
if (m_pMyVehicle) {
|
|
|
|
if (m_pMyVehicle->IsCar() && 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()) {
|
|
|
|
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) {
|
|
|
|
// PlayerInfo stuff
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(m_pMyVehicle->pPassengers); i++) {
|
|
|
|
CPed* passenger = m_pMyVehicle->pPassengers[i];
|
|
|
|
if (passenger && passenger != this && damagedBy)
|
|
|
|
passenger->ReactToAttack(damagedBy);
|
|
|
|
}
|
|
|
|
|
|
|
|
CPed *driverOfVeh = m_pMyVehicle->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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
m_fHealth = 1.0f;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
m_fHealth = 0.0f;
|
|
|
|
if (player == this)
|
|
|
|
m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED);
|
|
|
|
|
|
|
|
SetDie(NUM_ANIMS, 4.0f, 0.0f);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
m_fHealth = 0.0f;
|
|
|
|
SetDie(dieAnim, dieDelta, dieSpeed);
|
|
|
|
|
|
|
|
if (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) {
|
|
|
|
|
|
|
|
// There are PlayerInfo stuff here in VC
|
|
|
|
CDarkel::RegisterKillByPlayer(this, method, headShot);
|
|
|
|
m_threatEntity = player;
|
|
|
|
} else {
|
|
|
|
CDarkel::RegisterKillNotByPlayer(this, method);
|
|
|
|
}
|
|
|
|
if (method == WEAPONTYPE_DROWNING)
|
|
|
|
bIsInTheAir = false;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
#ifdef PED_SKIN
|
|
|
|
if(!IsClumpSkinned(GetClump()))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
#ifdef DEBUGMENU
|
|
|
|
if (bPopHeadsOnHeadshot || nodeId != PED_HEAD)
|
|
|
|
#else
|
|
|
|
if (nodeId != PED_HEAD)
|
|
|
|
#endif
|
|
|
|
SpawnFlyingComponent(nodeId, direction);
|
|
|
|
|
|
|
|
RecurseFrameChildrenVisibilityCB(frame, nil);
|
|
|
|
}
|
|
|
|
pos.x = 0.0f;
|
|
|
|
pos.y = 0.0f;
|
|
|
|
pos.z = 0.0f;
|
|
|
|
TransformToNode(pos, PED_HEAD);
|
|
|
|
|
|
|
|
if (CEntity::GetIsOnScreen()) {
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (CObject::nNoTempObjects >= NUMTEMPOBJECTS)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
#ifdef PED_SKIN
|
|
|
|
assert(!IsClumpSkinned(GetClump()));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CObject *obj = new CObject();
|
|
|
|
if (!obj)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
RwFrame *frame = RwFrameCreate();
|
|
|
|
RpClump *clump = RpClumpCreate();
|
|
|
|
RpClumpSetFrame(clump, frame);
|
|
|
|
RwMatrix *matrix = RwFrameGetLTM(m_pFrames[pedNode]->frame);
|
|
|
|
*RwFrameGetMatrix(frame) = *matrix;
|
|
|
|
|
|
|
|
flyingClumpTemp = clump;
|
|
|
|
RwFrameForAllObjects(m_pFrames[pedNode]->frame, CloneAtomicToFrameCB, frame);
|
|
|
|
RwFrameForAllChildren(m_pFrames[pedNode]->frame, RecurseFrameChildrenToCloneCB, frame);
|
|
|
|
flyingClumpTemp = nil;
|
|
|
|
switch (pedNode) {
|
|
|
|
case PED_HEAD:
|
|
|
|
// So popping head would have wheel collision. They disabled it anyway
|
|
|
|
obj->SetModelIndexNoCreate(MI_CAR_WHEEL);
|
|
|
|
break;
|
|
|
|
case PED_UPPERARML:
|
|
|
|
case PED_UPPERARMR:
|
|
|
|
obj->SetModelIndexNoCreate(MI_BODYPARTB);
|
|
|
|
obj->SetCenterOfMass(0.25f, 0.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
case PED_UPPERLEGL:
|
|
|
|
case PED_UPPERLEGR:
|
|
|
|
obj->SetModelIndexNoCreate(MI_BODYPARTA);
|
|
|
|
obj->SetCenterOfMass(0.4f, 0.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
obj->RefModelInfo(GetModelIndex());
|
|
|
|
obj->AttachToRwObject((RwObject*)clump);
|
|
|
|
obj->m_fMass = 15.0f;
|
|
|
|
obj->m_fTurnMass = 5.0f;
|
|
|
|
obj->m_fAirResistance = 0.99f;
|
|
|
|
obj->m_fElasticity = 0.03f;
|
|
|
|
obj->m_fBuoyancy = m_fMass*GRAVITY/0.75f;
|
|
|
|
obj->ObjectCreatedBy = TEMP_OBJECT;
|
|
|
|
obj->SetIsStatic(false);
|
|
|
|
obj->bIsPickup = false;
|
|
|
|
obj->m_nSpecialCollisionResponseCases = COLLRESPONSE_SMALLBOX;
|
|
|
|
|
|
|
|
// life time - the more objects the are, the shorter this one will live
|
|
|
|
CObject::nNoTempObjects++;
|
|
|
|
if (CObject::nNoTempObjects > 20)
|
|
|
|
obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 12000;
|
|
|
|
else if (CObject::nNoTempObjects > 10)
|
|
|
|
obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 30000;
|
|
|
|
else
|
|
|
|
obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 60000;
|
|
|
|
|
|
|
|
CVector localForcePos, forceDir;
|
|
|
|
|
|
|
|
if (direction == 2) {
|
|
|
|
obj->m_vecMoveSpeed = 0.03f * GetForward();
|
|
|
|
obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f;
|
|
|
|
obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
|
|
|
localForcePos = CVector(0.0f, 0.0f, 0.0f);
|
|
|
|
forceDir = GetForward();
|
|
|
|
} else {
|
|
|
|
obj->m_vecMoveSpeed = -0.03f * GetForward();
|
|
|
|
obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f;
|
|
|
|
obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
|
|
|
localForcePos = CVector(0.0f, 0.0f, 0.0f);
|
|
|
|
forceDir = -GetForward();
|
|
|
|
}
|
|
|
|
obj->ApplyTurnForce(forceDir, localForcePos);
|
|
|
|
CWorld::Add(obj);
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
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(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
|
|
|
|
// }
|
|
|
|
|
|
|
|
bBodyPartJustCameOff = true;
|
|
|
|
m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8
|
|
|
|
CPed::DoesLOSBulletHitPed(CColPoint &colPoint)
|
|
|
|
{
|
|
|
|
#ifdef FIX_BUGS
|
|
|
|
return 1;
|
|
|
|
#else
|
|
|
|
uint8 retVal = 2;
|
|
|
|
|
|
|
|
float headZ = GetNodePosition(PED_HEAD).z;
|
|
|
|
|
|
|
|
if (m_nPedState == PED_FALL)
|
|
|
|
retVal = 1;
|
|
|
|
|
|
|
|
float colZ = colPoint.point.z;
|
|
|
|
if (colZ < headZ)
|
|
|
|
retVal = 1;
|
|
|
|
|
|
|
|
if (headZ + 0.2f <= colZ)
|
|
|
|
retVal = 0;
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
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
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
|| m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && m_pedInObjective == collideWith
|
|
|
|
|| collideWith->m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && collideWith->m_pedInObjective == this
|
|
|
|
#endif
|
|
|
|
)) {
|
|
|
|
|
|
|
|
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 (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 (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);
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
m_fRotationCur = 0.3f + m_fRotationCur;
|
|
|
|
m_fRotationDest = m_fRotationCur;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(250, 450);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
if (m_pedInObjective && (collideWith == m_pedInObjective || collideWith->m_pedInObjective == m_pedInObjective) && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) {
|
|
|
|
#else
|
|
|
|
if (m_pedInObjective && collideWith == m_pedInObjective && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) {
|
|
|
|
#endif
|
|
|
|
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
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
|| collideWith->IsPlayer() || CTimer::GetTimeInMilliseconds() < m_nPedStateTimer
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
|
|
|
|
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_FIGHT_PPUNCH, 8.0f);
|
|
|
|
animAssoc->flags |= ASSOC_FADEOUTWHENDONE;
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000;
|
|
|
|
#endif
|
|
|
|
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
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
|| m_pedStats->m_defendWeakness <= collideWith->m_pedStats->m_defendWeakness
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
// 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_HIT_LEFT;
|
|
|
|
else
|
|
|
|
animToPlay = ANIM_SHOT_LEFT_PARTIAL;
|
|
|
|
} 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_HIT_RIGHT;
|
|
|
|
else
|
|
|
|
animToPlay = ANIM_SHOT_RIGHT_PARTIAL;
|
|
|
|
} else {
|
|
|
|
if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT)
|
|
|
|
animToPlay = ANIM_HIT_BACK;
|
|
|
|
else
|
|
|
|
animToPlay = ANIM_SHOT_BACK_PARTIAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_FIGHT_PUNCH_39, 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_KO_SPIN_L;
|
|
|
|
else
|
|
|
|
animToPlay = ANIM_KD_RIGHT;
|
|
|
|
} else {
|
|
|
|
CVector moveForce = GetRight();
|
|
|
|
moveForce.z += 0.1f;
|
|
|
|
ApplyMoveForce(moveForce);
|
|
|
|
if (heLooksToUs)
|
|
|
|
animToPlay = ANIM_KO_SPIN_R;
|
|
|
|
else
|
|
|
|
animToPlay = ANIM_KD_LEFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nPedState == PED_ATTACK && collideWith->IsPedInControl())
|
|
|
|
DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 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 (!this->m_pCollidingEntity || car->GetStatus() == STATUS_PLAYER)
|
|
|
|
this->m_pCollidingEntity = car;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nPedState == PED_DEAD)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_pCurSurface) {
|
|
|
|
if (m_pCurSurface->IsVehicle() && (((CVehicle*)m_pCurSurface)->m_vehType == VEHICLE_TYPE_BOAT || 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 distVec anymore.
|
|
|
|
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->m_vehType == VEHICLE_TYPE_CAR) {
|
|
|
|
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();
|
|
|
|
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
distVec *= Min(car->m_fMass / 1400.0f, 1.0f);
|
|
|
|
#endif
|
|
|
|
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_KO_SKID_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();
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
distVec *= Min(car->m_fMass / 1400.0f, 1.0f);
|
|
|
|
#endif
|
|
|
|
car->ApplyMoveForce(distVec * -60.0f);
|
|
|
|
Say(SOUND_PED_DEFEND);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VC_PED_PORTS
|
|
|
|
// Killing gang members with car wasn't triggering a fight, until now... Taken from VC.
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|