diff options
-rw-r--r-- | README.md | 124 | ||||
-rw-r--r-- | src/animation/AnimManager.h | 4 | ||||
-rw-r--r-- | src/audio/AudioManager.cpp | 69 | ||||
-rw-r--r-- | src/audio/AudioManager.h | 2 | ||||
-rw-r--r-- | src/control/Garages.cpp | 3 | ||||
-rw-r--r-- | src/control/Garages.h | 5 | ||||
-rw-r--r-- | src/control/Script.cpp | 852 | ||||
-rw-r--r-- | src/core/CutsceneMgr.h | 1 | ||||
-rw-r--r-- | src/core/PlayerInfo.cpp | 16 | ||||
-rw-r--r-- | src/core/PlayerInfo.h | 2 | ||||
-rw-r--r-- | src/core/World.cpp | 13 | ||||
-rw-r--r-- | src/core/World.h | 2 | ||||
-rw-r--r-- | src/core/config.h | 13 | ||||
-rw-r--r-- | src/core/re3.cpp | 1 | ||||
-rw-r--r-- | src/math/Vector.h | 36 | ||||
-rw-r--r-- | src/math/Vector2D.h | 13 | ||||
-rw-r--r-- | src/peds/Ped.cpp | 887 | ||||
-rw-r--r-- | src/peds/Ped.h | 29 | ||||
-rw-r--r-- | src/render/Renderer.cpp | 24 | ||||
-rw-r--r-- | src/render/Renderer.h | 4 | ||||
-rw-r--r-- | src/render/Weather.cpp | 25 | ||||
-rw-r--r-- | src/render/Weather.h | 6 | ||||
-rw-r--r-- | src/vehicles/Automobile.cpp | 6 |
23 files changed, 1976 insertions, 161 deletions
@@ -1,76 +1,88 @@ -# Intro +# re3 +[![Build status](https://ci.appveyor.com/api/projects/status/hyiwgegks122h8jg?svg=true)](https://ci.appveyor.com/project/aap/re3/branch/master) +<a href="https://discord.gg/jYpXxTm"><img src="https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat" /></a> +<a href="https://ci.appveyor.com/api/projects/aap/re3/artifacts/bin/Debug/re3.dll?branch=master&job=Configuration%3A+Debug"><img src="https://img.shields.io/badge/download-debug-9cf.svg" /></a> +<a href="https://ci.appveyor.com/api/projects/aap/re3/artifacts/bin/Release/re3.dll?branch=master&job=Configuration%3A+Release"><img src="https://img.shields.io/badge/download-release-blue.svg" /></a> + +## Intro The aim of this project is to reverse GTA III for PC by replacing parts of the game [one by one](https://en.wikipedia.org/wiki/Ship_of_Theseus) such that we have a working game at all times. -Apparently you can download a binary of the latest version here: -[Debug](https://ci.appveyor.com/api/projects/aap/re3/artifacts/bin/Debug/re3.dll?branch=master&job=Configuration%3A+Debug), -[Release](https://ci.appveyor.com/api/projects/aap/re3/artifacts/bin/Release/re3.dll?branch=master&job=Configuration%3A+Release). +## How can I try it? -Build status: -[![Build status](https://ci.appveyor.com/api/projects/status/hyiwgegks122h8jg?svg=true)](https://ci.appveyor.com/project/aap/re3/branch/master) +- re3 requires game assets to work, so you need to own a copy of GTA III. +- Since re3 is a DLL that works with original GTA III for now, you need Simple DLL Loader. You can get it [here](https://github.com/aap/simpledllloader). +- Build re3 or download it from one of the above links (Debug or Release). +- Make sure you included the re3 in `plugins.cfg` or `dlls.cfg`. +- re3 starts the script `main_freeroam.scm` that comes along with it by default, so you should copy it to from `gamefiles/` to your game's `data/` directory. + +![#ffa500](https://placehold.it/15/ffa500/000000?text=+) **Notice** + +If you want to load original script/story, press and hold G while game is loading. +This includes both starting new game and loading save game. + +![#ffa500](https://placehold.it/15/ffa500/000000?text=+) **Notice if you will build it** + +There are various settings at the very bottom of `config.h`, you may want to take a look there. i.e. FIX_BUGS define fixes the bugs we've come across. -Re3 starts the script main_freeroam.scm by default. Make sure you copy it to your data directory. +https://github.com/GTAmodding/re3/tree/master/src/core/config.h -# Strategy +## I want to contribute, where should I start? A good approach is to start at the fringes of the code base, i.e. classes that don't depend on code that we don't have reversed yet. If a function uses only few unreversed functions that would be inconvenient to reverse at the time, calling the original functions is acceptable. -# Progress - -This is a list of some things that have been reversed to some non-trivial extent. -Not everything is listed, check the code. -(TODO: keep this list at least a bit up to date...) - +### Unreversed / incomplete classes (at least the ones we know) ``` -CPool -CTxdStore -CVector -CVector2D -CMatrix -CModelInfo -CBaseModelInfo -CSimpleModelInfo -CTimeModelInfo -CClumpModelInfo -CPedModelInfo -CVehicleModelInfo -CVisibilityPlugins -CRenderer -CSprite -CSprite2d -CFont -CEntity -CPhysical -CCollision -CCullZones -CTheZones -CPathFind +CAudioManager, cDMAudio, cSampleManager and all audio - being worked on +CAccidentManager +CBoat +CBrightLights +CBulletInfo +CBulletTraces CCam -CParticle -CParticleMgr -CPointLights -CCoronas -CAntennas -CClouds -CHud +CCamera +CCivilianPed +CCopPed +CCrane +CCranes +CCullZone +CCullZones +CEmergencyPed +CExplosion +CFallingGlassPane +CFire +CFireManager +CGame +CGarage +CGarages +CGlass +CMenuManager +CMotionBlurStreaks +CPacManPickups +CPed - being worked on +CPedIK +CPhoneInfo - one function left +CPlayerInfo +CPlayerPed +CProjectile +CProjectileInfo +CRoadBlocks +CRunningScript - being worked on +CStats +CSpecialFX +CTrafficLights +CWaterCannon +CWaterCannons +CWeapon +CWeaponEffects ``` -# Low hanging fruit - -There are a couple of things that have been reversed for other projects -already that could probably be put into this project without too much effort. -Again, the list is not complete: - -* ~~Animation (https://github.com/aap/iii_anim)~~ -* File Loader (https://github.com/aap/librwgta/tree/master/tools/IIItest) -* ... - -# Coding style +### Coding style I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style), but realize that this is not the most popular style, so I'm willing to compromise. @@ -178,7 +190,7 @@ but here are some observations: * Generally, try to make the code look as if R* could have written it -# Environment Variables +### Environment Variables Here you can find a list of variables that you might need to set in windows: ``` "GTA_III_RE_DIR" * path to "gta3_re" game folder usually where this plugin run. diff --git a/src/animation/AnimManager.h b/src/animation/AnimManager.h index d2e85c06..0d4e17fe 100644 --- a/src/animation/AnimManager.h +++ b/src/animation/AnimManager.h @@ -61,9 +61,9 @@ enum AnimationId ANIM_KD_LEFT, ANIM_KD_RIGHT, ANIM_KO_SKID_FRONT, - ANIM_KO_SPIN_R, + ANIM_KO_SPIN_R, // named left in VC ANIM_KO_SKID_BACK, - ANIM_KO_SPIN_L, + ANIM_KO_SPIN_L, // named right in VC ANIM_SHOT_FRONT_PARTIAL, ANIM_SHOT_LEFT_PARTIAL, ANIM_SHOT_BACK_PARTIAL, diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index f136e6b2..a6f357c2 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -9290,11 +9290,75 @@ cAudioManager::UpdateGasPedalAudio(CAutomobile *automobile) automobile->m_fGasPedalAudio = newGasPedalAudio; } -WRAPPER void cAudioManager::UpdateReflections() { - EAXJMP(0x57B470); + const CVector &camPos = TheCamera.GetPosition(); + CColPoint colpoint; + CEntity *ent; + + if(m_nTimeOfRecentCrime & 7) { + if(((uint8)m_nTimeOfRecentCrime + 1) & 7) { + if(((uint8)m_nTimeOfRecentCrime + 2) & 7) { + if(((uint8)m_nTimeOfRecentCrime + 3) & 7) { + if(!(((uint8)m_nTimeOfRecentCrime + 4) & 7)) { + m_avecReflectionsPos[4] = camPos; + m_avecReflectionsPos[4].z += 50.f; + if(CWorld::ProcessVerticalLine( + camPos, m_avecReflectionsPos[4].z, colpoint, + ent, true, false, false, false, true, false, + false)) { + m_afReflectionsDistances[4] = + colpoint.point.z - camPos.z; + } else { + m_afReflectionsDistances[4] = 50.0f; + } + } + } else { + m_avecReflectionsPos[3] = camPos; + m_avecReflectionsPos[3].x += 50.f; + if(CWorld::ProcessLineOfSight( + camPos, m_avecReflectionsPos[3], colpoint, ent, true, + false, false, true, false, true, true)) { + m_afReflectionsDistances[3] = + Distance(camPos, colpoint.point); + } else { + m_afReflectionsDistances[3] = 50.0f; + } + } + } else { + m_avecReflectionsPos[2] = camPos; + m_avecReflectionsPos[2].x -= 50.f; + if(CWorld::ProcessLineOfSight(camPos, m_avecReflectionsPos[2], + colpoint, ent, true, false, false, + true, false, true, true)) { + m_afReflectionsDistances[2] = + Distance(camPos, colpoint.point); + } else { + m_afReflectionsDistances[2] = 50.0f; + } + } + } else { + m_avecReflectionsPos[1] = camPos; + m_avecReflectionsPos[1].y -= 50.f; + if(CWorld::ProcessLineOfSight(camPos, m_avecReflectionsPos[1], colpoint, + ent, true, false, false, true, false, true, + true)) { + m_afReflectionsDistances[1] = Distance(camPos, colpoint.point); + } else { + m_afReflectionsDistances[1] = 50.0f; + } + } + } else { + m_avecReflectionsPos[0] = camPos; + m_avecReflectionsPos[0].y += 50.f; + if(CWorld::ProcessLineOfSight(camPos, m_avecReflectionsPos[0], colpoint, ent, true, + false, false, true, false, true, true)) { + m_afReflectionsDistances[0] = Distance(camPos, colpoint.point); + } else { + m_afReflectionsDistances[0] = 50.0f; + } + } } bool @@ -9571,6 +9635,7 @@ InjectHook(0x57FCC0, &cAudioManager::SetupSuspectLastSeenReport, PATCH_JUMP); InjectHook(0x57A150, &cAudioManager::Terminate, PATCH_JUMP); InjectHook(0x57AC60, &cAudioManager::TranslateEntity, PATCH_JUMP); InjectHook(0x56AC80, &cAudioManager::UpdateGasPedalAudio, PATCH_JUMP); +InjectHook(0x57B470, &cAudioManager::UpdateReflections, PATCH_JUMP); InjectHook(0x56C600, &cAudioManager::UsesReverseWarning, PATCH_JUMP); InjectHook(0x56C3C0, &cAudioManager::UsesSiren, PATCH_JUMP); InjectHook(0x56C3F0, &cAudioManager::UsesSirenSwitching, PATCH_JUMP); diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 30f411a7..19809286 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -689,7 +689,7 @@ public: void TranslateEntity(CVector *v1, CVector *v2) const; void UpdateGasPedalAudio(CAutomobile *automobile); - void UpdateReflections(); // todo + void UpdateReflections(); bool UsesReverseWarning(int32 model) const; bool UsesSiren(int32 model) const; bool UsesSirenSwitching(int32 model) const; diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index b5ad37f4..b7a1fa8b 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -75,6 +75,9 @@ WRAPPER void CGarages::TriggerMessage(const char *text, int16, uint16 time, int1 WRAPPER bool CGarages::IsPointWithinHideOutGarage(CVector&) { EAXJMP(0x428260); } WRAPPER bool CGarages::IsPointWithinAnyGarage(CVector&) { EAXJMP(0x428320); } WRAPPER void CGarages::PlayerArrestedOrDied() { EAXJMP(0x427F60); } +WRAPPER int16 CGarages::AddOne(float, float, float, float, float, float, uint8, uint32) { EAXJMP(0x421FA0); } +WRAPPER void CGarages::SetTargetCarForMissonGarage(int16, CVehicle*) { EAXJMP(0x426BD0); } +WRAPPER bool CGarages::HasCarBeenDroppedOffYet(int16) { EAXJMP(0x426C20); } #if 0 WRAPPER void CGarages::PrintMessages(void) { EAXJMP(0x426310); } diff --git a/src/control/Garages.h b/src/control/Garages.h index 41c6b5ad..af592716 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -1,5 +1,7 @@ #pragma once +class CVehicle; + class CGarages { public: @@ -30,4 +32,7 @@ public: static void PlayerArrestedOrDied(); static void Init(void); static void Update(void); + static int16 AddOne(float, float, float, float, float, float, uint8, uint32); + static void SetTargetCarForMissonGarage(int16, CVehicle*); + static bool HasCarBeenDroppedOffYet(int16); }; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index ced06f1e..0b5f1105 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -11,21 +11,29 @@ #include "CivilianPed.h" #include "Clock.h" #include "CopPed.h" +#include "Coronas.h" #include "Cranes.h" +#include "CutsceneMgr.h" +#include "Darkel.h" #include "DMAudio.h" #include "EmergencyPed.h" +#include "Explosion.h" #include "FileMgr.h" +#include "Gangs.h" #include "Garages.h" #include "General.h" #include "HandlingMgr.h" +#include "Heli.h" #include "Hud.h" #include "Messages.h" #include "ModelIndices.h" #include "Pad.h" #include "PedRoutes.h" +#include "Phones.h" #include "Pickups.h" #include "PlayerInfo.h" #include "PlayerPed.h" +#include "PointLights.h" #include "Pools.h" #include "Population.h" #include "Remote.h" @@ -3572,7 +3580,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_IDLE); return 0; } @@ -3581,7 +3589,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE); return 0; } @@ -3593,7 +3601,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CVector pos = *(CVector*)&ScriptParams[1]; if (pos.z <= -100.0f) pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_GUARD_SPOT, pos); return 0; } @@ -3619,7 +3627,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) pos.y = (infY + supY) / 2; pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); float radius = max(pos.x - infX, pos.y - infY); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_GUARD_SPOT, pos, radius); return 0; } @@ -3628,7 +3636,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CollectParameters(&m_nIp, 1); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_WAIT_IN_CAR); return 0; } @@ -3672,6 +3680,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; assert(pPed); pPed->m_nSelectedWepSlot = pPed->GiveWeapon((eWeaponType)ScriptParams[1], ScriptParams[2]); + return 0; } case COMMAND_GIVE_WEAPON_TO_CHAR: { @@ -3956,7 +3965,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pTarget); return 0; } @@ -3966,7 +3975,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pTarget); return 0; } @@ -3976,7 +3985,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, pTarget); return 0; } @@ -3986,7 +3995,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, pTarget); return 0; } @@ -3996,7 +4005,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, pTarget); return 0; } @@ -4006,7 +4015,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, pTarget); return 0; } @@ -4016,7 +4025,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pTarget); return 0; } @@ -4026,7 +4035,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pTarget); return 0; } @@ -4036,7 +4045,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, pTarget); return 0; } @@ -4046,7 +4055,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, pTarget); return 0; } @@ -4056,7 +4065,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); return 0; } @@ -4066,7 +4075,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, pVehicle); return 0; } @@ -4076,7 +4085,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicle); return 0; } @@ -4091,7 +4100,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_DESTROY_CAR, pVehicle); return 0; } @@ -4117,7 +4126,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) pos.y = (infY + supY) / 2; pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); float radius = max(pos.x - infX, pos.y - infY); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, pos, radius); return 0; } @@ -4157,7 +4166,7 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) CollectParameters(&m_nIp, 3); CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); assert(pPed); - pPed->bObjectiveCompleted = false; + pPed->bScriptObjectiveCompleted = false; pPed->SetObjective(OBJECTIVE_FOLLOW_ROUTE, ScriptParams[1], ScriptParams[2]); return 0; } @@ -4331,6 +4340,806 @@ int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) } #endif +#if 0 +WRAPPER int8 CRunningScript::ProcessCommandsFrom500To599(int32 command) { EAXJMP(0x4429C0); } +#else +int8 CRunningScript::ProcessCommandsFrom500To599(int32 command) +{ + switch (command) { + case COMMAND_IS_CAR_UPSIDEDOWN: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + UpdateCompareFlag(pVehicle->GetUp().z <= -0.97f); + return 0; + } + case COMMAND_GET_PLAYER_CHAR: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CANCEL_OVERRIDE_RESTART: + CRestart::CancelOverrideRestart(); + return 0; + case COMMAND_SET_POLICE_IGNORE_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + if (ScriptParams[0]) { + pPed->m_pWanted->m_bIgnoredByCops = true; + CWorld::StopAllLawEnforcersInTheirTracks(); + } + else { + pPed->m_pWanted->m_bIgnoredByCops = false; + } + return 0; + } + case COMMAND_ADD_PAGER_MESSAGE_WITH_NUMBER: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 4); + CUserDisplay::Pager.AddMessageWithNumber(text, ScriptParams[0], -1, -1, -1, -1, -1, + ScriptParams[1], ScriptParams[2], ScriptParams[3]); + return 0; + } + case COMMAND_START_KILL_FRENZY: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 8); + CDarkel::StartFrenzy((eWeaponType)ScriptParams[0], ScriptParams[1], ScriptParams[2], + ScriptParams[3], text, ScriptParams[4], ScriptParams[5], + ScriptParams[6], ScriptParams[7] != 0, false); + return 0; + } + case COMMAND_READ_KILL_FRENZY_STATUS: + { + ScriptParams[0] = CDarkel::ReadStatus(); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SQRT: + { + CollectParameters(&m_nIp, 1); + *(float*)&ScriptParams[0] = Sqrt(*(float*)&ScriptParams[0]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_2D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_2D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_2D: + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D: + LocatePlayerCarCommand(command, &m_nIp); + return 0; + case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_2D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_2D: + case COMMAND_LOCATE_CHAR_IN_CAR_CAR_2D: + case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D: + case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D: + LocateCharCarCommand(command, &m_nIp); + return 0; + case COMMAND_GENERATE_RANDOM_FLOAT_IN_RANGE: + CollectParameters(&m_nIp, 2); + *(float*)&ScriptParams[0] = CGeneral::GetRandomNumberInRange(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_GENERATE_RANDOM_INT_IN_RANGE: + CollectParameters(&m_nIp, 2); + ScriptParams[0] = CGeneral::GetRandomNumberInRange(ScriptParams[0], ScriptParams[1]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_LOCK_CAR_DOORS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + pVehicle->m_nDoorLock = (eCarLock)ScriptParams[1]; + return 0; + } + case COMMAND_EXPLODE_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + pVehicle->BlowUpCar(nil); + return 0; + } + case COMMAND_ADD_EXPLOSION: + CollectParameters(&m_nIp, 4); + CExplosion::AddExplosion(nil, nil, (eExplosionType)ScriptParams[3], *(CVector*)&ScriptParams[0], 0); + return 0; + + case COMMAND_IS_CAR_UPRIGHT: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + UpdateCompareFlag(pVehicle->GetUp().z >= 0.0f); + return 0; + } + case COMMAND_TURN_CHAR_TO_FACE_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; + CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); + CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); + float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; + if (angle > TWOPI) + angle -= TWOPI; + if (!pVehicle) { + pSourcePed->m_fRotationCur = angle; + pSourcePed->m_fRotationDest = angle; + pSourcePed->SetHeading(angle); + } + return 0; + } + case COMMAND_TURN_CHAR_TO_FACE_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CPed* pTargetPed = CWorld::Players[ScriptParams[1]].m_pPed; + CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; + CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); + CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); + float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; + if (angle > TWOPI) + angle -= TWOPI; + if (!pVehicle) { + pSourcePed->m_fRotationCur = angle; + pSourcePed->m_fRotationDest = angle; + pSourcePed->SetHeading(angle); + } + return 0; + } + case COMMAND_TURN_PLAYER_TO_FACE_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; + CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); + CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); + float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; + if (angle > TWOPI) + angle -= TWOPI; + if (!pVehicle) { + pSourcePed->m_fRotationCur = angle; + pSourcePed->m_fRotationDest = angle; + pSourcePed->SetHeading(angle); + } + return 0; + } + case COMMAND_SET_CHAR_OBJ_GOTO_COORD_ON_FOOT: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + CVector target; + target.x = *(float*)&ScriptParams[1]; + target.y = *(float*)&ScriptParams[2]; + target.z = CWorld::FindGroundZForCoord(target.x, target.y); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, target); + return 0; + } + /* Not implemented*/ + //case COMMAND_SET_CHAR_OBJ_GOTO_COORD_IN_CAR: + case COMMAND_CREATE_PICKUP: + { + CollectParameters(&m_nIp, 5); + int16 model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + CVector pos = *(CVector*)&ScriptParams[2]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + 0.5f; + // unused? + CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CPickups::GenerateNewOne(pos, model, ScriptParams[1], 0); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_HAS_PICKUP_BEEN_COLLECTED: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CPickups::IsPickUpPickedUp(ScriptParams[0]) != 0); + return 0; + case COMMAND_REMOVE_PICKUP: + CollectParameters(&m_nIp, 1); + CPickups::RemovePickUp(ScriptParams[0]); + return 0; + case COMMAND_SET_TAXI_LIGHTS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + ((CAutomobile*)pVehicle)->SetTaxiLight(ScriptParams[1] != 0); + return 0; + } + case COMMAND_PRINT_BIG_Q: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 2); + CMessages::AddBigMessageQ(text, ScriptParams[0], ScriptParams[1] - 1); + return 0; + } + case COMMAND_PRINT_WITH_NUMBER_BIG_Q: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 3); + CMessages::AddBigMessageWithNumberQ(text, ScriptParams[1], ScriptParams[2] - 1, + ScriptParams[0], -1, -1, -1, -1, -1); + return 0; + } + case COMMAND_SET_GARAGE: + { + CollectParameters(&m_nIp, 7); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, ScriptParams[6], 0); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_GARAGE_WITH_CAR_MODEL: + { + CollectParameters(&m_nIp, 8); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, ScriptParams[6], ScriptParams[7]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_TARGET_CAR_FOR_MISSION_GARAGE: + { + CollectParameters(&m_nIp, 2); + CVehicle* pTarget; + if (ScriptParams[1] >= 0) { + pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + assert(pTarget); + } + else { + pTarget = nil; + } + CGarages::SetTargetCarForMissonGarage(ScriptParams[0], pTarget); + return 0; + } + case COMMAND_IS_CAR_IN_MISSION_GARAGE: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CGarages::HasCarBeenDroppedOffYet(ScriptParams[0])); + return 0; + case COMMAND_SET_FREE_BOMBS: + CollectParameters(&m_nIp, 1); + CGarages::BombsAreFree = (ScriptParams[0] != 0); + return 0; + //case COMMAND_SET_POWERPOINT: + case COMMAND_SET_ALL_TAXI_LIGHTS: + CollectParameters(&m_nIp, 1); + CAutomobile::SetAllTaxiLights(ScriptParams[0] != 0); + return 0; + case COMMAND_IS_CAR_ARMED_WITH_ANY_BOMB: + { + CollectParameters(&m_nIp, 1); + CAutomobile* pCar = (CAutomobile*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pCar); + assert(pCar->m_vehType == VEHICLE_TYPE_CAR); + UpdateCompareFlag(pCar->m_bombType != 0); //TODO: enum + return 0; + } + case COMMAND_APPLY_BRAKES_TO_PLAYERS_CAR: + CollectParameters(&m_nIp, 2); + CPad::GetPad(ScriptParams[0])->bApplyBrakes = (ScriptParams[1] != 0); + return 0; + case COMMAND_SET_PLAYER_HEALTH: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + pPed->m_fHealth = ScriptParams[1]; + return 0; + } + case COMMAND_SET_CHAR_HEALTH: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + if (ScriptParams[1]) { + pPed->m_fHealth = ScriptParams[1]; + } + else if (pPed->bInVehicle) { + pPed->SetDead(); + if (!pPed->IsPlayer()) + pPed->FlagToDestroyWhenNextProcessed(); + } + else { + pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } + return 0; + } + case COMMAND_SET_CAR_HEALTH: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + pVehicle->m_fHealth = ScriptParams[1]; + return 0; + } + case COMMAND_GET_PLAYER_HEALTH: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + ScriptParams[0] = pPed->m_fHealth; // correct cast float to int + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_CHAR_HEALTH: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + ScriptParams[0] = pPed->m_fHealth; // correct cast float to int + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_CAR_HEALTH: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + ScriptParams[0] = pVehicle->m_fHealth; // correct cast float to int + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_CAR_ARMED_WITH_BOMB: + { + CollectParameters(&m_nIp, 2); + CAutomobile* pCar = (CAutomobile*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pCar); + assert(pCar->m_vehType == VEHICLE_TYPE_CAR); + UpdateCompareFlag(pCar->m_bombType == ScriptParams[1]); //TODO: enum + return 0; + } + case COMMAND_CHANGE_CAR_COLOUR: + { + CollectParameters(&m_nIp, 3); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + if (ScriptParams[1] >= 256 || ScriptParams[2] >= 256) + debug("CHANGE_CAR_COLOUR - Colours must be less than %d", 256); + pVehicle->m_currentColour1 = ScriptParams[1]; + pVehicle->m_currentColour2 = ScriptParams[2]; + return 0; + } + case COMMAND_SWITCH_PED_ROADS_ON: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.SwitchPedRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, false); + return 0; + } + case COMMAND_SWITCH_PED_ROADS_OFF: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.SwitchPedRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, true); + return 0; + } + case COMMAND_CHAR_LOOK_AT_CHAR_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pSourcePed); + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + assert(pTargetPed); + pSourcePed->SetLookFlag(pTargetPed, true); + pSourcePed->SetLookTimer(60000); + return 0; + } + case COMMAND_CHAR_LOOK_AT_PLAYER_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pSourcePed); + CPed* pTargetPed = CWorld::Players[ScriptParams[1]].m_pPed; + assert(pTargetPed); + pSourcePed->SetLookFlag(pTargetPed, true); + pSourcePed->SetLookTimer(60000); + return 0; + } + case COMMAND_PLAYER_LOOK_AT_CHAR_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pSourcePed); + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + assert(pTargetPed); + pSourcePed->SetLookFlag(pTargetPed, true); + pSourcePed->SetLookTimer(60000); + return 0; + } + case COMMAND_STOP_CHAR_LOOKING: + { + CollectParameters(&m_nIp, 1); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pSourcePed); + pSourcePed->ClearLookFlag(); + pSourcePed->bKeepTryingToLook = false; + if (pSourcePed->GetPedState() == PED_LOOK_HEADING || pSourcePed->GetPedState() == PED_LOOK_ENTITY) + pSourcePed->RestorePreviousState(); + return 0; + } + case COMMAND_STOP_PLAYER_LOOKING: + { + CollectParameters(&m_nIp, 1); + CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pSourcePed); + pSourcePed->ClearLookFlag(); + pSourcePed->bKeepTryingToLook = false; + if (pSourcePed->GetPedState() == PED_LOOK_HEADING || pSourcePed->GetPedState() == PED_LOOK_ENTITY) + pSourcePed->RestorePreviousState(); + return 0; + } + case COMMAND_SWITCH_HELICOPTER: + CollectParameters(&m_nIp, 1); + CHeli::ActivateHeli(ScriptParams[0] != 0); + return 0; + + //case COMMAND_SET_GANG_ATTITUDE: + //case COMMAND_SET_GANG_GANG_ATTITUDE: + //case COMMAND_SET_GANG_PLAYER_ATTITUDE: + //case COMMAND_SET_GANG_PED_MODELS: + case COMMAND_SET_GANG_CAR_MODEL: + CollectParameters(&m_nIp, 2); + CGangs::SetGangVehicleModel(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_SET_GANG_WEAPONS: + CollectParameters(&m_nIp, 3); + CGangs::SetGangWeapons(ScriptParams[0], (eWeaponType)ScriptParams[1], (eWeaponType)ScriptParams[2]); + return 0; + case COMMAND_SET_CHAR_OBJ_RUN_TO_AREA: + { + CollectParameters(&m_nIp, 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + float infX = *(float*)&ScriptParams[1]; + float infY = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[1]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[2]; + } + CVector pos; + pos.x = (infX + supX) / 2; + pos.y = (infY + supY) / 2; + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = max(pos.x - infX, pos.y - infY); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_RUN_TO_AREA, pos, radius); + return 0; + } + case COMMAND_SET_CHAR_OBJ_RUN_TO_COORD: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + CVector pos; + pos.x = *(float*)&ScriptParams[1]; + pos.y = *(float*)&ScriptParams[2]; + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_RUN_TO_AREA, pos); + return 0; + } + case COMMAND_IS_PLAYER_TOUCHING_OBJECT_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + bool isTouching = false; + if (pPed->bInVehicle) + isTouching = false; + else if (pPed->GetHasCollidedWith(pObject)) + isTouching = true; + UpdateCompareFlag(isTouching); + return 0; + } + case COMMAND_IS_CHAR_TOUCHING_OBJECT_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + bool isTouching = false; + if (pPed->bInVehicle && pPed->m_pMyVehicle) + isTouching = false; + else if (pPed->GetHasCollidedWith(pObject)) + isTouching = true; + UpdateCompareFlag(isTouching); + return 0; + } + case COMMAND_LOAD_SPECIAL_CHARACTER: + { + CollectParameters(&m_nIp, 1); + char name[16]; + strncpy(name, (char*)&CTheScripts::ScriptSpace[m_nIp], 8); + for (int i = 0; i < 8; i++) { + if (name[i] >= 'A' && name[i] <= 'Z') + name[i] += 'a' - 'A'; + } + CStreaming::RequestSpecialChar(ScriptParams[0] - 1, name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); + m_nIp += 8; + return 0; + } + case COMMAND_HAS_SPECIAL_CHARACTER_LOADED: + { + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CStreaming::HasSpecialCharLoaded(ScriptParams[0] - 1)); + return 0; + } + case COMMAND_FLASH_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + pVehicle->bHasBlip = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_FLASH_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + pPed->bHasBlip = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_FLASH_OBJECT: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + assert(pObject); + pObject->bHasBlip = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_IS_PLAYER_IN_REMOTE_MODE: + CollectParameters(&m_nIp, 2); + UpdateCompareFlag(CWorld::Players[ScriptParams[0]].IsPlayerInRemoteMode()); + return 0; + case COMMAND_ARM_CAR_WITH_BOMB: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + assert(pVehicle); + assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + ((CAutomobile*)pVehicle)->m_bombType = ScriptParams[1]; + ((CAutomobile*)pVehicle)->m_pBombRigger = FindPlayerPed(); + return 0; + } + case COMMAND_SET_CHAR_PERSONALITY: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + pPed->SetPedStats((ePedStats)ScriptParams[1]); + return 0; + } + case COMMAND_SET_CUTSCENE_OFFSET: + CollectParameters(&m_nIp, 3); + CCutsceneMgr::SetCutsceneOffset(*(CVector*)&ScriptParams[0]); + return 0; + case COMMAND_SET_ANIM_GROUP_FOR_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(pPed); + pPed->m_animGroup = (AssocGroupId)ScriptParams[1]; + return 0; + } + case COMMAND_SET_ANIM_GROUP_FOR_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + assert(pPed); + pPed->m_animGroup = (AssocGroupId)ScriptParams[1]; + return 0; + } + case COMMAND_REQUEST_MODEL: + { + CollectParameters(&m_nIp, 1); + int model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + CStreaming::RequestModel(model, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_NOFADE | STREAMFLAGS_SCRIPTOWNED); + return 0; + } + case COMMAND_HAS_MODEL_LOADED: + { + CollectParameters(&m_nIp, 1); + int model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + UpdateCompareFlag(CStreaming::HasModelLoaded(model)); + return 0; + } + case COMMAND_MARK_MODEL_AS_NO_LONGER_NEEDED: + { + CollectParameters(&m_nIp, 1); + int model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + CStreaming::SetMissionDoesntRequireModel(model); + return 0; + } + case COMMAND_GRAB_PHONE: + { + CollectParameters(&m_nIp, 2); + ScriptParams[0] = gPhoneInfo.GrabPhone(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_REPEATED_PHONE_MESSAGE: + { + CollectParameters(&m_nIp, 1); + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text, nil, nil, nil, nil, nil); + return 0; + } + case COMMAND_SET_PHONE_MESSAGE: + { + CollectParameters(&m_nIp, 1); + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text, nil, nil, nil, nil, nil); + return 0; + } + case COMMAND_HAS_PHONE_DISPLAYED_MESSAGE: + { + CollectParameters(&m_nIp, 1); + gPhoneInfo.HasMessageBeenDisplayed(ScriptParams[0]); + return 0; + } + case COMMAND_TURN_PHONE_OFF: + { + CollectParameters(&m_nIp, 1); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], nil, nil, nil, nil, nil, nil); + return 0; + } + case COMMAND_DRAW_CORONA: + { + CollectParameters(&m_nIp, 9); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CCoronas::RegisterCorona((uint32)this + m_nIp, ScriptParams[6], ScriptParams[7], ScriptParams[8], + 255, pos, *(float*)&ScriptParams[3], 150.0f, ScriptParams[4], ScriptParams[5], 1, 0, 0, 0.0f); + return 0; + } + case COMMAND_DRAW_LIGHT: + { + CollectParameters(&m_nIp, 6); + CVector pos = *(CVector*)&ScriptParams[0]; + CVector unused(0.0f, 0.0f, 0.0f); + CPointLights::AddLight(0, *(CVector*)&ScriptParams[0], CVector(0.0f, 0.0f, 0.0f), 12.0f, + ScriptParams[3] / 255.0f, ScriptParams[4] / 255.0f, ScriptParams[5] / 255.0f, 0, true); + return 0; + } + case COMMAND_STORE_WEATHER: + CWeather::StoreWeatherState(); + return 0; + case COMMAND_RESTORE_WEATHER: + CWeather::RestoreWeatherState(); + return 0; + case COMMAND_STORE_CLOCK: + CClock::StoreClock(); + return 0; + case COMMAND_RESTORE_CLOCK: + CClock::RestoreClock(); + return 0; + case COMMAND_RESTART_CRITICAL_MISSION: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRestart::OverrideNextRestart(pos, *(float*)&ScriptParams[3]); + if (CWorld::Players[CWorld::PlayerInFocus].m_WBState != WBSTATE_PLAYING) //TODO: enum + printf("RESTART_CRITICAL_MISSION - Player state is not PLAYING\n"); + CWorld::Players[CWorld::PlayerInFocus].PlayerFailedCriticalMission(); + return 0; + } + case COMMAND_IS_PLAYER_PLAYING: + { + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_PLAYING); + return 0; + } + //case COMMAND_SET_COLL_OBJ_NO_OBJ: + default: + assert(0); + } + return -1; +} +#endif + int16 CRunningScript::GetPadState(uint16 pad, uint16 button) { CPad* pPad = CPad::GetPad(pad); @@ -4365,7 +5174,6 @@ bool CTheScripts::IsVehicleStopped(CVehicle* pVehicle) return 0.01f * CTimer::GetTimeStep() >= pVehicle->m_fDistanceTravelled; } -WRAPPER int8 CRunningScript::ProcessCommandsFrom500To599(int32 command) { EAXJMP(0x4429C0); } WRAPPER int8 CRunningScript::ProcessCommandsFrom600To699(int32 command) { EAXJMP(0x444B20); } WRAPPER int8 CRunningScript::ProcessCommandsFrom700To799(int32 command) { EAXJMP(0x4458A0); } WRAPPER int8 CRunningScript::ProcessCommandsFrom800To899(int32 command) { EAXJMP(0x448240); } diff --git a/src/core/CutsceneMgr.h b/src/core/CutsceneMgr.h index 8c4a918b..e95a2a04 100644 --- a/src/core/CutsceneMgr.h +++ b/src/core/CutsceneMgr.h @@ -31,6 +31,7 @@ public: static CCutsceneObject* GetCutsceneObject(int id) { return ms_pCutsceneObjects[id]; } static int GetCutsceneTimeInMilleseconds(void) { return 1000.0f * ms_cutsceneTimer; } static char *GetCutsceneName(void) { return ms_cutsceneName; } + static void SetCutsceneOffset(const CVector& vec) { ms_cutsceneOffset = vec; } static bool HasCutsceneFinished(void); static void Initialise(void); diff --git a/src/core/PlayerInfo.cpp b/src/core/PlayerInfo.cpp index be2c0687..f0b7d444 100644 --- a/src/core/PlayerInfo.cpp +++ b/src/core/PlayerInfo.cpp @@ -72,6 +72,22 @@ CPlayerInfo::ArrestPlayer() CStats::TimesArrested++;
} +bool +CPlayerInfo::IsPlayerInRemoteMode() +{ + return m_pRemoteVehicle || m_bInRemoteMode; +} + +void +CPlayerInfo::PlayerFailedCriticalMission() +{ + if (m_WBState != WBSTATE_PLAYING) + return; + m_WBState = WBSTATE_FAILED_CRITICAL_MISSION; + m_nWBTime = CTimer::GetTimeInMilliseconds(); + CDarkel::ResetOnPlayerDeath(); +} + STARTPATCHES InjectHook(0x4A1700, &CPlayerInfo::LoadPlayerSkin, PATCH_JUMP); InjectHook(0x4A1750, &CPlayerInfo::DeletePlayerSkin, PATCH_JUMP); diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index 5784e1fb..ef21fb52 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -75,6 +75,8 @@ public: void Process(void); void KillPlayer(void); void ArrestPlayer(void); + bool IsPlayerInRemoteMode(void); + void PlayerFailedCriticalMission(void); }; static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error"); diff --git a/src/core/World.cpp b/src/core/World.cpp index 5dea09bd..ae0d67cc 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -999,6 +999,19 @@ CWorld::RemoveFallenCars(void) } void +CWorld::StopAllLawEnforcersInTheirTracks(void) +{ + int poolSize = CPools::GetVehiclePool()->GetSize(); + for (int poolIndex = poolSize - 1; poolIndex >= 0; poolIndex--) { + CVehicle* veh = CPools::GetVehiclePool()->GetSlot(poolIndex); + if (veh) { + if (veh->bIsLawEnforcer) + veh->SetMoveSpeed(0.0f, 0.0f, 0.0f); + } + } +} + +void CWorld::Process(void) { if (!(CTimer::GetFrameCounter() & 63)) diff --git a/src/core/World.h b/src/core/World.h index a1aa0376..3b04403e 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -120,6 +120,8 @@ public: static void RemoveFallenPeds(); static void RemoveFallenCars(); + static void StopAllLawEnforcersInTheirTracks(); + static void Initialise(); static void ShutDown(); static void RepositionCertainDynamicObjects(); diff --git a/src/core/config.h b/src/core/config.h index 12cb7be8..175a5f61 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -87,6 +87,9 @@ enum Config { NUM_FIRES = 40, NUMPEDROUTES = 200, + + NUMVISIBLEENTITIES = 2000, + NUMINVISIBLEENTITIES = 150, }; // We'll use this once we're ready to become independent of the game @@ -141,17 +144,17 @@ enum Config { # define CHATTYSPLASH // print what the game is loading #endif -#define FIX_BUGS // fix bugs in the game, TODO: use this more +#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more // Pad #define KANGAROO_CHEAT // Hud & radar #define ASPECT_RATIO_SCALE -#define TRIANGULAR_BLIPS +#define TRIANGULAR_BLIPS // height indicating triangular radar blips, as in VC // Script -#define USE_DEBUG_SCRIPT_LOADER +#define USE_DEBUG_SCRIPT_LOADER // makes game load main_freeroam.scm by default // Vehicles #define EXPLODING_AIRTRAIN // can blow up jumbo jet with rocket launcher @@ -162,6 +165,6 @@ enum Config { // Peds #define ANIMATE_PED_COL_MODEL -#define VC_PED_PORTS -#define NEW_WALK_AROUND_ALGORITHM +#define VC_PED_PORTS // various ports from VC's CPed, mostly subtle +#define NEW_WALK_AROUND_ALGORITHM // to make walking around vehicles/objects less awkward #define CANCELLABLE_CAR_ENTER diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 62e9a040..d6bc8148 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -354,6 +354,7 @@ DebugMenuPopulate(void) #ifndef MASTER DebugMenuAddVarBool8("Debug", "Toggle unused fight feature", (int8*)&CPed::bUnusedFightThingOnPlayer, nil); DebugMenuAddVarBool8("Debug", "Toggle banned particles", (int8*)&CParticle::bEnableBannedParticles, nil); + DebugMenuAddVarBool8("Debug", "Toggle popping heads on headshot", (int8*)&CPed::bPopHeadsOnHeadshot, nil); #endif DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); diff --git a/src/math/Vector.h b/src/math/Vector.h index 42087339..605d96ab 100644 --- a/src/math/Vector.h +++ b/src/math/Vector.h @@ -78,21 +78,6 @@ public: bool IsZero(void) { return x == 0.0f && y == 0.0f && z == 0.0f; } }; -inline float -DotProduct(const CVector &v1, const CVector &v2) -{ - return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; -} - -inline CVector -CrossProduct(const CVector &v1, const CVector &v2) -{ - return CVector( - v1.y*v2.z - v1.z*v2.y, - v1.z*v2.x - v1.x*v2.z, - v1.x*v2.y - v1.y*v2.x); -} - inline CVector operator+(const CVector &left, const CVector &right) { return CVector(left.x + right.x, left.y + right.y, left.z + right.z); @@ -117,3 +102,24 @@ inline CVector operator/(const CVector &left, float right) { return CVector(left.x / right, left.y / right, left.z / right); } + +inline float +DotProduct(const CVector &v1, const CVector &v2) +{ + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; +} + +inline CVector +CrossProduct(const CVector &v1, const CVector &v2) +{ + return CVector( + v1.y*v2.z - v1.z*v2.y, + v1.z*v2.x - v1.x*v2.z, + v1.x*v2.y - v1.y*v2.x); +} + +inline float +Distance(const CVector &v1, const CVector &v2) +{ + return (v2 - v1).Magnitude(); +}
\ No newline at end of file diff --git a/src/math/Vector2D.h b/src/math/Vector2D.h index a090155c..1e4d698f 100644 --- a/src/math/Vector2D.h +++ b/src/math/Vector2D.h @@ -49,9 +49,6 @@ public: CVector2D operator+(const CVector2D &rhs) const { return CVector2D(x+rhs.x, y+rhs.y); } - CVector2D operator*(float t) const { - return CVector2D(x*t, y*t); - } CVector2D operator/(float t) const { return CVector2D(x/t, y/t); } @@ -91,3 +88,13 @@ NormalizeXY(float &x, float &y) }else x = 1.0f; } + +inline CVector2D operator*(const CVector2D &left, float right) +{ + return CVector2D(left.x * right, left.y * right); +} + +inline CVector2D operator*(float left, const CVector2D &right) +{ + return CVector2D(left * right.x, left * right.y); +} diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 4f0ce736..4e64c1db 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -49,20 +49,14 @@ #include "ParticleObject.h" #include "Floater.h" -WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); } -WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); } WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); } -WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); } -WRAPPER void CPed::ServiceTalking(void) { EAXJMP(0x4E5870); } -WRAPPER void CPed::UpdatePosition(void) { EAXJMP(0x4C7A00); } WRAPPER void CPed::WanderPath(void) { EAXJMP(0x4D28D0); } -WRAPPER void CPed::UpdateFromLeader(void) { EAXJMP(0x4D8F30); } WRAPPER void CPed::SetEnterCar_AllClear(CVehicle*, uint32, uint32) { EAXJMP(0x4E0A40); } WRAPPER bool CPed::WarpPedToNearEntityOffScreen(CEntity*) { EAXJMP(0x4E5570); } WRAPPER void CPed::SetObjective(eObjective, CVector) { EAXJMP(0x4D8A90); } WRAPPER void CPed::SetObjective(eObjective, CVector, float) { EAXJMP(0x4D8770); } -WRAPPER void CPed::WarpPedIntoCar(CVehicle*) { EAXJMP(0x4D7D20); } WRAPPER void CPed::SetCarJack(CVehicle*) { EAXJMP(0x4E0220); } +WRAPPER void CPed::WarpPedToNearLeaderOffScreen(void) { EAXJMP(0x4E52A0); } #define FEET_OFFSET 1.04f @@ -80,7 +74,36 @@ CPedAudioData (&CPed::CommentWaitTime)[38] = *(CPedAudioData(*)[38]) * (uintptr* uint16 nPlayerInComboMove; -FightMove (&tFightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844; +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}, +}; +// *(FightMove(*)[NUM_FIGHTMOVES])* (uintptr*)0x5F9844; uint16 &CPed::nThreatReactionRangeMultiplier = *(uint16*)0x5F8C98; uint16 &CPed::nEnterCarRangeMultiplier = *(uint16*)0x5F8C94; @@ -261,6 +284,7 @@ static char WaitStateText[][16] = { #ifndef MASTER int nDisplayDebugInfo = 0; bool CPed::bUnusedFightThingOnPlayer = false; +bool CPed::bPopHeadsOnHeadshot = false; void CPed::SwitchDebugDisplay(void) @@ -853,7 +877,11 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 direction) frame = GetNodeFrame(nodeId); if (frame) { if (CGame::nastyGame) { +#ifndef MASTER + if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) +#else if (nodeId != PED_HEAD) +#endif SpawnFlyingComponent(nodeId, direction); RecurseFrameChildrenVisibilityCB(frame, nil); @@ -1827,11 +1855,11 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) // Getting out if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) { - float pedZSpeedOnExit = m_vecMoveSpeed.z - 0.008f * CTimer::GetTimeStep(); + float nextZSpeed = m_vecMoveSpeed.z - GRAVITY * CTimer::GetTimeStep(); // If we're not in ground at next step, apply animation - if (neededPos.z + pedZSpeedOnExit >= autoZPos.z) { - m_vecMoveSpeed.z = pedZSpeedOnExit; + if (neededPos.z + nextZSpeed >= autoZPos.z) { + m_vecMoveSpeed.z = nextZSpeed; ApplyMoveSpeed(); // Removing below line breaks the animation neededPos.z = GetPosition().z; @@ -4829,19 +4857,19 @@ CPed::LoadFightData(void) switch (hitLevel) { case 'G': - tFightMoves[moveId].hitLevel = 1; + tFightMoves[moveId].hitLevel = HITLEVEL_GROUND; break; case 'H': - tFightMoves[moveId].hitLevel = 4; + tFightMoves[moveId].hitLevel = HITLEVEL_HIGH; break; case 'L': - tFightMoves[moveId].hitLevel = 2; + tFightMoves[moveId].hitLevel = HITLEVEL_LOW; break; case 'M': - tFightMoves[moveId].hitLevel = 3; + tFightMoves[moveId].hitLevel = HITLEVEL_MEDIUM; break; case 'N': - tFightMoves[moveId].hitLevel = 0; + tFightMoves[moveId].hitLevel = HITLEVEL_NULL; break; default: break; @@ -4962,7 +4990,7 @@ CPed::FightStrike(CVector &touchedNodePos) } nearPed->ReactToAttack(this); - // Mostly unused. + // 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; @@ -4978,7 +5006,7 @@ CPed::FightStrike(CVector &touchedNodePos) } if (CGame::nastyGame - && tFightMoves[m_lastFightMove].hitLevel > 3 + && tFightMoves[m_lastFightMove].hitLevel > HITLEVEL_MEDIUM && nearPed->m_nPedState == PED_DIE && nearPed->GetIsOnScreen()) { @@ -5556,7 +5584,7 @@ CPed::CollideWithPed(CPed *collideWith) if (!heIsMissionChar) { CVector2D posDiff2D(posDiff); int direction = collideWith->GetLocalDirection(posDiff2D); - collideWith->StartFightDefend(direction, 4, 5); + collideWith->StartFightDefend(direction, HITLEVEL_HIGH, 5); } } } @@ -6370,7 +6398,7 @@ CPed::Fight(void) } else if (currentAssoc && m_fightState != FIGHTSTATE_MOVE_FINISHED) { float animTime = currentAssoc->currentTime; FightMove &curMove = tFightMoves[m_lastFightMove]; - if (curMove.hitLevel != 0 && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightState >= FIGHTSTATE_NO_MOVE) { + if (curMove.hitLevel != HITLEVEL_NULL && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightState >= FIGHTSTATE_NO_MOVE) { CVector touchingNodePos(0.0f, 0.0f, 0.0f); RwFrame *touchingFrame = nil; @@ -6415,7 +6443,7 @@ CPed::Fight(void) return; } - if (curMove.hitLevel != 0) { + if (curMove.hitLevel != HITLEVEL_NULL) { if (animTime > curMove.endFireTime) { if (IsPlayer()) currentAssoc->speed = 1.0f; @@ -6868,8 +6896,8 @@ CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) } #ifdef VC_PED_PORTS if (ped->m_pCurrentPhysSurface) { - ped->m_vecMoveSpeed.x += ((CPhysical*)ped->m_pCurrentPhysSurface)->m_vecMoveSpeed.x; - ped->m_vecMoveSpeed.y += ((CPhysical*)ped->m_pCurrentPhysSurface)->m_vecMoveSpeed.y; + ped->m_vecMoveSpeed.x += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.x; + ped->m_vecMoveSpeed.y += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.y; } #endif } @@ -8305,8 +8333,7 @@ CPed::InvestigateEvent(void) bool CPed::IsPedDoingDriveByShooting(void) { - if (this == FindPlayerPed() && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { - + if (FindPlayerPed() == this && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { if (TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight) return true; } @@ -9011,7 +9038,8 @@ FinishFuckUCB(CAnimBlendAssociation *animAssoc, void *arg) } void -CPed::Pause(void) { +CPed::Pause(void) +{ m_moved = CVector2D(0.0f, 0.0f); if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) ClearPause(); @@ -13395,7 +13423,7 @@ CPed::ProcessObjective(void) punchAssoc->flags |= ASSOC_FADEOUTWHENDONE; CVector2D offset(distWithTarget.x, distWithTarget.y); int dir = m_pedInObjective->GetLocalDirection(offset); - m_pedInObjective->StartFightDefend(dir, 4, 5); + m_pedInObjective->StartFightDefend(dir, HITLEVEL_HIGH, 5); m_pedInObjective->ReactToAttack(this); m_pedInObjective->Say(SOUND_PED_ROBBED); Say(SOUND_PED_MUGGING); @@ -13612,7 +13640,7 @@ LocalPosForWalkAround(CVector2D colMin, CVector2D colMax, int walkAround, uint32 bool CanWeSeeTheCorner(CVector2D dist, CVector2D fwdOffset) { - // because if dist is more then 5 unit, fov isn't important, we want shortest way + // because fov isn't important if dist is more then 5 unit, we want shortest way if (dist.Magnitude() > 5.0f) return true; @@ -13743,6 +13771,7 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) CVector cornerToGo = CVector(10.0f, 10.0f, 10.0f); int dirToGo; m_walkAroundType = 0; + int iWouldPreferGoingBack = 0; // 1:left 2:right #endif float adjustedCheckInterval = 0.7f * checkIntervalInDist; CVector posToCheck; @@ -13770,6 +13799,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { cornerToGo = tl; m_walkAroundType = 1; + + if (m_vehEnterType == CAR_DOOR_LR) + iWouldPreferGoingBack = 1; } else if(CanWeSeeTheCorner(tl, GetForward())){ cornerToGo = tl; dirToGo = GetLocalDirection(tl); @@ -13805,6 +13837,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { cornerToGo = tr; m_walkAroundType = 2; + + if (m_vehEnterType == CAR_DOOR_RR) + iWouldPreferGoingBack = 2; } else if (CanWeSeeTheCorner(tr, GetForward())) { cornerToGo = tr; dirToGo = GetLocalDirection(tr); @@ -13837,7 +13872,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) #ifdef NEW_WALK_AROUND_ALGORITHM else { CVector br = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMin.y, 0.0f) - GetPosition(); - if (br.Magnitude2D() < cornerToGo.Magnitude2D()) { + if (iWouldPreferGoingBack == 2) + m_walkAroundType = 4; + else if (br.Magnitude2D() < cornerToGo.Magnitude2D()) { if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { cornerToGo = br; m_walkAroundType = 5; @@ -13873,7 +13910,9 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) #ifdef NEW_WALK_AROUND_ALGORITHM else { CVector bl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMin.y, 0.0f) - GetPosition(); - if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) { + if (iWouldPreferGoingBack == 1) + m_walkAroundType = 7; + else if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) { if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { cornerToGo = bl; m_walkAroundType = 6; @@ -14274,7 +14313,7 @@ CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) m_ped_flagH10 = false; bOnBoat = false; } else { - m_pCurrentPhysSurface = collidingEnt; + m_pCurrentPhysSurface = (CPhysical*)collidingEnt; collidingEnt->RegisterReference((CEntity**)&m_pCurrentPhysSurface); m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition(); m_pCurSurface = collidingEnt; @@ -14479,7 +14518,7 @@ CPed::WillChat(CPed *stranger) } if (m_nSurfaceTouched == SURFACE_TARMAC) return false; - if (this == stranger) + if (stranger == this) return false; if (m_nPedType == stranger->m_nPedType) return true; @@ -14758,7 +14797,7 @@ CPed::ProcessBuoyancy(void) float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.8f : 1.1f); #endif - if (mod_Buoyancy.ProcessBuoyancy(this, 0.008f * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) { + if (mod_Buoyancy.ProcessBuoyancy(this, GRAVITY * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) { m_flagD8 = true; CEntity *entity; CColPoint point; @@ -15738,6 +15777,783 @@ CPed::SeekCar(void) } } +void +CPed::ServiceTalking(void) +{ + if (!bBodyPartJustCameOff || m_bodyPartBleeding != PED_HEAD) { + if (strcmpi(CModelInfo::GetModelInfo(m_modelIndex)->GetName(), "bomber")) { + if (m_nPedState == PED_ON_FIRE) + m_queuedSound = SOUND_PED_BURNING; + } else { + m_queuedSound = SOUND_PED_BOMBER; + } + if (m_queuedSound != SOUND_TOTAL_PED_SOUNDS) { + if (m_queuedSound == SOUND_PED_DEATH) + m_soundStart = CTimer::GetTimeInMilliseconds() - 1; + + if (CTimer::GetTimeInMilliseconds() > m_soundStart) { + DMAudio.PlayOneShot(m_audioEntityId, m_queuedSound, 1.0f); + m_lastSoundStart = CTimer::GetTimeInMilliseconds(); + m_soundStart = + CommentWaitTime[m_queuedSound - SOUND_PED_DEATH].m_nFixedDelayTime + + CTimer::GetTimeInMilliseconds() + + CGeneral::GetRandomNumberInRange(0, CommentWaitTime[m_queuedSound - SOUND_PED_DEATH].m_nOverrideFixedDelayTime); + m_lastQueuedSound = m_queuedSound; + m_queuedSound = SOUND_TOTAL_PED_SOUNDS; + } + } + } +} + +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_FLAG800)) { + 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) { + RwMatrix headMat; + CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &headMat); + for(int i = 0; i < 4; ++i) { + CVector bloodDir(0.0f, 0.0f, 0.1f); + CVector bloodPos = headMat.pos - 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_FLAG800) ? + 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_lastFightMove = FIGHTMOVE_HITONFLOOR; + break; + case HITLEVEL_LOW: +#ifndef VC_PED_PORTS + if (direction == 2) { + CPed::SetFall(1000, ANIM_KO_SKID_BACK, false); + return; + } +#else + if (direction == 2 && (!IsPlayer() || ((CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f))) { + CPed::SetFall(1000, ANIM_KO_SKID_BACK, false); + return; + } else if (direction != 2 && !IsPlayer() && (CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f) { + CPed::SetFall(1000, ANIM_KO_SHOT_STOM, false); + return; + } +#endif + m_lastFightMove = FIGHTMOVE_HITBODY; + break; + case HITLEVEL_HIGH: + switch (direction) { + case 1: + m_lastFightMove = FIGHTMOVE_HITLEFT; + break; + case 2: + m_lastFightMove = FIGHTMOVE_HITBACK; + break; + case 3: + m_lastFightMove = FIGHTMOVE_HITRIGHT; + break; + default: + if (unk <= 5) + m_lastFightMove = FIGHTMOVE_HITHEAD; + else + m_lastFightMove = FIGHTMOVE_HITBIGSTEP; + break; + } + break; + default: + switch (direction) { + case 1: + m_lastFightMove = FIGHTMOVE_HITLEFT; + break; + case 2: + m_lastFightMove = FIGHTMOVE_HITBACK; + break; + case 3: + m_lastFightMove = FIGHTMOVE_HITRIGHT; + break; + default: + if (unk <= 5) + m_lastFightMove = FIGHTMOVE_HITCHEST; + else + m_lastFightMove = FIGHTMOVE_HITBIGSTEP; + break; + } + break; + } + if (m_nPedState == PED_GETUP && !IsPedHeadAbovePos(0.0f)) + m_lastFightMove = FIGHTMOVE_HITONFLOOR; + + if (m_nPedState == PED_FIGHT) { + CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].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_lastFightMove].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(); + } + m_nPedState = PED_FIGHT; + 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_lastFightMove].animId, 8.0f); + moveAssoc->SetFinishCallback(FinishFightMoveCB, this); + m_fightState = FIGHTSTATE_NO_MOVE; + m_takeAStepAfterAttack = false; + bIsAttacking = true; + } + } + } +} + +void +CPed::UpdateFromLeader(void) +{ + if (CTimer::GetTimeInMilliseconds() <= m_objectiveTimer) + return; + + if (!m_leader) + return; + + CVector leaderDist; + if (m_leader->bInVehicle && m_leader->m_pMyVehicle) + leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); + else + leaderDist = m_leader->GetPosition() - GetPosition(); + + if (leaderDist.Magnitude() > 30.0f) { + if (IsPedInControl()) { + SetObjective(OBJECTIVE_NONE); + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + SetLeader(nil); + return; + } + + if (IsPedInControl()) { + if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) + WarpPedToNearLeaderOffScreen(); + + if (m_leader->m_nPedState == PED_DEAD) { + SetLeader(nil); + SetObjective(OBJECTIVE_FLEE_TILL_SAFE); + return; + } + if (!m_leader->bInVehicle) { + if (m_leader->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (bInVehicle) { + if (m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT && m_objective != OBJECTIVE_LEAVE_VEHICLE) + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + + return; + } + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + RestorePreviousObjective(); + RestorePreviousState(); + } + } + if (m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy == RANDOM_CHAR) { + SetLeader(nil); + return; + } + } + if (bInVehicle || !m_leader->bInVehicle || m_leader->m_nPedState != PED_DRIVING) { + if (m_leader->m_objective != OBJECTIVE_NONE && (!m_leader->IsPlayer() || m_leader->m_objective != OBJECTIVE_IDLE) + && m_objective != m_leader->m_objective) { + + switch (m_leader->m_objective) { + case OBJECTIVE_IDLE: + case OBJECTIVE_FLEE_TILL_SAFE: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_FOLLOW_ROUTE: + SetObjective(m_leader->m_objective); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_GUARD_SPOT: + SetObjective(OBJECTIVE_GUARD_SPOT, m_leader->m_vecSeekPosEx); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + if (m_leader->m_pedInObjective) { + SetObjective(m_leader->m_objective, m_leader->m_pedInObjective); + m_objectiveTimer = m_leader->m_objectiveTimer; + } + break; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_leader->m_carInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_carInObjective); + return; + } + break; + case OBJECTIVE_FIGHT_CHAR: + return; + case OBJECTIVE_HAIL_TAXI: + m_leader = nil; + SetObjective(OBJECTIVE_NONE); + break; + default: + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); + break; + } + } else { + if (m_leader->m_nPedState == PED_ATTACK) { + CEntity *lookTargetOfLeader = m_leader->m_pLookTarget; + if (lookTargetOfLeader && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT + && lookTargetOfLeader->IsPed() && lookTargetOfLeader != this) { + + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, lookTargetOfLeader); + SetObjectiveTimer(8000); + SetLookFlag(m_leader->m_pLookTarget, false); + SetLookTimer(500); + } + } else { + if (IsPedInControl() && m_nPedState != PED_ATTACK) { +#ifndef VC_PED_PORTS + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); +#else + if (m_leader->m_objective != OBJECTIVE_NONE || m_objective != OBJECTIVE_NONE + || m_leader->m_nPedState != PED_CHAT || m_nPedState != PED_CHAT) { + + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); + } else { + SetObjective(OBJECTIVE_NONE); + } +#endif + } + if (m_nPedState == PED_IDLE && m_leader->IsPlayer()) { + if (ScanForThreats() && m_threatEntity) { + m_pLookTarget = m_threatEntity; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && !GetWeapon()->IsTypeMelee()) { + m_pPointGunAt = m_threatEntity; + if (m_threatEntity) + m_threatEntity->RegisterReference((CEntity **) &m_pPointGunAt); + SetAttack(m_threatEntity); + } + } + } + } + } + } else { + if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (m_leader->m_pMyVehicle->m_nNumPassengers < m_leader->m_pMyVehicle->m_nNumMaxPassengers) + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_pMyVehicle); + } + } + } else if (bInVehicle) { + if ((!m_leader->bInVehicle || m_leader->m_nPedState == PED_EXIT_CAR) && m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT) { + + switch (m_leader->m_objective) { + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_pMyVehicle == m_leader->m_pMyVehicle || m_pMyVehicle == m_leader->m_carInObjective) + break; + + // fall through + default: + if (m_pMyVehicle && m_objective != OBJECTIVE_LEAVE_VEHICLE) { +#ifdef VC_PED_PORTS + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 250; +#endif + SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle); + } + + break; + } + } + } +} + +void +CPed::UpdatePosition(void) +{ + if (CReplay::IsPlayingBack() || !bIsStanding) + return; + + CVector2D velocityChange; + + SetHeading(m_fRotationCur); + if (m_pCurrentPhysSurface) { + CVector2D velocityOfSurface; + CPhysical *curSurface = m_pCurrentPhysSurface; + if (!IsPlayer() && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) { + + // It seems R* didn't like m_vecOffsetFromPhysSurface for boats + CVector offsetToSurface = GetPosition() - curSurface->GetPosition(); + offsetToSurface.z -= FEET_OFFSET; + + CVector surfaceMoveVelocity = curSurface->m_vecMoveSpeed; + CVector surfaceTurnVelocity = CrossProduct(curSurface->m_vecTurnSpeed, offsetToSurface); + + // Also we use that weird formula instead of friction if it's boat + float slideMult = -curSurface->m_vecTurnSpeed.MagnitudeSqr(); + velocityOfSurface = slideMult * offsetToSurface * CTimer::GetTimeStep() + (surfaceTurnVelocity + surfaceMoveVelocity); + m_vecMoveSpeed.z = slideMult * offsetToSurface.z * CTimer::GetTimeStep() + (surfaceTurnVelocity.z + surfaceMoveVelocity.z); + } else { + velocityOfSurface = curSurface->GetSpeed(m_vecOffsetFromPhysSurface); + } + // Reminder: m_moved is displacement from walking/running. + velocityChange = m_moved + velocityOfSurface - m_vecMoveSpeed; + m_fRotationCur += curSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + m_fRotationDest += curSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + } else if (m_nSurfaceTouched != SURFACE_STONE || m_vecDamageNormal.x == 0.0f && m_vecDamageNormal.y == 0.0f) { + velocityChange = m_moved - m_vecMoveSpeed; + } else { + // Ped got damaged by steep slope + m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.001f); + // some kind of + CVector2D reactionForce = m_vecDamageNormal * (1.0f / m_vecDamageNormal.Magnitude2D()); + + velocityChange = 0.02f * reactionForce + m_moved; + + float reactionAndVelocityDotProd = DotProduct2D(reactionForce, velocityChange); + // they're in same direction + if (reactionAndVelocityDotProd < 0.0f) { + velocityChange -= reactionAndVelocityDotProd * reactionForce; + } + } + + // Take time step into account + if (m_pCurrentPhysSurface) { + float speedChange = velocityChange.Magnitude(); + float changeMult = speedChange; + if (m_nPedState != PED_DIE || !m_pCurrentPhysSurface->IsVehicle()) { + if (!m_pCurrentPhysSurface->IsVehicle() || !((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) + changeMult = 0.01f * CTimer::GetTimeStep(); + } else { + changeMult = 0.002f * CTimer::GetTimeStep(); + } + + if (speedChange > changeMult) { + velocityChange = velocityChange * (changeMult / speedChange); + } + } + m_vecMoveSpeed.x += velocityChange.x; + m_vecMoveSpeed.y += velocityChange.y; +} + +void +CPed::SetPedPositionInCar(void) +{ + if (CReplay::IsPlayingBack()) + return; + + if (bChangedSeat) { + bool notYet = false; + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LOW_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LOW_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SHUFFLE_RHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSHUFFLE_RHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE_L) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN_L) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_L) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_R)) { + notYet = true; + } + if (notYet) { + LineUpPedWithCar(LINE_UP_TO_CAR_START); + bChangedSeat = false; + return; + } + } + CVehicleModelInfo *vehModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(m_pMyVehicle->m_modelIndex); + CMatrix newMat(m_pMyVehicle->GetMatrix()); + CVector seatPos; + if (m_pMyVehicle->pDriver == this) { + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + seatPos = vehModel->m_positions[BOAT_POS_FRONTSEAT]; + else + seatPos = vehModel->m_positions[CAR_POS_FRONTSEAT]; + + if (!m_pMyVehicle->IsBoat() && m_pMyVehicle->m_vehType != VEHICLE_TYPE_BIKE) + seatPos.x = -seatPos.x; + + } else if (m_pMyVehicle->pPassengers[0] == this) { + if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) + seatPos = vehModel->m_positions[BOAT_POS_FRONTSEAT]; + else + seatPos = vehModel->m_positions[CAR_POS_FRONTSEAT]; + } else if (m_pMyVehicle->pPassengers[1] == this) { + seatPos = vehModel->m_positions[CAR_POS_BACKSEAT]; + seatPos.x = -seatPos.x; + } else { + if (m_pMyVehicle->pPassengers[2] == this) { + seatPos = vehModel->m_positions[CAR_POS_BACKSEAT]; + } else if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT) { + seatPos = vehModel->m_positions[BOAT_POS_FRONTSEAT]; + } else { + seatPos = vehModel->m_positions[CAR_POS_FRONTSEAT]; + } + } + newMat.GetPosition() += Multiply3x3(newMat, seatPos); + // Already done below (SetTranslate(0.0f, 0.0f, 0.0f)) + // tempMat.SetUnity(); + + // Rear seats on vans don't face to front, so rotate them HALFPI. + if (m_pMyVehicle->bIsVan) { + CMatrix tempMat; + if (m_pMyVehicle->pPassengers[1] == this) { + m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI; + tempMat.SetTranslate(0.0f, 0.0f, 0.0f); + tempMat.RotateZ(-HALFPI); + newMat = newMat * tempMat; + } else if (m_pMyVehicle->pPassengers[2] == this) { + m_fRotationCur = HALFPI + m_pMyVehicle->GetForward().Heading(); + tempMat.SetTranslate(0.0f, 0.0f, 0.0f); + tempMat.RotateZ(HALFPI); + newMat = newMat * tempMat; + } else { + m_fRotationCur = m_pMyVehicle->GetForward().Heading(); + } + } else { + m_fRotationCur = m_pMyVehicle->GetForward().Heading(); + } + GetMatrix() = newMat; +} + +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; +} + +CObject* +CPed::SpawnFlyingComponent(int pedNode, int8 direction) +{ + if (CObject::nNoTempObjects >= NUMTEMPOBJECTS) + return nil; + + CObject *obj = new CObject(); + if (!obj) + return nil; + + RwFrame *frame = RwFrameCreate(); + RpClump *clump = RpClumpCreate(); + RpClumpSetFrame(clump, frame); + RwMatrix *matrix = RwFrameGetLTM(GetNodeFrame(pedNode)); + *RwFrameGetMatrix(frame) = *matrix; + + flyingClumpTemp = clump; + RwFrameForAllObjects(GetNodeFrame(pedNode), CloneAtomicToFrameCB, frame); + RwFrameForAllChildren(GetNodeFrame(pedNode), 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(m_modelIndex); + 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->bIsStatic = false; + obj->bIsPickup = false; + obj->m_nSpecialCollisionResponseCases = COLLRESPONSE_SPLIT_MODEL; + + // 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::WarpPedIntoCar(CVehicle *car) +{ + bInVehicle = true; + m_pMyVehicle = car; + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_carInObjective = car; + m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); + m_nPedState = PED_DRIVING; + bUsesCollision = false; + bIsInTheAir = false; + m_ped_flagI4 = true; + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + car->SetDriver(this); + car->pDriver->RegisterReference((CEntity **) &car->pDriver); + + } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + for (int i = 0; i < 4; i++) { + if (!car->pPassengers[i]) { + car->pPassengers[i] = this; + car->pPassengers[i]->RegisterReference((CEntity **) &car->pPassengers[i]); + break; + } + } + } else + return; + + if (IsPlayer()) { + car->m_status = STATUS_PLAYER; + AudioManager.PlayerJustGotInCar(); + CCarCtrl::RegisterVehicleOfInterest(car); + } else { + car->m_status = STATUS_PHYSICS; + } + + CWorld::Remove(this); + GetPosition() = car->GetPosition(); + CWorld::Add(this); + + if (car->bIsAmbulanceOnDuty) { + car->bIsAmbulanceOnDuty = false; + --CCarCtrl::NumAmbulancesOnDuty; + } + if (car->bIsFireTruckOnDuty) { + car->bIsFireTruckOnDuty = false; + --CCarCtrl::NumFiretrucksOnDuty; + } + if (!car->bEngineOn) { + car->bEngineOn = true; + DMAudio.PlayOneShot(car->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); + } + if (car->IsBoat()) { + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); + CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(ourWeapon->m_nModelId); + } else { + + // Because we can use Uzi for drive by + // RemoveWeaponWhenEnteringVehicle in VC + if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { + if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) + m_storedWeapon = GetWeapon()->m_eWeaponType; + SetCurrentWeapon(WEAPONTYPE_UZI); + } else { + CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(ourWeapon->m_nModelId); + } + + if (car->bLowVehicle) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); + } + StopNonPartialAnims(); + if (car->bIsBus) + bRenderPedInCar = false; + + bChangedSeat = true; +} + class CPed_ : public CPed { public: @@ -15956,4 +16772,9 @@ STARTPATCHES InjectHook(0x4C5FE0, &CPed::ScanForThreats, PATCH_JUMP); InjectHook(0x4C6C10, &CPed::ScanForInterestingStuff, PATCH_JUMP); InjectHook(0x4D3F90, &CPed::SeekCar, PATCH_JUMP); + InjectHook(0x4E5870, &CPed::ServiceTalking, PATCH_JUMP); + InjectHook(0x4E7780, &CPed::StartFightDefend, PATCH_JUMP); + InjectHook(0x4D8F30, &CPed::UpdateFromLeader, PATCH_JUMP); + InjectHook(0x4D4970, &CPed::SetPedPositionInCar, PATCH_JUMP); + InjectHook(0x4D7D20, &CPed::WarpPedIntoCar, PATCH_JUMP); ENDPATCHES
\ No newline at end of file diff --git a/src/peds/Ped.h b/src/peds/Ped.h index b8d2f5dd..50a8bfec 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -15,6 +15,7 @@ struct CPathNode; class CAccident; +class CObject; struct CPedAudioData { @@ -58,6 +59,15 @@ enum PedRouteType PEDROUTE_GO_TO_START_WHEN_DONE }; +enum FightMoveHitLevel +{ + HITLEVEL_NULL, + HITLEVEL_GROUND, + HITLEVEL_LOW, + HITLEVEL_MEDIUM, + HITLEVEL_HIGH +}; + struct FightMove { AnimationId animId; @@ -65,7 +75,7 @@ struct FightMove float endFireTime; float comboFollowOnTime; float strikeRadius; - uint8 hitLevel; + uint8 hitLevel; // FightMoveHitLevel uint8 damage; uint8 flags; }; @@ -99,7 +109,8 @@ enum PedFightMoves FIGHTMOVE_HITBIGSTEP, FIGHTMOVE_HITONFLOOR, FIGHTMOVE_HITBEHIND, - FIGHTMOVE_IDLE2NORM + FIGHTMOVE_IDLE2NORM, + NUM_FIGHTMOVES }; enum ePedPieceTypes @@ -352,7 +363,7 @@ public: uint8 bShakeFist : 1; // test shake hand at look entity uint8 bNoCriticalHits : 1; // if set, limbs won't came off - uint8 m_ped_flagI4 : 1; // seems like related with cars + uint8 m_ped_flagI4 : 1; // we've been put to car by script? - related with cars uint8 bHasAlreadyBeenRecorded : 1; uint8 bFallenDown : 1; #ifdef VC_PED_PORTS @@ -420,7 +431,7 @@ public: float m_headingRate; uint16 m_vehEnterType; // TODO: this is more like a door, not a type int16 m_walkAroundType; - CEntity *m_pCurrentPhysSurface; + CPhysical *m_pCurrentPhysSurface; CVector m_vecOffsetFromPhysSurface; CEntity *m_pCurSurface; CVector m_vecSeekPos; @@ -522,7 +533,6 @@ public: void SetDead(void); void ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer); void RemoveBodyPart(PedNode nodeId, int8 direction); - void SpawnFlyingComponent(int, int8); bool OurPedCanSeeThisOne(CEntity *target); void Avoid(void); void Attack(void); @@ -660,7 +670,6 @@ public: void ProcessBuoyancy(void); void ServiceTalking(void); void SetJump(void); - void UpdatePosition(void); void WanderPath(void); void ReactToPointGun(CEntity*); void SeekCar(void); @@ -681,6 +690,7 @@ public: void ScanForInterestingStuff(void); void WarpPedIntoCar(CVehicle*); void SetCarJack(CVehicle*); + void WarpPedToNearLeaderOffScreen(void); // Static methods static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset); @@ -756,6 +766,8 @@ public: void WanderRange(void); void SetFollowRoute(int16, int16); void SeekBoatPosition(void); + void UpdatePosition(void); + CObject *SpawnFlyingComponent(int, int8); #ifdef VC_PED_PORTS bool CanPedJumpThis(CEntity*, CVector*); #else @@ -785,9 +797,12 @@ public: static CPedAudioData (&CommentWaitTime)[38]; #ifndef MASTER + static bool bUnusedFightThingOnPlayer; + static bool bPopHeadsOnHeadshot; + + // Mobile things static void SwitchDebugDisplay(void); void DebugRenderOnePedText(void); - static bool bUnusedFightThingOnPlayer; #endif }; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 562d5882..8322c22a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -40,9 +40,9 @@ struct EntityInfo CLinkList<EntityInfo> &gSortedVehiclesAndPeds = *(CLinkList<EntityInfo>*)0x629AC0; int32 &CRenderer::ms_nNoOfVisibleEntities = *(int32*)0x940730; -CEntity **CRenderer::ms_aVisibleEntityPtrs = (CEntity**)0x6E9920; +CEntity *(&CRenderer::ms_aVisibleEntityPtrs)[NUMVISIBLEENTITIES] = *(CEntity * (*)[NUMVISIBLEENTITIES]) * (uintptr*)0x6E9920; +CEntity *(&CRenderer::ms_aInVisibleEntityPtrs)[NUMINVISIBLEENTITIES] = *(CEntity * (*)[NUMINVISIBLEENTITIES]) * (uintptr*)0x880B50; int32 &CRenderer::ms_nNoOfInVisibleEntities = *(int32*)0x8F1B78; -CEntity **CRenderer::ms_aInVisibleEntityPtrs = (CEntity**)0x880B50; CVector &CRenderer::ms_vecCameraPosition = *(CVector*)0x8E2C3C; CVehicle *&CRenderer::m_pFirstPersonVehicle = *(CVehicle**)0x885B80; @@ -73,9 +73,9 @@ CRenderer::PreRender(void) for(i = 0; i < ms_nNoOfInVisibleEntities; i++) ms_aInVisibleEntityPtrs[i]->PreRender(); - for(node = CVisibilityPlugins::m_alphaEntityList.tail.prev; - node != &CVisibilityPlugins::m_alphaEntityList.head; - node = node->prev) + for(node = CVisibilityPlugins::m_alphaEntityList.head.next; + node != &CVisibilityPlugins::m_alphaEntityList.tail; + node = node->next) ((CEntity*)node->item.entity)->PreRender(); CHeli::SpecialHeliPreRender(); @@ -983,7 +983,7 @@ CRenderer::ScanSectorList(CPtrList *lists) dy = ms_vecCameraPosition.y - ent->GetPosition().y; if(dx > -65.0f && dx < 65.0f && dy > -65.0f && dy < 65.0f && - ms_nNoOfInVisibleEntities < 150) + ms_nNoOfInVisibleEntities < NUMINVISIBLEENTITIES - 1) ms_aInVisibleEntityPtrs[ms_nNoOfInVisibleEntities++] = ent; break; case VIS_STREAMME: @@ -1033,7 +1033,7 @@ CRenderer::ScanSectorList_Priority(CPtrList *lists) dy = ms_vecCameraPosition.y - ent->GetPosition().y; if(dx > -65.0f && dx < 65.0f && dy > -65.0f && dy < 65.0f && - ms_nNoOfInVisibleEntities < 150) + ms_nNoOfInVisibleEntities < NUMINVISIBLEENTITIES - 1) ms_aInVisibleEntityPtrs[ms_nNoOfInVisibleEntities++] = ent; break; case VIS_STREAMME: @@ -1078,7 +1078,7 @@ CRenderer::ScanSectorList_Subway(CPtrList *lists) dy = ms_vecCameraPosition.y - ent->GetPosition().y; if(dx > -65.0f && dx < 65.0f && dy > -65.0f && dy < 65.0f && - ms_nNoOfInVisibleEntities < 150) + ms_nNoOfInVisibleEntities < NUMINVISIBLEENTITIES - 1) ms_aInVisibleEntityPtrs[ms_nNoOfInVisibleEntities++] = ent; break; } @@ -1160,8 +1160,12 @@ CRenderer::IsEntityCullZoneVisible(CEntity *ent) return IsVehicleCullZoneVisible(ent); case ENTITY_TYPE_PED: ped = (CPed*)ent; - if(ped->bInVehicle) - return ped->m_pMyVehicle && IsVehicleCullZoneVisible(ped->m_pMyVehicle); + if (ped->bInVehicle) { + if (ped->m_pMyVehicle) + return IsVehicleCullZoneVisible(ped->m_pMyVehicle); + else + return true; + } return !(ped->m_pCurSurface && ped->m_pCurSurface->bZoneCulled2); case ENTITY_TYPE_OBJECT: obj = (CObject*)ent; diff --git a/src/render/Renderer.h b/src/render/Renderer.h index 817cdaae..ea49ed4e 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -19,9 +19,9 @@ class CPtrList; class CRenderer { static int32 &ms_nNoOfVisibleEntities; - static CEntity **ms_aVisibleEntityPtrs; // [2000]; + static CEntity *(&ms_aVisibleEntityPtrs)[NUMVISIBLEENTITIES]; static int32 &ms_nNoOfInVisibleEntities; - static CEntity **ms_aInVisibleEntityPtrs; // [150]; + static CEntity *(&ms_aInVisibleEntityPtrs)[NUMINVISIBLEENTITIES]; static CVector &ms_vecCameraPosition; static CVehicle *&m_pFirstPersonVehicle; diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp index db1bc80b..479f3404 100644 --- a/src/render/Weather.cpp +++ b/src/render/Weather.cpp @@ -27,6 +27,11 @@ float &CWeather::Rainbow = *(float*)0x940598; bool &CWeather::bScriptsForceRain = *(bool*)0x95CD7D; bool &CWeather::Stored_StateStored = *(bool*)0x95CDC1; +float &CWeather::Stored_InterpolationValue = *(float*)0x942F54; +int16 &CWeather::Stored_OldWeatherType = *(int16*)0x95CC68; +int16 &CWeather::Stored_NewWeatherType = *(int16*)0x95CCAE; +float &CWeather::Stored_Rain = *(float*)0x885B4C; + WRAPPER void CWeather::RenderRainStreaks(void) { EAXJMP(0x524550); } WRAPPER void CWeather::Update(void) { EAXJMP(0x522C10); } @@ -46,3 +51,23 @@ void CWeather::ForceWeatherNow(int16 weather) NewWeatherType = weather; ForcedWeatherType = weather; } + +void CWeather::StoreWeatherState() +{ + Stored_StateStored = true; + Stored_InterpolationValue = InterpolationValue; + Stored_Rain = Rain; + Stored_NewWeatherType = NewWeatherType; + Stored_OldWeatherType = OldWeatherType; +} + +void CWeather::RestoreWeatherState() +{ +#ifdef FIX_BUGS // it's not used anyway though + Stored_StateStored = false; +#endif + InterpolationValue = Stored_InterpolationValue; + Rain = Stored_Rain; + NewWeatherType = Stored_NewWeatherType; + OldWeatherType = Stored_OldWeatherType; +}
\ No newline at end of file diff --git a/src/render/Weather.h b/src/render/Weather.h index 41cc5c0e..b5704b01 100644 --- a/src/render/Weather.h +++ b/src/render/Weather.h @@ -32,6 +32,10 @@ public: static bool &bScriptsForceRain; static bool &Stored_StateStored; + static float &Stored_InterpolationValue; + static int16 &Stored_OldWeatherType; + static int16 &Stored_NewWeatherType; + static float &Stored_Rain; static void RenderRainStreaks(void); static void Update(void); @@ -39,4 +43,6 @@ public: static void ReleaseWeather(); static void ForceWeather(int16); static void ForceWeatherNow(int16); + static void StoreWeatherState(); + static void RestoreWeatherState(); }; diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 0fa8547e..30446894 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -2474,8 +2474,8 @@ CAutomobile::TankControl(void) int lifeSpan = 250; if(m_vecMoveSpeed.Magnitude() > 0.08f){ lifeSpan = 125; - flashPos.x += 0.5f*m_vecMoveSpeed.x; - flashPos.y += 0.5f*m_vecMoveSpeed.y; + flashPos.x += 5.0f*m_vecMoveSpeed.x; + flashPos.y += 5.0f*m_vecMoveSpeed.y; } CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.4f, black, 0, 0, 0, lifeSpan); flashPos += 0.3f*shotDir; @@ -4210,7 +4210,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type) if(atomic == nil) return nil; - obj = new CObject; + obj = new CObject(); if(obj == nil) return nil; |