enum SoundTypeTrap { ACTIVATING = 5, } class TrapBase extends ItemBase { #ifdef SERVER protected const int SPAWN_FLAGS = ECE_CREATEPHYSICS; #else protected const int SPAWN_FLAGS = ECE_LOCAL; #endif protected const int DAMAGE_TRIGGER_MINE = 75; protected const float UPDATE_TIMER_INTERVAL = 0.05; float m_InitWaitTime; //After this time after deployment, the trap is activated bool m_NeedActivation; //If activation of trap is needed float m_DefectRate; //Added damage after trap activation float m_DamagePlayers; //How much damage player gets when caught float m_DamageOthers; //How much damage player gets when caught bool m_AddActivationDefect; // Damage trap after activation bool m_AddDeactivationDefect; // Damage trap after deactivation protected bool m_IsActive; // True means that the trap is ready to detonate protected bool m_IsInProgress; protected bool m_Disarmed = false; //! DEPRECATED Used for explosive traps to prevent detonation after destroying through disarm action bool m_WasActivatedOrDeactivated; string m_AnimationPhaseGrounded; string m_AnimationPhaseSet; string m_AnimationPhaseTriggered; string m_InfoSetup; string m_InfoDeactivated; string m_InfoDamageManipulation; string m_InfoDamage; string m_InfoActivationTime; protected ref Timer m_Timer; protected ref Timer m_UpdateTimer; protected TrapTrigger m_TrapTrigger; protected ref array m_ClothingDmg; void TrapBase() { m_IsInProgress = false; m_NeedActivation = true; m_InitWaitTime = 5; //After this time after deployment, the trap is activated m_DefectRate = 15; //Added damage after trap activation m_DamagePlayers = 25; //How much damage player gets when caught m_DamageOthers = 100; //How much damage others gets when caught m_AddActivationDefect = false; m_AddDeactivationDefect = false; m_WasActivatedOrDeactivated = false; m_AnimationPhaseGrounded = ""; m_AnimationPhaseSet = ""; m_AnimationPhaseTriggered = ""; m_InfoSetup = "#STR_TrapBase0"; m_InfoDeactivated = "#STR_TrapBase1"; m_InfoDamageManipulation = "#STR_TrapBase2"; m_InfoDamage = "#STR_TrapBase3"; m_InfoActivationTime = "#STR_TrapBase4" + m_InitWaitTime.ToString() + "#STR_TrapBase5"; m_UpdateTimer = new ref Timer(); //! timer calling OnUpdate in configured interval RegisterNetSyncVariableBool("m_IsActive"); RegisterNetSyncVariableBool("m_IsInProgress"); } void OnUpdate(EntityAI victim); TrapTrigger GetTrapTrigger() { return m_TrapTrigger; } //! this event is called all variables are synchronized on client override void OnVariablesSynchronized() { super.OnVariablesSynchronized(); if (GetGame().IsMultiplayer()) { if (m_IsActive && !m_IsInProgress) SetActive(); if (m_IsInProgress && !m_IsActive) StartActivate(null); } } override void EEDelete(EntityAI parent) { super.EEDelete(parent); if (GetGame() && m_TrapTrigger) { GetGame().ObjectDelete(m_TrapTrigger); m_TrapTrigger = null; } } override void OnStoreSave(ParamsWriteContext ctx) { super.OnStoreSave(ctx); ctx.Write(m_IsActive); ctx.Write(m_IsInProgress); } //---------------------------------------------------------------- override bool OnStoreLoad(ParamsReadContext ctx, int version) { if ( !super.OnStoreLoad(ctx, version) ) return false; bool b_is_active = false; if ( !ctx.Read( b_is_active ) ) b_is_active = false; bool b_is_in_progress = false; if ( !ctx.Read( b_is_in_progress ) ) b_is_in_progress = false; if ( b_is_active ) { SetActive(); } if (b_is_in_progress && !b_is_active) { StartActivate(null); } return true; } bool IsActive() { return m_IsActive && m_IsInProgress == false && GetHierarchyRootPlayer() == null; } bool IsInactive() { return !IsActive() && m_IsInProgress == false && GetHierarchyRootPlayer() == null; } // trap cannot be taken when is activated override bool IsTakeable() { if ( m_IsInProgress == false && !IsActive() ) { return true; } return false; } bool IsActivable() { return !IsActive() && GetHierarchyRootPlayer() == null && GetHierarchyParent() == null && m_IsInProgress == false && !IsRuined() && m_NeedActivation; } bool IsPlaceable() { if ( GetHierarchyRootPlayer() != null && GetHierarchyRootPlayer().GetHumanInventory().GetEntityInHands() == this ) { PlayerBase player = PlayerBase.Cast( GetHierarchyRootPlayer() ); vector player_pos = player.GetPosition(); vector aim_pos = player.GetAimPosition(); if ( vector.DistanceSq( player_pos, aim_pos ) <= ( Math.SqrFloat( 1.5 ) ) ) { return IsPlaceableAtPosition( aim_pos ); } } return false; } bool IsPlaceableAtPosition( vector position ) { if ( position[1] < g_Game.SurfaceGetSeaLevelMax() + 0.03 ) { return false; } else if ( GetGame().SurfaceIsPond( position[0], position[2] ) ) { return false; } return true; } void Disarm() { SetInactive(false); RefreshState(); GetGame().RPCSingleParam(this, ERPCs.RPC_TRAP_DISARM, null, true); OnDisarm(); } //! also called from RPC on client void OnDisarm(); void SnapOnObject(EntityAI victim) { if ( GetGame().IsServer() ) { if ( m_Timer ) { m_Timer.Stop(); } RefreshState(); if (m_DamagePlayers > 0) { if (victim) { if ( victim.IsInherited(SurvivorBase)) { victim.DecreaseHealth("", "", m_DamagePlayers); } else if (victim.IsInherited(DayZCreatureAI)) { victim.DecreaseHealth("", "", m_DamageOthers); } else if (victim.IsInherited(ItemBase)) { ItemBase victim_item = ItemBase.Cast(victim); float damage_coef = 1; if (victim_item.HasQuantity() && victim_item.GetQuantityMax() != 0 && victim_item.GetQuantity() > 0) { damage_coef = victim_item.GetQuantityMax() / victim_item.GetQuantity(); // Lower quantity increases damage exposure } if (damage_coef > 0) { int item_size_x = 1; int item_size_y = 1; GetGame().GetInventoryItemSize(victim_item, item_size_x, item_size_y); float add_damage = 300 * damage_coef / Math.Clamp(item_size_x * item_size_y, 1, int.MAX); victim_item.DecreaseHealth("", "", add_damage); } } } } Synch(victim); } OnSteppedOn(victim); } void RemoveFromObject(EntityAI victim) { OnSteppedOut(victim); } void OnSteppedOn(EntityAI victim) { SetInactive(false); } void OnSteppedOut(EntityAI victim); //! keeping "step" here for consistency only // Synchronizes states protected void Synch(EntityAI victim) { if (GetGame().IsServer()) { if (victim && !victim.GetAllowDamage()) return; Param1 p = new Param1(victim); GetGame().RPCSingleParam(this, ERPCs.RPC_TRAP_VICTIM, p, true); } } // On server -> client synchronization override void OnRPC(PlayerIdentity sender, int rpc_type, ParamsReadContext ctx) { super.OnRPC(sender, rpc_type, ctx); if ( !GetGame().IsDedicatedServer() ) { switch (rpc_type) { case ERPCs.RPC_TRAP_VICTIM: Param1 victim = new Param1(null); if (ctx.Read(victim)) { if (victim.param1) SnapOnObject(victim.param1); } break; case ERPCs.RPC_TRAP_DISARM: OnDisarm(); break; case SoundTypeTrap.ACTIVATING: Param1 p = new Param1(false); bool isActivating = false; if (ctx.Read(p)) isActivating = p.param1; break; } } } void RefreshState() { if ( !m_WasActivatedOrDeactivated ) { return; } if ( GetGame().IsServer() ) { // item is owned by player if ( GetHierarchyRootPlayer() != NULL && m_AnimationPhaseGrounded != "" ) { SetAnimationPhase( m_AnimationPhaseSet, 1 ); if ( m_AnimationPhaseTriggered != m_AnimationPhaseGrounded ) { SetAnimationPhase( m_AnimationPhaseTriggered, 1 ); } SetAnimationPhase( m_AnimationPhaseGrounded, 0 ); } // item is set active else if ( IsActive() ) { if ( m_AnimationPhaseGrounded != "" ) { SetAnimationPhase( m_AnimationPhaseGrounded, 1 ); } if ( m_AnimationPhaseSet != "" && m_AnimationPhaseTriggered != "" ) { SetAnimationPhase( m_AnimationPhaseTriggered, 1 ); SetAnimationPhase( m_AnimationPhaseSet, 0 ); } } // item is inactive and not owned by player (on the ground) else if ( IsInactive() ) { if ( m_AnimationPhaseGrounded != "" && m_AnimationPhaseTriggered != m_AnimationPhaseGrounded ) { SetAnimationPhase( m_AnimationPhaseGrounded, 1 ); } if ( m_AnimationPhaseSet != "" && m_AnimationPhaseTriggered != "" ) { SetAnimationPhase( m_AnimationPhaseSet, 1 ); SetAnimationPhase( m_AnimationPhaseTriggered, 0 ); } } } } void SetupTrap() { if (GetGame().IsServer()) { if (GetHierarchyRootPlayer() && GetHierarchyRootPlayer().CanDropEntity(this)) SetupTrapPlayer(PlayerBase.Cast(GetHierarchyRootPlayer())); } } void SetupTrapPlayer( PlayerBase player, bool set_position = true ) { if (GetGame().IsServer()) { if (set_position) { player.LocalDropEntity(this); vector trapPos = player.GetDirection() * 1.5; trapPos[1] = 0; SetPosition(player.GetPosition() + trapPos); } if (m_NeedActivation == false) SetActive(); } } void AddDefect() { if ( GetGame().IsServer() ) { DecreaseHealth( "", "", m_DefectRate ); } } void SetActive() { m_WasActivatedOrDeactivated = true; m_IsInProgress = false; m_IsActive = true; if (m_AddActivationDefect) { AddDefect(); } if (GetGame().IsServer()) { CreateTrigger(); RefreshState(); SetSynchDirty(); } OnActivate(); } void OnActivate(); void StartActivate(PlayerBase player) { if (GetGame().IsServer()) { m_Timer = new Timer(CALL_CATEGORY_SYSTEM); HideSelection("safety_pin"); if (m_InitWaitTime > 0) { m_IsInProgress = true; m_Timer.Run(m_InitWaitTime, this, "SetActive"); SetSynchDirty(); } else SetActive(); } } void StartDeactivate(PlayerBase player); void SetInactive(bool stop_timer = true) { m_WasActivatedOrDeactivated = true; m_IsActive = false; if (m_Timer && stop_timer) m_Timer.Stop(); if (m_AddDeactivationDefect) AddDefect(); SetSynchDirty(); DeleteTrigger(); RefreshState(); } void CreateTrigger() { if (Class.CastTo(m_TrapTrigger, GetGame().CreateObjectEx("TrapTrigger", GetPosition(), SPAWN_FLAGS))) { vector mins = "-0.01 -0.05 -0.01"; vector maxs = "0.01 0.5 0.01"; m_TrapTrigger.SetOrientation(GetOrientation()); m_TrapTrigger.SetExtents(mins, maxs); m_TrapTrigger.SetParentObject(this); GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).Call(DeferredEnableTrigger); } } void DeleteTrigger() { if (m_TrapTrigger) { m_TrapTrigger.SetParentObject(null); m_TrapTrigger.DeleteSafe(); } } void DeferredEnableTrigger() { if (m_TrapTrigger) m_TrapTrigger.SetEnabled(); } override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner) { super.OnItemLocationChanged(old_owner, new_owner); if (GetGame().IsServer()) { RefreshState(); // TAKE ACTIVE TRAP FROM VICINITY if (old_owner == NULL && new_owner != NULL && IsActive()) { // TAKE INTO HANDS if ( new_owner.IsPlayer() ) { SnapOnObject(new_owner); } else if (new_owner.GetHierarchyRootPlayer()) { SnapOnObject(new_owner.GetHierarchyRootPlayer()); } } } } override void EEItemAttached(EntityAI item, string slot_name) { super.EEItemAttached(item, slot_name); if (GetGame().IsServer()) RefreshState(); } override void EEItemDetached(EntityAI item, string slot_name) { super.EEItemDetached(item, slot_name); if (GetGame().IsServer()) RefreshState(); } override void OnPlacementComplete(Man player, vector position = "0 0 0", vector orientation = "0 0 0") { super.OnPlacementComplete(player, position, orientation); if (GetGame().IsServer()) { SetOrientation(orientation); SetPosition(position); PlaceOnSurface(); SetSynchDirty(); } } override bool CanPutInCargo( EntityAI parent ) { if ( !super.CanPutInCargo(parent) ) { return false; } return IsTakeable(); } override bool CanPutIntoHands( EntityAI parent ) { if ( !super.CanPutIntoHands( parent ) ) { return false; } return IsTakeable(); } override bool CanRemoveFromHands( EntityAI parent ) { return IsTakeable(); } override bool CanBePlaced( Man player, vector position ) { return IsPlaceableAtPosition( position ); } //! DEPRECATED Set if trap can be disarmed using ActionClapBearTrapWithThisItem bool CanBeClapped() { return true; } //Set if trap can be disarmed using trap-specific action bool CanBeDisarmed() { return false; } //! DEPRECATED void SetDisarmed( bool disarmed ) { m_Disarmed = disarmed; } //! DEPRECATED bool GetDisarmed() { return m_Disarmed; } //================================================================ // ADVANCED PLACEMENT //================================================================ override void SetActions() { super.SetActions(); AddAction(ActionActivateTrap); } // HELPERS protected EntityAI GetClosestCarWheel(EntityAI victim) { //! carscript specific handling (not all traps are uses this) vector trapPosXZ = GetPosition(); trapPosXZ[1] = 0; GameInventory inv = victim.GetInventory(); for (int i = 0; i < inv.AttachmentCount(); i++) { //! ruined wheel, bail out EntityAI wheelEntity = inv.GetAttachmentFromIndex(i); if (wheelEntity && wheelEntity.Type() == CarWheel_Ruined) { continue; } //! ignore all spare wheel int slotId; string slotName; wheelEntity.GetInventory().GetCurrentAttachmentSlotInfo(slotId, slotName); slotName.ToLower(); if (slotName.Contains("spare")) { continue } //! actual, healthy wheel, let it pass if (wheelEntity && wheelEntity.IsInherited(CarWheel)) { vector entPosXZ = wheelEntity.GetPosition(); entPosXZ[1] = 0; if (vector.Distance(trapPosXZ, entPosXZ) < 1) { return wheelEntity; } } } return null; } protected void DamageClothing(PlayerBase player) { //Array used to find all relevant information about currently equipped clothes array equippedClothes = new array; equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("LEGS"))); equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("BACK"))); equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("VEST"))); equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("HeadGear"))); equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("Mask"))); equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("BODY"))); equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("FEET"))); equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("GLOVES"))); //Damage all currently equipped clothes for (int i = 0; i < equippedClothes.Count(); i++) { //If no item is equipped on slot, slot is ignored if (equippedClothes[i] == null) { continue; } equippedClothes[i].DecreaseHealth(m_ClothingDmg[i], false); } } //!DEPRECATED protected ref EffectSound m_DeployLoopSound; //DEPRECATED in favor of m_DeployLoopSoundEx void PlayDeployLoopSound(); //!DEPRECATED void StopDeployLoopSound(); //!DEPRECATED }