class BearTrap extends TrapBase { static const int RAYCAST_SOURCES_COUNT = 5; // Raycasts start positions: // Positions are local to model. Vertical offset prevents ground collision. static const vector m_RaycastSources[RAYCAST_SOURCES_COUNT] = { "0.0 0.1 0.0", // center "0.2 0.1 0.2", // north east "-.2 0.1 0.2", // north west "0.2 0.1 -0.2", // south east "-0.2 0.1 -0.2" // south west }; void BearTrap() { m_DamagePlayers = 5; // How much damage player gets when caught m_DamageOthers = 5; // How much damage other entities(CreatureAI) gets when caught m_DefectRate = 0; m_InitWaitTime = 0.0; // After this time after deployment, the trap is activated m_AnimationPhaseGrounded = "placing"; m_AnimationPhaseSet = "BearTrap_Set"; m_AnimationPhaseTriggered = "placing"; } override bool CanBeDisarmed() { return true; } override void EEHealthLevelChanged(int oldLevel, int newLevel, string zone) { super.EEHealthLevelChanged(oldLevel, newLevel, zone); if (GetGame().IsServer()) { if (newLevel == GameConstants.STATE_RUINED) { SetInactive(); } } } override void CreateTrigger() { super.CreateTrigger(); vector mins = "-0.1 -0.05 -0.1"; vector maxs = "0.1 0.4 0.1"; m_TrapTrigger.SetOrientation(GetOrientation()); m_TrapTrigger.SetExtents(mins, maxs); m_TrapTrigger.SetParentObject(this); } override void OnUpdate(EntityAI victim) { if (victim && victim.IsInherited(CarScript)) { EntityAI wheel = GetClosestCarWheel(victim); if (wheel) { OnServerSteppedOn(wheel, ""); } } } override void OnSteppedOn(EntityAI victim) { if (GetGame().IsServer() && victim) { if (!victim.GetAllowDamage()) return; if (victim.IsInherited(CarScript)) { //! CarScript specific reaction on BearTrap Param1 params = new Param1(victim); m_UpdateTimer.Run(UPDATE_TIMER_INTERVAL, this, "OnUpdate", params, true); return; } else { foreach (vector raycastSourcePosition: m_RaycastSources) { vector raycastStart = ModelToWorld(raycastSourcePosition); vector raycastEnd = "0 0.5 0" + raycastStart; RaycastRVParams rayInput = new RaycastRVParams(raycastStart, raycastEnd, this); rayInput.flags = CollisionFlags.ALLOBJECTS; rayInput.type = ObjIntersectFire; rayInput.radius = 0.05; array results = new array(); if (DayZPhysics.RaycastRVProxy(rayInput, results)) { foreach (RaycastRVResult result: results) { if (result.obj && !result.obj.IsDamageDestroyed() && !result.obj.IsAnyInherited({ItemBase, Plant})) { OnServerSteppedOn(result.obj, result.obj.GetDamageZoneNameByComponentIndex(result.component)); return; } } } } OnServerSteppedOn(victim, "zone_leg_random"); } } else if (!GetGame().IsDedicatedServer()) //! this is also called on client (OnRPC->SnapOn->OnSteppedOn chain) { if (victim) { if (victim.IsInherited(PlayerBase)) { victim.SpawnDamageDealtEffect(); } PlaySoundBiteLeg(); } } } override void OnSteppedOut(EntityAI victim) { if (victim.IsInherited(CarScript)) { if (m_UpdateTimer && m_UpdateTimer.IsRunning()) { m_UpdateTimer.Stop(); } } } protected void OnServerSteppedOn(Object obj, string damageZone) { if (obj.IsInherited(CarWheel)) { obj.ProcessDirectDamage(DamageType.CLOSE_COMBAT, this, damageZone, "BearTrapHit_CarWheel", "0 0 0", 1); if (m_UpdateTimer.IsRunning()) { m_UpdateTimer.Stop(); } SetInactive(false); Synch(EntityAI.Cast(obj)); return; } if (obj.IsDamageDestroyed()) return; string zoneUsed = damageZone; if (damageZone == "zone_leg_random") { zoneUsed = "LeftLeg"; if (Math.RandomIntInclusive(0, 1) == 1) zoneUsed = "RightLeg"; } //! Generic limp handling ZombieBase zombie; if (obj.IsInherited(PlayerBase) || (Class.CastTo(zombie,obj) && !zombie.IsCrawling() && Math.RandomIntInclusive(0, 1) == 1)) { CauseVictimToStartLimping(obj, ""); } obj.ProcessDirectDamage(DamageType.CLOSE_COMBAT, this, zoneUsed, "BearTrapHit", "0 0 0", 1); SetInactive(false); Synch(EntityAI.Cast(obj)); } // Causes the player to start limping. This is temporary and should at some point be replaced by broken legs void CauseVictimToStartLimping(Object obj, string damagedZone) { PlayerBase player; ZombieBase zombie; if (Class.CastTo(player,obj)) { player.DamageAllLegs(player.GetMaxHealth() * 2); //reduce legs health (not regular DamageSystem damage, does not transfer!) } else if (Class.CastTo(zombie,obj)) { zombie.SetHealth("LeftLeg", "Health", 0.0); zombie.SetHealth("RightLeg", "Health", 0.0); } } void PlaySoundBiteLeg() { EffectSound sound = SEffectManager.PlaySound("beartrapCloseDamage_SoundSet", GetPosition(), 0, 0, false); sound.SetAutodestroy(true); } void PlaySoundBiteEmpty() { EffectSound sound = SEffectManager.PlaySound("beartrapClose_SoundSet", GetPosition(), 0, 0, false); sound.SetAutodestroy(true); } void PlaySoundOpen() { EffectSound sound = SEffectManager.PlaySound("beartrapOpen_SoundSet", GetPosition(), 0, 0, false); sound.SetAutodestroy(true); } override void OnActivate() { #ifndef SERVER PlaySoundOpen(); #endif } override void OnDisarm() { #ifndef SERVER PlaySoundBiteEmpty(); #endif } //================================================================ // ADVANCED PLACEMENT //================================================================ override void OnPlacementComplete(Man player, vector position = "0 0 0", vector orientation = "0 0 0") { super.OnPlacementComplete(player, position, orientation); if (GetGame().IsServer()) { PlayerBase player_PB = PlayerBase.Cast(player); StartActivate(player_PB); } } override bool IsDeployable() { return true; } override string GetLoopDeploySoundset() { return "beartrap_deploy_SoundSet"; } override void SetActions() { super.SetActions(); AddAction(ActionClapBearTrapWithThisItem); AddAction(ActionTogglePlaceObject); AddAction(ActionDeployObject); } #ifdef DEVELOPER //================================================================ // DEBUG //================================================================ //Debug menu Spawn Ground Special override void OnDebugSpawn() { StartActivate(null); } override void GetDebugActions(out TSelectableActionInfoArrayEx outputList) { outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.ACTIVATE_ENTITY, "Activate", FadeColors.LIGHT_GREY)); outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.DEACTIVATE_ENTITY, "Deactivate", FadeColors.LIGHT_GREY)); outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.LIGHT_GREY)); super.GetDebugActions(outputList); } override bool OnAction(int action_id, Man player, ParamsReadContext ctx) { if (super.OnAction(action_id, player, ctx)) return true; if (GetGame().IsServer() || !GetGame().IsMultiplayer()) { if (action_id == EActions.ACTIVATE_ENTITY) { StartActivate(null); } else if (action_id == EActions.DEACTIVATE_ENTITY) { SetInactive(); } } return false; } #endif }