diff options
Diffstat (limited to 'src/weapons')
-rw-r--r-- | src/weapons/BulletInfo.cpp | 190 | ||||
-rw-r--r-- | src/weapons/Explosion.cpp | 191 | ||||
-rw-r--r-- | src/weapons/Explosion.h | 31 | ||||
-rw-r--r-- | src/weapons/ProjectileInfo.cpp | 261 | ||||
-rw-r--r-- | src/weapons/ProjectileInfo.h | 1 | ||||
-rw-r--r-- | src/weapons/ShotInfo.cpp | 2 | ||||
-rw-r--r-- | src/weapons/Weapon.cpp | 1874 | ||||
-rw-r--r-- | src/weapons/Weapon.h | 30 | ||||
-rw-r--r-- | src/weapons/WeaponEffects.cpp | 73 | ||||
-rw-r--r-- | src/weapons/WeaponInfo.cpp | 168 | ||||
-rw-r--r-- | src/weapons/WeaponInfo.h | 28 | ||||
-rw-r--r-- | src/weapons/WeaponType.h | 57 |
12 files changed, 2136 insertions, 770 deletions
diff --git a/src/weapons/BulletInfo.cpp b/src/weapons/BulletInfo.cpp index bfe27e18..b49db74a 100644 --- a/src/weapons/BulletInfo.cpp +++ b/src/weapons/BulletInfo.cpp @@ -23,6 +23,7 @@ #include "WeaponInfo.h" #include "World.h" #include "SurfaceTable.h" +#include "Heli.h" #ifdef SQUEEZE_PERFORMANCE uint32 bulletInfoInUse; @@ -32,9 +33,14 @@ uint32 bulletInfoInUse; #define NUM_PED_BLOOD_PARTICLES (8) #define BLOOD_PARTICLE_OFFSET (CVector(0.0f, 0.0f, 0.0f)) #define NUM_VEHICLE_SPARKS (16) +#define NUM_TYRE_POP_SMOKES (4) #define NUM_OTHER_SPARKS (8) #define BULLET_HIT_FORCE (7.5f) -#define MAP_BORDER (1960.0f) + +#define BULLET_BOUNDARY_MIN_X -2400.0f +#define BULLET_BOUNDARY_MAX_X 1600.0f +#define BULLET_BOUNDARY_MIN_Y -2000.0f +#define BULLET_BOUNDARY_MAX_Y 2000.0f CBulletInfo gaBulletInfo[CBulletInfo::NUM_BULLETS]; bool bPlayerSniperBullet; @@ -91,7 +97,6 @@ void CBulletInfo::Update(void) if (bulletInfoInUse == 0) return; #endif - bool bAddSound = true; bPlayerSniperBullet = false; for (int i = 0; i < NUM_BULLETS; i++) { CBulletInfo* pBullet = &gaBulletInfo[i]; @@ -107,34 +112,35 @@ void CBulletInfo::Update(void) } CVector vecOldPos = pBullet->m_vecPosition; CVector vecNewPos = pBullet->m_vecPosition + pBullet->m_vecSpeed * CTimer::GetTimeStep() * 0.5f; - CWorld::bIncludeCarTyres = true; + + if ( vecNewPos.x <= BULLET_BOUNDARY_MIN_X || vecNewPos.x >= BULLET_BOUNDARY_MAX_X || vecNewPos.y <= BULLET_BOUNDARY_MIN_Y || vecNewPos.y >= BULLET_BOUNDARY_MAX_Y ) { + pBullet->m_bInUse = false; + continue; + } CWorld::bIncludeDeadPeds = true; + CWorld::bIncludeBikers = true; + CWorld::bIncludeCarTyres = 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 (CWorld::ProcessLineOfSight(vecOldPos, vecNewPos, point, pHitEntity, true, true, true, true, true, false, false, true)) { + + CWeapon::CheckForShootingVehicleOccupant(&pHitEntity, &point, pBullet->m_eWeaponType, vecOldPos, vecNewPos); 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_STD_HITBYGUN_FRONT); - 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; + if (pPed->IsPedInControl() && !pPed->bIsDucking) { + pPed->ClearAttackByRemovingAnim(); + CAnimBlendAssociation* pAnim = CAnimManager::AddAnimation(pPed->GetClump(), ASSOCGRP_STD, ANIM_STD_HITBYGUN_FRONT); + 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; #ifdef SQUEEZE_PERFORMANCE - bulletInfoInUse--; + bulletInfoInUse--; #endif - vecNewPos = point.point; - } - else { - bAddSound = false; - } + vecNewPos = point.point; } if (CGame::nastyGame) { CVector vecParticleDirection = (point.point - pPed->GetPosition()) * 0.01f; @@ -163,13 +169,24 @@ void CBulletInfo::Update(void) } } 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); + CEntity *source = pBullet->m_pSource; + if ( !source || !source->IsPed() || ((CPed*)source)->m_attachedTo != pHitEntity) { + if ( point.pieceB >= CAR_PIECE_WHEEL_LF && point.pieceB <= CAR_PIECE_WHEEL_RR ) { + ((CVehicle*)pHitEntity)->BurstTyre(point.pieceB, true); + for (int j=0; j<NUM_TYRE_POP_SMOKES; j++) { + CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, point.point, point.normal / 20); + } + } else { + // CVector sth(0.0f, 0.0f, 0.0f); // unused + ((CVehicle*)pHitEntity)->InflictDamage(source, pBullet->m_eWeaponType, pBullet->m_nDamage); + if ( pBullet->m_eWeaponType == WEAPONTYPE_FLAMETHROWER ) { + gFireManager.StartFire(pHitEntity, pBullet->m_pSource, 0.8f, 1); + } 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; @@ -178,19 +195,28 @@ void CBulletInfo::Update(void) #endif vecNewPos = point.point; #endif - } - else { + } 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->GetIsStatic() && pObject->m_fUprootLimit <= 0.0f) { - pObject->SetIsStatic(false); - pObject->AddToMovingList(); + CEntity *source = pBullet->m_pSource; + if ( !source || !source->IsPed() || ((CPed*)source)->m_attachedTo != pHitEntity) { + if (pHitEntity->IsObject()) { + CObject *pHitObject = (CObject*)pHitEntity; + if ( !pHitObject->bInfiniteMass && pHitObject->m_fCollisionDamageMultiplier < 99.9f) { + bool notStatic = !pHitObject->GetIsStatic(); + if (notStatic && pHitObject->m_fUprootLimit <= 0.0f) { + pHitObject->bIsStatic = false; + pHitObject->AddToMovingList(); + } + + notStatic = !pHitObject->GetIsStatic(); + if (!notStatic) { + CVector moveForce = point.normal * -BULLET_HIT_FORCE; + pHitObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z); + } + } else if (pHitObject->m_nCollisionDamageEffect >= DAMAGE_EFFECT_SMASH_COMPLETELY) { + pHitObject->ObjectDamage(50.f); } - if (!pObject->GetIsStatic()) - pObject->ApplyMoveForce(-BULLET_HIT_FORCE * point.normal); } } #ifdef FIX_BUGS @@ -201,38 +227,55 @@ void CBulletInfo::Update(void) vecNewPos = point.point; #endif } - if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE && bAddSound) { + if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || pBullet->m_eWeaponType == WEAPONTYPE_LASERSCOPE) { cAudioScriptObject* pAudio; switch (pHitEntity->GetType()) { - 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; - default: break; + case ENTITY_TYPE_BUILDING: + if (!DMAudio.IsAudioInitialised()) + break; + + pAudio = new cAudioScriptObject(); + if (pAudio) + pAudio->Reset(); + pAudio->Posn = pHitEntity->GetPosition(); + pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_1; + pAudio->AudioEntity = AEHANDLE_NONE; + DMAudio.CreateOneShotScriptObject(pAudio); + break; + case ENTITY_TYPE_OBJECT: + if (!DMAudio.IsAudioInitialised()) + break; + + pAudio = new cAudioScriptObject(); + if (pAudio) + pAudio->Reset(); + pAudio->Posn = pHitEntity->GetPosition(); + pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_2; + pAudio->AudioEntity = AEHANDLE_NONE; + DMAudio.CreateOneShotScriptObject(pAudio); + break; + case ENTITY_TYPE_DUMMY: + if (!DMAudio.IsAudioInitialised()) + break; + + pAudio = new cAudioScriptObject(); + if (pAudio) + pAudio->Reset(); + pAudio->Posn = pHitEntity->GetPosition(); + pAudio->AudioId = SCRIPT_SOUND_BULLET_HIT_GROUND_3; + pAudio->AudioEntity = AEHANDLE_NONE; + DMAudio.CreateOneShotScriptObject(pAudio); + break; + case ENTITY_TYPE_PED: + ++CStats::BulletsThatHit; + DMAudio.PlayOneShot(((CPed*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f); + ((CPed*)pHitEntity)->Say(SOUND_PED_BULLET_HIT); + break; + case ENTITY_TYPE_VEHICLE: + ++CStats::BulletsThatHit; + DMAudio.PlayOneShot(((CVehicle*)pHitEntity)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f); + break; + default: break; } } CGlass::WasGlassHitByBullet(pHitEntity, point.point); @@ -241,19 +284,14 @@ void CBulletInfo::Update(void) CWorld::pIgnoreEntity = nil; CWorld::bIncludeDeadPeds = false; CWorld::bIncludeCarTyres = false; - if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE) { + CWorld::bIncludeBikers = false; + if (pBullet->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || pBullet->m_eWeaponType == WEAPONTYPE_LASERSCOPE) { 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; -#ifdef SQUEEZE_PERFORMANCE - bulletInfoInUse--; -#endif - } + CHeli::TestSniperCollision(&PlayerSniperBulletStart, &PlayerSniperBulletEnd); } } diff --git a/src/weapons/Explosion.cpp b/src/weapons/Explosion.cpp index f79c0278..7683ed97 100644 --- a/src/weapons/Explosion.cpp +++ b/src/weapons/Explosion.cpp @@ -25,12 +25,25 @@ CExplosion gaExplosion[NUM_EXPLOSIONS]; RwRGBA colMedExpl = { 0, 0, 0, 0 }; RwRGBA colUpdate = { 0, 0, 0, 0 }; +const RwRGBA colAddExplosion = { 160, 160, 160, 255 }; +const RwRGBA colGrenade = { 96, 96, 96, 255 }; + int AudioHandle = AEHANDLE_NONE; void CExplosion::Initialise() { debug("Initialising CExplosion...\n"); + ClearAllExplosions(); + AudioHandle = DMAudio.CreateEntity(AUDIOTYPE_EXPLOSION, (void*)1); + if (AudioHandle >= 0) + DMAudio.SetEntityStatus(AudioHandle, TRUE); + debug("CExplosion ready\n"); +} + +void +CExplosion::ClearAllExplosions() +{ for (int i = 0; i < ARRAY_SIZE(gaExplosion); i++) { gaExplosion[i].m_ExplosionType = EXPLOSION_GRENADE; gaExplosion[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f); @@ -43,11 +56,8 @@ CExplosion::Initialise() gaExplosion[i].m_nIteration = 0; gaExplosion[i].m_fStartTime = 0.0f; gaExplosion[i].m_bIsBoat = false; + gaExplosion[i].m_bMakeSound = true; } - AudioHandle = DMAudio.CreateEntity(AUDIOTYPE_EXPLOSION, (void*)1); - if (AudioHandle >= 0) - DMAudio.SetEntityStatus(AudioHandle, TRUE); - debug("CExplosion ready\n"); } void @@ -79,6 +89,12 @@ CExplosion::GetExplosionType(uint8 id) return gaExplosion[id].m_ExplosionType; } +bool +CExplosion::DoesExplosionMakeSound(uint8 id) +{ + return gaExplosion[id].m_bMakeSound; +}; + CVector * CExplosion::GetExplosionPosition(uint8 id) { @@ -86,14 +102,19 @@ CExplosion::GetExplosionPosition(uint8 id) } bool -CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime) +#ifdef SIMPLER_MISSIONS +CExplosion::AddExplosion(CEntity* explodingEntity, CEntity* culprit, eExplosionType type, const CVector& pos, uint32 lifetime, bool makeSound, float radius) +#else +CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime, bool makeSound) +#endif { CVector pPosn; CVector posGround; RwRGBA colorMedium = colMedExpl; + RwRGBA color = colAddExplosion; + RwRGBA colorGrenade = colGrenade; bool bDontExplode = false; - const RwRGBA color = { 160, 160, 160, 255 }; pPosn = pos; pPosn.z += 5.0f; #ifdef FIX_BUGS @@ -128,19 +149,28 @@ CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionT explosion.m_nIteration = 1; explosion.m_nActiveCounter = 1; explosion.m_bIsBoat = false; + explosion.m_bMakeSound = makeSound; explosion.m_nParticlesExpireTime = lifetime != 0 ? CTimer::GetTimeInMilliseconds() + lifetime : 0; switch (type) { case EXPLOSION_GRENADE: +#ifdef SIMPLER_MISSIONS + explosion.m_fRadius = (radius == -1.0f ? 9.0f : radius); +#else explosion.m_fRadius = 9.0f; +#endif explosion.m_fPower = 300.0f; explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750; explosion.m_fPropagationRate = 0.5f; posGround = pos; posGround.z = CWorld::FindGroundZFor3DCoord(posGround.x, posGround.y, posGround.z + 3.0f, nil); CEventList::RegisterEvent(EVENT_EXPLOSION, posGround, 250); - if (Distance(explosion.m_vecPosition, TheCamera.GetPosition()) < 40.0f) - CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, explosion.m_vecPosition, CVector(0.0f, 0.0f, 0.0f), nil, 5.5f, color); + if (Distance(explosion.m_vecPosition, TheCamera.GetPosition()) < 40.0f) { + uint8 tmp = CGeneral::GetRandomNumberInRange(0, 64) - 64; + colorGrenade.green += tmp; + colorGrenade.blue += tmp; + CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, explosion.m_vecPosition, CVector(0.0f, 0.0f, 0.0f), nil, 4.5f, colorGrenade); + } break; case EXPLOSION_MOLOTOV: { @@ -150,18 +180,17 @@ CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionT explosion.m_fPropagationRate = 0.5f; posGround = pos; bool found; - posGround.z = CWorld::FindGroundZFor3DCoord(posGround.x, posGround.y, posGround.z + 3.0f, &found); - if (found) { - float waterLevel; - if (CWaterLevel::GetWaterLevelNoWaves(posGround.x, posGround.y, posGround.z, &waterLevel) - && posGround.z < waterLevel - && waterLevel - 6.0f < posGround.z) // some subway/tunnels check? - bDontExplode = true; - else - gFireManager.StartFire(posGround, 1.8f, false); - } - else + float tmp = CWorld::FindGroundZFor3DCoord(posGround.x, posGround.y, posGround.z + 3.0f, &found); + if (found) + posGround.z = tmp; + + float waterLevel; + if (CWaterLevel::GetWaterLevelNoWaves(posGround.x, posGround.y, posGround.z, &waterLevel) + && posGround.z < waterLevel && waterLevel - 6.0f < posGround.z) { // some subway/tunnels check? bDontExplode = true; + } else if (found) { + gFireManager.StartFire(posGround, 1.8f, false); + } break; } case EXPLOSION_ROCKET: @@ -175,6 +204,7 @@ CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionT break; case EXPLOSION_CAR: case EXPLOSION_CAR_QUICK: + case EXPLOSION_BOAT: explosion.m_fRadius = 9.0f; explosion.m_fPower = 300.0f; explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 4250; @@ -184,59 +214,71 @@ CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionT if (explosion.m_pVictimEntity->IsVehicle() && ((CVehicle*)explosion.m_pVictimEntity)->IsBoat()) explosion.m_bIsBoat = true; CEventList::RegisterEvent(EVENT_EXPLOSION, EVENT_ENTITY_VEHICLE, explosion.m_pVictimEntity, nil, 1000); - } else + } else { CEventList::RegisterEvent(EVENT_EXPLOSION, pos, 1000); + } if (explosion.m_pVictimEntity != nil && !explosion.m_bIsBoat) { - int rn = (CGeneral::GetRandomNumber() & 1) + 2; - for (int i = 0; i < rn; i++) { - CParticle::AddParticle(PARTICLE_EXPLOSION_MEDIUM, explosion.m_pVictimEntity->GetPosition(), CVector(0.0f, 0.0f, 0.0f), nil, 3.5f, colMedExpl); - CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, explosion.m_pVictimEntity->GetPosition(), CVector(0.0f, 0.0f, 0.0f), nil, 5.5f, color); - } CVehicle *veh = (CVehicle*)explosion.m_pVictimEntity; - int32 component = CAR_WING_LR; - - // miami leftover - if (veh->IsBike()) - component = BIKE_FORKS_REAR; - - if (veh->IsComponentPresent(component)) { - CVector componentPos; - veh->GetComponentWorldPosition(component, componentPos); - rn = (CGeneral::GetRandomNumber() & 1) + 1; + CVector componentPos; + + if (veh->IsBike()) { + veh->GetComponentWorldPosition(BIKE_FORKS_REAR, componentPos); + } else if (veh->IsComponentPresent(CAR_BUMP_REAR) && veh->IsComponentPresent(CAR_WHEEL_LB)) { //mb it's another enum + CVector tmpVec; + veh->GetComponentWorldPosition(CAR_BUMP_REAR, componentPos); + veh->GetComponentWorldPosition(CAR_WHEEL_LB, tmpVec); + componentPos += tmpVec; + componentPos /= 2.0f; + } else if (veh->IsComponentPresent(CAR_BOOT)) { + veh->GetComponentWorldPosition(CAR_BOOT, componentPos); + } + if (componentPos.x != 0.0f) { + int rn = (CGeneral::GetRandomNumber() & 1) + 1; for (int i = 0; i < rn; i++) - CParticle::AddJetExplosion(componentPos, 1.4f, 0.0f); + CParticle::AddJetExplosion(componentPos, (CGeneral::GetRandomNumber() & 7) / 7.0f + 1.5f, 0.5f); } } break; case EXPLOSION_HELI: - explosion.m_fRadius = 6.0f; - explosion.m_fPower = 300.0f; + case EXPLOSION_HELI2: + if (type == EXPLOSION_HELI2) { + explosion.m_fRadius = 12.0f; + explosion.m_fPower = 500.0f; + } else { + explosion.m_fRadius = 6.0f; + explosion.m_fPower = 300.0f; + } explosion.m_fStopTime = lifetime + CTimer::GetTimeInMilliseconds() + 750; explosion.m_fPropagationRate = 0.5f; explosion.m_fStartTime = CTimer::GetTimeInMilliseconds(); for (int i = 0; i < 10; i++) { CVector randpos; - uint8 x, y, z; - x = CGeneral::GetRandomNumber(); - y = CGeneral::GetRandomNumber(); - z = CGeneral::GetRandomNumber(); - randpos = pos + CVector(x - 128, y - 128, z - 128) / 20.0f; + randpos.x = CGeneral::GetRandomNumber(); + randpos.y = CGeneral::GetRandomNumber(); + randpos.z = CGeneral::GetRandomNumber(); + randpos -= CVector(128, 128, 128); + randpos /= 20.0f; + randpos += pos; CParticle::AddParticle(PARTICLE_EXPLOSION_MFAST, randpos, CVector(0.0f, 0.0f, 0.0f), nil, 2.5f, color); - x = CGeneral::GetRandomNumber(); - y = CGeneral::GetRandomNumber(); - z = CGeneral::GetRandomNumber(); - randpos = pos + CVector(x - 128, y - 128, z - 128) / 20.0f; + randpos.x = CGeneral::GetRandomNumber(); + randpos.y = CGeneral::GetRandomNumber(); + randpos.z = CGeneral::GetRandomNumber(); + randpos -= CVector(128, 128, 128); + randpos /= 20.0f; + randpos += pos; CParticle::AddParticle(PARTICLE_EXPLOSION_LFAST, randpos, CVector(0.0f, 0.0f, 0.0f), nil, 5.0f, color); - x = CGeneral::GetRandomNumber(); - y = CGeneral::GetRandomNumber(); - z = CGeneral::GetRandomNumber(); - randpos = pos + CVector(x - 128, y - 128, z - 128) / 20.0f; + randpos.x = CGeneral::GetRandomNumber(); + randpos.y = CGeneral::GetRandomNumber(); + randpos.z = CGeneral::GetRandomNumber(); + randpos -= CVector(128, 128, 128); + randpos /= 20.0f; + randpos += pos; CParticle::AddJetExplosion(randpos, 1.4f, 3.0f); } @@ -259,13 +301,10 @@ CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionT explosion.m_fPropagationRate = 0.5f; for (int i = 0; i < 6; i++) { CVector randpos; - uint8 x, y, z; - - x = CGeneral::GetRandomNumber(); - y = CGeneral::GetRandomNumber(); - z = CGeneral::GetRandomNumber(); - randpos = CVector(x - 128, y - 128, z - 128); - + randpos.x = CGeneral::GetRandomNumber(); + randpos.y = CGeneral::GetRandomNumber(); + randpos.z = CGeneral::GetRandomNumber(); + randpos -= CVector(128, 128, 128); randpos.x /= 50.0f; randpos.y /= 50.0f; randpos.z /= 25.0f; @@ -297,7 +336,11 @@ CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionT CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z + 4.0f, nil); // BUG? result is unused CEventList::RegisterEvent(EVENT_EXPLOSION, posGround, 250); break; + default: + debug("Undefined explosion type, AddExplosion, Explosion.cpp"); + break; } + if (bDontExplode) { explosion.m_nIteration = 0; return false; @@ -306,8 +349,12 @@ CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionT if (explosion.m_fPower != 0.0f && explosion.m_nParticlesExpireTime == 0) CWorld::TriggerExplosion(pos, explosion.m_fRadius, explosion.m_fPower, culprit, (type == EXPLOSION_ROCKET || type == EXPLOSION_CAR_QUICK || type == EXPLOSION_MINE || type == EXPLOSION_BARREL || type == EXPLOSION_TANK_GRENADE || type == EXPLOSION_HELI_BOMB)); - TheCamera.CamShake(0.6f, pos.x, pos.y, pos.z); - CPad::GetPad(0)->StartShake_Distance(300, 128, pos.x, pos.y, pos.z); + if (type == EXPLOSION_MOLOTOV) { + TheCamera.CamShake(0.2f, pos.x, pos.y, pos.z); + } else { + TheCamera.CamShake(0.6f, pos.x, pos.y, pos.z); + CPad::GetPad(0)->StartShake_Distance(300, 128, pos.x, pos.y, pos.z); + } return true; } @@ -333,6 +380,7 @@ CExplosion::Update() case EXPLOSION_GRENADE: case EXPLOSION_ROCKET: case EXPLOSION_HELI: + case EXPLOSION_HELI2: case EXPLOSION_MINE: case EXPLOSION_BARREL: if (CTimer::GetFrameCounter() & 1) { @@ -351,8 +399,10 @@ CExplosion::Update() point1.z += 5.0f; CColPoint colPoint; CEntity *pEntity; - CWorld::ProcessVerticalLine(point1, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil); - explosion.m_fZshift = colPoint.point.z; + if (CWorld::ProcessVerticalLine(point1, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) + explosion.m_fZshift = colPoint.point.z; + else + explosion.m_fZshift = explosion.m_vecPosition.z; } float ff = ((float)explosion.m_nIteration * 0.55f); for (int i = 0; i < 5 * ff; i++) { @@ -361,8 +411,6 @@ CExplosion::Update() CVector pos = explosion.m_vecPosition; pos.x += ff * Sin(angle); pos.y += ff * Cos(angle); - pos.z += 5.0f; // what is the point of this? - pos.z = explosion.m_fZshift + 0.5f; CParticle::AddParticle(PARTICLE_EXPLOSION_MEDIUM, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, CGeneral::GetRandomNumberInRange(-3.0f, 3.0f), CGeneral::GetRandomNumberInRange(-180.0f, 180.0f)); } @@ -370,9 +418,10 @@ CExplosion::Update() break; case EXPLOSION_CAR: case EXPLOSION_CAR_QUICK: + case EXPLOSION_BOAT: if (someTime >= 3500) { - if (explosion.m_pVictimEntity != nil && !explosion.m_bIsBoat) { - if ((CGeneral::GetRandomNumber() & 0xF) == 0) { + if (explosion.m_pVictimEntity != nil) { + if ((CGeneral::GetRandomNumber() & 0xF) == 0 && !explosion.m_bIsBoat) { CVehicle *veh = (CVehicle*)explosion.m_pVictimEntity; uint8 component = CAR_WING_LR; @@ -383,16 +432,14 @@ CExplosion::Update() if (veh->IsComponentPresent(component)) { CVector componentPos; veh->GetComponentWorldPosition(component, componentPos); - CParticle::AddJetExplosion(componentPos, 1.5f, 0.0f); + CParticle::AddJetExplosion(componentPos, 0.5f, 0.0f); } } if (CTimer::GetTimeInMilliseconds() > explosion.m_fStartTime) { explosion.m_fStartTime = CTimer::GetTimeInMilliseconds() + 125 + (CGeneral::GetRandomNumber() & 0x7F); CVector pos = explosion.m_pVictimEntity->GetPosition(); - for (int i = 0; i < (CGeneral::GetRandomNumber() & 1) + 1; i++) { + for (int i = 0; i < (CGeneral::GetRandomNumber() & 1) + 1; i++) CParticle::AddParticle(PARTICLE_EXPLOSION_MEDIUM, pos, CVector(0.0f, 0.0f, 0.0f), nil, 3.5f, color); - CParticle::AddParticle(PARTICLE_EXPLOSION_LARGE, pos, CVector(0.0f, 0.0f, 0.0f), nil, 5.5f, color); - } } } if (CTimer::GetFrameCounter() & 1) { @@ -419,13 +466,15 @@ CExplosion::Update() CVector pos(x - 128, y - 128, (z % 128) + 1); pos.Normalise(); - pos *= ff / 5.0f; + pos *= (explosion.m_nIteration + 1) * ff / 5.0f; pos += explosion.m_vecPosition; pos.z += 0.5f; CParticle::AddParticle(PARTICLE_EXPLOSION_LARGE, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, CGeneral::GetRandomNumberInRange(-3.0f, 3.0f), CGeneral::GetRandomNumberInRange(-180.0f, 180.0f)); } } break; + default: + break; } if (someTime > 0) explosion.m_nIteration++; diff --git a/src/weapons/Explosion.h b/src/weapons/Explosion.h index bf54328c..e76c99ea 100644 --- a/src/weapons/Explosion.h +++ b/src/weapons/Explosion.h @@ -10,7 +10,9 @@ enum eExplosionType EXPLOSION_ROCKET, EXPLOSION_CAR, EXPLOSION_CAR_QUICK, + EXPLOSION_BOAT, EXPLOSION_HELI, + EXPLOSION_HELI2, EXPLOSION_MINE, EXPLOSION_BARREL, EXPLOSION_TANK_GRENADE, @@ -28,22 +30,29 @@ class CExplosion float m_fStopTime; uint8 m_nIteration; uint8 m_nActiveCounter; + bool m_bIsBoat; + bool m_bMakeSound; float m_fStartTime; uint32 m_nParticlesExpireTime; float m_fPower; - bool m_bIsBoat; float m_fZshift; public: - static void Initialise(); - static void Shutdown(); - static int8 GetExplosionActiveCounter(uint8 id); - static void ResetExplosionActiveCounter(uint8 id); - static uint8 GetExplosionType(uint8 id); - static CVector *GetExplosionPosition(uint8 id); - static bool AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime); - static void Update(); - static bool TestForExplosionInArea(eExplosionType type, float x1, float x2, float y1, float y2, float z1, float z2); - static void RemoveAllExplosionsInArea(CVector pos, float radius); +#ifdef SIMPLER_MISSIONS + static bool AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime, bool makeSound = true, float radius = -1.0f); +#else + static bool AddExplosion(CEntity* explodingEntity, CEntity* culprit, eExplosionType type, const CVector& pos, uint32 lifetime, bool makeSound = true); +#endif + static void ClearAllExplosions(); //done + static bool DoesExplosionMakeSound(uint8 id); //done + static int8 GetExplosionActiveCounter(uint8 id); //done + static CVector *GetExplosionPosition(uint8 id); //done + static uint8 GetExplosionType(uint8 id); //done, mb need change type to tExplosionType + static void Initialise(); //done + static void RemoveAllExplosionsInArea(CVector pos, float radius); //done + static void ResetExplosionActiveCounter(uint8 id); //done + static void Shutdown(); //done + static void Update(); //done + static bool TestForExplosionInArea(eExplosionType type, float x1, float x2, float y1, float y2, float z1, float z2); //done, not used }; extern CExplosion gaExplosion[NUM_EXPLOSIONS];
\ No newline at end of file diff --git a/src/weapons/ProjectileInfo.cpp b/src/weapons/ProjectileInfo.cpp index da00b87a..10aa3ef5 100644 --- a/src/weapons/ProjectileInfo.cpp +++ b/src/weapons/ProjectileInfo.cpp @@ -20,6 +20,11 @@ uint32 projectileInUse; CProjectileInfo gaProjectileInfo[NUM_PROJECTILES]; CProjectile *CProjectileInfo::ms_apProjectile[NUM_PROJECTILES]; +#define PROJECTILE_BOUNDARY_MIN_X -2390.0f +#define PROJECTILE_BOUNDARY_MAX_X 1590.0f +#define PROJECTILE_BOUNDARY_MIN_Y -1990.0f +#define PROJECTILE_BOUNDARY_MAX_Y 1990.0f + void CProjectileInfo::Initialise() { @@ -66,65 +71,89 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, switch (weapon) { - case WEAPONTYPE_ROCKETLAUNCHER: - { - float vy = 1.25f; - time = CTimer::GetTimeInMilliseconds() + 1400; - if (ped->IsPlayer()) { - matrix.GetForward() = TheCamera.Cams[TheCamera.ActiveCam].Front; - matrix.GetUp() = TheCamera.Cams[TheCamera.ActiveCam].Up; - matrix.GetRight() = CrossProduct(TheCamera.Cams[TheCamera.ActiveCam].Up, TheCamera.Cams[TheCamera.ActiveCam].Front); - matrix.GetPosition() = pos; - } else if (ped->m_pSeekTarget != nil) { - float ry = CGeneral::GetRadianAngleBetweenPoints(1.0f, ped->m_pSeekTarget->GetPosition().z, 1.0f, pos.z); - float rz = Atan2(-ped->GetForward().x, ped->GetForward().y); - vy = 0.35f * speed + 0.15f; - matrix.SetTranslate(0.0f, 1.0f, 1.0f); - matrix.Rotate(0.0f, ry, rz); - matrix.GetPosition() += pos; - } else { - matrix = ped->GetMatrix(); + case WEAPONTYPE_ROCKET: + { + float vy = 0.35f; + time = CTimer::GetTimeInMilliseconds() + 2000; + if (entity->GetModelIndex() == MI_SPARROW || entity->GetModelIndex() == MI_HUNTER || entity->GetModelIndex() == MI_SENTINEL) { + matrix = ped->GetMatrix(); + matrix.GetPosition() = pos; + CVector vecSpeed = ((CPhysical*)entity)->m_vecMoveSpeed; + vy += Max(0.0f, DotProduct(vecSpeed, entity->GetForward())) + Max(0.0f, DotProduct(vecSpeed, entity->GetUp())); + } else { + if (ped->IsPlayer()) { + matrix.GetForward() = TheCamera.Cams[TheCamera.ActiveCam].Front; + matrix.GetUp() = TheCamera.Cams[TheCamera.ActiveCam].Up; + matrix.GetRight() = CrossProduct(TheCamera.Cams[TheCamera.ActiveCam].Up, TheCamera.Cams[TheCamera.ActiveCam].Front); + matrix.GetPosition() = pos; + } else if (ped->m_pSeekTarget != nil) { + float ry = CGeneral::GetRadianAngleBetweenPoints(1.0f, ped->m_pSeekTarget->GetPosition().z, 1.0f, pos.z); + float rz = Atan2(-ped->GetForward().x, ped->GetForward().y); + vy = 0.35f * speed + 0.15f; + matrix.SetTranslate(0.0f, 1.0f, 1.0f); + matrix.Rotate(0.0f, ry, rz); + matrix.GetPosition() += pos; + } else { + matrix = ped->GetMatrix(); + } + } + velocity = Multiply3x3(matrix, CVector(0.0f, vy, 0.0f)); + gravity = false; + break; } - velocity = Multiply3x3(matrix, CVector(0.0f, vy, 0.0f)); - gravity = false; - break; - } - case WEAPONTYPE_FLAMETHROWER: + case WEAPONTYPE_MOLOTOV: + { + time = CTimer::GetTimeInMilliseconds() + 2000; + float scale = 0.22f * speed + 0.15f; + if (scale < 0.2f) + scale = 0.2f; + float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); + matrix.SetTranslate(0.0f, 0.0f, 0.0f); + matrix.RotateZ(angle); + matrix.GetPosition() += pos; + velocity.x = -1.0f * scale * Sin(angle); + velocity.y = scale * Cos(angle); + velocity.z = (0.2f * speed + 0.4f) * scale; + break; + } + case WEAPONTYPE_TEARGAS: + { + time = CTimer::GetTimeInMilliseconds() + 20000; + float scale = 0.0f; + if (speed != 0.0f) + scale = 0.22f * speed + 0.15f; + float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); + matrix.SetTranslate(0.0f, 0.0f, 0.0f); + matrix.RotateZ(angle); + matrix.GetPosition() += pos; + SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5; + velocity.x = -1.0f * scale * Sin(angle); + velocity.y = scale * Cos(angle); + velocity.z = (0.4f * speed + 0.4f) * scale; + elasticity = 0.5f; + break; + } + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: + { + time = CTimer::GetTimeInMilliseconds() + 2000; + float scale = 0.0f; + if (speed != 0.0f) + scale = 0.22f * speed + 0.15f; + float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); + matrix.SetTranslate(0.0f, 0.0f, 0.0f); + matrix.RotateZ(angle); + matrix.GetPosition() += pos; + SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5; + velocity.x = -1.0f * scale * Sin(angle); + velocity.y = scale * Cos(angle); + velocity.z = (0.4f * speed + 0.4f) * scale; + elasticity = 0.5f; + break; + } + default: Error("Undefined projectile type, AddProjectile, ProjectileInfo.cpp"); break; - case WEAPONTYPE_MOLOTOV: - { - time = CTimer::GetTimeInMilliseconds() + 2000; - float scale = 0.22f * speed + 0.15f; - if (scale < 0.2f) - scale = 0.2f; - float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); - matrix.SetTranslate(0.0f, 0.0f, 0.0f); - matrix.RotateZ(angle); - matrix.GetPosition() += pos; - velocity.x = -1.0f * scale * Sin(angle); - velocity.y = scale * Cos(angle); - velocity.z = (0.2f * speed + 0.4f) * scale; - break; - } - case WEAPONTYPE_GRENADE: - { - time = CTimer::GetTimeInMilliseconds() + 2000; - float scale = 0.0f; - if (speed != 0.0f) - scale = 0.22f * speed + 0.15f; - float angle = Atan2(-ped->GetForward().x, ped->GetForward().y); - matrix.SetTranslate(0.0f, 0.0f, 0.0f); - matrix.RotateZ(angle); - matrix.GetPosition() += pos; - SpecialCollisionResponseCase = COLLRESPONSE_UNKNOWN5; - velocity.x = -1.0f * scale * Sin(angle); - velocity.y = scale * Cos(angle); - velocity.z = (0.4f * speed + 0.4f) * scale; - elasticity = 0.5f; - break; - } - default: break; } int i = 0; @@ -139,18 +168,20 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, switch (weapon) { - case WEAPONTYPE_ROCKETLAUNCHER: + case WEAPONTYPE_ROCKET: ms_apProjectile[i] = new CProjectile(MI_MISSILE); break; - case WEAPONTYPE_FLAMETHROWER: + case WEAPONTYPE_TEARGAS: + ms_apProjectile[i] = new CProjectile(MI_TEARGAS); break; - case WEAPONTYPE_MOLOTOV: + case WEAPONTYPE_MOLOTOV: ms_apProjectile[i] = new CProjectile(MI_MOLOTOV); break; - case WEAPONTYPE_GRENADE: + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: ms_apProjectile[i] = new CProjectile(MI_GRENADE); break; - default: break; + default: break; } if (ms_apProjectile[i] == nil) @@ -174,13 +205,28 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, CWorld::Add(ms_apProjectile[i]); gaProjectileInfo[i].m_vecPos = ms_apProjectile[i]->GetPosition(); + + if (entity && entity->IsPed() && !ped->m_pCollidingEntity) { + ped->m_pCollidingEntity = ms_apProjectile[i]; + } return true; } void CProjectileInfo::RemoveProjectile(CProjectileInfo *info, CProjectile *projectile) { - RemoveNotAdd(info->m_pSource, info->m_eWeaponType, projectile->GetPosition()); + // TODO(Miami): New parameter: 1 + switch (info->m_eWeaponType) { + case WEAPONTYPE_GRENADE: + CExplosion::AddExplosion(nil, info->m_pSource, EXPLOSION_GRENADE, projectile->GetPosition(), 0); + break; + case WEAPONTYPE_MOLOTOV: + CExplosion::AddExplosion(nil, info->m_pSource, EXPLOSION_MOLOTOV, projectile->GetPosition(), 0); + break; + case WEAPONTYPE_ROCKET: + CExplosion::AddExplosion(nil, info->m_pSource->IsVehicle() ? ((CVehicle*)info->m_pSource)->pDriver : info->m_pSource, EXPLOSION_ROCKET, projectile->GetPosition(), 0); + break; + } #ifdef SQUEEZE_PERFORMANCE projectileInUse--; #endif @@ -193,18 +239,17 @@ CProjectileInfo::RemoveProjectile(CProjectileInfo *info, CProjectile *projectile void CProjectileInfo::RemoveNotAdd(CEntity *entity, eWeaponType weaponType, CVector pos) { - switch (weaponType) - { - case WEAPONTYPE_GRENADE: - CExplosion::AddExplosion(nil, entity, EXPLOSION_GRENADE, pos, 0); - break; - case WEAPONTYPE_MOLOTOV: - CExplosion::AddExplosion(nil, entity, EXPLOSION_MOLOTOV, pos, 0); - break; - case WEAPONTYPE_ROCKETLAUNCHER: - CExplosion::AddExplosion(nil, entity, EXPLOSION_ROCKET, pos, 0); - break; - default: break; + // TODO(Miami): New parameter: 1 + switch (weaponType) { + case WEAPONTYPE_GRENADE: + CExplosion::AddExplosion(nil, entity, EXPLOSION_GRENADE, pos, 0); + break; + case WEAPONTYPE_MOLOTOV: + CExplosion::AddExplosion(nil, entity, EXPLOSION_MOLOTOV, pos, 0); + break; + case WEAPONTYPE_ROCKET: + CExplosion::AddExplosion(nil, entity, EXPLOSION_ROCKET, pos, 0); + break; } } @@ -216,6 +261,8 @@ CProjectileInfo::Update() return; #endif + int tearGasOffset = -0.0f; // unused + for (int i = 0; i < ARRAY_SIZE(gaProjectileInfo); i++) { if (!gaProjectileInfo[i].m_bInUse) continue; @@ -231,21 +278,46 @@ CProjectileInfo::Update() gaProjectileInfo[i].m_bInUse = false; continue; } + if ( (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_TEARGAS) && ms_apProjectile[i]->m_fElasticity > 0.1f ) { + if ( Abs(ms_apProjectile[i]->m_vecMoveSpeed.x) < 0.05f && Abs(ms_apProjectile[i]->m_vecMoveSpeed.y) < 0.05f && Abs(ms_apProjectile[i]->m_vecMoveSpeed.z) < 0.05f ) { + ms_apProjectile[i]->m_fElasticity = 0.03f; + } + } + const CVector &projectilePos = ms_apProjectile[i]->GetPosition(); + CVector nextPos = CTimer::GetTimeStep() * ms_apProjectile[i]->m_vecMoveSpeed + projectilePos; + + if ( nextPos.x <= PROJECTILE_BOUNDARY_MIN_X || nextPos.x >= PROJECTILE_BOUNDARY_MAX_X || nextPos.y <= PROJECTILE_BOUNDARY_MIN_Y || nextPos.y >= PROJECTILE_BOUNDARY_MAX_Y ) { + // Not RemoveProjectile, because we don't want no explosion + gaProjectileInfo[i].m_bInUse = false; + CWorld::Remove(ms_apProjectile[i]); + delete ms_apProjectile[i]; + continue; + } + if ( gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_TEARGAS && CTimer::GetTimeInMilliseconds() > gaProjectileInfo[i].m_nExplosionTime - 19500 ) { + CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(0.2f, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0); + CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(-0.2f, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0); + CParticle::AddParticle(PARTICLE_TEARGAS, projectilePos, CVector(tearGasOffset, tearGasOffset, 0.0f), 0, 0.0f, 0, 0, 0, 0); + + if ( CTimer::GetTimeInMilliseconds() & 0x200 ) + CWorld::SetPedsChoking(projectilePos.x, projectilePos.y, projectilePos.z, 6.0f, gaProjectileInfo[i].m_pSource); + } - if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) { - CParticle::AddParticle(PARTICLE_SMOKE, ms_apProjectile[i]->GetPosition(), CVector(0.0f, 0.0f, 0.0f)); + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) { + CParticle::AddParticlesAlongLine(PARTICLE_ROCKET_SMOKE, gaProjectileInfo[i].m_vecPos, projectilePos, CVector(0.0f, 0.0f, 0.0f), 0.7f, 0, 0, 0, 3000); } - if (CTimer::GetTimeInMilliseconds() <= gaProjectileInfo[i].m_nExplosionTime) { - if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) { + if (CTimer::GetTimeInMilliseconds() <= gaProjectileInfo[i].m_nExplosionTime || gaProjectileInfo[i].m_nExplosionTime == 0) { + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) { CVector pos = ms_apProjectile[i]->GetPosition(); CWorld::pIgnoreEntity = ms_apProjectile[i]; if (ms_apProjectile[i]->bHasCollided || !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false) - || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER && (CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos))) { + || CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos)) { RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); } CWorld::pIgnoreEntity = nil; + ms_apProjectile[i]->m_vecMoveSpeed *= 1.07f; + } else if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_MOLOTOV) { CVector pos = ms_apProjectile[i]->GetPosition(); CWorld::pIgnoreEntity = ms_apProjectile[i]; @@ -254,15 +326,25 @@ CProjectileInfo::Update() || ((gaProjectileInfo[i].m_vecPos - gaProjectileInfo[i].m_pSource->GetPosition()).MagnitudeSqr() >= 2.0f)) { if (ms_apProjectile[i]->bHasCollided - || !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false) - || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER && (CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos))) { + || !CWorld::GetIsLineOfSightClear(gaProjectileInfo[i].m_vecPos, pos, true, true, true, true, false, false)) { RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); } } CWorld::pIgnoreEntity = nil; } } else { - RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE) { + CEntity *ent = gaProjectileInfo[i].m_pSource; + if (ent->IsPed() && ((CPed*)ped)->IsPlayer()) { + CPed *ped = (CPed*)ent; + if (ped->GetWeapon(ped->GetWeaponSlot(WEAPONTYPE_DETONATOR)).m_eWeaponType != WEAPONTYPE_DETONATOR + || ped->GetWeapon(ped->GetWeaponSlot(WEAPONTYPE_DETONATOR)).m_nAmmoTotal == 0) { + gaProjectileInfo[i].m_nExplosionTime = 0; + } + } + } else { + RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); + } } gaProjectileInfo[i].m_vecPos = ms_apProjectile[i]->GetPosition(); @@ -275,7 +357,7 @@ CProjectileInfo::IsProjectileInRange(float x1, float x2, float y1, float y2, flo bool result = false; for (int i = 0; i < ARRAY_SIZE(ms_apProjectile); i++) { if (gaProjectileInfo[i].m_bInUse) { - if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_MOLOTOV || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_GRENADE) { + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_MOLOTOV || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_GRENADE) { const CVector &pos = ms_apProjectile[i]->GetPosition(); if (pos.x >= x1 && pos.x <= x2 && pos.y >= y1 && pos.y <= y2 && pos.z >= z1 && pos.z <= z2) { result = true; @@ -296,6 +378,19 @@ CProjectileInfo::IsProjectileInRange(float x1, float x2, float y1, float y2, flo } void +CProjectileInfo::RemoveDetonatorProjectiles() +{ + for (int i = 0; i < ARRAY_SIZE(ms_apProjectile); i++) { + if (gaProjectileInfo[i].m_bInUse && gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE) { + CExplosion::AddExplosion(nil, gaProjectileInfo[i].m_pSource, EXPLOSION_GRENADE, gaProjectileInfo[i].m_vecPos, 0); // TODO(Miami): New parameter: 1 + gaProjectileInfo[i].m_bInUse = false; + CWorld::Remove(ms_apProjectile[i]); + delete ms_apProjectile[i]; + } + } +} + +void CProjectileInfo::RemoveAllProjectiles() { #ifdef SQUEEZE_PERFORMANCE diff --git a/src/weapons/ProjectileInfo.h b/src/weapons/ProjectileInfo.h index 3d8074c9..d1688948 100644 --- a/src/weapons/ProjectileInfo.h +++ b/src/weapons/ProjectileInfo.h @@ -26,6 +26,7 @@ public: static void RemoveNotAdd(CEntity *entity, eWeaponType weaponType, CVector pos); static bool RemoveIfThisIsAProjectile(CObject *pObject); static void RemoveAllProjectiles(); + static void RemoveDetonatorProjectiles(); static void Update(); static bool IsProjectileInRange(float x1, float x2, float y1, float y2, float z1, float z2, bool remove); }; diff --git a/src/weapons/ShotInfo.cpp b/src/weapons/ShotInfo.cpp index e604093c..788bcbe1 100644 --- a/src/weapons/ShotInfo.cpp +++ b/src/weapons/ShotInfo.cpp @@ -146,4 +146,4 @@ CShotInfo::Update() if (!((CTimer::GetFrameCounter() + slot) & 3)) CWorld::SetCarsOnFire(shot.m_startPos.x, shot.m_startPos.y, shot.m_startPos.z, 4.0f, shot.m_sourceEntity); } -}
\ No newline at end of file +} diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 6eab1a65..c0319a11 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -30,25 +30,24 @@ #include "WaterLevel.h" #include "WeaponInfo.h" #include "World.h" +#include "SurfaceTable.h" +#include "Bike.h" +#include "Glass.h" +#include "Sprite.h" +#include "Pickups.h" #include "SaveBuf.h" -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 -}; +float fReloadAnimSampleFraction[5] = { 0.5f, 0.7f, 0.75f, 0.75f, 0.7f }; +float fSeaSparrowAimingAngle = 10.0f; +float fHunterAimingAngle = 30.0f; +float fPlayerAimScaleDist = 5.0f; +float fPlayerAimScale = 2.5f; + +bool CWeapon::bPhotographHasBeenTaken; + +#ifdef SECUROM +int32 sniperPirateCheck = 0x00797743; // 'Cwy\0' ??? +#endif CWeaponInfo * CWeapon::GetInfo() @@ -58,6 +57,17 @@ CWeapon::GetInfo() return info; } +CWeapon::CWeapon(eWeaponType type, int32 ammo) +{ + m_eWeaponType = type; + m_eWeaponState = WEAPONSTATE_READY; + m_nAmmoTotal = Min(ammo, 99999); + m_nAmmoInClip = 0; + Reload(); + m_nTimer = 0; + m_bAddRotOffset = false; +} + void CWeapon::InitialiseWeapons(void) { @@ -66,6 +76,7 @@ CWeapon::InitialiseWeapons(void) CExplosion::Initialise(); CProjectileInfo::Initialise(); CBulletInfo::Initialise(); + bPhotographHasBeenTaken = false; } void @@ -87,18 +98,41 @@ CWeapon::UpdateWeapons(void) CBulletInfo::Update(); } + void CWeapon::Initialise(eWeaponType type, int32 ammo) { m_eWeaponType = type; m_eWeaponState = WEAPONSTATE_READY; - if (ammo > 99999) - m_nAmmoTotal = 99999; - else - m_nAmmoTotal = ammo; + m_nAmmoTotal = Min(ammo, 99999); m_nAmmoInClip = 0; Reload(); m_nTimer = 0; + int32 modelId = CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_nModelId; + int32 model2Id = CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_nModel2Id; + + if ( modelId != -1 ) + CModelInfo::GetModelInfo(modelId)->AddRef(); + if ( model2Id != -1 ) + CModelInfo::GetModelInfo(model2Id)->AddRef(); +} + +void +CWeapon::Shutdown() +{ + int32 modelId = CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_nModelId; + if (modelId != -1) + CModelInfo::GetModelInfo(modelId)->RemoveRef(); + + int32 model2Id = CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_nModel2Id; + if (model2Id != -1) + CModelInfo::GetModelInfo(model2Id)->RemoveRef(); + + m_eWeaponType = WEAPONTYPE_UNARMED; + m_eWeaponState = WEAPONSTATE_READY; + m_nAmmoInClip = 0; + m_nAmmoTotal = 0; + m_nTimer = 0; } bool @@ -108,19 +142,18 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) CVector fireOffset(0.0f, 0.0f, 0.6f); CVector *source = fireSource; - - if (!fireSource) - { - fireOffset = shooter->GetMatrix() * fireOffset; #ifdef FIX_BUGS - static CVector tmp; - tmp = fireOffset; - source = &tmp; + static CVector shooterSource; #else - source = &fireOffset; + CVector shooterSource; #endif - + + if ( !fireSource ) + { + shooterSource = shooter->GetMatrix() * fireOffset; + source = &shooterSource; } + if ( m_bAddRotOffset ) { float heading = RADTODEG(shooter->GetForward().Heading()); @@ -133,44 +166,60 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) return false; bool fired; + bool addFireRateAsDelay = true; if ( GetInfo()->m_eWeaponFire != WEAPON_FIRE_MELEE ) { - if ( m_nAmmoInClip <= 0 ) - return false; + if (m_nAmmoInClip <= 0) { + if (m_nAmmoTotal <= 0 || m_eWeaponState == WEAPONSTATE_RELOADING) + return false; + + Reload(); + } switch ( m_eWeaponType ) { case WEAPONTYPE_SHOTGUN: + case WEAPONTYPE_SPAS12_SHOTGUN: + case WEAPONTYPE_STUBBY_SHOTGUN: { + addFireRateAsDelay = true; fired = FireShotgun(shooter, source); break; } - case WEAPONTYPE_COLT45: - case WEAPONTYPE_UZI: - case WEAPONTYPE_AK47: - { - fired = FireInstantHit(shooter, source); - - break; - } - case WEAPONTYPE_SNIPERRIFLE: + case WEAPONTYPE_LASERSCOPE: { - fired = FireSniper(shooter); - + if (shooter == FindPlayerPed()) + fired = FireSniper(shooter); + else + fired = FireInstantHit(shooter, source); + break; } - - case WEAPONTYPE_M16: + + case WEAPONTYPE_COLT45: + case WEAPONTYPE_PYTHON: + case WEAPONTYPE_UZI: + case WEAPONTYPE_TEC9: + case WEAPONTYPE_SILENCED_INGRAM: + case WEAPONTYPE_MP5: + case WEAPONTYPE_M4: + case WEAPONTYPE_RUGER: + case WEAPONTYPE_M60: + case WEAPONTYPE_MINIGUN: + case WEAPONTYPE_HELICANNON: { - if ( TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON && shooter == FindPlayerPed() ) + if ((TheCamera.PlayerWeaponMode.Mode == CCam::MODE_HELICANNON_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON) + && shooter == FindPlayerPed()) { + addFireRateAsDelay = true; fired = FireM16_1stPerson(shooter); - else + } else { + addFireRateAsDelay = false; fired = FireInstantHit(shooter, source); - + } break; } @@ -193,12 +242,12 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) case WEAPONTYPE_MOLOTOV: case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: + case WEAPONTYPE_TEARGAS: { 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 ) { @@ -210,6 +259,11 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) else fired = FireProjectile(shooter, source, 0.3f); + if (m_eWeaponType == WEAPONTYPE_DETONATOR_GRENADE) { + ((CPed*)shooter)->GiveWeapon(WEAPONTYPE_DETONATOR, 1, true); + ((CPed*)shooter)->GetWeapon(((CPed*)shooter)->GetWeaponSlot(WEAPONTYPE_DETONATOR)).m_eWeaponState = WEAPONSTATE_READY; + ((CPed*)shooter)->SetCurrentWeapon(WEAPONTYPE_DETONATOR); + } break; } @@ -229,16 +283,10 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) break; } - - case WEAPONTYPE_HELICANNON: + + case WEAPONTYPE_CAMERA: { - 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); + fired = TakePhotograph(shooter); break; } @@ -257,17 +305,65 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) if (shooter->IsPed()) { CPed* shooterPed = (CPed*)shooter; - - shooterPed->bIsShooting = true; - - if (shooterPed->IsPlayer()) - isPlayer = true; - + + if ( m_eWeaponType != WEAPONTYPE_CAMERA ) + { + shooterPed->bIsShooting = true; + + if (shooterPed->IsPlayer()) + isPlayer = true; + } + DMAudio.PlayOneShot(shooterPed->m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f); + + if ( isPlayer ) + { + CPed *aimPed = (CPed *)shooterPed->m_pSeekTarget; + if ( aimPed ) + { + if ( aimPed->IsPed() ) + shooterPed->Say(SOUND_PED_ON_FIRE); + } + } + } + + switch ( m_eWeaponType ) + { + case WEAPONTYPE_COLT45: + case WEAPONTYPE_PYTHON: + case WEAPONTYPE_SHOTGUN: + case WEAPONTYPE_SPAS12_SHOTGUN: + case WEAPONTYPE_STUBBY_SHOTGUN: + case WEAPONTYPE_TEC9: + case WEAPONTYPE_UZI: + case WEAPONTYPE_SILENCED_INGRAM: + case WEAPONTYPE_MP5: + case WEAPONTYPE_M4: + case WEAPONTYPE_RUGER: + case WEAPONTYPE_SNIPERRIFLE: + case WEAPONTYPE_LASERSCOPE: + case WEAPONTYPE_M60: + case WEAPONTYPE_MINIGUN: + CStats::RoundsFiredByPlayer++; + break; + + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: + case WEAPONTYPE_MOLOTOV: + case WEAPONTYPE_ROCKET: + case WEAPONTYPE_ROCKETLAUNCHER: + case WEAPONTYPE_DETONATOR: + case WEAPONTYPE_HELICANNON: + CStats::KgsOfExplosivesUsed++; + break; } + - if (m_nAmmoInClip > 0) m_nAmmoInClip--; - if (m_nAmmoTotal > 0 && (m_nAmmoTotal < 25000 || isPlayer)) m_nAmmoTotal--; + if (m_nAmmoInClip > 0) + m_nAmmoInClip--; + + if (m_nAmmoTotal > 0 && (m_nAmmoTotal < 25000 || isPlayer) && (!isPlayer || CStats::GetPercentageProgress() < 100.0f || m_eWeaponType == WEAPONTYPE_DETONATOR)) + m_nAmmoTotal--; if (m_eWeaponState == WEAPONSTATE_READY && m_eWeaponType == WEAPONTYPE_FLAMETHROWER) DMAudio.PlayOneShot(((CPhysical*)shooter)->m_audioEntityId, SOUND_WEAPON_FLAMETHROWER_FIRE, 0.0f); @@ -276,8 +372,12 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) if (m_nAmmoInClip == 0) { - if (m_nAmmoTotal == 0) + if (m_nAmmoTotal == 0) { + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_CAMERA) + CPad::GetPad(0)->Clear(false); + return true; + } m_eWeaponState = WEAPONSTATE_RELOADING; m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload; @@ -291,9 +391,10 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) return true; } - m_nTimer = CTimer::GetTimeInMilliseconds() + 1000; - if (shooter == FindPlayerPed()) - CStats::RoundsFiredByPlayer++; + if ( addFireRateAsDelay ) + m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nFiringRate; + else + m_nTimer = CTimer::GetTimeInMilliseconds(); } } else @@ -302,9 +403,14 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) { m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload; m_eWeaponState = WEAPONSTATE_FIRING; + + if (shooter->IsPed() && m_eWeaponType != WEAPONTYPE_CHAINSAW) + { + DMAudio.PlayOneShot(((CPed*)shooter)->m_audioEntityId, SOUND_MELEE_ATTACK_START, m_eWeaponType << 8); + } } - FireMelee(shooter, *source); + fired = FireMelee(shooter, *source); } if ( m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT ) @@ -314,7 +420,7 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) } bool -CWeapon::FireFromCar(CAutomobile *shooter, bool left) +CWeapon::FireFromCar(CVehicle *shooter, bool left, bool right) { ASSERT(shooter!=nil); @@ -324,12 +430,15 @@ CWeapon::FireFromCar(CAutomobile *shooter, bool left) if ( m_nAmmoInClip <= 0 ) return false; - if ( FireInstantHitFromCar(shooter, left) ) + if ( FireInstantHitFromCar(shooter, left, right) ) { 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--; + if ( m_nAmmoInClip > 0 ) + m_nAmmoInClip--; + + if ( m_nAmmoTotal < 25000 && m_nAmmoTotal > 0 && (!shooter || shooter->GetStatus() != STATUS_PLAYER || CStats::GetPercentageProgress() < 100.f)) + m_nAmmoTotal--; m_eWeaponState = WEAPONSTATE_FIRING; @@ -345,8 +454,6 @@ CWeapon::FireFromCar(CAutomobile *shooter, bool left) } m_nTimer = CTimer::GetTimeInMilliseconds() + 1000; - if ( shooter == FindPlayerVehicle() ) - CStats::RoundsFiredByPlayer++; } return true; @@ -360,27 +467,45 @@ CWeapon::FireMelee(CEntity *shooter, CVector &fireSource) CWeaponInfo *info = GetInfo(); bool anim2Playing = false; - if ( RpAnimBlendClumpGetAssociation(shooter->GetClump(), info->m_Anim2ToPlay) ) - anim2Playing = true; - + + if ( CPed::GetFireAnimGround(info, false) != (AnimationId)0 ) + { + if ( RpAnimBlendClumpGetAssociation(shooter->GetClump(), CPed::GetFireAnimGround(info, false)) ) + anim2Playing = true; + } + ASSERT(shooter->IsPed()); CPed *shooterPed = (CPed*)shooter; + if (shooterPed == FindPlayerPed()) + { + if (m_eWeaponType == WEAPONTYPE_GOLFCLUB || m_eWeaponType == WEAPONTYPE_NIGHTSTICK || + (m_eWeaponType >= WEAPONTYPE_BASEBALLBAT && m_eWeaponType <= WEAPONTYPE_CHAINSAW)) + { + CGlass::BreakGlassPhysically(fireSource, info->m_fRadius); + + if (m_eWeaponType == WEAPONTYPE_CHAINSAW) + CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, FindPlayerPed(), FindPlayerPed(), 1000); + } + } + + int damageEntityRegistered = 0; + 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) ) + && victimPed != shooterPed->m_leader || !(CGeneral::GetRandomNumber() & 31) + && (!shooterPed->IsGangMember() || victimPed->CanBeDamagedByThisGangMember(shooterPed)) ) { bool collided = false; - CColModel *victimPedCol = &CTempColModels::ms_colModelPed1; - if ( victimPed->OnGround() || !victimPed->IsPedHeadAbovePos(-0.3f) ) - victimPedCol = &CTempColModels::ms_colModelPedGroundHit; - + if (victimPed->m_nPedState == PED_DRIVING && (m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BRASSKNUCKLE + || info->IsFlagSet(WEAPONFLAG_FIGHTMODE))) + continue; float victimPedRadius = victimPed->GetBoundRadius() + info->m_fRadius; if ( victimPed->bUsesCollision || victimPed->Dead() || victimPed->Driving() ) @@ -389,12 +514,28 @@ CWeapon::FireMelee(CEntity *shooter, CVector &fireSource) if ( SQR(victimPedRadius) > (victimPedPos-fireSource).MagnitudeSqr() ) { CVector collisionDist; + CColModel* victimPedCol = &CTempColModels::ms_colModelPed1; + bool useLocalPos = false; + if (victimPed->m_nPedState == PED_FALL + || victimPed->m_nPedState == PED_DIE && victimPed->bIsPedDieAnimPlaying + || victimPed->m_nWaitState == WAITSTATE_SIT_IDLE + || victimPed->m_nWaitState == WAITSTATE_SUN_BATHE_IDLE) + { + useLocalPos = true; + victimPedCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(victimPed->GetModelIndex()))->AnimatePedColModelSkinnedWorld(victimPed->GetClump()); + } else if (victimPed->DyingOrDead()) { + victimPedCol = &CTempColModels::ms_colModelPedGroundHit; + } int32 s = 0; while ( s < victimPedCol->numSpheres ) { CColSphere *sphere = &victimPedCol->spheres[s]; - collisionDist = victimPedPos+sphere->center-fireSource; + + if (useLocalPos) + collisionDist = sphere->center - fireSource; + else + collisionDist = victimPedPos + sphere->center - fireSource; if ( SQR(sphere->radius + info->m_fRadius) > collisionDist.MagnitudeSqr() ) { @@ -415,65 +556,127 @@ CWeapon::FireMelee(CEntity *shooter, CVector &fireSource) int32 localDir = victimPed->GetLocalDirection(posOffset); - bool isBat = m_eWeaponType == WEAPONTYPE_BASEBALLBAT; + bool isHeavy = m_eWeaponType >= WEAPONTYPE_GOLFCLUB && m_eWeaponType <= WEAPONTYPE_KATANA && m_eWeaponType != WEAPONTYPE_HAMMER; + + if (shooterPed->m_fDamageImpulse == 0.0f) + { + shooterPed->m_pDamageEntity = victimPed; + victimPed->RegisterReference(&shooterPed->m_pDamageEntity); + } + + damageEntityRegistered = 3; + if (victimPed->bInVehicle) + { + CVehicle *victimVeh = victimPed->m_pMyVehicle; + if (victimVeh) + { + if (victimVeh->IsBike()) + { + CBike *victimBike = (CBike*)victimVeh; + victimBike->KnockOffRider(m_eWeaponType, localDir, victimPed, false); + if (victimBike->pDriver) + victimBike->pDriver->ReactToAttack(shooterPed); + else + { + if (victimVeh->pPassengers[0]) + victimVeh->pPassengers[0]->ReactToAttack(shooterPed); + } + continue; + } + } + } if ( !victimPed->DyingOrDead() ) victimPed->ReactToAttack(shooterPed); uint8 hitLevel = HITLEVEL_HIGH; - if ( isBat && victimPed->OnGround() ) + if ( isHeavy && (victimPed->OnGround() || victimPed->m_nWaitState == WAITSTATE_SUN_BATHE_IDLE)) hitLevel = HITLEVEL_GROUND; victimPed->StartFightDefend(localDir, hitLevel, 10); if ( !victimPed->DyingOrDead() ) { - if ( shooterPed->IsPlayer() && isBat && anim2Playing ) + if ( shooterPed->IsPlayer() && isHeavy && 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 + if ( victimPed->IsPlayer() && isHeavy ) // 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 ( CGame::nastyGame && victimPed->GetIsOnScreen() ) { - if ( victimPed->GetIsOnScreen() ) - { - CVector dir = collisionDist * RecipSqrt(1.0f, 10.0f*collisionDist.MagnitudeSqr()); + 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 ( isHeavy ) + { + 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); - CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, dir); + } - if ( isBat ) + if (m_eWeaponType == WEAPONTYPE_CHAINSAW) + { + if (victimPed->m_nPedState != PED_DEAD && !((CTimer::GetFrameCounter() + 17) & 1) + || victimPed->m_nPedState == PED_DEAD && !((CTimer::GetFrameCounter() + 17) & 3)) { - 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); + CParticle::AddParticle(PARTICLE_TEST, bloodPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.2f); } + CVector newDir(dir); + newDir.z += 0.2f; + CParticle::AddParticle(PARTICLE_BLOOD_SMALL, bloodPos, newDir); + CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, newDir); + newDir.z = dir.z + 0.1f; + CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, newDir); + newDir.x = 0.0f; + newDir.y = 0.0f; + newDir.z = 0.01f; + CParticle::AddParticle(PARTICLE_DEBRIS2, bloodPos, newDir); + + CVector dropDir(CGeneral::GetRandomNumberInRange(-0.15f, 0.15f), CGeneral::GetRandomNumberInRange(0.1f, 0.35f), 0.f); + CVector dropPos(CGeneral::GetRandomNumberInRange(SCREEN_STRETCH_X(50.0f), SCREEN_STRETCH_FROM_RIGHT(50.0f)), + CGeneral::GetRandomNumberInRange(SCREEN_STRETCH_Y(50.0f), SCREEN_STRETCH_FROM_BOTTOM(50.0f)), 1.f); + CParticle::AddParticle(PARTICLE_BLOODDROP, dropPos, dropDir, nil, CGeneral::GetRandomNumberInRange(0.1f, 0.15f), + CRGBA(0, 0, 0, 0), 0, 0, CGeneral::GetRandomNumber() & 1, 0); + + } + if (info->m_AnimToPlay == ASSOCGRP_KNIFE) + { + dir += 0.1f * shooterPed->GetUp() + 0.05f * shooterPed->GetRight(); + CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, dir); + CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, dir); + CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, dir); } } if ( !victimPed->OnGround() ) { if ( victimPed->m_fHealth > 0.0f - && (victimPed->m_fHealth < 20.0f && victimPedHealth > 20.0f || isBat && !victimPed->IsPlayer()) ) + && (victimPed->m_fHealth < 30.0f && victimPedHealth > 30.0f || + (isHeavy || m_eWeaponType == WEAPONTYPE_BRASSKNUCKLE) && !victimPed->IsPlayer()) ) { posOffset.Normalise(); victimPed->bIsStanding = false; - victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 3.0f); + if(m_eWeaponType == WEAPONTYPE_CHAINSAW) + victimPed->ApplyMoveForce(posOffset.x*-2.0f, posOffset.y*-2.0f, 2.0f); + else + victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 3.0f); - if ( isBat && victimPed->IsPlayer() ) + if ( isHeavy && victimPed->IsPlayer() ) victimPed->SetFall(3000, AnimationId(ANIM_STD_HIGHIMPACT_FRONT + localDir), false); else victimPed->SetFall(1500, AnimationId(ANIM_STD_HIGHIMPACT_FRONT + localDir), false); @@ -486,21 +689,151 @@ CWeapon::FireMelee(CEntity *shooter, CVector &fireSource) { posOffset.Normalise(); victimPed->bIsStanding = false; - victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 3.0f); + if(m_eWeaponType == WEAPONTYPE_CHAINSAW) + victimPed->ApplyMoveForce(posOffset.x*-1.0f, posOffset.y*-1.0f, 1.0f); + else + 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); + if (m_eWeaponType != WEAPONTYPE_KNIFE && m_eWeaponType != WEAPONTYPE_MACHETE + && m_eWeaponType != WEAPONTYPE_KATANA && m_eWeaponType != WEAPONTYPE_CHAINSAW) { + + 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); + } else { + if (victimPed->m_nPedType == PEDTYPE_COP) + CEventList::RegisterEvent(EVENT_ASSAULT_NASTYWEAPON_POLICE, EVENT_ENTITY_PED, victimPed, shooterPed, 2000); + else + CEventList::RegisterEvent(EVENT_ASSAULT_NASTYWEAPON, EVENT_ENTITY_PED, victimPed, shooterPed, 2000); + } } } } } } } + CVehicle *nearVeh = (CVehicle*)CWorld::TestSphereAgainstWorld(fireSource, info->m_fRadius, nil, false, true, false, false, false, false); + if (nearVeh && nearVeh->IsCar()) + { + CAutomobile *nearCar = (CAutomobile*)nearVeh; + m_eWeaponState = WEAPONSTATE_MELEE_MADECONTACT; + if (shooterPed == FindPlayerPed()) + { + if (nearCar->IsLawEnforcementVehicle()) + { + FindPlayerPed()->SetWantedLevelNoDrop(1); + } + CEventList::RegisterEvent(EVENT_ASSAULT, EVENT_ENTITY_VEHICLE, nearCar, shooterPed, 2000); + } + float oldHealth = nearCar->m_fHealth; + if (m_eWeaponType == WEAPONTYPE_CHAINSAW) + { + for( int32 i=0; i<4; i++ ) + { + CParticle::AddParticle(PARTICLE_SPARK_SMALL, gaTempSphereColPoints[0].point, CVector(0.0f, 0.0f, 0.3f)); + CParticle::AddParticle(PARTICLE_SPARK, gaTempSphereColPoints[0].point, gaTempSphereColPoints[0].normal * 0.1f); + } + } + if (m_eWeaponType == WEAPONTYPE_CHAINSAW) + { + nearCar->VehicleDamage(info->m_nDamage * (0.00075f * nearCar->pHandling->fMass), gaTempSphereColPoints[0].pieceB); + + CParticle::AddParticle(PARTICLE_HEATHAZE, gaTempSphereColPoints[0].point, CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0); + } + else + { + nearCar->VehicleDamage(info->m_nDamage* (0.01f * nearCar->pHandling->fMass), gaTempSphereColPoints[0].pieceB); + } + if (nearCar->m_fHealth < oldHealth) + { + nearCar->m_nLastWeaponDamage = m_eWeaponType; + nearCar->m_pLastDamageEntity = shooterPed; + } + if (shooterPed->m_fDamageImpulse == 0.0f) + { + shooterPed->m_pDamageEntity = nearCar; + nearCar->RegisterReference(&shooterPed->m_pDamageEntity); + } + damageEntityRegistered = 2; + if (FindPlayerPed()->GetWeapon() == this && nearCar->VehicleCreatedBy != MISSION_VEHICLE) + { + if (nearCar->AutoPilot.m_nDrivingStyle != DRIVINGSTYLE_PLOUGH_THROUGH + && (CGeneral::GetRandomTrueFalse() || nearCar->AutoPilot.m_nCarMission != MISSION_CRUISE)) + { + int leaveCarDelay = 200; + CPed *driver = nearCar->pDriver; + if (driver && driver->CharCreatedBy != MISSION_CHAR) + { + if (driver->m_pedStats->m_temper <= driver->m_pedStats->m_fear) + { + driver->SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + } + else + { + driver->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, FindPlayerPed()); + driver->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; + driver->m_prevObjective = OBJECTIVE_KILL_CHAR_ON_FOOT; + } + driver->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 200; + leaveCarDelay = 400; + } + for (int j = 0; j < nearCar->m_nNumPassengers; ++j) + { + CPed *passenger = nearCar->pPassengers[j]; + if (passenger && passenger->CharCreatedBy != MISSION_CHAR) + { + nearCar->pPassengers[j]->SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + leaveCarDelay; + leaveCarDelay += 200; + } + } + } + else + { + CPed *driver = nearCar->pDriver; + if (driver) + { + if (driver->m_objective != OBJECTIVE_LEAVE_CAR && driver->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && + driver->m_objective != OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE) + { + if (nearCar->AutoPilot.m_nDrivingStyle != DRIVINGSTYLE_PLOUGH_THROUGH) + nearCar->AutoPilot.m_nCruiseSpeed = nearCar->AutoPilot.m_nCruiseSpeed * 1.5f; + + nearCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_PLOUGH_THROUGH; + } + } + } + } + } + if (m_eWeaponType == WEAPONTYPE_CHAINSAW) + { + CEntity *nearStatic = (CObject*)CWorld::TestSphereAgainstWorld(fireSource, info->m_fRadius, nil, true, false, false, true, false, false); + if (nearStatic) + { + for(int i=0; i < 4; i++) { + CParticle::AddParticle(PARTICLE_SPARK_SMALL, gaTempSphereColPoints[0].point, CVector(0.0f, 0.0f, 0.3f), 0, 0.0f, 0, 0, 0, 0); + CParticle::AddParticle(PARTICLE_SPARK, gaTempSphereColPoints[0].point, 0.1f * gaTempSphereColPoints[0].normal, 0, 0.0f, 0, 0, 0, 0); + } + + CParticle::AddParticle(PARTICLE_HEATHAZE, gaTempSphereColPoints[0].point, CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0); + + if (!damageEntityRegistered) + { + m_eWeaponState = WEAPONSTATE_MELEE_MADECONTACT; + if (shooterPed->m_fDamageImpulse == 0.0f) + { + shooterPed->m_pDamageEntity = nearStatic; + nearStatic->RegisterReference(&shooterPed->m_pDamageEntity); + } + } + if (nearStatic->IsObject() && ((CObject*)nearStatic)->m_nCollisionDamageEffect >= DAMAGE_EFFECT_SMASH_COMPLETELY) + ((CObject*)nearStatic)->ObjectDamage(200.0f); + } + } return true; } @@ -542,9 +875,6 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) int32 accuracy = shooterPed->m_wepAccuracy; int32 inaccuracy = 100-accuracy; - if ( accuracy != 100 ) - FindPlayerPed(); //what ? - CPed *threatAttack = (CPed*)shooterPed->m_pPointGunAt; if ( threatAttack->IsPed() ) { @@ -555,19 +885,40 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) target = threatAttack->GetPosition(); target -= *fireSource; - target *= info->m_fRange / target.Magnitude(); + float distToTarget = Max(target.Magnitude(), 0.01f); + target *= info->m_fRange / distToTarget; target += *fireSource; - if ( inaccuracy != 0 ) + if (shooter == FindPlayerPed() && inaccuracy != 0.f) { + float newInaccuracy = fPlayerAimScale * FindPlayerPed()->m_fAttackButtonCounter * (inaccuracy * Min(1.f, fPlayerAimScaleDist / distToTarget)); + if (FindPlayerPed()->bIsDucking) + newInaccuracy *= 0.4f; + + target.x += CGeneral::GetRandomNumberInRange(-0.15f, 0.15f) * newInaccuracy; + target.y += CGeneral::GetRandomNumberInRange(-0.15f, 0.15f) * newInaccuracy; + target.z += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f) * newInaccuracy; + FindPlayerPed()->m_fAttackButtonCounter += info->m_nDamage * 0.04f; + } + else if (inaccuracy > 0.f) + { + if (threatAttack == FindPlayerPed()) + { + float speed = Min(0.33f, FindPlayerPed()->m_vecMoveSpeed.Magnitude()); + inaccuracy *= (0.3f * speed * 100.f / 33.f + 0.8f); + } 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); + if (shooter == FindPlayerPed()) + CWorld::bIncludeDeadPeds = true; + + CWorld::bIncludeBikers = true; + ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, false, false); CWorld::bIncludeDeadPeds = false; + CWorld::bIncludeBikers = false; } else { @@ -577,11 +928,13 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) shooterPed->TransformToNode(target, PED_HANDR); - ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false); + CWorld::bIncludeBikers = true; + ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, false, false); + CWorld::bIncludeBikers = false; } #ifdef FIX_BUGS // fix muzzleflash rotation - heading = CGeneral::GetAngleBetweenPoints(fireSource->x, fireSource->y, target.x, target.y); + heading = CGeneral::GetAngleBetweenPoints(source.x, source.y, target.x, target.y); angle = DEGTORAD(heading); ahead = CVector2D(-Sin(angle), Cos(angle)); @@ -590,38 +943,43 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) } else if ( shooter == FindPlayerPed() && TheCamera.Cams[0].Using3rdPersonMouseCam() ) { - CVector src, trgt; - TheCamera.Find3rdPersonCamTargetVector(info->m_fRange, *fireSource, src, trgt); + TheCamera.Find3rdPersonCamTargetVector(info->m_fRange, *fireSource, source, target); #ifdef FREE_CAM CPed *shooterPed = (CPed *)shooter; if((shooterPed->m_pedIK.m_flags & CPedIK::GUN_POINTED_SUCCESSFULLY) == 0) { - trgt.x = info->m_fRange; - trgt.y = 0.0f; - trgt.z = 0.0f; + target.x = info->m_fRange; + target.y = 0.0f; + target.z = 0.0f; - shooterPed->TransformToNode(trgt, PED_HANDR); + shooterPed->TransformToNode(target, PED_HANDR); } #endif #ifdef FIX_BUGS // fix muzzleflash rotation - heading = CGeneral::GetAngleBetweenPoints(src.x, src.y, trgt.x, trgt.y); + heading = CGeneral::GetAngleBetweenPoints(source.x, source.y, target.x, target.y); angle = DEGTORAD(heading); ahead = CVector2D(-Sin(angle), Cos(angle)); ahead.Normalise(); #endif - + CWorld::bIncludeBikers = true; CWorld::bIncludeDeadPeds = true; - ProcessLineOfSight(src, trgt,point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false); + CWorld::bIncludeCarTyres = true; + ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, false, false); + CWorld::bIncludeBikers = false; CWorld::bIncludeDeadPeds = false; + CWorld::bIncludeCarTyres = false; + + if (victim) + CheckForShootingVehicleOccupant(&victim, &point, m_eWeaponType, source, target); int32 rotSpeed = 1; - if ( m_eWeaponType == WEAPONTYPE_M16 ) + if ( m_eWeaponType == WEAPONTYPE_M4 ) rotSpeed = 4; CVector bulletPos; - if ( CHeli::TestBulletCollision(&src, &trgt, &bulletPos, 4) ) + 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), nil, 0.0f, rotSpeed); @@ -629,140 +987,117 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) } else { - float shooterHeading = RADTODEG(shooter->GetForward().Heading()); - float shooterAngle = DEGTORAD(shooterHeading); + uint32 model = shooter->GetModelIndex(); + if (model == MI_HUNTER || model == MI_SEASPAR || model == MI_SPARROW) + { + float inaccuracyMult = 0.6f; + target = shooter->GetForward(); + if (shooter->GetStatus() == STATUS_PLAYER) + { + target *= info->m_fRange; + target += *fireSource; + CWeapon::DoDriveByAutoAiming(FindPlayerPed(), (CVehicle*)shooter, fireSource, &target); + target -= *fireSource; + target.Normalise(); + if (model == MI_SEASPAR || model == MI_SPARROW) + inaccuracyMult = 0.1f; + else + inaccuracyMult = 0.3f; + } + target.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f) * inaccuracyMult; + target.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f) * inaccuracyMult; + target.z += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f) * inaccuracyMult; - CVector2D rotOffset(-Sin(shooterAngle), Cos(shooterAngle)); - rotOffset.Normalise(); + target.Normalise(); + target *= info->m_fRange; + target += *fireSource; + CWorld::pIgnoreEntity = shooter; + ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false); + CWorld::pIgnoreEntity = nil; - target = *fireSource; - target.x += rotOffset.x * info->m_fRange; - target.y += rotOffset.y * info->m_fRange; + int32 rotSpeed = 1; + if (m_eWeaponType == WEAPONTYPE_M4) + rotSpeed = 4; - if ( shooter->IsPed() ) - DoDoomAiming(shooter, fireSource, &target); + 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); + } + } + else + { + float shooterHeading = RADTODEG(shooter->GetForward().Heading()); + float shooterAngle = DEGTORAD(shooterHeading); - ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false); + CVector2D rotOffset(-Sin(shooterAngle), Cos(shooterAngle)); + rotOffset.Normalise(); - int32 rotSpeed = 1; - if ( m_eWeaponType == WEAPONTYPE_M16 ) - rotSpeed = 4; + target = *fireSource; + target.x += rotOffset.x * info->m_fRange; + target.y += rotOffset.y * info->m_fRange; - 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); + CParticle::HandleShootableBirdsStuff(shooter, *fireSource); + if (shooter->IsPed() && ((CPed*)shooter)->bDoomAim && (shooter != FindPlayerPed() || !info->IsFlagSet(WEAPONFLAG_CANAIM))) + { + CWeapon::DoDoomAiming(shooter, fireSource, &target); + } + + CWorld::bIncludeBikers = true; + ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, false, false); + CWorld::bIncludeBikers = false; + + int32 rotSpeed = 1; + if (m_eWeaponType == WEAPONTYPE_M4) + 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; + if ( shooter->IsPed() && victim) + { + if (victim == ((CPed*)shooter)->m_leader) + return false; + + if (victim->IsPed() && ((CPed*)shooter)->IsGangMember() && !((CPed*)victim)->CanBeDamagedByThisGangMember((CPed*)shooter)) + return false; + } - CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed *)shooter, 1000); + if (shooter->IsPed()) + CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed*)shooter, 1000); + else if (shooter->IsVehicle() && ((CVehicle*)shooter)->pDriver) + CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_VEHICLE, shooter, ((CVehicle*)shooter)->pDriver, 1000); if ( shooter == FindPlayerPed() ) { - CStats::InstantHitsFiredByPlayer++; if ( !(CTimer::GetFrameCounter() & 3) ) MakePedsJumpAtShot((CPhysical*)shooter, fireSource, &target); } switch ( m_eWeaponType ) { - case WEAPONTYPE_AK47: + case WEAPONTYPE_M4: + case WEAPONTYPE_RUGER: + case WEAPONTYPE_M60: + case WEAPONTYPE_MINIGUN: + case WEAPONTYPE_HELICANNON: { static uint8 counter = 0; - if ( !(++counter & 1) ) + if ( info->m_nFiringRate >= 50 || !(++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)); +#ifdef FIX_BUGS + AddGunFlashBigGuns(*fireSource, target); +#else + AddGunFlashBigGuns(*fireSource, *fireSource + target); +#endif CVector gunshellPos = *fireSource; gunshellPos -= CVector(0.65f*ahead.x, 0.65f*ahead.y, 0.0f); @@ -775,6 +1110,9 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) } case WEAPONTYPE_UZI: + case WEAPONTYPE_TEC9: + case WEAPONTYPE_SILENCED_INGRAM: + case WEAPONTYPE_MP5: { CPointLights::AddLight(CPointLights::LIGHT_POINT, *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f, @@ -813,6 +1151,9 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) } case WEAPONTYPE_COLT45: + case WEAPONTYPE_PYTHON: + case WEAPONTYPE_SNIPERRIFLE: + case WEAPONTYPE_LASERSCOPE: { CPointLights::AddLight(CPointLights::LIGHT_POINT, *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f, @@ -851,6 +1192,71 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) } void +CWeapon::AddGunFlashBigGuns(CVector start, CVector end) +{ + CPointLights::AddLight(CPointLights::LIGHT_POINT, + start, CVector(0.0f, 0.0f, 0.0f), 5.0f, + 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false); + CVector gunflashPos = start; + + CVector shootVec = end - start; + + // Wtf did you do there R*? + shootVec.Normalise(); + CVector2D ahead = shootVec; + ahead.Normalise(); + + 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 = start; + 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 = start; + 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 = start; + 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 = start; + 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 = start; + float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f); + CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x * rnd, ahead.y * rnd, 0.0f)); +} + +void CWeapon::AddGunshell(CEntity *shooter, CVector const &source, CVector2D const &direction, float size) { ASSERT(shooter!=nil); @@ -879,6 +1285,7 @@ CWeapon::AddGunshell(CEntity *shooter, CVector const &source, CVector2D const &d } } + void CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, CVector *source, CVector *target, CColPoint *point, CVector2D ahead) @@ -892,72 +1299,99 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, if ( victim ) { - CGlass::WasGlassHitByBullet(victim, point->point); - - CVector traceTarget = point->point; - CBulletTraces::AddTrace(source, &traceTarget); - - if ( shooter != nil ) + if (shooter) { - if ( shooter == FindPlayerPed() ) + if (shooter && shooter->IsPed() && ((CPed*)shooter)->m_attachedTo == victim) + return; + + if (shooter->IsPed() && !((CPed*)shooter)->IsPlayer()) { - if ( victim->IsPed() || victim->IsVehicle() ) - CStats::InstantHitsHitByPlayer++; + CPed* shooterPed = (CPed*)shooter; + CEntity* guyWePointGun = shooterPed->m_pPointGunAt; + if (guyWePointGun) + { + if (victim != guyWePointGun) + { + float distWithAim = (guyWePointGun->GetPosition() - shooter->GetPosition()).Magnitude(); + float distWithBullet = (point->point - shooter->GetPosition()).Magnitude(); + if (distWithAim > 0.1f && distWithBullet > 0.1f) + { + // Normalize + CVector aimDir = (guyWePointGun->GetPosition() - shooter->GetPosition()) * (1.0f / distWithAim); + CVector bulletDir = (point->point - shooter->GetPosition()) * (1.0f / distWithBullet); + + float dotProd = DotProduct(aimDir, bulletDir); + float aimAndBulletAngle; + if (dotProd <= 0.35f) + aimAndBulletAngle = PI; + else + aimAndBulletAngle = Acos(dotProd); + + if (aimAndBulletAngle <= DEGTORAD(45.0f) && (aimAndBulletAngle <= DEGTORAD(15.0f) || distWithBullet / distWithAim >= 0.75f) && distWithBullet / distWithAim >= 0.99f) + { + shooterPed->bObstacleShowedUpDuringKillObjective = false; + shooterPed->m_shotTime = 0; + } + else + { + shooterPed->bObstacleShowedUpDuringKillObjective = true; + shooterPed->m_shootTimer = 0; + shooterPed->m_shotTime = CTimer::GetTimeInMilliseconds(); + if (distWithAim < 10.0f) + shooterPed->SetAttackTimer(1500); + else + shooterPed->SetAttackTimer(3000); + } + } + } + } } } + CGlass::WasGlassHitByBullet(victim, point->point); + + CVector traceTarget = point->point; + CBulletTraces::AddTrace(source, &traceTarget, m_eWeaponType, shooter); - if ( victim->IsPed() && ((CPed*)shooter)->m_nPedType != ((CPed*)victim)->m_nPedType || ((CPed*)shooter)->m_nPedType == PEDTYPE_PLAYER2 ) + if (victim->IsPed() && shooter->IsVehicle() && ((CVehicle*)shooter)->pDriver) + shooter = ((CVehicle*)shooter)->pDriver; + + if ( victim->IsPed() && shooter->IsPed() && + (((CPed*)shooter)->m_nPedType != ((CPed*)victim)->m_nPedType || ((CPed*)shooter)->m_nPedType == PEDTYPE_PLAYER2 || + !((CPed*)shooter)->IsGangMember() && ((CPed*)shooter)->m_nPedType != PEDTYPE_COP)) { CPed *victimPed = (CPed *)victim; if ( !victimPed->DyingOrDead() && victim != shooter ) { - if ( victimPed->DoesLOSBulletHitPed(*point) ) - { - CVector pos = victimPed->GetPosition(); + CVector pos = victimPed->GetPosition(); - CVector2D posOffset(source->x-pos.x, source->y-pos.y); - int32 localDir = victimPed->GetLocalDirection(posOffset); + CVector2D posOffset(source->x-pos.x, source->y-pos.y); + int32 localDir = victimPed->GetLocalDirection(posOffset); - victimPed->ReactToAttack(shooter); + victimPed->ReactToAttack(shooter); - if ( !victimPed->IsPedInControl() || victimPed->bIsDucking ) + if ( !victimPed->IsPedInControl() || victimPed->bIsDucking ) + { + victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir); + } + else + { + if ( victimPed->bCanBeShotInVehicle && (IsShotgun(m_eWeaponType) || + (!victimPed->IsPlayer() && (m_eWeaponType == WEAPONTYPE_HELICANNON || m_eWeaponType == WEAPONTYPE_M60 || m_eWeaponType == WEAPONTYPE_PYTHON)))) { + posOffset.Normalise(); + victimPed->bIsStanding = false; + + victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 5.0f); + victimPed->SetFall(1500, AnimationId(ANIM_STD_HIGHIMPACT_FRONT + localDir), false); + victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir); } else { - if ( m_eWeaponType == WEAPONTYPE_SHOTGUN || m_eWeaponType == WEAPONTYPE_HELICANNON ) + if ( victimPed->IsPlayer() ) { - posOffset.Normalise(); - victimPed->bIsStanding = false; - - victimPed->ApplyMoveForce(posOffset.x*-5.0f, posOffset.y*-5.0f, 5.0f); - victimPed->SetFall(1500, AnimationId(ANIM_STD_HIGHIMPACT_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_STD_HITBYGUN_FRONT + 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 + CPlayerPed *victimPlayer = (CPlayerPed *)victimPed; + if ( victimPlayer->m_nHitAnimDelayTimer < CTimer::GetTimeInMilliseconds() && victimPed->m_nPedState != PED_DRIVING ) { victimPed->ClearAttackByRemovingAnim(); @@ -966,31 +1400,53 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, asoc->blendAmount = 0.0f; asoc->blendDelta = 8.0f; + + if ( m_eWeaponType == WEAPONTYPE_M4 ) + victimPlayer->m_nHitAnimDelayTimer = CTimer::GetTimeInMilliseconds() + 2500; + else + victimPlayer->m_nHitAnimDelayTimer = CTimer::GetTimeInMilliseconds() + 1000; } + } + else + { + victimPed->ClearAttackByRemovingAnim(); - victimPed->InflictDamage(shooter, m_eWeaponType, info->m_nDamage, (ePedPieceTypes)point->pieceB, localDir); + CAnimBlendAssociation *asoc = CAnimManager::AddAnimation(victimPed->GetClump(), ASSOCGRP_STD, AnimationId(ANIM_STD_HITBYGUN_FRONT + 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 ( 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; + if ( CGame::nastyGame ) + { + uint8 bloodAmount = 8; + if ( IsShotgun(m_eWeaponType) || m_eWeaponType == WEAPONTYPE_HELICANNON ) + bloodAmount = 32; - CVector dir = (point->point - victim->GetPosition()) * 0.01f; - dir.z = 0.01f; + 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); - } + if ( victimPed->GetIsOnScreen() ) + { + for ( uint8 i = 0; i < bloodAmount; i++ ) + CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point->point, dir); + } + + if (m_eWeaponType == WEAPONTYPE_MINIGUN) + { + CParticle::AddParticle(PARTICLE_TEST, point->point, CVector(0.f, 0.f, 0.f), nil, 0.f, 0, 0, 0, 0); + CParticle::AddParticle(PARTICLE_TEST, point->point + CVector(0.2f, -0.2f, 0.f), CVector(0.f, 0.f, 0.f), nil, 0.f, 0, 0, 0, 0); + CParticle::AddParticle(PARTICLE_TEST, point->point + CVector(-0.2f, 0.2f, 0.f), CVector(0.f, 0.f, 0.f), nil, 0.f, 0, 0, 0, 0); } } } @@ -1035,9 +1491,9 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f); #ifndef FIX_BUGS - 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; + CVector dist = point->point - (*source); + float distMagnitude = dist.Magnitude(); + CVector smokePos = point->point - Max(distMagnitude / 10.0f, 0.2f) * dist / distMagnitude; #else CVector smokePos = point->point; #endif // !FIX_BUGS @@ -1052,20 +1508,30 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, } case ENTITY_TYPE_VEHICLE: { - ((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage); + if (point->pieceB >= CAR_PIECE_WHEEL_LF && point->pieceB <= CAR_PIECE_WHEEL_RR) { + ((CVehicle*)victim)->BurstTyre(point->pieceB, true); - for ( int32 i = 0; i < 16; i++ ) - CParticle::AddParticle(PARTICLE_SPARK, point->point, point->normal*0.05f); + for (int32 i = 0; i < 4; i++) + CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, point->point, point->normal * 0.05f); + } + else + { + ((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); #ifndef FIX_BUGS - 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; + 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; #else - CVector smokePos = point->point; -#endif // !FIX_BUGS + CVector smokePos = point->point; +#endif + + CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f)); + } - CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f)); if ( shooter->IsPed() ) { @@ -1090,19 +1556,23 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, CObject *victimObject = (CObject *)victim; - if ( !victimObject->bInfiniteMass ) + if ( !victimObject->bInfiniteMass && victimObject->m_fCollisionDamageMultiplier < 99.9f) { - if ( victimObject->GetIsStatic() && victimObject->m_fUprootLimit <= 0.0f ) + bool notStatic = !victimObject->GetIsStatic(); + if (notStatic && victimObject->m_fUprootLimit <= 0.0f) { victimObject->SetIsStatic(false); victimObject->AddToMovingList(); } - if ( !victimObject->GetIsStatic()) + notStatic = !victimObject->GetIsStatic(); + if (!notStatic) { - CVector moveForce = point->normal*-4.0f; + CVector moveForce = point->normal * -4.0f; victimObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z); } + } else if (victimObject->m_nCollisionDamageEffect >= DAMAGE_EFFECT_SMASH_COMPLETELY) { + victimObject->ObjectDamage(50.f); } break; @@ -1120,17 +1590,20 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, } case ENTITY_TYPE_VEHICLE: { + CStats::BulletsThatHit++; DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f); break; } case ENTITY_TYPE_PED: { + CStats::BulletsThatHit++; DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f); ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT); break; } case ENTITY_TYPE_OBJECT: { + CStats::BulletsThatHit++; PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point->point); break; } @@ -1143,7 +1616,7 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, } } else - CBulletTraces::AddTrace(source, target); + CBulletTraces::AddTrace(source, target, m_eWeaponType, shooter); if ( shooter == FindPlayerPed() ) CPad::GetPad(0)->StartShake_Distance(240, 128, FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z); @@ -1151,6 +1624,7 @@ CWeapon::DoBulletImpact(CEntity *shooter, CEntity *victim, BlowUpExplosiveThings(victim); } + bool CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) { @@ -1196,10 +1670,35 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) else shooterAngle = RADTODEG(shooter->GetForward().Heading()); + int shootsAtOnce; + int checkObstacleOnShootNo; + float angleRange; + switch (m_eWeaponType) { + case WEAPONTYPE_SHOTGUN: + angleRange = DEGTORAD(9.0f); + checkObstacleOnShootNo = 1; + shootsAtOnce = 3; + break; + case WEAPONTYPE_SPAS12_SHOTGUN: + angleRange = DEGTORAD(6.0f); + checkObstacleOnShootNo = 1; + shootsAtOnce = 3; + break; + case WEAPONTYPE_STUBBY_SHOTGUN: + angleRange = DEGTORAD(18.0f); + checkObstacleOnShootNo = 2; + shootsAtOnce = 5; + break; + default: + break; + } + bool statUpdated = false; + float halfAngleRange = angleRange / 2.f; + float angleBetweenTwoShot = angleRange / (shootsAtOnce - 1.f); - for ( int32 i = 0; i < 5; i++ ) // five shoots at once + for ( int32 i = 0; i < shootsAtOnce; i++ ) { - float shootAngle = DEGTORAD(7.5f*i + shooterAngle - 15.0f); + float shootAngle = DEGTORAD(RADTODEG(halfAngleRange - angleBetweenTwoShot * i) + shooterAngle); CVector2D shootRot(-Sin(shootAngle), Cos(shootAngle)); shootRot.Normalise(); @@ -1212,12 +1711,16 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) 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); + float f = (i - (shootsAtOnce / 2)) * angleBetweenTwoShot; 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); + CWorld::bIncludeCarTyres = true; + CWorld::bIncludeBikers = true; + CWorld::bIncludeDeadPeds = true; + ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, false, false); + CWorld::bIncludeDeadPeds = false; + CWorld::bIncludeCarTyres = false; } else { @@ -1233,24 +1736,84 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) 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); + CVector pos; + if (shooterPed->m_pPointGunAt->IsPed()) { + ((CPed*)shooterPed->m_pPointGunAt)->m_pedIK.GetComponentPosition(pos, PED_MID); + } else { + pos = ((CPed*)shooterPed->m_pPointGunAt)->GetPosition(); + } + + float distToTarget = (pos - (*fireSource)).Magnitude2D(); + target.z += info->m_fRange / distToTarget * (pos.z - target.z); } } + if (shooter == FindPlayerPed()) + CWorld::bIncludeDeadPeds = true; - ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false); + CWorld::bIncludeBikers = true; + ProcessLineOfSight(*fireSource, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, false, false); + CWorld::bIncludeDeadPeds = false; } + CWorld::bIncludeBikers = false; if ( victim ) { CGlass::WasGlassHitByBullet(victim, point.point); + CWeapon::BlowUpExplosiveThings(victim); + if (i == checkObstacleOnShootNo) + { + if (shooter) + { + if (shooter->IsPed() && !((CPed*)shooter)->IsPlayer()) + { + CPed *shooterPed = (CPed*)shooter; + CEntity *guyWePointGun = shooterPed->m_pPointGunAt; + if (guyWePointGun) + { + if (victim != guyWePointGun) + { + float distWithAim = (guyWePointGun->GetPosition() - shooter->GetPosition()).Magnitude(); + float distWithBullet = (point.point - shooter->GetPosition()).Magnitude(); + if (distWithAim > 0.1f && distWithBullet > 0.1f) + { + // Normalize + CVector aimDir = (guyWePointGun->GetPosition() - shooter->GetPosition()) * (1.0f / distWithAim); + CVector bulletDir = (point.point - shooter->GetPosition()) * (1.0f / distWithBullet); + + float dotProd = DotProduct(aimDir, bulletDir); + float aimAndBulletAngle; + if (dotProd <= 0.35f) + aimAndBulletAngle = PI; + else + aimAndBulletAngle = Acos(dotProd); - CBulletTraces::AddTrace(fireSource, &point.point); + if (aimAndBulletAngle <= DEGTORAD(45.0f) && (aimAndBulletAngle <= DEGTORAD(15.0f) || distWithBullet / distWithAim >= 0.75f) && distWithBullet / distWithAim >= 0.99f) + { + shooterPed->bObstacleShowedUpDuringKillObjective = false; + shooterPed->m_shotTime = 0; + } + else + { + shooterPed->bObstacleShowedUpDuringKillObjective = true; + shooterPed->m_shootTimer = 0; + shooterPed->m_shotTime = CTimer::GetTimeInMilliseconds(); + if (distWithAim < 10.0f) + shooterPed->SetAttackTimer(1500); + else + shooterPed->SetAttackTimer(3000); + } + } + } + } + } + } + } + CBulletTraces::AddTrace(fireSource, &point.point, m_eWeaponType, shooter); if ( victim->IsPed() ) { CPed *victimPed = (CPed *)victim; - if ( !victimPed->OnGround() && victim != shooter && victimPed->DoesLOSBulletHitPed(point) ) + if ( !victimPed->DyingOrDead() && victim != shooter ) { bool cantStandup = true; @@ -1263,7 +1826,8 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) posOffset.Normalise(); - if ( victimPed->m_getUpTimer > (CTimer::GetTimeInMilliseconds() - 3000) ) + if ( victimPed->m_getUpTimer > (CTimer::GetTimeInMilliseconds() - 3000) || + !victimPed->bCanBeShotInVehicle) cantStandup = false; if ( victimPed->bIsStanding && cantStandup ) @@ -1288,7 +1852,7 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) if ( CGame::nastyGame ) { uint8 bloodAmount = 8; - if ( m_eWeaponType == WEAPONTYPE_SHOTGUN ) + if ( IsShotgun(m_eWeaponType) ) bloodAmount = 32; CVector dir = (point.point - victim->GetPosition()) * 0.01f; @@ -1300,6 +1864,36 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) 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 (victimPed->GetIsOnScreen()) + { + for (uint8 i = 0; i < 8; i++) + CParticle::AddParticle(PARTICLE_BLOOD_SMALL, point.point + CVector(0.0f, 0.0f, 0.15f), dir); + } + if (victimPed->Dead()) + { + CAnimBlendAssociation *hitAssoc; + if (RpAnimBlendClumpGetFirstAssociation(victimPed->GetClump(), ASSOC_FRONTAL)) + { + hitAssoc = CAnimManager::BlendAnimation(victimPed->GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR_FRONT, 8.0f); + } + else + { + hitAssoc = CAnimManager::BlendAnimation(victimPed->GetClump(), ASSOCGRP_STD, ANIM_STD_HIT_FLOOR, 8.0f); + } + if (hitAssoc) + { + hitAssoc->SetCurrentTime(0.0f); + hitAssoc->SetRun(); + hitAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + } + } + } } } else @@ -1308,21 +1902,29 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) { case ENTITY_TYPE_VEHICLE: { - ((CVehicle *)victim)->InflictDamage(shooter, m_eWeaponType, info->m_nDamage); + if (point.pieceB >= CAR_PIECE_WHEEL_LF && point.pieceB <= CAR_PIECE_WHEEL_RR) { + ((CVehicle*)victim)->BurstTyre(point.pieceB, true); - for ( int32 i = 0; i < 16; i++ ) - CParticle::AddParticle(PARTICLE_SPARK, point.point, point.normal*0.05f); + for (int32 i = 0; i < 4; i++) + CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, point.point, point.normal * 0.05f); + } + else + { + ((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); #ifndef FIX_BUGS - 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; + 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; #else - CVector smokePos = point.point; + CVector smokePos = point.point; #endif - CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f)); - + CParticle::AddParticle(PARTICLE_BULLETHIT_SMOKE, smokePos, CVector(0.0f, 0.0f, 0.0f)); + } break; } @@ -1352,13 +1954,15 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) if ( !victimObject->bInfiniteMass ) { - if ( victimObject->GetIsStatic() && victimObject->m_fUprootLimit <= 0.0f ) + bool notStatic = !victimObject->GetIsStatic(); + if ( notStatic && victimObject->m_fUprootLimit <= 0.0f ) { victimObject->SetIsStatic(false); victimObject->AddToMovingList(); } - if ( !victimObject->GetIsStatic()) + notStatic = !victimObject->GetIsStatic(); + if ( !notStatic ) { CVector moveForce = point.normal*-5.0f; victimObject->ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z); @@ -1381,17 +1985,29 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) } case ENTITY_TYPE_VEHICLE: { + if (!statUpdated) { + CStats::BulletsThatHit++; + statUpdated = true; + } DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f); break; } case ENTITY_TYPE_PED: { + if (!statUpdated) { + CStats::BulletsThatHit++; + statUpdated = true; + } DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f); ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT); break; } case ENTITY_TYPE_OBJECT: { + if (!statUpdated) { + CStats::BulletsThatHit++; + statUpdated = true; + } PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point); break; } @@ -1407,7 +2023,7 @@ CWeapon::FireShotgun(CEntity *shooter, CVector *fireSource) { CVector traceTarget = *fireSource; traceTarget += (target - (*fireSource)) * Min(info->m_fRange, 30.0f) / info->m_fRange; - CBulletTraces::AddTrace(fireSource, &traceTarget); + CBulletTraces::AddTrace(fireSource, &traceTarget, m_eWeaponType, shooter); } } @@ -1424,10 +2040,12 @@ CWeapon::FireProjectile(CEntity *shooter, CVector *fireSource, float power) ASSERT(fireSource!=nil); CVector source, target; + eWeaponType projectileType = m_eWeaponType; if ( m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER ) { source = *fireSource; + projectileType = WEAPONTYPE_ROCKET; if ( shooter->IsPed() && ((CPed*)shooter)->IsPlayer() ) { @@ -1469,7 +2087,7 @@ CWeapon::FireProjectile(CEntity *shooter, CVector *fireSource, float power) if ( !CWorld::GetIsLineOfSightClear(source, target, true, true, false, true, false, false, false) ) { if ( m_eWeaponType != WEAPONTYPE_GRENADE ) - CProjectileInfo::RemoveNotAdd(shooter, m_eWeaponType, *fireSource); + CProjectileInfo::RemoveNotAdd(shooter, projectileType, *fireSource); else { if ( shooter->IsPed() ) @@ -1478,14 +2096,22 @@ CWeapon::FireProjectile(CEntity *shooter, CVector *fireSource, float power) 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); + CProjectileInfo::AddProjectile(shooter, WEAPONTYPE_GRENADE, source, 0.0f); else - CProjectileInfo::RemoveNotAdd(shooter, m_eWeaponType, *fireSource); + CProjectileInfo::RemoveNotAdd(shooter, WEAPONTYPE_GRENADE, *fireSource); } } } else - CProjectileInfo::AddProjectile(shooter, m_eWeaponType, *fireSource, power); + CProjectileInfo::AddProjectile(shooter, projectileType, *fireSource, power); + + + CWorld::pIgnoreEntity = nil; + + if ( shooter->IsPed() ) + CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed *)shooter, 1000); + else if ( shooter->IsVehicle() && ((CVehicle*)shooter)->pDriver ) + CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_VEHICLE, shooter, ((CVehicle*)shooter)->pDriver, 1000); return true; } @@ -1538,26 +2164,85 @@ CWeapon::FireAreaEffect(CEntity *shooter, CVector *fireSource) CShotInfo::AddShot(shooter, m_eWeaponType, *fireSource, target); CWeapon::GenerateFlameThrowerParticles(*fireSource, dir); + + if ( shooter == (CEntity *)FindPlayerPed() ) + { + for ( int32 i = 0; i < FindPlayerPed()->m_numNearPeds; i++ ) + { + if ( FindPlayerPed()->m_nearPeds[i]->CharCreatedBy == RANDOM_CHAR ) + { + if ( FindPlayerPed()->m_nearPeds[i]->IsPedInControl() && FindPlayerPed()->m_nearPeds[i]->m_nPedState != PED_FLEE_ENTITY ) + FindPlayerPed()->m_nearPeds[i]->SetFlee(shooter, 10000); + } + } + } return true; } bool +CWeapon::LaserScopeDot(CVector *pOutPos, float *pOutSize) +{ + CWeaponInfo *info = GetInfo(); + + float range = info->m_fRange; + + CVector source, target; + CEntity *foundEnt = nil; + CColPoint foundCol; + + source = 0.5f * TheCamera.Cams[TheCamera.ActiveCam].Front + TheCamera.Cams[TheCamera.ActiveCam].Source; + target = TheCamera.Cams[TheCamera.ActiveCam].Front; + target.Normalise(); + target *= range; + target += source; + + if ( CWorld::ProcessLineOfSight(source, target, foundCol, foundEnt, true, true, true, true, false, false, false) ) + { + CVector pos = foundCol.point; + float w, h; + + if ( CSprite::CalcScreenCoors(foundCol.point, &pos, &w, &h, true) ) + { + *pOutPos = pos; + *pOutSize = w * 0.05f; + + CCoronas::RegisterCorona((uintptr)this + 7, 128, 0, 0, 255, pos, 1.2f, 50.0f, CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f); + + return true; + } + } + + return false; +} + +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) ) + + if ( (CEntity *)FindPlayerPed() == shooter ) { - return false; + int16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode; + if (!( mode == CCam::MODE_M16_1STPERSON + || mode == CCam::MODE_SNIPER + || mode == CCam::MODE_CAMERA + || mode == CCam::MODE_ROCKETLAUNCHER + || mode == CCam::MODE_M16_1STPERSON_RUNABOUT + || mode == CCam::MODE_SNIPER_RUNABOUT + || mode == CCam::MODE_ROCKETLAUNCHER_RUNABOUT) ) + { + return false; + } } +#ifdef SECUROM + if (sniperPirateCheck){ + // if not pirated game + // sniperPirateCheck = 0; + } +#endif + #ifndef FIX_BUGS CWeaponInfo *info = GetInfo(); //unused #endif @@ -1569,15 +2254,16 @@ CWeapon::FireSniper(CEntity *shooter) CVector dir = cam->Front; if ( DotProduct(dir, CVector(0.0f, -0.9894f, 0.145f)) > 0.997f ) - CCoronas::bSmallMoon = !CCoronas::bSmallMoon; + CCoronas::MoonSize = (CCoronas::MoonSize+1) & 7; dir.Normalise(); dir *= 16.0f; - CBulletInfo::AddBullet(shooter, m_eWeaponType, source, dir); +#ifdef SECUROM + if (sniperPirateCheck) return true; +#endif - if ( shooter == FindPlayerPed() ) - CStats::InstantHitsFiredByPlayer++; + CBulletInfo::AddBullet(shooter, m_eWeaponType, source, dir); if ( shooter == FindPlayerPed() ) { @@ -1585,14 +2271,75 @@ CWeapon::FireSniper(CEntity *shooter) FindPlayerPed()->GetPosition().x, FindPlayerPed()->GetPosition().y, FindPlayerPed()->GetPosition().z); + + CParticle::HandleShootableBirdsStuff(shooter, source); CamShakeNoPos(&TheCamera, 0.2f); } + if ( shooter->IsPed() ) + CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_PED, shooter, (CPed*)shooter, 1000); + else if ( shooter->IsVehicle() && ((CVehicle*)shooter)->pDriver ) + CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_VEHICLE, shooter, ((CVehicle*)shooter)->pDriver, 1000); + return true; } bool +CWeapon::TakePhotograph(CEntity *shooter) +{ + if ( TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_CAMERA ) + { + CSpecialFX::bSnapShotActive = true; + CSpecialFX::SnapShotFrames = 0; + CStats::PhotosTaken++; + bPhotographHasBeenTaken = true; + + for ( int32 i = CPools::GetPedPool()->GetSize() - 1; i >= 0; i--) + { + CPed *ped = CPools::GetPedPool()->GetSlot(i); + if ( ped ) + { + if ( (ped->GetPosition() - TheCamera.GetPosition()).Magnitude() < 125.0f ) + { + CVector pedPos = ped->GetPosition(); + pedPos.z += 0.8f; + + CVector pos; + float w, h; + + if ( CSprite::CalcScreenCoors(pedPos, &pos, &w, &h, false) ) + { + if ( SCREEN_WIDTH * 0.1f < pos.x && SCREEN_WIDTH * 0.9f > pos.x + && SCREEN_HEIGHT * 0.1f < pos.y && SCREEN_HEIGHT * 0.9f > pos.y ) + { + CVector source, target; + CEntity *foundEnt = nil; + CColPoint foundCol; + + target = pedPos; + source = TheCamera.GetForward() * 2.0f + TheCamera.GetPosition(); + + if ( CWorld::ProcessLineOfSight(source, target, foundCol, foundEnt, true, true, true, true, true, true, false) ) + { + if ( foundEnt != (CEntity*)ped ) + continue; + } + + ped->bHasBeenPhotographed = true; + } + } + } + } + } + + return true; + } + + return false; +} + +bool CWeapon::FireM16_1stPerson(CEntity *shooter) { ASSERT(shooter!=nil); @@ -1601,6 +2348,7 @@ CWeapon::FireM16_1stPerson(CEntity *shooter) if (!( mode == CCam::MODE_M16_1STPERSON || mode == CCam::MODE_SNIPER + || mode == CCam::MODE_CAMERA || mode == CCam::MODE_ROCKETLAUNCHER || mode == CCam::MODE_M16_1STPERSON_RUNABOUT || mode == CCam::MODE_SNIPER_RUNABOUT @@ -1612,10 +2360,12 @@ CWeapon::FireM16_1stPerson(CEntity *shooter) CWeaponInfo *info = GetInfo(); + CWorld::bIncludeCarTyres = true; + CWorld::bIncludeBikers = true; + CColPoint point; CEntity *victim; - CWorld::bIncludeCarTyres = true; CWorld::pIgnoreEntity = shooter; CWorld::bIncludeDeadPeds = true; @@ -1625,9 +2375,12 @@ CWeapon::FireM16_1stPerson(CEntity *shooter) 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; + if (ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false)) { + CheckForShootingVehicleOccupant(&victim, &point, m_eWeaponType, source, target); + } CWorld::pIgnoreEntity = nil; + CWorld::bIncludeDeadPeds = false; + CWorld::bIncludeBikers = false; CWorld::bIncludeCarTyres = false; CVector2D front(cam->Front.x, cam->Front.y); @@ -1636,7 +2389,8 @@ CWeapon::FireM16_1stPerson(CEntity *shooter) DoBulletImpact(shooter, victim, &source, &target, &point, front); CVector bulletPos; - if ( CHeli::TestBulletCollision(&source, &target, &bulletPos, 4) ) + + if ( CHeli::TestBulletCollision(&source, &target, &bulletPos, (m_eWeaponType == WEAPONTYPE_M60 || m_eWeaponType == WEAPONTYPE_HELICANNON ? 20 : 4)) ) { for ( int32 i = 0; i < 16; i++ ) CParticle::AddParticle(PARTICLE_SPARK, bulletPos, CVector(0.0f, 0.0f, 0.0f)); @@ -1644,77 +2398,137 @@ CWeapon::FireM16_1stPerson(CEntity *shooter) if ( shooter == FindPlayerPed() ) { -#ifdef FIX_BUGS - CStats::InstantHitsFiredByPlayer++; -#endif - 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; + float mult; + switch (m_eWeaponType) { + case WEAPONTYPE_M4: + mult = 0.0003f; + break; + case WEAPONTYPE_RUGER: + mult = 0.00015f; + break; + case WEAPONTYPE_HELICANNON: + case WEAPONTYPE_M60: + mult = 0.0003f; + break; + default: + mult = 0.0002f; + break; } + + if (FindPlayerPed()->bIsDucking || FindPlayerPed()->m_attachedTo) + mult *= 0.3f; + + TheCamera.Cams[TheCamera.ActiveCam].Beta += float((CGeneral::GetRandomNumber() & 127) - 64) * mult; + TheCamera.Cams[TheCamera.ActiveCam].Alpha += float((CGeneral::GetRandomNumber() & 127) - 64) * mult; + + // yes, double + double notFiringRate = (20.0 - info->m_nFiringRate) / 80.0; + double raisedNotFiringRate = Max(1.0, Max(0.0, notFiringRate)); + + uint8 shakeFreq = 80.0 * raisedNotFiringRate + 130.0; + CPad::GetPad(0)->StartShake(20000.0f * CTimer::GetTimeStep() / shakeFreq, shakeFreq); } return true; } bool -CWeapon::FireInstantHitFromCar(CAutomobile *shooter, bool left) +CWeapon::FireInstantHitFromCar(CVehicle *shooter, bool left, bool right) { CWeaponInfo *info = GetInfo(); CVehicleModelInfo *modelInfo = shooter->GetModelInfo(); - + CVector source, target; - if ( left ) + + if ( shooter->IsBike() ) { - source = shooter->GetMatrix() * CVector(-shooter->GetColModel()->boundingBox.max.x + -0.2f, - float(CGeneral::GetRandomNumber() & 255) * 0.001f + modelInfo->GetFrontSeatPosn().y, - modelInfo->GetFrontSeatPosn().z + 0.5f); - source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed; - - - target = shooter->GetMatrix() * CVector(-info->m_fRange, - modelInfo->GetFrontSeatPosn().y, + if ( shooter->pDriver ) + { + source = info->m_vecFireOffset; + + shooter->pDriver->TransformToNode(source, PED_HANDR); + source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed; + + if ( left ) + target = source - info->m_fRange * shooter->GetRight(); + else if ( right ) + target = source + info->m_fRange * shooter->GetRight(); + else + target = source + info->m_fRange * shooter->GetForward(); + + } + else if ( left ) + { + source = shooter->GetMatrix() * CVector(-shooter->GetColModel()->boundingBox.max.x + -0.25f, + float(CGeneral::GetRandomNumber() & 255) * 0.001f + modelInfo->GetFrontSeatPosn().y - 0.05f, + modelInfo->GetFrontSeatPosn().z + 0.63f); + source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed; + + + target = shooter->GetMatrix() * CVector(-info->m_fRange, + modelInfo->GetFrontSeatPosn().y, + modelInfo->GetFrontSeatPosn().z + 0.6f); + } + else if ( right ) + { + source = shooter->GetMatrix() * CVector(shooter->GetColModel()->boundingBox.max.x + 0.25f, + float(CGeneral::GetRandomNumber() & 255) * 0.001f + modelInfo->GetFrontSeatPosn().y - 0.18f, + modelInfo->GetFrontSeatPosn().z + 0.52f); + source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed; + + target = shooter->GetMatrix() * CVector(info->m_fRange, + modelInfo->GetFrontSeatPosn().y, + modelInfo->GetFrontSeatPosn().z + 0.5f); + } + else + { + source = shooter->GetMatrix() * CVector(float(CGeneral::GetRandomNumber() & 255) * 0.001f + -0.4f, + modelInfo->GetFrontSeatPosn().y + shooter->GetColModel()->boundingBox.max.y + 0.2f, + modelInfo->GetFrontSeatPosn().z + 0.55f); + source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed; + + target = shooter->GetMatrix() * CVector(0.0f, + info->m_fRange, modelInfo->GetFrontSeatPosn().z + 0.5f); + } } else { - source = shooter->GetMatrix() * CVector(shooter->GetColModel()->boundingBox.max.x + 0.2f, - float(CGeneral::GetRandomNumber() & 255) * 0.001f + modelInfo->GetFrontSeatPosn().y, - modelInfo->GetFrontSeatPosn().z + 0.5f); + if ( left ) + source = info->m_vecFireOffset; + else + { + source = 1.8f * info->m_vecFireOffset; + source.z -= 0.1f; + } + + shooter->pDriver->TransformToNode(source, PED_HANDR); source += CTimer::GetTimeStep() * shooter->m_vecMoveSpeed; - - target = shooter->GetMatrix() * CVector(info->m_fRange, - modelInfo->GetFrontSeatPosn().y, - modelInfo->GetFrontSeatPosn().z + 0.5f); - } - #undef FRONTSEATPOS - - if ( TheCamera.GetLookingLRBFirstPerson() && !left ) - { - source -= 0.3f * shooter->GetForward(); - target -= 0.3f * shooter->GetForward(); + + if ( left ) + target = source - info->m_fRange * shooter->GetRight(); + else + target = source + info->m_fRange * shooter->GetRight(); } 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); + DoDriveByAutoAiming(FindPlayerPed(), shooter, &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)); + { + if ( !shooter->IsBike() ) + CParticle::AddParticle(PARTICLE_GUNFLASH, source, CVector(0.0f, 0.0f, 0.0f)); + else + CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, source, 1.4f*shooter->m_vecMoveSpeed); + } else - CamShakeNoPos(&TheCamera, 0.01f); + CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, source, 1.6f*shooter->m_vecMoveSpeed, nil, 0.18f); CEventList::RegisterEvent(EVENT_GUNSHOT, EVENT_ENTITY_VEHICLE, shooter, FindPlayerPed(), 1000); @@ -1723,7 +2537,12 @@ CWeapon::FireInstantHitFromCar(CAutomobile *shooter, bool left) CColPoint point; CEntity *victim; + + CWorld::bIncludeBikers = true; + CWorld::pIgnoreEntity = shooter; ProcessLineOfSight(source, target, point, victim, m_eWeaponType, shooter, true, true, true, true, true, true, false); + CWorld::pIgnoreEntity = NULL; + CWorld::bIncludeBikers = false; if ( !(CTimer::GetFrameCounter() & 3) ) MakePedsJumpAtShot(shooter, &source, &target); @@ -1731,7 +2550,7 @@ CWeapon::FireInstantHitFromCar(CAutomobile *shooter, bool left) if ( victim ) { CVector traceTarget = point.point; - CBulletTraces::AddTrace(&source, &traceTarget); + CBulletTraces::AddTrace(&source, &traceTarget, m_eWeaponType, shooter); if ( victim->IsPed() ) { @@ -1818,7 +2637,7 @@ CWeapon::FireInstantHitFromCar(CAutomobile *shooter, bool left) { float norm = 30.0f/info->m_fRange; CVector traceTarget = (target-source)*norm + source; - CBulletTraces::AddTrace(&source, &traceTarget); + CBulletTraces::AddTrace(&source, &traceTarget, m_eWeaponType, shooter); } if ( shooter == FindPlayerVehicle() ) @@ -1839,8 +2658,6 @@ CWeapon::DoDoomAiming(CEntity *shooter, CVector *source, CVector *target) #endif CPed *shooterPed = (CPed*)shooter; - if ( shooterPed->IsPed() && shooterPed->bCrouchWhenShooting ) - return; int16 lastEntity; CEntity *entities[16]; @@ -1859,7 +2676,8 @@ CWeapon::DoDoomAiming(CEntity *shooter, CVector *source, CVector *target) if ( !(victim->GetStatus() == STATUS_TRAIN_MOVING || victim->GetStatus() == STATUS_TRAIN_NOT_MOVING || victim->GetStatus() == STATUS_HELI - || victim->GetStatus() == STATUS_PLANE) ) + || victim->GetStatus() == STATUS_PLANE + || victim->GetStatus() == STATUS_WRECKED) ) { float distToVictim = (shooterPed->GetPosition()-victim->GetPosition()).Magnitude2D(); float distToVictimZ = Abs(shooterPed->GetPosition().z-victim->GetPosition().z); @@ -1878,7 +2696,10 @@ CWeapon::DoDoomAiming(CEntity *shooter, CVector *source, CVector *target) } } - if ( closestEntityDist < DOOMAUTOAIMING_MAXDIST ) + CColPoint foundCol; + CEntity *foundEnt; + if (closestEntityDist < DOOMAUTOAIMING_MAXDIST + && !CWorld::ProcessLineOfSight(*source, entities[closestEntity]->GetPosition(), foundCol, foundEnt, true, false, false, false, false, false, false, true)) { CEntity *victim = entities[closestEntity]; ASSERT(victim !=nil); @@ -1967,10 +2788,11 @@ CWeapon::DoTankDoomAiming(CEntity *shooter, CEntity *driver, CVector *source, CV } } + void -CWeapon::DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target) +CWeapon::DoDriveByAutoAiming(CEntity *driver, CVehicle *vehicle, CVector *source, CVector *target) { - ASSERT(shooter!=nil); + ASSERT(driver!=nil); ASSERT(source!=nil); ASSERT(target!=nil); @@ -1978,27 +2800,36 @@ CWeapon::DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target) CEntity entity; // unused #endif - CPed *shooterPed = (CPed*)shooter; - if ( shooterPed->IsPed() && shooterPed->bCrouchWhenShooting ) - return; + CPed *shooterPed = (CPed*)driver; int16 lastEntity; - CEntity *entities[16]; - CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, entities, false, false, true, false, false); + CEntity *peds[16]; + CWorld::FindObjectsInRange(*source, (*target-*source).Magnitude(), true, &lastEntity, 15, peds, false, false, true, false, false); float closestEntityDist = 10000.0f; int16 closestEntity; for ( int32 i = 0; i < lastEntity; i++ ) { - CEntity *victim = entities[i]; + CPed *victim = (CPed*)peds[i]; ASSERT(victim!=nil); - if ( shooter != victim ) + if (driver != victim && !victim->DyingOrDead() && victim->m_attachedTo != vehicle) { float lineDist = CCollision::DistToLine(source, target, &victim->GetPosition()); - float distToVictim = (victim->GetPosition() - shooter->GetPosition()).Magnitude(); - float pedDist = 0.15f*distToVictim + lineDist; + + uint32 model = vehicle->GetModelIndex(); + float pedDist; + if (model == MI_HUNTER || model == MI_SEASPAR || model == MI_SPARROW) + { + float distToVictim = (victim->GetPosition() - vehicle->GetPosition()).Magnitude(); + pedDist = lineDist / Max(5.f, distToVictim); + } + else + { + float distToVictim = (victim->GetPosition() - driver->GetPosition()).Magnitude(); + pedDist = 0.15f * distToVictim + lineDist; + } if ( DotProduct((*target-*source), victim->GetPosition()-*source) > 0.0f && pedDist < closestEntityDist) { @@ -2007,14 +2838,24 @@ CWeapon::DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target) } } } + uint32 model = vehicle->GetModelIndex(); + float maxAimDistance = CAR_DRIVEBYAUTOAIMING_MAXDIST; + if (model == MI_HUNTER) + { + maxAimDistance = Tan(DEGTORAD(fHunterAimingAngle)); + } + else if (model == MI_SEASPAR || model == MI_SPARROW) + { + maxAimDistance = Tan(DEGTORAD(fSeaSparrowAimingAngle)); + } - if ( closestEntityDist < DRIVEBYAUTOAIMING_MAXDIST ) + if ( closestEntityDist < maxAimDistance ) { - CEntity *victim = entities[closestEntity]; + CEntity *victim = peds[closestEntity]; ASSERT(victim!=nil); float distToTarget = (*source - *target).Magnitude(); - float distToSource = (*source - victim->GetPosition()).Magnitude(); + float distToSource = (*source - victim->GetPosition()).Magnitude(); *target = (distToTarget / distToSource) * (victim->GetPosition() - *source) + *source; } } @@ -2034,8 +2875,10 @@ CWeapon::Reload(void) } void -CWeapon::Update(int32 audioEntity) +CWeapon::Update(int32 audioEntity, CPed *pedToAdjustSound) { + CWeaponInfo *info = GetInfo(); + switch ( m_eWeaponState ) { case WEAPONSTATE_MELEE_MADECONTACT: @@ -2046,18 +2889,19 @@ CWeapon::Update(int32 audioEntity) case WEAPONSTATE_FIRING: { - if ( m_eWeaponType == WEAPONTYPE_SHOTGUN && AEHANDLE_IS_OK(audioEntity) ) + if ( IsShotgun(m_eWeaponType) && AEHANDLE_IS_OK(audioEntity) ) { - uint32 timePassed = m_nTimer - gReloadSampleTime[WEAPONTYPE_SHOTGUN]; + uint32 timePassed = m_nTimer - CWeaponInfo::ms_aReloadSampleTime[m_eWeaponType]; 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 ) + if ( GetInfo()->m_eWeaponFire != WEAPON_FIRE_MELEE && m_nAmmoTotal == 0 ) { m_eWeaponState = WEAPONSTATE_OUT_OF_AMMO; - else + CPickups::RemoveAllPickupsOfACertainWeaponGroupWithNoAmmo(m_eWeaponType); + } else m_eWeaponState = WEAPONSTATE_READY; } @@ -2066,11 +2910,49 @@ CWeapon::Update(int32 audioEntity) case WEAPONSTATE_RELOADING: { - if ( AEHANDLE_IS_OK(audioEntity) && m_eWeaponType < WEAPONTYPE_LAST_WEAPONTYPE ) + if ( AEHANDLE_IS_OK(audioEntity) && m_eWeaponType < WEAPONTYPE_TOTALWEAPONS) { - uint32 timePassed = m_nTimer - gReloadSampleTime[m_eWeaponType]; - if ( CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed ) - DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f); + CAnimBlendAssociation *reloadAssoc = nil; + if (pedToAdjustSound) { + if (CPed::GetReloadAnim(info) && (!CWorld::Players[CWorld::PlayerInFocus].m_bFastReload || !pedToAdjustSound->IsPlayer())) { + reloadAssoc = RpAnimBlendClumpGetAssociation(pedToAdjustSound->GetClump(), CPed::GetReloadAnim(info)); + if (!reloadAssoc) { + reloadAssoc = RpAnimBlendClumpGetAssociation(pedToAdjustSound->GetClump(), CPed::GetCrouchReloadAnim(info)); + } + } + } + if (reloadAssoc && reloadAssoc->IsRunning() && reloadAssoc->blendAmount > 0.2f) { + float soundStart = 0.75f; + switch (info->m_AnimToPlay) { + case ASSOCGRP_PYTHON: + soundStart = fReloadAnimSampleFraction[0]; + break; + case ASSOCGRP_COLT: + case ASSOCGRP_TEC: + soundStart = fReloadAnimSampleFraction[1]; + break; + case ASSOCGRP_UZI: + soundStart = fReloadAnimSampleFraction[2]; + break; + case ASSOCGRP_RIFLE: + soundStart = fReloadAnimSampleFraction[3]; + break; + case ASSOCGRP_M60: + soundStart = fReloadAnimSampleFraction[4]; + break; + default: + break; + } + if (reloadAssoc->GetProgress() >= soundStart && (reloadAssoc->currentTime - reloadAssoc->timeStep) / reloadAssoc->hierarchy->totalLength < soundStart) + DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, m_eWeaponType); + if (CTimer::GetTimeInMilliseconds() > m_nTimer && reloadAssoc->GetProgress() < 0.9f) { + m_nTimer = CTimer::GetTimeInMilliseconds(); + } + } else { + uint32 timePassed = m_nTimer - CWeaponInfo::ms_aReloadSampleTime[m_eWeaponType]; + if (CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed) + DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, m_eWeaponType); + } } if ( CTimer::GetTimeInMilliseconds() > m_nTimer ) @@ -2157,17 +3039,20 @@ FireOneInstantHitRound(CVector *source, CVector *target, int32 damage) } case ENTITY_TYPE_VEHICLE: { + CStats::BulletsThatHit++; DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_VEHICLE, 1.0f); break; } case ENTITY_TYPE_PED: { + CStats::BulletsThatHit++; DMAudio.PlayOneShot(((CPhysical*)victim)->m_audioEntityId, SOUND_WEAPON_HIT_PED, 1.0f); ((CPed*)victim)->Say(SOUND_PED_BULLET_HIT); break; } case ENTITY_TYPE_OBJECT: { + CStats::BulletsThatHit++; PlayOneShotScriptObject(SCRIPT_SOUND_BULLET_HIT_GROUND_2, point.point); break; } @@ -2193,13 +3078,15 @@ FireOneInstantHitRound(CVector *source, CVector *target, int32 damage) bool CWeapon::IsTypeMelee(void) { - return m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT; + return CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_eWeaponFire == WEAPON_FIRE_MELEE; } bool CWeapon::IsType2Handed(void) { - return m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType <= WEAPONTYPE_FLAMETHROWER && m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER; + return m_eWeaponType == WEAPONTYPE_FLAMETHROWER || m_eWeaponType == WEAPONTYPE_HELICANNON || m_eWeaponType == WEAPONTYPE_M60 || + m_eWeaponType == WEAPONTYPE_M4 || IsShotgun(m_eWeaponType) || + m_eWeaponType == WEAPONTYPE_RUGER || m_eWeaponType == WEAPONTYPE_SNIPERRIFLE || m_eWeaponType == WEAPONTYPE_LASERSCOPE; } void @@ -2284,14 +3171,14 @@ CWeapon::BlowUpExplosiveThings(CEntity *thing) { CObject *object = (CObject*)thing; int32 mi = object->GetModelIndex(); - if ( IsExplosiveThingModel(mi) && !object->bHasBeenDamaged ) + if ( IsExplosiveThingModel(mi) && !object->bHasBeenDamaged && object->IsObject() ) { 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; + object->m_vecMoveSpeed.z += 0.55f; else object->m_vecMoveSpeed.z += 0.45f; @@ -2310,19 +3197,25 @@ CWeapon::BlowUpExplosiveThings(CEntity *thing) bool CWeapon::HasWeaponAmmoToBeUsed(void) { - switch (m_eWeaponType) { - case WEAPONTYPE_UNARMED: - case WEAPONTYPE_BASEBALLBAT: - return true; - default: - return m_nAmmoTotal != 0; - } + // FIX: This is better (not bug tho) +//#if 0 + if (m_eWeaponType <= WEAPONTYPE_CHAINSAW) +//#else +// if (CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_eWeaponFire == WEAPON_FIRE_MELEE) +//#endif + return true; + else + return m_nAmmoTotal != 0; } bool CPed::IsPedDoingDriveByShooting(void) { +#ifdef FIX_BUGS + if (FindPlayerPed() == this && CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nWeaponSlot == WEAPONSLOT_SUBMACHINEGUN) { +#else if (FindPlayerPed() == this && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { +#endif if (TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight) return true; } @@ -2332,7 +3225,82 @@ CPed::IsPedDoingDriveByShooting(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); + return CWorld::ProcessLineOfSight(point1, point2, point, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, false, ignoreSomeObjects, true); +} + + +void +CWeapon::CheckForShootingVehicleOccupant(CEntity **victim, CColPoint *point, eWeaponType weapon, CVector const& source, CVector const& target) +{ + if (!(*victim)->IsVehicle()) + return; + + CColSphere headSphere; + + CVehicle *veh = (CVehicle*)*victim; + CColPoint origPoint(*point); + float radius = 1.0f; + bool found = false; + CColLine shootLine(source, target); + + if (veh->pDriver && veh->pDriver->bCanBeShotInVehicle) { + CVector pos(0.f, 0.f, 0.f); + veh->pDriver->TransformToNode(pos, PED_HEAD); + headSphere.Set(0.2f, pos + CVector(0.f, 0.f, 0.1f), 0, PEDPIECE_HEAD); + if (CCollision::ProcessLineSphere(shootLine, headSphere, *point, radius)) { + *victim = veh->pDriver; + found = true; + } + } + + for(int i = 0; i < ARRAY_SIZE(veh->pPassengers); i++) { + CPed *passenger = veh->pPassengers[i]; + if (passenger && passenger->bCanBeShotInVehicle) { + CVector pos(0.f, 0.f, 0.f); + passenger->TransformToNode(pos, PED_HEAD); + headSphere.Set(0.2f, pos + CVector(0.f, 0.f, 0.1f), 0, PEDPIECE_HEAD); + if (CCollision::ProcessLineSphere(shootLine, headSphere, *point, radius)) { + *victim = passenger; + found = true; + } + } + } + if (veh->IsCar()) { + CVector distVec = target - source; + if (DotProduct(distVec, veh->GetForward()) < 0.0f && DotProduct(distVec, veh->GetUp()) <= 0.0f) { + CColModel *colModel = veh->GetColModel(); + if (colModel->numTriangles > 0) { + bool passesGlass = false; + CMatrix invVehMat; + Invert(veh->GetMatrix(), invVehMat); + shootLine.p0 = invVehMat * shootLine.p0; + shootLine.p1 = invVehMat * shootLine.p1; + CCollision::CalculateTrianglePlanes(colModel); + for (int i = 0; i < colModel->numTriangles; i++) { + if (colModel->triangles[i].surface == SURFACE_GLASS && + CCollision::TestLineTriangle(shootLine, colModel->vertices, colModel->triangles[i], colModel->trianglePlanes[i])) { + passesGlass = true; + break; + } + } + CAutomobile *car = (CAutomobile*)veh; + + // No need to damage windscreen if there isn't one. + if (passesGlass && car->Damage.ProgressPanelDamage(VEHPANEL_WINDSCREEN)) { + if (car->Damage.GetPanelStatus(VEHPANEL_WINDSCREEN) == PANEL_STATUS_SMASHED2) + car->Damage.ProgressPanelDamage(VEHPANEL_WINDSCREEN); + + car->SetPanelDamage(CAR_WINDSCREEN, VEHPANEL_WINDSCREEN, true); + DMAudio.PlayOneShot(veh->m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.f); + } + } + } + } + + if (!found) { + *victim = veh; + *point = origPoint; + } } #ifdef COMPATIBLE_SAVES diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index c7685e0d..f720b312 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -2,12 +2,13 @@ #include "WeaponType.h" -#define DRIVEBYAUTOAIMING_MAXDIST (2.5f) +#define CAR_DRIVEBYAUTOAIMING_MAXDIST (2.5f) #define DOOMAUTOAIMING_MAXDIST (9000.0f) class CEntity; class CPhysical; -class CAutomobile; +class CVehicle; +class CPed; struct CColPoint; class CWeaponInfo; @@ -20,10 +21,13 @@ public: int32 m_nAmmoTotal; uint32 m_nTimer; bool m_bAddRotOffset; - + + static bool bPhotographHasBeenTaken; + CWeapon() { m_bAddRotOffset = false; } + CWeapon(eWeaponType type, int32 ammo); CWeaponInfo *GetInfo(); @@ -32,12 +36,14 @@ public: static void UpdateWeapons (void); void Initialise(eWeaponType type, int32 ammo); + void Shutdown(); bool Fire (CEntity *shooter, CVector *fireSource); - bool FireFromCar (CAutomobile *shooter, bool left); + bool FireFromCar (CVehicle *shooter, bool left, bool right); bool FireMelee (CEntity *shooter, CVector &fireSource); bool FireInstantHit(CEntity *shooter, CVector *fireSource); + static void AddGunFlashBigGuns(CVector start, CVector end); 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); @@ -47,16 +53,18 @@ public: static void GenerateFlameThrowerParticles(CVector pos, CVector dir); bool FireAreaEffect (CEntity *shooter, CVector *fireSource); + bool LaserScopeDot (CVector *pOutPos, float *pOutSize); bool FireSniper (CEntity *shooter); + bool TakePhotograph (CEntity *shooter); bool FireM16_1stPerson (CEntity *shooter); - bool FireInstantHitFromCar(CAutomobile *shooter, bool left); + bool FireInstantHitFromCar(CVehicle *shooter, bool left, bool right); - 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); + static void DoDoomAiming (CEntity *shooter, CVector *source, CVector *target); + static void DoTankDoomAiming (CEntity *shooter, CEntity *driver, CVector *source, CVector *target); + static void DoDriveByAutoAiming(CEntity *driver, CVehicle *vehicle, CVector *source, CVector *target); void Reload(void); - void Update(int32 audioEntity); + void Update(int32 audioEntity, CPed *pedToAdjustSound); bool IsTypeMelee (void); bool IsType2Handed(void); @@ -66,8 +74,12 @@ public: static void BlowUpExplosiveThings(CEntity *thing); bool HasWeaponAmmoToBeUsed(void); + static bool IsShotgun(int weapon) { return weapon == WEAPONTYPE_SHOTGUN || weapon == WEAPONTYPE_SPAS12_SHOTGUN || weapon == WEAPONTYPE_STUBBY_SHOTGUN; } + 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 void CheckForShootingVehicleOccupant(CEntity **victim, CColPoint *point, eWeaponType weapon, CVector const& source, CVector const& target); + #ifdef COMPATIBLE_SAVES void Save(uint8*& buf); void Load(uint8*& buf); diff --git a/src/weapons/WeaponEffects.cpp b/src/weapons/WeaponEffects.cpp index 32e55fb1..bb95ea85 100644 --- a/src/weapons/WeaponEffects.cpp +++ b/src/weapons/WeaponEffects.cpp @@ -4,9 +4,11 @@ #include "WeaponEffects.h" #include "TxdStore.h" #include "Sprite.h" +#include "PlayerPed.h" +#include "World.h" +#include "WeaponType.h" RwTexture *gpCrossHairTex; -RwRaster *gpCrossHairRaster; CWeaponEffects gCrossHair; @@ -25,10 +27,10 @@ CWeaponEffects::Init(void) { gCrossHair.m_bActive = false; gCrossHair.m_vecPos = CVector(0.0f, 0.0f, 0.0f); - gCrossHair.m_nRed = 0; + gCrossHair.m_nRed = 255; gCrossHair.m_nGreen = 0; gCrossHair.m_nBlue = 0; - gCrossHair.m_nAlpha = 255; + gCrossHair.m_nAlpha = 127; gCrossHair.m_fSize = 1.0f; gCrossHair.m_fRotation = 0.0f; @@ -37,8 +39,7 @@ CWeaponEffects::Init(void) int32 slot = CTxdStore::FindTxdSlot("particle"); CTxdStore::SetCurrentTxd(slot); - gpCrossHairTex = RwTextureRead("crosshair", nil); - gpCrossHairRaster = RwTextureGetRaster(gpCrossHairTex); + gpCrossHairTex = RwTextureRead("target256", "target256m"); CTxdStore::PopCurrentTxd(); } @@ -47,9 +48,7 @@ void CWeaponEffects::Shutdown(void) { RwTextureDestroy(gpCrossHairTex); -#if GTA_VERSION >= GTA3_PC_11 gpCrossHairTex = nil; -#endif } void @@ -57,10 +56,6 @@ CWeaponEffects::MarkTarget(CVector pos, uint8 red, uint8 green, uint8 blue, uint { 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; } @@ -73,13 +68,37 @@ CWeaponEffects::ClearCrossHair(void) void CWeaponEffects::Render(void) { + static float aCrossHairSize[WEAPONTYPE_TOTALWEAPONS] = + { + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 0.4f, 0.4f, + 0.5f, + 0.3f, + 0.9f, 0.9f, 0.9f, + 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, + 0.1f, 0.1f, + 1.0f, + 0.6f, + 0.7f, + 0.0f, 0.0f + }; + + + if ( gCrossHair.m_bActive ) { + float size = aCrossHairSize[FindPlayerPed()->GetWeapon()->m_eWeaponType]; + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)FALSE); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpCrossHairRaster); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); +#ifdef FIX_BUGS + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); +#else + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVDESTALPHA); +#endif + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpCrossHairTex)); RwV3d pos; float w, h; @@ -88,17 +107,27 @@ CWeaponEffects::Render(void) PUSH_RENDERGROUP("CWeaponEffects::Render"); 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); + CSprite::RenderOneXLUSprite_Rotate_Aspect(pos.x, pos.y, pos.z, + w, h, + 255, 88, 100, 158, + recipz, gCrossHair.m_fRotation, gCrossHair.m_nAlpha); + + float recipz2 = 1.0f / pos.z; + + CSprite::RenderOneXLUSprite_Rotate_Aspect(pos.x, pos.y, pos.z, + size*w, size*h, + 107, 134, 247, 158, + recipz2, TWOPI - gCrossHair.m_fRotation, gCrossHair.m_nAlpha); + + gCrossHair.m_fRotation += 0.02f; + if ( gCrossHair.m_fRotation > TWOPI ) + gCrossHair.m_fRotation = 0.0; POP_RENDERGROUP(); } - + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)TRUE); } }
\ No newline at end of file diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp index ba872454..1f78b7d4 100644 --- a/src/weapons/WeaponInfo.cpp +++ b/src/weapons/WeaponInfo.cpp @@ -6,28 +6,102 @@ #include "AnimManager.h" #include "AnimBlendAssociation.h" #include "Weapon.h" +#include "ModelInfo.h" +#include "ModelIndices.h" -static CWeaponInfo aWeaponInfo[WEAPONTYPE_TOTALWEAPONS]; +uint16 CWeaponInfo::ms_aReloadSampleTime[WEAPONTYPE_TOTALWEAPONS] = +{ + 0, // UNARMED + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // GRENADE + 0, // DETONATEGRENADE + 0, // TEARGAS + 0, // MOLOTOV + 0, // ROCKET + 250, // COLT45 + 250, // PYTHON + 650, // SHOTGUN + 650, // SPAS12 SHOTGUN + 650, // STUBBY SHOTGUN + 400, // TEC9 + 400, // UZIhec + 400, // SILENCED_INGRAM + 400, // MP5 + 300, // M16 + 300, // AK47 + 423, // SNIPERRIFLE + 423, // LASERSCOPE + 400, // ROCKETLAUNCHER + 0, // FLAMETHROWER + 0, // M60 + 0, // MINIGUN + 0, // DETONATOR + 0, // HELICANNON + 0 // CAMERA +}; + +// Yeah... +int32 CWeaponInfo::ms_aMaxAmmoForWeapon[WEAPONTYPE_TOTALWEAPONS] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; -static char ms_aWeaponNames[][32] = { +CWeaponInfo aWeaponInfo[WEAPONTYPE_TOTALWEAPONS]; +char CWeaponInfo::ms_aWeaponNames[WEAPONTYPE_TOTALWEAPONS][32] = +{ "Unarmed", + "BrassKnuckle", + "ScrewDriver", + "GolfClub", + "NightStick", + "Knife", "BaseballBat", + "Hammer", + "Cleaver", + "Machete", + "Katana", + "Chainsaw", + "Grenade", + "DetonateGrenade", + "TearGas", + "Molotov", + "Rocket", "Colt45", - "Uzi", + "Python", "Shotgun", - "AK47", - "M16", + "Spas12Shotgun", + "StubbyShotgun", + "Tec9", + "Uzi", + "SilencedIngram", + "Mp5", + "m4", + "Ruger", "SniperRifle", + "LaserScope", "RocketLauncher", "FlameThrower", - "Molotov", - "Grenade", + "M60", + "Minigun", "Detonator", - "HeliCannon" + "HeliCannon", + "Camera", }; CWeaponInfo* -CWeaponInfo::GetWeaponInfo(eWeaponType weaponType) { +CWeaponInfo::GetWeaponInfo(eWeaponType weaponType) +{ return &aWeaponInfo[weaponType]; } @@ -37,9 +111,26 @@ CWeaponInfo::Initialise(void) debug("Initialising CWeaponInfo...\n"); for (int i = 0; i < WEAPONTYPE_TOTALWEAPONS; i++) { aWeaponInfo[i].m_eWeaponFire = WEAPON_FIRE_INSTANT_HIT; - aWeaponInfo[i].m_AnimToPlay = ANIM_STD_PUNCH; - aWeaponInfo[i].m_Anim2ToPlay = ANIM_STD_NUM; + aWeaponInfo[i].m_fRange = 0.0f; + aWeaponInfo[i].m_nFiringRate = 0; + aWeaponInfo[i].m_nReload = 0; + aWeaponInfo[i].m_nAmountofAmmunition = 0; + aWeaponInfo[i].m_nDamage = 0; + aWeaponInfo[i].m_fSpeed = 0.0f; + aWeaponInfo[i].m_fRadius = 0.0f; + aWeaponInfo[i].m_fLifespan = 0.0f; + aWeaponInfo[i].m_fSpread = 0.0f; + aWeaponInfo[i].m_vecFireOffset = CVector(0.0f, 0.0f, 0.0f); + aWeaponInfo[i].m_AnimToPlay = ASSOCGRP_UNARMED; + aWeaponInfo[i].m_fAnimLoopStart = 0.0f; + aWeaponInfo[i].m_fAnimLoopEnd = 0.0f; + aWeaponInfo[i].m_fAnimFrameFire = 0.0f; + aWeaponInfo[i].m_fAnim2LoopStart = 0.0f; + aWeaponInfo[i].m_fAnim2LoopEnd = 0.0f; + aWeaponInfo[i].m_fAnim2FrameFire = 0.0f; + aWeaponInfo[i].m_fAnimBreakout = 0.0f; aWeaponInfo[i].m_Flags = WEAPONFLAG_USE_GRAVITY | WEAPONFLAG_SLOWS_DOWN | WEAPONFLAG_RAND_SPEED | WEAPONFLAG_EXPANDS | WEAPONFLAG_EXPLODES; + aWeaponInfo[i].m_nWeaponSlot = WEAPONSLOT_UNARMED; } debug("Loading weapon data...\n"); LoadWeaponData(); @@ -51,21 +142,18 @@ CWeaponInfo::LoadWeaponData(void) { float spread, speed, lifeSpan, radius; float range, fireOffsetX, fireOffsetY, fireOffsetZ; - float delayBetweenAnimAndFire, delayBetweenAnim2AndFire, animLoopStart, animLoopEnd; + float anim2LoopStart, anim2LoopEnd, delayBetweenAnim2AndFire, animBreakout; + float delayBetweenAnimAndFire, animLoopStart, animLoopEnd; int flags, ammoAmount, damage, reload, weaponType; - int firingRate, modelId; + int firingRate, modelId, modelId2, weaponSlot; char line[256], weaponName[32], fireType[32]; - char animToPlay[32], anim2ToPlay[32]; - - CAnimBlendAssociation *animAssoc; - AnimationId animId; + char animToPlay[32]; size_t bp, buflen; int lp, linelen; CFileMgr::SetDir("DATA"); buflen = CFileMgr::LoadFile("WEAPON.DAT", work_buff, sizeof(work_buff), "r"); - CFileMgr::SetDir(""); for (bp = 0; bp < buflen; ) { // read file line by line @@ -96,10 +184,9 @@ CWeaponInfo::LoadWeaponData(void) fireType[0] = '\0'; fireOffsetY = 0.0f; fireOffsetZ = 0.0f; - animId = ANIM_STD_WALK; sscanf( &line[lp], - "%s %s %f %d %d %d %d %f %f %f %f %f %f %f %s %s %f %f %f %f %d %d", + "%s %s %f %d %d %d %d %f %f %f %f %f %f %f %s %f %f %f %f %f %f %f %d %d %x %d", weaponName, fireType, &range, @@ -115,27 +202,23 @@ CWeaponInfo::LoadWeaponData(void) &fireOffsetY, &fireOffsetZ, animToPlay, - anim2ToPlay, &animLoopStart, &animLoopEnd, &delayBetweenAnimAndFire, + &anim2LoopStart, + &anim2LoopEnd, &delayBetweenAnim2AndFire, + &animBreakout, &modelId, - &flags); + &modelId2, + &flags, + &weaponSlot); if (strncmp(weaponName, "ENDWEAPONDATA", 13) == 0) return; weaponType = FindWeaponType(weaponName); - animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animToPlay); - animId = static_cast<AnimationId>(animAssoc->animId); - - if (strcmp(anim2ToPlay, "null") != 0) { - animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, anim2ToPlay); - aWeaponInfo[weaponType].m_Anim2ToPlay = (AnimationId) animAssoc->animId; - } - CVector vecFireOffset(fireOffsetX, fireOffsetY, fireOffsetZ); aWeaponInfo[weaponType].m_eWeaponFire = FindWeaponFireType(fireType); @@ -149,13 +232,35 @@ CWeaponInfo::LoadWeaponData(void) aWeaponInfo[weaponType].m_fLifespan = lifeSpan; aWeaponInfo[weaponType].m_fSpread = spread; aWeaponInfo[weaponType].m_vecFireOffset = vecFireOffset; - aWeaponInfo[weaponType].m_AnimToPlay = animId; aWeaponInfo[weaponType].m_fAnimLoopStart = animLoopStart / 30.0f; aWeaponInfo[weaponType].m_fAnimLoopEnd = animLoopEnd / 30.0f; + aWeaponInfo[weaponType].m_fAnim2LoopStart = anim2LoopStart / 30.0f; + aWeaponInfo[weaponType].m_fAnim2LoopEnd = anim2LoopEnd / 30.0f; aWeaponInfo[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire / 30.0f; aWeaponInfo[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire / 30.0f; + aWeaponInfo[weaponType].m_fAnimBreakout = animBreakout / 30.0f; aWeaponInfo[weaponType].m_nModelId = modelId; + aWeaponInfo[weaponType].m_nModel2Id = modelId2; aWeaponInfo[weaponType].m_Flags = flags; + aWeaponInfo[weaponType].m_nWeaponSlot = weaponSlot; + + if (animLoopEnd < 98.0f && weaponType != WEAPONTYPE_FLAMETHROWER && !CWeapon::IsShotgun(weaponType)) + aWeaponInfo[weaponType].m_nFiringRate = ((aWeaponInfo[weaponType].m_fAnimLoopEnd - aWeaponInfo[weaponType].m_fAnimLoopStart) * 900.0f); + + if (weaponType == WEAPONTYPE_DETONATOR || weaponType == WEAPONTYPE_HELICANNON) + modelId = -1; + else if (weaponType == WEAPONTYPE_DETONATOR_GRENADE) + modelId = MI_BOMB; + + if (modelId != -1) + ((CWeaponModelInfo*)CModelInfo::GetModelInfo(modelId))->SetWeaponInfo(weaponType); + + for (int i = 0; i < NUM_ANIM_ASSOC_GROUPS; i++) { + if (!strcmp(animToPlay, CAnimManager::GetAnimGroupName((AssocGroupId)i))) { + aWeaponInfo[weaponType].m_AnimToPlay = (AssocGroupId)i; + break; + } + } } } @@ -177,6 +282,7 @@ CWeaponInfo::FindWeaponFireType(char *name) if (strcmp(name, "INSTANT_HIT") == 0) return WEAPON_FIRE_INSTANT_HIT; if (strcmp(name, "PROJECTILE") == 0) return WEAPON_FIRE_PROJECTILE; if (strcmp(name, "AREA_EFFECT") == 0) return WEAPON_FIRE_AREA_EFFECT; + if (strcmp(name, "CAMERA") == 0) return WEAPON_FIRE_CAMERA; Error("Unknown weapon fire type, WeaponInfo.cpp"); return WEAPON_FIRE_INSTANT_HIT; } diff --git a/src/weapons/WeaponInfo.h b/src/weapons/WeaponInfo.h index 96e2ecf4..d7f1563d 100644 --- a/src/weapons/WeaponInfo.h +++ b/src/weapons/WeaponInfo.h @@ -1,5 +1,6 @@ #pragma once +#include "AnimManager.h" #include "AnimationId.h" #include "WeaponType.h" @@ -16,10 +17,25 @@ enum WEAPONFLAG_1ST_PERSON = 1 << 8, WEAPONFLAG_HEAVY = 1 << 9, WEAPONFLAG_THROW = 1 << 10, + WEAPONFLAG_RELOAD_LOOP2START = 1 << 11, + WEAPONFLAG_USE_2ND = 1 << 12, + WEAPONFLAG_GROUND_2ND = 1 << 13, + WEAPONFLAG_FINISH_3RD = 1 << 14, + WEAPONFLAG_RELOAD = 1 << 15, + WEAPONFLAG_FIGHTMODE = 1 << 16, + WEAPONFLAG_CROUCHFIRE = 1 << 17, + WEAPONFLAG_COP3_RD = 1 << 18, + WEAPONFLAG_GROUND_3RD = 1 << 19, + WEAPONFLAG_PARTIALATTACK = 1 << 20, + WEAPONFLAG_ANIMDETONATE = 1 << 21, }; class CWeaponInfo { + static char ms_aWeaponNames[WEAPONTYPE_TOTALWEAPONS][32]; public: + static uint16 ms_aReloadSampleTime[WEAPONTYPE_TOTALWEAPONS]; + static int32 ms_aMaxAmmoForWeapon[WEAPONTYPE_TOTALWEAPONS]; + eWeaponFire m_eWeaponFire; float m_fRange; uint32 m_nFiringRate; @@ -31,22 +47,28 @@ public: float m_fLifespan; float m_fSpread; CVector m_vecFireOffset; - AnimationId m_AnimToPlay; - AnimationId m_Anim2ToPlay; + AssocGroupId m_AnimToPlay; float m_fAnimLoopStart; float m_fAnimLoopEnd; float m_fAnimFrameFire; + float m_fAnim2LoopStart; + float m_fAnim2LoopEnd; float m_fAnim2FrameFire; + float m_fAnimBreakout; int32 m_nModelId; + int32 m_nModel2Id; uint32 m_Flags; + uint32 m_nWeaponSlot; + static void Initialise(void); static void LoadWeaponData(void); static CWeaponInfo *GetWeaponInfo(eWeaponType weaponType); static eWeaponFire FindWeaponFireType(char *name); static eWeaponType FindWeaponType(char *name); static void Shutdown(void); + static bool IsWeaponSlotAmmoMergeable(uint32 slot) { return slot == WEAPONSLOT_SHOTGUN || slot == WEAPONSLOT_SUBMACHINEGUN || slot == WEAPONSLOT_RIFLE; } bool IsFlagSet(uint32 flag) const { return (m_Flags & flag) != 0; } }; -VALIDATE_SIZE(CWeaponInfo, 0x54);
\ No newline at end of file +VALIDATE_SIZE(CWeaponInfo, 0x64); diff --git a/src/weapons/WeaponType.h b/src/weapons/WeaponType.h index b45740b7..1220196f 100644 --- a/src/weapons/WeaponType.h +++ b/src/weapons/WeaponType.h @@ -3,20 +3,44 @@ enum eWeaponType { WEAPONTYPE_UNARMED, + WEAPONTYPE_BRASSKNUCKLE, + WEAPONTYPE_SCREWDRIVER, + WEAPONTYPE_GOLFCLUB, + WEAPONTYPE_NIGHTSTICK, + WEAPONTYPE_KNIFE, WEAPONTYPE_BASEBALLBAT, + WEAPONTYPE_HAMMER, + WEAPONTYPE_CLEAVER, + WEAPONTYPE_MACHETE, + WEAPONTYPE_KATANA, + WEAPONTYPE_CHAINSAW, + WEAPONTYPE_GRENADE, + WEAPONTYPE_DETONATOR_GRENADE, + WEAPONTYPE_TEARGAS, + WEAPONTYPE_MOLOTOV, + WEAPONTYPE_ROCKET, WEAPONTYPE_COLT45, - WEAPONTYPE_UZI, + WEAPONTYPE_PYTHON, WEAPONTYPE_SHOTGUN, - WEAPONTYPE_AK47, - WEAPONTYPE_M16, + WEAPONTYPE_SPAS12_SHOTGUN, + WEAPONTYPE_STUBBY_SHOTGUN, + WEAPONTYPE_TEC9, + WEAPONTYPE_UZI, + WEAPONTYPE_SILENCED_INGRAM, + WEAPONTYPE_MP5, + WEAPONTYPE_M4, + WEAPONTYPE_RUGER, WEAPONTYPE_SNIPERRIFLE, + WEAPONTYPE_LASERSCOPE, WEAPONTYPE_ROCKETLAUNCHER, WEAPONTYPE_FLAMETHROWER, - WEAPONTYPE_MOLOTOV, - WEAPONTYPE_GRENADE, + WEAPONTYPE_M60, + WEAPONTYPE_MINIGUN, WEAPONTYPE_DETONATOR, WEAPONTYPE_HELICANNON, - WEAPONTYPE_LAST_WEAPONTYPE, + WEAPONTYPE_CAMERA, + WEAPONTYPE_TOTALWEAPONS = 37, + WEAPONTYPE_HEALTH = 37, WEAPONTYPE_ARMOUR, WEAPONTYPE_RAMMEDBYCAR, WEAPONTYPE_RUNOVERBYCAR, @@ -25,9 +49,22 @@ enum eWeaponType WEAPONTYPE_DROWNING, WEAPONTYPE_FALL, WEAPONTYPE_UNIDENTIFIED, - - WEAPONTYPE_TOTALWEAPONS = WEAPONTYPE_LAST_WEAPONTYPE, - WEAPONTYPE_TOTAL_INVENTORY_WEAPONS = 13, + WEAPONTYPE_ANYMELEE, + WEAPONTYPE_ANYWEAPON +}; + +enum { + WEAPONSLOT_UNARMED = 0, + WEAPONSLOT_MELEE, + WEAPONSLOT_PROJECTILE, + WEAPONSLOT_HANDGUN, + WEAPONSLOT_SHOTGUN, + WEAPONSLOT_SUBMACHINEGUN, + WEAPONSLOT_RIFLE, + WEAPONSLOT_HEAVY, + WEAPONSLOT_SNIPER, + WEAPONSLOT_OTHER, + TOTAL_WEAPON_SLOTS }; enum eWeaponFire { @@ -35,7 +72,7 @@ enum eWeaponFire { WEAPON_FIRE_INSTANT_HIT, WEAPON_FIRE_PROJECTILE, WEAPON_FIRE_AREA_EFFECT, - WEAPON_FIRE_USE + WEAPON_FIRE_CAMERA }; // Taken from MTA SA, seems it's unchanged |