summaryrefslogtreecommitdiffstats
path: root/src/weapons
diff options
context:
space:
mode:
Diffstat (limited to 'src/weapons')
-rw-r--r--src/weapons/BulletInfo.cpp266
-rw-r--r--src/weapons/BulletInfo.h17
-rw-r--r--src/weapons/Explosion.cpp2
-rw-r--r--src/weapons/Explosion.h2
-rw-r--r--src/weapons/ProjectileInfo.cpp4
-rw-r--r--src/weapons/ProjectileInfo.h8
-rw-r--r--src/weapons/Weapon.cpp2235
-rw-r--r--src/weapons/Weapon.h60
-rw-r--r--src/weapons/WeaponEffects.cpp106
-rw-r--r--src/weapons/WeaponEffects.h27
10 files changed, 2679 insertions, 48 deletions
diff --git a/src/weapons/BulletInfo.cpp b/src/weapons/BulletInfo.cpp
index 54fa6844..9e83a4ec 100644
--- a/src/weapons/BulletInfo.cpp
+++ b/src/weapons/BulletInfo.cpp
@@ -2,4 +2,268 @@
#include "patcher.h"
#include "BulletInfo.h"
-WRAPPER bool CBulletInfo::TestForSniperBullet(float x1, float x2, float y1, float y2, float z1, float z2) { EAXJMP(0x558D40); }
+#include "AnimBlendAssociation.h"
+#include "AudioManager.h"
+#include "AudioScriptObject.h"
+#ifdef FIX_BUGS
+#include "Collision.h"
+#endif
+#include "RpAnimBlend.h"
+#include "Entity.h"
+#include "EventList.h"
+#include "Fire.h"
+#include "Glass.h"
+#include "Particle.h"
+#include "Ped.h"
+#include "Object.h"
+#include "Stats.h"
+#include "Timer.h"
+#include "Vehicle.h"
+#include "Weapon.h"
+#include "WeaponInfo.h"
+#include "World.h"
+
+#define BULLET_LIFETIME (1000)
+#define NUM_PED_BLOOD_PARTICLES (8)
+#define BLOOD_PARTICLE_OFFSET (CVector(0.0f, 0.0f, 0.0f))
+#define NUM_VEHICLE_SPARKS (16)
+#define NUM_OTHER_SPARKS (8)
+#define BULLET_HIT_FORCE (7.5f)
+#define MAP_BORDER (1960.0f)
+
+CBulletInfo gaBulletInfo[CBulletInfo::NUM_BULLETS];
+bool bPlayerSniperBullet;
+CVector PlayerSniperBulletStart;
+CVector PlayerSniperBulletEnd;
+
+void CBulletInfo::Initialise(void)
+{
+ debug("Initialising CBulletInfo...\n");
+ for (int i = 0; i < NUM_BULLETS; i++) {
+ gaBulletInfo[i].m_bInUse = false;
+ gaBulletInfo[i].m_eWeaponType = WEAPONTYPE_COLT45;
+ gaBulletInfo[i].m_fTimer = 0.0f;
+ gaBulletInfo[i].m_pSource = nil;
+ }
+ debug("CBulletInfo ready\n");
+}
+
+void CBulletInfo::Shutdown(void)
+{
+ debug("Shutting down CBulletInfo...\n");
+ debug("CBulletInfo shut down\n");
+}
+
+bool CBulletInfo::AddBullet(CEntity* pSource, eWeaponType type, CVector vecPosition, CVector vecSpeed)
+{
+ int i;
+ for (i = 0; i < NUM_BULLETS; i++) {
+ if (!gaBulletInfo[i].m_bInUse)
+ break;
+ }
+ if (i == NUM_BULLETS)
+ return false;
+ gaBulletInfo[i].m_pSource = pSource;
+ gaBulletInfo[i].m_eWeaponType = type;
+ gaBulletInfo[i].m_nDamage = CWeaponInfo::GetWeaponInfo(type)->m_nDamage;
+ gaBulletInfo[i].m_vecPosition = vecPosition;
+ gaBulletInfo[i].m_vecSpeed = vecSpeed;
+ gaBulletInfo[i].m_fTimer = CTimer::GetTimeInMilliseconds() + BULLET_LIFETIME;
+ gaBulletInfo[i].m_bInUse = true;
+ return true;
+}
+
+void CBulletInfo::Update(void)
+{
+ bool bAddSound = true;
+ bPlayerSniperBullet = false;
+ for (int i = 0; i < NUM_BULLETS; i++) {
+ CBulletInfo* pBullet = &gaBulletInfo[i];
+ if (pBullet->m_pSource && pBullet->m_pSource->IsPed() && !((CPed*)pBullet->m_pSource)->IsPointerValid())
+ pBullet->m_pSource = nil;
+ if (!pBullet->m_bInUse)
+ continue;
+ if (CTimer::GetTimeInMilliseconds() > pBullet->m_fTimer)
+ pBullet->m_bInUse = false;
+ CVector vecOldPos = pBullet->m_vecPosition;
+ CVector vecNewPos = pBullet->m_vecPosition + pBullet->m_vecSpeed * CTimer::GetTimeStep() * 0.5f;
+ CWorld::bIncludeCarTyres = true;
+ CWorld::bIncludeDeadPeds = true;
+ CWorld::pIgnoreEntity = pBullet->m_pSource;
+ CColPoint point;
+ CEntity* pHitEntity;
+ if (CWorld::ProcessLineOfSight(vecOldPos, vecNewPos, point, pHitEntity, true, true, true, true, true, true)) {
+ if (pBullet->m_pSource && (pHitEntity->IsPed() || pHitEntity->IsVehicle()))
+ CStats::InstantHitsHitByPlayer++;
+ if (pHitEntity->IsPed()) {
+ CPed* pPed = (CPed*)pHitEntity;
+ if (!pPed->DyingOrDead() && pPed != pBullet->m_pSource) {
+ if (pPed->DoesLOSBulletHitPed(point)) {
+ if (pPed->IsPedInControl() && !pPed->bIsDucking) {
+ pPed->ClearAttackByRemovingAnim();
+ CAnimBlendAssociation* pAnim = CAnimManager::AddAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_SHOT_FRONT_PARTIAL);
+ pAnim->SetBlend(0.0f, 8.0f);
+ }
+ pPed->InflictDamage(pBullet->m_pSource, pBullet->m_eWeaponType, pBullet->m_nDamage, (ePedPieceTypes)point.pieceB, pPed->GetLocalDirection(pPed->GetPosition() - point.point));
+ CEventList::RegisterEvent(pPed->m_nPedType == PEDTYPE_COP ? EVENT_SHOOT_COP : EVENT_SHOOT_PED, EVENT_ENTITY_PED, pPed, (CPed*)pBullet->m_pSource, 1000);
+ pBullet->m_bInUse = false;
+ vecNewPos = point.point;
+ }
+ else {
+ bAddSound = false;
+ }
+ }
+ if (CGame::nastyGame) {
+ CVector vecParticleDirection = (point.point - pPed->GetPosition()) * 0.01f;
+ vecParticleDirection.z = 0.01f;
+ if (pPed->GetIsOnScreen()) {
+ for (int j = 0; j < NUM_PED_BLOOD_PARTICLES; j++)
+ CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point.point + BLOOD_PARTICLE_OFFSET, vecParticleDirection);
+ }
+ if (pPed->GetPedState() == PED_DEAD) {
+ CAnimBlendAssociation* pAnim;
+ if (RpAnimBlendClumpGetFirstAssociation(pPed->GetClump(), ASSOC_FLAG800))
+ pAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f);
+ else
+ pAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT, 8.0f);
+ if (pAnim) {
+ pAnim->SetCurrentTime(0.0f);
+ pAnim->flags |= ASSOC_RUNNING;
+ pAnim->flags &= ~ASSOC_FADEOUTWHENDONE;
+ }
+ }
+ pBullet->m_bInUse = false;
+ vecNewPos = point.point;
+ }
+ }
+ else if (pHitEntity->IsVehicle()) {
+ CVehicle* pVehicle = (CVehicle*)pHitEntity;
+ pVehicle->InflictDamage(pBullet->m_pSource, pBullet->m_eWeaponType, pBullet->m_nDamage);
+ if (pBullet->m_eWeaponType == WEAPONTYPE_FLAMETHROWER) // huh?
+ gFireManager.StartFire(pVehicle, pBullet->m_pSource, 0.8f, true);
+ else {
+ for (int j = 0; j < NUM_VEHICLE_SPARKS; j++)
+ CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal / 20);
+ }
+#ifdef FIX_BUGS
+ pBullet->m_bInUse = false;
+ vecNewPos = point.point;
+#endif
+ }
+ else {
+ for (int j = 0; j < NUM_OTHER_SPARKS; j++)
+ CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal / 20);
+ if (pHitEntity->IsObject()) {
+ CObject* pObject = (CObject*)pHitEntity;
+ if (!pObject->bInfiniteMass) {
+ if (pObject->bIsStatic && pObject->m_fUprootLimit <= 0.0f) {
+ pObject->bIsStatic = false;
+ pObject->AddToMovingList();
+ }
+ if (!pObject->bIsStatic)
+ pObject->ApplyMoveForce(-BULLET_HIT_FORCE * point.normal);
+ }
+ }
+#ifdef FIX_BUGS
+ pBullet->m_bInUse = false;
+ vecNewPos = point.point;
+#endif
+ }
+ if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE && bAddSound) {
+ cAudioScriptObject* pAudio;
+ switch (pHitEntity->m_type) {
+ case ENTITY_TYPE_BUILDING:
+ pAudio = new cAudioScriptObject();
+ pAudio->Posn = pHitEntity->GetPosition();
+ pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_1;
+ pAudio->AudioEntity = AEHANDLE_NONE;
+ DMAudio.CreateOneShotScriptObject(pAudio);
+ break;
+ case ENTITY_TYPE_OBJECT:
+ pAudio = new cAudioScriptObject();
+ pAudio->Posn = pHitEntity->GetPosition();
+ pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_2;
+ pAudio->AudioEntity = AEHANDLE_NONE;
+ DMAudio.CreateOneShotScriptObject(pAudio);
+ break;
+ case ENTITY_TYPE_DUMMY:
+ pAudio = new cAudioScriptObject();
+ pAudio->Posn = pHitEntity->GetPosition();
+ pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_3;
+ pAudio->AudioEntity = AEHANDLE_NONE;
+ DMAudio.CreateOneShotScriptObject(pAudio);
+ break;
+ case ENTITY_TYPE_PED:
+ DMAudio.PlayOneShot(((CPed*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)pHitEntity)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ case ENTITY_TYPE_VEHICLE:
+ DMAudio.PlayOneShot(((CVehicle*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ }
+ CGlass::WasGlassHitByBullet(pHitEntity, point.point);
+ CWeapon::BlowUpExplosiveThings(pHitEntity);
+ }
+ CWorld::pIgnoreEntity = nil;
+ CWorld::bIncludeDeadPeds = false;
+ CWorld::bIncludeCarTyres = false;
+ if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE) {
+ bPlayerSniperBullet = true;
+ PlayerSniperBulletStart = pBullet->m_vecPosition;
+ PlayerSniperBulletEnd = vecNewPos;
+ }
+ pBullet->m_vecPosition = vecNewPos;
+ if (pBullet->m_vecPosition.x < -MAP_BORDER || pBullet->m_vecPosition.x > MAP_BORDER ||
+ pBullet->m_vecPosition.y < -MAP_BORDER || pBullet->m_vecPosition.y > MAP_BORDER)
+ pBullet->m_bInUse = false;
+ }
+}
+
+bool CBulletInfo::TestForSniperBullet(float x1, float x2, float y1, float y2, float z1, float z2)
+{
+ if (!bPlayerSniperBullet)
+ return false;
+#ifdef FIX_BUGS // original code is not going work anyway...
+ CColLine line(PlayerSniperBulletStart, PlayerSniperBulletEnd);
+ CColBox box;
+ box.Set(CVector(x1, y1, z1), CVector(x2, y2, z2), 0, 0);
+ return CCollision::TestLineBox(line, box);
+#else
+ float minP = 0.0f;
+ float maxP = 1.0f;
+ float minX = min(PlayerSniperBulletStart.x, PlayerSniperBulletEnd.x);
+ float maxX = max(PlayerSniperBulletStart.x, PlayerSniperBulletEnd.x);
+ if (minX < x2 || maxX > x1) {
+ if (minX < x1)
+ minP = min(minP, (x1 - minX) / (maxX - minX));
+ if (maxX > x2)
+ maxP = max(maxP, (maxX - x2) / (maxX - minX));
+ }
+ else
+ return false;
+ float minY = min(PlayerSniperBulletStart.y, PlayerSniperBulletEnd.y);
+ float maxY = max(PlayerSniperBulletStart.y, PlayerSniperBulletEnd.y);
+ if (minY < y2 || maxY > y1) {
+ if (minY < y1)
+ minP = min(minP, (y1 - minY) / (maxY - minY));
+ if (maxY > y2)
+ maxP = max(maxP, (maxY - y2) / (maxY - minY));
+ }
+#ifdef FIX_BUGS
+ else
+ return false;
+#endif
+ float minZ = min(PlayerSniperBulletStart.z, PlayerSniperBulletEnd.z);
+ float maxZ = max(PlayerSniperBulletStart.z, PlayerSniperBulletEnd.z);
+ if (minZ < z2 || maxZ > z1) {
+ if (minZ < z1)
+ minP = min(minP, (z1 - minZ) / (maxZ - minZ));
+ if (maxZ > z2)
+ maxP = max(maxP, (maxZ - z2) / (maxZ - minZ));
+ }
+ else
+ return false;
+ return minP <= maxP;
+#endif
+}
diff --git a/src/weapons/BulletInfo.h b/src/weapons/BulletInfo.h
index 3905b56d..c7d740b2 100644
--- a/src/weapons/BulletInfo.h
+++ b/src/weapons/BulletInfo.h
@@ -1,7 +1,24 @@
#pragma once
+class CEntity;
+enum eWeaponType;
+
class CBulletInfo
{
+ eWeaponType m_eWeaponType;
+ CEntity* m_pSource;
+ float m_fTimer; // big mistake
+ bool m_bInUse;
+ CVector m_vecPosition;
+ CVector m_vecSpeed;
+ int16 m_nDamage;
public:
+ enum {
+ NUM_BULLETS = 100
+ };
+ static void Initialise(void);
+ static void Shutdown(void);
+ static bool AddBullet(CEntity* pSource, eWeaponType type, CVector vecPosition, CVector vecSpeed);
+ static void Update(void);
static bool TestForSniperBullet(float x1, float x2, float y1, float y2, float z1, float z2);
}; \ No newline at end of file
diff --git a/src/weapons/Explosion.cpp b/src/weapons/Explosion.cpp
index 3d00052a..02243702 100644
--- a/src/weapons/Explosion.cpp
+++ b/src/weapons/Explosion.cpp
@@ -19,7 +19,7 @@
#include "WaterLevel.h"
#include "World.h"
-CExplosion(&gaExplosion)[NUM_EXPLOSIONS] = *(CExplosion(*)[NUM_EXPLOSIONS])*(uintptr*)0x64E208;
+CExplosion gaExplosion[NUM_EXPLOSIONS];
// these two were not initialised in original code, I'm really not sure what were they meant to be
RwRGBA colMedExpl = { 0, 0, 0, 0 };
diff --git a/src/weapons/Explosion.h b/src/weapons/Explosion.h
index 45e2d5bb..bf54328c 100644
--- a/src/weapons/Explosion.h
+++ b/src/weapons/Explosion.h
@@ -46,4 +46,4 @@ public:
static void RemoveAllExplosionsInArea(CVector pos, float radius);
};
-extern CExplosion (&gaExplosion)[NUM_EXPLOSIONS]; \ No newline at end of file
+extern CExplosion gaExplosion[NUM_EXPLOSIONS]; \ No newline at end of file
diff --git a/src/weapons/ProjectileInfo.cpp b/src/weapons/ProjectileInfo.cpp
index b33d2d62..8f04278c 100644
--- a/src/weapons/ProjectileInfo.cpp
+++ b/src/weapons/ProjectileInfo.cpp
@@ -13,8 +13,8 @@
#include "Weapon.h"
#include "World.h"
-CProjectileInfo (&gaProjectileInfo)[NUM_PROJECTILES] = *(CProjectileInfo(*)[NUM_PROJECTILES])*(uintptr*)0x64ED50;
-CProjectile* (&CProjectileInfo::ms_apProjectile)[NUM_PROJECTILES] = *(CProjectile*(*)[NUM_PROJECTILES])*(uintptr*)0x87C748;
+CProjectileInfo gaProjectileInfo[NUM_PROJECTILES];
+CProjectile *CProjectileInfo::ms_apProjectile[NUM_PROJECTILES];
void
CProjectileInfo::Initialise()
diff --git a/src/weapons/ProjectileInfo.h b/src/weapons/ProjectileInfo.h
index a4ea369a..b88322f9 100644
--- a/src/weapons/ProjectileInfo.h
+++ b/src/weapons/ProjectileInfo.h
@@ -9,14 +9,14 @@ class CProjectileInfo
{
public:
eWeaponType m_eWeaponType;
- CEntity* m_pSource;
+ CEntity *m_pSource;
uint32 m_nExplosionTime;
bool m_bInUse;
CVector m_vecPos;
public:
- static CProjectileInfo* GetProjectileInfo(int32 id);
- static CProjectile* (&ms_apProjectile)[NUM_PROJECTILES];
+ static CProjectileInfo *GetProjectileInfo(int32 id);
+ static CProjectile *ms_apProjectile[NUM_PROJECTILES];
static void Initialise();
static void Shutdown();
@@ -29,4 +29,4 @@ public:
static bool IsProjectileInRange(float x1, float x2, float y1, float y2, float z1, float z2, bool remove);
};
-extern CProjectileInfo (&gaProjectileInfo)[NUM_PROJECTILES]; \ No newline at end of file
+extern CProjectileInfo gaProjectileInfo[NUM_PROJECTILES]; \ No newline at end of file
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 0f41264f..98154e93 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -1,23 +1,92 @@
#include "common.h"
#include "patcher.h"
#include "Weapon.h"
+#include "AnimBlendAssociation.h"
+#include "AudioManager.h"
+#include "BulletInfo.h"
+#include "Camera.h"
+#include "Coronas.h"
+#include "DMAudio.h"
+#include "Explosion.h"
+#include "General.h"
+#include "Glass.h"
+#include "Heli.h"
+#include "ModelIndices.h"
+#include "Object.h"
+#include "Pad.h"
+#include "Particle.h"
+#include "Ped.h"
+#include "PointLights.h"
+#include "Pools.h"
+#include "ProjectileInfo.h"
+#include "RpAnimBlend.h"
+#include "ShotInfo.h"
+#include "SpecialFX.h"
+#include "Stats.h"
+#include "TempColModels.h"
#include "Timer.h"
+#include "Vehicle.h"
+#include "WaterLevel.h"
#include "WeaponInfo.h"
-#include "Ped.h"
#include "World.h"
-WRAPPER void CWeapon::ShutdownWeapons(void) { EAXJMP(0x55C2F0); }
-WRAPPER void CWeapon::UpdateWeapons(void) { EAXJMP(0x55C310); }
-WRAPPER bool CWeapon::Fire(CEntity*, CVector*) { EAXJMP(0x55C380); }
-WRAPPER void CWeapon::FireFromCar(CAutomobile *car, bool left) { EAXJMP(0x55C940); }
-WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, float) { EAXJMP(0x55F770); }
-WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); }
-WRAPPER void CWeapon::DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end) { EAXJMP(0x563200); }
-WRAPPER void CWeapon::InitialiseWeapons(void) { EAXJMP(0x55C2D0); }
-WRAPPER void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage) { EAXJMP(0x563B00); }
+uint16 gReloadSampleTime[WEAPONTYPE_LAST_WEAPONTYPE] =
+{
+ 0, // UNARMED
+ 0, // BASEBALLBAT
+ 250, // COLT45
+ 400, // UZI
+ 650, // SHOTGUN
+ 300, // AK47
+ 300, // M16
+ 423, // SNIPERRIFLE
+ 400, // ROCKETLAUNCHER
+ 0, // FLAMETHROWER
+ 0, // MOLOTOV
+ 0, // GRENADE
+ 0, // DETONATOR
+ 0 // HELICANNON
+};
+
+CWeaponInfo *
+CWeapon::GetInfo()
+{
+ CWeaponInfo *info = CWeaponInfo::GetWeaponInfo(m_eWeaponType);
+ ASSERT(info!=nil);
+ return info;
+}
+
+void
+CWeapon::InitialiseWeapons(void)
+{
+ CWeaponInfo::Initialise();
+ CShotInfo::Initialise();
+ CExplosion::Initialise();
+ CProjectileInfo::Initialise();
+ CBulletInfo::Initialise();
+}
+
+void
+CWeapon::ShutdownWeapons(void)
+{
+ CWeaponInfo::Shutdown();
+ CShotInfo::Shutdown();
+ CExplosion::Shutdown();
+ CProjectileInfo::Shutdown();
+ CBulletInfo::Shutdown();
+}
void
-CWeapon::Initialise(eWeaponType type, int ammo)
+CWeapon::UpdateWeapons(void)
+{
+ CShotInfo::Update();
+ CExplosion::Update();
+ CProjectileInfo::Update();
+ CBulletInfo::Update();
+}
+
+void
+CWeapon::Initialise(eWeaponType type, int32 ammo)
{
m_eWeaponType = type;
m_eWeaponState = WEAPONSTATE_READY;
@@ -30,13 +99,1871 @@ CWeapon::Initialise(eWeaponType type, int ammo)
m_nTimer = 0;
}
+bool
+CWeapon::Fire(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+
+ CVector fireOffset(0.0f, 0.0f, 0.6f);
+ CVector *source = fireSource;
+
+ if ( !fireSource )
+ source = &(shooter->GetMatrix() * fireOffset);
+
+ if ( m_bAddRotOffset )
+ {
+ float heading = RADTODEG(shooter->GetForward().Heading());
+ float angle = DEGTORAD(heading);
+ (*source).x += -Sin(angle) * 0.15f;
+ (*source).y += Cos(angle) * 0.15f;
+ }
+
+ if ( m_eWeaponState != WEAPONSTATE_READY && m_eWeaponState != WEAPONSTATE_FIRING )
+ return false;
+
+ bool fired;
+
+ if ( GetInfo()->m_eWeaponFire != WEAPON_FIRE_MELEE )
+ {
+ if ( m_nAmmoInClip <= 0 )
+ return false;
+
+ switch ( m_eWeaponType )
+ {
+ case WEAPONTYPE_SHOTGUN:
+ {
+ fired = FireShotgun(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_COLT45:
+ case WEAPONTYPE_UZI:
+ case WEAPONTYPE_AK47:
+ {
+ fired = FireInstantHit(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_SNIPERRIFLE:
+ {
+ fired = FireSniper(shooter);
+
+ break;
+ }
+
+ case WEAPONTYPE_M16:
+ {
+ if ( TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON && shooter == FindPlayerPed() )
+ fired = FireM16_1stPerson(shooter);
+ else
+ fired = FireInstantHit(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_ROCKETLAUNCHER:
+ {
+ if ( shooter->IsPed() && ((CPed*)shooter)->m_pSeekTarget != nil )
+ {
+ float distToTarget = (shooter->GetPosition() - ((CPed*)shooter)->m_pSeekTarget->GetPosition()).Magnitude();
+
+ if ( distToTarget > 8.0f || ((CPed*)shooter)->IsPlayer() )
+ fired = FireProjectile(shooter, source, 0.0f);
+ else
+ fired = false;
+ }
+ else
+ fired = FireProjectile(shooter, source, 0.0f);
+
+ break;
+ }
+
+ case WEAPONTYPE_MOLOTOV:
+ case WEAPONTYPE_GRENADE:
+ {
+ if ( shooter == FindPlayerPed() )
+ {
+ fired = FireProjectile(shooter, source, ((CPlayerPed*)shooter)->m_fAttackButtonCounter*0.0375f);
+ if ( m_eWeaponType == WEAPONTYPE_GRENADE )
+ CStats::KgsOfExplosivesUsed++;
+ }
+ else if ( shooter->IsPed() && ((CPed*)shooter)->m_pSeekTarget != nil )
+ {
+ float distToTarget = (shooter->GetPosition() - ((CPed*)shooter)->m_pSeekTarget->GetPosition()).Magnitude();
+ float power = clamp((distToTarget-10.0f)*0.02f, 0.2f, 1.0f);
+
+ fired = FireProjectile(shooter, source, power);
+ }
+ else
+ fired = FireProjectile(shooter, source, 0.3f);
+
+ break;
+ }
+
+ case WEAPONTYPE_FLAMETHROWER:
+ {
+ fired = FireAreaEffect(shooter, source);
+
+ break;
+ }
+
+ case WEAPONTYPE_DETONATOR:
+ {
+ CWorld::UseDetonator(shooter);
+ m_nAmmoTotal = 1;
+ m_nAmmoInClip = m_nAmmoTotal;
+ fired = true;
+
+ break;
+ }
+
+ case WEAPONTYPE_HELICANNON:
+ {
+ if ( (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_HELICANNON_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON )
+ && shooter == FindPlayerPed() )
+ {
+ fired = FireM16_1stPerson(shooter);
+ }
+ else
+ fired = FireInstantHit(shooter, source);
+
+ break;
+ }
+
+ default:
+ {
+ debug("Unknown weapon type, Weapon.cpp");
+ break;
+ }
+ }
+
+ if ( fired )
+ {
+ bool isPlayer = false;
+
+ if ( shooter->IsPed() )
+ {
+ CPed *shooterPed = (CPed*)shooter;
+
+ shooterPed->bIsShooting = true;
+
+ if ( shooterPed->IsPlayer() )
+ isPlayer = true;
+
+ DMAudio.PlayOneShot(shooterPed->m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+ }
+
+ if ( m_nAmmoInClip > 0 ) m_nAmmoInClip--;
+ if ( m_nAmmoTotal > 0 && (m_nAmmoTotal < 25000 || isPlayer) ) m_nAmmoTotal--;
+
+ if ( m_eWeaponState == WEAPONSTATE_READY && m_eWeaponType == WEAPONTYPE_FLAMETHROWER )
+ DMAudio.PlayOneShot(((CPhysical*)shooter)->m_audioEntityId, SOUND_WEAPON_FLAMETHROWER_FIRE, 0.0f);
+
+ m_eWeaponState = WEAPONSTATE_FIRING;
+ }
+
+ if ( m_nAmmoInClip == 0 )
+ {
+ if ( m_nAmmoTotal == 0 )
+ return true;
+
+ m_eWeaponState = WEAPONSTATE_RELOADING;
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload;
+
+ if ( shooter == FindPlayerPed() )
+ {
+ if ( CWorld::Players[CWorld::PlayerInFocus].m_bFastReload )
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload / 4;
+ }
+
+ return true;
+ }
+
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ if ( shooter == FindPlayerPed() )
+ CStats::RoundsFiredByPlayer++;
+ }
+ else
+ {
+ if ( m_eWeaponState != WEAPONSTATE_FIRING )
+ {
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload;
+ m_eWeaponState = WEAPONSTATE_FIRING;
+ }
+
+ FireMelee(shooter, *source);
+ }
+
+ if ( m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT )
+ return true;
+ else
+ return fired;
+}
+
+bool
+CWeapon::FireFromCar(CAutomobile *shooter, bool left)
+{
+ ASSERT(shooter!=nil);
+
+ if ( m_eWeaponState != WEAPONSTATE_READY && m_eWeaponState != WEAPONSTATE_FIRING )
+ return false;
+
+ if ( m_nAmmoInClip <= 0 )
+ return false;
+
+ if ( FireInstantHitFromCar(shooter, left) )
+ {
+ DMAudio.PlayOneShot(shooter->m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+
+ if ( m_nAmmoInClip > 0 ) m_nAmmoInClip--;
+ if ( m_nAmmoTotal < 25000 && m_nAmmoTotal > 0 ) m_nAmmoTotal--;
+
+ m_eWeaponState = WEAPONSTATE_FIRING;
+
+ if ( m_nAmmoInClip == 0 )
+ {
+ if ( m_nAmmoTotal == 0 )
+ return true;
+
+ m_eWeaponState = WEAPONSTATE_RELOADING;
+ m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload;
+
+ return true;
+ }
+
+ m_nTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ if ( shooter == FindPlayerVehicle() )
+ CStats::RoundsFiredByPlayer++;
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireMelee(CEntity *shooter, CVector &fireSource)
+{
+ ASSERT(shooter!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ bool anim2Playing = false;
+ if ( RpAnimBlendClumpGetAssociation(shooter->GetClump(), info->m_Anim2ToPlay) )
+ anim2Playing = true;
+
+ ASSERT(shooter->IsPed());
+
+ CPed *shooterPed = (CPed*)shooter;
+
+ for ( int32 i = 0; i < shooterPed->m_numNearPeds; i++ )
+ {
+ CPed *victimPed = shooterPed->m_nearPeds[i];
+ ASSERT(victimPed!=nil);
+
+ if ( (victimPed->m_nPedType != shooterPed->m_nPedType || victimPed == shooterPed->m_pSeekTarget)
+ && victimPed != shooterPed->m_leader || !(CGeneral::GetRandomNumber() & 31) )
+ {
+ bool collided = false;
+
+ CColModel *victimPedCol = &CTempColModels::ms_colModelPed1;
+ if ( victimPed->OnGround() || !victimPed->IsPedHeadAbovePos(-0.3f) )
+ victimPedCol = &CTempColModels::ms_colModelPedGroundHit;
+
+
+ float victimPedRadius = victimPed->GetBoundRadius() + info->m_fRadius;
+ if ( victimPed->bUsesCollision || victimPed->Dead() || victimPed->Driving() )
+ {
+ CVector victimPedPos = victimPed->GetPosition();
+ if ( SQR(victimPedRadius) > (victimPedPos-(*fireSource)).MagnitudeSqr() )
+ {
+ CVector collisionDist;
+
+ int32 s = 0;
+ while ( s < victimPedCol->numSpheres )
+ {
+ CColSphere *sphere = &victimPedCol->spheres[s];
+ collisionDist = victimPedPos+sphere->center-(*fireSource);
+
+ if ( SQR(sphere->radius + info->m_fRadius) > collisionDist.MagnitudeSqr() )
+ {
+ collided = true;
+ break;
+ }
+ s++;
+ }
+
+ if ( !(victimPed->IsPlayer() && victimPed->GetPedState() == PED_GETUP) )
+ {
+ if ( collided )
+ {
+ float victimPedHealth = victimPed->m_fHealth;
+ CVector bloodPos = fireSource + (collisionDist*0.7f);
+
+ CVector2D posOffset(shooterPed->GetPosition().x-victimPedPos.x, shooterPed->GetPosition().y-victimPedPos.y);
+
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ bool isBat = m_eWeaponType == WEAPONTYPE_BASEBALLBAT;
+
+ if ( !victimPed->DyingOrDead() )
+ victimPed->ReactToAttack(shooterPed);
+
+ uint8 hitLevel = HITLEVEL_HIGH;
+ if ( isBat && victimPed->OnGround() )
+ hitLevel = HITLEVEL_GROUND;
+
+ victimPed->StartFightDefend(localDir, hitLevel, 10);
+
+ if ( !victimPed->DyingOrDead() )
+ {
+ if ( shooterPed->IsPlayer() && isBat && anim2Playing )
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, 100.0f, PEDPIECE_TORSO, localDir);
+ else if ( shooterPed->IsPlayer() && ((CPlayerPed*)shooterPed)->m_bAdrenalineActive )
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, 3.5f*info->m_nDamage, PEDPIECE_TORSO, localDir);
+ else
+ {
+ if ( victimPed->IsPlayer() && isBat ) // wtf, it's not fair
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, 2.0f*info->m_nDamage, PEDPIECE_TORSO, localDir);
+ else
+ victimPed->InflictDamage(shooterPed, m_eWeaponType, info->m_nDamage, PEDPIECE_TORSO, localDir);
+ }
+ }
+
+ if ( CGame::nastyGame )
+ {
+ if ( victimPed->GetIsOnScreen() )
+ {
+ CVector dir = collisionDist * RecipSqrt(1.0f, 10.0f*collisionDist.MagnitudeSqr());
+
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+
+ if ( isBat )
+ {
+ dir.x += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ dir.y += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+
+ dir.x += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ dir.y += CGeneral::GetRandomNumberInRange(-0.05f, 0.05f);
+ CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir);
+ }
+ }
+ }
+
+ if ( !victimPed->OnGround() )
+ {
+ if ( victimPed->m_fHealth > 0.0f
+ && (victimPed->m_fHealth < 20.0f && victimPedHealth > 20.0f || isBat && !victimPed->IsPlayer()) )
+ {
+ posOffset.Normalise();
+ victimPed->bIsStanding = false;
+ victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 3.0f);
+
+ if ( isBat && victimPed->IsPlayer() )
+ victimPed->SetFall(3000, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+ else
+ victimPed->SetFall(1500, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+
+ shooterPed->m_pSeekTarget = victimPed;
+ shooterPed->m_pSeekTarget->RegisterReference(&shooterPed->m_pSeekTarget);
+ }
+ }
+ else if (victimPed->Dying() && !anim2Playing)
+ {
+ posOffset.Normalise();
+ victimPed->bIsStanding = false;
+ victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 3.0f);
+ }
+
+ m_eWeaponState = WEAPONSTATE_MELEE_MADECONTACT;
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_ASSAULT_POLICE, EVENT_ENTITY_PED, victimPed, shooterPed, 2000);
+ else
+ CEventList::RegisterEvent(EVENT_ASSAULT, EVENT_ENTITY_PED, victimPed, shooterPed, 2000);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ CVector source, target;
+ CColPoint point;
+ CEntity *victim = nil;
+
+ float heading = RADTODEG(shooter->GetForward().Heading());
+ float angle = DEGTORAD(heading);
+
+ CVector2D ahead(-Sin(angle), Cos(angle));
+ ahead.Normalise();
+
+ CVector vel = ((CPed *)shooter)->m_vecMoveSpeed;
+ int32 shooterMoving = false;
+ if ( Abs(vel.x) > 0.0f && Abs(vel.y) > 0.0f )
+ shooterMoving = true;
+
+ if ( shooter == FindPlayerPed() )
+ {
+ static float prev_heading = 0.0f;
+ prev_heading = ((CPed*)shooter)->m_fRotationCur;
+ }
+
+ if ( shooter->IsPed() && ((CPed *)shooter)->m_pPointGunAt )
+ {
+ CPed *shooterPed = (CPed *)shooter;
+ if ( shooterPed->m_pedIK.m_flags & CPedIK::GUN_POINTED_SUCCESSFULLY )
+ {
+ int32 accuracy = shooterPed->m_wepAccuracy;
+ int32 inaccuracy = 100-accuracy;
+
+ if ( accuracy != 100 )
+ FindPlayerPed(); //what ?
+
+ CPed *threatAttack = (CPed*)shooterPed->m_pPointGunAt;
+ if ( threatAttack->IsPed() )
+ {
+ threatAttack->m_pedIK.GetComponentPosition(target, PED_MID);
+ threatAttack->ReactToPointGun(shooter);
+ }
+ else
+ target = threatAttack->GetPosition();
+
+ target -= *fireSource;
+ target *= info->m_fRange / target.Magnitude();
+ target += *fireSource;
+
+ if ( inaccuracy != 0 )
+ {
+ target.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f) * inaccuracy;
+ target.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f) * inaccuracy;
+ target.z += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f) * inaccuracy;
+ }
+
+ CWorld::bIncludeDeadPeds = true;
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ CWorld::bIncludeDeadPeds = false;
+ }
+ else
+ {
+ target.x = info->m_fRange;
+ target.y = 0.0f;
+ target.z = 0.0f;
+
+ for (RwFrame *i = shooterPed->GetNodeFrame(PED_HANDR); i; i = RwFrameGetParent(i))
+ RwV3dTransformPoints(target, target, 1, RwFrameGetMatrix(i));
+
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ }
+ }
+ else if ( shooter == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam() )
+ {
+ CVector src, trgt;
+ TheCamera.Find3rdPersonCamTargetVector(info->m_fRange, *fireSource, src, trgt);
+
+ CWorld::bIncludeDeadPeds = true;
+ ProcessLineOfSight(src, trgt,point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ CWorld::bIncludeDeadPeds = false;
+
+ int32 rotSpeed = 1;
+ if ( m_eWeaponType == WEAPONTYPE_M16 )
+ rotSpeed = 4;
+
+ CVector bulletPos;
+ if ( CHeli::TestBulletCollision(&src, &trgt, &bulletPos, 4) )
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, bulletPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, rotSpeed);
+ }
+ }
+ else
+ {
+ float shooterHeading = RADTODEG(shooter->GetForward().Heading());
+ float shooterAngle = DEGTORAD(shooterHeading);
+
+ CVector2D rotOffset(-Sin(shooterAngle), Cos(shooterAngle));
+ rotOffset.Normalise();
+
+ target = *fireSource;
+ target.x = rotOffset.x * info->m_fRange;
+ target.y = rotOffset.y * info->m_fRange;
+
+ if ( shooter->IsPed() )
+ DoDoomAiming(shooter, fireSource, &target);
+
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+
+ int32 rotSpeed = 1;
+ if ( m_eWeaponType == WEAPONTYPE_M16 )
+ rotSpeed = 4;
+
+ CVector bulletPos;
+ if ( CHeli::TestBulletCollision(fireSource, &target, &bulletPos, 4) )
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, bulletPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, rotSpeed);
+ }
+ }
+
+ if ( victim && shooter->IsPed() && victim == ((CPed*)shooter)->m_leader )
+ return false;
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed *)shooter, 1000);
+
+ if ( shooter == FindPlayerPed() )
+ {
+ CStats::InstantHitsFiredByPlayer++;
+ if ( !(CTimer::GetFrameCounter() & 3) )
+ MakePedsJumpAtShot((CPhysical*)shooter, fireSource, &target);
+ }
+
+ switch ( m_eWeaponType )
+ {
+ case WEAPONTYPE_AK47:
+ {
+ static uint8 counter = 0;
+
+ if ( !(++counter & 1) )
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.10f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.08f);
+ gunflashPos += CVector(0.05f*ahead.x, 0.05f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+
+ CVector gunsmokePos = *fireSource;
+ float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*rnd, ahead.y*rnd, 0.0f));
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.5f*ahead.x, 0.5f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.018f);
+ }
+
+ break;
+ }
+
+ case WEAPONTYPE_M16:
+ {
+ static uint8 counter = 0;
+
+ if ( !(++counter & 1) )
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.08f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos.z += 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos.z += 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+ gunflashPos.z += 0.03f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos.z -= 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos.z -= 0.04f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+ gunflashPos.z -= 0.03f;
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ CVector offset = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ offset.Normalise2D();
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos += CVector(0.06f*offset.x, 0.06f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos += CVector(0.04f*offset.x, 0.04f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos += CVector(0.03f*offset.x, 0.03f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ gunflashPos = *fireSource;
+ gunflashPos += CVector(-0.1f*ahead.x, -0.1f*ahead.y, 0.0f);
+ gunflashPos -= CVector(0.06f*offset.x, 0.06f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos -= CVector(0.04f*offset.x, 0.04f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos -= CVector(0.03f*offset.x, 0.03f*offset.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ CVector gunsmokePos = *fireSource;
+ float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*rnd, ahead.y*rnd, 0.0f));
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.65f*ahead.x, 0.65f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.02f);
+ }
+
+ break;
+ }
+
+ case WEAPONTYPE_UZI:
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+
+ if ( shooterMoving )
+ gunflashPos += CVector(1.5f*vel.x, 1.5f*vel.y, 0.0f);
+
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.07f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.05f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos += CVector(0.03f*ahead.x, 0.03f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.03f);
+ gunflashPos += CVector(0.03f*ahead.x, 0.03f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+ gunflashPos += CVector(0.02f*ahead.x, 0.02f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.01f);
+
+ CVector gunsmokePos = *fireSource;
+ float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*rnd, ahead.y*rnd, 0.0f));
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.2f*ahead.x, 0.2f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.015f);
+
+ break;
+ }
+
+ case WEAPONTYPE_COLT45:
+ {
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CVector gunflashPos = *fireSource;
+
+ if ( shooterMoving )
+ gunflashPos += CVector(1.5f*vel.x, 1.5f*vel.y, 0.0f);
+
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f);
+ gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f);
+ gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.02f);
+
+ CVector gunsmokePos = *fireSource;
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*0.10f, ahead.y*0.10f, 0.0f), nil, 0.005f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*0.15f, ahead.y*0.15f, 0.0f), nil, 0.015f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*0.20f, ahead.y*0.20f, 0.0f), nil, 0.025f);
+
+ CVector gunshellPos = *fireSource;
+ gunshellPos -= CVector(0.2f*ahead.x, 0.2f*ahead.y, 0.0f);
+ CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f));
+ dir.Normalise2D();
+ AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.015f);
+
+ break;
+ }
+ }
+
+ DoBulletImpact(shooter, victim, fireSource, &target, &point, ahead);
+
+ return true;
+}
+
+void
+CWeapon::AddGunshell(CEntity *shooter, CVector const &source, CVector2D const &direction, float size)
+{
+ ASSERT(shooter!=nil);
+
+ if ( shooter == nil)
+ return;
+
+ CVector dir(direction.x*0.05f, direction.y*0.05f, CGeneral::GetRandomNumberInRange(0.02f, 0.08f));
+
+ static CVector prevEntityPosition(0.0f, 0.0f, 0.0f);
+ CVector entityPosition = shooter->GetPosition();
+
+ CVector diff = entityPosition - prevEntityPosition;
+
+ if ( Abs(diff.x)+Abs(diff.y)+Abs(diff.z) > 1.5f )
+ {
+ prevEntityPosition = entityPosition;
+
+ CParticle::AddParticle(PARTICLE_GUNSHELL_FIRST,
+ source, dir, nil, size, CGeneral::GetRandomNumberInRange(-20.0f, 20.0f));
+ }
+ else
+ {
+ CParticle::AddParticle(PARTICLE_GUNSHELL,
+ source, dir, nil, size, CGeneral::GetRandomNumberInRange(-20.0f, 20.0f));
+ }
+}
+
+void
+CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim,
+ CVector *source, CVector *target, CColPoint *point, CVector2D ahead)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+ ASSERT(point!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ if ( victim )
+ {
+ CGlass::WasGlassHitByBullet(victim, point->point);
+
+ CVector traceTarget = point->point;
+ CBulletTraces::AddTrace(source, &traceTarget);
+
+ if ( shooter != nil )
+ {
+ if ( shooter == FindPlayerPed() )
+ {
+ if ( victim->IsPed() || victim->IsVehicle() )
+ CStats::InstantHitsHitByPlayer++;
+ }
+ }
+
+ if ( victim->IsPed() && ((CPed*)shooter)->m_nPedType != ((CPed*)victim)->m_nPedType || ((CPed*)shooter)->m_nPedType == PEDTYPE_PLAYER2 )
+ {
+ CPed *victimPed = (CPed *)victim;
+ if ( !victimPed->OnGround() && victim != shooter )
+ {
+ if ( victimPed->DoesLOSBulletHitPed(*point) )
+ {
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset(source->x-pos.x, source->y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ReactToAttack(shooter);
+
+ if ( !victimPed->IsPedInControl() || victimPed->bIsDucking )
+ {
+ victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir);
+ }
+ else
+ {
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN || m_eWeaponType == WEAPONTYPE_HELICANNON )
+ {
+ posOffset.Normalise();
+ victimPed->bIsStanding = false;
+
+ victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 5.0f);
+ victimPed->SetFall(1500, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+
+ victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir);
+ }
+ else
+ {
+ if ( victimPed->IsPlayer() )
+ {
+ CPlayerPed *victimPlayer = (CPlayerPed *)victimPed;
+ if ( victimPlayer->m_nHitAnimDelayTimer < CTimer::GetTimeInMilliseconds() )
+ {
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+
+ if ( m_eWeaponType == WEAPONTYPE_AK47 || m_eWeaponType == WEAPONTYPE_M16 )
+ victimPlayer->m_nHitAnimDelayTimer = CTimer::GetTimeInMilliseconds() + 2500;
+ else
+ victimPlayer->m_nHitAnimDelayTimer = CTimer::GetTimeInMilliseconds() + 1000;
+ }
+ }
+ else
+ {
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+ }
+
+ victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir);
+ }
+ }
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_SHOOT_COP, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+ else
+ CEventList::RegisterEvent(EVENT_SHOOT_PED, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+
+ if ( CGame::nastyGame )
+ {
+ uint8 bloodAmount = 8;
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN || m_eWeaponType == WEAPONTYPE_HELICANNON )
+ bloodAmount = 32;
+
+ CVector dir = (point->point - victim->GetPosition()) * 0.01f;
+ dir.z = 0.01f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ for ( uint8 i = 0; i < bloodAmount; i++ )
+ CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point->point, dir);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( CGame::nastyGame )
+ {
+ CVector dir = (point->point - victim->GetPosition()) * 0.01f;
+ dir.z = 0.01f;
+
+ if ( victim->GetIsOnScreen() )
+ {
+ for ( int32 i = 0; i < 8; i++ )
+ CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point->point + CVector(0.0f, 0.0f, 0.15f), dir);
+ }
+
+ if ( victimPed->Dead() )
+ {
+ CAnimBlendAssociation *asoc;
+ if ( RpAnimBlendClumpGetFirstAssociation(victimPed->GetClump(), ASSOC_FLAG800) )
+ asoc = CAnimManager::BlendAnimation(victimPed->GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f);
+ else
+ asoc = CAnimManager::BlendAnimation(victimPed->GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT, 8.0f);
+
+ if ( asoc )
+ {
+ asoc->SetCurrentTime(0.0f);
+ asoc->flags |= ASSOC_RUNNING;
+ asoc->flags &= ~ASSOC_FADEOUTWHENDONE;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f);
+
+ CVector dist = point->point - (*source);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 2.0f) * CVector(ahead.x, ahead.y, 0.0f);
+ CVector smokePos = *source + offset;
+
+ smokePos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.z += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ ((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage);
+
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f);
+
+ CVector dist = point->point - (*source);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 0.5f) * CVector(ahead.x, ahead.y, 0.0f);
+ CVector smokePos = *source + offset;
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ if ( shooter->IsPed() )
+ {
+ CPed *shooterPed = (CPed *)shooter;
+
+ if ( shooterPed->bNotAllowedToDuck )
+ {
+ if ( shooterPed->bKindaStayInSamePlace && victim != shooterPed->m_pPointGunAt )
+ {
+ shooterPed->bKindaStayInSamePlace = false;
+ shooterPed->m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + 15000;
+ }
+ }
+ }
+
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ for ( int32 i = 0; i < 8; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f);
+
+ CObject *victimObject = (CObject *)victim;
+
+ if ( !victimObject->bInfiniteMass )
+ {
+ if ( victimObject->bIsStatic && victimObject->m_fUprootLimit <= 0.0f )
+ {
+ victimObject->bIsStatic = false;
+ victimObject->AddToMovingList();
+ }
+
+ if ( !victimObject->bIsStatic )
+ {
+ CVector moveForce = point->normal*-4.0f;
+ victimObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z);
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point->point);
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point->point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point->point);
+ break;
+ }
+ }
+ }
+ else
+ CBulletTraces::AddTrace(source, target);
+
+ if ( shooter == FindPlayerPed() )
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z);
+
+ BlowUpExplosiveThings(victim);
+}
+
+bool
+CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ float heading = RADTODEG(shooter->GetForward().Heading());
+ float angle = DEGTORAD(heading);
+
+ CVector2D rotOffset(-Sin(angle), Cos(angle));
+ rotOffset.Normalise();
+
+ CVector gunflashPos = *fireSource;
+ gunflashPos += CVector(rotOffset.x*0.1f, rotOffset.y*0.1f, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f);
+ gunflashPos += CVector(rotOffset.x*0.1f, rotOffset.y*0.1f, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.15f);
+ gunflashPos += CVector(rotOffset.x*0.1f, rotOffset.y*0.1f, 0.0f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.2f);
+ CParticle::AddParticle(PARTICLE_GUNFLASH, *fireSource, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f);
+
+ CVector gunsmokePos = *fireSource;
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.10f, rotOffset.y*0.10f, 0.0f), nil, 0.1f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.15f, rotOffset.y*0.15f, 0.0f), nil, 0.1f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.20f, rotOffset.y*0.20f, 0.0f), nil, 0.1f);
+ CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(rotOffset.x*0.25f, rotOffset.y*0.25f, 0.0f), nil, 0.1f);
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed*)shooter, 1000);
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, *fireSource, CVector(0.0, 0.0, 0.0), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ float shooterAngle;
+
+ if ( shooter->IsPed() && ((CPed*)shooter)->m_pPointGunAt != nil )
+ {
+ CEntity *threatAttack = ((CPed*)shooter)->m_pPointGunAt;
+ shooterAngle = CGeneral::GetAngleBetweenPoints(threatAttack->GetPosition().x, threatAttack->GetPosition().y,
+ (*fireSource).x, (*fireSource).y);
+ }
+ else
+ shooterAngle = RADTODEG(shooter->GetForward().Heading());
+
+
+ for ( int32 i = 0; i < 5; i++ ) // five shoots at once
+ {
+ float shootAngle = DEGTORAD(7.5f*i + shooterAngle - 15.0f);
+ CVector2D shootRot(-Sin(shootAngle), Cos(shootAngle));
+
+ CVector source, target;
+ CColPoint point;
+ CEntity *victim;
+
+ if ( shooter == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam() )
+ {
+ TheCamera.Find3rdPersonCamTargetVector(1.0f, *fireSource, source, target);
+ CVector Left = CrossProduct(TheCamera.Cams[TheCamera.ActiveCam].Front, TheCamera.Cams[TheCamera.ActiveCam].Up);
+
+ float f = float(i - 2) * (DEGTORAD(7.5f) / 2);
+ target = f * Left + target - source;
+ target *= info->m_fRange;
+ target += source;
+
+ ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ }
+ else
+ {
+ target = *fireSource;
+ target.x += shootRot.x * info->m_fRange;
+ target.y += shootRot.y * info->m_fRange;
+
+ if ( shooter->IsPed() )
+ {
+ CPed *shooterPed = (CPed *)shooter;
+
+ if ( shooterPed->m_pPointGunAt == nil )
+ DoDoomAiming(shooter, fireSource, &target);
+ else
+ {
+ float distToTarget = (shooterPed->m_pPointGunAt->GetPosition() - (*fireSource)).Magnitude2D();
+ target.z += info->m_fRange / distToTarget * (shooterPed->m_pPointGunAt->GetPosition().z - target.z);
+ }
+ }
+
+ ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ }
+
+ if ( victim )
+ {
+ CGlass::WasGlassHitByBullet(victim, point.point);
+
+ CBulletTraces::AddTrace(fireSource, &point.point);
+
+ if ( victim->IsPed() )
+ {
+ CPed *victimPed = (CPed *)victim;
+ if ( !victimPed->OnGround() && victim != shooter && victimPed->DoesLOSBulletHitPed(point) )
+ {
+ bool cantStandup = true;
+
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset((*fireSource).x-pos.x, (*fireSource).y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ReactToAttack(FindPlayerPed());
+
+ posOffset.Normalise();
+
+ if ( victimPed->m_getUpTimer > (CTimer::GetTimeInMilliseconds() - 3000) )
+ cantStandup = false;
+
+ if ( victimPed->bIsStanding && cantStandup )
+ {
+ victimPed->bIsStanding = false;
+
+ victimPed->ApplyMoveForce(posOffset.x*-6.0f, posOffset.y*-6.0f, 5.0f);
+ }
+ else
+ victimPed->ApplyMoveForce(posOffset.x*-2.0f, posOffset.y*-2.0f, 0.0f);
+
+ if ( cantStandup )
+ victimPed->SetFall(1500, AnimationId(ANIM_KO_SKID_FRONT + localDir), false);
+
+ victimPed->InflictDamage(nil, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point.pieceB, localDir);
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_SHOOT_COP, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+ else
+ CEventList::RegisterEvent(EVENT_SHOOT_PED, EVENT_ENTITY_PED, victim, (CPed*)shooter, 10000);
+
+ if ( CGame::nastyGame )
+ {
+ uint8 bloodAmount = 8;
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN )
+ bloodAmount = 32;
+
+ CVector dir = (point.point - victim->GetPosition()) * 0.01f;
+ dir.z = 0.01f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ for ( uint8 i = 0; i < bloodAmount; i++ )
+ CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point.point, dir);
+ }
+ }
+ }
+ }
+ else
+ {
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_VEHICLE:
+ {
+ ((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage);
+
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal*0.05f);
+
+ CVector dist = point.point - (*fireSource);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 2.0f) * CVector(shootRot.x, shootRot.y, 0.0f);
+ CVector smokePos = *fireSource + offset;
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ break;
+ }
+
+ case ENTITY_TYPE_BUILDING:
+ case ENTITY_TYPE_OBJECT:
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal*0.05f);
+
+ CVector dist = point.point - (*fireSource);
+ CVector offset = dist - max(0.2f*dist.Magnitude(), 2.0f) * CVector(shootRot.x, shootRot.y, 0.0f);
+ CVector smokePos = *fireSource + offset;
+
+ smokePos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+ smokePos.z += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f);
+
+ CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f));
+
+ if ( victim->IsObject() )
+ {
+ CObject *victimObject = (CObject *)victim;
+
+ if ( !victimObject->bInfiniteMass )
+ {
+ if ( victimObject->bIsStatic && victimObject->m_fUprootLimit <= 0.0f )
+ {
+ victimObject->bIsStatic = false;
+ victimObject->AddToMovingList();
+ }
+
+ if ( !victimObject->bIsStatic )
+ {
+ CVector moveForce = point.normal*-5.0f;
+ victimObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z);
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point.point);
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point.point);
+ break;
+ }
+ }
+ }
+ else
+ {
+ CVector traceTarget = *fireSource;
+ traceTarget += (target - (*fireSource)) * min(info->m_fRange, 30.0f) / info->m_fRange;
+ CBulletTraces::AddTrace(fireSource, &traceTarget);
+ }
+ }
+
+ if ( shooter == FindPlayerPed() )
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z);
+
+ return true;
+}
+
+bool
+CWeapon::FireProjectile(CEntity *shooter, CVector *fireSource, float power)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CVector source, target;
+
+ if ( m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER )
+ {
+ source = *fireSource;
+
+ if ( shooter->IsPed() && ((CPed*)shooter)->IsPlayer() )
+ {
+ int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+ if (!( mode == CCam::MODE_M16_1STPERSON
+ || mode == CCam::MODE_SNIPER
+ || mode == CCam::MODE_ROCKETLAUNCHER
+ || mode == CCam::MODE_M16_1STPERSON_RUNABOUT
+ || mode == CCam::MODE_SNIPER_RUNABOUT
+ || mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) )
+ {
+ return false;
+ }
+
+ *fireSource += TheCamera.Cams[TheCamera.ActiveCam].Front;
+ }
+ else
+ *fireSource += shooter->GetForward();
+
+ target = *fireSource;
+ }
+ else
+ {
+ float dot = DotProduct(*fireSource-shooter->GetPosition(), shooter->GetForward());
+
+ if ( dot < 0.3f )
+ *fireSource += (0.3f-dot) * shooter->GetForward();
+
+ target = *fireSource;
+
+ if ( target.z - shooter->GetPosition().z > 0.0f )
+ target += 0.6f*shooter->GetForward();
+
+ source = *fireSource - shooter->GetPosition();
+
+ source = *fireSource - DotProduct(source, shooter->GetForward()) * shooter->GetForward();
+ }
+
+ if ( !CWorld::GetIsLineOfSightClear(source, target, true, true, false, true, false, false, false) )
+ {
+ if ( m_eWeaponType != WEAPONTYPE_GRENADE )
+ CProjectileInfo::RemoveNotAdd(shooter, m_eWeaponType, *fireSource);
+ else
+ {
+ if ( shooter->IsPed() )
+ {
+ source = shooter->GetPosition() - shooter->GetForward();
+ source.z -= 0.4f;
+
+ if ( !CWorld::TestSphereAgainstWorld(source, 0.5f, nil, false, false, true, false, false, false) )
+ CProjectileInfo::AddProjectile(shooter, m_eWeaponType, source, 0.0f);
+ else
+ CProjectileInfo::RemoveNotAdd(shooter, m_eWeaponType, *fireSource);
+ }
+ }
+ }
+ else
+ CProjectileInfo::AddProjectile(shooter, m_eWeaponType, *fireSource, power);
+
+ return true;
+}
+
+void
+CWeapon::GenerateFlameThrowerParticles(CVector pos, CVector dir)
+{
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+
+ dir *= 0.7f;
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos, dir);
+}
+
+bool
+CWeapon::FireAreaEffect(CEntity *shooter, CVector *fireSource)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(fireSource!=nil);
+
+ CWeaponInfo *info = GetInfo();
+
+ float heading = RADTODEG(shooter->GetForward().Heading());
+
+ CVector source;
+ CVector target;
+ CVector dir;
+
+ if ( shooter == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam() )
+ {
+ TheCamera.Find3rdPersonCamTargetVector(info->m_fRange, *fireSource, source, target);
+ float norm = (1.0f / info->m_fRange);
+ dir = (target - source) * norm;
+ }
+ else
+ {
+ float angle = DEGTORAD(heading);
+ dir = CVector(-Sin(angle)*0.5f, Cos(angle)*0.5f, 0.0f);
+ target = *fireSource + dir;
+ }
+
+ CShotInfo::AddShot(shooter, m_eWeaponType, *fireSource, target);
+ CWeapon::GenerateFlameThrowerParticles(*fireSource, dir);
+
+ return true;
+}
+
+bool
+CWeapon::FireSniper(CEntity *shooter)
+{
+ ASSERT(shooter!=nil);
+
+ int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+ if (!( mode == CCam::MODE_M16_1STPERSON
+ || mode == CCam::MODE_SNIPER
+ || mode == CCam::MODE_ROCKETLAUNCHER
+ || mode == CCam::MODE_M16_1STPERSON_RUNABOUT
+ || mode == CCam::MODE_SNIPER_RUNABOUT
+ || mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) )
+ {
+ return false;
+ }
+
+#ifndef FIX_BUGS
+ CWeaponInfo *info = GetInfo(); //unused
+#endif
+
+ CCam *cam = &TheCamera.Cams[TheCamera.ActiveCam];
+ ASSERT(cam!=nil);
+
+ CVector source = cam->Source;
+ CVector dir = cam->Front;
+
+ if ( DotProduct(dir, CVector(0.0f, -0.9894f, 0.145f)) > 0.997f )
+ CCoronas::bSmallMoon = !CCoronas::bSmallMoon;
+
+ dir.Normalise();
+ dir *= 16.0f;
+
+ CBulletInfo::AddBullet(shooter, m_eWeaponType, source, dir);
+
+ if ( shooter == FindPlayerPed() )
+ CStats::InstantHitsFiredByPlayer++;
+
+ if ( shooter == FindPlayerPed() )
+ {
+ CPad::GetPad(0)->StartShake_Distance(240, 128,
+ FindPlayerPed()->GetPosition().x,
+ FindPlayerPed()->GetPosition().y,
+ FindPlayerPed()->GetPosition().z);
+
+ CamShakeNoPos(&TheCamera, 0.2f);
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireM16_1stPerson(CEntity *shooter)
+{
+ ASSERT(shooter!=nil);
+
+ int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode;
+
+ if (!( mode == CCam::MODE_M16_1STPERSON
+ || mode == CCam::MODE_SNIPER
+ || mode == CCam::MODE_ROCKETLAUNCHER
+ || mode == CCam::MODE_M16_1STPERSON_RUNABOUT
+ || mode == CCam::MODE_SNIPER_RUNABOUT
+ || mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT
+ || mode == CCam::MODE_HELICANNON_1STPERSON) )
+ {
+ return false;
+ }
+
+ CWeaponInfo *info = GetInfo();
+
+ CColPoint point;
+ CEntity *victim;
+
+ CWorld::bIncludeCarTyres = true;
+ CWorld::pIgnoreEntity = shooter;
+ CWorld::bIncludeDeadPeds = true;
+
+ CCam *cam = &TheCamera.Cams[TheCamera.ActiveCam];
+ ASSERT(cam!=nil);
+
+ CVector source = cam->Source;
+ CVector target = cam->Front*info->m_fRange + source;
+
+ ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+ CWorld::bIncludeDeadPeds = false;
+ CWorld::pIgnoreEntity = nil;
+ CWorld::bIncludeCarTyres = false;
+
+ CVector2D front(cam->Front.x, cam->Front.y);
+ front.Normalise();
+
+ DoBulletImpact(shooter, victim, &source, &target, &point, front);
+
+ CVector bulletPos;
+ if ( CHeli::TestBulletCollision(&source, &target, &bulletPos, 4) )
+ {
+ for ( int32 i = 0; i < 16; i++ )
+ CParticle::AddParticle(PARTICLE_SPARK, bulletPos, CVector(0.0f, 0.0f, 0.0f));
+ }
+
+ if ( shooter == FindPlayerPed() )
+ {
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z);
+
+ if ( m_eWeaponType == WEAPONTYPE_M16 )
+ {
+ TheCamera.Cams[TheCamera.ActiveCam].Beta += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0003f;
+ TheCamera.Cams[TheCamera.ActiveCam].Alpha += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0003f;
+ }
+ else if ( m_eWeaponType == WEAPONTYPE_HELICANNON )
+ {
+ TheCamera.Cams[TheCamera.ActiveCam].Beta += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0001f;
+ TheCamera.Cams[TheCamera.ActiveCam].Alpha += float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0001f;
+ }
+ }
+
+ return true;
+}
+
+bool
+CWeapon::FireInstantHitFromCar(CAutomobile *shooter, bool left)
+{
+ CWeaponInfo *info = GetInfo();
+
+ CVehicleModelInfo *modelInfo = shooter->GetModelInfo();
+
+ #define FRONTSEATPOS() (&(shooter->IsBoat() ? modelInfo->m_positions[BOAT_POS_FRONTSEAT] : modelInfo->m_positions[CAR_POS_FRONTSEAT]))
+
+ CVector source, target;
+ if ( left )
+ {
+ source = shooter->GetMatrix() * CVector(-shooter->GetColModel()->boundingBox.max.x + -0.2f,
+ float(CGeneral::GetRandomNumber() & 255) * 0.001f + FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed;
+
+
+ target = shooter->GetMatrix() * CVector(-info->m_fRange,
+ FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ }
+ else
+ {
+ source = shooter->GetMatrix() * CVector(shooter->GetColModel()->boundingBox.max.x + 0.2f,
+ float(CGeneral::GetRandomNumber() & 255) * 0.001f + FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed;
+
+ target = shooter->GetMatrix() * CVector(info->m_fRange,
+ FRONTSEATPOS()->y,
+ FRONTSEATPOS()->z + 0.5f);
+ }
+ #undef FRONTSEATPOS
+
+ if ( TheCamera.GetLookingLRBFirstPerson() && !left )
+ {
+ source -= 0.3f * shooter->GetForward();
+ target -= 0.3f * shooter->GetForward();
+ }
+
+ target += CVector(float(CGeneral::GetRandomNumber()&255)*0.01f-1.28f,
+ float(CGeneral::GetRandomNumber()&255)*0.01f-1.28f,
+ float(CGeneral::GetRandomNumber()&255)*0.01f-1.28f);
+
+ DoDriveByAutoAiming(FindPlayerPed(), &source, &target);
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, FindPlayerPed(), FindPlayerPed(), 1000);
+
+ if ( !TheCamera.GetLookingLRBFirstPerson() )
+ CParticle::AddParticle(PARTICLE_GUNFLASH, source, CVector(0.0f, 0.0f, 0.0f));
+ else
+ CamShakeNoPos(&TheCamera, 0.01f);
+
+ CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_VEHICLE, shooter, FindPlayerPed(), 1000);
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT, source, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CColPoint point;
+ CEntity *victim;
+ ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false);
+
+ if ( !(CTimer::GetFrameCounter() & 3) )
+ MakePedsJumpAtShot(shooter, &source, &target);
+
+ if ( victim )
+ {
+ CVector traceTarget = point.point;
+ CBulletTraces::AddTrace(&source, &traceTarget);
+
+ if ( victim->IsPed() )
+ {
+ CPed *victimPed = (CPed*)victim;
+
+ if ( !victimPed->DyingOrDead() && victim != (CEntity *)shooter )
+ {
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset(source.x-pos.x, source.y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ReactToAttack(FindPlayerPed());
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+
+ victimPed->InflictDamage(shooter, WEAPONTYPE_UZI_DRIVEBY, 3*info->m_nDamage, (ePedPieceTypes)point.pieceB, localDir);
+
+ pos.z += 0.8f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ if ( CGame::nastyGame )
+ {
+ for ( int32 i = 0; i < 4; i++ )
+ {
+ CVector dir;
+ dir.x = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.y = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.z = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+
+ CParticle::AddParticle(PARTICLE_BLOOD, pos, dir);
+ }
+ }
+ }
+
+ if ( victimPed->m_nPedType == PEDTYPE_COP )
+ CEventList::RegisterEvent(EVENT_SHOOT_COP, EVENT_ENTITY_PED, victimPed, FindPlayerPed(), 10000);
+ else
+ CEventList::RegisterEvent(EVENT_SHOOT_PED, EVENT_ENTITY_PED, victimPed, FindPlayerPed(), 10000);
+ }
+ }
+ else if ( victim->IsVehicle() )
+ ((CVehicle *)victim)->InflictDamage(FindPlayerPed(), WEAPONTYPE_UZI_DRIVEBY, info->m_nDamage);
+ else
+ CGlass::WasGlassHitByBullet(victim, point.point);
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point.point);
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point.point);
+ break;
+ }
+ }
+ }
+ else
+ {
+ float norm = 30.0f/info->m_fRange;
+ CVector traceTarget = (target-source)*norm + source;
+ CBulletTraces::AddTrace(&source, &traceTarget);
+ }
+
+ if ( shooter == FindPlayerVehicle() )
+ CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerVehicle()->GetPosition().x, FindPlayerVehicle()->GetPosition().y, FindPlayerVehicle()->GetPosition().z);
+
+ return true;
+}
+
+void
+CWeapon::DoDoomAiming(CEntity *shooter, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target !=nil);
+
+#ifndef FIX_BUGS
+ CEntity entity; // unused
+#endif
+
+ CPed *shooterPed = (CPed*)shooter;
+ if ( shooterPed->IsPed() && shooterPed->bCrouchWhenShooting )
+ return;
+
+ int16 lastEntity;
+ CEntity *entities[16];
+ CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, entities, false, true, true, false, false);
+
+ float closestEntityDist = 10000.0f;
+ int16 closestEntity;
+
+ for ( int32 i = 0; i < lastEntity; i++ )
+ {
+ CEntity *victim = entities[i];
+ ASSERT(victim!=nil);
+
+ if ( (CEntity*)shooterPed != victim && shooterPed->CanSeeEntity(victim, DEGTORAD(22.5f)) )
+ {
+ if ( !(victim->m_status == STATUS_TRAIN_MOVING
+ || victim->m_status == STATUS_TRAIN_NOT_MOVING
+ || victim->m_status == STATUS_HELI
+ || victim->m_status == STATUS_PLANE) )
+ {
+ float distToVictim = (shooterPed->GetPosition()-victim->GetPosition()).Magnitude2D();
+ float distToVictimZ = Abs(shooterPed->GetPosition().z-victim->GetPosition().z);
+
+ if ( 1.5f*distToVictimZ < distToVictim )
+ {
+ float entityDist = Sqrt(SQR(distToVictim) + SQR(distToVictimZ));
+
+ if ( entityDist < closestEntityDist )
+ {
+ closestEntityDist = entityDist;
+ closestEntity = i;
+ }
+ }
+ }
+ }
+ }
+
+ if ( closestEntityDist < DOOMAUTOAIMING_MAXDIST )
+ {
+ CEntity *victim = entities[closestEntity];
+ ASSERT(victim !=nil);
+
+ float distToTarget = (*target - *source).Magnitude2D();
+ float distToSource = (victim->GetPosition() - *source).Magnitude2D();
+
+ float victimZ = victim->GetPosition().z + 0.3f;
+ if ( victim->IsPed() )
+ {
+ if ( ((CPed*)victim)->bIsDucking )
+ victimZ -= 0.8f;
+ }
+
+ (*target).z = (distToTarget / distToSource) * (victimZ - (*source).z) + (*source).z;
+ }
+}
+
+void
+CWeapon::DoTankDoomAiming(CEntity *shooter, CEntity *driver, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(driver!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+#ifndef FIX_BUGS
+ CEntity entity; // unused
+#endif
+
+ int16 lastEntity;
+ CEntity *entities[16];
+ CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, entities, false, true, false, false, false);
+
+ float closestEntityDist = 10000.0f;
+ int16 closestEntity;
+
+ float normZ = (target->z - source->z) / (*target-*source).Magnitude();
+
+ for ( int32 i = 0; i < lastEntity; i++ )
+ {
+ CEntity *victim = entities[i];
+
+ ASSERT(victim!=nil);
+
+ if ( shooter != victim && driver != victim )
+ {
+ if ( !(victim->m_status == STATUS_TRAIN_MOVING
+ || victim->m_status == STATUS_TRAIN_NOT_MOVING
+ || victim->m_status == STATUS_HELI
+ || victim->m_status == STATUS_PLANE) )
+ {
+ if ( !(victim->IsVehicle() && victim->bRenderScorched) )
+ {
+ float distToVictim = (shooter->GetPosition()-victim->GetPosition()).Magnitude2D();
+ float distToVictimZ = Abs(shooter->GetPosition().z - (distToVictim*normZ + victim->GetPosition().z));
+
+ if ( 3.0f*distToVictimZ < distToVictim )
+ {
+ if ( CCollision::DistToLine(source, target,
+ &CVector(victim->GetPosition().x, victim->GetPosition().y, 0.0f)) < victim->GetBoundRadius()*3.0f )
+ {
+ float vehicleDist = Sqrt(SQR(distToVictim) + SQR(distToVictimZ));
+ if ( vehicleDist < closestEntityDist )
+ {
+ closestEntityDist = vehicleDist;
+ closestEntity = i;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( closestEntityDist < DOOMAUTOAIMING_MAXDIST )
+ {
+ CEntity *victim = entities[closestEntity];
+ ASSERT(victim!=nil);
+
+ float distToTarget = (*target - *source).Magnitude2D();
+ float distToSource = (victim->GetPosition() - *source).Magnitude2D();
+
+ (*target).z = (distToTarget / distToSource) * (0.3f + victim->GetPosition().z - (*source).z) + (*source).z;
+ }
+}
+
+void
+CWeapon::DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+#ifndef FIX_BUGS
+ CEntity entity; // unused
+#endif
+
+ CPed *shooterPed = (CPed*)shooter;
+ if ( shooterPed->IsPed() && shooterPed->bCrouchWhenShooting )
+ return;
+
+ int16 lastEntity;
+ CEntity *entities[16];
+ CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, entities, false, false, true, false, false);
+
+ float closestEntityDist = 10000.0f;
+ int16 closestEntity;
+
+ for ( int32 i = 0; i < lastEntity; i++ )
+ {
+ CEntity *victim = entities[i];
+ ASSERT(victim!=nil);
+
+ if ( shooter != victim )
+ {
+ float lineDist = CCollision::DistToLine(source, target, &victim->GetPosition());
+ float distToVictim = (victim->GetPosition() - shooter->GetPosition()).Magnitude();
+ float pedDist = 0.15f*distToVictim + lineDist;
+
+ if ( DotProduct((*target-*source), victim->GetPosition()-*source) > 0.0f && pedDist < closestEntityDist)
+ {
+ closestEntity = i;
+ closestEntityDist = pedDist;
+ }
+ }
+ }
+
+ if ( closestEntityDist < DRIVEBYAUTOAIMING_MAXDIST )
+ {
+ CEntity *victim = entities[closestEntity];
+ ASSERT(victim!=nil);
+
+ float distToTarget = (*source - *target).Magnitude();
+ float distToSource = (*source - victim->GetPosition()).Magnitude();
+ *target = (distToTarget / distToSource) * (victim->GetPosition() - *source) + *source;
+ }
+}
+
void
CWeapon::Reload(void)
{
if (m_nAmmoTotal == 0)
return;
- CWeaponInfo *info = CWeaponInfo::GetWeaponInfo(m_eWeaponType);
+ CWeaponInfo *info = GetInfo();
if (m_nAmmoTotal >= info->m_nAmountofAmmunition)
m_nAmmoInClip = info->m_nAmountofAmmunition;
@@ -44,10 +1971,159 @@ CWeapon::Reload(void)
m_nAmmoInClip = m_nAmmoTotal;
}
-bool
-CWeapon::IsType2Handed(void)
+void
+CWeapon::Update(int32 audioEntity)
{
- return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER;
+ switch ( m_eWeaponState )
+ {
+ case WEAPONSTATE_MELEE_MADECONTACT:
+ {
+ m_eWeaponState = WEAPONSTATE_READY;
+ break;
+ }
+
+ case WEAPONSTATE_FIRING:
+ {
+ if ( m_eWeaponType == WEAPONTYPE_SHOTGUN && AEHANDLE_IS_OK(audioEntity) )
+ {
+ uint32 timePassed = m_nTimer - gReloadSampleTime[WEAPONTYPE_SHOTGUN];
+ if ( CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed )
+ DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f);
+ }
+
+ if ( CTimer::GetTimeInMilliseconds() > m_nTimer )
+ {
+ if ( GetInfo()->m_eWeaponFire != WEAPON_FIRE_MELEE && m_nAmmoTotal == 0 )
+ m_eWeaponState = WEAPONSTATE_OUT_OF_AMMO;
+ else
+ m_eWeaponState = WEAPONSTATE_READY;
+ }
+
+ break;
+ }
+
+ case WEAPONSTATE_RELOADING:
+ {
+ if ( AEHANDLE_IS_OK(audioEntity) && m_eWeaponType < WEAPONTYPE_LAST_WEAPONTYPE )
+ {
+ uint32 timePassed = m_nTimer - gReloadSampleTime[m_eWeaponType];
+ if ( CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed )
+ DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f);
+ }
+
+ if ( CTimer::GetTimeInMilliseconds() > m_nTimer )
+ {
+ Reload();
+ m_eWeaponState = WEAPONSTATE_READY;
+ }
+
+ break;
+ }
+ }
+}
+
+void
+FireOneInstantHitRound(CVector *source, CVector *target, int32 damage)
+{
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+ CParticle::AddParticle(PARTICLE_GUNFLASH, *source, CVector(0.0f, 0.0f, 0.0f));
+
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ *source, CVector(0.0f, 0.0f, 0.0f), 5.0f,
+ 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false);
+
+ CColPoint point;
+ CEntity *victim;
+ CWorld::ProcessLineOfSight(*source, *target, point, victim, true, true, true, true, true, true, false);
+
+ CParticle::AddParticle(PARTICLE_HELI_ATTACK, *source, ((*target) - (*source)) * 0.15f);
+
+ if ( victim )
+ {
+ if ( victim->IsPed() )
+ {
+ CPed *victimPed = (CPed *)victim;
+ if ( !victimPed->DyingOrDead() )
+ {
+ CVector pos = victimPed->GetPosition();
+
+ CVector2D posOffset((*source).x-pos.x, (*source).y-pos.y);
+ int32 localDir = victimPed->GetLocalDirection(posOffset);
+
+ victimPed->ClearAttackByRemovingAnim();
+
+ CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_SHOT_FRONT_PARTIAL + localDir));
+ ASSERT(asoc!=nil);
+ asoc->blendAmount = 0.0f;
+ asoc->blendDelta = 8.0f;
+
+ victimPed->InflictDamage(nil, WEAPONTYPE_UZI, damage, (ePedPieceTypes)point.pieceB, localDir);
+
+ pos.z += 0.8f;
+
+ if ( victimPed->GetIsOnScreen() )
+ {
+ if ( CGame::nastyGame )
+ {
+ for ( int32 i = 0; i < 4; i++ )
+ {
+ CVector dir;
+ dir.x = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.y = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+ dir.z = CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
+
+ CParticle::AddParticle(PARTICLE_BLOOD, pos, dir);
+ }
+ }
+ }
+ }
+ }
+ else if ( victim->IsVehicle() )
+ ((CVehicle *)victim)->InflictDamage(nil, WEAPONTYPE_UZI, damage);
+ //BUG ? no CGlass::WasGlassHitByBullet
+
+ switch ( victim->m_type )
+ {
+ case ENTITY_TYPE_BUILDING:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_1, point.point);
+ CParticle::AddParticle(PARTICLE_SMOKE, point.point, CVector(0.0f, 0.0f, 0.01f));
+ break;
+ }
+ case ENTITY_TYPE_VEHICLE:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f);
+ break;
+ }
+ case ENTITY_TYPE_PED:
+ {
+ DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f);
+ ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT);
+ break;
+ }
+ case ENTITY_TYPE_OBJECT:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point);
+ break;
+ }
+ case ENTITY_TYPE_DUMMY:
+ {
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_3, point.point);
+ break;
+ }
+ }
+ }
+ else
+ {
+ float waterLevel;
+ if ( CWaterLevel::GetWaterLevel((*target).x, (*target).y, (*target).z + 10.0f, &waterLevel, false) )
+ {
+ CParticle::AddParticle(PARTICLE_BOAT_SPLASH, CVector((*target).x, (*target).y, waterLevel), CVector(0.0f, 0.0f, 0.01f));
+ PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_WATER, point.point); // no sound(empty)
+ }
+ }
}
bool
@@ -57,32 +2133,75 @@ CWeapon::IsTypeMelee(void)
}
bool
-CWeapon::HitsGround(CEntity *holder, CVector *firePos, CEntity *aimingTo)
+CWeapon::IsType2Handed(void)
{
+ return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER;
+}
+
+void
+CWeapon::MakePedsJumpAtShot(CPhysical *shooter, CVector *source, CVector *target)
+{
+ ASSERT(shooter!=nil);
+ ASSERT(source!=nil);
+ ASSERT(target!=nil);
+
+ float minx = min(source->x, target->x) - 2.0f;
+ float maxx = max(source->x, target->x) + 2.0f;
+ float miny = min(source->y, target->y) - 2.0f;
+ float maxy = max(source->y, target->y) + 2.0f;
+ float minz = min(source->z, target->z) - 2.0f;
+ float maxz = max(source->z, target->z) + 2.0f;
+
+ for ( int32 i = CPools::GetPedPool()->GetSize() - 1; i >= 0; i--)
+ {
+ CPed *ped = CPools::GetPedPool()->GetSlot(i);
+
+ if ( ped )
+ {
+ if ( ped->GetPosition().x > minx && ped->GetPosition().x < maxx
+ && ped->GetPosition().y > miny && ped->GetPosition().y < maxy
+ && ped->GetPosition().z > minz && ped->GetPosition().z < maxz )
+ {
+ if ( ped != FindPlayerPed() && !((uint8)(ped->m_randomSeed ^ CGeneral::GetRandomNumber()) & 31) )
+ ped->SetEvasiveDive(shooter, 1);
+ }
+ }
+ }
+}
+
+bool
+CWeapon::HitsGround(CEntity *holder, CVector *fireSource, CEntity *aimingTo)
+{
+ ASSERT(holder!=nil);
+ ASSERT(aimingTo!=nil);
+
if (!holder->IsPed() || !((CPed*)holder)->m_pSeekTarget)
return false;
- CWeaponInfo *ourType = CWeaponInfo::GetWeaponInfo(m_eWeaponType);
- CVector adjustedOffset = ourType->m_vecFireOffset;
+ CWeaponInfo *info = GetInfo();
+
+ CVector adjustedOffset = info->m_vecFireOffset;
adjustedOffset.z += 0.6f;
- CVector point1, point2;
+ CVector source, target;
CEntity *foundEnt = nil;
CColPoint foundCol;
- if (firePos)
- point1 = *firePos;
+ if (fireSource)
+ source = *fireSource;
else
- point1 = holder->GetMatrix() * adjustedOffset;
+ source = holder->GetMatrix() * adjustedOffset;
CEntity *aimEntity = aimingTo ? aimingTo : ((CPed*)holder)->m_pSeekTarget;
- point2 = aimEntity->GetPosition();
- point2.z += 0.6f;
+ ASSERT(aimEntity!=nil);
+
+ target = aimEntity->GetPosition();
+ target.z += 0.6f;
- CWorld::ProcessLineOfSight(point1, point2, foundCol, foundEnt, true, false, false, false, false, false, false);
+ CWorld::ProcessLineOfSight(source, target, foundCol, foundEnt, true, false, false, false, false, false, false);
if (foundEnt && foundEnt->IsBuilding()) {
// That was supposed to be Magnitude, according to leftover code in assembly
- float diff = (foundCol.point.z - point1.z);
+ float diff = (foundCol.point.z - source.z);
if (diff < 0.0f && diff > -3.0f)
return true;
}
@@ -90,6 +2209,36 @@ CWeapon::HitsGround(CEntity *holder, CVector *firePos, CEntity *aimingTo)
return false;
}
+void
+CWeapon::BlowUpExplosiveThings(CEntity *thing)
+{
+ if ( thing )
+ {
+ CObject *object = (CObject*)thing;
+ int32 mi = object->GetModelIndex();
+ if ( IsExplosiveThingModel(mi) && !object->bHasBeenDamaged )
+ {
+ object->bHasBeenDamaged = true;
+
+ CExplosion::AddExplosion(object, FindPlayerPed(), EXPLOSION_BARREL, object->GetPosition()+CVector(0.0f,0.0f,0.5f), 100);
+
+ if ( MI_EXPLODINGBARREL == mi )
+ object->m_vecMoveSpeed.z += 0.75f;
+ else
+ object->m_vecMoveSpeed.z += 0.45f;
+
+ object->m_vecMoveSpeed.x += float((CGeneral::GetRandomNumber()&255) - 128) * 0.0002f;
+ object->m_vecMoveSpeed.y += float((CGeneral::GetRandomNumber()&255) - 128) * 0.0002f;
+
+ if ( object->bIsStatic )
+ {
+ object->bIsStatic = false;
+ object->AddToMovingList();
+ }
+ }
+ }
+}
+
bool
CWeapon::HasWeaponAmmoToBeUsed(void)
{
@@ -102,8 +2251,42 @@ CWeapon::HasWeaponAmmoToBeUsed(void)
}
}
+bool
+CWeapon::ProcessLineOfSight(CVector const &point1, CVector const &point2, CColPoint &point, CEntity *&entity, eWeaponType type, CEntity *shooter, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
+{
+ return CWorld::ProcessLineOfSight(point1, point2, point, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects);
+}
+
STARTPATCHES
+
+ InjectHook(0x55C2D0, CWeapon::InitialiseWeapons, PATCH_JUMP);
+ InjectHook(0x55C2F0, CWeapon::ShutdownWeapons, PATCH_JUMP);
+ InjectHook(0x55C310, CWeapon::UpdateWeapons, PATCH_JUMP);
InjectHook(0x55C330, &CWeapon::Initialise, PATCH_JUMP);
+ InjectHook(0x55C380, &CWeapon::Fire, PATCH_JUMP);
+ InjectHook(0x55C940, &CWeapon::FireFromCar, PATCH_JUMP);
+ InjectHook(0x55CA20, &CWeapon::FireMelee, PATCH_JUMP);
+ InjectHook(0x55D2E0, &CWeapon::FireInstantHit, PATCH_JUMP);
+ InjectHook(0x55F770, &CWeapon::AddGunshell, PATCH_JUMP);
+ InjectHook(0x55F950, &CWeapon::DoBulletImpact, PATCH_JUMP);
+ InjectHook(0x560620, &CWeapon::FireShotgun, PATCH_JUMP);
+ InjectHook(0x561900, &CWeapon::FireProjectile, PATCH_JUMP);
+ InjectHook(0x561C70, CWeapon::GenerateFlameThrowerParticles, PATCH_JUMP);
+ InjectHook(0x561E00, &CWeapon::FireAreaEffect, PATCH_JUMP);
+ InjectHook(0x561FE0, &CWeapon::FireSniper, PATCH_JUMP);
+ InjectHook(0x562180, &CWeapon::FireM16_1stPerson, PATCH_JUMP);
+ InjectHook(0x5624D0, &CWeapon::FireInstantHitFromCar, PATCH_JUMP);
+ InjectHook(0x562EB0, CWeapon::DoDoomAiming, PATCH_JUMP);
+ InjectHook(0x563200, CWeapon::DoTankDoomAiming, PATCH_JUMP);
+ InjectHook(0x563660, CWeapon::DoDriveByAutoAiming, PATCH_JUMP);
InjectHook(0x5639D0, &CWeapon::Reload, PATCH_JUMP);
+ InjectHook(0x563A10, &CWeapon::Update, PATCH_JUMP);
+ InjectHook(0x563FB0, &CWeapon::IsTypeMelee, PATCH_JUMP);
+ InjectHook(0x563FD0, &CWeapon::IsType2Handed, PATCH_JUMP);
+ InjectHook(0x564680, CWeapon::MakePedsJumpAtShot, PATCH_JUMP);
InjectHook(0x564890, &CWeapon::HitsGround, PATCH_JUMP);
+ InjectHook(0x564A60, CWeapon::BlowUpExplosiveThings, PATCH_JUMP);
+ InjectHook(0x564B80, &CWeapon::HasWeaponAmmoToBeUsed, PATCH_JUMP);
+ InjectHook(0x564C00, CWeapon::ProcessLineOfSight, PATCH_JUMP);
+
ENDPATCHES
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index 84760550..265ffddb 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -1,5 +1,8 @@
#pragma once
+#define DRIVEBYAUTOAIMING_MAXDIST (2.5f)
+#define DOOMAUTOAIMING_MAXDIST (9000.0f)
+
enum eWeaponType
{
WEAPONTYPE_UNARMED,
@@ -49,7 +52,10 @@ enum eWeaponState
};
class CEntity;
+class CPhysical;
class CAutomobile;
+struct CColPoint;
+class CWeaponInfo;
class CWeapon
{
@@ -64,22 +70,50 @@ public:
CWeapon() {
m_bAddRotOffset = false;
}
+
+ CWeaponInfo *GetInfo();
- static void ShutdownWeapons(void);
- void Initialise(eWeaponType type, int ammo);
- void Update(int32 audioEntity);
+ static void InitialiseWeapons(void);
+ static void ShutdownWeapons (void);
+ static void UpdateWeapons (void);
+
+ void Initialise(eWeaponType type, int32 ammo);
+
+ bool Fire (CEntity *shooter, CVector *fireSource);
+ bool FireFromCar (CAutomobile *shooter, bool left);
+ bool FireMelee (CEntity *shooter, CVector &fireSource);
+ bool FireInstantHit(CEntity *shooter, CVector *fireSource);
+
+ void AddGunshell (CEntity *shooter, CVector const &source, CVector2D const &direction, float size);
+ void DoBulletImpact(CEntity *shooter, CEntity *victim, CVector *source, CVector *target, CColPoint *point, CVector2D ahead);
+
+ bool FireShotgun (CEntity *shooter, CVector *fireSource);
+ bool FireProjectile(CEntity *shooter, CVector *fireSource, float power);
+
+ static void GenerateFlameThrowerParticles(CVector pos, CVector dir);
+
+ bool FireAreaEffect (CEntity *shooter, CVector *fireSource);
+ bool FireSniper (CEntity *shooter);
+ bool FireM16_1stPerson (CEntity *shooter);
+ bool FireInstantHitFromCar(CAutomobile *shooter, bool left);
+
+ static void DoDoomAiming (CEntity *shooter, CVector *source, CVector *target);
+ static void DoTankDoomAiming (CEntity *shooter, CEntity *driver, CVector *source, CVector *target);
+ static void DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target);
+
void Reload(void);
- bool Fire(CEntity*, CVector*);
- void FireFromCar(CAutomobile *car, bool left);
- void AddGunshell(CEntity*, CVector const&, CVector2D const&, float);
- bool IsTypeMelee(void);
+ void Update(int32 audioEntity);
+ bool IsTypeMelee (void);
bool IsType2Handed(void);
- static void DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end);
- bool HitsGround(CEntity* holder, CVector* firePos, CEntity* aimingTo);
+
+ static void MakePedsJumpAtShot(CPhysical *shooter, CVector *source, CVector *target);
+
+ bool HitsGround(CEntity *holder, CVector *fireSource, CEntity *aimingTo);
+ static void BlowUpExplosiveThings(CEntity *thing);
bool HasWeaponAmmoToBeUsed(void);
- static void InitialiseWeapons(void);
- static void UpdateWeapons(void);
+
+ static bool ProcessLineOfSight(CVector const &point1, CVector const &point2, CColPoint &point, CEntity *&entity, eWeaponType type, CEntity *shooter, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects);
};
-static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error");
+VALIDATE_SIZE(CWeapon, 0x18);
-void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage); \ No newline at end of file
+void FireOneInstantHitRound(CVector *source, CVector *target, int32 damage); \ No newline at end of file
diff --git a/src/weapons/WeaponEffects.cpp b/src/weapons/WeaponEffects.cpp
new file mode 100644
index 00000000..2ed9e662
--- /dev/null
+++ b/src/weapons/WeaponEffects.cpp
@@ -0,0 +1,106 @@
+#include "common.h"
+#include "patcher.h"
+#include "WeaponEffects.h"
+#include "TxdStore.h"
+#include "Sprite.h"
+
+RwTexture *gpCrossHairTex;
+RwRaster *gpCrossHairRaster;
+
+CWeaponEffects gCrossHair;
+
+CWeaponEffects::CWeaponEffects()
+{
+
+}
+
+CWeaponEffects::~CWeaponEffects()
+{
+
+}
+
+void
+CWeaponEffects::Init(void)
+{
+ gCrossHair.m_bActive = false;
+ gCrossHair.m_vecPos = CVector(0.0f, 0.0f, 0.0f);
+ gCrossHair.m_nRed = 0;
+ gCrossHair.m_nGreen = 0;
+ gCrossHair.m_nBlue = 0;
+ gCrossHair.m_nAlpha = 255;
+ gCrossHair.m_fSize = 1.0f;
+ gCrossHair.m_fRotation = 0.0f;
+
+
+ CTxdStore::PushCurrentTxd();
+ int32 slot = CTxdStore::FindTxdSlot("particle");
+ CTxdStore::SetCurrentTxd(slot);
+
+ gpCrossHairTex = RwTextureRead("crosshair", nil);
+ gpCrossHairRaster = RwTextureGetRaster(gpCrossHairTex);
+
+ CTxdStore::PopCurrentTxd();
+}
+
+void
+CWeaponEffects::Shutdown(void)
+{
+ RwTextureDestroy(gpCrossHairTex);
+}
+
+void
+CWeaponEffects::MarkTarget(CVector pos, uint8 red, uint8 green, uint8 blue, uint8 alpha, float size)
+{
+ gCrossHair.m_bActive = true;
+ gCrossHair.m_vecPos = pos;
+ gCrossHair.m_nRed = red;
+ gCrossHair.m_nGreen = green;
+ gCrossHair.m_nBlue = blue;
+ gCrossHair.m_nAlpha = alpha;
+ gCrossHair.m_fSize = size;
+}
+
+void
+CWeaponEffects::ClearCrossHair(void)
+{
+ gCrossHair.m_bActive = false;
+}
+
+void
+CWeaponEffects::Render(void)
+{
+ if ( gCrossHair.m_bActive )
+ {
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE);
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpCrossHairRaster);
+
+ RwV3d pos;
+ float w, h;
+ if ( CSprite::CalcScreenCoors(gCrossHair.m_vecPos, &pos, &w, &h, true) )
+ {
+ float recipz = 1.0f / pos.z;
+ CSprite::RenderOneXLUSprite(pos.x, pos.y, pos.z,
+ gCrossHair.m_fSize * w, gCrossHair.m_fSize * h,
+ gCrossHair.m_nRed, gCrossHair.m_nGreen, gCrossHair.m_nBlue, 255,
+ recipz, 255);
+ }
+
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
+ }
+}
+
+STARTPATCHES
+ //InjectHook(0x564C40, CWeaponEffects::CWeaponEffects, PATCH_JUMP);
+ //InjectHook(0x564C50, CWeaponEffects::~CWeaponEffects, PATCH_JUMP);
+ InjectHook(0x564C60, CWeaponEffects::Init, PATCH_JUMP);
+ InjectHook(0x564CF0, CWeaponEffects::Shutdown, PATCH_JUMP);
+ InjectHook(0x564D00, CWeaponEffects::MarkTarget, PATCH_JUMP);
+ InjectHook(0x564D60, CWeaponEffects::ClearCrossHair, PATCH_JUMP);
+ InjectHook(0x564D70, CWeaponEffects::Render, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/weapons/WeaponEffects.h b/src/weapons/WeaponEffects.h
new file mode 100644
index 00000000..31c5a309
--- /dev/null
+++ b/src/weapons/WeaponEffects.h
@@ -0,0 +1,27 @@
+#pragma once
+
+class CWeaponEffects
+{
+public:
+ bool m_bActive;
+ char _pad[3];
+ CVector m_vecPos;
+ uint8 m_nRed;
+ uint8 m_nGreen;
+ uint8 m_nBlue;
+ uint8 m_nAlpha;
+ float m_fSize;
+ float m_fRotation;
+
+public:
+ CWeaponEffects();
+ ~CWeaponEffects();
+
+ static void Init(void);
+ static void Shutdown(void);
+ static void MarkTarget(CVector pos, uint8 red, uint8 green, uint8 blue, uint8 alpha, float size);
+ static void ClearCrossHair(void);
+ static void Render(void);
+};
+
+VALIDATE_SIZE(CWeaponEffects, 0x1C); \ No newline at end of file