bool CShotgun::Shoot(bool resetAnimation, bool autoreload/* =true */, bool noSound /* =false */) { IEntityClass *ammo = m_pShared->fireparams.ammo_type_class; int ammoCount = m_pWeapon->GetAmmoCount(ammo); if(m_pShared->fireparams.clip_size==0) ammoCount = m_pWeapon->GetInventoryAmmoCount(ammo); CActor *pActor = m_pWeapon->GetOwnerActor(); bool playerIsShooter = pActor?pActor->IsPlayer():false; if(!CanFire(true)) { if((ammoCount <= 0) && (!m_reloading)) { m_pWeapon->PlayAction(m_pShared->actions.empty_clip); //Auto reload m_pWeapon->Reload(); } return false; } else if(m_pWeapon->IsWeaponLowered()) { m_pWeapon->PlayAction(m_pShared->actions.null_fire); return false; } if(m_reloading) { if(m_pWeapon->IsBusy()) m_pWeapon->SetBusy(false); if(CanFire(true) && !m_break_reload) { m_break_reload = true; m_pWeapon->RequestCancelReload(); } return false; } // Aim assistance m_pWeapon->AssistAiming(); const char *action = m_pShared->actions.fire_cock.c_str(); if(ammoCount == 1 || (m_pShared->fireparams.no_cock && m_pWeapon->IsZoomed())) action = m_pShared->actions.fire.c_str(); m_pWeapon->PlayAction(action, 0, false, CItem::eIPAF_Default|CItem::eIPAF_RestartAnimation|CItem::eIPAF_CleanBlending); Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE); Vec3 pos = GetFiringPos(hit); Vec3 fdir = ApplySpread(GetFiringDir(hit, pos), GetSpread()); Vec3 vel = GetFiringVelocity(fdir); Vec3 dir; CheckNearMisses(hit, pos, fdir, WEAPON_HIT_RANGE, m_pShared->shotgunparams.spread); bool serverSpawn = m_pWeapon->IsServerSpawn(ammo); // SHOT HERE for(int i = 0; i < m_pShared->shotgunparams.pellets; i++) { CProjectile *pAmmo = m_pWeapon->SpawnAmmo(ammo, false); if(pAmmo) { dir = ApplySpread(fdir, m_pShared->shotgunparams.spread); int hitTypeId = g_pGame->GetGameRules()->GetHitTypeId(m_pShared->fireparams.hit_type.c_str()); pAmmo->SetParams(m_pWeapon->GetOwnerId(), m_pWeapon->GetHostId(), m_pWeapon->GetEntityId(), m_pShared->shotgunparams.pelletdamage, hitTypeId, playerIsShooter?m_pShared->fireparams.damage_drop_per_meter:0.0f, m_pShared->fireparams.damage_drop_min_distance); pAmmo->SetDestination(m_pWeapon->GetDestination()); pAmmo->Launch(pos, dir, vel); if((!m_pShared->tracerparams.geometry.empty() || !m_pShared->tracerparams.effect.empty()) && (ammoCount==GetClipSize() || (ammoCount%m_pShared->tracerparams.frequency==0))) { EmitTracer(pos,hit,false); } m_projectileId = pAmmo->GetEntity()->GetId(); } } m_pWeapon->OnShoot(m_pWeapon->GetOwnerId(), 0, ammo, pos, dir, vel); if(m_pWeapon->IsServer()) { const char *ammoName = ammo != NULL ? ammo->GetName() : NULL; g_pGame->GetIGameFramework()->GetIGameplayRecorder()->Event(m_pWeapon->GetOwner(), GameplayEvent(eGE_WeaponShot, ammoName, m_pShared->shotgunparams.pellets, (void *)m_pWeapon->GetEntityId())); } MuzzleFlashEffect(true); RejectEffect(); m_fired = true; m_next_shot += m_next_shot_dt; m_zoomtimeout = m_next_shot + 0.5f; ammoCount--; if(playerIsShooter) { if(pActor->InZeroG()) { IEntityPhysicalProxy *pPhysicsProxy = (IEntityPhysicalProxy *)pActor->GetEntity()->GetProxy(ENTITY_PROXY_PHYSICS); SMovementState ms; pActor->GetMovementController()->GetMovementState(ms); CPlayer *plr = (CPlayer *)pActor; if(m_recoilparams.back_impulse > 0.0f) { Vec3 impulseDir = ms.aimDirection * -1.0f; Vec3 impulsePos = ms.pos; float impulse = m_recoilparams.back_impulse; pPhysicsProxy->AddImpulse(-1, impulsePos, impulseDir * impulse * 100.0f, true, 1.0f); } if(m_recoilparams.angular_impulse > 0.0f) { float impulse = m_recoilparams.angular_impulse; pActor->AddAngularImpulse(Ang3(0,impulse,0), 1.0f); } } if(pActor->IsClient()) if(gEnv->pInput) gEnv->pInput->ForceFeedbackEvent(SFFOutputEvent(eDI_XI, eFF_Rumble_Basic, 0.15f, 0.0f, fabsf(m_recoilparams.back_impulse)*3.0f)); } if(m_pShared->fireparams.clip_size != -1) { if(m_pShared->fireparams.clip_size!=0) m_pWeapon->SetAmmoCount(ammo, ammoCount); else m_pWeapon->SetInventoryAmmoCount(ammo, ammoCount); } if((ammoCount<1) && !m_pShared->fireparams.slider_layer.empty()) { const char *slider_back_layer = m_pShared->fireparams.slider_layer.c_str(); m_pWeapon->PlayLayer(slider_back_layer, CItem::eIPAF_Default|CItem::eIPAF_NoBlend); } if(OutOfAmmo()) { m_pWeapon->OnOutOfAmmo(ammo); if(autoreload) { m_pWeapon->GetScheduler()->TimerAction(m_pWeapon->GetCurrentAnimationTime(eIGS_FirstPerson), CSchedulerAction<ScheduleReload>::Create(m_pWeapon), false); } } m_pWeapon->RequestShoot(ammo, pos, dir, vel, hit, 1.0f, 0, false); return true; }
bool CSpammer::ShootRocket(EntityId target) { IEntityClass* pAmmoClass = m_fireParams->fireparams.ammo_type_class; int ammoCount = m_pWeapon->GetAmmoCount(pAmmoClass); CActor *pOwnerActor = m_pWeapon->GetOwnerActor(); const bool playerIsShooter = pOwnerActor ? pOwnerActor->IsPlayer() : false; const bool clientIsShooter = pOwnerActor ? pOwnerActor->IsClient() : false; bool bHit = false; ray_hit rayhit; rayhit.pCollider = 0; Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE, &bHit, &rayhit); Vec3 pos = GetFiringPos(hit); Vec3 dir = GetFiringDir(hit, pos); Vec3 vel = GetFiringVelocity(dir); int flags = CItem::eIPAF_Default; if (IsProceduralRecoilEnabled() && pOwnerActor) { pOwnerActor->ProceduralRecoil(m_fireParams->proceduralRecoilParams.duration, m_fireParams->proceduralRecoilParams.strength, m_fireParams->proceduralRecoilParams.kickIn, m_fireParams->proceduralRecoilParams.arms); } float speedOverride = -1.f; GetWeapon()->PlayAction(GetFragmentIds().fire, 0, false, flags, speedOverride); CheckNearMisses(hit, pos, dir, (hit-pos).len(), 1.0f); CProjectile* pAmmo = m_pWeapon->SpawnAmmo(m_fireParams->fireparams.spawn_ammo_class, false); const EntityId weaponOwnerId = m_pWeapon->GetOwnerId(); EntityId ammoId = 0; if (pAmmo) { ammoId = pAmmo->GetEntityId(); CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId, string().Format("Invalid hit type '%s' in fire params for '%s'", m_fireParams->fireparams.hit_type.c_str(), m_pWeapon->GetEntity()->GetName())); CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId == g_pGame->GetGameRules()->GetHitTypeId(m_fireParams->fireparams.hit_type.c_str()), "Sanity Check Failed: Stored hit type id does not match the type string, possibly CacheResources wasn't called on this weapon type"); pAmmo->SetParams(CProjectile::SProjectileDesc( weaponOwnerId, m_pWeapon->GetHostId(), m_pWeapon->GetEntityId(), m_fireParams->fireparams.damage, m_fireParams->fireparams.damage_drop_min_distance, m_fireParams->fireparams.damage_drop_per_meter, m_fireParams->fireparams.damage_drop_min_damage, m_fireParams->fireparams.hitTypeId, m_fireParams->fireparams.bullet_pierceability_modifier, m_pWeapon->IsZoomed())); // this must be done after owner is set pAmmo->InitWithAI(); pAmmo->SetDestination(target); pAmmo->Launch(pos, dir, vel, m_speed_scale); m_projectileId = ammoId; if (clientIsShooter && pAmmo->IsPredicted() && gEnv->IsClient() && gEnv->bServer) { pAmmo->GetGameObject()->BindToNetwork(); } } if (m_pWeapon->IsServer()) { const char *ammoName = pAmmoClass != NULL ? pAmmoClass->GetName() : NULL; g_pGame->GetIGameFramework()->GetIGameplayRecorder()->Event(m_pWeapon->GetOwner(), GameplayEvent(eGE_WeaponShot, ammoName, 1, (void *)(EXPAND_PTR)m_pWeapon->GetEntityId())); } OnShoot(weaponOwnerId, ammoId, pAmmoClass, pos, dir, vel); if(playerIsShooter) { const SThermalVisionParams& thermalParams = m_fireParams->thermalVisionParams; m_pWeapon->AddShootHeatPulse(pOwnerActor, thermalParams.weapon_shootHeatPulse, thermalParams.weapon_shootHeatPulseTime, thermalParams.owner_shootHeatPulse, thermalParams.owner_shootHeatPulseTime); } m_muzzleEffect.Shoot(this, hit, m_barrelId); RecoilImpulse(pos, dir); m_fired = true; m_next_shot += m_next_shot_dt; if (++m_barrelId == m_fireParams->fireparams.barrel_count) m_barrelId = 0; ammoCount--; int clipSize = GetClipSize(); if (clipSize != -1) { if (clipSize!=0) m_pWeapon->SetAmmoCount(pAmmoClass, ammoCount); else m_pWeapon->SetInventoryAmmoCount(pAmmoClass, ammoCount); } m_pWeapon->RequestShoot(pAmmoClass, pos, dir, vel, hit, m_speed_scale, pAmmo? pAmmo->GetGameObject()->GetPredictionHandle() : 0, false); return true; }
bool CShotgun::Shoot(bool resetAnimation, bool autoreload/* =true */, bool isRemote) { CCCPOINT(Shotgun_TryShoot); m_firePending = false; m_shotIndex++; IEntityClass* ammo = m_fireParams->fireparams.ammo_type_class; int ammoCount = m_pWeapon->GetAmmoCount(ammo); int clipSize = GetClipSize(); if (clipSize == 0) ammoCount = m_pWeapon->GetInventoryAmmoCount(ammo); CActor *pActor = m_pWeapon->GetOwnerActor(); bool playerIsShooter = pActor ? pActor->IsPlayer() : false; bool shooterIsClient = pActor ? pActor->IsClient() : false; if (!CanFire(true)) { if ((ammoCount <= 0) && (!m_reloading)) { m_pWeapon->PlayAction(GetFragmentIds().empty_clip); m_pWeapon->OnFireWhenOutOfAmmo(); CCCPOINT(Shotgun_TryShootWhileOutOfAmmo); } else { CCCPOINT(Shotgun_TryShootWhileCannotBeFired); } return false; } if (m_reloading) { if(m_pWeapon->IsBusy()) m_pWeapon->SetBusy(false); if(CanFire(true) && !m_break_reload) { m_break_reload = true; m_pWeapon->RequestCancelReload(); } CCCPOINT(Shotgun_TryShootWhileReloading); return false; } uint32 flags = CItem::eIPAF_Default; if (IsProceduralRecoilEnabled() && pActor) { pActor->ProceduralRecoil(m_fireParams->proceduralRecoilParams.duration, m_fireParams->proceduralRecoilParams.strength, m_fireParams->proceduralRecoilParams.kickIn, m_fireParams->proceduralRecoilParams.arms); } float speedOverride = -1.f; m_pWeapon->PlayAction(GetFragmentIds().fire, 0, false, flags, speedOverride); Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE); Vec3 pos = GetFiringPos(hit); Vec3 fdir = GetFiringDir(hit, pos); Vec3 vel = GetFiringVelocity(fdir); Vec3 dir; const float hitDist = hit.GetDistance(pos); CheckNearMisses(hit, pos, fdir, WEAPON_HIT_RANGE, m_fireParams->shotgunparams.spread); CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId, string().Format("Invalid hit type '%s' in fire params for '%s'", m_fireParams->fireparams.hit_type.c_str(), m_pWeapon->GetEntity()->GetName())); CRY_ASSERT_MESSAGE(m_fireParams->fireparams.hitTypeId == g_pGame->GetGameRules()->GetHitTypeId(m_fireParams->fireparams.hit_type.c_str()), "Sanity Check Failed: Stored hit type id does not match the type string, possibly CacheResources wasn't called on this weapon type"); int quad = cry_random(0, 3); const int numPellets = m_fireParams->shotgunparams.pellets; std::vector<CProjectile*> projList; projList.reserve(numPellets); int ammoCost = (m_fireParams->fireparams.fake_fire_rate && playerIsShooter) ? m_fireParams->fireparams.fake_fire_rate : 1; ammoCost = min(ammoCost, ammoCount); EntityId firstAmmoId = 0; // SHOT HERE for (int i = 0; i < numPellets; i++) { CProjectile *pAmmo = m_pWeapon->SpawnAmmo(m_fireParams->fireparams.spawn_ammo_class, false); if (pAmmo) { if(!firstAmmoId) { firstAmmoId = pAmmo->GetEntityId(); } projList.push_back(pAmmo); dir = ApplySpread(fdir, m_fireParams->shotgunparams.spread, quad); quad = (quad+1)%4; int pelletDamage = m_fireParams->shotgunparams.pelletdamage; if (!playerIsShooter) pelletDamage += m_fireParams->shotgunparams.npc_additional_damage; const bool canOvercharge = m_pWeapon->GetSharedItemParams()->params.can_overcharge; const float overchargeModifier = pActor ? pActor->GetOverchargeDamageScale() : 1.0f; if (canOvercharge) { pelletDamage = int(pelletDamage * overchargeModifier); } CProjectile::SProjectileDesc projectileDesc( m_pWeapon->GetOwnerId(), m_pWeapon->GetHostId(), m_pWeapon->GetEntityId(), pelletDamage, m_fireParams->fireparams.damage_drop_min_distance, m_fireParams->fireparams.damage_drop_per_meter, m_fireParams->fireparams.damage_drop_min_damage, m_fireParams->fireparams.hitTypeId, m_fireParams->fireparams.bullet_pierceability_modifier, m_pWeapon->IsZoomed()); projectileDesc.pointBlankAmount = m_fireParams->fireparams.point_blank_amount; projectileDesc.pointBlankDistance = m_fireParams->fireparams.point_blank_distance; projectileDesc.pointBlankFalloffDistance = m_fireParams->fireparams.point_blank_falloff_distance; if (m_fireParams->fireparams.ignore_damage_falloff) projectileDesc.damageFallOffAmount = 0.0f; const Vec3 pelletDestination = pos + (dir * hitDist); pAmmo->SetParams(projectileDesc); pAmmo->SetDestination(m_pWeapon->GetDestination()); pAmmo->Launch(pos, dir, vel); pAmmo->CreateBulletTrail( pelletDestination ); pAmmo->SetKnocksTargetInfo( GetShared() ); if ((!m_fireParams->tracerparams.geometry.empty() || !m_fireParams->tracerparams.effect.empty()) && ((ammoCount == clipSize) || (ammoCount%m_fireParams->tracerparams.frequency==0))) { EmitTracer(pos, pelletDestination, &m_fireParams->tracerparams, pAmmo); } if(shooterIsClient) { pAmmo->RegisterLinkedProjectile(m_shotIndex); if(gEnv->bMultiplayer) { float damageCap = g_pGameCVars->pl_shotgunDamageCap; pAmmo->SetDamageCap(damageCap); } } m_projectileId = pAmmo->GetEntity()->GetId(); pAmmo->SetAmmoCost(ammoCost); } } if (m_pWeapon->IsServer()) { const char *ammoName = ammo != NULL ? ammo->GetName() : NULL; g_pGame->GetIGameFramework()->GetIGameplayRecorder()->Event(m_pWeapon->GetOwner(), GameplayEvent(eGE_WeaponShot, ammoName, m_fireParams->shotgunparams.pellets, (void *)(EXPAND_PTR)m_pWeapon->GetEntityId())); } m_muzzleEffect.Shoot(this, hit, m_barrelId); m_fired = true; SetNextShotTime(m_next_shot + m_next_shot_dt); ammoCount -= ammoCost; if (ammoCount < m_fireParams->fireparams.minimum_ammo_count) ammoCount = 0; if (clipSize != -1) { if (clipSize != 0) m_pWeapon->SetAmmoCount(ammo, ammoCount); else m_pWeapon->SetInventoryAmmoCount(ammo, ammoCount); } OnShoot(m_pWeapon->GetOwnerId(), firstAmmoId, ammo, pos, dir, vel); const SThermalVisionParams& thermalParams = m_fireParams->thermalVisionParams; m_pWeapon->AddShootHeatPulse(pActor, thermalParams.weapon_shootHeatPulse, thermalParams.weapon_shootHeatPulseTime, thermalParams.owner_shootHeatPulse, thermalParams.owner_shootHeatPulseTime); if (OutOfAmmo()) { m_pWeapon->OnOutOfAmmo(ammo); if (autoreload) { uint32 scheduleTime = max(m_pWeapon->GetCurrentAnimationTime(eIGS_Owner), (uint)(m_next_shot*1000)); m_pWeapon->GetScheduler()->TimerAction(scheduleTime, CSchedulerAction<ScheduleReload>::Create(ScheduleReload(this, m_pWeapon)), false); m_autoReloading = true; } } m_pWeapon->RequestShoot(ammo, pos, dir, vel, hit, 1.0f, 0, false); #if defined(ANTI_CHEAT) const int numProjectiles = projList.size(); uint32 shotId = m_pWeapon->GetLastShotId(); for(int i = 0; i < numProjectiles; i++) { CProjectile * pAmmo = projList[i]; pAmmo->SetShotId(shotId); shotId -= (1 << CWeapon::GetShotIdCountOffset()); } #endif CCCPOINT(Shotgun_Fired); return true; }