1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150 |
- class ZombieBase extends DayZInfected
- {
- const float TARGET_CONE_ANGLE_CHASE = 20;
- const float TARGET_CONE_ANGLE_FIGHT = 30;
- const float ORIENTATION_SYNC_THRESHOLD = 30; //threshold for local heading/orientation sync
-
- const float SHOCK_TO_STUN_MULTIPLIER = 2.82;
- //! server / singleplayer properties
- protected int m_StanceVariation = 0;
- protected int m_LastMindState = -1;
- protected float m_LastMovementSpeed = -1;
-
- protected bool m_KnuckleLand = false;
- protected float m_KnuckleOutTimer = 0;
- protected int m_MindState = -1;
- protected int m_OrientationLocal = -1; //local 'companion' value for sync checking
- protected int m_OrientationSynced = -1;
- protected float m_OrientationTimer;
- protected float m_MovementSpeed = -1;
-
- protected vector m_DefaultHitPosition;
- protected float m_DeltaTime;
-
- protected AbstractWave m_LastSoundVoiceAW;
- protected ref InfectedSoundEventHandler m_InfectedSoundEventHandler;
- protected ref array<Object> m_AllTargetObjects;
- protected ref array<typename>m_TargetableObjects;
-
- //static ref map<int,ref array<string>> m_FinisherSelectionMap; //! which selections in the FireGeometry trigger which finisher on hit (when applicable)
-
- protected bool m_IsCrawling; //'DayZInfectedCommandCrawl' is transition to crawl only, 'DayZInfectedCommandMove' used after that, hence this VARIABLE_WET
-
- protected bool m_FinisherInProgress = false; //is this object being backstabbed?
-
- protected ref ArrowManagerBase m_ArrowManager;
- //-------------------------------------------------------------
- void ZombieBase()
- {
- Init();
- }
-
- void Init()
- {
- SetEventMask(EntityEvent.INIT);
-
- m_IsCrawling = false;
-
- RegisterNetSyncVariableInt("m_MindState", -1, 4);
- RegisterNetSyncVariableInt("m_OrientationSynced", 0, 359);
- RegisterNetSyncVariableFloat("m_MovementSpeed", -1, 3);
- RegisterNetSyncVariableBool("m_IsCrawling");
-
- //! sets default hit position and cache it here (mainly for impact particles)
- m_DefaultHitPosition = SetDefaultHitPosition(GetDayZInfectedType().GetDefaultHitPositionComponent());
- //! client only
- if ( !GetGame().IsDedicatedServer() )
- {
- m_LastSoundVoiceAW = null;
- m_InfectedSoundEventHandler = new InfectedSoundEventHandler(this);
- }
- m_AllTargetObjects = new array<Object>;
- m_TargetableObjects = new array<typename>;
- m_TargetableObjects.Insert(PlayerBase);
- m_TargetableObjects.Insert(AnimalBase);
-
- m_OrientationTimer = 0;
-
- m_ArrowManager = new ArrowManagerBase(this);
- }
-
- //! synced variable(s) handler
- override void OnVariablesSynchronized()
- {
- DebugSound("[Infected @ " + this + "][OnVariablesSynchronized]");
- HandleSoundEvents();
-
- if ( m_OrientationLocal != m_OrientationSynced )
- {
- m_OrientationLocal = m_OrientationSynced;
- }
- }
- //-------------------------------------------------------------
- override void EOnInit(IEntity other, int extra)
- {
- if ( !GetGame().IsMultiplayer() || GetGame().IsServer() )
- {
- m_StanceVariation = Math.RandomInt(0, 4);
-
- DayZInfectedCommandMove moveCommand = GetCommand_Move();
- moveCommand.SetStanceVariation(m_StanceVariation);
- }
- }
-
- override bool IsZombie()
- {
- return true;
- }
-
- override bool IsDanger()
- {
- return true;
- }
-
- override bool IsZombieMilitary()
- {
- return false;
- }
-
- bool IsMale()
- {
- return true;
- }
-
- override bool CanBeBackstabbed()
- {
- return true;
- }
-
- //-------------------------------------------------------------
- override AnimBootsType GetBootsType()
- {
- return AnimBootsType.Boots;
- }
-
- override bool CanBeSkinned()
- {
- return false;
- }
- //-------------------------------------------------------------
- override bool IsHealthVisible()
- {
- return false;
- }
- //-------------------------------------------------------------
- override bool IsRefresherSignalingViable()
- {
- return false;
- }
-
- override bool IsSelfAdjustingTemperature()
- {
- return IsAlive();
- }
- //! returns hit component for attacking AI
- override string GetHitComponentForAI()
- {
- return GetDayZInfectedType().GetHitComponentForAI();
- }
- //! returns default hit component (fallback)
- override string GetDefaultHitComponent()
- {
- return GetDayZInfectedType().GetDefaultHitComponent();
- }
- override vector GetDefaultHitPosition()
- {
- return m_DefaultHitPosition;
- }
-
- protected vector SetDefaultHitPosition(string pSelection)
- {
- return GetSelectionPositionMS(pSelection);
- }
- //! returns suitable hit components for finisher attacks; DEPRECATED
- override array<string> GetSuitableFinisherHitComponents()
- {
- return GetDayZInfectedType().GetSuitableFinisherHitComponents();
- }
-
- int GetMindStateSynced()
- {
- return m_MindState;
- }
-
- //! returns rounded zombie yaw for sync purposes
- int GetOrientationSynced()
- {
- return m_OrientationSynced;
- }
- //-------------------------------------------------------------
- //!
- //! CommandHandler
- //!
- void CommandHandler(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
- {
- m_DeltaTime = pDt;
-
- //! for mods
- if ( ModCommandHandlerBefore(pDt, pCurrentCommandID, pCurrentCommandFinished) )
- {
- return;
- }
- //! handle death
- if ( pCurrentCommandID != DayZInfectedConstants.COMMANDID_DEATH )
- {
- if ( HandleDeath(pCurrentCommandID) )
- return;
- }
- else if (!pCurrentCommandFinished)
- {
- return;
- }
-
- //! movement handler (just for sync now)
- HandleMove(pCurrentCommandID);
- HandleOrientation(pDt,pCurrentCommandID);
-
- //! handle finished commands
- if (pCurrentCommandFinished)
- {
- //! default behaviour after finish is to start move
- DayZInfectedCommandMove moveCommand = StartCommand_Move();
- moveCommand.SetStanceVariation(m_StanceVariation);
-
- return;
- }
-
- //! for mods
- if ( ModCommandHandlerInside(pDt, pCurrentCommandID, pCurrentCommandFinished) )
- {
- return;
- }
-
- //! crawl transition
- if ( HandleCrawlTransition(pCurrentCommandID) )
- {
- return;
- }
-
- //! damage hits
- if ( HandleDamageHit(pCurrentCommandID) )
- {
- return;
- }
-
- DayZInfectedInputController inputController = GetInputController();
- if ( inputController )
- {
- if ( HandleVault(pCurrentCommandID, inputController, pDt) )
- {
- return;
- }
-
- if ( HandleMindStateChange(pCurrentCommandID, inputController, pDt) )
- {
- return;
- }
-
- if ( FightLogic(pCurrentCommandID, inputController, pDt) )
- {
- return;
- }
- }
-
- //!
- if ( ModCommandHandlerAfter(pDt, pCurrentCommandID, pCurrentCommandFinished) )
- {
- return;
- }
- }
- //-------------------------------------------------------------
- //!
- //! CommandHandlerDebug
- //!
- void CommandHandlerDebug(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
- {
- if ( GetPluginManager() )
- {
- PluginDayZInfectedDebug infectedDebug = PluginDayZInfectedDebug.Cast(GetPluginManager().GetPluginByType(PluginDayZInfectedDebug));
- if ( infectedDebug )
- infectedDebug.CommandHandler(this);
- }
- }
- //-------------------------------------------------------------
- //!
- //! HandleMove
- //!
-
- void HandleMove(int pCurrentCommandID)
- {
- DayZInfectedInputController ic = GetInputController();
- m_MovementSpeed = ic.GetMovementSpeed();
- if (Math.AbsFloat(m_LastMovementSpeed - m_MovementSpeed) >= 0.9 && m_LastMovementSpeed != m_MovementSpeed)
- {
- SetSynchDirty();
- }
-
- m_LastMovementSpeed = m_MovementSpeed;
- }
-
- //-------------------------------------------------------------
- //!
- //! HandleOrientation
- //!
-
- void HandleOrientation(float pDt, int pCurrentCommandID)
- {
- m_OrientationTimer += pDt;
-
- int yaw = Math.Round(GetOrientation()[0]);
- yaw = Math.NormalizeAngle(yaw);
-
- //atan2(sin(x-y), cos(x-y))
- float angleSourceRad = m_OrientationSynced * Math.DEG2RAD;
- float angleTargetRad = yaw * Math.DEG2RAD;
-
- float angleDiffRad = Math.Atan2(Math.Sin(angleTargetRad - angleSourceRad), Math.Cos(angleSourceRad - angleTargetRad));
- angleDiffRad *= Math.RAD2DEG;
- angleDiffRad = Math.Round(angleDiffRad);
-
- if (m_OrientationTimer >= 2.0 || m_OrientationSynced == -1 || Math.AbsInt(angleDiffRad) > ORIENTATION_SYNC_THRESHOLD)
- {
- m_OrientationTimer = 0.0;
-
- if (m_OrientationSynced == -1 || Math.AbsInt(angleDiffRad) > 5)
- {
- m_OrientationSynced = yaw;
- SetSynchDirty();
- }
- }
- }
-
- //-------------------------------------------------------------
- //!
- //! HandleDeath
- //!
- float m_DamageHitDirection = 0;
- int m_DeathType = 0;
- bool HandleDeath(int pCurrentCommandID)
- {
- if ( !IsAlive() || m_FinisherInProgress )
- {
- StartCommand_Death(m_DeathType, m_DamageHitDirection);
- m_MovementSpeed = -1;
- m_MindState = -1;
- SetSynchDirty();
- return true;
- }
- return false;
- }
-
- bool EvaluateDeathAnimationEx(EntityAI pSource, ZombieHitData data, out int pAnimType, out float pAnimHitDir)
- {
- bool ret = EvaluateDeathAnimation(pSource,data.m_DamageZone,data.m_AmmoType,pAnimType,pAnimHitDir);
-
- return ret;
- }
-
- bool EvaluateDeathAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType, out float pAnimHitDir)
- {
- //!
- bool doPhxImpulse = GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " doPhxImpulse") > 0;
-
- //! anim type
- pAnimType = doPhxImpulse;
-
- //! direction
- pAnimHitDir = ComputeHitDirectionAngle(pSource);
-
- //! add some impulse if needed
- if ( doPhxImpulse )
- {
- vector impulse = 80 * m_TransportHitVelocity;
- impulse[1] = 80 * 1.5;
- //Print("Impulse: " + impulse.ToString());
-
- dBodyApplyImpulse(this, impulse);
- }
-
- return true;
- }
-
- //-------------------------------------------------------------
- //!
- //! HandleVault
- //!
-
- int m_ActiveVaultType = -1;
-
- int GetVaultType(float height)
- {
- if ( height <= 0.6 )
- return 0;
- else if ( height <= 1.1 )
- return 1;
- else if ( height <= 1.6 )
- return 2;
- else
- return 3;
- }
-
- bool HandleVault(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
- {
- if ( pCurrentCommandID == DayZInfectedConstants.COMMANDID_VAULT )
- {
- DayZInfectedCommandVault vaultCmd = GetCommand_Vault();
- if ( vaultCmd && vaultCmd.WasLand() )
- {
- m_KnuckleOutTimer = 0;
- m_KnuckleLand = true;
- }
- if ( m_KnuckleLand )
- {
- m_KnuckleOutTimer += pDt;
- if ( m_KnuckleOutTimer > 2.0 )
- StartCommand_Vault(-1);
- }
-
- return true;
- }
-
- if ( pInputController.IsVault() )
- {
- float vaultHeight = pInputController.GetVaultHeight();
- int vaultType = GetVaultType(vaultHeight);
- m_KnuckleLand = false;
- StartCommand_Vault(vaultType);
- return true;
- }
-
- return false;
- }
-
- //-------------------------------------------------------------
- //!
- //! Mind state change
- //!
- bool HandleMindStateChange(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
- {
- DayZInfectedCommandMove moveCommand = GetCommand_Move();
-
- m_MindState = pInputController.GetMindState();
- if ( m_LastMindState != m_MindState )
- {
- switch ( m_MindState )
- {
- case DayZInfectedConstants.MINDSTATE_CALM:
- if ( moveCommand && !moveCommand.IsTurning() )
- moveCommand.SetIdleState(0);
- break;
- case DayZInfectedConstants.MINDSTATE_DISTURBED:
- if ( moveCommand && !moveCommand.IsTurning() )
- moveCommand.SetIdleState(1);
- break;
-
- case DayZInfectedConstants.MINDSTATE_CHASE:
- if ( moveCommand && !moveCommand.IsTurning() && (m_LastMindState < DayZInfectedConstants.MINDSTATE_CHASE) )
- moveCommand.SetIdleState(2);
- break;
- }
-
- m_LastMindState = m_MindState;
- m_AttackCooldownTime = 0.0;
- SetSynchDirty();
- }
- return false;
- }
- //-------------------------------------------------------------
- //!
- //! Sound (client only)
- //!
-
- protected void HandleSoundEvents()
- {
- //! no sound handler - bail out
- if ( !m_InfectedSoundEventHandler )
- {
- return;
- }
- //! infected is dead
- if ( !IsAlive() )
- {
- //! stop all sounds
- m_InfectedSoundEventHandler.Stop();
- return;
- }
- switch ( m_MindState )
- {
- case DayZInfectedConstants.MINDSTATE_CALM:
- m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_CALM_MOVE);
- break;
- case DayZInfectedConstants.MINDSTATE_ALERTED:
- m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_ALERTED_MOVE);
- break;
- case DayZInfectedConstants.MINDSTATE_DISTURBED:
- m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_DISTURBED_IDLE);
- break
- case DayZInfectedConstants.MINDSTATE_CHASE:
- m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_CHASE_MOVE);
- break;
- default:
- m_InfectedSoundEventHandler.Stop();
- break;
- }
-
- DebugSound("[Infected @ " + this + "][MindState]" + typename.EnumToString(DayZInfectedConstants, m_MindState));
- DebugSound("[Infected @ " + this + "][SoundEventID]" + typename.EnumToString(EInfectedSoundEventID, m_InfectedSoundEventHandler.GetCurrentStateEventID()));
- }
- AbstractWave ProcessVoiceFX(string pSoundSetName)
- {
- SoundParams soundParams;
- SoundObjectBuilder soundObjectBuilder;
- SoundObject soundObject;
- if (!GetGame().IsDedicatedServer())
- {
- soundParams = new SoundParams( pSoundSetName );
- if ( !soundParams.IsValid() )
- {
- //SoundError("Invalid sound set.");
- return null;
- }
-
- soundObjectBuilder = new SoundObjectBuilder( soundParams );
- soundObject = soundObjectBuilder.BuildSoundObject();
- AttenuateSoundIfNecessary(soundObject);
- return PlaySound(soundObject, soundObjectBuilder);
- }
- return null;
- }
- override void OnSoundVoiceEvent(int event_id, string event_user_string)
- {
- //super.OnSoundVoiceEvent(event_id, event_user_string);
- AnimSoundVoiceEvent voice_event = GetCreatureAIType().GetSoundVoiceEvent(event_id);
- if (voice_event != null)
- {
- //! stop state sound when playing anim SoundVoice
- if (m_InfectedSoundEventHandler) // && m_InfectedSoundEventHandler.IsPlaying())
- {
- m_InfectedSoundEventHandler.Stop();
- DebugSound("[Infected @ " + this + "][SoundEvent] InfectedSoundEventHandler - stop all");
- }
- //! stop playing of old SoundVoice from anim (if any)
- if (m_LastSoundVoiceAW != null)
- {
- DebugSound("[Infected @ " + this + "][AnimVoiceEvent] Stopping LastAW");
- m_LastSoundVoiceAW.Stop();
- }
-
- //! play new SoundVoice from anim
- ProcessSoundVoiceEvent(voice_event, m_LastSoundVoiceAW);
-
- HandleSoundEvents();
- }
- }
-
- protected void ProcessSoundVoiceEvent(AnimSoundVoiceEvent sound_event, out AbstractWave aw)
- {
- if (!GetGame().IsDedicatedServer())
- {
- SoundObjectBuilder objectBuilder = sound_event.GetSoundBuilder();
- if (NULL != objectBuilder)
- {
- objectBuilder.AddEnvSoundVariables(GetPosition());
- SoundObject soundObject = objectBuilder.BuildSoundObject();
- AttenuateSoundIfNecessary(soundObject);
- aw = PlaySound(soundObject, objectBuilder);
- }
- }
-
- if (GetGame().IsServer())
- {
- if (sound_event.m_NoiseParams != NULL)
- GetGame().GetNoiseSystem().AddNoise(this, sound_event.m_NoiseParams, NoiseAIEvaluate.GetNoiseReduction(GetGame().GetWeather()));
- }
- }
-
- //-------------------------------------------------------------
- //!
- //! Combat
- //!
-
- EntityAI m_ActualTarget = null;
- float m_AttackCooldownTime = 0;
- DayZInfectedAttackType m_ActualAttackType = null;
-
- bool FightLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
- {
- if (pCurrentCommandID == DayZInfectedConstants.COMMANDID_MOVE)
- {
- // we attack only in chase & fight state
- int mindState = pInputController.GetMindState();
- if (mindState == DayZInfectedConstants.MINDSTATE_CHASE)
- {
- return ChaseAttackLogic(pCurrentCommandID, pInputController, pDt);
- }
- else if (mindState == DayZInfectedConstants.MINDSTATE_FIGHT)
- {
- return FightAttackLogic(pCurrentCommandID, pInputController, pDt);
- }
- }
- else if (pCurrentCommandID == DayZInfectedConstants.COMMANDID_ATTACK)
- {
- DayZInfectedCommandAttack attackCommand = GetCommand_Attack();
- if (attackCommand && attackCommand.WasHit())
- {
- if (m_ActualTarget != null)
- {
- if (m_ActualTarget.GetMeleeTargetType() == EMeleeTargetType.NONALIGNABLE)
- return false;
- bool playerInBlockStance = false;
- vector targetPos = m_ActualTarget.GetPosition();
- vector hitPosWS = targetPos;
- vector zombiePos = GetPosition();
- PlayerBase playerTarget = PlayerBase.Cast(m_ActualTarget);
- if (playerTarget)
- {
- playerInBlockStance = playerTarget.GetMeleeFightLogic() && playerTarget.GetMeleeFightLogic().IsInBlock();
- }
- if (vector.DistanceSq(targetPos, zombiePos) <= m_ActualAttackType.m_Distance * m_ActualAttackType.m_Distance)
- {
- //! player is in block stance and facing the infected
- if (playerInBlockStance && (Math.RAD2DEG * Math.AbsFloat(Math3D.AngleFromPosition(targetPos, MiscGameplayFunctions.GetHeadingVector(playerTarget), zombiePos))) <= GameConstants.AI_MAX_BLOCKABLE_ANGLE)
- {
- //! infected is playing heavy attack - decrease the dmg to light
- if (m_ActualAttackType.m_IsHeavy == 1)
- {
- hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition()); //! override hit pos by pos defined in type
- DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), "MeleeZombie", hitPosWS);
- }
- else
- {
- //! infected is playing light attack - do not send damage, play animation instead
- hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
- DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), "Dummy_Light", hitPosWS);
- }
- }
- else
- {
- hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition()); //! override hit pos by pos defined in type
- DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), m_ActualAttackType.m_AmmoType, hitPosWS);
- }
- }
- }
- }
-
- return true;
- }
-
- return false;
- }
-
- bool ChaseAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
- {
- // always update target - it can be destroyed
- m_ActualTarget = pInputController.GetTargetEntity();
-
- //! do not attack players in vehicle - hotfix
- PlayerBase pb = PlayerBase.Cast(m_ActualTarget);
- if ( pb && pb.GetCommand_Vehicle() )
- {
- return false;
- }
- if ( m_ActualTarget == NULL )
- return false;
-
- vector targetPos = m_ActualTarget.GetPosition();
- if ( !CanAttackToPosition(targetPos) )
- return false;
-
- float targetDist = vector.Distance(targetPos, this.GetPosition());
- int pitch = GetAttackPitch(m_ActualTarget);
-
- m_ActualAttackType = GetDayZInfectedType().ChooseAttack(DayZInfectedAttackGroupType.CHASE, targetDist, pitch);
- if (m_ActualAttackType)
- {
- Object target = DayZPlayerUtils.GetMeleeTarget(this.GetPosition(), this.GetDirection(), TARGET_CONE_ANGLE_CHASE, m_ActualAttackType.m_Distance, -1.0, 2.0, this, m_TargetableObjects, m_AllTargetObjects);
- //! target is outside the targeting cone; skip attack
- if (m_ActualTarget != target)
- {
- m_AllTargetObjects.Clear();
- return false;
- }
- StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
- m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
- return true;
- }
-
- return false;
- }
-
- bool FightAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
- {
- // always update target - it can be destroyed
- m_ActualTarget = pInputController.GetTargetEntity();
-
- //! do not attack players in vehicle - hotfix
- PlayerBase pb = PlayerBase.Cast(m_ActualTarget);
- if (pb && pb.GetCommand_Vehicle())
- return false;
- if (m_AttackCooldownTime > 0)
- {
- m_AttackCooldownTime -= pDt * GameConstants.AI_ATTACKSPEED;
- return false;
- }
-
- if (m_ActualTarget == null)
- return false;
- vector targetPos = m_ActualTarget.GetPosition();
- float targetDist = vector.Distance(targetPos, this.GetPosition());
- int pitch = GetAttackPitch(m_ActualTarget);
-
- if (!CanAttackToPosition(targetPos))
- return false;
- m_ActualAttackType = GetDayZInfectedType().ChooseAttack(DayZInfectedAttackGroupType.FIGHT, targetDist, pitch);
- if (m_ActualAttackType)
- {
- Object target = DayZPlayerUtils.GetMeleeTarget(this.GetPosition(), this.GetDirection(), TARGET_CONE_ANGLE_FIGHT, m_ActualAttackType.m_Distance, -1.0, 2.0, this, m_TargetableObjects, m_AllTargetObjects);
- //! target is outside the targeting cone; skip attack
- if (m_AllTargetObjects.Count() > 0 && m_AllTargetObjects[0] != m_ActualTarget)
- {
- m_AllTargetObjects.Clear();
- return false;
- }
- StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
- m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
- return true;
- }
- return false;
- }
- int GetAttackPitch(EntityAI target)
- {
- vector attackRefPos;
- attackRefPos = target.GetDefaultHitPosition();
- //! no default hit pos fallback
- if ( attackRefPos != vector.Zero )
- {
- attackRefPos = target.ModelToWorld(attackRefPos);
- }
- else
- {
- attackRefPos = target.GetPosition();
- }
- // Now we have only erect stance, we need to get head position later too
- float headPosY = GetPosition()[1];
- headPosY += 1.8;
-
- float diff = Math.AbsFloat(attackRefPos[1] - headPosY);
-
- if ( diff < 0.3 )
- return 0;
-
- if ( headPosY > attackRefPos[1] )
- return -1;
- else
- return 1;
- }
-
- //-------------------------------------------------------------
- //!
- //! Crawl transition
- //!
-
- int m_CrawlTransition = -1;
-
- bool HandleCrawlTransition(int pCurrentCommandID)
- {
- if ( m_CrawlTransition != -1 )
- {
- StartCommand_Crawl(m_CrawlTransition);
-
- m_CrawlTransition = -1;
- m_IsCrawling = true;
- SetSynchDirty();
- return true;
- }
- return pCurrentCommandID == DayZInfectedConstants.COMMANDID_CRAWL;
- }
-
- bool EvaluateCrawlTransitionAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType)
- {
- pAnimType = -1;
- if ( pComponent == "LeftLeg" && GetHealth(pComponent, "Health") == 0 )
- pAnimType = 0;
- else if ( pComponent == "RightLeg" && GetHealth(pComponent, "Health") == 0 )
- pAnimType = 2;
-
- if ( pAnimType != -1 )
- {
- vector targetDirection = GetDirection();
- vector toSourceDirection = (pSource.GetPosition() - GetPosition());
- targetDirection[1] = 0;
- toSourceDirection[1] = 0;
- targetDirection.Normalize();
- toSourceDirection.Normalize();
- float cosFi = vector.Dot(targetDirection, toSourceDirection);
- if ( cosFi >= 0 ) // front
- pAnimType++;
- }
-
- return pAnimType != -1;
- }
-
- //-------------------------------------------------------------
- //!
- //! Damage hits
- //!
-
- bool m_DamageHitToProcess = false;
-
- bool m_DamageHitHeavy = false;
- int m_DamageHitType = 0;
- float m_ShockDamage = 0;
-
- const float HIT_INTERVAL_MIN = 0.3; // Minimum time in seconds before a COMMANDID_HIT to COMMANDID_HIT transition is allowed
- float m_HitElapsedTime = HIT_INTERVAL_MIN;
-
- bool HandleDamageHit(int pCurrentCommandID)
- {
- if ( pCurrentCommandID == DayZInfectedConstants.COMMANDID_HIT )
- {
- // Throttle hit command up to a fixed rate
- if ( m_HitElapsedTime < HIT_INTERVAL_MIN )
- {
- m_HitElapsedTime += m_DeltaTime;
- m_DamageHitToProcess = false;
- m_ShockDamage = 0;
- return false;
- }
- }
-
- if ( m_DamageHitToProcess )
- {
- int randNum = Math.RandomIntInclusive(0, 100);
- float stunChange = SHOCK_TO_STUN_MULTIPLIER * m_ShockDamage;
-
- if ( m_DamageHitHeavy || randNum <= stunChange || ( m_MindState == DayZInfectedConstants.MINDSTATE_CALM || m_MindState == DayZInfectedConstants.MINDSTATE_DISTURBED ) )
- {
- StartCommand_Hit(m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection);
- m_HitElapsedTime = 0;
- }
-
- m_DamageHitToProcess = false;
- m_ShockDamage = 0;
- m_HeavyHitOverride = false;
- return true;
- }
- return false;
- }
- //! selects animation type and direction based on damage system data
- bool EvaluateDamageHitAnimation(EntityAI pSource, string pComponent, string pAmmoType, out bool pHeavyHit, out int pAnimType, out float pAnimHitDir)
- {
- int invertHitDir = 0; //Used to flip the heavy hit animation direction
-
- //! heavy hit
- pHeavyHit = ((GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " hitAnimation") > 0) || m_HeavyHitOverride);
- invertHitDir = GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " invertHitDir");
-
- //! anim type
- pAnimType = 0; // belly
-
- if ( !pHeavyHit )
- {
- if ( pComponent == "Torso" ) // body
- pAnimType = 1;
- else if ( pComponent == "Head" ) // head
- pAnimType = 2;
- }
-
- //! direction
- //pAnimHitDir = ComputeHitDirectionAngle(pSource);
- pAnimHitDir = ComputeHitDirectionAngleEx(pSource, invertHitDir);
- //! shock GetDamage
- //m_ShockDamage = GetGame().ConfigGetFloat( "CfgAmmo " + pAmmoType + " DamageApplied " + "Shock " + "damage");
- return true;
- }
-
- float ComputeHitDirectionAngle(EntityAI pSource)
- {
- vector targetDirection = GetDirection();
- vector toSourceDirection = (pSource.GetPosition() - GetPosition());
- targetDirection[1] = 0;
- toSourceDirection[1] = 0;
- targetDirection.Normalize();
- toSourceDirection.Normalize();
- float cosFi = vector.Dot(targetDirection, toSourceDirection);
- vector cross = targetDirection * toSourceDirection;
-
- float dirAngle = Math.Acos(cosFi) * Math.RAD2DEG;
- if ( cross[1] < 0 )
- dirAngle = -dirAngle;
-
- return dirAngle;
- }
-
- float ComputeHitDirectionAngleEx(EntityAI pSource, int invertHitDir = 0)
- {
- vector targetDirection = GetDirection();
- vector toSourceDirection = (pSource.GetPosition() - GetPosition());
- targetDirection[1] = 0;
- toSourceDirection[1] = 0;
- targetDirection.Normalize();
- toSourceDirection.Normalize();
- float cosFi = vector.Dot(targetDirection, toSourceDirection);
- vector cross = targetDirection * toSourceDirection;
-
- float dirAngle = Math.Acos(cosFi) * Math.RAD2DEG;
-
- // We will invert direction of the hit
- if ( invertHitDir > 0 )
- dirAngle -= 180;
- if ( cross[1] < 0 )
- dirAngle = -dirAngle;
-
- return dirAngle;
- }
-
- //-------------------------------------------------------------
- //!
- //! Events from damage system
- //!
- override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
- {
- super.EEHitBy(damageResult, damageType, source, component, dmgZone, ammo, modelPos, speedCoef);
-
- m_TransportHitRegistered = false;
-
- if ( !IsAlive() )
- {
- ZombieHitData data = new ZombieHitData;
- data.m_Component = component;
- data.m_DamageZone = dmgZone;
- data.m_AmmoType = ammo;
- EvaluateDeathAnimationEx(source, data, m_DeathType, m_DamageHitDirection);
- }
- else
- {
- int crawlTransitionType = -1;
- if ( EvaluateCrawlTransitionAnimation(source, dmgZone, ammo, crawlTransitionType) )
- {
- m_CrawlTransition = crawlTransitionType;
- return;
- }
-
- if ( EvaluateDamageHitAnimation(source, dmgZone, ammo, m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection) )
- {
- if ( dmgZone )
- m_ShockDamage = damageResult.GetDamage( dmgZone, "Shock" );
- m_DamageHitToProcess = true;
- return;
- }
- }
- }
-
- override void EEHitByRemote(int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos)
- {
- super.EEHitByRemote(damageType, source, component, dmgZone, ammo, modelPos);
- }
- //! sound debug messages
- protected void DebugSound(string s)
- {
- //Print(s);
- }
-
- //-------------------------------------------------------------
- //!
- //! Phx contact event
- //!
-
- override protected void EOnContact(IEntity other, Contact extra)
- {
- if ( !IsAlive() )
- return;
- Transport transport = Transport.Cast(other);
- if ( transport )
- {
- if ( GetGame().IsServer() )
- {
- RegisterTransportHit(transport);
- }
- }
- }
-
- override bool CanReceiveAttachment(EntityAI attachment, int slotId)
- {
- if ( !IsAlive() )
- {
- return false;
- }
- return super.CanReceiveAttachment(attachment, slotId);
- }
-
- override vector GetCenter()
- {
- return GetBonePositionWS( GetBoneIndexByName( "spine3" ) );
- }
-
- //! returns true if backstab is in progress; used for suspending of AI targeting and other useful things besides
- override bool IsBeingBackstabbed()
- {
- return m_FinisherInProgress;
- }
-
- override void SetBeingBackstabbed(int backstabType)
- {
- // disable AI simulation
- GetAIAgent().SetKeepInIdle(true);
-
- // select death animation
- switch (backstabType)
- {
- case EMeleeHitType.FINISHER_LIVERSTAB:
- m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_BACKSTAB;
- break;
-
- case EMeleeHitType.FINISHER_NECKSTAB:
- m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_NECKSTAB;
- break;
-
- default:
- m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_DEFAULT;
- }
- // set flag - death command will be executed
- m_FinisherInProgress = true;
- }
-
- //! returns true if crawling; 'DayZInfectedCommandCrawl' is only for the transition, after that it remains 'DayZInfectedCommandMove' (unreliable)
- bool IsCrawling()
- {
- return m_IsCrawling;
- }
-
- // called from command death when stealth attack wan't successful
- void OnRecoverFromDeath()
- {
- // enable AI simulation again
- GetAIAgent().SetKeepInIdle(false);
- // reset flag
- m_FinisherInProgress = false;
- }
-
- override void AddArrow(Object arrow, int componentIndex, vector closeBonePosWS, vector closeBoneRotWS)
- {
- CachedObjectsArrays.ARRAY_STRING.Clear();
- GetActionComponentNameList(componentIndex, CachedObjectsArrays.ARRAY_STRING, "fire");
-
- int pivot = -1;
-
-
- for (int i = 0; i < CachedObjectsArrays.ARRAY_STRING.Count() && pivot == -1; i++)
- {
- pivot = GetBoneIndexByName(CachedObjectsArrays.ARRAY_STRING.Get(i));
- }
-
- vector parentTransMat[4];
- vector arrowTransMat[4];
-
- if (pivot == -1)
- {
- GetTransformWS(parentTransMat);
- }
- else
- {
- vector rotMatrix[3];
- Math3D.YawPitchRollMatrix(closeBoneRotWS * Math.RAD2DEG,rotMatrix);
-
- parentTransMat[0] = rotMatrix[0];
- parentTransMat[1] = rotMatrix[1];
- parentTransMat[2] = rotMatrix[2];
- parentTransMat[3] = closeBonePosWS;
- }
-
- arrow.GetTransform(arrowTransMat);
- Math3D.MatrixInvMultiply4(parentTransMat, arrowTransMat, arrowTransMat);
- // orthogonalize matrix - parent might be skewed
- Math3D.MatrixOrthogonalize4(arrowTransMat);
- arrow.SetTransform(arrowTransMat);
-
- AddChild(arrow, pivot);
- }
-
- override bool IsManagingArrows()
- {
- return true;
- }
-
- override ArrowManagerBase GetArrowManager()
- {
- return m_ArrowManager;
- }
- }
- //! an extendable data container
- class ZombieHitData
- {
- int m_Component;
- string m_DamageZone;
- string m_AmmoType;
- }
|