diff options
author | Nikolay Korolev <nickvnuk@gmail.com> | 2020-04-15 22:31:52 +0200 |
---|---|---|
committer | Nikolay Korolev <nickvnuk@gmail.com> | 2020-04-15 22:31:52 +0200 |
commit | 1795f3d47993e7a9833e6f265bb91fb6ce400f1c (patch) | |
tree | 766dd0f14ba4df90cbac836c03cdfc501c9cd009 | |
parent | fix (diff) | |
parent | Merge pull request #440 from Fire-Head/master (diff) | |
download | re3-1795f3d47993e7a9833e6f265bb91fb6ce400f1c.tar re3-1795f3d47993e7a9833e6f265bb91fb6ce400f1c.tar.gz re3-1795f3d47993e7a9833e6f265bb91fb6ce400f1c.tar.bz2 re3-1795f3d47993e7a9833e6f265bb91fb6ce400f1c.tar.lz re3-1795f3d47993e7a9833e6f265bb91fb6ce400f1c.tar.xz re3-1795f3d47993e7a9833e6f265bb91fb6ce400f1c.tar.zst re3-1795f3d47993e7a9833e6f265bb91fb6ce400f1c.zip |
41 files changed, 2744 insertions, 244 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index a5b44461..41ada399 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -43,3 +43,5 @@ after_build: artifacts: - path: bin/%CONFIGURATION%/re3.dll name: re3.dll +- path: bin/%CONFIGURATION%/re3.pdb + name: re3.pdb @@ -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/premake5.lua b/premake5.lua index 4ec2eca1..173fe3e4 100644 --- a/premake5.lua +++ b/premake5.lua @@ -94,13 +94,14 @@ project "re3" filter "configurations:Debug" defines { "DEBUG" } staticruntime "on" - symbols "On" + symbols "Full" setpaths("$(GTA_III_RE_DIR)/", "gta3.exe", "plugins/") filter "configurations:Release" defines { "NDEBUG" } optimize "On" staticruntime "on" + symbols "Full" setpaths("$(GTA_III_RE_DIR)/", "gta3.exe", "plugins/") filter "configurations:ReleaseFH" 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/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/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 2bfe8290..b028b5fb 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -691,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); @@ -749,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); @@ -1559,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/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 cee2b323..4696df31 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 177a99d1..d975c464 100644 --- a/src/weapons/BulletInfo.cpp +++ b/src/weapons/BulletInfo.cpp @@ -267,10 +267,3 @@ bool CBulletInfo::TestForSniperBullet(float x1, float x2, float y1, float y2, fl return minP <= maxP; #endif } - -STARTPATCHES - InjectHook(0x558220, &CBulletInfo::Initialise, PATCH_JUMP); - InjectHook(0x558450, &CBulletInfo::Shutdown, PATCH_JUMP); - InjectHook(0x558470, &CBulletInfo::AddBullet, PATCH_JUMP); - InjectHook(0x558550, &CBulletInfo::Update, PATCH_JUMP); -ENDPATCHES
\ No newline at end of file diff --git a/src/weapons/BulletInfo.h b/src/weapons/BulletInfo.h index fb8fd3a8..51954565 100644 --- a/src/weapons/BulletInfo.h +++ b/src/weapons/BulletInfo.h @@ -1,7 +1,7 @@ #pragma once -#include "Weapon.h" class CEntity; +enum eWeaponType; class CBulletInfo { diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 290b9179..7b6b4170 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -1,24 +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); } -WRAPPER void CWeapon::BlowUpExplosiveThings(CEntity* pEntity) { EAXJMP(0x564A60); } +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; @@ -31,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; @@ -45,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 @@ -58,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; } @@ -91,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) { @@ -103,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 79a53dcb..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,23 +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 void BlowUpExplosiveThings(CEntity*); + + 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 |