diff options
Diffstat (limited to 'src/weapons')
-rw-r--r-- | src/weapons/ProjectileInfo.cpp | 82 | ||||
-rw-r--r-- | src/weapons/ProjectileInfo.h | 1 | ||||
-rw-r--r-- | src/weapons/Weapon.cpp | 620 | ||||
-rw-r--r-- | src/weapons/Weapon.h | 14 | ||||
-rw-r--r-- | src/weapons/WeaponInfo.cpp | 125 | ||||
-rw-r--r-- | src/weapons/WeaponInfo.h | 33 | ||||
-rw-r--r-- | src/weapons/WeaponType.h | 30 |
7 files changed, 682 insertions, 223 deletions
diff --git a/src/weapons/ProjectileInfo.cpp b/src/weapons/ProjectileInfo.cpp index 47bc65ac..35e55b36 100644 --- a/src/weapons/ProjectileInfo.cpp +++ b/src/weapons/ProjectileInfo.cpp @@ -45,6 +45,7 @@ CProjectileInfo::GetProjectileInfo(int32 id) return &gaProjectileInfo[id]; } +// --MIAMI: Mostly done bool CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, float speed) { @@ -58,32 +59,36 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, switch (weapon) { - case WEAPONTYPE_ROCKETLAUNCHER: + case WEAPONTYPE_ROCKET: { - 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); + 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; - } else if (ped->m_pSeekTarget != nil) { + 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(); + } else { + matrix = ped->GetMatrix(); + } } velocity = Multiply3x3(matrix, CVector(0.0f, vy, 0.0f)); gravity = false; break; } - case WEAPONTYPE_FLAMETHROWER: - Error("Undefined projectile type, AddProjectile, ProjectileInfo.cpp"); - break; case WEAPONTYPE_MOLOTOV: { time = CTimer::GetTimeInMilliseconds() + 2000; @@ -100,6 +105,7 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, break; } case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: { time = CTimer::GetTimeInMilliseconds() + 2000; float scale = 0.0f; @@ -116,7 +122,9 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, elasticity = 0.5f; break; } - default: break; + default: + Error("Undefined projectile type, AddProjectile, ProjectileInfo.cpp"); + break; } int i = 0; @@ -127,7 +135,7 @@ 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: @@ -136,6 +144,7 @@ CProjectileInfo::AddProjectile(CEntity *entity, eWeaponType weapon, CVector pos, ms_apProjectile[i] = new CProjectile(MI_MOLOTOV); break; case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: ms_apProjectile[i] = new CProjectile(MI_GRENADE); break; default: break; @@ -158,6 +167,10 @@ 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; } @@ -182,7 +195,7 @@ CProjectileInfo::RemoveNotAdd(CEntity *entity, eWeaponType weaponType, CVector p case WEAPONTYPE_MOLOTOV: CExplosion::AddExplosion(nil, entity, EXPLOSION_MOLOTOV, pos, 0); break; - case WEAPONTYPE_ROCKETLAUNCHER: + case WEAPONTYPE_ROCKET: CExplosion::AddExplosion(nil, entity, EXPLOSION_ROCKET, pos, 0); break; default: break; @@ -204,17 +217,17 @@ CProjectileInfo::Update() continue; } - if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) { + if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET) { CParticle::AddParticle(PARTICLE_SMOKE, ms_apProjectile[i]->GetPosition(), CVector(0.0f, 0.0f, 0.0f)); } if (CTimer::GetTimeInMilliseconds() <= gaProjectileInfo[i].m_nExplosionTime) { - if (gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER) { + 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))) { + || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET && (CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos))) { RemoveProjectile(&gaProjectileInfo[i], ms_apProjectile[i]); } CWorld::pIgnoreEntity = nil; @@ -227,14 +240,25 @@ CProjectileInfo::Update() { 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))) { + || gaProjectileInfo[i].m_eWeaponType == WEAPONTYPE_ROCKET && (CHeli::TestRocketCollision(&pos) || CPlane::TestRocketCollision(&pos))) { 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(); @@ -247,7 +271,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; @@ -263,6 +287,20 @@ CProjectileInfo::IsProjectileInRange(float x1, float x2, float y1, float y2, flo return result; } +// --MIAMI: Done +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() { 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/Weapon.cpp b/src/weapons/Weapon.cpp index 88c4788c..4c1f1c52 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -30,20 +30,38 @@ #include "WeaponInfo.h" #include "World.h" +// TODO(Miami) +#define AUDIO_NOT_READY + uint16 gReloadSampleTime[WEAPONTYPE_LAST_WEAPONTYPE] = { 0, // UNARMED - 0, // BASEBALLBAT + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // GRENADE + 0, // DETONATEGRENADE + 0, // MOLOTOV + 0, // ROCKET 250, // COLT45 - 400, // UZI 650, // SHOTGUN - 300, // AK47 + 400, // TEC9 + 400, // UZIhec + 400, // SILENCED_INGRAM + 400, // MP5 300, // M16 + 300, // AK47 423, // SNIPERRIFLE 400, // ROCKETLAUNCHER 0, // FLAMETHROWER - 0, // MOLOTOV - 0, // GRENADE 0, // DETONATOR 0 // HELICANNON }; @@ -85,18 +103,42 @@ CWeapon::UpdateWeapons(void) CBulletInfo::Update(); } +// --MIAMI: Done 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; + int modelId = CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_nModelId; + if (modelId != -1) + CModelInfo::GetModelInfo(modelId)->AddRef(); + + int model2Id = CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_nModel2Id; + if (model2Id != -1) + CModelInfo::GetModelInfo(model2Id)->AddRef(); +} + +// --MIAMI: Done +void +CWeapon::Shutdown() +{ + int modelId = CWeaponInfo::GetWeaponInfo(m_eWeaponType)->m_nModelId; + if (modelId != -1) + CModelInfo::GetModelInfo(modelId)->RemoveRef(); + + int 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 @@ -124,6 +166,7 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) return false; bool fired; + bool addFireRateAsDelay = true; if ( GetInfo()->m_eWeaponFire != WEAPON_FIRE_MELEE ) { @@ -134,6 +177,7 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) { case WEAPONTYPE_SHOTGUN: { + addFireRateAsDelay = true; fired = FireShotgun(shooter, source); break; @@ -141,10 +185,21 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) case WEAPONTYPE_COLT45: case WEAPONTYPE_UZI: + case WEAPONTYPE_TEC9: + case WEAPONTYPE_SILENCED_INGRAM: + case WEAPONTYPE_MP5: case WEAPONTYPE_AK47: + case WEAPONTYPE_M16: + case WEAPONTYPE_HELICANNON: { - fired = FireInstantHit(shooter, source); - + if ((TheCamera.PlayerWeaponMode.Mode == CCam::MODE_HELICANNON_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON) + && shooter == FindPlayerPed()) { + addFireRateAsDelay = false; + fired = FireM16_1stPerson(shooter); + } else { + addFireRateAsDelay = true; + fired = FireInstantHit(shooter, source); + } break; } @@ -155,16 +210,6 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) break; } - case WEAPONTYPE_M16: - { - if ( TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON && shooter == FindPlayerPed() ) - fired = FireM16_1stPerson(shooter); - else - fired = FireInstantHit(shooter, source); - - break; - } - case WEAPONTYPE_ROCKETLAUNCHER: { if ( shooter->IsPed() && ((CPed*)shooter)->m_pSeekTarget != nil ) @@ -184,6 +229,7 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) case WEAPONTYPE_MOLOTOV: case WEAPONTYPE_GRENADE: + case WEAPONTYPE_DETONATOR_GRENADE: { if ( shooter == FindPlayerPed() ) { @@ -201,6 +247,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; } @@ -221,19 +272,6 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) break; } - case WEAPONTYPE_HELICANNON: - { - if ( (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_HELICANNON_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON ) - && shooter == FindPlayerPed() ) - { - fired = FireM16_1stPerson(shooter); - } - else - fired = FireInstantHit(shooter, source); - - break; - } - default: { debug("Unknown weapon type, Weapon.cpp"); @@ -241,51 +279,58 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) } } - if ( fired ) + if (fired) { bool isPlayer = false; - if ( shooter->IsPed() ) + if (shooter->IsPed()) { - CPed *shooterPed = (CPed*)shooter; + CPed* shooterPed = (CPed*)shooter; shooterPed->bIsShooting = true; - if ( shooterPed->IsPlayer() ) + if (shooterPed->IsPlayer()) isPlayer = true; DMAudio.PlayOneShot(shooterPed->m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f); } - if ( m_nAmmoInClip > 0 ) m_nAmmoInClip--; - if ( m_nAmmoTotal > 0 && (m_nAmmoTotal < 25000 || isPlayer) ) m_nAmmoTotal--; + if (m_nAmmoInClip > 0) + m_nAmmoInClip--; - if ( m_eWeaponState == WEAPONSTATE_READY && m_eWeaponType == WEAPONTYPE_FLAMETHROWER ) + 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); m_eWeaponState = WEAPONSTATE_FIRING; - } - if ( m_nAmmoInClip == 0 ) - { - if ( m_nAmmoTotal == 0 ) - return true; + if (m_nAmmoInClip == 0) + { + if (m_nAmmoTotal == 0) + return true; - m_eWeaponState = WEAPONSTATE_RELOADING; - m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload; + m_eWeaponState = WEAPONSTATE_RELOADING; + m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload; - if ( shooter == FindPlayerPed() ) - { - if ( CWorld::Players[CWorld::PlayerInFocus].m_bFastReload ) - m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload / 4; + if (shooter == FindPlayerPed()) + { + if (CWorld::Players[CWorld::PlayerInFocus].m_bFastReload) + m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload / 4; + } + + return true; } - return true; - } + if (addFireRateAsDelay) + m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nFiringRate; + else + m_nTimer = CTimer::GetTimeInMilliseconds(); - m_nTimer = CTimer::GetTimeInMilliseconds() + 1000; - if ( shooter == FindPlayerPed() ) - CStats::RoundsFiredByPlayer++; + if (shooter == FindPlayerPed()) + CStats::RoundsFiredByPlayer++; + } } else { @@ -293,9 +338,15 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) { m_nTimer = CTimer::GetTimeInMilliseconds() + GetInfo()->m_nReload; m_eWeaponState = WEAPONSTATE_FIRING; +#ifndef AUDIO_NOT_READY + if (shooter->IsPed() && m_eWeaponType != WEAPONTYPE_CHAINSAW) + { + DMAudio.PlayOneShot(((CPed*)shooter)->m_audioEntityId, 188, m_eWeaponType << 8); + } +#endif } - FireMelee(shooter, *source); + fired = FireMelee(shooter, *source); } if ( m_eWeaponType == WEAPONTYPE_UNARMED || m_eWeaponType == WEAPONTYPE_BASEBALLBAT ) @@ -305,7 +356,7 @@ CWeapon::Fire(CEntity *shooter, CVector *fireSource) } bool -CWeapon::FireFromCar(CAutomobile *shooter, bool left) +CWeapon::FireFromCar(CVehicle *shooter, bool left) { ASSERT(shooter!=nil); @@ -343,6 +394,7 @@ CWeapon::FireFromCar(CAutomobile *shooter, bool left) return true; } +// --MIAMI: Done, except commented things bool CWeapon::FireMelee(CEntity *shooter, CVector &fireSource) { @@ -350,28 +402,39 @@ CWeapon::FireMelee(CEntity *shooter, CVector &fireSource) CWeaponInfo *info = GetInfo(); - bool anim2Playing = false; - if ( RpAnimBlendClumpGetAssociation(shooter->GetClump(), info->m_Anim2ToPlay) ) - anim2Playing = true; + bool anim2Playing = RpAnimBlendClumpGetAssociation(shooter->GetClump(), CPed::GetFireAnimGround(info, false)); 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)) { + + // TODO(Miami): BreakGlassPhysically + 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->m_bFightMode)) + continue; float victimPedRadius = victimPed->GetBoundRadius() + info->m_fRadius; if ( victimPed->bUsesCollision || victimPed->Dead() || victimPed->Driving() ) @@ -380,12 +443,29 @@ 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() ) { @@ -406,65 +486,115 @@ 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; + // TODO(Miami): Bike 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); + + // TODO(Miami): New particle + /* + v116.z = 0.0; + v116.x = CGeneral::GetRandomNumberInRange(-0.15f, 0.15f); + v116.y = CGeneral::GetRandomNumberInRange(0.1f, 0.35f); + v115.x = CGeneral::GetRandomNumberInRange(SCREEN_STRETCH_X(50.0f), SCREEN_STRETCH_FROM_RIGHT(50.0f)); + v115.z = 1.0; + v115.y = CGeneral::GetRandomNumberInRange(SCREEN_STRETCH_Y(50.0f), SCREEN_STRETCH_FROM_BOTTOM(50.0f)); + CParticle::AddParticle(41, v115, v116, 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.x += 0.1f * shooterPed->GetUp().x + 0.05f * shooterPed->GetRight().x; + dir.y += 0.1f * shooterPed->GetUp().y + 0.05f * shooterPed->GetRight().y; + dir.z += 0.1f * shooterPed->GetUp().z + 0.05f * shooterPed->GetRight().z; + 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 > 20.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_KO_SKID_FRONT + localDir), false); else victimPed->SetFall(1500, AnimationId(ANIM_KO_SKID_FRONT + localDir), false); @@ -477,21 +607,152 @@ 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(int 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); + + // TODO(Miami): Particle not in III + // CParticle::AddParticle(81, gaTempSphereColPoints[0].point, CVector(0.0f, 0.0f, 0.0f), 0, 0.0f, 0, 0, 0, 0); + } + else + { + nearCar->VehicleDamage(info->m_nDamage* (0.00075f * 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_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_TILL_SAFE); + passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + leaveCarDelay; + leaveCarDelay += 200; + } + } + } + else + { + CPed *driver = nearCar->pDriver; + if (driver) + { + if (driver->m_objective != OBJECTIVE_LEAVE_VEHICLE && driver->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && + driver->m_objective != OBJECTIVE_FLEE_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); + } + + // TODO(Miami): Particle not in III + //CParticle::AddParticle(81, 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; } @@ -634,45 +895,15 @@ CWeapon::FireInstantHit(CEntity *shooter, CVector *fireSource) switch ( m_eWeaponType ) { - case WEAPONTYPE_AK47: - { - static uint8 counter = 0; - - if ( !(++counter & 1) ) - { - CPointLights::AddLight(CPointLights::LIGHT_POINT, - *fireSource, CVector(0.0f, 0.0f, 0.0f), 5.0f, - 1.0f, 0.8f, 0.0f, CPointLights::FOG_NONE, false); - - CVector gunflashPos = *fireSource; - gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f); - CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.10f); - gunflashPos += CVector(0.06f*ahead.x, 0.06f*ahead.y, 0.0f); - CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.08f); - gunflashPos += CVector(0.05f*ahead.x, 0.05f*ahead.y, 0.0f); - CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.06f); - gunflashPos += CVector(0.04f*ahead.x, 0.04f*ahead.y, 0.0f); - CParticle::AddParticle(PARTICLE_GUNFLASH_NOANIM, gunflashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.04f); - - CVector gunsmokePos = *fireSource; - float rnd = CGeneral::GetRandomNumberInRange(0.05f, 0.25f); - CParticle::AddParticle(PARTICLE_GUNSMOKE2, gunsmokePos, CVector(ahead.x*rnd, ahead.y*rnd, 0.0f)); - - CVector gunshellPos = *fireSource; - gunshellPos -= CVector(0.5f*ahead.x, 0.5f*ahead.y, 0.0f); - CVector dir = CrossProduct(CVector(ahead.x, ahead.y, 0.0f), CVector(0.0f, 0.0f, 5.0f)); - dir.Normalise2D(); - AddGunshell(shooter, gunshellPos, CVector2D(dir.x, dir.y), 0.018f); - } - - break; - } - case WEAPONTYPE_M16: + case WEAPONTYPE_AK47: + // 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, @@ -739,6 +970,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, @@ -1387,10 +1621,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() ) { @@ -1432,7 +1668,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() ) @@ -1441,14 +1677,14 @@ 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); return true; } @@ -1532,7 +1768,7 @@ 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; @@ -1555,6 +1791,7 @@ CWeapon::FireSniper(CEntity *shooter) return true; } +// --MIAMI: Heavily TODO bool CWeapon::FireM16_1stPerson(CEntity *shooter) { @@ -1599,7 +1836,9 @@ CWeapon::FireM16_1stPerson(CEntity *shooter) DoBulletImpact(shooter, victim, &source, &target, &point, front); CVector bulletPos; - if ( CHeli::TestBulletCollision(&source, &target, &bulletPos, 4) ) + + // TODO(Miami): M60 + 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)); @@ -1609,23 +1848,34 @@ CWeapon::FireM16_1stPerson(CEntity *shooter) { 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; + // TODO(Miami) + float mult; + switch (m_eWeaponType) { + case WEAPONTYPE_M16: // case WEAPONTYPE_M4: + case WEAPONTYPE_HELICANNON: + // case WEAPONTYPE_M60: + mult = 0.0003f; + break; + case WEAPONTYPE_AK47: // case WEAPONTYPE_RUGER: + mult = 0.00015f; + 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; } return true; } bool -CWeapon::FireInstantHitFromCar(CAutomobile *shooter, bool left) +CWeapon::FireInstantHitFromCar(CVehicle *shooter, bool left) { CWeaponInfo *info = GetInfo(); @@ -1996,8 +2246,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: @@ -2030,9 +2282,57 @@ CWeapon::Update(int32 audioEntity) { if ( AEHANDLE_IS_OK(audioEntity) && m_eWeaponType < WEAPONTYPE_LAST_WEAPONTYPE ) { - uint32 timePassed = m_nTimer - gReloadSampleTime[m_eWeaponType]; - if ( CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed ) - DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f); + 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 = 0.5f; + break; + case ASSOCGRP_COLT: + case ASSOCGRP_TEC: + soundStart = 0.7f; + break; + case ASSOCGRP_UZI: + soundStart = 0.75f; + break; + case ASSOCGRP_RIFLE: + soundStart = 0.75f; + break; + case ASSOCGRP_M60: + soundStart = 0.7f; + break; + default: + break; + } + if (reloadAssoc->GetProgress() >= soundStart && (reloadAssoc->currentTime - reloadAssoc->timeStep) / reloadAssoc->hierarchy->totalLength < soundStart) { +#ifdef AUDIO_NOT_READY + DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f); +#else + DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, m_eWeaponType); +#endif + } + if (CTimer::GetTimeInMilliseconds() > m_nTimer && reloadAssoc->GetProgress() < 0.9f) { + m_nTimer = CTimer::GetTimeInMilliseconds(); + } + } else { + uint32 timePassed = m_nTimer - gReloadSampleTime[m_eWeaponType]; + if (CTimer::GetPreviousTimeInMilliseconds() < timePassed && CTimer::GetTimeInMilliseconds() >= timePassed) { +#ifdef AUDIO_NOT_READY + DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, 0.0f); +#else + DMAudio.PlayOneShot(audioEntity, SOUND_WEAPON_RELOAD, m_eWeaponType); +#endif + } + } } if ( CTimer::GetTimeInMilliseconds() > m_nTimer ) @@ -2155,13 +2455,17 @@ 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; + // TODO(Miami): Uncomment + return m_eWeaponType == WEAPONTYPE_FLAMETHROWER || m_eWeaponType == WEAPONTYPE_HELICANNON || /* m_eWeaponType == WEAPONTYPE_M60 */ + m_eWeaponType == WEAPONTYPE_M16 || + (m_eWeaponType >= WEAPONTYPE_SHOTGUN && m_eWeaponType < WEAPONTYPE_TEC9) || // Shotguns + m_eWeaponType == WEAPONTYPE_AK47 || m_eWeaponType == WEAPONTYPE_SNIPERRIFLE /*|| m_eWeaponType == WEAPONTYPE_LASERSCOPE*/; } void @@ -2268,13 +2572,15 @@ 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 diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index 1b2c0320..f6228b32 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -7,7 +7,8 @@ class CEntity; class CPhysical; -class CAutomobile; +class CVehicle; +class CPed; struct CColPoint; class CWeaponInfo; @@ -16,8 +17,8 @@ class CWeapon public: eWeaponType m_eWeaponType; eWeaponState m_eWeaponState; - uint32 m_nAmmoInClip; - uint32 m_nAmmoTotal; + int32 m_nAmmoInClip; + int32 m_nAmmoTotal; uint32 m_nTimer; bool m_bAddRotOffset; @@ -32,9 +33,10 @@ 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 FireMelee (CEntity *shooter, CVector &fireSource); bool FireInstantHit(CEntity *shooter, CVector *fireSource); @@ -49,14 +51,14 @@ public: bool FireAreaEffect (CEntity *shooter, CVector *fireSource); bool FireSniper (CEntity *shooter); bool FireM16_1stPerson (CEntity *shooter); - bool FireInstantHitFromCar(CAutomobile *shooter, bool left); + bool FireInstantHitFromCar(CVehicle *shooter, bool left); static void DoDoomAiming (CEntity *shooter, CVector *source, CVector *target); static void DoTankDoomAiming (CEntity *shooter, CEntity *driver, CVector *source, CVector *target); static void DoDriveByAutoAiming(CEntity *shooter, CVector *source, CVector *target); void Reload(void); - void Update(int32 audioEntity); + void Update(int32 audioEntity, CPed *pedToAdjustSound); bool IsTypeMelee (void); bool IsType2Handed(void); diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp index c4ab75d2..d5e759b9 100644 --- a/src/weapons/WeaponInfo.cpp +++ b/src/weapons/WeaponInfo.cpp @@ -6,24 +6,47 @@ #include "AnimManager.h" #include "AnimBlendAssociation.h" #include "Weapon.h" +#include "ModelInfo.h" +#include "ModelIndices.h" + +// 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, +}; CWeaponInfo CWeaponInfo::ms_apWeaponInfos[WEAPONTYPE_TOTALWEAPONS]; +// --MIAMI: Todo static char ms_aWeaponNames[][32] = { "Unarmed", + "BrassKnuckle", + "ScrewDriver", + "GolfClub", + "NightStick", + "Knife", "BaseballBat", + "Hammer", + "Cleaver", + "Machete", + "Katana", + "Chainsaw", + "Grenade", + "DetonateGrenade", + "Molotov", + "Rocket", "Colt45", - "Uzi", "Shotgun", - "AK47", + "Tec9", + "Uzi", + "SilencedIngram", + "Mp5", "M16", + "AK47", "SniperRifle", "RocketLauncher", "FlameThrower", - "Molotov", - "Grenade", "Detonator", - "HeliCannon" + "HeliCannon", }; CWeaponInfo* @@ -31,45 +54,61 @@ CWeaponInfo::GetWeaponInfo(eWeaponType weaponType) { return &CWeaponInfo::ms_apWeaponInfos[weaponType]; } +// --MIAMI: done except WEAPONTYPE_TOTALWEAPONS value void CWeaponInfo::Initialise(void) { debug("Initialising CWeaponInfo...\n"); for (int i = 0; i < WEAPONTYPE_TOTALWEAPONS; i++) { ms_apWeaponInfos[i].m_eWeaponFire = WEAPON_FIRE_INSTANT_HIT; - ms_apWeaponInfos[i].m_AnimToPlay = ANIM_PUNCH_R; - ms_apWeaponInfos[i].m_Anim2ToPlay = NUM_ANIMS; + ms_apWeaponInfos[i].m_fRange = 0.0f; + ms_apWeaponInfos[i].m_nFiringRate = 0; + ms_apWeaponInfos[i].m_nReload = 0; + ms_apWeaponInfos[i].m_nAmountofAmmunition = 0; + ms_apWeaponInfos[i].m_nDamage = 0; + ms_apWeaponInfos[i].m_fSpeed = 0.0f; + ms_apWeaponInfos[i].m_fRadius = 0.0f; + ms_apWeaponInfos[i].m_fLifespan = 0.0f; + ms_apWeaponInfos[i].m_fSpread = 0.0f; + ms_apWeaponInfos[i].m_vecFireOffset = CVector(0.0f, 0.0f, 0.0f); + ms_apWeaponInfos[i].m_AnimToPlay = ASSOCGRP_UNARMED; + ms_apWeaponInfos[i].m_fAnimLoopStart = 0.0f; + ms_apWeaponInfos[i].m_fAnimLoopEnd = 0.0f; + ms_apWeaponInfos[i].m_fAnimFrameFire = 0.0f; + ms_apWeaponInfos[i].m_fAnim2LoopStart = 0.0f; + ms_apWeaponInfos[i].m_fAnim2LoopEnd = 0.0f; + ms_apWeaponInfos[i].m_fAnim2FrameFire = 0.0f; + ms_apWeaponInfos[i].m_fAnimBreakout = 0.0f; ms_apWeaponInfos[i].m_bUseGravity = 1; ms_apWeaponInfos[i].m_bSlowsDown = 1; ms_apWeaponInfos[i].m_bRandSpeed = 1; ms_apWeaponInfos[i].m_bExpands = 1; ms_apWeaponInfos[i].m_bExplodes = 1; + ms_apWeaponInfos[i].m_nWeaponSlot = 0; } debug("Loading weapon data...\n"); LoadWeaponData(); debug("CWeaponInfo ready\n"); } +// --MIAMI: Done, commented parts wait for weapons port void 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]; int 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 @@ -101,10 +140,9 @@ CWeaponInfo::LoadWeaponData(void) fireType[0] = '\0'; fireOffsetY = 0.0f; fireOffsetZ = 0.0f; - animId = ANIM_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, @@ -120,27 +158,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 (strncmp(anim2ToPlay, "null", 4) != 0) { - animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, anim2ToPlay); - ms_apWeaponInfos[weaponType].m_Anim2ToPlay = (AnimationId) animAssoc->animId; - } - CVector vecFireOffset(fireOffsetX, fireOffsetY, fireOffsetZ); ms_apWeaponInfos[weaponType].m_eWeaponFire = FindWeaponFireType(fireType); @@ -154,12 +188,16 @@ CWeaponInfo::LoadWeaponData(void) ms_apWeaponInfos[weaponType].m_fLifespan = lifeSpan; ms_apWeaponInfos[weaponType].m_fSpread = spread; ms_apWeaponInfos[weaponType].m_vecFireOffset = vecFireOffset; - ms_apWeaponInfos[weaponType].m_AnimToPlay = animId; ms_apWeaponInfos[weaponType].m_fAnimLoopStart = animLoopStart / 30.0f; ms_apWeaponInfos[weaponType].m_fAnimLoopEnd = animLoopEnd / 30.0f; + ms_apWeaponInfos[weaponType].m_fAnim2LoopStart = anim2LoopStart / 30.0f; + ms_apWeaponInfos[weaponType].m_fAnim2LoopEnd = anim2LoopEnd / 30.0f; ms_apWeaponInfos[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire / 30.0f; ms_apWeaponInfos[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire / 30.0f; + ms_apWeaponInfos[weaponType].m_fAnimBreakout = animBreakout / 30.0f; ms_apWeaponInfos[weaponType].m_nModelId = modelId; + ms_apWeaponInfos[weaponType].m_nModel2Id = modelId2; + ms_apWeaponInfos[weaponType].m_bUseGravity = flags; ms_apWeaponInfos[weaponType].m_bSlowsDown = flags >> 1; ms_apWeaponInfos[weaponType].m_bDissipates = flags >> 2; @@ -171,6 +209,39 @@ CWeaponInfo::LoadWeaponData(void) ms_apWeaponInfos[weaponType].m_b1stPerson = flags >> 8; ms_apWeaponInfos[weaponType].m_bHeavy = flags >> 9; ms_apWeaponInfos[weaponType].m_bThrow = flags >> 10; + ms_apWeaponInfos[weaponType].m_bReloadLoop2Start = flags >> 11; + ms_apWeaponInfos[weaponType].m_bUse2nd = flags >> 12; + ms_apWeaponInfos[weaponType].m_bGround2nd = flags >> 13; + ms_apWeaponInfos[weaponType].m_bFinish3rd = flags >> 14; + ms_apWeaponInfos[weaponType].m_bReload = flags >> 15; + ms_apWeaponInfos[weaponType].m_bFightMode = flags >> 16; + ms_apWeaponInfos[weaponType].m_bCrouchFire = flags >> 17; + ms_apWeaponInfos[weaponType].m_bCop3rd = flags >> 18; + ms_apWeaponInfos[weaponType].m_bGround3rd = flags >> 19; + ms_apWeaponInfos[weaponType].m_bPartialAttack = flags >> 20; + ms_apWeaponInfos[weaponType].m_bAnimDetonate = flags >> 21; + + ms_apWeaponInfos[weaponType].m_nWeaponSlot = weaponSlot; + + // TODO(Miami): Enable once weapons are done + if (animLoopEnd < 98.0f && weaponType != WEAPONTYPE_FLAMETHROWER && weaponType != WEAPONTYPE_SHOTGUN + /*&& weaponType != 20 && weaponType != 21*/) + ms_apWeaponInfos[weaponType].m_nFiringRate = ((ms_apWeaponInfos[weaponType].m_fAnimLoopEnd - ms_apWeaponInfos[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))) { + ms_apWeaponInfos[weaponType].m_AnimToPlay = (AssocGroupId)i; + break; + } + } } } diff --git a/src/weapons/WeaponInfo.h b/src/weapons/WeaponInfo.h index b5882082..41450047 100644 --- a/src/weapons/WeaponInfo.h +++ b/src/weapons/WeaponInfo.h @@ -3,28 +3,34 @@ #include "AnimationId.h" #include "WeaponType.h" +enum AssocGroupId; + class CWeaponInfo { -// static CWeaponInfo(&ms_apWeaponInfos)[14]; - static CWeaponInfo ms_apWeaponInfos[14]; + static CWeaponInfo ms_apWeaponInfos[WEAPONTYPE_TOTALWEAPONS]; public: + static int32 ms_aMaxAmmoForWeapon[WEAPONTYPE_TOTALWEAPONS]; + eWeaponFire m_eWeaponFire; float m_fRange; uint32 m_nFiringRate; uint32 m_nReload; - uint32 m_nAmountofAmmunition; + int32 m_nAmountofAmmunition; uint32 m_nDamage; float m_fSpeed; float m_fRadius; 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; // flags uint8 m_bUseGravity : 1; uint8 m_bSlowsDown : 1; @@ -34,9 +40,24 @@ public: uint8 m_bExplodes : 1; uint8 m_bCanAim : 1; uint8 m_bCanAimWithArm : 1; + uint8 m_b1stPerson : 1; uint8 m_bHeavy : 1; uint8 m_bThrow : 1; + uint8 m_bReloadLoop2Start : 1; + uint8 m_bUse2nd : 1; + uint8 m_bGround2nd : 1; + uint8 m_bFinish3rd : 1; + uint8 m_bReload : 1; + + uint8 m_bFightMode : 1; + uint8 m_bCrouchFire : 1; + uint8 m_bCop3rd : 1; + uint8 m_bGround3rd : 1; + uint8 m_bPartialAttack : 1; + uint8 m_bAnimDetonate : 1; + + uint32 m_nWeaponSlot; static void Initialise(void); static void LoadWeaponData(void); @@ -46,4 +67,4 @@ public: static void Shutdown(void); }; -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..6516828a 100644 --- a/src/weapons/WeaponType.h +++ b/src/weapons/WeaponType.h @@ -1,22 +1,39 @@ #pragma once +// --MIAMI: TODO 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_MOLOTOV, + WEAPONTYPE_ROCKET, WEAPONTYPE_COLT45, - WEAPONTYPE_UZI, WEAPONTYPE_SHOTGUN, - WEAPONTYPE_AK47, + WEAPONTYPE_TEC9, + WEAPONTYPE_UZI, + WEAPONTYPE_SILENCED_INGRAM, + WEAPONTYPE_MP5, WEAPONTYPE_M16, + WEAPONTYPE_AK47, WEAPONTYPE_SNIPERRIFLE, WEAPONTYPE_ROCKETLAUNCHER, WEAPONTYPE_FLAMETHROWER, - WEAPONTYPE_MOLOTOV, - WEAPONTYPE_GRENADE, WEAPONTYPE_DETONATOR, WEAPONTYPE_HELICANNON, WEAPONTYPE_LAST_WEAPONTYPE, + WEAPONTYPE_HEALTH, WEAPONTYPE_ARMOUR, WEAPONTYPE_RAMMEDBYCAR, WEAPONTYPE_RUNOVERBYCAR, @@ -27,7 +44,10 @@ enum eWeaponType WEAPONTYPE_UNIDENTIFIED, WEAPONTYPE_TOTALWEAPONS = WEAPONTYPE_LAST_WEAPONTYPE, - WEAPONTYPE_TOTAL_INVENTORY_WEAPONS = 13, +}; + +enum { + TOTAL_WEAPON_SLOTS = 10, }; enum eWeaponFire { |