summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--README.md124
-rw-r--r--src/animation/AnimManager.h4
-rw-r--r--src/audio/AudioManager.cpp69
-rw-r--r--src/audio/AudioManager.h2
-rw-r--r--src/control/Garages.cpp3
-rw-r--r--src/control/Garages.h5
-rw-r--r--src/control/Script.cpp852
-rw-r--r--src/core/CutsceneMgr.h1
-rw-r--r--src/core/PlayerInfo.cpp16
-rw-r--r--src/core/PlayerInfo.h2
-rw-r--r--src/core/World.cpp13
-rw-r--r--src/core/World.h2
-rw-r--r--src/core/config.h13
-rw-r--r--src/core/re3.cpp1
-rw-r--r--src/math/Vector.h36
-rw-r--r--src/math/Vector2D.h13
-rw-r--r--src/peds/Ped.cpp887
-rw-r--r--src/peds/Ped.h29
-rw-r--r--src/render/Renderer.cpp24
-rw-r--r--src/render/Renderer.h4
-rw-r--r--src/render/Weather.cpp25
-rw-r--r--src/render/Weather.h6
-rw-r--r--src/vehicles/Automobile.cpp6
23 files changed, 1976 insertions, 161 deletions
diff --git a/README.md b/README.md
index 3e8a4a6b..6d4d6afd 100644
--- a/README.md
+++ b/README.md
@@ -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;