From 2fc69a0aa51e2fc73a42bec9d4bcf3d38e6b3af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Mon, 5 Aug 2019 16:07:10 +0300 Subject: [PATCH] CPed part 218 --- src/core/re3.cpp | 4 + src/peds/Ped.cpp | 688 ++++++++++++++++++++++++++++++++++++++++++----- src/peds/Ped.h | 32 ++- 3 files changed, 656 insertions(+), 68 deletions(-) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 9681160f..9fe53579 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -16,6 +16,7 @@ #include "Boat.h" #include "Heli.h" #include "Automobile.h" +#include "Ped.h" #include "debugmenu_public.h" #include @@ -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); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 77264b3b..e76b6030 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -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 \ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 3d179822..7e0e9aa3 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -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);