summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraap <aap@papnet.eu>2020-04-15 22:36:21 +0200
committeraap <aap@papnet.eu>2020-04-15 22:36:21 +0200
commitafce2e1bb3212a01efe0205313cf5d632eee8a20 (patch)
treee9602e11ba49ad3cd35c0af4355eec330d73aa8b
parentimplemented most of librw wrapper (diff)
parentMerge pull request #440 from Fire-Head/master (diff)
downloadre3-afce2e1bb3212a01efe0205313cf5d632eee8a20.tar
re3-afce2e1bb3212a01efe0205313cf5d632eee8a20.tar.gz
re3-afce2e1bb3212a01efe0205313cf5d632eee8a20.tar.bz2
re3-afce2e1bb3212a01efe0205313cf5d632eee8a20.tar.lz
re3-afce2e1bb3212a01efe0205313cf5d632eee8a20.tar.xz
re3-afce2e1bb3212a01efe0205313cf5d632eee8a20.tar.zst
re3-afce2e1bb3212a01efe0205313cf5d632eee8a20.zip
-rw-r--r--README.md1
-rw-r--r--src/audio/AudioManager.h2
-rw-r--r--src/control/AutoPilot.cpp2
-rw-r--r--src/control/CarCtrl.cpp2
-rw-r--r--src/control/Garages.cpp12
-rw-r--r--src/control/PathFind.cpp203
-rw-r--r--src/control/PathFind.h33
-rw-r--r--src/control/SceneEdit.cpp1101
-rw-r--r--src/control/SceneEdit.h93
-rw-r--r--src/control/Script.cpp2
-rw-r--r--src/core/Collision.cpp5
-rw-r--r--src/core/Collision.h11
-rw-r--r--src/core/Frontend.cpp127
-rw-r--r--src/core/Frontend.h8
-rw-r--r--src/core/Game.cpp2
-rw-r--r--src/core/General.h5
-rw-r--r--src/core/Pad.cpp2
-rw-r--r--src/core/World.cpp5
-rw-r--r--src/core/World.h6
-rw-r--r--src/core/main.cpp11
-rw-r--r--src/core/re3.cpp3
-rw-r--r--src/entities/Physical.cpp8
-rw-r--r--src/math/Vector.h7
-rw-r--r--src/math/Vector2D.h7
-rw-r--r--src/modelinfo/ModelIndices.h7
-rw-r--r--src/peds/Ped.cpp19
-rw-r--r--src/peds/Ped.h15
-rw-r--r--src/peds/PlayerPed.cpp8
-rw-r--r--src/peds/PlayerPed.h4
-rw-r--r--src/peds/Population.cpp60
-rw-r--r--src/render/Clouds.cpp2
-rw-r--r--src/render/Glass.cpp16
-rw-r--r--src/render/Renderer.cpp17
-rw-r--r--src/render/Renderer.h16
-rw-r--r--src/render/Sprite.cpp18
-rw-r--r--src/vehicles/Automobile.cpp7
-rw-r--r--src/vehicles/Heli.cpp8
-rw-r--r--src/vehicles/Vehicle.cpp12
-rw-r--r--src/vehicles/Vehicle.h12
-rw-r--r--src/weapons/BulletInfo.cpp4
-rw-r--r--src/weapons/BulletInfo.h7
-rw-r--r--src/weapons/Weapon.cpp2235
-rw-r--r--src/weapons/Weapon.h60
43 files changed, 3935 insertions, 250 deletions
diff --git a/README.md b/README.md
index c7d83212..53f2136a 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,6 @@ to reverse at the time, calling the original functions is acceptable.
### Unreversed / incomplete classes (at least the ones we know)
```
CBulletInfo
-CPedPath
CWeapon
CWorld
```
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
index 31a07f9b..ad558061 100644
--- a/src/audio/AudioManager.h
+++ b/src/audio/AudioManager.h
@@ -118,7 +118,7 @@ enum eScriptSounds : int16 {
SCRIPT_SOUND_BULLET_HIT_GROUND_1 = 106,
SCRIPT_SOUND_BULLET_HIT_GROUND_2 = 107,
SCRIPT_SOUND_BULLET_HIT_GROUND_3 = 108,
- SCRIPT_SOUND_109 = 109,
+ SCRIPT_SOUND_BULLET_HIT_WATER = 109, //no sound
SCRIPT_SOUND_110 = 110,
SCRIPT_SOUND_111 = 111,
SCRIPT_SOUND_PAYPHONE_RINGING = 112,
diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp
index b5bca21d..65e73e5d 100644
--- a/src/control/AutoPilot.cpp
+++ b/src/control/AutoPilot.cpp
@@ -35,7 +35,7 @@ void CAutoPilot::ModifySpeed(float speed)
m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
(uint32)(positionBetweenNodes * m_nTimeToSpendOnCurrentCurve);
#else
- m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - positionBetweenNodes * m_nSpeedScaleFactor;
+ m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - positionBetweenNodes * m_nTimeToSpendOnCurrentCurve;
#endif
}
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 264f1f3f..197fca63 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -426,7 +426,7 @@ CCarCtrl::GenerateOneRandomCar()
(uint32)((0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve);
#else
pCar->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
- (0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nSpeedScaleFactor;
+ (0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve;
#endif
CVector directionCurrentLink(directionCurrentLinkX, directionCurrentLinkY, 0.0f);
CVector directionNextLink(directionNextLinkX, directionNextLinkY, 0.0f);
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index d971d453..d187f666 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -307,13 +307,13 @@ void CGarage::Update()
CGarages::bCamShouldBeOutisde = true;
}
if (pVehicle) {
- if (IsEntityEntirelyOutside(pVehicle, 0.0f))
+ if (!IsEntityEntirelyOutside(pVehicle, 0.0f))
TheCamera.pToGarageWeAreInForHackAvoidFirstPerson = this;
if (pVehicle->GetModelIndex() == MI_MRWHOOP) {
if (pVehicle->IsWithinArea(
m_fX1 - DISTANCE_FOR_MRWHOOP_HACK,
- m_fX2 + DISTANCE_FOR_MRWHOOP_HACK,
- m_fY1 - DISTANCE_FOR_MRWHOOP_HACK,
+ m_fY1 + DISTANCE_FOR_MRWHOOP_HACK,
+ m_fX2 - DISTANCE_FOR_MRWHOOP_HACK,
m_fY2 + DISTANCE_FOR_MRWHOOP_HACK)) {
TheCamera.pToGarageWeAreIn = this;
CGarages::bCamShouldBeOutisde = true;
@@ -1082,7 +1082,7 @@ void CGarage::Update()
#ifdef FIX_BUGS
bool bCreatedAllCars = false;
#else
- bool bCraetedAllCars;
+ bool bCreatedAllCars;
#endif
switch (m_eGarageType) {
case GARAGE_HIDEOUT_ONE: bCreatedAllCars = RestoreCarsForThisHideout(CGarages::aCarsInSafeHouse1); break;
@@ -2313,6 +2313,10 @@ void CGarages::Load(uint8* buf, uint32 size)
#ifdef FIX_GARAGE_SIZE
VALIDATESAVEBUF(size);
#endif
+
+ MessageEndTime = 0;
+ bCamShouldBeOutisde = false;
+ MessageStartTime = 0;
}
bool
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index 61cd3d4e..9f45c454 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -14,9 +14,8 @@ bool gbShowCarPathsLinks;
CPathFind &ThePaths = *(CPathFind*)0x8F6754;
-WRAPPER bool CPedPath::CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16) { EAXJMP(0x42E680); }
-
#define MAX_DIST INT16_MAX-1
+#define MIN_PED_ROUTE_DISTANCE 23.8f
// object flags:
// 1 UseInRoadBlock
@@ -28,6 +27,199 @@ CPathInfoForObject *&InfoForTilePeds = *(CPathInfoForObject**)0x8F1AE4;
CTempDetachedNode *&DetachedNodesCars = *(CTempDetachedNode**)0x8E2824;
CTempDetachedNode *&DetachedNodesPeds = *(CTempDetachedNode**)0x8E28A0;
+bool
+CPedPath::CalcPedRoute(int8 pathType, CVector position, CVector destination, CVector *pointPoses, int16 *pointsFound, int16 maxPoints)
+{
+ *pointsFound = 0;
+ CVector vecDistance = destination - position;
+ if (Abs(vecDistance.x) > MIN_PED_ROUTE_DISTANCE || Abs(vecDistance.y) > MIN_PED_ROUTE_DISTANCE || Abs(vecDistance.z) > MIN_PED_ROUTE_DISTANCE)
+ return false;
+ CVector vecPos = (position + destination) * 0.5f;
+ CVector vecSectorStartPos (vecPos.x - 14.0f, vecPos.y - 14.0f, vecPos.z);
+ CVector2D vecSectorEndPos (vecPos.x + 28.0f, vecPos.x + 28.0f);
+ const int16 nodeStartX = (position.x - vecSectorStartPos.x) / 0.7f;
+ const int16 nodeStartY = (position.y - vecSectorStartPos.y) / 0.7f;
+ const int16 nodeEndX = (destination.x - vecSectorStartPos.x) / 0.7f;
+ const int16 nodeEndY = (destination.y - vecSectorStartPos.y) / 0.7f;
+ if (nodeStartX == nodeEndX && nodeStartY == nodeEndY)
+ return false;
+ CPedPathNode pathNodes[40][40];
+ CPedPathNode pathNodesList[416];
+ for (int32 x = 0; x < 40; x++) {
+ for (int32 y = 0; y < 40; y++) {
+ pathNodes[x][y].bBlockade = false;
+ pathNodes[x][y].id = INT16_MAX;
+ pathNodes[x][y].nodeIdX = x;
+ pathNodes[x][y].nodeIdY = y;
+ }
+ }
+ CWorld::AdvanceCurrentScanCode();
+ if (pathType != ROUTE_NO_BLOCKADE) {
+ const int32 nStartX = max(CWorld::GetSectorIndexX(vecSectorStartPos.x), 0);
+ const int32 nStartY = max(CWorld::GetSectorIndexY(vecSectorStartPos.y), 0);
+ const int32 nEndX = min(CWorld::GetSectorIndexX(vecSectorEndPos.x), NUMSECTORS_X - 1);
+ const int32 nEndY = min(CWorld::GetSectorIndexY(vecSectorEndPos.y), NUMSECTORS_Y - 1);
+ for (int32 y = nStartY; y <= nEndY; y++) {
+ for (int32 x = nStartX; x <= nEndX; x++) {
+ CSector *pSector = CWorld::GetSector(x, y);
+ AddBlockadeSectorList(pSector->m_lists[ENTITYLIST_VEHICLES], pathNodes, &vecSectorStartPos);
+ AddBlockadeSectorList(pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], pathNodes, &vecSectorStartPos);
+ AddBlockadeSectorList(pSector->m_lists[ENTITYLIST_OBJECTS], pathNodes, &vecSectorStartPos);
+ AddBlockadeSectorList(pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], pathNodes, &vecSectorStartPos);
+ }
+ }
+ }
+ for (int32 i = 0; i < 416; i++) {
+ pathNodesList[i].prev = nil;
+ pathNodesList[i].next = nil;
+ }
+ CPedPathNode *pStartPathNode = &pathNodes[nodeStartX][nodeStartY];
+ CPedPathNode *pEndPathNode = &pathNodes[nodeEndX][nodeEndY];
+ pEndPathNode->bBlockade = false;
+ pEndPathNode->id = 0;
+ pEndPathNode->prev = nil;
+ pEndPathNode->next = pathNodesList;
+ pathNodesList[0].prev = pEndPathNode;
+ int32 pathNodeIndex = 0;
+ CPedPathNode *pPreviousNode = nil;
+ for (; pathNodeIndex < 414; pathNodeIndex++)
+ {
+ pPreviousNode = pathNodesList[pathNodeIndex].prev;
+ while (pPreviousNode && pPreviousNode != pStartPathNode) {
+ const uint8 nodeIdX = pPreviousNode->nodeIdX;
+ const uint8 nodeIdY = pPreviousNode->nodeIdY;
+ if (nodeIdX > 0) {
+ AddNodeToPathList(&pathNodes[nodeIdX - 1][nodeIdY], pathNodeIndex + 5, pathNodesList);
+ if (nodeIdY > 0)
+ AddNodeToPathList(&pathNodes[nodeIdX - 1][nodeIdY - 1], pathNodeIndex + 7, pathNodesList);
+ if (nodeIdY < 39)
+ AddNodeToPathList(&pathNodes[nodeIdX - 1][nodeIdY + 1], pathNodeIndex + 7, pathNodesList);
+ }
+ if (nodeIdX < 39) {
+ AddNodeToPathList(&pathNodes[nodeIdX + 1][nodeIdY], pathNodeIndex + 5, pathNodesList);
+ if (nodeIdY > 0)
+ AddNodeToPathList(&pathNodes[nodeIdX + 1][nodeIdY - 1], pathNodeIndex + 7, pathNodesList);
+ if (nodeIdY < 39)
+ AddNodeToPathList(&pathNodes[nodeIdX + 1][nodeIdY + 1], pathNodeIndex + 7, pathNodesList);
+ }
+ if (nodeIdY > 0)
+ AddNodeToPathList(&pathNodes[nodeIdX][nodeIdY - 1], pathNodeIndex + 5, pathNodesList);
+ if (nodeIdY < 39)
+ AddNodeToPathList(&pathNodes[nodeIdX][nodeIdY + 1], pathNodeIndex + 5, pathNodesList);
+ pPreviousNode = pPreviousNode->prev;
+ if (!pPreviousNode)
+ break;
+ }
+
+ if (pPreviousNode && pPreviousNode == pStartPathNode)
+ break;
+ }
+ if (pathNodeIndex == 414)
+ return false;
+ CPedPathNode *pPathNode = pStartPathNode;
+ for (*pointsFound = 0; pPathNode != pEndPathNode && *pointsFound < maxPoints; ++ *pointsFound) {
+ const uint8 nodeIdX = pPathNode->nodeIdX;
+ const uint8 nodeIdY = pPathNode->nodeIdY;
+ if (nodeIdX > 0 && pathNodes[nodeIdX - 1][nodeIdY].id + 5 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX - 1][nodeIdY];
+ else if (nodeIdX > 39 && pathNodes[nodeIdX + 1][nodeIdY].id + 5 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX + 1][nodeIdY];
+ else if (nodeIdY > 0 && pathNodes[nodeIdX][nodeIdY - 1].id + 5 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX][nodeIdY - 1];
+ else if (nodeIdY > 39 && pathNodes[nodeIdX][nodeIdY + 1].id + 5 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX][nodeIdY + 1];
+ else if (nodeIdX > 0 && nodeIdY > 0 && pathNodes[nodeIdX - 1][nodeIdY - 1].id + 7 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX - 1][nodeIdY - 1];
+ else if (nodeIdX > 0 && nodeIdY < 39 && pathNodes[nodeIdX - 1][nodeIdY + 1].id + 7 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX - 1][nodeIdY + 1];
+ else if (nodeIdX < 39 && nodeIdY > 0 && pathNodes[nodeIdX + 1][nodeIdY - 1].id + 7 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX + 1][nodeIdY - 1];
+ else if (nodeIdX < 39 && nodeIdY < 39 && pathNodes[nodeIdX + 1][nodeIdY + 1].id + 7 == pPathNode->id)
+ pPathNode = &pathNodes[nodeIdX + 1][nodeIdY + 1];
+ pointPoses[*pointsFound] = vecSectorStartPos;
+ pointPoses[*pointsFound].x += pPathNode->nodeIdX * 0.7f;
+ pointPoses[*pointsFound].y += pPathNode->nodeIdY * 0.7f;
+ }
+ return true;
+}
+
+
+void
+CPedPath::AddNodeToPathList(CPedPathNode *pNodeToAdd, int16 id, CPedPathNode *pNodeList)
+{
+ if (!pNodeToAdd->bBlockade && id < pNodeToAdd->id) {
+ if (pNodeToAdd->id != INT16_MAX)
+ RemoveNodeFromList(pNodeToAdd);
+ AddNodeToList(pNodeToAdd, id, pNodeList);
+ }
+}
+
+void
+CPedPath::RemoveNodeFromList(CPedPathNode *pNode)
+{
+ pNode->next->prev = pNode->prev;
+ if (pNode->prev)
+ pNode->prev->next = pNode->next;
+}
+
+void
+CPedPath::AddNodeToList(CPedPathNode *pNode, int16 index, CPedPathNode *pList)
+{
+ pNode->prev = pList[index].prev;
+ pNode->next = &pList[index];
+ if (pList[index].prev)
+ pList[index].prev->next = pNode;
+ pList[index].prev = pNode;
+ pNode->id = index;
+}
+
+void
+CPedPath::AddBlockadeSectorList(CPtrList& list, CPedPathNode(*pathNodes)[40], CVector *pPosition)
+{
+ CPtrNode* listNode = list.first;
+ while (listNode) {
+ CEntity* pEntity = (CEntity*)listNode->item;
+ if (pEntity->m_scanCode != CWorld::GetCurrentScanCode() && pEntity->bUsesCollision) {
+ pEntity->m_scanCode = CWorld::GetCurrentScanCode();
+ AddBlockade(pEntity, pathNodes, pPosition);
+ }
+ listNode = listNode->next;
+ }
+}
+
+void
+CPedPath::AddBlockade(CEntity *pEntity, CPedPathNode(*pathNodes)[40], CVector *pPosition)
+{
+ const CColBox& boundingBox = pEntity->GetColModel()->boundingBox;
+ const float fBoundMaxY = boundingBox.max.y + 0.3f;
+ const float fBoundMinY = boundingBox.min.y - 0.3f;
+ const float fBoundMaxX = boundingBox.max.x + 0.3f;
+ const float fDistanceX = pPosition->x - pEntity->m_matrix.GetPosition().x;
+ const float fDistanceY = pPosition->y - pEntity->m_matrix.GetPosition().y;
+ const float fBoundRadius = pEntity->GetBoundRadius();
+ CVector vecBoundCentre;
+ pEntity->GetBoundCentre(vecBoundCentre);
+ if (vecBoundCentre.x + fBoundRadius >= pPosition->x &&
+ vecBoundCentre.y + fBoundRadius >= pPosition->y &&
+ vecBoundCentre.x - fBoundRadius <= pPosition->x + 28.0f &&
+ vecBoundCentre.y - fBoundRadius <= pPosition->y + 28.0f) {
+ for (int16 x = 0; x < 40; x++) {
+ const float pointX = x * 0.7f + fDistanceX;
+ for (int16 y = 0; y < 40; y++) {
+ if (!pathNodes[x][y].bBlockade) {
+ const float pointY = y * 0.7f + fDistanceY;
+ CVector2D point(pointX, pointY);
+ if (fBoundMaxX > Abs(DotProduct2D(point, pEntity->m_matrix.GetRight()))) {
+ float fDotProduct = DotProduct2D(point, pEntity->m_matrix.GetForward());
+ if (fBoundMaxY > fDotProduct && fBoundMinY < fDotProduct)
+ pathNodes[x][y].bBlockade = true;
+ }
+ }
+ }
+ }
+ }
+}
+
void
CPathFind::Init(void)
{
@@ -1576,6 +1768,13 @@ CPathFind::DisplayPathData(void)
}
STARTPATCHES
+ InjectHook(0x42E680, &CPedPath::CalcPedRoute, PATCH_JUMP);
+ InjectHook(0x42F100, &CPedPath::AddNodeToPathList, PATCH_JUMP);
+ InjectHook(0x42F140, &CPedPath::RemoveNodeFromList, PATCH_JUMP);
+ InjectHook(0x42F160, &CPedPath::AddNodeToList, PATCH_JUMP);
+ InjectHook(0x42F1A0, &CPedPath::AddBlockade, PATCH_JUMP);
+ InjectHook(0x42F420, &CPedPath::AddBlockadeSectorList, PATCH_JUMP);
+
InjectHook(0x4294A0, &CPathFind::Init, PATCH_JUMP);
InjectHook(0x42D580, &CPathFind::AllocatePathFindInfoMem, PATCH_JUMP);
InjectHook(0x429540, &CPathFind::RegisterMapObject, PATCH_JUMP);
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index 81467cdf..ea88ade6 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -3,11 +3,7 @@
#include "Treadable.h"
class CVehicle;
-
-class CPedPath {
-public:
- static bool CalcPedRoute(uint8, CVector, CVector, CVector*, int16*, int16);
-};
+class CPtrList;
enum
{
@@ -30,6 +26,33 @@ enum
SWITCH_ON = 1,
};
+enum
+{
+ ROUTE_ADD_BLOCKADE = 0,
+ ROUTE_NO_BLOCKADE = 1
+};
+
+struct CPedPathNode
+{
+ bool bBlockade;
+ uint8 nodeIdX;
+ uint8 nodeIdY;
+ int16 id;
+ CPedPathNode* prev;
+ CPedPathNode* next;
+};
+static_assert(sizeof(CPedPathNode) == 0x10, "CPedPathNode: error");
+
+class CPedPath {
+public:
+ static bool CalcPedRoute(int8 pathType, CVector position, CVector destination, CVector *pointPoses, int16 *pointsFound, int16 maxPoints);
+ static void AddNodeToPathList(CPedPathNode *pNodeToAdd, int16 id, CPedPathNode *pNodeList);
+ static void RemoveNodeFromList(CPedPathNode *pNode);
+ static void AddNodeToList(CPedPathNode *pNode, int16 index, CPedPathNode *pList);
+ static void AddBlockade(CEntity *pEntity, CPedPathNode(*pathNodes)[40], CVector *pPosition);
+ static void AddBlockadeSectorList(CPtrList& list, CPedPathNode(*pathNodes)[40], CVector *pPosition);
+};
+
struct CPathNode
{
CVector pos;
diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp
index 3e55d431..8d804e4d 100644
--- a/src/control/SceneEdit.cpp
+++ b/src/control/SceneEdit.cpp
@@ -2,11 +2,1096 @@
#include "patcher.h"
#include "SceneEdit.h"
-bool &CSceneEdit::m_bEditOn = *(bool*)0x95CD77;
-int32 &CSceneEdit::m_bCameraFollowActor = *(int*)0x940590;
-bool &CSceneEdit::m_bRecording = *(bool*)0x95CD1F;
-CVector &CSceneEdit::m_vecCurrentPosition = *(CVector*)0x943064;
-CVector &CSceneEdit::m_vecCamHeading = *(CVector*)0x942F8C;
-
-WRAPPER void CSceneEdit::Update(void) { EAXJMP(0x585570); }
-WRAPPER void CSceneEdit::Init(void) { EAXJMP(0x585170); }
+#include "Automobile.h"
+#include "Camera.h"
+#include "CarCtrl.h"
+#include "CivilianPed.h"
+#include "FileMgr.h"
+#include "Font.h"
+#include "ModelIndices.h"
+#include "ModelInfo.h"
+#include "Pad.h"
+#include "Ped.h"
+#include "Population.h"
+#include "Text.h"
+#include "Timecycle.h"
+#include "Streaming.h"
+#include "Vehicle.h"
+#include "WeaponInfo.h"
+#include "World.h"
+
+bool CSceneEdit::m_bEditOn;
+int32 CSceneEdit::m_bCameraFollowActor;
+bool CSceneEdit::m_bRecording;
+CVector CSceneEdit::m_vecCurrentPosition;
+CVector CSceneEdit::m_vecCamHeading;
+CVector CSceneEdit::m_vecGotoPosition;
+int32 CSceneEdit::m_nVehicle;
+int32 CSceneEdit::m_nVehicle2;
+int32 CSceneEdit::m_nActor;
+int32 CSceneEdit::m_nActor2;
+int32 CSceneEdit::m_nVehiclemodelId;
+int32 CSceneEdit::m_nPedmodelId;
+int16 CSceneEdit::m_nCurrentMovieCommand;
+int16 CSceneEdit::m_nNumActors;
+int16 CSceneEdit::m_nNumMovieCommands;
+int16 CSceneEdit::m_nCurrentCommand;
+int16 CSceneEdit::m_nCurrentVehicle;
+int16 CSceneEdit::m_nCurrentActor;
+int16 CSceneEdit::m_nWeaponType;
+bool CSceneEdit::m_bCommandActive;
+bool CSceneEdit::m_bActorSelected;
+bool CSceneEdit::m_bActor2Selected;
+bool CSceneEdit::m_bVehicleSelected;
+int16 CSceneEdit::m_nNumVehicles;
+CPed* CSceneEdit::pActors[NUM_ACTORS_IN_MOVIE];
+CVehicle* CSceneEdit::pVehicles[NUM_VEHICLES_IN_MOVIE];
+bool CSceneEdit::m_bDrawGotoArrow;
+CMovieCommand CSceneEdit::Movie[NUM_COMMANDS_IN_MOVIE];
+
+#define SHADOW_OFFSET (2.0f)
+#define ACTION_MESSAGE_X_RIGHT (60.0f)
+#define ACTION_MESSAGE_Y (8.0f)
+#define SELECTED_MESSAGE_X_RIGHT (60.0f)
+#define SELECTED_MESSAGE_Y (248.0f)
+#define COMMAND_NAME_X_RIGHT (60.0f)
+#define COMMAND_NAME_Y (38.0f)
+#define COMMAND_NAME_HEIGHT (16.0f)
+
+#define NUM_COMMANDS_TO_DRAW (9)
+
+static const char* pCommandStrings[] = {
+ "do-nothing", "New Actor", "Move Actor", "Select Actor", "Delete Actor",
+ "New Vehicle", "Move Vehicle", "Select Vehicle", "Delete Vehicle", "Give Weapon",
+ "Goto", "Goto (wait)", "Get In Car", "Get Out Car", "Kill",
+ "Flee", "Wait", "Position Camera", "Set Camera Target", "Select Camera Mode",
+ "Save Movie", "Load Movie", "Play Movie", "END"
+};
+
+static_assert(ARRAY_SIZE(pCommandStrings) == CSceneEdit::MOVIE_TOTAL_COMMANDS, "Scene edit: not all commands have names");
+
+static int32 NextValidModelId(int32 mi, int32 step)
+{
+ int32 result = -1;
+ int32 i = mi;
+ while (result == -1) {
+ i += step;
+ if (i < 0 || i > 5500) {
+ step = -step;
+ continue;
+ }
+ CBaseModelInfo* pInfo = CModelInfo::GetModelInfo(i);
+ CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)pInfo;
+ if (!pInfo)
+ continue;
+ if (pInfo->m_type == MITYPE_PED
+#ifdef FIX_BUGS
+ && !(i >= MI_SPECIAL01 && i <= MI_SPECIAL04)
+#endif
+ ||
+ pInfo->m_type == MITYPE_VEHICLE &&
+#ifdef FIX_BUGS
+ (pVehicleInfo->m_vehicleType == VEHICLE_TYPE_CAR || pVehicleInfo->m_vehicleType == VEHICLE_TYPE_BOAT))
+#else // && and || priority failure it seems, also crashes on special models
+ pVehicleInfo->m_vehicleType == VEHICLE_TYPE_CAR || pVehicleInfo->m_vehicleType == VEHICLE_TYPE_BOAT)
+#endif
+ result = i;
+ }
+ return result;
+}
+
+void CSceneEdit::LoadMovie(void)
+{
+ ReInitialise();
+ CFileMgr::SetDir("DATA");
+ int fid = CFileMgr::OpenFile("movie.dat", "r");
+#ifdef FIX_BUGS
+ if (fid >= 0)
+#endif
+ {
+ CFileMgr::Read(fid, (char*)&Movie, sizeof(Movie));
+ CFileMgr::Read(fid, (char*)&m_nNumMovieCommands, sizeof(m_nNumMovieCommands));
+ CFileMgr::CloseFile(fid);
+ }
+ CFileMgr::SetDir("");
+ m_bCommandActive = false;
+}
+
+void CSceneEdit::SaveMovie(void)
+{
+ CFileMgr::SetDir("DATA");
+ int fid = CFileMgr::OpenFileForWriting("movie.dat");
+ if (fid >= 0) {
+ CFileMgr::Write(fid, (char*)&Movie, sizeof(Movie));
+ CFileMgr::Write(fid, (char*)&m_nNumMovieCommands, sizeof(m_nNumMovieCommands));
+ CFileMgr::CloseFile(fid);
+ }
+ CFileMgr::SetDir("");
+ m_bCommandActive = false;
+}
+
+void CSceneEdit::Initialise(void)
+{
+ m_nActor = -1;
+ m_nActor2 = -1;
+ m_nVehicle = -1;
+ m_nVehicle2 = -1;
+ m_nCurrentCommand = MOVIE_NEW_ACTOR;
+ m_nVehiclemodelId = MI_INFERNUS;
+ m_nPedmodelId = MI_MALE01;
+ m_nNumVehicles = 0;
+ m_nNumActors = 0;
+ m_nNumMovieCommands = 0;
+ m_bCommandActive = false;
+ m_bRecording = true;
+ m_bEditOn = false;
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++)
+ pActors[i] = nil;
+ for (int i = 0; i < NUM_VEHICLES_IN_MOVIE; i++)
+ pVehicles[i] = nil;
+ m_vecCamHeading = TheCamera.Cams[TheCamera.ActiveCam].Front;
+ m_vecGotoPosition = CVector(0.0f, 0.0f, 0.0f);
+ m_bCameraFollowActor = false;
+ TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true;
+ m_bDrawGotoArrow = false;
+}
+
+void CSceneEdit::InitPlayback(void)
+{
+ m_nVehiclemodelId = MI_INFERNUS;
+ m_nPedmodelId = MI_MALE01;
+ m_bCommandActive = false;
+ m_nNumActors = 0;
+ m_nNumVehicles = 0;
+ m_nActor = -1;
+ m_nActor2 = -1;
+ m_nVehicle = -1;
+ m_nVehicle2 = -1;
+ TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true;
+ m_vecCamHeading = TheCamera.Cams[TheCamera.ActiveCam].Front;
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++) {
+ if (pActors[i]) {
+ CPopulation::RemovePed(pActors[i]);
+ pActors[i] = nil;
+ }
+ }
+ m_nCurrentActor = 0;
+ for (int i = 0; i < NUM_VEHICLES_IN_MOVIE; i++) {
+ if (pVehicles[i]) {
+ CWorld::Remove(pVehicles[i]);
+ delete pVehicles[i];
+ pVehicles[i] = nil;
+ }
+ }
+ m_nCurrentVehicle = 0;
+ m_vecGotoPosition = CVector(0.0f, 0.0f, 0.0f);
+ m_nCurrentMovieCommand = MOVIE_DO_NOTHING;
+ m_bDrawGotoArrow = false;
+}
+
+void CSceneEdit::ReInitialise(void)
+{
+ m_nVehiclemodelId = MI_INFERNUS;
+ m_nPedmodelId = MI_MALE01;
+ m_nCurrentCommand = MOVIE_NEW_ACTOR;
+ m_bEditOn = true;
+ m_bRecording = true;
+ m_bCommandActive = false;
+#ifdef FIX_BUGS
+ m_bCameraFollowActor = false;
+ TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true; // not enough...
+#endif
+ m_nActor = -1;
+ m_nActor2 = -1;
+ m_nVehicle = -1;
+ m_nVehicle2 = -1;
+ m_nNumMovieCommands = 0;
+ m_nCurrentMovieCommand = MOVIE_DO_NOTHING;
+ m_nNumActors = 0;
+ m_nNumVehicles = 0;
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++) {
+ if (pActors[i]) {
+ CPopulation::RemovePed(pActors[i]);
+ pActors[i] = nil;
+ }
+ }
+ for (int i = 0; i < NUM_VEHICLES_IN_MOVIE; i++) {
+ if (pVehicles[i]) {
+ CWorld::Remove(pVehicles[i]);
+ delete pVehicles[i];
+ pVehicles[i] = nil;
+ }
+ }
+ for (int i = 0; i < NUM_COMMANDS_IN_MOVIE; i++) {
+ Movie[i].m_nCommandId = MOVIE_DO_NOTHING;
+ Movie[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f);
+ Movie[i].m_vecCamera = CVector(0.0f, 0.0f, 0.0f);
+ Movie[i].m_nActorId = -1;
+ Movie[i].m_nActor2Id = -1;
+ Movie[i].m_nVehicleId = -1;
+ Movie[i].m_nModelIndex = 0;
+ }
+ m_vecGotoPosition = CVector(0.0f, 0.0f, 0.0f);
+ m_bDrawGotoArrow = false;
+}
+
+void CSceneEdit::Update(void)
+{
+ if (!m_bEditOn)
+ return;
+ if (m_bRecording)
+ ProcessCommand();
+ else {
+ if (m_bCameraFollowActor && m_nActor != -1) {
+ if (pActors[m_nActor]->bInVehicle)
+ TheCamera.TakeControl(pActors[m_nActor]->m_pMyVehicle, CCam::MODE_BEHINDCAR, JUMP_CUT, CAMCONTROL_SCRIPT);
+ else
+ TheCamera.TakeControl(pActors[m_nActor], CCam::MODE_FOLLOWPED, JUMP_CUT, CAMCONTROL_SCRIPT);
+ }
+ PlayBack();
+ }
+}
+
+void CSceneEdit::Draw(void)
+{
+ char str[200];
+ wchar wstr[200];
+ if (TheCamera.m_WideScreenOn)
+ return;
+#ifndef FIX_BUGS
+ CFont::SetPropOff();
+#endif
+ CFont::SetBackgroundOff();
+ CFont::SetScale(SCREEN_SCALE_X(0.8f), SCREEN_SCALE_Y(1.35f));
+ CFont::SetCentreOn();
+ CFont::SetRightJustifyOn();
+ CFont::SetRightJustifyWrap(0.0f);
+ CFont::SetBackGroundOnlyTextOff();
+#ifdef FIX_BUGS
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetPropOn();
+ CFont::SetDropColor(CRGBA(0, 0, 0, 255));
+ CFont::SetDropShadowPosition(1);
+#else
+ CFont::SetFontStyle(FONT_HEADING);
+ CFont::SetPropOff();
+#endif
+ sprintf(str, "Action");
+ AsciiToUnicode(str, wstr);
+ CFont::SetColor(CRGBA(0, 0, 0, 0));
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(ACTION_MESSAGE_X_RIGHT - SHADOW_OFFSET), SCREEN_SCALE_Y(ACTION_MESSAGE_Y + SHADOW_OFFSET), wstr);
+ CFont::SetColor(CRGBA(193, 164, 120, 255));
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(ACTION_MESSAGE_X_RIGHT), SCREEN_SCALE_Y(ACTION_MESSAGE_Y), wstr);
+ sprintf(str, "Selected");
+ AsciiToUnicode(str, wstr);
+ CFont::SetColor(CRGBA(0, 0, 0, 0));
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(SELECTED_MESSAGE_X_RIGHT - SHADOW_OFFSET), SCREEN_SCALE_Y(SELECTED_MESSAGE_Y + SHADOW_OFFSET), wstr);
+ CFont::SetColor(CRGBA(193, 164, 120, 255));
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(SELECTED_MESSAGE_X_RIGHT), SCREEN_SCALE_Y(SELECTED_MESSAGE_Y), wstr);
+ CFont::SetCentreOff();
+ CFont::SetScale(SCREEN_SCALE_X(0.7f), SCREEN_SCALE_Y(0.7f));
+#ifdef FIX_BUGS
+ CFont::SetFontStyle(FONT_BANK);
+#else
+ CFont::SetFontStyle(FONT_HEADING);
+#endif
+ CFont::SetColor(CRGBA(0, 0, 0, 0));
+ for (int i = 0; i < NUM_COMMANDS_TO_DRAW; i++) {
+ int16 nCommandDrawn = m_nCurrentCommand + i - NUM_COMMANDS_TO_DRAW / 2;
+ if (nCommandDrawn >= MOVIE_TOTAL_COMMANDS)
+ nCommandDrawn -= (MOVIE_TOTAL_COMMANDS - 1);
+ if (nCommandDrawn <= MOVIE_DO_NOTHING)
+ nCommandDrawn += (MOVIE_TOTAL_COMMANDS - 1);
+ sprintf(str, pCommandStrings[nCommandDrawn]);
+ AsciiToUnicode(str, wstr);
+ CFont::SetColor(CRGBA(0, 0, 0, 0));
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(COMMAND_NAME_X_RIGHT - SHADOW_OFFSET), SCREEN_SCALE_Y(COMMAND_NAME_Y + SHADOW_OFFSET + i * COMMAND_NAME_HEIGHT), wstr);
+ if (nCommandDrawn == m_nCurrentCommand)
+ CFont::SetColor(CRGBA(156, 91, 40, 255));
+ else
+ CFont::SetColor(CRGBA(193, 164, 120, 255));
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(COMMAND_NAME_X_RIGHT), SCREEN_SCALE_Y(COMMAND_NAME_Y + i * COMMAND_NAME_HEIGHT), wstr);
+ }
+}
+
+void CSceneEdit::ProcessCommand(void)
+{
+ if (!m_bCommandActive) {
+ ClearForNewCommand();
+ if (CPad::GetPad(1)->GetDPadUpJustDown()) {
+ if (--m_nCurrentCommand == MOVIE_DO_NOTHING)
+ m_nCurrentCommand = MOVIE_END;
+ }
+ if (CPad::GetPad(1)->GetDPadDownJustDown()) {
+ if (++m_nCurrentCommand == MOVIE_TOTAL_COMMANDS)
+ m_nCurrentCommand = MOVIE_NEW_ACTOR;
+ }
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ if (m_nCurrentCommand != MOVIE_DO_NOTHING)
+ m_bCommandActive = true;
+ }
+ return;
+ }
+ switch (m_nCurrentCommand) {
+ case MOVIE_DO_NOTHING:
+ m_bCommandActive = false;
+ break;
+ case MOVIE_NEW_ACTOR:
+ if (m_nActor == -1) {
+ if (m_nNumActors == NUM_ACTORS_IN_MOVIE)
+ break;
+ if (!CStreaming::HasModelLoaded(m_nPedmodelId)) {
+ CStreaming::RequestModel(m_nPedmodelId, 0);
+#ifdef FIX_BUGS
+ CStreaming::LoadAllRequestedModels(false); // otherwise gets stuck :(
+#endif
+ break;
+ }
+ CPed* pPed = new CCivilianPed(PEDTYPE_SPECIAL, m_nPedmodelId);
+ pPed->CharCreatedBy = MISSION_CHAR;
+ pPed->GetPosition() = m_vecCurrentPosition;
+ pPed->SetOrientation(0.0f, 0.0f, 0.0f);
+ CWorld::Add(pPed);
+ pPed->bUsesCollision = false;
+ pPed->bAffectedByGravity = false;
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++) {
+ if (pActors[i] == nil) {
+ m_nActor = i;
+ pActors[i] = pPed;
+ break;
+ }
+ }
+ }
+ else {
+ pActors[m_nActor]->GetPosition() = m_vecCurrentPosition;
+ pActors[m_nActor]->SetOrientation(0.0f, 0.0f, 0.0f);
+ int32 mi = m_nPedmodelId;
+ if (CPad::GetPad(1)->GetLeftShoulder1JustDown())
+ mi = NextValidModelId(m_nPedmodelId, -1);
+ else if (CPad::GetPad(1)->GetRightShoulder1JustDown())
+ mi = NextValidModelId(m_nPedmodelId, 1);
+ if (mi == m_nPedmodelId) {
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ pActors[m_nActor]->bUsesCollision = true;
+ pActors[m_nActor]->bAffectedByGravity = true;
+ ++m_nNumActors;
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_NEW_ACTOR;
+ Movie[m_nNumMovieCommands].m_vecPosition = m_vecCurrentPosition;
+ Movie[m_nNumMovieCommands].m_nModelIndex = m_nPedmodelId;
+ Movie[m_nNumMovieCommands++].m_nActorId = m_nActor;
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ CWorld::Remove(pActors[m_nActor]);
+ delete pActors[m_nActor];
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ }
+ else {
+ m_nPedmodelId = mi;
+ if (pActors[m_nActor]) {
+ CWorld::Remove(pActors[m_nActor]);
+ delete pActors[m_nActor];
+ }
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ }
+ }
+ break;
+ case MOVIE_MOVE_ACTOR:
+ SelectActor();
+ if (m_bCommandActive)
+ break;
+ pActors[m_nActor]->GetPosition() = m_vecCurrentPosition;
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ m_bCommandActive = false;
+#ifndef FIX_BUGS // why? it crashes, also makes no sense
+ pActors[m_nActor] = nil;
+#endif
+ SelectActor();
+ }
+ break;
+ case MOVIE_SELECT_ACTOR:
+ SelectActor();
+ break;
+ case MOVIE_DELETE_ACTOR:
+ SelectActor();
+ if (m_bActorSelected) {
+ CPopulation::RemovePed(pActors[m_nActor]);
+ m_nCurrentActor = 0;
+ --m_nNumActors;
+#ifdef FIX_BUGS
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+#else
+ m_nActor = -1;
+ pActors[m_nActor] = nil;
+#endif
+ SelectActor();
+ m_bCommandActive = false;
+ }
+ else if (CPad::GetPad(1)->GetCircleJustDown()) {
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_NEW_VEHICLE:
+ if (m_nVehicle == -1) {
+ if (m_nNumVehicles == NUM_VEHICLES_IN_MOVIE)
+ break;
+ if (!CStreaming::HasModelLoaded(m_nVehiclemodelId)) {
+ CStreaming::RequestModel(m_nVehiclemodelId, 0);
+#ifdef FIX_BUGS
+ CStreaming::LoadAllRequestedModels(false); // otherwise gets stuck :(
+#endif
+ break;
+ }
+ CVehicle* pVehicle = new CAutomobile(m_nVehiclemodelId, MISSION_VEHICLE);
+ pVehicle->m_status = STATUS_PHYSICS;
+ pVehicle->GetPosition() = m_vecCurrentPosition;
+ pVehicle->SetOrientation(0.0f, 0.0f, 0.0f);
+ CWorld::Add(pVehicle);
+ pVehicle->bUsesCollision = false;
+ pVehicle->bAffectedByGravity = false;
+ for (int i = 0; i < NUM_VEHICLES_IN_MOVIE; i++) {
+ if (pVehicles[i] == nil) {
+ m_nVehicle = i;
+ pVehicles[i] = pVehicle;
+ break;
+ }
+ }
+ }
+ else {
+ pVehicles[m_nVehicle]->GetPosition() = m_vecCurrentPosition;
+ pVehicles[m_nVehicle]->SetOrientation(0.0f, 0.0f, 0.0f);
+ int32 mi = m_nVehiclemodelId;
+ if (CPad::GetPad(1)->GetLeftShoulder1JustDown())
+ mi = NextValidModelId(m_nVehiclemodelId, -1);
+ else if (CPad::GetPad(1)->GetRightShoulder1JustDown())
+ mi = NextValidModelId(m_nVehiclemodelId, 1);
+ if (mi == m_nVehiclemodelId) {
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ pVehicles[m_nVehicle]->bUsesCollision = true;
+ pVehicles[m_nVehicle]->bAffectedByGravity = true;
+ ++m_nNumVehicles;
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_NEW_VEHICLE;
+ Movie[m_nNumMovieCommands].m_vecPosition = m_vecCurrentPosition;
+ Movie[m_nNumMovieCommands].m_nModelIndex = m_nVehiclemodelId;
+ Movie[m_nNumMovieCommands++].m_nVehicleId = m_nVehicle;
+ m_nVehicle = -1;
+ m_bCommandActive = false;
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ CWorld::Remove(pVehicles[m_nVehicle]);
+ delete pVehicles[m_nVehicle];
+ pVehicles[m_nVehicle] = nil;
+ m_nVehicle = -1;
+ m_bCommandActive = false;
+ }
+ }
+ else {
+ m_nVehiclemodelId = mi;
+ if (pVehicles[m_nVehicle]) {
+ CWorld::Remove(pVehicles[m_nVehicle]);
+ delete pVehicles[m_nVehicle];
+ }
+ pVehicles[m_nVehicle] = nil;
+ m_nVehicle = -1;
+ }
+ }
+ break;
+ case MOVIE_MOVE_VEHICLE:
+ SelectVehicle();
+ if (m_bCommandActive)
+ break;
+ pVehicles[m_nVehicle]->GetPosition() = m_vecCurrentPosition;
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ m_bCommandActive = false;
+#ifndef FIX_BUGS // again, why? works wrong
+ pVehicles[m_nVehicle] = nil;
+#endif
+ m_nVehicle = -1;
+ }
+ break;
+ case MOVIE_SELECT_VEHICLE:
+ SelectVehicle();
+ break;
+ case MOVIE_DELETE_VEHICLE:
+ SelectVehicle();
+ if (m_bVehicleSelected) {
+ CWorld::Remove(pVehicles[m_nVehicle]);
+ delete pVehicles[m_nVehicle];
+ m_nCurrentVehicle = 0;
+ --m_nNumVehicles;
+ pVehicles[m_nVehicle] = nil;
+ m_nVehicle = -1;
+ SelectVehicle();
+ m_bCommandActive = false;
+ }
+ else if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pVehicles[m_nVehicle] = nil;
+ m_nVehicle = -1;
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_GIVE_WEAPON:
+ if (m_bActorSelected) {
+ if (SelectWeapon()) {
+ m_bCommandActive = false;
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_GIVE_WEAPON;
+ Movie[m_nNumMovieCommands].m_nActorId = m_nActor;
+ Movie[m_nNumMovieCommands++].m_nModelIndex = m_nWeaponType;
+ }
+ }
+ else {
+ SelectActor();
+ m_bCommandActive = true;
+ }
+ break;
+ case MOVIE_GOTO:
+ case MOVIE_GOTO_WAIT:
+ if (!m_bActorSelected) {
+ m_bDrawGotoArrow = true;
+ SelectActor();
+ if (m_nActor == -1)
+ m_bCommandActive = true;
+ }
+ else {
+ m_vecGotoPosition = m_vecCurrentPosition;
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ if (pActors[m_nActor]->bInVehicle) {
+ if (CCarCtrl::JoinCarWithRoadSystemGotoCoors(pActors[m_nActor]->m_pMyVehicle, m_vecGotoPosition, false))
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT;
+ else
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS;
+ pActors[m_nActor]->m_pMyVehicle->m_status = STATUS_PHYSICS;
+ pActors[m_nActor]->m_pMyVehicle->bEngineOn = true;
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCruiseSpeed = max(16, pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCruiseSpeed);
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds();
+ TheCamera.TakeControl(pActors[m_nActor]->m_pMyVehicle, CCam::MODE_BEHINDCAR, JUMP_CUT, CAMCONTROL_SCRIPT);
+ }
+ else {
+ pActors[m_nActor]->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, m_vecGotoPosition);
+ TheCamera.TakeControl(pActors[m_nActor], CCam::MODE_FOLLOWPED, JUMP_CUT, CAMCONTROL_SCRIPT);
+ }
+ m_bDrawGotoArrow = false;
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_GOTO;
+ Movie[m_nNumMovieCommands].m_nActorId = m_nActor;
+ Movie[m_nNumMovieCommands++].m_vecPosition = m_vecGotoPosition;
+ }
+ if (!m_bDrawGotoArrow) {
+ if (pActors[m_nActor]->bInVehicle && pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_NONE ||
+ !pActors[m_nActor]->bInVehicle && pActors[m_nActor]->m_objective == OBJECTIVE_NONE) {
+ if (pActors[m_nActor]) // if there is something that requires this check the least, it's this one
+ m_vecCamHeading = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].Source;
+ m_bCommandActive = false;
+ TheCamera.Cams[TheCamera.ActiveCam].Mode = CCam::MODE_FIGHT_CAM_RUNABOUT;
+ m_vecCurrentPosition = pActors[m_nActor]->GetPosition();
+ pActors[m_nActor]->SetObjective(OBJECTIVE_NONE);
+ if (pActors[m_nActor]->bInVehicle)
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
+ }
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ }
+ break;
+ case MOVIE_GET_IN_CAR:
+ if (m_bActorSelected)
+ SelectVehicle();
+ else {
+ SelectActor();
+ if (m_nActor != -1)
+ m_bCommandActive = true;
+ }
+ if (m_bVehicleSelected) {
+ pActors[m_nActor]->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicles[m_nVehicle]);
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_GET_IN_CAR;
+ Movie[m_nNumMovieCommands].m_nActorId = m_nActor;
+ Movie[m_nNumMovieCommands++].m_nVehicleId = m_nVehicle;
+ m_nVehicle = -1;
+ m_bCommandActive = false;
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pVehicles[m_nVehicle] = nil;
+ m_nVehicle = -1;
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_GET_OUT_CAR:
+ SelectActor();
+ if (m_bActorSelected) {
+ if (pActors[m_nActor]->bInVehicle) {
+ pActors[m_nActor]->SetObjective(OBJECTIVE_LEAVE_VEHICLE);
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_GET_OUT_CAR;
+ Movie[m_nNumMovieCommands++].m_nActorId = m_nActor;
+ }
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pVehicles[m_nVehicle] = nil;
+ m_nVehicle = -1;
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_KILL:
+ if (!m_bActorSelected) {
+ SelectActor();
+ m_bCommandActive = true;
+ }
+ else if (!m_bActor2Selected) {
+ SelectActor2();
+ if (m_bActorSelected && m_bActor2Selected && m_nActor != -1 && m_nActor2 != -1 && m_nActor != m_nActor2) {
+ pActors[m_nActor]->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pActors[m_nActor2]);
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_KILL;
+ Movie[m_nNumMovieCommands].m_nActorId = m_nActor;
+ Movie[m_nNumMovieCommands++].m_nActor2Id = m_nActor2;
+ m_bCommandActive = false;
+ }
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ pActors[m_nActor2] = nil;
+ m_nActor2 = -1;
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_FLEE:
+ if (!m_bActorSelected) {
+ SelectActor();
+ m_bCommandActive = true;
+ }
+ else if (!m_bActor2Selected) {
+ SelectActor2();
+ if (m_bActorSelected && m_bActor2Selected && m_nActor != -1 && m_nActor2 != -1 && m_nActor != m_nActor2) {
+ pActors[m_nActor]->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pActors[m_nActor2]);
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_FLEE;
+ Movie[m_nNumMovieCommands].m_nActorId = m_nActor;
+ Movie[m_nNumMovieCommands++].m_nActor2Id = m_nActor2;
+ m_bCommandActive = false;
+ }
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ pActors[m_nActor2] = nil;
+ m_nActor2 = -1;
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_WAIT:
+ SelectActor();
+ if (m_bActorSelected) {
+ pActors[m_nActor]->SetObjective(OBJECTIVE_IDLE);
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_WAIT;
+ Movie[m_nNumMovieCommands++].m_nActorId = m_nActor;
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pActors[m_nActor] = nil;
+ m_nActor = -1;
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_POSITION_CAMERA:
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_POSITION_CAMERA;
+ Movie[m_nNumMovieCommands].m_vecPosition = TheCamera.Cams[TheCamera.ActiveCam].Source;
+ Movie[m_nNumMovieCommands++].m_vecCamera = m_vecCamHeading;
+ m_bCommandActive = false;
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ m_bCommandActive = false;
+ }
+ break;
+ case MOVIE_SET_CAMERA_TARGET:
+ if (!m_bActorSelected) {
+ SelectActor();
+ m_bCommandActive = true;
+ }
+ else {
+ TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity = pActors[m_nActor];
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ Movie[m_nNumMovieCommands].m_nCommandId = MOVIE_SET_CAMERA_TARGET;
+ Movie[m_nNumMovieCommands++].m_nActorId = m_nActor;
+ m_bCommandActive = false;
+ }
+ }
+ break;
+ case MOVIE_SELECT_CAMERA_MODE:
+ m_bCommandActive = false;
+ break;
+ case MOVIE_SAVE_MOVIE:
+ SaveMovie();
+ break;
+ case MOVIE_LOAD_MOVIE:
+ LoadMovie();
+ break;
+ case MOVIE_PLAY_MOVIE:
+ InitPlayback();
+ LoadMovie();
+ m_bRecording = false;
+ break;
+ case MOVIE_END:
+ m_bRecording = false;
+ break;
+ default:
+ assert(0);
+ }
+}
+
+void CSceneEdit::PlayBack(void)
+{
+ m_nCurrentCommand = Movie[m_nCurrentMovieCommand].m_nCommandId;
+ if (m_nCurrentMovieCommand >= m_nNumMovieCommands) {
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ m_nCurrentCommand = MOVIE_DO_NOTHING;
+ m_bRecording = true;
+ ReInitialise();
+ }
+ return;
+ }
+ switch (m_nCurrentCommand) {
+ case MOVIE_DO_NOTHING:
+ case MOVIE_MOVE_ACTOR:
+ case MOVIE_SELECT_ACTOR:
+ case MOVIE_DELETE_ACTOR:
+ case MOVIE_MOVE_VEHICLE:
+ case MOVIE_SELECT_VEHICLE:
+ case MOVIE_DELETE_VEHICLE:
+ break;
+ case MOVIE_NEW_ACTOR:
+ {
+ m_nPedmodelId = Movie[m_nCurrentMovieCommand].m_nModelIndex;
+ m_vecCurrentPosition = Movie[m_nCurrentMovieCommand].m_vecPosition;
+ if (!CStreaming::HasModelLoaded(m_nPedmodelId)) {
+ CStreaming::RequestModel(m_nPedmodelId, 0);
+#ifdef FIX_BUGS
+ CStreaming::LoadAllRequestedModels(false); // otherwise gets stuck :(
+#endif
+ break;
+ }
+ CPed* pPed = new CCivilianPed(PEDTYPE_SPECIAL, m_nPedmodelId);
+ pPed->CharCreatedBy = MISSION_CHAR;
+ CWorld::Add(pPed);
+ pPed->GetPosition() = m_vecCurrentPosition;
+ pPed->SetOrientation(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++) {
+ if (pActors[i] == nil) {
+ m_nActor = i;
+ pActors[i] = pPed;
+ break;
+ }
+ }
+ m_nNumActors++;
+ m_nCurrentMovieCommand++;
+ break;
+ }
+ case MOVIE_NEW_VEHICLE:
+ {
+ m_nVehiclemodelId = Movie[m_nCurrentMovieCommand].m_nModelIndex;
+ m_vecCurrentPosition = Movie[m_nCurrentMovieCommand].m_vecPosition;
+ if (!CStreaming::HasModelLoaded(m_nVehiclemodelId)) {
+ CStreaming::RequestModel(m_nVehiclemodelId, 0);
+#ifdef FIX_BUGS
+ CStreaming::LoadAllRequestedModels(false); // otherwise gets stuck :(
+#endif
+ break;
+ }
+ CVehicle* pVehicle = new CAutomobile(m_nVehiclemodelId, MISSION_VEHICLE);
+ pVehicle->m_status = STATUS_PHYSICS;
+ pVehicle->GetPosition() = m_vecCurrentPosition;
+ pVehicle->SetOrientation(0.0f, 0.0f, 0.0f);
+ CWorld::Add(pVehicle);
+ for (int i = 0; i < NUM_VEHICLES_IN_MOVIE; i++) {
+ if (pVehicles[i] == nil) {
+ m_nVehicle = i;
+ pVehicles[i] = pVehicle;
+ break;
+ }
+ }
+ m_nNumVehicles++;
+ m_nCurrentMovieCommand++;
+ break;
+ }
+ case MOVIE_GIVE_WEAPON:
+ m_nActor = Movie[m_nCurrentMovieCommand].m_nActorId;
+ m_nWeaponType = Movie[m_nCurrentMovieCommand].m_nModelIndex;
+ pActors[m_nActor]->GiveWeapon((eWeaponType)m_nWeaponType, 1000);
+ pActors[m_nActor]->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pActors[m_nActor]->GetWeapon()->m_eWeaponType)->m_nModelId);
+ pActors[m_nActor]->SetCurrentWeapon(m_nWeaponType);
+ m_nCurrentMovieCommand++;
+ break;
+ case MOVIE_GOTO:
+ case MOVIE_GOTO_WAIT:
+ m_nActor = Movie[m_nCurrentMovieCommand].m_nActorId;
+ m_vecGotoPosition = Movie[m_nCurrentMovieCommand].m_vecPosition;
+ if (pActors[m_nActor]->bInVehicle) {
+ if (pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission != MISSION_GOTOCOORDS &&
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission != MISSION_GOTOCOORDS_STRAIGHT) {
+ if ((pActors[m_nActor]->m_pMyVehicle->GetPosition() - m_vecGotoPosition).Magnitude() < 5.0f) {
+ if (CCarCtrl::JoinCarWithRoadSystemGotoCoors(pActors[m_nActor]->m_pMyVehicle, m_vecGotoPosition, false))
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT;
+ else
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS;
+ pActors[m_nActor]->m_pMyVehicle->m_status = STATUS_PHYSICS;
+ pActors[m_nActor]->m_pMyVehicle->bEngineOn = true;
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCruiseSpeed = max(16, pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nCruiseSpeed);
+ pActors[m_nActor]->m_pMyVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds();
+ if (m_nCurrentCommand != MOVIE_GOTO_WAIT)
+ ++m_nCurrentMovieCommand;
+ }
+ else
+ ++m_nCurrentMovieCommand;
+ }
+ }
+ else {
+ if (pActors[m_nActor]->m_objective != OBJECTIVE_GOTO_AREA_ON_FOOT) {
+ pActors[m_nActor]->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, m_vecGotoPosition);
+ ++m_nCurrentMovieCommand;
+ }
+ }
+ break;
+ case MOVIE_GET_IN_CAR:
+ m_nActor = Movie[m_nCurrentMovieCommand].m_nActorId;
+ if (!pActors[m_nActor]->bInVehicle){
+ m_nVehicle = Movie[m_nCurrentMovieCommand].m_nVehicleId;
+ pActors[m_nActor]->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicles[m_nVehicle]);
+ }
+ else
+ ++m_nCurrentMovieCommand;
+ break;
+ case MOVIE_GET_OUT_CAR:
+ m_nActor = Movie[m_nCurrentMovieCommand].m_nActorId;
+ if (pActors[m_nActor]->bInVehicle)
+ pActors[m_nActor]->SetObjective(OBJECTIVE_LEAVE_VEHICLE);
+ else
+ ++m_nCurrentMovieCommand;
+ break;
+ case MOVIE_KILL:
+ m_nActor = Movie[m_nCurrentMovieCommand].m_nActorId;
+ m_nActor2 = Movie[m_nCurrentMovieCommand].m_nActor2Id;
+ pActors[m_nActor]->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pActors[m_nActor2]);
+ if (pActors[m_nActor2]->GetPedState() == PED_DEAD)
+ ++m_nCurrentMovieCommand;
+ break;
+ case MOVIE_FLEE:
+ m_nActor = Movie[m_nCurrentMovieCommand].m_nActorId;
+ m_nActor2 = Movie[m_nCurrentMovieCommand].m_nActor2Id;
+ pActors[m_nActor]->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pActors[m_nActor2]);
+ ++m_nCurrentMovieCommand;
+ break;
+ case MOVIE_WAIT:
+ m_nActor = Movie[m_nCurrentMovieCommand].m_nActorId;
+ pActors[m_nActor]->SetObjective(OBJECTIVE_IDLE);
+ ++m_nCurrentMovieCommand;
+ break;
+ case MOVIE_POSITION_CAMERA:
+ TheCamera.Cams[TheCamera.ActiveCam].Source = Movie[m_nCurrentMovieCommand].m_vecPosition;
+ m_vecCamHeading = Movie[m_nCurrentMovieCommand].m_vecCamera;
+ TheCamera.Cams[TheCamera.ActiveCam].Front = m_vecCamHeading;
+ ++m_nCurrentMovieCommand;
+ break;
+ case MOVIE_SET_CAMERA_TARGET:
+ m_bCameraFollowActor = true;
+ TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity = pActors[Movie[m_nNumMovieCommands].m_nActorId];
+ TheCamera.pTargetEntity = pActors[Movie[m_nNumMovieCommands].m_nActorId];
+ TheCamera.m_bLookingAtPlayer = false;
+ ++m_nCurrentMovieCommand;
+ break;
+ case MOVIE_SELECT_CAMERA_MODE:
+ m_bCommandActive = false; // this is wrong
+ break;
+ }
+}
+
+void CSceneEdit::ClearForNewCommand(void)
+{
+ m_nActor = -1;
+ m_nActor2 = -1;
+ m_nVehicle = -1;
+ m_bActorSelected = false;
+ m_bActor2Selected = false;
+ m_bVehicleSelected = false;
+ m_bDrawGotoArrow = false;
+}
+void CSceneEdit::SelectActor(void)
+{
+ m_bActorSelected = false;
+ if (m_nActor != -1) {
+ if (CPad::GetPad(1)->GetLeftShoulder1JustDown()) {
+ CPed* pPed;
+ do {
+ if (--m_nActor < 0)
+ m_nActor = NUM_ACTORS_IN_MOVIE - 1;
+ pPed = pActors[m_nActor];
+ } while (pPed == nil);
+ TheCamera.Cams[TheCamera.ActiveCam].Source = pPed->GetPosition() - m_vecCamHeading;
+ }
+ else if (CPad::GetPad(1)->GetRightShoulder1JustDown()) {
+ CPed* pPed;
+ do {
+ if (++m_nActor == NUM_ACTORS_IN_MOVIE)
+ m_nActor = 0;
+ pPed = pActors[m_nActor];
+ } while (pPed == nil);
+ TheCamera.Cams[TheCamera.ActiveCam].Source = pPed->GetPosition() - m_vecCamHeading;
+ }
+ m_vecCurrentPosition = pActors[m_nActor]->GetPosition();
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ m_bActorSelected = true;
+ m_bCommandActive = false;
+ }
+ else if (CPad::GetPad(1)->GetCircleJustDown()) {
+ m_nActor = -1;
+ }
+ }
+ else if (m_nNumActors != 0) {
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++) {
+ if (pActors[i] != nil) {
+ m_nActor = i;
+ break;
+ }
+ }
+ TheCamera.Cams[TheCamera.ActiveCam].Source = pActors[m_nActor]->GetPosition() - m_vecCamHeading;
+ if (m_nNumActors == 1) {
+ m_bActorSelected = true;
+ m_bCommandActive = false;
+ }
+ }
+ else {
+ m_bCommandActive = false;
+ }
+}
+
+void CSceneEdit::SelectActor2(void)
+{
+ m_bActor2Selected = false;
+ if (m_nNumActors <= 1) {
+ m_bCommandActive = false;
+ return;
+ }
+ if (m_nActor2 != -1) {
+ if (CPad::GetPad(1)->GetLeftShoulder1JustDown()) {
+ CPed* pPed;
+ do {
+ if (--m_nActor2 < 0)
+ m_nActor2 = NUM_ACTORS_IN_MOVIE - 1;
+ pPed = pActors[m_nActor2];
+ } while (pPed == nil || pPed == pActors[m_nActor]);
+ TheCamera.Cams[TheCamera.ActiveCam].Source = pPed->GetPosition() - m_vecCamHeading;
+ }
+ else if (CPad::GetPad(1)->GetRightShoulder1JustDown()) {
+ CPed* pPed;
+ do {
+ if (++m_nActor2 == NUM_ACTORS_IN_MOVIE)
+ m_nActor2 = 0;
+ pPed = pActors[m_nActor2];
+ } while (pPed == nil || pPed == pActors[m_nActor]);
+ TheCamera.Cams[TheCamera.ActiveCam].Source = pPed->GetPosition() - m_vecCamHeading;
+ }
+ m_vecCurrentPosition = pActors[m_nActor2]->GetPosition();
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ m_bActor2Selected = true;
+ m_bCommandActive = false;
+ }
+ else if (CPad::GetPad(1)->GetCircleJustDown()) {
+ m_nActor2 = -1;
+ }
+ }
+ else {
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++) {
+ if (pActors[i] != nil && pActors[m_nActor] != pActors[i] ) {
+ m_nActor2 = i;
+ break;
+ }
+ }
+ TheCamera.Cams[TheCamera.ActiveCam].Source = pActors[m_nActor2]->GetPosition() - m_vecCamHeading;
+ }
+}
+
+void CSceneEdit::SelectVehicle(void)
+{
+ m_bVehicleSelected = false;
+ if (m_nVehicle != -1) {
+ if (CPad::GetPad(1)->GetLeftShoulder1JustDown()) {
+ CVehicle* pVehicle;
+ do {
+ if (--m_nVehicle < 0)
+ m_nVehicle = NUM_VEHICLES_IN_MOVIE - 1;
+ pVehicle = pVehicles[m_nVehicle];
+ } while (pVehicle == nil);
+ }
+ else if (CPad::GetPad(1)->GetRightShoulder1JustDown()) {
+ CVehicle* pVehicle;
+ do {
+ if (++m_nVehicle == NUM_VEHICLES_IN_MOVIE)
+ m_nVehicle = 0;
+ pVehicle = pVehicles[m_nVehicle];
+ } while (pVehicle == nil);
+ }
+ m_vecCurrentPosition = pVehicles[m_nVehicle]->GetPosition();
+ TheCamera.Cams[TheCamera.ActiveCam].Source = pVehicles[m_nVehicle]->GetPosition() - m_vecCamHeading;
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ m_bVehicleSelected = true;
+ m_bCommandActive = false;
+ }
+ else if (CPad::GetPad(1)->GetCircleJustDown()) {
+ m_nVehicle = -1;
+ }
+ }
+ else if (m_nNumVehicles != 0) {
+ for (int i = 0; i < NUM_ACTORS_IN_MOVIE; i++) {
+ if (pVehicles[i] != nil) {
+ m_nVehicle = i;
+ break;
+ }
+ }
+ }
+}
+
+bool CSceneEdit::SelectWeapon(void)
+{
+ if (m_nWeaponType == WEAPONTYPE_UNARMED) {
+ m_nWeaponType = WEAPONTYPE_COLT45;
+ return false;
+ }
+ if (CPad::GetPad(1)->GetLeftShoulder1JustDown()) {
+ if (++m_nWeaponType >= WEAPONTYPE_DETONATOR)
+ m_nWeaponType = WEAPONTYPE_BASEBALLBAT;
+ pActors[m_nActor]->ClearWeapons();
+ pActors[m_nActor]->GiveWeapon((eWeaponType)m_nWeaponType, 1000);
+ pActors[m_nActor]->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pActors[m_nActor]->GetWeapon()->m_eWeaponType)->m_nModelId);
+ pActors[m_nActor]->SetCurrentWeapon(m_nWeaponType);
+ }
+ else if (CPad::GetPad(1)->GetRightShoulder1JustDown()){
+ if (--m_nWeaponType <= WEAPONTYPE_UNARMED)
+ m_nWeaponType = WEAPONTYPE_GRENADE;
+ pActors[m_nActor]->ClearWeapons();
+ pActors[m_nActor]->GiveWeapon((eWeaponType)m_nWeaponType, 1000);
+ pActors[m_nActor]->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pActors[m_nActor]->GetWeapon()->m_eWeaponType)->m_nModelId);
+ pActors[m_nActor]->SetCurrentWeapon(m_nWeaponType);
+ }
+ if (CPad::GetPad(1)->GetTriangleJustDown()) {
+ m_bCommandActive = false;
+ return true;
+ }
+ if (CPad::GetPad(1)->GetCircleJustDown()) {
+ pActors[m_nActor]->ClearWeapons();
+ m_nWeaponType = WEAPONTYPE_UNARMED;
+ m_bCommandActive = false;
+ return false;
+ }
+ return false;
+} \ No newline at end of file
diff --git a/src/control/SceneEdit.h b/src/control/SceneEdit.h
index 0de72c19..6dcefa31 100644
--- a/src/control/SceneEdit.h
+++ b/src/control/SceneEdit.h
@@ -1,14 +1,95 @@
#pragma once
+class CPed;
+class CVehicle;
+
+struct CMovieCommand
+{
+ int32 m_nCommandId;
+ CVector m_vecPosition;
+ CVector m_vecCamera;
+ int16 m_nActorId;
+ int16 m_nActor2Id;
+ int16 m_nVehicleId;
+ int16 m_nModelIndex;
+};
+
class CSceneEdit
{
public:
- static bool &m_bEditOn;
- static int32 &m_bCameraFollowActor;
- static bool &m_bRecording;
- static CVector &m_vecCurrentPosition;
- static CVector &m_vecCamHeading;
+ enum {
+ MOVIE_DO_NOTHING = 0,
+ MOVIE_NEW_ACTOR,
+ MOVIE_MOVE_ACTOR,
+ MOVIE_SELECT_ACTOR,
+ MOVIE_DELETE_ACTOR,
+ MOVIE_NEW_VEHICLE,
+ MOVIE_MOVE_VEHICLE,
+ MOVIE_SELECT_VEHICLE,
+ MOVIE_DELETE_VEHICLE,
+ MOVIE_GIVE_WEAPON,
+ MOVIE_GOTO,
+ MOVIE_GOTO_WAIT,
+ MOVIE_GET_IN_CAR,
+ MOVIE_GET_OUT_CAR,
+ MOVIE_KILL,
+ MOVIE_FLEE,
+ MOVIE_WAIT,
+ MOVIE_POSITION_CAMERA,
+ MOVIE_SET_CAMERA_TARGET,
+ MOVIE_SELECT_CAMERA_MODE,
+ MOVIE_SAVE_MOVIE,
+ MOVIE_LOAD_MOVIE,
+ MOVIE_PLAY_MOVIE,
+ MOVIE_END,
+ MOVIE_TOTAL_COMMANDS
+ };
+ enum {
+ NUM_ACTORS_IN_MOVIE = 5,
+ NUM_VEHICLES_IN_MOVIE = 5,
+ NUM_COMMANDS_IN_MOVIE = 20
+ };
+ static int32 m_bCameraFollowActor;
+ static CVector m_vecCurrentPosition;
+ static CVector m_vecCamHeading;
+ static CVector m_vecGotoPosition;
+ static int32 m_nVehicle;
+ static int32 m_nVehicle2;
+ static int32 m_nActor;
+ static int32 m_nActor2;
+ static int32 m_nVehiclemodelId;
+ static int32 m_nPedmodelId;
+ static int16 m_nCurrentMovieCommand;
+ static int16 m_nCurrentCommand;
+ static int16 m_nCurrentVehicle;
+ static int16 m_nCurrentActor;
+ static bool m_bEditOn;
+ static bool m_bRecording;
+ static bool m_bCommandActive;
+ static bool m_bActorSelected;
+ static bool m_bActor2Selected;
+ static bool m_bVehicleSelected;
+ static int16 m_nNumActors;
+ static int16 m_nNumVehicles;
+ static int16 m_nNumMovieCommands;
+ static int16 m_nWeaponType;
+ static CPed* pActors[NUM_ACTORS_IN_MOVIE];
+ static CVehicle* pVehicles[NUM_VEHICLES_IN_MOVIE];
+ static bool m_bDrawGotoArrow;
+ static CMovieCommand Movie[NUM_COMMANDS_IN_MOVIE];
+ static void LoadMovie(void);
+ static void SaveMovie(void);
+ static void Initialise(void);
+ static void InitPlayback(void);
+ static void ReInitialise(void);
static void Update(void);
- static void Init(void);
+ static void Draw(void);
+ static void ProcessCommand(void);
+ static void PlayBack(void);
+ static void ClearForNewCommand(void);
+ static void SelectActor(void);
+ static void SelectActor2(void);
+ static void SelectVehicle(void);
+ static bool SelectWeapon(void);
};
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 1f085d32..83d072f3 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -11359,7 +11359,7 @@ VALIDATESAVEBUF(size)
void CTheScripts::ClearSpaceForMissionEntity(const CVector& pos, CEntity* pEntity)
{
- static CColPoint aTempColPoints[32];
+ static CColPoint aTempColPoints[MAX_COLLISION_POINTS];
int16 entities = 0;
CEntity* aEntities[16];
CWorld::FindObjectsKindaColliding(pos, pEntity->GetBoundRadius(), false, &entities, 16, aEntities, false, true, true, false, false);
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index c884f751..85145e86 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -31,8 +31,8 @@ enum Direction
DIR_Z_NEG,
};
-eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250;
-CLinkList<CColModel*> &CCollision::ms_colModelCache = *(CLinkList<CColModel*>*)0x95CB58;
+eLevelName CCollision::ms_collisionInMemory;
+CLinkList<CColModel*> CCollision::ms_colModelCache;
void
CCollision::Init(void)
@@ -1355,6 +1355,7 @@ CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA,
modelB.triangles[aTriangleIndicesB[j]],
modelB.trianglePlanes[aTriangleIndicesB[j]],
spherepoints[numCollisions], coldist);
+
if(hasCollided)
numCollisions++;
}
diff --git a/src/core/Collision.h b/src/core/Collision.h
index 1cbd1690..bdf51eb8 100644
--- a/src/core/Collision.h
+++ b/src/core/Collision.h
@@ -3,6 +3,13 @@
#include "templates.h"
#include "Game.h" // for eLevelName
+// If you spawn many tanks at once, you will see that collisions of two entity exceeds 32.
+#ifdef FIX_BUGS
+#define MAX_COLLISION_POINTS 64
+#else
+#define MAX_COLLISION_POINTS 32
+#endif
+
struct CColSphere
{
CVector center;
@@ -110,8 +117,8 @@ struct CColModel
class CCollision
{
public:
- static eLevelName &ms_collisionInMemory;
- static CLinkList<CColModel*> &ms_colModelCache;
+ static eLevelName ms_collisionInMemory;
+ static CLinkList<CColModel*> ms_colModelCache;
static void Init(void);
static void Shutdown(void);
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 48683abc..166ecb35 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -82,34 +82,34 @@ int curBottomBarOption = -1;
int hoveredBottomBarOption = -1;
#endif
-int32 CMenuManager::OS_Language = LANG_ENGLISH; // *(int32*)0x5F2F78;
-int8 CMenuManager::m_PrefsUseVibration; // = *(int8*)0x95CD92;
-int8 CMenuManager::m_DisplayControllerOnFoot; // = *(int8*)0x95CD8D;
-int8 CMenuManager::m_PrefsVsync = 1; // *(int8*)0x5F2E58;
-int8 CMenuManager::m_PrefsVsyncDisp = 1; // *(int8*)0x5F2E5C;
-int8 CMenuManager::m_PrefsFrameLimiter = 1; // *(int8*)0x5F2E60;
-int8 CMenuManager::m_PrefsShowSubtitles = 1; // *(int8*)0x5F2E54;
-int8 CMenuManager::m_PrefsSpeakers; // = *(int8*)0x95CD7E;
-int32 CMenuManager::m_ControlMethod; // = *(int32*)0x8F5F7C;
-int8 CMenuManager::m_PrefsDMA = 1; // *(int8*)0x5F2F74;
-int32 CMenuManager::m_PrefsLanguage; // = *(int32*)0x941238;
+int32 CMenuManager::OS_Language = LANG_ENGLISH;
+int8 CMenuManager::m_PrefsUseVibration;
+int8 CMenuManager::m_DisplayControllerOnFoot;
+int8 CMenuManager::m_PrefsVsync = 1;
+int8 CMenuManager::m_PrefsVsyncDisp = 1;
+int8 CMenuManager::m_PrefsFrameLimiter = 1;
+int8 CMenuManager::m_PrefsShowSubtitles = 1;
+int8 CMenuManager::m_PrefsSpeakers;
+int32 CMenuManager::m_ControlMethod;
+int8 CMenuManager::m_PrefsDMA = 1;
+int32 CMenuManager::m_PrefsLanguage;
uint8 CMenuManager::m_PrefsStereoMono; // *(bool*)0x95CDB5; // unused except restore settings
-bool CMenuManager::m_PrefsAllowNastyGame = true; // *(bool*)0x5F2E64;
-bool CMenuManager::m_bStartUpFrontEndRequested; // = *(bool*)0x95CCF4;
-bool CMenuManager::m_bShutDownFrontEndRequested; // = *(bool*)0x95CD6A;
+bool CMenuManager::m_PrefsAllowNastyGame = true;
+bool CMenuManager::m_bStartUpFrontEndRequested;
+bool CMenuManager::m_bShutDownFrontEndRequested;
-int8 CMenuManager::m_PrefsUseWideScreen; // = *(int8*)0x95CD23;
-int8 CMenuManager::m_PrefsRadioStation; // = *(int8*)0x95CDA4;
-int32 CMenuManager::m_PrefsBrightness = 256; // = *(int32*)0x5F2E50;
-float CMenuManager::m_PrefsLOD; // = *(float*)0x8F42C4;
-int8 CMenuManager::m_bFrontEnd_ReloadObrTxtGxt; // = *(int8*)0x628CFC;
-int32 CMenuManager::m_PrefsMusicVolume = 102; // = *(int32*)0x5F2E4C;
-int32 CMenuManager::m_PrefsSfxVolume = 102; // = *(int32*)0x5F2E48;
+int8 CMenuManager::m_PrefsUseWideScreen;
+int8 CMenuManager::m_PrefsRadioStation;
+int32 CMenuManager::m_PrefsBrightness = 256;
+float CMenuManager::m_PrefsLOD = CRenderer::ms_lodDistScale;
+int8 CMenuManager::m_bFrontEnd_ReloadObrTxtGxt;
+int32 CMenuManager::m_PrefsMusicVolume = 102;
+int32 CMenuManager::m_PrefsSfxVolume = 102;
-char CMenuManager::m_PrefsSkinFile[256] = "$$\"\""; // = (char*)0x5F2E74;
+char CMenuManager::m_PrefsSkinFile[256] = "$$\"\"";
-int32 CMenuManager::m_KeyPressedCode = -1; // = *(int32*)0x5F2E70;
+int32 CMenuManager::m_KeyPressedCode = -1;
// Originally that was PS2 option color, they forget it here and used in PrintBriefs once(but didn't use the output anyway)
#ifdef PS2_LIKE_MENU
@@ -119,29 +119,26 @@ const CRGBA TEXT_COLOR = CRGBA(235, 170, 50, 255); // PC briefs text color
#endif
const float menuXYpadding = MENUACTION_POS_Y; // *(float*)0x5F355C; // not original name
-float MENU_TEXT_SIZE_X = SMALLTEXT_X_SCALE; //*(float*)0x5F2E40;
-float MENU_TEXT_SIZE_Y = SMALLTEXT_Y_SCALE; //*(float*)0x5F2E44;
+float MENU_TEXT_SIZE_X = SMALLTEXT_X_SCALE;
+float MENU_TEXT_SIZE_Y = SMALLTEXT_Y_SCALE;
bool holdingScrollBar; // *(bool*)0x628D59; // not original name
-int32 CMenuManager::m_SelectedMap; // *(int32*)0x8E2880;
-int32 CMenuManager::m_SelectedGameType; // *(int32*)0x942F88;
+int32 CMenuManager::m_SelectedMap;
+int32 CMenuManager::m_SelectedGameType;
// Used in a hidden menu
uint8 CMenuManager::m_PrefsPlayerRed = 255;
uint8 CMenuManager::m_PrefsPlayerGreen = 128;
uint8 CMenuManager::m_PrefsPlayerBlue; // why??
-CMenuManager FrontEndMenuManager; // = *(CMenuManager*)0x8F59D8;
+CMenuManager FrontEndMenuManager;
-// Move this somewhere else.
-float CRenderer::ms_lodDistScale = 1.2f; // *(float*)0x5F726C;
-
-uint32 TimeToStopPadShaking; // = *(uint32*)0x628CF8;
-char *pEditString; // = *(char**)0x628D00;
-int32 *pControlEdit; // = *(int32**)0x628D08;
-bool DisplayComboButtonErrMsg; // = *(bool*)0x628D14;
-int32 MouseButtonJustClicked; // = *(int32*)0x628D0C;
-int32 JoyButtonJustClicked; // = *(int32*)0x628D10;
+uint32 TimeToStopPadShaking;
+char *pEditString;
+int32 *pControlEdit;
+bool DisplayComboButtonErrMsg;
+int32 MouseButtonJustClicked;
+int32 JoyButtonJustClicked;
//int32 *pControlTemp = 0;
#ifndef MASTER
@@ -283,6 +280,12 @@ ScaleAndCenterX(float x)
} while(0)
#endif
+#define PREPARE_MENU_HEADER \
+ CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255))); \
+ CFont::SetRightJustifyOn(); \
+ CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT)); \
+ CFont::SetFontStyle(FONT_HEADING);
+
#define ProcessSlider(value, increaseAction, decreaseAction, hoverStartX, hoverEndX) \
do { \
lastActiveBarX = DisplaySlider(SCREEN_STRETCH_FROM_RIGHT(MENUSLIDER_X + columnWidth), MENU_Y(bitAboveNextItemY), MENU_Y(smallestSliderBar), MENU_Y(usableLineHeight), MENU_X(MENUSLIDER_UNK), value); \
@@ -447,8 +450,8 @@ CMenuManager::CheckCodesForControls(int typeOfControl)
if (typeOfControl == KEYBOARD) {
if (*pControlEdit == rsESC) {
escPressed = true;
- } else if (*pControlEdit > rsF3 && *pControlEdit != rsF9 && *pControlEdit != rsLWIN &&
- *pControlEdit != rsRWIN && *pControlEdit != rsRALT) {
+ } else if (*pControlEdit != rsF1 && *pControlEdit != rsF2 && *pControlEdit != rsF3 && *pControlEdit != rsF9 &&
+ *pControlEdit != rsLWIN && *pControlEdit != rsRWIN && *pControlEdit != rsRALT) {
typeToSave = KEYBOARD;
if (ControlsManager.GetControllerKeyAssociatedWithAction(action, KEYBOARD) != rsNULL &&
*pControlEdit != ControlsManager.GetControllerKeyAssociatedWithAction(action, KEYBOARD)) {
@@ -465,7 +468,10 @@ CMenuManager::CheckCodesForControls(int typeOfControl)
DisplayComboButtonErrMsg = true;
}
- ControlsManager.ClearSettingsAssociatedWithAction(action, typeToSave);
+#ifdef FIX_BUGS
+ if(!escPressed && !invalidKey)
+#endif
+ ControlsManager.ClearSettingsAssociatedWithAction(action, typeToSave);
if (!DisplayComboButtonErrMsg && !escPressed && !invalidKey) {
if (typeOfControl == KEYBOARD) {
ControlsManager.DeleteMatchingActionInitiators(action, *pControlEdit, KEYBOARD);
@@ -670,6 +676,17 @@ CMenuManager::Draw()
CFont::SetCentreOff();
CFont::SetJustifyOn();
CFont::SetBackGroundOnlyTextOn();
+#ifdef GTA3_1_1_PATCH
+ CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+ CFont::SetRightJustifyOn();
+ CFont::SetFontStyle(FONT_HEADING);
+ CFont::SetScale(MENU_X(0.7f), MENU_Y(0.5f));
+ CFont::SetWrapx(SCREEN_WIDTH);
+ CFont::SetRightJustifyWrap(0.0f);
+ strcpy(gString, "V1.1");
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(SCREEN_WIDTH / 10, SCREEN_HEIGHT / 45, gUString);
+#endif
CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN));
CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH));
@@ -696,17 +713,9 @@ CMenuManager::Draw()
#endif
if (aScreens[m_nCurrScreen].m_ScreenName[0] != '\0') {
- CFont::SetRightJustifyOn();
- CFont::SetFontStyle(FONT_HEADING);
-#ifdef PS2_LIKE_MENU
- CFont::SetColor(CRGBA(0, 0, 0, 255));
- CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(1.3f));
- CFont::PrintString(MENU_X_RIGHT_ALIGNED(50.0f), SCREEN_SCALE_FROM_BOTTOM(75.0f), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName));
-#else
- CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
- CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT));
+ PREPARE_MENU_HEADER
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName));
-#endif
+
// Weird place to put that.
nextYToUse += 24.0f + 10.0f;
}
@@ -1735,11 +1744,8 @@ CMenuManager::DrawControllerSetupScreen()
CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN));
CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH));
- // Page header
- CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
- CFont::SetRightJustifyOn();
- CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT));
- CFont::SetFontStyle(FONT_HEADING);
+ PREPARE_MENU_HEADER
+
switch (m_ControlMethod) {
case CONTROL_STANDARD:
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y),
@@ -2417,10 +2423,8 @@ CMenuManager::DrawPlayerSetupScreen()
CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN));
CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH));
- CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
- CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT));
- CFont::SetRightJustifyOn();
- CFont::SetFontStyle(FONT_HEADING);
+ PREPARE_MENU_HEADER
+
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get("FET_PS"));
// lstrcpy's changed with strcpy
@@ -3314,10 +3318,7 @@ CMenuManager::PrintStats()
// ::Draw already does that.
/*
- CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
- CFont::SetRightJustifyOn();
- CFont::SetFontStyle(FONT_HEADING);
- CFont::SetScale(MENU_X(MENUHEADER_WIDTH), MENU_Y(MENUHEADER_HEIGHT));
+ PREPARE_MENU_HEADER
CFont::PrintString(MENU_X_RIGHT_ALIGNED(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName));
*/
CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X), MENU_Y(MENU_TEXT_SIZE_Y));
diff --git a/src/core/Frontend.h b/src/core/Frontend.h
index 9064cf4e..8fe61a36 100644
--- a/src/core/Frontend.h
+++ b/src/core/Frontend.h
@@ -2,10 +2,16 @@
#include "Sprite2d.h"
+#ifdef PS2_LIKE_MENU
+#define MENUHEADER_POS_X 50.0f
+#define MENUHEADER_POS_Y 75.0f
+#define MENUHEADER_HEIGHT 1.3f
+#else
#define MENUHEADER_POS_X 35.0f
#define MENUHEADER_POS_Y 93.0f
-#define MENUHEADER_WIDTH 0.84f
#define MENUHEADER_HEIGHT 1.6f
+#endif
+#define MENUHEADER_WIDTH 0.84f
#define MENU_X_MARGIN 40.0f
#define MENUACTION_POS_Y 60.0f
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index daac3ec5..fe747ac1 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -350,7 +350,7 @@ bool CGame::Initialise(const char* datFile)
CAntennas::Init();
CGlass::Init();
gPhoneInfo.Initialise();
- CSceneEdit::Init();
+ CSceneEdit::Initialise();
LoadingScreen("Loading the Game", "Load scripts", nil);
CTheScripts::Init();
CGangs::Initialise();
diff --git a/src/core/General.h b/src/core/General.h
index f32846eb..77828854 100644
--- a/src/core/General.h
+++ b/src/core/General.h
@@ -90,6 +90,11 @@ public:
return -Atan2(x / y, 1.0f);
}
}
+
+ static float GetAngleBetweenPoints(float x1, float y1, float x2, float y2)
+ {
+ return RADTODEG(GetRadianAngleBetweenPoints(x1, y1, x2, y2));
+ }
// should return direction in 0-8 range. fits perfectly to peds' path directions.
static int GetNodeHeadingFromVector(float x, float y)
diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index f83998b8..201dc5b6 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -644,6 +644,8 @@ void CPad::AddToCheatString(char c)
{
for ( int32 i = ARRAY_SIZE(CheatString) - 2; i >= 0; i-- )
CheatString[i + 1] = CheatString[i];
+
+ CheatString[0] = c;
#define _CHEATCMP(str) strncmp(str, CheatString, sizeof(str)-1)
// "4414LDRULDRU" - R2 R2 L1 R2 LEFT DOWN RIGHT UP LEFT DOWN RIGHT UP
diff --git a/src/core/World.cpp b/src/core/World.cpp
index d64569b3..313b958a 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -21,7 +21,7 @@
#include "Population.h"
#include "Fire.h"
-CColPoint *gaTempSphereColPoints = (CColPoint*)0x6E64C0; // [32]
+CColPoint gaTempSphereColPoints[MAX_COLLISION_POINTS];
CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60;
CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C;
@@ -29,7 +29,7 @@ CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x6656
uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64;
uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61;
-CPlayerInfo (&CWorld::Players)[NUMPLAYERS] = *(CPlayerInfo (*)[NUMPLAYERS])*(uintptr*)0x9412F0;
+CPlayerInfo CWorld::Players[NUMPLAYERS];
bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC;
CEntity *&CWorld::pIgnoreEntity = *(CEntity**)0x8F6494;
bool &CWorld::bIncludeDeadPeds = *(bool*)0x95CD8F;
@@ -58,6 +58,7 @@ WRAPPER void CWorld::ClearPedsFromArea(float, float, float, float, float, float)
WRAPPER void CWorld::CallOffChaseForArea(float, float, float, float) { EAXJMP(0x4B5530); }
WRAPPER void CWorld::TriggerExplosion(const CVector& a1, float a2, float a3, CEntity *a4, bool a5) { EAXJMP(0x4B1140); }
WRAPPER void CWorld::SetPedsOnFire(float, float, float, float, CEntity*) { EAXJMP(0x4B3D30); }
+WRAPPER void CWorld::UseDetonator(CEntity *) { EAXJMP(0x4B4650); }
void
CWorld::Initialise()
diff --git a/src/core/World.h b/src/core/World.h
index 07e7889f..d3f1e2d5 100644
--- a/src/core/World.h
+++ b/src/core/World.h
@@ -61,7 +61,7 @@ class CWorld
public:
static uint8 &PlayerInFocus;
- static CPlayerInfo (&Players)[NUMPLAYERS];
+ static CPlayerInfo Players[NUMPLAYERS];
static CEntity *&pIgnoreEntity;
static bool &bIncludeDeadPeds;
static bool &bNoMoreCollisionTorque;
@@ -142,9 +142,11 @@ public:
static void RemoveStaticObjects();
static void Process();
static void TriggerExplosion(const CVector &, float, float, CEntity*, bool);
+
+ static void UseDetonator(CEntity *);
};
-extern CColPoint *gaTempSphereColPoints;
+extern CColPoint gaTempSphereColPoints[MAX_COLLISION_POINTS];
class CPlayerPed;
class CVehicle;
diff --git a/src/core/main.cpp b/src/core/main.cpp
index f09c2e0a..b028b5fb 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -58,6 +58,7 @@
#include "Console.h"
#include "timebars.h"
#include "GenericGameStorage.h"
+#include "SceneEdit.h"
GlobalScene &Scene = *(GlobalScene*)0x726768;
@@ -690,14 +691,14 @@ DisplayGameDebugText()
CFont::SetPropOn();
CFont::SetBackgroundOff();
CFont::SetFontStyle(FONT_BANK);
- CFont::SetScale(SCREEN_STRETCH_X(0.5f), SCREEN_STRETCH_Y(0.5f));
+ CFont::SetScale(SCREEN_SCALE_X(0.5f), SCREEN_SCALE_Y(0.5f));
CFont::SetCentreOff();
CFont::SetRightJustifyOff();
CFont::SetWrapx(SCREEN_WIDTH);
CFont::SetJustifyOff();
CFont::SetBackGroundOnlyTextOff();
CFont::SetColor(CRGBA(255, 108, 0, 255));
- CFont::PrintString(10.0f, 10.0f, ver);
+ CFont::PrintString(SCREEN_SCALE_X(10.0f), SCREEN_SCALE_Y(10.0f), ver);
FrameSamples++;
FramesPerSecondCounter += 1000.0f / (CTimer::GetTimeStepNonClippedInSeconds() * 1000.0f);
@@ -748,6 +749,7 @@ DisplayGameDebugText()
AsciiToUnicode(str, ustr);
+ // Let's not scale those numbers, they look better that way :eyes:
CFont::SetPropOff();
CFont::SetBackgroundOff();
CFont::SetScale(0.7f, 1.5f);
@@ -863,11 +865,9 @@ Render2dStuff(void)
MusicManager.DisplayRadioStationName();
TheConsole.Display();
-/*
if(CSceneEdit::m_bEditOn)
CSceneEdit::Draw();
else
-*/
CHud::Draw();
CUserDisplay::OnscnTimer.ProcessForDisplay();
CMessages::Display();
@@ -1560,8 +1560,9 @@ void SystemInit()
//
#endif
-
+#ifdef GTA_PS2_STUFF
CPad::Initialise();
+#endif
CPad::GetPad(0)->Mode = 0;
CGame::frenchGame = false;
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 321ff172..5d76d642 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -22,6 +22,8 @@
#include "Console.h"
#include "Debug.h"
#include "Hud.h"
+#include "SceneEdit.h"
+#include "Pad.h"
#include <list>
@@ -332,6 +334,7 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Spawn", "Spawn Predator", [](){ SpawnCar(MI_PREDATOR); });
DebugMenuAddVarBool8("Debug", "Draw hud", (int8*)&CHud::m_Wants_To_Draw_Hud, nil);
+ DebugMenuAddVarBool8("Debug", "Edit on", (int8*)&CSceneEdit::m_bEditOn, nil);
DebugMenuAddVar("Debug", "Engine Status", &engineStatus, nil, 1, 0, 226, nil);
DebugMenuAddCmd("Debug", "Set Engine Status", SetEngineStatus);
DebugMenuAddCmd("Debug", "Fix Car", FixCar);
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index 9fc77a8c..bbdf68f5 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -612,7 +612,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl
if(model == MI_FIRE_HYDRANT && !Bobj->bHasBeenDamaged){
CParticleObject::AddObject(POBJECT_FIRE_HYDRANT, B->GetPosition() - CVector(0.0f, 0.0f, 0.5f), true);
Bobj->bHasBeenDamaged = true;
- }else if(B->IsObject() && model != MI_EXPLODINGBARREL && model != MI_PETROLPUMP)
+ }else if(B->IsObject() && !IsExplosiveThingModel(model))
Bobj->bHasBeenDamaged = true;
}else{
if(IsGlass(B->GetModelIndex()))
@@ -1037,7 +1037,7 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
int numCollisions;
int mostColliding;
- CColPoint colpoints[32];
+ CColPoint colpoints[MAX_COLLISION_POINTS];
CVector shift = { 0.0f, 0.0f, 0.0f };
bool doShift = false;
CEntity *boat = nil;
@@ -1187,7 +1187,7 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists)
bool
CPhysical::ProcessCollisionSectorList_SimpleCar(CPtrList *lists)
{
- static CColPoint aColPoints[32];
+ static CColPoint aColPoints[MAX_COLLISION_POINTS];
float radius;
CVector center;
int listtype;
@@ -1349,7 +1349,7 @@ collision:
bool
CPhysical::ProcessCollisionSectorList(CPtrList *lists)
{
- static CColPoint aColPoints[32];
+ static CColPoint aColPoints[MAX_COLLISION_POINTS];
float radius;
CVector center;
CPtrList *list;
diff --git a/src/math/Vector.h b/src/math/Vector.h
index 1274a4b2..269ffc88 100644
--- a/src/math/Vector.h
+++ b/src/math/Vector.h
@@ -46,6 +46,13 @@ public:
y *= invsqrt;
z *= invsqrt;
}
+
+ void Normalise2D(void) {
+ float sq = MagnitudeSqr2D();
+ float invsqrt = RecipSqrt(sq);
+ x *= invsqrt;
+ y *= invsqrt;
+ }
const CVector &operator+=(CVector const &right) {
x += right.x;
diff --git a/src/math/Vector2D.h b/src/math/Vector2D.h
index 1e4d698f..705ad763 100644
--- a/src/math/Vector2D.h
+++ b/src/math/Vector2D.h
@@ -13,13 +13,14 @@ public:
void Normalise(void){
float sq = MagnitudeSqr();
- if(sq > 0.0f){
+ //if(sq > 0.0f){
float invsqrt = RecipSqrt(sq);
x *= invsqrt;
y *= invsqrt;
- }else
- x = 1.0f;
+ //}else
+ // x = 1.0f;
}
+
const CVector2D &operator+=(CVector2D const &right) {
x += right.x;
y += right.y;
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index 20d1b7f3..309fa1bb 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -490,3 +490,10 @@ IsPoliceVehicleModel(int16 id)
id == MI_POLICE ||
id == MI_ENFORCER;
}
+
+inline bool
+IsExplosiveThingModel(int16 id)
+{
+ return id == MI_EXPLODINGBARREL ||
+ id == MI_PETROLPUMP;
+} \ No newline at end of file
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 80d99e29..412b1f04 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -62,7 +62,7 @@
CPed *gapTempPedList[50];
uint16 gnNumTempPedList;
-CColPoint &aTempPedColPts = *(CColPoint*)0x62DB14;
+CColPoint aTempPedColPts[MAX_COLLISION_POINTS];
// Corresponds to ped sounds (from SOUND_PED_DEATH to SOUND_PED_TAXI_CALL)
PedAudioData CommentWaitTime[39] = {
@@ -106,8 +106,6 @@ PedAudioData CommentWaitTime[39] = {
{1000, 1000, 1000, 1000},
{1000, 1000, 5000, 5000},
};
-// *(CPedAudioData(*)[39]) * (uintptr*)0x5F94C4;
-
uint16 nPlayerInComboMove;
RpClump *flyingClumpTemp;
@@ -139,10 +137,9 @@ FightMove tFightMoves[NUM_FIGHTMOVES] = {
{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;
+uint16 CPed::nThreatReactionRangeMultiplier = 1;
+uint16 CPed::nEnterCarRangeMultiplier = 1;
CVector vecPedCarDoorAnimOffset;
CVector vecPedCarDoorLoAnimOffset;
@@ -151,9 +148,9 @@ CVector vecPedQuickDraggedOutCarAnimOffset;
CVector vecPedDraggedOutCarAnimOffset;
CVector vecPedTrainDoorAnimOffset;
-bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
-bool &CPed::bPedCheat2 = *(bool*)0x95CD5A;
-bool &CPed::bPedCheat3 = *(bool*)0x95CD59;
+bool CPed::bNastyLimbsCheat;
+bool CPed::bPedCheat2;
+bool CPed::bPedCheat3;
CVector2D CPed::ms_vec2DFleePosition;
void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); }
@@ -1231,7 +1228,7 @@ CPed::Attack(void)
weaponAnimAssoc->SetCurrentTime(0.0f);
if (IsPlayer()) {
- ((CPlayerPed*)this)->field_1376 = 0.0f;
+ ((CPlayerPed*)this)->m_fAttackButtonCounter = 0.0f;
((CPlayerPed*)this)->m_bHaveTargetSelected = false;
}
}
@@ -4143,7 +4140,7 @@ CPed::SetGetUp(void)
&& ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 5) % 8
|| CCollision::ProcessColModels(GetMatrix(), *CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(),
collidingVeh->GetMatrix(), *CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(),
- &aTempPedColPts, nil, nil) > 0)) {
+ aTempPedColPts, nil, nil) > 0)) {
bGetUpAnimStarted = false;
if (IsPlayer())
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index 2edd5d68..9f660693 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -796,7 +796,12 @@ public:
PedState GetPedState(void) { return m_nPedState; }
void SetPedState(PedState state) { m_nPedState = state; }
+ bool Dead(void) { return m_nPedState == PED_DEAD; }
+ bool Dying(void) { return m_nPedState == PED_DIE; }
bool DyingOrDead(void) { return m_nPedState == PED_DIE || m_nPedState == PED_DEAD; }
+ bool OnGround(void) { return m_nPedState == PED_FALL || m_nPedState == PED_DIE || m_nPedState == PED_DEAD; }
+
+ bool Driving(void) { return m_nPedState == PED_DRIVING; }
bool InVehicle(void) { return bInVehicle && m_pMyVehicle; } // True when ped is sitting/standing in vehicle, not in enter/exit state.
bool EnteringCar(void) { return m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK; }
@@ -823,14 +828,14 @@ public:
}
// set by 0482:set_threat_reaction_range_multiplier opcode
- static uint16 &nThreatReactionRangeMultiplier;
+ static uint16 nThreatReactionRangeMultiplier;
// set by 0481:set_enter_car_range_multiplier opcode
- static uint16 &nEnterCarRangeMultiplier;
+ static uint16 nEnterCarRangeMultiplier;
- static bool &bNastyLimbsCheat;
- static bool &bPedCheat2;
- static bool &bPedCheat3;
+ static bool bNastyLimbsCheat;
+ static bool bPedCheat2;
+ static bool bPedCheat3;
static CVector2D ms_vec2DFleePosition;
#ifdef TOGGLEABLE_BETA_FEATURES
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index ccc0a43a..dcd9486f 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -43,8 +43,8 @@ CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1)
m_fStaminaProgress = 0.0f;
m_nEvadeAmount = 0;
field_1367 = 0;
- m_nShotDelay = 0;
- field_1376 = 0.0f;
+ m_nHitAnimDelayTimer = 0;
+ m_fAttackButtonCounter = 0.0f;
m_bHaveTargetSelected = false;
m_bHasLockOnTarget = false;
m_bCanBeDamaged = true;
@@ -1024,10 +1024,10 @@ CPlayerPed::ProcessPlayerWeapon(CPad *padUsed)
if (padUsed->WeaponJustDown()) {
m_bHaveTargetSelected = true;
} else if (!m_bHaveTargetSelected) {
- field_1376 += CTimer::GetTimeStepNonClipped();
+ m_fAttackButtonCounter += CTimer::GetTimeStepNonClipped();
}
} else {
- field_1376 = 0.0f;
+ m_fAttackButtonCounter = 0.0f;
m_bHaveTargetSelected = false;
}
SetAttack(nil);
diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h
index c139bbbc..f96d8e6a 100644
--- a/src/peds/PlayerPed.h
+++ b/src/peds/PlayerPed.h
@@ -20,8 +20,8 @@ public:
uint8 m_nEvadeAmount;
int8 field_1367;
uint32 m_nSpeedTimer;
- int32 m_nShotDelay;
- float field_1376; // m_fAttackButtonCounter?
+ uint32 m_nHitAnimDelayTimer;
+ float m_fAttackButtonCounter;
bool m_bHaveTargetSelected; // may have better name
int8 field_1381;
int8 field_1382;
diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp
index 6959487f..e26e2eaf 100644
--- a/src/peds/Population.cpp
+++ b/src/peds/Population.cpp
@@ -47,36 +47,36 @@ const RegenerationPoint aSafeZones[] = {
CVector(-321.0f, -1043.0f, -13.2f), CVector(-328.0f, -1045.0f, -13.2f), CVector(-398.0f, -1044.0f, -13.5f), CVector(-390.0f, -1040.5f, -13.5f) },
{ LEVEL_COMMERCIAL, LEVEL_SUBURBAN, 425.0f, 280.0f, 471.0f, 447.0f, 20.0f, 5.0f,
CVector(-292.0f, -457.0f, -11.6f), CVector(-310.0f, -461.0f, -11.6f), CVector(-413.0f, -461.0f, -11.5f), CVector(-399.0f, -457.0f, -11.3f) }
-}; // *(RegenerationPoint(*)[8]) * (uintptr*)0x5FA578;
-
-PedGroup CPopulation::ms_pPedGroups[NUMPEDGROUPS]; // = *(PedGroup(*)[NUMPEDGROUPS]) * (uintptr*)0x6E9248;
-bool CPopulation::ms_bGivePedsWeapons; // = *(bool*)0x95CCF6;
-int32 CPopulation::m_AllRandomPedsThisType = -1; // = *(int32*)0x5FA570;
-float CPopulation::PedDensityMultiplier = 1.0f; // = *(float*)0x5FA56C;
-uint32 CPopulation::ms_nTotalMissionPeds; // = *(uint32*)0x8F5F70;
-int32 CPopulation::MaxNumberOfPedsInUse = 25; // *(int32*)0x5FA574;
-uint32 CPopulation::ms_nNumCivMale; // = *(uint32*)0x8F2548;
-uint32 CPopulation::ms_nNumCivFemale; // = *(uint32*)0x8F5F44;
-uint32 CPopulation::ms_nNumCop; // = *(uint32*)0x885AFC;
-bool CPopulation::bZoneChangeHasHappened; // = *(bool*)0x95CD79;
-uint32 CPopulation::ms_nNumEmergency; // = *(uint32*)0x94071C;
-int8 CPopulation::m_CountDownToPedsAtStart; // = *(int8*)0x95CD4F;
-uint32 CPopulation::ms_nNumGang1; // = *(uint32*)0x8F1B1C;
-uint32 CPopulation::ms_nNumGang2; // = *(uint32*)0x8F1B14;
-uint32 CPopulation::ms_nTotalPeds; // = *(uint32*)0x95CB50;
-uint32 CPopulation::ms_nNumGang3; // = *(uint32*)0x8F2548;
-uint32 CPopulation::ms_nTotalGangPeds; // = *(uint32*)0x885AF0;
-uint32 CPopulation::ms_nNumGang4; // = *(uint32*)0x8F1B2C;
-uint32 CPopulation::ms_nTotalCivPeds; // = *(uint32*)0x8F2C3C;
-uint32 CPopulation::ms_nNumGang5; // = *(uint32*)0x8F1B30;
-uint32 CPopulation::ms_nNumDummy; // = *(uint32*)0x8F1A98;
-uint32 CPopulation::ms_nNumGang6; // = *(uint32*)0x8F1B20;
-uint32 CPopulation::ms_nNumGang9; // = *(uint32*)0x8F1B10;
-uint32 CPopulation::ms_nNumGang7; // = *(uint32*)0x8F1B28;
-uint32 CPopulation::ms_nNumGang8; // = *(uint32*)0x8F1B0C;
-CVector CPopulation::RegenerationPoint_a; // = *(CVector*)0x8E2AA4;
-CVector CPopulation::RegenerationPoint_b; // = *(CVector*)0x8E2A98;
-CVector CPopulation::RegenerationForward; // = *(CVector*)0x8F1AD4;
+};
+
+PedGroup CPopulation::ms_pPedGroups[NUMPEDGROUPS];
+bool CPopulation::ms_bGivePedsWeapons;
+int32 CPopulation::m_AllRandomPedsThisType = -1;
+float CPopulation::PedDensityMultiplier = 1.0f;
+uint32 CPopulation::ms_nTotalMissionPeds;
+int32 CPopulation::MaxNumberOfPedsInUse = 25;
+uint32 CPopulation::ms_nNumCivMale;
+uint32 CPopulation::ms_nNumCivFemale;
+uint32 CPopulation::ms_nNumCop;
+bool CPopulation::bZoneChangeHasHappened;
+uint32 CPopulation::ms_nNumEmergency;
+int8 CPopulation::m_CountDownToPedsAtStart;
+uint32 CPopulation::ms_nNumGang1;
+uint32 CPopulation::ms_nNumGang2;
+uint32 CPopulation::ms_nTotalPeds;
+uint32 CPopulation::ms_nNumGang3;
+uint32 CPopulation::ms_nTotalGangPeds;
+uint32 CPopulation::ms_nNumGang4;
+uint32 CPopulation::ms_nTotalCivPeds;
+uint32 CPopulation::ms_nNumGang5;
+uint32 CPopulation::ms_nNumDummy;
+uint32 CPopulation::ms_nNumGang6;
+uint32 CPopulation::ms_nNumGang9;
+uint32 CPopulation::ms_nNumGang7;
+uint32 CPopulation::ms_nNumGang8;
+CVector CPopulation::RegenerationPoint_a;
+CVector CPopulation::RegenerationPoint_b;
+CVector CPopulation::RegenerationForward;
void
CPopulation::Initialise()
diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp
index 39866294..7debe3d3 100644
--- a/src/render/Clouds.cpp
+++ b/src/render/Clouds.cpp
@@ -233,7 +233,7 @@ CClouds::Render(void)
szx*55.0f, szy*55.0f,
tr, tg, tb, br, bg, bb, 0.0f, -1.0f,
1.0f/screenpos.z,
- IndividualRotation/65336.0f * 2*3.14f + ms_cameraRoll,
+ (uint16)IndividualRotation/65336.0f * 6.28f + ms_cameraRoll,
fluffyalpha);
bCloudOnScreen[i] = true;
}else
diff --git a/src/render/Glass.cpp b/src/render/Glass.cpp
index 41d31985..ac6c1728 100644
--- a/src/render/Glass.cpp
+++ b/src/render/Glass.cpp
@@ -404,6 +404,7 @@ CGlass::AskForObjectToBeRenderedInGlass(CEntity *entity)
void
CGlass::RenderEntityInGlass(CEntity *entity)
{
+ ASSERT(entity!=nil);
CObject *object = (CObject *)entity;
if ( object->bGlassBroken )
@@ -419,7 +420,7 @@ CGlass::RenderEntityInGlass(CEntity *entity)
uint8 alpha = CalcAlphaWithNormal(&fwdNorm);
CColModel *col = object->GetColModel();
-
+ ASSERT(col!=nil);
if ( col->numTriangles >= 2 )
{
CVector a = object->GetMatrix() * col->vertices[0];
@@ -523,6 +524,8 @@ CGlass::RenderEntityInGlass(CEntity *entity)
int32
CGlass::CalcAlphaWithNormal(CVector *normal)
{
+ ASSERT(normal!=nil);
+
float fwdDir = 2.0f * DotProduct(*normal, TheCamera.GetForward());
float fwdDot = DotProduct(TheCamera.GetForward()-fwdDir*(*normal), CVector(0.57f, 0.57f, -0.57f));
return int32(lerp(fwdDot*fwdDot*fwdDot*fwdDot*fwdDot*fwdDot, 20.0f, 255.0f));
@@ -597,6 +600,8 @@ CGlass::RenderReflectionPolys(void)
void
CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed, CVector point, bool explosion)
{
+ ASSERT(entity!=nil);
+
CObject *object = (CObject *)entity;
if ( object->bGlassBroken )
@@ -605,7 +610,8 @@ CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed,
object->bGlassCracked = true;
CColModel *col = object->GetColModel();
-
+ ASSERT(col!=nil);
+
CVector a = object->GetMatrix() * col->vertices[0];
CVector b = object->GetMatrix() * col->vertices[1];
CVector c = object->GetMatrix() * col->vertices[2];
@@ -647,6 +653,8 @@ CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed,
void
CGlass::WindowRespondsToSoftCollision(CEntity *entity, float amount)
{
+ ASSERT(entity!=nil);
+
CObject *object = (CObject *)entity;
if ( amount > 50.0f && !object->bGlassCracked )
@@ -659,6 +667,8 @@ CGlass::WindowRespondsToSoftCollision(CEntity *entity, float amount)
void
CGlass::WasGlassHitByBullet(CEntity *entity, CVector point)
{
+ ASSERT(entity!=nil);
+
CObject *object = (CObject *)entity;
if ( IsGlass(object->GetModelIndex()) )
@@ -679,6 +689,8 @@ CGlass::WasGlassHitByBullet(CEntity *entity, CVector point)
void
CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point)
{
+ ASSERT(entity!=nil);
+
CObject *object = (CObject *)entity;
CVector distToGlass = object->GetPosition() - point;
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index d7834065..7b2f90e8 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -39,16 +39,17 @@ struct EntityInfo
float sort;
};
-CLinkList<EntityInfo> &gSortedVehiclesAndPeds = *(CLinkList<EntityInfo>*)0x629AC0;
+CLinkList<EntityInfo> gSortedVehiclesAndPeds;
-int32 &CRenderer::ms_nNoOfVisibleEntities = *(int32*)0x940730;
-CEntity *(&CRenderer::ms_aVisibleEntityPtrs)[NUMVISIBLEENTITIES] = *(CEntity * (*)[NUMVISIBLEENTITIES]) * (uintptr*)0x6E9920;
-CEntity *(&CRenderer::ms_aInVisibleEntityPtrs)[NUMINVISIBLEENTITIES] = *(CEntity * (*)[NUMINVISIBLEENTITIES]) * (uintptr*)0x880B50;
-int32 &CRenderer::ms_nNoOfInVisibleEntities = *(int32*)0x8F1B78;
+int32 CRenderer::ms_nNoOfVisibleEntities;
+CEntity *CRenderer::ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES];
+CEntity *CRenderer::ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES];
+int32 CRenderer::ms_nNoOfInVisibleEntities;
-CVector &CRenderer::ms_vecCameraPosition = *(CVector*)0x8E2C3C;
-CVehicle *&CRenderer::m_pFirstPersonVehicle = *(CVehicle**)0x885B80;
-bool &CRenderer::m_loadingPriority = *(bool*)0x95CD86;
+CVector CRenderer::ms_vecCameraPosition;
+CVehicle *CRenderer::m_pFirstPersonVehicle;
+bool CRenderer::m_loadingPriority;
+float CRenderer::ms_lodDistScale = 1.2f;
void
CRenderer::Init(void)
diff --git a/src/render/Renderer.h b/src/render/Renderer.h
index 42c154ec..362741e3 100644
--- a/src/render/Renderer.h
+++ b/src/render/Renderer.h
@@ -20,17 +20,17 @@ class CPtrList;
class CRenderer
{
- static int32 &ms_nNoOfVisibleEntities;
- static CEntity *(&ms_aVisibleEntityPtrs)[NUMVISIBLEENTITIES];
- static int32 &ms_nNoOfInVisibleEntities;
- static CEntity *(&ms_aInVisibleEntityPtrs)[NUMINVISIBLEENTITIES];
+ static int32 ms_nNoOfVisibleEntities;
+ static CEntity *ms_aVisibleEntityPtrs[NUMVISIBLEENTITIES];
+ static int32 ms_nNoOfInVisibleEntities;
+ static CEntity *ms_aInVisibleEntityPtrs[NUMINVISIBLEENTITIES];
- static CVector &ms_vecCameraPosition;
- static CVehicle *&m_pFirstPersonVehicle;
+ static CVector ms_vecCameraPosition;
+ static CVehicle *m_pFirstPersonVehicle;
public:
- static float ms_lodDistScale; // defined in Frontend.cpp
- static bool &m_loadingPriority;
+ static float ms_lodDistScale;
+ static bool m_loadingPriority;
static void Init(void);
static void Shutdown(void);
diff --git a/src/render/Sprite.cpp b/src/render/Sprite.cpp
index 8ac2315f..82754121 100644
--- a/src/render/Sprite.cpp
+++ b/src/render/Sprite.cpp
@@ -137,8 +137,8 @@ CSprite::RenderOneXLUSprite(float x, float y, float z, float w, float h, uint8 r
void
CSprite::RenderOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float rotation, uint8 a)
{
- float c = Cos(DEGTORAD(rotation));
- float s = Sin(DEGTORAD(rotation));
+ float c = Cos(rotation);
+ float s = Sin(rotation);
float xs[4];
float ys[4];
@@ -315,8 +315,8 @@ void
CSprite::RenderBufferedOneXLUSprite_Rotate_Aspect(float x, float y, float z, float w, float h, uint8 r, uint8 g, uint8 b, int16 intens, float recipz, float rotation, uint8 a)
{
m_bFlushSpriteBufferSwitchZTest = 0;
- float c = Cos(DEGTORAD(rotation));
- float s = Sin(DEGTORAD(rotation));
+ float c = Cos(rotation);
+ float s = Sin(rotation);
float xs[4];
float ys[4];
@@ -367,8 +367,8 @@ void
CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours(float x, float y, float z, float w, float h, uint8 r1, uint8 g1, uint8 b1, uint8 r2, uint8 g2, uint8 b2, float cx, float cy, float recipz, float rotation, uint8 a)
{
m_bFlushSpriteBufferSwitchZTest = 0;
- float c = Cos(DEGTORAD(rotation));
- float s = Sin(DEGTORAD(rotation));
+ float c = Cos(rotation);
+ float s = Sin(rotation);
float xs[4];
float ys[4];
@@ -398,11 +398,11 @@ CSprite::RenderBufferedOneXLUSprite_Rotate_2Colours(float x, float y, float z, f
// Colour factors, cx/y is the direction in which colours change from rgb1 to rgb2
cf[0] = (cx*(-c-s) + cy*(-c+s))*0.5f + 0.5f;
cf[0] = clamp(cf[0], 0.0f, 1.0f);
- cf[1] = (cx*(-c-s) + cy*(-c+s))*0.5f + 0.5f;
+ cf[1] = (cx*(-c+s) + cy*( c+s))*0.5f + 0.5f;
cf[1] = clamp(cf[1], 0.0f, 1.0f);
- cf[2] = (cx*(-c-s) + cy*(-c+s))*0.5f + 0.5f;
+ cf[2] = (cx*( c+s) + cy*( c-s))*0.5f + 0.5f;
cf[2] = clamp(cf[2], 0.0f, 1.0f);
- cf[3] = (cx*(-c-s) + cy*(-c+s))*0.5f + 0.5f;
+ cf[3] = (cx*( c-s) + cy*(-c-s))*0.5f + 0.5f;
cf[3] = clamp(cf[3], 0.0f, 1.0f);
float screenz = m_f2DNearScreenZ +
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 257c8d33..2a325b3d 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -356,7 +356,7 @@ CAutomobile::ProcessControl(void)
PruneReferences();
- if(m_status == STATUS_PLAYER && CRecordDataForChase::IsRecording())
+ if(m_status == STATUS_PLAYER && !CRecordDataForChase::IsRecording())
DoDriveByShootings();
}
break;
@@ -4206,8 +4206,7 @@ GetCurrentAtomicObjectCB(RwObject *object, void *data)
return object;
}
-CColPoint aTempPedColPts[32]; // this name doesn't make any sense
- // they probably copied it from Ped (both serves same purpose) and didn't change the name
+CColPoint spherepoints[MAX_COLLISION_POINTS];
CObject*
CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
@@ -4327,7 +4326,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(),
this->GetMatrix(), *this->GetColModel(),
- aTempPedColPts, nil, nil) > 0)
+ spherepoints, nil, nil) > 0)
obj->m_pCollidingEntity = this;
if(bRenderScorched)
diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp
index 3dc1deeb..c4cdcb02 100644
--- a/src/vehicles/Heli.cpp
+++ b/src/vehicles/Heli.cpp
@@ -78,6 +78,9 @@ CHeli::CHeli(int32 id, uint8 CreatedBy)
m_bTestRight = true;
m_fTargetOffset = 0.0f;
m_fSearchLightX = m_fSearchLightY = 0.0f;
+
+ // BUG: not in game but gets initialized to CDCDCDCD in debug
+ m_nLastShotTime = 0;
}
void
@@ -590,7 +593,12 @@ CHeli::PreRender(void)
break;
}
RwRGBA col = { r, g, b, 32 };
+#ifdef FIX_BUGS
+ pos.z = m_fHeliDustZ[frm];
+#else
+ // What the hell is the point of this?
pos.z = m_fHeliDustZ[(i - (i&3))/4]; // advance every 4 iterations, why not just /4?
+#endif
if(pos.z > -200.0f && GetPosition().z - pos.z < 20.0f)
CParticle::AddParticle(PARTICLE_HELI_DUST, pos, dir, nil, 0.0f, col);
i++;
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index f47fd131..ed8f4221 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -19,12 +19,12 @@
#include "Fire.h"
#include "Darkel.h"
-bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78;
-bool &CVehicle::bAllDodosCheat = *(bool *)0x95CD75;
-bool &CVehicle::bCheat3 = *(bool *)0x95CD66;
-bool &CVehicle::bCheat4 = *(bool *)0x95CD65;
-bool &CVehicle::bCheat5 = *(bool *)0x95CD64;
-bool &CVehicle::m_bDisableMouseSteering = *(bool *)0x60252C;
+bool CVehicle::bWheelsOnlyCheat;
+bool CVehicle::bAllDodosCheat;
+bool CVehicle::bCheat3;
+bool CVehicle::bCheat4;
+bool CVehicle::bCheat5;
+bool CVehicle::m_bDisableMouseSteering;
void *CVehicle::operator new(size_t sz) { return CPools::GetVehiclePool()->New(); }
void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehiclePool()->New(handle); }
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index f9becda0..bfc6d95d 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -277,12 +277,12 @@ public:
bool IsTaxi(void) { return GetModelIndex() == MI_TAXI || GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_BORGNINE; }
AnimationId GetDriverAnim(void) { return IsCar() && bLowVehicle ? ANIM_CAR_LSIT : (IsBoat() && GetModelIndex() != MI_SPEEDER ? ANIM_DRIVE_BOAT : ANIM_CAR_SIT); }
- static bool &bWheelsOnlyCheat;
- static bool &bAllDodosCheat;
- static bool &bCheat3;
- static bool &bCheat4;
- static bool &bCheat5;
- static bool &m_bDisableMouseSteering;
+ static bool bWheelsOnlyCheat;
+ static bool bAllDodosCheat;
+ static bool bCheat3;
+ static bool bCheat4;
+ static bool bCheat5;
+ static bool m_bDisableMouseSteering;
};
static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error");
diff --git a/src/weapons/BulletInfo.cpp b/src/weapons/BulletInfo.cpp
index 54fa6844..81138c0f 100644
--- a/src/weapons/BulletInfo.cpp
+++ b/src/weapons/BulletInfo.cpp
@@ -2,4 +2,8 @@
#include "patcher.h"
#include "BulletInfo.h"
+WRAPPER void CBulletInfo::Initialise(void) { EAXJMP(0x558220); }
+WRAPPER void CBulletInfo::Shutdown(void) { EAXJMP(0x558450); }
+WRAPPER void CBulletInfo::AddBullet(CEntity *firingEntity, eWeaponType type, CVector pos, CVector velocity) { EAXJMP(0x558470); }
+WRAPPER void CBulletInfo::Update(void) { EAXJMP(0x558550); }
WRAPPER bool CBulletInfo::TestForSniperBullet(float x1, float x2, float y1, float y2, float z1, float z2) { EAXJMP(0x558D40); }
diff --git a/src/weapons/BulletInfo.h b/src/weapons/BulletInfo.h
index 3905b56d..b10ef0a1 100644
--- a/src/weapons/BulletInfo.h
+++ b/src/weapons/BulletInfo.h
@@ -1,7 +1,14 @@
#pragma once
+class CEntity;
+enum eWeaponType;
+
class CBulletInfo
{
public:
+ static void Initialise(void);
+ static void Shutdown(void);
+ static void AddBullet(CEntity *firingEntity, eWeaponType type, CVector pos, CVector velocity);
+ static void Update(void);
static bool TestForSniperBullet(float x1, float x2, float y1, float y2, float z1, float z2);
}; \ No newline at end of file
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 0f41264f..7b6b4170 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -1,23 +1,92 @@
#include "common.h"
#include "patcher.h"
#include "Weapon.h"
+#include "AnimBlendAssociation.h"
+#include "AudioManager.h"
+#include "BulletInfo.h"
+#include "Camera.h"
+#include "Coronas.h"
+#include "DMAudio.h"
+#include "Explosion.h"
+#include "General.h"
+#include "Glass.h"
+#include "Heli.h"
+#include "ModelIndices.h"
+#include "Object.h"
+#include "Pad.h"
+#include "Particle.h"
+#include "Ped.h"
+#include "PointLights.h"
+#include "Pools.h"
+#include "ProjectileInfo.h"
+#include "RpAnimBlend.h"
+#include "ShotInfo.h"
+#include "SpecialFX.h"
+#include "Stats.h"
+#include "TempColModels.h"
#include "Timer.h"
+#include "Vehicle.h"
+#include "WaterLevel.h"
#include "WeaponInfo.h"
-#include "Ped.h"
#include "World.h"
-WRAPPER void CWeapon::ShutdownWeapons(void) { EAXJMP(0x55C2F0); }
-WRAPPER void CWeapon::UpdateWeapons(void) { EAXJMP(0x55C310); }
-WRAPPER bool CWeapon::Fire(CEntity*, CVector*) { EAXJMP(0x55C380); }
-WRAPPER void CWeapon::FireFromCar(CAutomobile *car, bool left) { EAXJMP(0x55C940); }
-WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, float) { EAXJMP(0x55F770); }
-WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); }
-WRAPPER void CWeapon::DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end) { EAXJMP(0x563200); }
-WRAPPER void CWeapon::InitialiseWeapons(void) { EAXJMP(0x55C2D0); }
-WRAPPER void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage) { EAXJMP(0x563B00); }
+uint16 gReloadSampleTime[WEAPONTYPE_LAST_WEAPONTYPE] =
+{
+ 0, // UNARMED
+ 0, // BASEBALLBAT
+ 250, // COLT45
+ 400, // UZI
+ 650, // SHOTGUN
+ 300, // AK47
+ 300, // M16
+ 423, // SNIPERRIFLE
+ 400, // ROCKETLAUNCHER
+ 0, // FLAMETHROWER
+ 0, // MOLOTOV
+ 0, // GRENADE
+ 0, // DETONATOR
+ 0 // HELICANNON
+};
+
+CWeaponInfo *
+CWeapon::GetInfo()
+{
+ CWeaponInfo *info = CWeaponInfo::GetWeaponInfo(m_eWeaponType);
+ ASSERT(info!=nil);
+ return info;
+}
+
+void
+CWeapon::InitialiseWeapons(void)
+{
+ CWeaponInfo::Initialise();
+ CShotInfo::Initialise();
+ CExplosion::Initialise();
+ CProjectileInfo::Initialise();
+ CBulletInfo::Initialise();
+}
+
+void
+CWeapon::ShutdownWeapons(void)
+{
+ CWeaponInfo::Shutdown();
+ CShotInfo::Shutdown();
+ CExplosion::Shutdown();
+ CProjectileInfo::Shutdown();
+ CBulletInfo::Shutdown();
+}
void
-CWeapon::Initialise(eWeaponType type, int ammo)
+CWeapon::UpdateWeapons(void)
+{
+ CShotInfo::Update();
+ CExplosion::Update();
+ CProjectileInfo::Update();
+ CBulletInfo::Update();
+}
+
+void
+CWeapon::Initialise(eWeaponType type, int32 ammo)
{
m_eWeaponType = type;
m_eWeaponState = WEAPONSTATE_READY;
@@ -30,13 +99,1871 @@ CWeapon::Initialise(eWeaponType type, int ammo)
m_nTimer = 0;
}
+bool
+CWeapon::Fire(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+
+ CVector fireOffset(0.0f, 0.0f, 0.6f);
+ CVector *source = fireSource;
+
+ if ( !fireSource )
+ source = &(shooter->GetMatrix() * fireOffset);
+
+ if ( m_bAddRotOffset )
+ {
+ float heading = RADTODEG(shooter->GetForward().Heading());
+ float angle = DEGTORAD(heading);
+ (*source).x += -Sin(angle) * 0.15f;
+ (*source).y += Cos(angle) * 0.15f;
+ }
+
+ if ( m_eWeaponState != WEAPONSTATE_READY && m_eWeaponState != WEAPONSTATE_FIRING )
+ return false;
+
+ bool fired;
+
+ if ( GetInfo()->m_eWeaponFire != WEAPON_FIRE_MELEE )
+ {
+ if ( m_nAmmoInClip <= 0 )
+ return false;
+
+ switch ( m_eWeaponType )
+ {
+ case WEAPONTYPE_SHOTGUN:
+ {
+ fired = FireShotgun(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_COLT45:
+ case WEAPONTYPE_UZI:
+ case WEAPONTYPE_AK47:
+ {
+ fired = FireInstantHit(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_SNIPERRIFLE:
+ {
+ fired = FireSniper(shooter);
+
+ break;
+ }
+
+ case WEAPONTYPE_M16:
+ {
+ if ( TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON && shooter == FindPlayerPed() )
+ fired = FireM16_1stPerson(shooter);
+ else
+ fired = FireInstantHit(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_ROCKETLAUNCHER:
+ {
+ if ( shooter->IsPed() && ((CPed*)shooter)->m_pSeekTarget != nil )
+ {
+ float distToTarget = (shooter->GetPosition() - ((CPed*)shooter)->m_pSeekTarget->GetPosition()).Magnitude();
+
+ if ( distToTarget > 8.0f || ((CPed*)shooter)->IsPlayer() )
+ fired = FireProjectile(shooter, source, 0.0f);
+ else
+ fired = false;
+ }
+ else
+ fired = FireProjectile(shooter, source, 0.0f);
+
+ break;
+ }
+
+ case WEAPONTYPE_MOLOTOV:
+ case WEAPONTYPE_GRENADE:
+ {
+ if ( shooter == FindPlayerPed() )
+ {
+ fired = FireProjectile(shooter, source, ((CPlayerPed*)shooter)->m_fAttackButtonCounter*0.0375f);
+ if ( m_eWeaponType == WEAPONTYPE_GRENADE )
+ CStats::KgsOfExplosivesUsed++;
+ }
+ else if ( shooter->IsPed() && ((CPed*)shooter)->m_pSeekTarget != nil )
+ {
+ float distToTarget = (shooter->GetPosition() - ((CPed*)shooter)->m_pSeekTarget->GetPosition()).Magnitude();
+ float power = clamp((distToTarget-10.0f)*0.02f, 0.2f, 1.0f);
+
+ fired = FireProjectile(shooter, source, power);
+ }
+ else
+ fired = FireProjectile(shooter, source, 0.3f);
+
+ break;
+ }
+
+ case WEAPONTYPE_FLAMETHROWER:
+ {
+ fired = FireAreaEffect(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_DETONATOR:
+ {
+ CWorld::UseDetonator(shooter);
+ m_nAmmoTotal = 1;
+ m_nAmmoInClip = m_nAmmoTotal;
+ fired = true;
+
+ break;
+ }
+
+ case WEAPONTYPE_HELICANNON:
+ {
+ if ( (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_HELICANNON_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON )
+ && shooter == FindPlayerPed() )
+ {
+ fired = FireM16_1stPerson(shooter);
+ }
+ else
+ fired = FireInstantHit(shooter, source);
+
+ break;
+ }
+
+ default:
+ {
+ debug("Unknown weapon type, Weapon.cpp");
+ break;
+ }
+ }
+
+ if ( fired )
+ {
+ bool isPlayer = false;
+
+ if ( shooter->IsPed() )
+ {
+ CPed *shooterPed = (CPed*)shooter;
+
+ shooterPed->bIsShooting = true;
+
+ if ( shooterPed->IsPlayer() )
+ isPlayer = true;
+
+ DMAudio.PlayOneShot(shooterPed->m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+ }
+
+ if ( m_nAmmoInClip > 0 ) m_nAmmoInClip--;
+ if ( m_nAmmoTotal > 0 && (m_nAmmoTotal < 25000 || isPlayer) ) m_nAmmoTotal--;
+
+ if ( m_eWeaponState == WEAPONSTATE_READY && m_eWeaponType == WEAPONTYPE_FLAMETHROWER )
+ DMAudio.PlayOneShot(((CPhysical*)shooter)->m_audioEntityId, SOUND_WEAPON_FLAMETHROWER_FIRE, 0.0f);
+
+ m_eWeaponState = WEAPONSTATE_FIRING;
+ }
+
+ if ( m_nAmmoInClip == 0 )
+ {
+ if ( m_nAmmoTotal == 0 )
+ return true;
+
+ m_eWeaponState = WEAPONSTATE_RELOADING;
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload;
+
+ if ( shooter == FindPlayerPed() )
+ {
+ if ( CWorld::Players[CWorld::PlayerInFocus].m_bFastReload )
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload / 4;
+ }
+
+ return true;
+ }
+
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ if ( shooter == FindPlayerPed() )
+ CStats::RoundsFiredByPlayer++;
+ }
+ else
+ {
+ if ( m_eWeaponState != WEAPONSTATE_FIRING )
+ {
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload;
+ m_eWeaponState = WEAPONSTATE_FIRING;
+ }
+
+ FireMelee(shooter, *source);
+ }
+
+ if ( m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT )
+ return true;
+ else
+ return fired;
+}
+
+bool
+CWeapon::FireFromCar(CAutomobile *shooter, bool left)
+{
+ ASSERT(shooter!=nil);
+
+ if ( m_eWeaponState != WEAPONSTATE_READY && m_eWeaponState != WEAPONSTATE_FIRING )
+ return false;
+
+ if ( m_nAmmoInClip <= 0 )
+ return false;
+
+ if ( FireInstantHitFromCar(shooter, left) )
+ {
+ DMAudio.PlayOneShot(shooter->m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+
+ if ( m_nAmmoInClip > 0 ) m_nAmmoInClip--;
+ if ( m_nAmmoTotal < 25000 && m_nAmmoTotal > 0 ) m_nAmmoTotal--;
+
+ m_eWeaponState = WEAPONSTATE_FIRING;
+
+ if ( m_nAmmoInClip == 0 )
+ {
+ if ( m_nAmmoTotal == 0 )
+ return true;
+
+ m_eWeaponState = WEAPONSTATE_RELOADING;
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload;
+
+ return true;
+ }
+
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ if ( shooter == FindPlayerVehicle() )
+ CStats::RoundsFiredByPlayer++;
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireMelee(CEntity *shooter, CVector &fireSource)
+{
+ ASSERT(shooter!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ bool anim2Playing = false;
+ if ( RpAnimBlendClumpGetAssociation(shooter->GetClump(), info->m_Anim2ToPlay) )
+ anim2Playing = true;
+
+ ASSERT(shooter->IsPed());
+
+ CPed *shooterPed = (CPed*)shooter;
+
+ for ( int32 i = 0; i < shooterPed->m_numNearPeds; i++ )
+ {
+ CPed *victimPed = shooterPed->m_nearPeds[i];
+ ASSERT(victimPed!=nil);
+
+ if ( (victimPed->m_nPedType != shooterPed->m_nPedType || victimPed == shooterPed->m_pSeekTarget)
+ && victimPed != shooterPed->m_leader || !(CGeneral::GetRandomNumber() & 31) )
+ {
+ bool collided = false;
+
+ CColModel *victimPedCol = &CTempColModels::ms_colModelPed1;
+ if ( victimPed->OnGround() || !victimPed->IsPedHeadAbovePos(-0.3f) )
+ victimPedCol = &CTempColModels::ms_colModelPedGroundHit;
+
+
+ float victimPedRadius = victimPed->GetBoundRadius() + info->m_fRadius;
+ if ( victimPed->bUsesCollision || victimPed->Dead() || victimPed->Driving() )
+ {
+ CVector victimPedPos = victimPed->GetPosition();
+ if ( SQR(victimPedRadius) > (victimPedPos-(*fireSource)).MagnitudeSqr() )
+ {
+ CVector collisionDist;
+
+ int32 s = 0;
+ while ( s < victimPedCol->numSpheres )
+ {
+ CColSphere *sphere = &victimPedCol->spheres[s];
+ collisionDist = victimPedPos+sphere->center-(*fireSource);
+
+ if ( SQR(sphere->radius + info->m_fRadius) > collisionDist.MagnitudeSqr() )
+ {
+ collided = true;
+ break;
+ }
+ s++;
+ }
+
+ if ( !(victimPed->IsPlayer() && victimPed->GetPedState() == PED_GETUP) )
+ {
+ if ( collided )
+ {
+ float victimPedHealth = victimPed->m_fHealth;
+ CVector bloodPos = fireSource + (collisionDist*0.7f);
+
+ CVector2D posOffset(shooterPed->GetPosition().x-victimPedPos.x, shooterPed->GetPosition().y-victimPedPos.y);
+
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ bool isBat = m_eWeaponType == WEAPONTYPE_BASEBALLBAT;
+
+ if ( !victimPed->DyingOrDead() )
+ victimPed->ReactToAttack(shooterPed);
+
+ uint8 hitLevel = HITLEVEL_HIGH;
+ if ( isBat && victimPed->OnGround() )
+ hitLevel = HITLEVEL_GROUND;
+
+ victimPed->StartFightDefend(localDir, hitLevel, 10);
+
+ if ( !victimPed->DyingOrDead() )
+ {
+ if ( shooterPed->IsPlayer() && isBat && anim2Playing )
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, 100.0f, PEDPIECE_TORSO, localDir);
+ else if ( shooterPed->IsPlayer() && ((CPlayerPed*)shooterPed)->m_bAdrenalineActive )
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, 3.5f*info->m_nDamage, PEDPIECE_TORSO, localDir);
+ else
+ {
+ if ( victimPed->IsPlayer() && isBat ) // wtf, it's not fair
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, 2.0f*info->m_nDamage, PEDPIECE_TORSO, localDir);
+ else
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, info->m_nDamage, PEDPIECE_TORSO, localDir);
+ }
+ }
+
+ if ( CGame::nastyGame )
+ {
+ if ( victimPed->GetIsOnScreen() )
+ {
+ CVector dir = collisionDist * RecipSqrt(1.0f, 10.0f*collisionDist.MagnitudeSqr());
+
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+
+ if ( isBat )
+ {
+ dir.x += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ dir.y += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+
+ dir.x += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ dir.y += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+ }
+ }
+ }
+
+ if ( !victimPed->OnGround() )
+ {
+ if ( victimPed->m_fHealth > 0.0f
+ && (victimPed->m_fHealth < 20.0f && victimPedHealth > 20.0f || isBat && !victimPed->IsPlayer()) )
+ {
+ posOffset.Normalise();
+ victimPed->bIsStanding = false;
+ victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 3.0f);
+
+ if ( isBat && victimPed->IsPlayer() )
+ victimPed->SetFall(3000, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+ else
+ victimPed->SetFall(1500, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+
+ shooterPed->m_pSeekTarget = victimPed;
+ shooterPed->m_pSeekTarget->RegisterReference(&shooterPed->m_pSeekTarget);
+ }
+ }
+ else if (victimPed->Dying() && !anim2Playing)
+ {
+ posOffset.Normalise();
+ victimPed->bIsStanding = false;
+ victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 3.0f);
+ }
+
+ m_eWeaponState = WEAPONSTATE_MELEE_MADECONTACT;
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_ASSAULT_POLICE, EVENT_ENTITY_PED, victimPed, shooterPed, 2000);
+ else
+ CEventList::RegisterEvent(EVENT_ASSAULT, EVENT_ENTITY_PED, victimPed, shooterPed, 2000);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ CVector source, target;
+ CColPoint point;
+ CEntity *victim = nil;
+
+ float heading = RADTODEG(shooter->GetForward().Heading());
+ float angle = DEGTORAD(heading);
+
+ CVector2D ahead(-Sin(angle), Cos(angle));
+ ahead.Normalise();
+
+ CVector vel = ((CPed *)shooter)->m_vecMoveSpeed;
+ int32 shooterMoving = false;
+ if ( Abs(vel.x) > 0.0f && Abs(vel.y) > 0.0f )
+ shooterMoving = true;
+
+ if ( shooter == FindPlayerPed() )
+ {
+ static float prev_heading = 0.0f;
+ prev_heading = ((CPed*)shooter)->m_fRotationCur;
+ }
+
+ if ( shooter->IsPed() && ((CPed *)shooter)->m_pPointGunAt )
+ {
+ CPed *shooterPed = (CPed *)shooter;
+ if ( shooterPed->m_pedIK.m_flags & CPedIK::GUN_POINTED_SUCCESSFULLY )
+ {
+ int32 accuracy = shooterPed->m_wepAccuracy;
+ int32 inaccuracy = 100-accuracy;
+
+ if ( accuracy != 100 )
+ FindPlayerPed(); //what ?
+
+ CPed *threatAttack = (CPed*)shooterPed->m_pPointGunAt;
+ if ( threatAttack->IsPed() )
+ {
+ threatAttack->m_pedIK.GetComponentPosition(target, PED_MID);
+ threatAttack->ReactToPointGun(shooter);
+ }
+ else
+ target = threatAttack->GetPosition();
+
+ target -= *fireSource;
+ target *= info->m_fRange / target.Magnitude();
+ target += *fireSource;
+
+ if ( inaccuracy != 0 )
+ {
+ target.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f) * inaccuracy;
+ target.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f) * inaccuracy;
+ target.z += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f) * inaccuracy;
+ }
+
+ CWorld::bIncludeDeadPeds = true;
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ CWorld::bIncludeDeadPeds = false;
+ }
+ else
+ {
+ target.x = info->m_fRange;
+ target.y = 0.0f;
+ target.z = 0.0f;
+
+ for (RwFrame *i = shooterPed->GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i))
+ RwV3dTransformPoints(target, target, 1, RwFrameGetMatrix(i));
+
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ }
+ }
+ else if ( shooter == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam() )
+ {
+ CVector src, trgt;
+ TheCamera.Find3rdPersonCamTargetVector(info->m_fRange, *fireSource, src, trgt);
+
+ CWorld::bIncludeDeadPeds = true;
+ ProcessLineOfSight(src, trgt,point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ CWorld::bIncludeDeadPeds = false;
+
+ int32 rotSpeed = 1;
+ if ( m_eWeaponType == WEAPONTYPE_M16 )
+ rotSpeed = 4;
+
+ CVector bulletPos;
+ if ( CHeli::TestBulletCollision(&src, &trgt, &bulletPos, 4) )
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, bulletPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, rotSpeed);
+ }
+ }
+ else
+ {
+ float shooterHeading = RADTODEG(shooter->GetForward().Heading());
+ float shooterAngle = DEGTORAD(shooterHeading);
+
+ CVector2D rotOffset(-Sin(shooterAngle), Cos(shooterAngle));
+ rotOffset.Normalise();
+
+ target = *fireSource;
+ target.x = rotOffset.x * info->m_fRange;
+ target.y = rotOffset.y * info->m_fRange;
+
+ if ( shooter->IsPed() )
+ DoDoomAiming(shooter, fireSource, &target);
+
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+
+ int32 rotSpeed = 1;
+ if ( m_eWeaponType == WEAPONTYPE_M16 )
+ rotSpeed = 4;
+
+ CVector bulletPos;
+ if ( CHeli::TestBulletCollision(fireSource, &target, &bulletPos, 4) )
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, bulletPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, rotSpeed);
+ }
+ }
+
+ if ( victim && shooter->IsPed() && victim == ((CPed*)shooter)->m_leader )
+ return false;
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed *)shooter, 1000);
+
+ if ( shooter == FindPlayerPed() )
+ {
+ CStats::InstantHitsFiredByPlayer++;
+ if ( !(CTimer::GetFrameCounter() & 3) )
+ MakePedsJumpAtShot((CPhysical*)shooter, fireSource, &target);
+ }
+
+ switch ( m_eWeaponType )
+ {
+ case WEAPONTYPE_AK47:
+ {
+ static uint8 counter = 0;
+
+ if ( !(++counter & 1) )
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.10f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.08f);
+ gunflashPos += CVector(0.05f*ahead.x, 0.05f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+
+ CVector gunsmokePos = *fireSource;
+ float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*rnd, ahead.y*rnd, 0.0f));
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.5f*ahead.x, 0.5f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.018f);
+ }
+
+ break;
+ }
+
+ case WEAPONTYPE_M16:
+ {
+ static uint8 counter = 0;
+
+ if ( !(++counter & 1) )
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.08f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos.z += 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos.z += 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+ gunflashPos.z += 0.03f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos.z -= 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos.z -= 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+ gunflashPos.z -= 0.03f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ CVector offset = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ offset.Normalise2D();
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos += CVector(0.06f*offset.x, 0.06f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos += CVector(0.04f*offset.x, 0.04f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos += CVector(0.03f*offset.x, 0.03f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos -= CVector(0.06f*offset.x, 0.06f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos -= CVector(0.04f*offset.x, 0.04f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos -= CVector(0.03f*offset.x, 0.03f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ CVector gunsmokePos = *fireSource;
+ float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*rnd, ahead.y*rnd, 0.0f));
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.65f*ahead.x, 0.65f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.02f);
+ }
+
+ break;
+ }
+
+ case WEAPONTYPE_UZI:
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+
+ if ( shooterMoving )
+ gunflashPos += CVector(1.5f*vel.x, 1.5f*vel.y, 0.0f);
+
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.07f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.05f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos += CVector(0.03f*ahead.x, 0.03f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos += CVector(0.03f*ahead.x, 0.03f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+ gunflashPos += CVector(0.02f*ahead.x, 0.02f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.01f);
+
+ CVector gunsmokePos = *fireSource;
+ float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*rnd, ahead.y*rnd, 0.0f));
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.2f*ahead.x, 0.2f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.015f);
+
+ break;
+ }
+
+ case WEAPONTYPE_COLT45:
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+
+ if ( shooterMoving )
+ gunflashPos += CVector(1.5f*vel.x, 1.5f*vel.y, 0.0f);
+
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ CVector gunsmokePos = *fireSource;
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*0.10f, ahead.y*0.10f, 0.0f), nil, 0.005f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*0.15f, ahead.y*0.15f, 0.0f), nil, 0.015f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*0.20f, ahead.y*0.20f, 0.0f), nil, 0.025f);
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.2f*ahead.x, 0.2f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.015f);
+
+ break;
+ }
+ }
+
+ DoBulletImpact(shooter, victim, fireSource, &target, &point, ahead);
+
+ return true;
+}
+
+void
+CWeapon::AddGunshell(CEntity *shooter, CVector const &source, CVector2D const &direction, float size)
+{
+ ASSERT(shooter!=nil);
+
+ if ( shooter == nil)
+ return;
+
+ CVector dir(direction.x*0.05f, direction.y*0.05f, CGeneral::GetRandomNumberInRange(0.02f, 0.08f));
+
+ static CVector prevEntityPosition(0.0f, 0.0f, 0.0f);
+ CVector entityPosition = shooter->GetPosition();
+
+ CVector diff = entityPosition - prevEntityPosition;
+
+ if ( Abs(diff.x)+Abs(diff.y)+Abs(diff.z) > 1.5f )
+ {
+ prevEntityPosition = entityPosition;
+
+ CParticle::AddParticle(PARTICLE_GUNSHELL_FIRST,
+ source, dir, nil, size, CGeneral::GetRandomNumberInRange(-20.0f, 20.0f));
+ }
+ else
+ {
+ CParticle::AddParticle(PARTICLE_GUNSHELL,
+ source, dir, nil, size, CGeneral::GetRandomNumberInRange(-20.0f, 20.0f));
+ }
+}
+
+void
+CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim,
+ CVector *source, CVector *target, CColPoint *point, CVector2D ahead)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+ ASSERT(point!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ if ( victim )
+ {
+ CGlass::WasGlassHitByBullet(victim, point->point);
+
+ CVector traceTarget = point->point;
+ CBulletTraces::AddTrace(source, &traceTarget);
+
+ if ( shooter != nil )
+ {
+ if ( shooter == FindPlayerPed() )
+ {
+ if ( victim->IsPed() || victim->IsVehicle() )
+ CStats::InstantHitsHitByPlayer++;
+ }
+ }
+
+ if ( victim->IsPed() && ((CPed*)shooter)->m_nPedType != ((CPed*)victim)->m_nPedType || ((CPed*)shooter)->m_nPedType == PEDTYPE_PLAYER2 )
+ {
+ CPed *victimPed = (CPed *)victim;
+ if ( !victimPed->OnGround() && victim != shooter )
+ {
+ if ( victimPed->DoesLOSBulletHitPed(*point) )
+ {
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset(source->x-pos.x, source->y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ReactToAttack(shooter);
+
+ if ( !victimPed->IsPedInControl() || victimPed->bIsDucking )
+ {
+ victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir);
+ }
+ else
+ {
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN || m_eWeaponType == WEAPONTYPE_HELICANNON )
+ {
+ posOffset.Normalise();
+ victimPed->bIsStanding = false;
+
+ victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 5.0f);
+ victimPed->SetFall(1500, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+
+ victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir);
+ }
+ else
+ {
+ if ( victimPed->IsPlayer() )
+ {
+ CPlayerPed *victimPlayer = (CPlayerPed *)victimPed;
+ if ( victimPlayer->m_nHitAnimDelayTimer < CTimer::GetTimeInMilliseconds() )
+ {
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+
+ if ( m_eWeaponType == WEAPONTYPE_AK47 || m_eWeaponType == WEAPONTYPE_M16 )
+ victimPlayer->m_nHitAnimDelayTimer = CTimer::GetTimeInMilliseconds() + 2500;
+ else
+ victimPlayer->m_nHitAnimDelayTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ }
+ }
+ else
+ {
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+ }
+
+ victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir);
+ }
+ }
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_SHOOT_COP, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+ else
+ CEventList::RegisterEvent(EVENT_SHOOT_PED, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+
+ if ( CGame::nastyGame )
+ {
+ uint8 bloodAmount = 8;
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN || m_eWeaponType == WEAPONTYPE_HELICANNON )
+ bloodAmount = 32;
+
+ CVector dir = (point->point - victim->GetPosition()) * 0.01f;
+ dir.z = 0.01f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ for ( uint8 i = 0; i < bloodAmount; i++ )
+ CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point->point, dir);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( CGame::nastyGame )
+ {
+ CVector dir = (point->point - victim->GetPosition()) * 0.01f;
+ dir.z = 0.01f;
+
+ if ( victim->GetIsOnScreen() )
+ {
+ for ( int32 i = 0; i < 8; i++ )
+ CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point->point + CVector(0.0f, 0.0f, 0.15f), dir);
+ }
+
+ if ( victimPed->Dead() )
+ {
+ CAnimBlendAssociation *asoc;
+ if ( RpAnimBlendClumpGetFirstAssociation(victimPed->GetClump(), ASSOC_FLAG800) )
+ asoc = CAnimManager::BlendAnimation(victimPed->GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f);
+ else
+ asoc = CAnimManager::BlendAnimation(victimPed->GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT, 8.0f);
+
+ if ( asoc )
+ {
+ asoc->SetCurrentTime(0.0f);
+ asoc->flags |= ASSOC_RUNNING;
+ asoc->flags &= ~ASSOC_FADEOUTWHENDONE;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f);
+
+ CVector dist = point->point - (*source);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 2.0f) * CVector(ahead.x, ahead.y, 0.0f);
+ CVector smokePos = *source + offset;
+
+ smokePos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.z += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ ((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage);
+
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f);
+
+ CVector dist = point->point - (*source);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 0.5f) * CVector(ahead.x, ahead.y, 0.0f);
+ CVector smokePos = *source + offset;
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ if ( shooter->IsPed() )
+ {
+ CPed *shooterPed = (CPed *)shooter;
+
+ if ( shooterPed->bNotAllowedToDuck )
+ {
+ if ( shooterPed->bKindaStayInSamePlace && victim != shooterPed->m_pPointGunAt )
+ {
+ shooterPed->bKindaStayInSamePlace = false;
+ shooterPed->m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + 15000;
+ }
+ }
+ }
+
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ for ( int32 i = 0; i < 8; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f);
+
+ CObject *victimObject = (CObject *)victim;
+
+ if ( !victimObject->bInfiniteMass )
+ {
+ if ( victimObject->bIsStatic && victimObject->m_fUprootLimit <= 0.0f )
+ {
+ victimObject->bIsStatic = false;
+ victimObject->AddToMovingList();
+ }
+
+ if ( !victimObject->bIsStatic )
+ {
+ CVector moveForce = point->normal*-4.0f;
+ victimObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z);
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point->point);
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point->point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point->point);
+ break;
+ }
+ }
+ }
+ else
+ CBulletTraces::AddTrace(source, target);
+
+ if ( shooter == FindPlayerPed() )
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z);
+
+ BlowUpExplosiveThings(victim);
+}
+
+bool
+CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ float heading = RADTODEG(shooter->GetForward().Heading());
+ float angle = DEGTORAD(heading);
+
+ CVector2D rotOffset(-Sin(angle), Cos(angle));
+ rotOffset.Normalise();
+
+ CVector gunflashPos = *fireSource;
+ gunflashPos += CVector(rotOffset.x*0.1f, rotOffset.y*0.1f, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f);
+ gunflashPos += CVector(rotOffset.x*0.1f, rotOffset.y*0.1f, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.15f);
+ gunflashPos += CVector(rotOffset.x*0.1f, rotOffset.y*0.1f, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.2f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, *fireSource, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f);
+
+ CVector gunsmokePos = *fireSource;
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.10f, rotOffset.y*0.10f, 0.0f), nil, 0.1f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.15f, rotOffset.y*0.15f, 0.0f), nil, 0.1f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.20f, rotOffset.y*0.20f, 0.0f), nil, 0.1f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.25f, rotOffset.y*0.25f, 0.0f), nil, 0.1f);
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed*)shooter, 1000);
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, *fireSource, CVector(0.0, 0.0, 0.0), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ float shooterAngle;
+
+ if ( shooter->IsPed() && ((CPed*)shooter)->m_pPointGunAt != nil )
+ {
+ CEntity *threatAttack = ((CPed*)shooter)->m_pPointGunAt;
+ shooterAngle = CGeneral::GetAngleBetweenPoints(threatAttack->GetPosition().x, threatAttack->GetPosition().y,
+ (*fireSource).x, (*fireSource).y);
+ }
+ else
+ shooterAngle = RADTODEG(shooter->GetForward().Heading());
+
+
+ for ( int32 i = 0; i < 5; i++ ) // five shoots at once
+ {
+ float shootAngle = DEGTORAD(7.5f*i + shooterAngle - 15.0f);
+ CVector2D shootRot(-Sin(shootAngle), Cos(shootAngle));
+
+ CVector source, target;
+ CColPoint point;
+ CEntity *victim;
+
+ if ( shooter == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam() )
+ {
+ TheCamera.Find3rdPersonCamTargetVector(1.0f, *fireSource, source, target);
+ CVector Left = CrossProduct(TheCamera.Cams[TheCamera.ActiveCam].Front, TheCamera.Cams[TheCamera.ActiveCam].Up);
+
+ float f = float(i - 2) * (DEGTORAD(7.5f) / 2);
+ target = f * Left + target - source;
+ target *= info->m_fRange;
+ target += source;
+
+ ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ }
+ else
+ {
+ target = *fireSource;
+ target.x += shootRot.x * info->m_fRange;
+ target.y += shootRot.y * info->m_fRange;
+
+ if ( shooter->IsPed() )
+ {
+ CPed *shooterPed = (CPed *)shooter;
+
+ if ( shooterPed->m_pPointGunAt == nil )
+ DoDoomAiming(shooter, fireSource, &target);
+ else
+ {
+ float distToTarget = (shooterPed->m_pPointGunAt->GetPosition() - (*fireSource)).Magnitude2D();
+ target.z += info->m_fRange / distToTarget * (shooterPed->m_pPointGunAt->GetPosition().z - target.z);
+ }
+ }
+
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ }
+
+ if ( victim )
+ {
+ CGlass::WasGlassHitByBullet(victim, point.point);
+
+ CBulletTraces::AddTrace(fireSource, &point.point);
+
+ if ( victim->IsPed() )
+ {
+ CPed *victimPed = (CPed *)victim;
+ if ( !victimPed->OnGround() && victim != shooter && victimPed->DoesLOSBulletHitPed(point) )
+ {
+ bool cantStandup = true;
+
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset((*fireSource).x-pos.x, (*fireSource).y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ReactToAttack(FindPlayerPed());
+
+ posOffset.Normalise();
+
+ if ( victimPed->m_getUpTimer > (CTimer::GetTimeInMilliseconds() - 3000) )
+ cantStandup = false;
+
+ if ( victimPed->bIsStanding && cantStandup )
+ {
+ victimPed->bIsStanding = false;
+
+ victimPed->ApplyMoveForce(posOffset.x*-6.0f, posOffset.y*-6.0f, 5.0f);
+ }
+ else
+ victimPed->ApplyMoveForce(posOffset.x*-2.0f, posOffset.y*-2.0f, 0.0f);
+
+ if ( cantStandup )
+ victimPed->SetFall(1500, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+
+ victimPed->InflictDamage(nil, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point.pieceB, localDir);
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_SHOOT_COP, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+ else
+ CEventList::RegisterEvent(EVENT_SHOOT_PED, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+
+ if ( CGame::nastyGame )
+ {
+ uint8 bloodAmount = 8;
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN )
+ bloodAmount = 32;
+
+ CVector dir = (point.point - victim->GetPosition()) * 0.01f;
+ dir.z = 0.01f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ for ( uint8 i = 0; i < bloodAmount; i++ )
+ CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point.point, dir);
+ }
+ }
+ }
+ }
+ else
+ {
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_VEHICLE:
+ {
+ ((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage);
+
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal*0.05f);
+
+ CVector dist = point.point - (*fireSource);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 2.0f) * CVector(shootRot.x, shootRot.y, 0.0f);
+ CVector smokePos = *fireSource + offset;
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ break;
+ }
+
+ case ENTITY_TYPE_BUILDING:
+ case ENTITY_TYPE_OBJECT:
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal*0.05f);
+
+ CVector dist = point.point - (*fireSource);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 2.0f) * CVector(shootRot.x, shootRot.y, 0.0f);
+ CVector smokePos = *fireSource + offset;
+
+ smokePos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.z += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ if ( victim->IsObject() )
+ {
+ CObject *victimObject = (CObject *)victim;
+
+ if ( !victimObject->bInfiniteMass )
+ {
+ if ( victimObject->bIsStatic && victimObject->m_fUprootLimit <= 0.0f )
+ {
+ victimObject->bIsStatic = false;
+ victimObject->AddToMovingList();
+ }
+
+ if ( !victimObject->bIsStatic )
+ {
+ CVector moveForce = point.normal*-5.0f;
+ victimObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z);
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point.point);
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point.point);
+ break;
+ }
+ }
+ }
+ else
+ {
+ CVector traceTarget = *fireSource;
+ traceTarget += (target - (*fireSource)) * min(info->m_fRange, 30.0f) / info->m_fRange;
+ CBulletTraces::AddTrace(fireSource, &traceTarget);
+ }
+ }
+
+ if ( shooter == FindPlayerPed() )
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z);
+
+ return true;
+}
+
+bool
+CWeapon::FireProjectile(CEntity *shooter, CVector *fireSource, float power)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CVector source, target;
+
+ if ( m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER )
+ {
+ source = *fireSource;
+
+ if ( shooter->IsPed() && ((CPed*)shooter)->IsPlayer() )
+ {
+ int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+ if (!( mode == CCam::MODE_M16_1STPERSON
+ || mode == CCam::MODE_SNIPER
+ || mode == CCam::MODE_ROCKETLAUNCHER
+ || mode == CCam::MODE_M16_1STPERSON_RUNABOUT
+ || mode == CCam::MODE_SNIPER_RUNABOUT
+ || mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) )
+ {
+ return false;
+ }
+
+ *fireSource += TheCamera.Cams[TheCamera.ActiveCam].Front;
+ }
+ else
+ *fireSource += shooter->GetForward();
+
+ target = *fireSource;
+ }
+ else
+ {
+ float dot = DotProduct(*fireSource-shooter->GetPosition(), shooter->GetForward());
+
+ if ( dot < 0.3f )
+ *fireSource += (0.3f-dot) * shooter->GetForward();
+
+ target = *fireSource;
+
+ if ( target.z - shooter->GetPosition().z > 0.0f )
+ target += 0.6f*shooter->GetForward();
+
+ source = *fireSource - shooter->GetPosition();
+
+ source = *fireSource - DotProduct(source, shooter->GetForward()) * shooter->GetForward();
+ }
+
+ if ( !CWorld::GetIsLineOfSightClear(source, target, true, true, false, true, false, false, false) )
+ {
+ if ( m_eWeaponType != WEAPONTYPE_GRENADE )
+ CProjectileInfo::RemoveNotAdd(shooter, m_eWeaponType, *fireSource);
+ else
+ {
+ if ( shooter->IsPed() )
+ {
+ source = shooter->GetPosition() - shooter->GetForward();
+ source.z -= 0.4f;
+
+ if ( !CWorld::TestSphereAgainstWorld(source, 0.5f, nil, false, false, true, false, false, false) )
+ CProjectileInfo::AddProjectile(shooter, m_eWeaponType, source, 0.0f);
+ else
+ CProjectileInfo::RemoveNotAdd(shooter, m_eWeaponType, *fireSource);
+ }
+ }
+ }
+ else
+ CProjectileInfo::AddProjectile(shooter, m_eWeaponType, *fireSource, power);
+
+ return true;
+}
+
+void
+CWeapon::GenerateFlameThrowerParticles(CVector pos, CVector dir)
+{
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+}
+
+bool
+CWeapon::FireAreaEffect(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ float heading = RADTODEG(shooter->GetForward().Heading());
+
+ CVector source;
+ CVector target;
+ CVector dir;
+
+ if ( shooter == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam() )
+ {
+ TheCamera.Find3rdPersonCamTargetVector(info->m_fRange, *fireSource, source, target);
+ float norm = (1.0f / info->m_fRange);
+ dir = (target - source) * norm;
+ }
+ else
+ {
+ float angle = DEGTORAD(heading);
+ dir = CVector(-Sin(angle)*0.5f, Cos(angle)*0.5f, 0.0f);
+ target = *fireSource + dir;
+ }
+
+ CShotInfo::AddShot(shooter, m_eWeaponType, *fireSource, target);
+ CWeapon::GenerateFlameThrowerParticles(*fireSource, dir);
+
+ return true;
+}
+
+bool
+CWeapon::FireSniper(CEntity *shooter)
+{
+ ASSERT(shooter!=nil);
+
+ int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+ if (!( mode == CCam::MODE_M16_1STPERSON
+ || mode == CCam::MODE_SNIPER
+ || mode == CCam::MODE_ROCKETLAUNCHER
+ || mode == CCam::MODE_M16_1STPERSON_RUNABOUT
+ || mode == CCam::MODE_SNIPER_RUNABOUT
+ || mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) )
+ {
+ return false;
+ }
+
+#ifndef FIX_BUGS
+ CWeaponInfo *info = GetInfo(); //unused
+#endif
+
+ CCam *cam = &TheCamera.Cams[TheCamera.ActiveCam];
+ ASSERT(cam!=nil);
+
+ CVector source = cam->Source;
+ CVector dir = cam->Front;
+
+ if ( DotProduct(dir, CVector(0.0f, -0.9894f, 0.145f)) > 0.997f )
+ CCoronas::bSmallMoon = !CCoronas::bSmallMoon;
+
+ dir.Normalise();
+ dir *= 16.0f;
+
+ CBulletInfo::AddBullet(shooter, m_eWeaponType, source, dir);
+
+ if ( shooter == FindPlayerPed() )
+ CStats::InstantHitsFiredByPlayer++;
+
+ if ( shooter == FindPlayerPed() )
+ {
+ CPad::GetPad(0)->StartShake_Distance(240, 128,
+ FindPlayerPed()->GetPosition().x,
+ FindPlayerPed()->GetPosition().y,
+ FindPlayerPed()->GetPosition().z);
+
+ CamShakeNoPos(&TheCamera, 0.2f);
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireM16_1stPerson(CEntity *shooter)
+{
+ ASSERT(shooter!=nil);
+
+ int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+
+ if (!( mode == CCam::MODE_M16_1STPERSON
+ || mode == CCam::MODE_SNIPER
+ || mode == CCam::MODE_ROCKETLAUNCHER
+ || mode == CCam::MODE_M16_1STPERSON_RUNABOUT
+ || mode == CCam::MODE_SNIPER_RUNABOUT
+ || mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT
+ || mode == CCam::MODE_HELICANNON_1STPERSON) )
+ {
+ return false;
+ }
+
+ CWeaponInfo *info = GetInfo();
+
+ CColPoint point;
+ CEntity *victim;
+
+ CWorld::bIncludeCarTyres = true;
+ CWorld::pIgnoreEntity = shooter;
+ CWorld::bIncludeDeadPeds = true;
+
+ CCam *cam = &TheCamera.Cams[TheCamera.ActiveCam];
+ ASSERT(cam!=nil);
+
+ CVector source = cam->Source;
+ CVector target = cam->Front*info->m_fRange + source;
+
+ ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ CWorld::bIncludeDeadPeds = false;
+ CWorld::pIgnoreEntity = nil;
+ CWorld::bIncludeCarTyres = false;
+
+ CVector2D front(cam->Front.x, cam->Front.y);
+ front.Normalise();
+
+ DoBulletImpact(shooter, victim, &source, &target, &point, front);
+
+ CVector bulletPos;
+ if ( CHeli::TestBulletCollision(&source, &target, &bulletPos, 4) )
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, bulletPos, CVector(0.0f, 0.0f, 0.0f));
+ }
+
+ if ( shooter == FindPlayerPed() )
+ {
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z);
+
+ if ( m_eWeaponType == WEAPONTYPE_M16 )
+ {
+ TheCamera.Cams[TheCamera.ActiveCam].Beta += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0003f;
+ TheCamera.Cams[TheCamera.ActiveCam].Alpha += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0003f;
+ }
+ else if ( m_eWeaponType == WEAPONTYPE_HELICANNON )
+ {
+ TheCamera.Cams[TheCamera.ActiveCam].Beta += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0001f;
+ TheCamera.Cams[TheCamera.ActiveCam].Alpha += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0001f;
+ }
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireInstantHitFromCar(CAutomobile *shooter, bool left)
+{
+ CWeaponInfo *info = GetInfo();
+
+ CVehicleModelInfo *modelInfo = shooter->GetModelInfo();
+
+ #define FRONTSEATPOS() (&(shooter->IsBoat() ? modelInfo->m_positions[BOAT_POS_FRONTSEAT] : modelInfo->m_positions[CAR_POS_FRONTSEAT]))
+
+ CVector source, target;
+ if ( left )
+ {
+ source = shooter->GetMatrix() * CVector(-shooter->GetColModel()->boundingBox.max.x + -0.2f,
+ float(CGeneral::GetRandomNumber() & 255) * 0.001f + FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed;
+
+
+ target = shooter->GetMatrix() * CVector(-info->m_fRange,
+ FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ }
+ else
+ {
+ source = shooter->GetMatrix() * CVector(shooter->GetColModel()->boundingBox.max.x + 0.2f,
+ float(CGeneral::GetRandomNumber() & 255) * 0.001f + FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed;
+
+ target = shooter->GetMatrix() * CVector(info->m_fRange,
+ FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ }
+ #undef FRONTSEATPOS
+
+ if ( TheCamera.GetLookingLRBFirstPerson() && !left )
+ {
+ source -= 0.3f * shooter->GetForward();
+ target -= 0.3f * shooter->GetForward();
+ }
+
+ target += CVector(float(CGeneral::GetRandomNumber()&255)*0.01f-1.28f,
+ float(CGeneral::GetRandomNumber()&255)*0.01f-1.28f,
+ float(CGeneral::GetRandomNumber()&255)*0.01f-1.28f);
+
+ DoDriveByAutoAiming(FindPlayerPed(), &source, &target);
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, FindPlayerPed(), FindPlayerPed(), 1000);
+
+ if ( !TheCamera.GetLookingLRBFirstPerson() )
+ CParticle::AddParticle(PARTICLE_GUNFLASH, source, CVector(0.0f, 0.0f, 0.0f));
+ else
+ CamShakeNoPos(&TheCamera, 0.01f);
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_VEHICLE, shooter, FindPlayerPed(), 1000);
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, source, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CColPoint point;
+ CEntity *victim;
+ ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+
+ if ( !(CTimer::GetFrameCounter() & 3) )
+ MakePedsJumpAtShot(shooter, &source, &target);
+
+ if ( victim )
+ {
+ CVector traceTarget = point.point;
+ CBulletTraces::AddTrace(&source, &traceTarget);
+
+ if ( victim->IsPed() )
+ {
+ CPed *victimPed = (CPed*)victim;
+
+ if ( !victimPed->DyingOrDead() && victim != (CEntity *)shooter )
+ {
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset(source.x-pos.x, source.y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ReactToAttack(FindPlayerPed());
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+
+ victimPed->InflictDamage(shooter, WEAPONTYPE_UZI_DRIVEBY, 3*info->m_nDamage, (ePedPieceTypes)point.pieceB, localDir);
+
+ pos.z += 0.8f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ if ( CGame::nastyGame )
+ {
+ for ( int32 i = 0; i < 4; i++ )
+ {
+ CVector dir;
+ dir.x = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.y = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.z = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+
+ CParticle::AddParticle(PARTICLE_BLOOD, pos, dir);
+ }
+ }
+ }
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_SHOOT_COP, EVENT_ENTITY_PED, victimPed, FindPlayerPed(), 10000);
+ else
+ CEventList::RegisterEvent(EVENT_SHOOT_PED, EVENT_ENTITY_PED, victimPed, FindPlayerPed(), 10000);
+ }
+ }
+ else if ( victim->IsVehicle() )
+ ((CVehicle *)victim)->InflictDamage(FindPlayerPed(), WEAPONTYPE_UZI_DRIVEBY, info->m_nDamage);
+ else
+ CGlass::WasGlassHitByBullet(victim, point.point);
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point.point);
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point.point);
+ break;
+ }
+ }
+ }
+ else
+ {
+ float norm = 30.0f/info->m_fRange;
+ CVector traceTarget = (target-source)*norm + source;
+ CBulletTraces::AddTrace(&source, &traceTarget);
+ }
+
+ if ( shooter == FindPlayerVehicle() )
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerVehicle()->GetPosition().x, FindPlayerVehicle()->GetPosition().y, FindPlayerVehicle()->GetPosition().z);
+
+ return true;
+}
+
+void
+CWeapon::DoDoomAiming(CEntity *shooter, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target !=nil);
+
+#ifndef FIX_BUGS
+ CEntity entity; // unused
+#endif
+
+ CPed *shooterPed = (CPed*)shooter;
+ if ( shooterPed->IsPed() && shooterPed->bCrouchWhenShooting )
+ return;
+
+ int16 lastEntity;
+ CEntity *entities[16];
+ CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, entities, false, true, true, false, false);
+
+ float closestEntityDist = 10000.0f;
+ int16 closestEntity;
+
+ for ( int32 i = 0; i < lastEntity; i++ )
+ {
+ CEntity *victim = entities[i];
+ ASSERT(victim!=nil);
+
+ if ( (CEntity*)shooterPed != victim && shooterPed->CanSeeEntity(victim, DEGTORAD(22.5f)) )
+ {
+ if ( !(victim->m_status == STATUS_TRAIN_MOVING
+ || victim->m_status == STATUS_TRAIN_NOT_MOVING
+ || victim->m_status == STATUS_HELI
+ || victim->m_status == STATUS_PLANE) )
+ {
+ float distToVictim = (shooterPed->GetPosition()-victim->GetPosition()).Magnitude2D();
+ float distToVictimZ = Abs(shooterPed->GetPosition().z-victim->GetPosition().z);
+
+ if ( 1.5f*distToVictimZ < distToVictim )
+ {
+ float entityDist = Sqrt(SQR(distToVictim) + SQR(distToVictimZ));
+
+ if ( entityDist < closestEntityDist )
+ {
+ closestEntityDist = entityDist;
+ closestEntity = i;
+ }
+ }
+ }
+ }
+ }
+
+ if ( closestEntityDist < DOOMAUTOAIMING_MAXDIST )
+ {
+ CEntity *victim = entities[closestEntity];
+ ASSERT(victim !=nil);
+
+ float distToTarget = (*target - *source).Magnitude2D();
+ float distToSource = (victim->GetPosition() - *source).Magnitude2D();
+
+ float victimZ = victim->GetPosition().z + 0.3f;
+ if ( victim->IsPed() )
+ {
+ if ( ((CPed*)victim)->bIsDucking )
+ victimZ -= 0.8f;
+ }
+
+ (*target).z = (distToTarget / distToSource) * (victimZ - (*source).z) + (*source).z;
+ }
+}
+
+void
+CWeapon::DoTankDoomAiming(CEntity *shooter, CEntity *driver, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(driver!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+#ifndef FIX_BUGS
+ CEntity entity; // unused
+#endif
+
+ int16 lastEntity;
+ CEntity *entities[16];
+ CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, entities, false, true, false, false, false);
+
+ float closestEntityDist = 10000.0f;
+ int16 closestEntity;
+
+ float normZ = (target->z - source->z) / (*target-*source).Magnitude();
+
+ for ( int32 i = 0; i < lastEntity; i++ )
+ {
+ CEntity *victim = entities[i];
+
+ ASSERT(victim!=nil);
+
+ if ( shooter != victim && driver != victim )
+ {
+ if ( !(victim->m_status == STATUS_TRAIN_MOVING
+ || victim->m_status == STATUS_TRAIN_NOT_MOVING
+ || victim->m_status == STATUS_HELI
+ || victim->m_status == STATUS_PLANE) )
+ {
+ if ( !(victim->IsVehicle() && victim->bRenderScorched) )
+ {
+ float distToVictim = (shooter->GetPosition()-victim->GetPosition()).Magnitude2D();
+ float distToVictimZ = Abs(shooter->GetPosition().z - (distToVictim*normZ + victim->GetPosition().z));
+
+ if ( 3.0f*distToVictimZ < distToVictim )
+ {
+ if ( CCollision::DistToLine(source, target,
+ &CVector(victim->GetPosition().x, victim->GetPosition().y, 0.0f)) < victim->GetBoundRadius()*3.0f )
+ {
+ float vehicleDist = Sqrt(SQR(distToVictim) + SQR(distToVictimZ));
+ if ( vehicleDist < closestEntityDist )
+ {
+ closestEntityDist = vehicleDist;
+ closestEntity = i;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( closestEntityDist < DOOMAUTOAIMING_MAXDIST )
+ {
+ CEntity *victim = entities[closestEntity];
+ ASSERT(victim!=nil);
+
+ float distToTarget = (*target - *source).Magnitude2D();
+ float distToSource = (victim->GetPosition() - *source).Magnitude2D();
+
+ (*target).z = (distToTarget / distToSource) * (0.3f + victim->GetPosition().z - (*source).z) + (*source).z;
+ }
+}
+
+void
+CWeapon::DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+#ifndef FIX_BUGS
+ CEntity entity; // unused
+#endif
+
+ CPed *shooterPed = (CPed*)shooter;
+ if ( shooterPed->IsPed() && shooterPed->bCrouchWhenShooting )
+ return;
+
+ int16 lastEntity;
+ CEntity *entities[16];
+ CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, entities, false, false, true, false, false);
+
+ float closestEntityDist = 10000.0f;
+ int16 closestEntity;
+
+ for ( int32 i = 0; i < lastEntity; i++ )
+ {
+ CEntity *victim = entities[i];
+ ASSERT(victim!=nil);
+
+ if ( shooter != victim )
+ {
+ float lineDist = CCollision::DistToLine(source, target, &victim->GetPosition());
+ float distToVictim = (victim->GetPosition() - shooter->GetPosition()).Magnitude();
+ float pedDist = 0.15f*distToVictim + lineDist;
+
+ if ( DotProduct((*target-*source), victim->GetPosition()-*source) > 0.0f && pedDist < closestEntityDist)
+ {
+ closestEntity = i;
+ closestEntityDist = pedDist;
+ }
+ }
+ }
+
+ if ( closestEntityDist < DRIVEBYAUTOAIMING_MAXDIST )
+ {
+ CEntity *victim = entities[closestEntity];
+ ASSERT(victim!=nil);
+
+ float distToTarget = (*source - *target).Magnitude();
+ float distToSource = (*source - victim->GetPosition()).Magnitude();
+ *target = (distToTarget / distToSource) * (victim->GetPosition() - *source) + *source;
+ }
+}
+
void
CWeapon::Reload(void)
{
if (m_nAmmoTotal == 0)
return;
- CWeaponInfo *info = CWeaponInfo::GetWeaponInfo(m_eWeaponType);
+ CWeaponInfo *info = GetInfo();
if (m_nAmmoTotal >= info->m_nAmountofAmmunition)
m_nAmmoInClip = info->m_nAmountofAmmunition;
@@ -44,10 +1971,159 @@ CWeapon::Reload(void)
m_nAmmoInClip = m_nAmmoTotal;
}
-bool
-CWeapon::IsType2Handed(void)
+void
+CWeapon::Update(int32 audioEntity)
{
- return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER;
+ switch ( m_eWeaponState )
+ {
+ case WEAPONSTATE_MELEE_MADECONTACT:
+ {
+ m_eWeaponState = WEAPONSTATE_READY;
+ break;
+ }
+
+ case WEAPONSTATE_FIRING:
+ {
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN && AEHANDLE_IS_OK(audioEntity) )
+ {
+ uint32 timePassed = m_nTimer - gReloadSampleTime[WEAPONTYPE_SHOTGUN];
+ if ( CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed )
+ DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f);
+ }
+
+ if ( CTimer::GetTimeInMilliseconds() > m_nTimer )
+ {
+ if ( GetInfo()->m_eWeaponFire != WEAPON_FIRE_MELEE && m_nAmmoTotal == 0 )
+ m_eWeaponState = WEAPONSTATE_OUT_OF_AMMO;
+ else
+ m_eWeaponState = WEAPONSTATE_READY;
+ }
+
+ break;
+ }
+
+ case WEAPONSTATE_RELOADING:
+ {
+ if ( AEHANDLE_IS_OK(audioEntity) && m_eWeaponType < WEAPONTYPE_LAST_WEAPONTYPE )
+ {
+ uint32 timePassed = m_nTimer - gReloadSampleTime[m_eWeaponType];
+ if ( CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed )
+ DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f);
+ }
+
+ if ( CTimer::GetTimeInMilliseconds() > m_nTimer )
+ {
+ Reload();
+ m_eWeaponState = WEAPONSTATE_READY;
+ }
+
+ break;
+ }
+ }
+}
+
+void
+FireOneInstantHitRound(CVector *source, CVector *target, int32 damage)
+{
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+ CParticle::AddParticle(PARTICLE_GUNFLASH, *source, CVector(0.0f, 0.0f, 0.0f));
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *source, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CColPoint point;
+ CEntity *victim;
+ CWorld::ProcessLineOfSight(*source, *target, point, victim, true, true, true, true, true, true, false);
+
+ CParticle::AddParticle(PARTICLE_HELI_ATTACK, *source, ((*target) - (*source)) * 0.15f);
+
+ if ( victim )
+ {
+ if ( victim->IsPed() )
+ {
+ CPed *victimPed = (CPed *)victim;
+ if ( !victimPed->DyingOrDead() )
+ {
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset((*source).x-pos.x, (*source).y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+
+ victimPed->InflictDamage(nil, WEAPONTYPE_UZI, damage, (ePedPieceTypes)point.pieceB, localDir);
+
+ pos.z += 0.8f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ if ( CGame::nastyGame )
+ {
+ for ( int32 i = 0; i < 4; i++ )
+ {
+ CVector dir;
+ dir.x = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.y = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.z = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+
+ CParticle::AddParticle(PARTICLE_BLOOD, pos, dir);
+ }
+ }
+ }
+ }
+ }
+ else if ( victim->IsVehicle() )
+ ((CVehicle *)victim)->InflictDamage(nil, WEAPONTYPE_UZI, damage);
+ //BUG ? no CGlass::WasGlassHitByBullet
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point.point);
+ CParticle::AddParticle(PARTICLE_SMOKE, point.point, CVector(0.0f, 0.0f, 0.01f));
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point.point);
+ break;
+ }
+ }
+ }
+ else
+ {
+ float waterLevel;
+ if ( CWaterLevel::GetWaterLevel((*target).x, (*target).y, (*target).z + 10.0f, &waterLevel, false) )
+ {
+ CParticle::AddParticle(PARTICLE_BOAT_SPLASH, CVector((*target).x, (*target).y, waterLevel), CVector(0.0f, 0.0f, 0.01f));
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_WATER, point.point); // no sound(empty)
+ }
+ }
}
bool
@@ -57,32 +2133,75 @@ CWeapon::IsTypeMelee(void)
}
bool
-CWeapon::HitsGround(CEntity *holder, CVector *firePos, CEntity *aimingTo)
+CWeapon::IsType2Handed(void)
{
+ return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER;
+}
+
+void
+CWeapon::MakePedsJumpAtShot(CPhysical *shooter, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+ float minx = min(source->x, target->x) - 2.0f;
+ float maxx = max(source->x, target->x) + 2.0f;
+ float miny = min(source->y, target->y) - 2.0f;
+ float maxy = max(source->y, target->y) + 2.0f;
+ float minz = min(source->z, target->z) - 2.0f;
+ float maxz = max(source->z, target->z) + 2.0f;
+
+ for ( int32 i = CPools::GetPedPool()->GetSize() - 1; i >= 0; i--)
+ {
+ CPed *ped = CPools::GetPedPool()->GetSlot(i);
+
+ if ( ped )
+ {
+ if ( ped->GetPosition().x > minx && ped->GetPosition().x < maxx
+ && ped->GetPosition().y > miny && ped->GetPosition().y < maxy
+ && ped->GetPosition().z > minz && ped->GetPosition().z < maxz )
+ {
+ if ( ped != FindPlayerPed() && (uint8)(ped->m_randomSeed ^ CGeneral::GetRandomNumber()) & 31 )
+ ped->SetEvasiveDive(shooter, 1);
+ }
+ }
+ }
+}
+
+bool
+CWeapon::HitsGround(CEntity *holder, CVector *fireSource, CEntity *aimingTo)
+{
+ ASSERT(holder!=nil);
+ ASSERT(aimingTo!=nil);
+
if (!holder->IsPed() || !((CPed*)holder)->m_pSeekTarget)
return false;
- CWeaponInfo *ourType = CWeaponInfo::GetWeaponInfo(m_eWeaponType);
- CVector adjustedOffset = ourType->m_vecFireOffset;
+ CWeaponInfo *info = GetInfo();
+
+ CVector adjustedOffset = info->m_vecFireOffset;
adjustedOffset.z += 0.6f;
- CVector point1, point2;
+ CVector source, target;
CEntity *foundEnt = nil;
CColPoint foundCol;
- if (firePos)
- point1 = *firePos;
+ if (fireSource)
+ source = *fireSource;
else
- point1 = holder->GetMatrix() * adjustedOffset;
+ source = holder->GetMatrix() * adjustedOffset;
CEntity *aimEntity = aimingTo ? aimingTo : ((CPed*)holder)->m_pSeekTarget;
- point2 = aimEntity->GetPosition();
- point2.z += 0.6f;
+ ASSERT(aimEntity!=nil);
+
+ target = aimEntity->GetPosition();
+ target.z += 0.6f;
- CWorld::ProcessLineOfSight(point1, point2, foundCol, foundEnt, true, false, false, false, false, false, false);
+ CWorld::ProcessLineOfSight(source, target, foundCol, foundEnt, true, false, false, false, false, false, false);
if (foundEnt && foundEnt->IsBuilding()) {
// That was supposed to be Magnitude, according to leftover code in assembly
- float diff = (foundCol.point.z - point1.z);
+ float diff = (foundCol.point.z - source.z);
if (diff < 0.0f && diff > -3.0f)
return true;
}
@@ -90,6 +2209,36 @@ CWeapon::HitsGround(CEntity *holder, CVector *firePos, CEntity *aimingTo)
return false;
}
+void
+CWeapon::BlowUpExplosiveThings(CEntity *thing)
+{
+ if ( thing )
+ {
+ CObject *object = (CObject*)thing;
+ int32 mi = object->GetModelIndex();
+ if ( IsExplosiveThingModel(mi) && !object->bHasBeenDamaged )
+ {
+ object->bHasBeenDamaged = true;
+
+ CExplosion::AddExplosion(object, FindPlayerPed(), EXPLOSION_BARREL, object->GetPosition()+CVector(0.0f,0.0f,0.5f), 100);
+
+ if ( MI_EXPLODINGBARREL == mi )
+ object->m_vecMoveSpeed.z += 0.75f;
+ else
+ object->m_vecMoveSpeed.z += 0.45f;
+
+ object->m_vecMoveSpeed.x += float((CGeneral::GetRandomNumber()&255) - 128) * 0.0002f;
+ object->m_vecMoveSpeed.y += float((CGeneral::GetRandomNumber()&255) - 128) * 0.0002f;
+
+ if ( object->bIsStatic )
+ {
+ object->bIsStatic = false;
+ object->AddToMovingList();
+ }
+ }
+ }
+}
+
bool
CWeapon::HasWeaponAmmoToBeUsed(void)
{
@@ -102,8 +2251,42 @@ CWeapon::HasWeaponAmmoToBeUsed(void)
}
}
+bool
+CWeapon::ProcessLineOfSight(CVector const &point1, CVector const &point2, CColPoint &point, CEntity *&entity, eWeaponType type, CEntity *shooter, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
+{
+ return CWorld::ProcessLineOfSight(point1, point2, point, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects);
+}
+
STARTPATCHES
+
+ InjectHook(0x55C2D0, CWeapon::InitialiseWeapons, PATCH_JUMP);
+ InjectHook(0x55C2F0, CWeapon::ShutdownWeapons, PATCH_JUMP);
+ InjectHook(0x55C310, CWeapon::UpdateWeapons, PATCH_JUMP);
InjectHook(0x55C330, &CWeapon::Initialise, PATCH_JUMP);
+ InjectHook(0x55C380, &CWeapon::Fire, PATCH_JUMP);
+ InjectHook(0x55C940, &CWeapon::FireFromCar, PATCH_JUMP);
+ InjectHook(0x55CA20, &CWeapon::FireMelee, PATCH_JUMP);
+ InjectHook(0x55D2E0, &CWeapon::FireInstantHit, PATCH_JUMP);
+ InjectHook(0x55F770, &CWeapon::AddGunshell, PATCH_JUMP);
+ InjectHook(0x55F950, &CWeapon::DoBulletImpact, PATCH_JUMP);
+ InjectHook(0x560620, &CWeapon::FireShotgun, PATCH_JUMP);
+ InjectHook(0x561900, &CWeapon::FireProjectile, PATCH_JUMP);
+ InjectHook(0x561C70, CWeapon::GenerateFlameThrowerParticles, PATCH_JUMP);
+ InjectHook(0x561E00, &CWeapon::FireAreaEffect, PATCH_JUMP);
+ InjectHook(0x561FE0, &CWeapon::FireSniper, PATCH_JUMP);
+ InjectHook(0x562180, &CWeapon::FireM16_1stPerson, PATCH_JUMP);
+ InjectHook(0x5624D0, &CWeapon::FireInstantHitFromCar, PATCH_JUMP);
+ InjectHook(0x562EB0, CWeapon::DoDoomAiming, PATCH_JUMP);
+ InjectHook(0x563200, CWeapon::DoTankDoomAiming, PATCH_JUMP);
+ InjectHook(0x563660, CWeapon::DoDriveByAutoAiming, PATCH_JUMP);
InjectHook(0x5639D0, &CWeapon::Reload, PATCH_JUMP);
+ InjectHook(0x563A10, &CWeapon::Update, PATCH_JUMP);
+ InjectHook(0x563FB0, &CWeapon::IsTypeMelee, PATCH_JUMP);
+ InjectHook(0x563FD0, &CWeapon::IsType2Handed, PATCH_JUMP);
+ InjectHook(0x564680, CWeapon::MakePedsJumpAtShot, PATCH_JUMP);
InjectHook(0x564890, &CWeapon::HitsGround, PATCH_JUMP);
+ InjectHook(0x564A60, CWeapon::BlowUpExplosiveThings, PATCH_JUMP);
+ InjectHook(0x564B80, &CWeapon::HasWeaponAmmoToBeUsed, PATCH_JUMP);
+ InjectHook(0x564C00, CWeapon::ProcessLineOfSight, PATCH_JUMP);
+
ENDPATCHES
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index 84760550..265ffddb 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -1,5 +1,8 @@
#pragma once
+#define DRIVEBYAUTOAIMING_MAXDIST (2.5f)
+#define DOOMAUTOAIMING_MAXDIST (9000.0f)
+
enum eWeaponType
{
WEAPONTYPE_UNARMED,
@@ -49,7 +52,10 @@ enum eWeaponState
};
class CEntity;
+class CPhysical;
class CAutomobile;
+struct CColPoint;
+class CWeaponInfo;
class CWeapon
{
@@ -64,22 +70,50 @@ public:
CWeapon() {
m_bAddRotOffset = false;
}
+
+ CWeaponInfo *GetInfo();
- static void ShutdownWeapons(void);
- void Initialise(eWeaponType type, int ammo);
- void Update(int32 audioEntity);
+ static void InitialiseWeapons(void);
+ static void ShutdownWeapons (void);
+ static void UpdateWeapons (void);
+
+ void Initialise(eWeaponType type, int32 ammo);
+
+ bool Fire (CEntity *shooter, CVector *fireSource);
+ bool FireFromCar (CAutomobile *shooter, bool left);
+ bool FireMelee (CEntity *shooter, CVector &fireSource);
+ bool FireInstantHit(CEntity *shooter, CVector *fireSource);
+
+ void AddGunshell (CEntity *shooter, CVector const &source, CVector2D const &direction, float size);
+ void DoBulletImpact(CEntity *shooter, CEntity *victim, CVector *source, CVector *target, CColPoint *point, CVector2D ahead);
+
+ bool FireShotgun (CEntity *shooter, CVector *fireSource);
+ bool FireProjectile(CEntity *shooter, CVector *fireSource, float power);
+
+ static void GenerateFlameThrowerParticles(CVector pos, CVector dir);
+
+ bool FireAreaEffect (CEntity *shooter, CVector *fireSource);
+ bool FireSniper (CEntity *shooter);
+ bool FireM16_1stPerson (CEntity *shooter);
+ bool FireInstantHitFromCar(CAutomobile *shooter, bool left);
+
+ static void DoDoomAiming (CEntity *shooter, CVector *source, CVector *target);
+ static void DoTankDoomAiming (CEntity *shooter, CEntity *driver, CVector *source, CVector *target);
+ static void DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target);
+
void Reload(void);
- bool Fire(CEntity*, CVector*);
- void FireFromCar(CAutomobile *car, bool left);
- void AddGunshell(CEntity*, CVector const&, CVector2D const&, float);
- bool IsTypeMelee(void);
+ void Update(int32 audioEntity);
+ bool IsTypeMelee (void);
bool IsType2Handed(void);
- static void DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end);
- bool HitsGround(CEntity* holder, CVector* firePos, CEntity* aimingTo);
+
+ static void MakePedsJumpAtShot(CPhysical *shooter, CVector *source, CVector *target);
+
+ bool HitsGround(CEntity *holder, CVector *fireSource, CEntity *aimingTo);
+ static void BlowUpExplosiveThings(CEntity *thing);
bool HasWeaponAmmoToBeUsed(void);
- static void InitialiseWeapons(void);
- static void UpdateWeapons(void);
+
+ static bool ProcessLineOfSight(CVector const &point1, CVector const &point2, CColPoint &point, CEntity *&entity, eWeaponType type, CEntity *shooter, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects);
};
-static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error");
+VALIDATE_SIZE(CWeapon, 0x18);
-void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage); \ No newline at end of file
+void FireOneInstantHitRound(CVector *source, CVector *target, int32 damage); \ No newline at end of file