CPed part 218

This commit is contained in:
eray orçunus 2019-08-05 16:07:10 +03:00
parent a3e3527a3b
commit 2fc69a0aa5
3 changed files with 656 additions and 68 deletions

View File

@ -16,6 +16,7 @@
#include "Boat.h"
#include "Heli.h"
#include "Automobile.h"
#include "Ped.h"
#include "debugmenu_public.h"
#include <vector>
@ -334,6 +335,9 @@ DebugMenuPopulate(void)
DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil);
DebugMenuAddVarBool8("Debug", "Don't render Vehicles", (int8*)&gbDontRenderVehicles, nil);
DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil);
#ifndef FINAL
DebugMenuAddVarBool8("Debug", "Toggle unused fight feature", (int8*)&CPed::bUnusedFightThingOnPlayer, nil);
#endif
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);

View File

@ -31,6 +31,7 @@
#include "FileMgr.h"
#include "TempColModels.h"
#include "Pickups.h"
#include "Train.h"
WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
@ -60,8 +61,8 @@ CColPoint &CPed::ms_tempColPoint = *(CColPoint*)0x62DB14;
// TODO: PedAudioData should be hardcoded into exe, and it isn't reversed yet.
CPedAudioData (&CPed::PedAudioData)[38] = *(CPedAudioData(*)[38]) * (uintptr*)0x5F94C4;
uint16 &CPed::unknownFightThing = *(uint16*)0x95CC58;
FightMove (&CPed::ms_fightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844;
uint16 &CPed::nPlayerInComboMove = *(uint16*)0x95CC58;
FightMove (&CPed::tFightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844;
uint16 &CPed::distanceMultToCountPedNear = *(uint16*)0x5F8C98;
@ -69,6 +70,10 @@ CVector &CPed::offsetToOpenRegularCarDoor = *(CVector*)0x62E030;
CVector &CPed::offsetToOpenLowCarDoor = *(CVector*)0x62E03C;
CVector &CPed::offsetToOpenVanDoor = *(CVector*)0x62E048;
#ifndef FINAL
bool CPed::bUnusedFightThingOnPlayer = false;
#endif
void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); }
void *CPed::operator new(size_t sz, int handle) { return CPools::GetPedPool()->New(handle); }
void CPed::operator delete(void *p, size_t sz) { CPools::GetPedPool()->Delete((CPed*)p); }
@ -374,7 +379,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bIsStanding = false;
m_ped_flagA2 = false;
m_ped_flagA4 = false;
bIsAttacking = false;
bIsPointingGunAt = false;
bIsLooking = false;
m_ped_flagA20 = false;
@ -531,7 +536,7 @@ RemoveAllModelCB(RwObject *object, void *data)
}
static PedOnGroundState
CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
CheckForPedsOnGroundToAttack(CPed *attacker, CPed **pedOnGround)
{
PedOnGroundState stateToReturn;
float angleToFace;
@ -549,22 +554,22 @@ CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
if (!CGame::nastyGame)
return NO_PED;
for (int currentPedId = 0; currentPedId < player->m_numNearPeds; currentPedId++) {
for (int currentPedId = 0; currentPedId < attacker->m_numNearPeds; currentPedId++) {
currentPed = player->m_nearPeds[currentPedId];
currentPed = attacker->m_nearPeds[currentPedId];
CVector posDifference = currentPed->GetPosition() - player->GetPosition();
CVector posDifference = currentPed->GetPosition() - attacker->GetPosition();
distance = posDifference.Magnitude();
if (distance < 2.0f) {
angleToFace = CGeneral::GetRadianAngleBetweenPoints(
currentPed->GetPosition().x, currentPed->GetPosition().y,
player->GetPosition().x, player->GetPosition().y);
attacker->GetPosition().x, attacker->GetPosition().y);
angleToFace = CGeneral::LimitRadianAngle(angleToFace);
player->m_fRotationCur = CGeneral::LimitRadianAngle(player->m_fRotationCur);
attacker->m_fRotationCur = CGeneral::LimitRadianAngle(attacker->m_fRotationCur);
angleDiff = Abs(angleToFace - player->m_fRotationCur);
angleDiff = Abs(angleToFace - attacker->m_fRotationCur);
if (angleDiff > PI)
angleDiff = 2 * PI - angleDiff;
@ -583,20 +588,21 @@ CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
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))) {
} 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;
}
} else {
foundBelow = 1;
pedBelow = currentPed;
break;
}
}
}
@ -609,7 +615,7 @@ CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
stateToReturn = PED_DEAD_ON_THE_FLOOR;
} else if (foundBelow) {
currentPed = pedBelow;
stateToReturn = PED_BELOW_PLAYER;
stateToReturn = PED_IN_FRONT_OF_ATTACKER;
} else {
currentPed = nil;
stateToReturn = NO_PED;
@ -992,7 +998,7 @@ CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg)
}
}
if (!ped->m_ped_flagA4)
if (!ped->bIsAttacking)
ped->ClearAttack();
}
@ -1018,7 +1024,7 @@ CPed::Attack(void)
ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType);
ourWeaponFire = ourWeapon->m_eWeaponFire;
weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay);
lastReloadWasInFuture = m_ped_flagA4;
lastReloadWasInFuture = bIsAttacking;
reloadAnimAssoc = nil;
reloadAnim = NUM_ANIMS;
delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire;
@ -1059,7 +1065,7 @@ CPed::Attack(void)
if (!weaponAnimAssoc) {
if (lastReloadWasInFuture) {
if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->field_1380) {
if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
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 {
@ -1131,7 +1137,7 @@ CPed::Attack(void)
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, reloadAnim, 8.0f);
ClearLookFlag();
ClearAimFlag();
m_ped_flagA4 = false;
bIsAttacking = false;
bIsPointingGunAt = false;
m_lastHitTime = CTimer::GetTimeInMilliseconds();
return;
@ -1145,8 +1151,7 @@ CPed::Attack(void)
weaponAnimAssoc->speed = 0.5f;
// BUG: We currently don't know any situation this cond. could be true.
if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) {
if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_lastHitTime) {
weaponAnimAssoc->callbackType = 0;
}
}
@ -1187,11 +1192,11 @@ CPed::Attack(void)
if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) {
if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd
&& (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime)
&& (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_lastHitTime)
&& GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) {
weaponAnim = weaponAnimAssoc->animId;
if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
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 {
@ -1234,7 +1239,7 @@ CPed::Attack(void)
if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire)
lastReloadWasInFuture = false;
m_ped_flagA4 = lastReloadWasInFuture;
bIsAttacking = lastReloadWasInFuture;
}
void
@ -4270,15 +4275,15 @@ CPed::SetAttack(CEntity* victim)
return;
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HGUN_RELOAD)) {
m_ped_flagA4 = false;
bIsAttacking = false;
return;
}
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD)) {
if (!IsPlayer() || m_nPedState != PED_ATTACK || ((CPlayerPed*)this)->field_1380)
m_ped_flagA4 = false;
bIsAttacking = false;
else
m_ped_flagA4 = true;
bIsAttacking = true;
return;
}
@ -4295,7 +4300,7 @@ CPed::SetAttack(CEntity* victim)
if (m_nPedState != PED_ATTACK) {
m_nPedState = PED_ATTACK;
m_ped_flagA4 = false;
bIsAttacking = false;
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, 8.0f);
animAssoc->SetRun();
if (animAssoc->currentTime != animAssoc->hierarchy->totalLength)
@ -4334,7 +4339,7 @@ CPed::SetAttack(CEntity* victim)
}
}
if (m_nPedState == PED_ATTACK) {
m_ped_flagA4 = true;
bIsAttacking = true;
return;
}
@ -4370,7 +4375,7 @@ CPed::SetAttack(CEntity* victim)
animDelta = 1000.0f;
if (GetWeapon()->m_eWeaponType != WEAPONTYPE_BASEBALLBAT
|| CheckForPedsOnGroundToAttack((CPlayerPed*)this, nil) < PED_ON_THE_FLOOR) {
|| 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);
@ -4438,7 +4443,7 @@ CPed::StartFightAttack(uint8 buttonPressure)
CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f;
CPed *pedOnGround = nil;
if (IsPlayer() && CheckForPedsOnGroundToAttack((CPlayerPed*)this, &pedOnGround) > PED_BELOW_PLAYER) {
if (IsPlayer() && CheckForPedsOnGroundToAttack(this, &pedOnGround) > PED_IN_FRONT_OF_ATTACKER) {
m_lastFightMove = FIGHTMOVE_GROUNDKICK;
} else if (m_pedStats->m_flags & STAT_SHOPPING_BAGS) {
m_lastFightMove = FIGHTMOVE_ROUNDHOUSE;
@ -4457,14 +4462,18 @@ CPed::StartFightAttack(uint8 buttonPressure)
SetLookFlag(pedOnGround, 1);
SetLookTimer(1500);
}
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ms_fightMoves[m_lastFightMove].animId, 4.0f);
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].animId, 4.0f);
animAssoc->SetFinishCallback(FinishFightMoveCB, this);
m_fightUnk2 = 0;
m_fightUnk1 = 0;
m_ped_flagA4 = true;
m_takeAStepAfterAttack = false;
#ifndef FINAL
m_takeAStepAfterAttack = IsPlayer() && bUnusedFightThingOnPlayer;
#endif
bIsAttacking = true;
if (IsPlayer())
unknownFightThing = 0;
nPlayerInComboMove = 0;
}
void
@ -4513,28 +4522,28 @@ CPed::LoadFightData(void)
if (strncmp(moveName, "ENDWEAPONDATA", 13) == 0)
return;
ms_fightMoves[moveId].startFireTime = startFireTime / 30.0f;
ms_fightMoves[moveId].endFireTime = endFireTime / 30.0f;
ms_fightMoves[moveId].comboFollowOnTime = comboFollowOnTime / 30.0f;
ms_fightMoves[moveId].strikeRadius = strikeRadius;
ms_fightMoves[moveId].damage = damage;
ms_fightMoves[moveId].flags = flags;
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':
ms_fightMoves[moveId].hitLevel = 1;
tFightMoves[moveId].hitLevel = 1;
break;
case 'H':
ms_fightMoves[moveId].hitLevel = 4;
tFightMoves[moveId].hitLevel = 4;
break;
case 'L':
ms_fightMoves[moveId].hitLevel = 2;
tFightMoves[moveId].hitLevel = 2;
break;
case 'M':
ms_fightMoves[moveId].hitLevel = 3;
tFightMoves[moveId].hitLevel = 3;
break;
case 'N':
ms_fightMoves[moveId].hitLevel = 0;
tFightMoves[moveId].hitLevel = 0;
break;
default:
break;
@ -4542,9 +4551,9 @@ CPed::LoadFightData(void)
if (strncmp(animName, "null", 4) != 0) {
animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animName);
ms_fightMoves[moveId].animId = (AnimationId)animAssoc->animId;
tFightMoves[moveId].animId = (AnimationId)animAssoc->animId;
} else {
ms_fightMoves[moveId].animId = ANIM_WALK;
tFightMoves[moveId].animId = ANIM_WALK;
}
moveId++;
}
@ -4584,9 +4593,9 @@ CPed::FightStrike(CVector &touchedNodePos)
for (int i = 0; i < m_numNearPeds; i++) {
nearPed = m_nearPeds[i];
if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
maxDistanceToBeBeaten = nearPed->GetBoundRadius() + ms_fightMoves[m_lastFightMove].strikeRadius + 0.1f;
maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_lastFightMove].strikeRadius + 0.1f;
else
maxDistanceToBeBeaten = nearPed->GetBoundRadius() + ms_fightMoves[m_lastFightMove].strikeRadius;
maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_lastFightMove].strikeRadius;
if (nearPed->bUsesCollision || nearPed->m_nPedState == PED_DEAD) {
CVector nearPedCentre;
@ -4605,7 +4614,7 @@ CPed::FightStrike(CVector &touchedNodePos)
attackDistance = nearPed->GetPosition() + ourCol->spheres[j].center;
attackDistance -= touchedNodePos;
CColSphere *ourPieces = ourCol->spheres;
float maxDistanceToBeat = ourPieces[j].radius + ms_fightMoves[m_lastFightMove].strikeRadius;
float maxDistanceToBeat = ourPieces[j].radius + tFightMoves[m_lastFightMove].strikeRadius;
// We can beat him too
if (sq(maxDistanceToBeat) > attackDistance.MagnitudeSqr()) {
@ -4626,7 +4635,7 @@ CPed::FightStrike(CVector &touchedNodePos)
float oldVictimHealth = nearPed->m_fHealth;
CVector bloodPos = 0.5f * attackDistance + touchedNodePos;
int damageMult = ms_fightMoves[m_lastFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1;
int damageMult = tFightMoves[m_lastFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1;
CVector2D diff (GetPosition() - nearPed->GetPosition());
int direction = nearPed->GetLocalDirection(diff);
@ -4654,16 +4663,16 @@ CPed::FightStrike(CVector &touchedNodePos)
else
unk2 = damageMult;
nearPed->StartFightDefend(direction, ms_fightMoves[m_lastFightMove].hitLevel, unk2);
nearPed->StartFightDefend(direction, tFightMoves[m_lastFightMove].hitLevel, unk2);
PlayHitSound(nearPed);
m_fightUnk2 = -1;
RpAnimBlendClumpGetAssociation(GetClump(), ms_fightMoves[m_lastFightMove].animId)->speed = 0.6f;
RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_lastFightMove].animId)->speed = 0.6f;
if (nearPed->m_nPedState != PED_DIE && nearPed->m_nPedState != PED_DEAD) {
nearPed->InflictDamage(this, WEAPONTYPE_UNARMED, damageMult * 3.0f, closestPedPiece, direction);
}
if (CGame::nastyGame
&& ms_fightMoves[m_lastFightMove].hitLevel > 3
&& tFightMoves[m_lastFightMove].hitLevel > 3
&& nearPed->m_nPedState == PED_DIE
&& nearPed->GetIsOnScreen()) {
@ -5707,15 +5716,15 @@ CPed::EndFight(uint8 endType)
animAssoc->flags |= ASSOC_DELETEFADEDOUT;
switch (endType) {
case 0:
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 1:
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 2:
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;
@ -5725,6 +5734,555 @@ CPed::EndFight(uint8 endType)
m_nWaitTimer = 0;
}
void
CPed::EnterCar(void)
{
if (m_pMyVehicle && m_pMyVehicle->m_status != STATUS_WRECKED && m_fHealth > 0.0f) {
CVehicle* veh = (CVehicle*)m_pSeekTarget;
// Not used.
// CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehEnterType);
if (veh->CanPedOpenLocks(this)) {
if (m_vehEnterType) {
CAnimBlendAssociation *enterAssoc = m_pVehicleAnim;
if (enterAssoc)
veh->ProcessOpenDoor(m_vehEnterType, enterAssoc->animId, enterAssoc->currentTime);
}
}
bIsInTheAir = false;
LineUpPedWithCar(LINE_UP_TO_CAR_START);
} else {
QuitEnteringCar();
SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
}
}
uint8
CPed::GetNearestTrainPedPosition(CVehicle *train, CVector &enterPos)
{
CVector enterStepOffset;
CVehicleModelInfo *trainModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(train->m_modelIndex);
CMatrix trainMat = CMatrix(train->GetMatrix());
CVector leftEntryPos, rightEntryPos, midEntryPos;
float distLeftEntry, distRightEntry, distMidEntry;
// enterStepOffset = offsetToOpenRegularCarDoor;
enterStepOffset = CVector(1.5f, 0.0f, 0.0f);
if (train->pPassengers[TRAIN_POS_LEFT_ENTRY]) {
distLeftEntry = 999.0f;
} else {
leftEntryPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterStepOffset;
leftEntryPos = Multiply3x3(trainMat, leftEntryPos);
leftEntryPos += train->GetPosition();
distLeftEntry = (leftEntryPos - GetPosition()).Magnitude();
}
if (train->pPassengers[TRAIN_POS_MID_ENTRY]) {
distMidEntry = 999.0f;
} else {
midEntryPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterStepOffset;
midEntryPos = Multiply3x3(trainMat, midEntryPos);
midEntryPos += train->GetPosition();
distMidEntry = (midEntryPos - GetPosition()).Magnitude();
}
if (train->pPassengers[TRAIN_POS_RIGHT_ENTRY]) {
distRightEntry = 999.0f;
} else {
rightEntryPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterStepOffset;
rightEntryPos = Multiply3x3(trainMat, rightEntryPos);
rightEntryPos += train->GetPosition();
distRightEntry = (rightEntryPos - GetPosition()).Magnitude();
}
if (distMidEntry < distLeftEntry) {
if (distMidEntry < distRightEntry) {
enterPos = midEntryPos;
m_vehEnterType = TRAIN_POS_MID_ENTRY;
} else {
enterPos = rightEntryPos;
m_vehEnterType = TRAIN_POS_RIGHT_ENTRY;
}
} else if (distRightEntry < distLeftEntry) {
enterPos = rightEntryPos;
m_vehEnterType = TRAIN_POS_RIGHT_ENTRY;
} else {
enterPos = leftEntryPos;
m_vehEnterType = TRAIN_POS_LEFT_ENTRY;
}
return 1;
}
uint8
CPed::GetNearestTrainDoor(CVehicle *train, CVector &doorPos)
{
GetNearestTrainPedPosition(train, doorPos);
/*
// Not used.
CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(train->m_modelIndex);
CMatrix trainMat = CMatrix(train->GetMatrix());
doorPos = trainModel->m_positions[m_vehEnterType];
doorPos.x -= 1.5f;
doorPos = Multiply3x3(trainMat, doorPos);
doorPos += train->GetPosition();
*/
return 1;
}
void
CPed::LineUpPedWithTrain(void)
{
CVector lineUpPos;
CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(m_pMyVehicle->m_modelIndex);
CVector enterOffset(1.5f, 0.0f, -0.2f);
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI;
m_fRotationDest = m_fRotationCur;
if (!bInVehicle) {
GetNearestTrainDoor(m_pMyVehicle, lineUpPos);
lineUpPos.z += 0.2f;
} else {
if (m_pMyVehicle->pPassengers[TRAIN_POS_LEFT_ENTRY] == this) {
lineUpPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterOffset;
} else if (m_pMyVehicle->pPassengers[TRAIN_POS_MID_ENTRY] == this) {
lineUpPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterOffset;
} else if (m_pMyVehicle->pPassengers[TRAIN_POS_RIGHT_ENTRY] == this) {
lineUpPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterOffset;
}
lineUpPos = Multiply3x3(m_pMyVehicle->GetMatrix(), lineUpPos);
lineUpPos += m_pMyVehicle->GetPosition();
}
if (m_pVehicleAnim) {
float percentageLeft = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength;
lineUpPos += (GetPosition() - lineUpPos) * percentageLeft;
}
GetPosition() = lineUpPos;
// CVector pedPos = GetPosition();
GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur);
GetPosition() += lineUpPos;
}
void
CPed::EnterTrain(void)
{
LineUpPedWithTrain();
}
void
CPed::ExitTrain(void)
{
LineUpPedWithTrain();
}
void
CPed::ExitCar(void)
{
if (!m_pVehicleAnim)
return;
AnimationId exitAnim = (AnimationId) m_pVehicleAnim->animId;
float animTime = m_pVehicleAnim->currentTime;
m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, exitAnim, animTime);
if (m_pSeekTarget) {
// Car is upside down
if (m_pMyVehicle->GetUp().z > -0.8f) {
if (exitAnim != ANIM_CAR_CLOSE_RHS && exitAnim != ANIM_CAR_CLOSE_LHS && animTime <= 0.3f)
LineUpPedWithCar((m_pMyVehicle->m_modelIndex == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START));
else
LineUpPedWithCar(LINE_UP_TO_CAR_END);
} else {
LineUpPedWithCar(LINE_UP_TO_CAR_END);
}
}
// If there is someone in front of the door, make him fall while we exit.
if (m_nPedState == PED_EXIT_CAR) {
CPed *foundPed = nil;
for (int i = 0; i < m_numNearPeds; i++) {
if ((m_nearPeds[i]->GetPosition() - GetPosition()).MagnitudeSqr2D() < 0.04f) {
foundPed = m_nearPeds[i];
break;
}
}
if (foundPed && animTime > 0.4f && foundPed->IsPedInControl())
foundPed->SetFall(1000, ANIM_KO_SKID_FRONT, 1);
}
}
void
CPed::Fall(void)
{
if (m_getUpTimer != -1 && CTimer::GetTimeInMilliseconds() > m_getUpTimer)
ClearFall();
}
void
CPed::Fight(void)
{
CAnimBlendAssociation *currentAssoc = nil, *animAssoc;
bool hasShoppingBags, punchOnly, canKick, canKneeHead, canRoundhouse;
float angleToFace, nextAngle;
bool goForward = false;
int nextFightMove;
switch (m_lastFightMove) {
case FIGHTMOVE_NULL:
return;
case FIGHTMOVE_IDLE2NORM:
m_lastFightMove = FIGHTMOVE_NULL;
RestorePreviousState();
break;
case FIGHTMOVE_IDLE:
// currentAssoc = nil;
break;
default:
currentAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_lastFightMove].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_fightUnk2 > -2) {
float animTime = currentAssoc->currentTime;
FightMove &curMove = tFightMoves[m_lastFightMove];
if (curMove.hitLevel != 0 && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightUnk2 >= 0) {
CVector touchingNodePos(0.0f, 0.0f, 0.0f);
RwFrame *touchingFrame = nil;
switch (m_lastFightMove) {
case FIGHTMOVE_STDPUNCH:
case FIGHTMOVE_PUNCHHOOK:
case FIGHTMOVE_BODYBLOW:
touchingFrame = GetNodeFrame(PED_HANDR);
break;
case FIGHTMOVE_IDLE:
case FIGHTMOVE_SHUFFLE_F:
break;
case FIGHTMOVE_KNEE:
touchingFrame = GetNodeFrame(PED_LOWERLEGR);
break;
case FIGHTMOVE_HEADBUTT:
touchingFrame = GetNodeFrame(PED_HEAD);
break;
case FIGHTMOVE_PUNCHJAB:
touchingFrame = GetNodeFrame(PED_HANDL);
break;
case FIGHTMOVE_KICK:
case FIGHTMOVE_LONGKICK:
case FIGHTMOVE_ROUNDHOUSE:
case FIGHTMOVE_GROUNDKICK:
touchingFrame = GetNodeFrame(PED_FOOTR);
break;
}
while (touchingFrame) {
RwV3dTransformPoints(touchingNodePos, touchingNodePos, 1, RwFrameGetMatrix(touchingFrame));
touchingFrame = RwFrameGetParent(touchingFrame);
}
if (m_lastFightMove == FIGHTMOVE_PUNCHJAB) {
touchingNodePos += 0.1f * GetForward();
} else if (m_lastFightMove == FIGHTMOVE_PUNCHHOOK) {
touchingNodePos += 0.22f * GetForward();
}
FightStrike(touchingNodePos);
m_fightButtonPressure = 0;
return;
}
if (curMove.hitLevel != 0) {
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) {
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curMove.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_lastFightMove != 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;
PedState nearPedState = nearPed->m_nPedState;
if (nearPedState != PED_FALL && nearPedState != PED_GETUP && nearPedState != PED_DIE && nearPedState != PED_DEAD) {
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 (nearPedState != 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, 1);
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;
PedState fightingPedState = m_pedInObjective->m_nPedState;
if (fightingPedState != PED_FALL && fightingPedState != PED_GETUP && fightingPedState != PED_DIE && fightingPedState != PED_DEAD) {
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, 1);
SetLookTimer(1500);
} else if (goForward) {
nextFightMove = FIGHTMOVE_SHUFFLE_F;
} else {
nextFightMove = FIGHTMOVE_STDPUNCH;
}
}
if (nextFightMove != FIGHTMOVE_IDLE) {
m_lastFightMove = (PedFightMoves) nextFightMove;
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].animId, 4.0f);
animAssoc->SetFinishCallback(FinishFightMoveCB, this);
if (m_fightUnk2 == -2 && animAssoc->currentTime == 0.0f) {
animAssoc->SetCurrentTime(0.0f);
animAssoc->SetRun();
}
m_fightButtonPressure = 0;
}
m_fightUnk2 = 0;
} else if (m_takeAStepAfterAttack && m_lastFightMove != FIGHTMOVE_SHUFFLE_F
#ifndef FIX_BUGS
&& CheckForPedsOnGroundToAttack(this, nil) == 4) {
#else
&& CheckForPedsOnGroundToAttack(this, nil) == PED_IN_FRONT_OF_ATTACKER) {
#endif
m_lastFightMove = FIGHTMOVE_SHUFFLE_F;
animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_lastFightMove].animId);
if (animAssoc) {
animAssoc->SetCurrentTime(0.0f);
animAssoc->blendDelta = 4.0f;
animAssoc->SetRun();
} else {
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].animId, 32.0f);
}
animAssoc->SetFinishCallback(FinishFightMoveCB, this);
m_fightUnk2 = 0;
m_fightButtonPressure = 0;
m_takeAStepAfterAttack = false;
} else if (m_takeAStepAfterAttack) {
EndFight(ENDFIGHT_FAST);
} else if (m_lastFightMove == FIGHTMOVE_IDLE) {
if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
EndFight(ENDFIGHT_NORMAL);
}
} else {
m_lastFightMove = FIGHTMOVE_IDLE;
if (IsPlayer())
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500;
else
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000;
}
}
WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); }
WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); }
WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); }
@ -5880,4 +6438,10 @@ STARTPATCHES
InjectHook(0x4EB5C0, &CPed::DoesLOSBulletHitPed, PATCH_JUMP);
InjectHook(0x4E3EC0, &CPed::DuckAndCover, PATCH_JUMP);
InjectHook(0x4E8D30, &CPed::EndFight, PATCH_JUMP);
InjectHook(0x4E0D30, &CPed::EnterCar, PATCH_JUMP);
InjectHook(0x4E2E50, &CPed::GetNearestTrainPedPosition, PATCH_JUMP);
InjectHook(0x4E2D70, &CPed::GetNearestTrainDoor, PATCH_JUMP);
InjectHook(0x4E33D0, &CPed::LineUpPedWithTrain, PATCH_JUMP);
InjectHook(0x4E18D0, &CPed::ExitCar, PATCH_JUMP);
InjectHook(0x4E7EE0, &CPed::Fight, PATCH_JUMP);
ENDPATCHES

View File

@ -22,6 +22,13 @@ struct CPedAudioData
int m_nMaxRandomDelayTime;
};
enum
{
ENDFIGHT_NORMAL,
ENDFIGHT_WITH_A_STEP,
ENDFIGHT_FAST
};
struct FightMove
{
AnimationId animId;
@ -152,7 +159,7 @@ enum PedLineUpPhase {
enum PedOnGroundState {
NO_PED,
PED_BELOW_PLAYER,
PED_IN_FRONT_OF_ATTACKER,
PED_ON_THE_FLOOR,
PED_DEAD_ON_THE_FLOOR
};
@ -241,7 +248,7 @@ public:
// cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CPed.h from R*
uint8 bIsStanding : 1;
uint8 m_ped_flagA2 : 1;
uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime)
uint8 bIsAttacking : 1; // doesn't reset after fist fight, also stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime)
uint8 bIsPointingGunAt : 1;
uint8 bIsLooking : 1;
uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA
@ -418,7 +425,7 @@ public:
PedFightMoves m_lastFightMove;
uint8 m_fightButtonPressure;
int8 m_fightUnk2; // TODO
uint8 m_fightUnk1; // TODO
bool m_takeAStepAfterAttack;
uint8 pad_4B3;
CFire *m_pFire;
CEntity *m_pLookTarget;
@ -429,7 +436,7 @@ public:
uint32 m_lookTimer;
uint32 m_standardTimer;
uint32 m_attackTimer;
uint32 m_lastHitTime;
uint32 m_lastHitTime; // obviously not correct
uint32 m_hitRecoverTimer;
uint32 m_objectiveTimer;
uint32 m_duckTimer;
@ -584,6 +591,12 @@ public:
uint8 DoesLOSBulletHitPed(CColPoint &point);
bool DuckAndCover(void);
void EndFight(uint8);
void EnterCar(void);
uint8 GetNearestTrainPedPosition(CVehicle*, CVector&);
uint8 GetNearestTrainDoor(CVehicle*, CVector&);
void LineUpPedWithTrain(void);
void ExitCar(void);
void Fight(void);
// Static methods
static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset);
@ -641,6 +654,9 @@ public:
void SetPedStats(ePedStats);
bool IsGangMember(void);
void Die(void);
void EnterTrain(void);
void ExitTrain(void);
void Fall(void);
bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; }
CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; }
@ -659,9 +675,13 @@ public:
static bool &bPedCheat2;
static bool &bPedCheat3;
static CColPoint &ms_tempColPoint;
static uint16 &unknownFightThing; // TODO
static FightMove (&ms_fightMoves)[24];
static uint16 &nPlayerInComboMove;
static FightMove (&tFightMoves)[24];
static CPedAudioData (&PedAudioData)[38];
#ifndef FINAL
static bool bUnusedFightThingOnPlayer;
#endif
};
void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);