3 const float TARGET_CONE_ANGLE_CHASE = 20;
4 const float TARGET_CONE_ANGLE_FIGHT = 30;
5 const float ORIENTATION_SYNC_THRESHOLD = 30;
7 const float SHOCK_TO_STUN_MULTIPLIER = 2.82;
10 protected int m_StanceVariation = 0;
11 protected int m_LastMindState = -1;
12 protected float m_LastMovementSpeed = -1;
14 protected bool m_KnuckleLand =
false;
15 protected float m_KnuckleOutTimer = 0;
17 protected int m_MindState = -1;
18 protected int m_OrientationLocal = -1;
19 protected int m_OrientationSynced = -1;
21 protected float m_MovementSpeed = -1;
36 protected bool m_FinisherInProgress =
false;
54 RegisterNetSyncVariableInt(
"m_MindState", -1, 4);
55 RegisterNetSyncVariableInt(
"m_OrientationSynced", 0, 359);
56 RegisterNetSyncVariableFloat(
"m_MovementSpeed", -1, 3);
57 RegisterNetSyncVariableBool(
"m_IsCrawling");
63 if ( !
GetGame().IsDedicatedServer() )
65 m_LastSoundVoiceAW = null;
74 m_OrientationTimer = 0;
82 DebugSound(
"[Infected @ " +
this +
"][OnVariablesSynchronized]");
85 if ( m_OrientationLocal != m_OrientationSynced )
87 m_OrientationLocal = m_OrientationSynced;
96 m_StanceVariation =
Math.RandomInt(0, 4);
99 moveCommand.SetStanceVariation(m_StanceVariation);
157 return GetDayZInfectedType().GetHitComponentForAI();
163 return GetDayZInfectedType().GetDefaultHitComponent();
168 return m_DefaultHitPosition;
173 return GetSelectionPositionMS(pSelection);
179 return GetDayZInfectedType().GetSuitableFinisherHitComponents();
190 return m_OrientationSynced;
198 void CommandHandler(
float pDt,
int pCurrentCommandID,
bool pCurrentCommandFinished)
211 if ( HandleDeath(pCurrentCommandID) )
214 else if (!pCurrentCommandFinished)
221 HandleMove(pCurrentCommandID);
222 HandleOrientation(pDt,pCurrentCommandID);
225 if (pCurrentCommandFinished)
229 moveCommand.SetStanceVariation(m_StanceVariation);
241 if ( HandleCrawlTransition(pCurrentCommandID) )
247 if ( HandleDamageHit(pCurrentCommandID) )
253 if ( inputController )
255 if ( HandleVault(pCurrentCommandID, inputController, pDt) )
260 if ( HandleMindStateChange(pCurrentCommandID, inputController, pDt) )
265 if ( FightLogic(pCurrentCommandID, inputController, pDt) )
287 PluginDayZInfectedDebug infectedDebug = PluginDayZInfectedDebug.Cast(
GetPluginManager().GetPluginByType(PluginDayZInfectedDebug));
289 infectedDebug.CommandHandler(
this);
300 m_MovementSpeed = ic.GetMovementSpeed();
301 if (
Math.AbsFloat(m_LastMovementSpeed - m_MovementSpeed) >= 0.9 && m_LastMovementSpeed != m_MovementSpeed)
306 m_LastMovementSpeed = m_MovementSpeed;
316 m_OrientationTimer += pDt;
319 yaw =
Math.NormalizeAngle(yaw);
322 float angleSourceRad = m_OrientationSynced *
Math.DEG2RAD;
323 float angleTargetRad = yaw *
Math.DEG2RAD;
325 float angleDiffRad =
Math.Atan2(
Math.Sin(angleTargetRad - angleSourceRad),
Math.Cos(angleSourceRad - angleTargetRad));
326 angleDiffRad *=
Math.RAD2DEG;
327 angleDiffRad =
Math.Round(angleDiffRad);
329 if (m_OrientationTimer >= 2.0 || m_OrientationSynced == -1 ||
Math.AbsInt(angleDiffRad) > ORIENTATION_SYNC_THRESHOLD)
331 m_OrientationTimer = 0.0;
333 if (m_OrientationSynced == -1 ||
Math.AbsInt(angleDiffRad) > 5)
335 m_OrientationSynced = yaw;
346 float m_DamageHitDirection = 0;
351 if ( !IsAlive() || m_FinisherInProgress )
353 StartCommand_Death(m_DeathType, m_DamageHitDirection);
354 m_MovementSpeed = -1;
365 bool ret = EvaluateDeathAnimation(pSource,data.m_DamageZone,data.m_AmmoType,pAnimType,pAnimHitDir);
373 bool doPhxImpulse =
GetGame().ConfigGetInt(
"cfgAmmo " + pAmmoType +
" doPhxImpulse") > 0;
376 pAnimType = doPhxImpulse;
379 pAnimHitDir = ComputeHitDirectionAngle(pSource);
384 vector impulse = 80 * m_TransportHitVelocity;
385 impulse[1] = 80 * 1.5;
399 int m_ActiveVaultType = -1;
405 else if ( height <= 1.1 )
407 else if ( height <= 1.6 )
417 DayZInfectedCommandVault vaultCmd = GetCommand_Vault();
418 if ( vaultCmd && vaultCmd.WasLand() )
420 m_KnuckleOutTimer = 0;
421 m_KnuckleLand =
true;
425 m_KnuckleOutTimer += pDt;
426 if ( m_KnuckleOutTimer > 2.0 )
427 StartCommand_Vault(-1);
433 if ( pInputController.IsVault() )
435 float vaultHeight = pInputController.GetVaultHeight();
436 int vaultType = GetVaultType(vaultHeight);
437 m_KnuckleLand =
false;
438 StartCommand_Vault(vaultType);
454 m_MindState = pInputController.GetMindState();
455 if ( m_LastMindState != m_MindState )
457 switch ( m_MindState )
460 if ( moveCommand && !moveCommand.IsTurning() )
461 moveCommand.SetIdleState(0);
465 if ( moveCommand && !moveCommand.IsTurning() )
466 moveCommand.SetIdleState(1);
470 if ( moveCommand && !moveCommand.IsTurning() && (m_LastMindState <
DayZInfectedConstants.MINDSTATE_CHASE) )
471 moveCommand.SetIdleState(2);
475 m_LastMindState = m_MindState;
476 m_AttackCooldownTime = 0.0;
490 if ( !m_InfectedSoundEventHandler )
499 m_InfectedSoundEventHandler.Stop();
503 switch ( m_MindState )
518 m_InfectedSoundEventHandler.Stop();
522 DebugSound(
"[Infected @ " +
this +
"][MindState]" +
typename.EnumToString(
DayZInfectedConstants, m_MindState));
523 DebugSound(
"[Infected @ " +
this +
"][SoundEventID]" +
typename.EnumToString(
EInfectedSoundEventID, m_InfectedSoundEventHandler.GetCurrentStateEventID()));
531 if (!
GetGame().IsDedicatedServer())
534 if ( !soundParams.IsValid() )
541 soundObject = soundObjectBuilder.BuildSoundObject();
542 AttenuateSoundIfNecessary(soundObject);
544 return PlaySound(soundObject, soundObjectBuilder);
553 AnimSoundVoiceEvent voice_event = GetCreatureAIType().GetSoundVoiceEvent(event_id);
554 if (voice_event != null)
557 if (m_InfectedSoundEventHandler)
559 m_InfectedSoundEventHandler.Stop();
560 DebugSound(
"[Infected @ " +
this +
"][SoundEvent] InfectedSoundEventHandler - stop all");
564 if (m_LastSoundVoiceAW != null)
566 DebugSound(
"[Infected @ " +
this +
"][AnimVoiceEvent] Stopping LastAW");
567 m_LastSoundVoiceAW.Stop();
571 ProcessSoundVoiceEvent(voice_event, m_LastSoundVoiceAW);
579 if (!
GetGame().IsDedicatedServer())
582 if (NULL != objectBuilder)
585 SoundObject soundObject = objectBuilder.BuildSoundObject();
586 AttenuateSoundIfNecessary(soundObject);
587 aw =
PlaySound(soundObject, objectBuilder);
593 if (sound_event.m_NoiseParams != NULL)
604 float m_AttackCooldownTime = 0;
612 int mindState = pInputController.GetMindState();
615 return ChaseAttackLogic(pCurrentCommandID, pInputController, pDt);
619 return FightAttackLogic(pCurrentCommandID, pInputController, pDt);
624 DayZInfectedCommandAttack attackCommand = GetCommand_Attack();
625 if (attackCommand && attackCommand.WasHit())
627 if (m_ActualTarget != null)
632 bool playerInBlockStance =
false;
633 vector targetPos = m_ActualTarget.GetPosition();
634 vector hitPosWS = targetPos;
640 playerInBlockStance = playerTarget.GetMeleeFightLogic() && playerTarget.GetMeleeFightLogic().IsInBlock();
643 if (
vector.DistanceSq(targetPos, zombiePos) <= m_ActualAttackType.m_Distance * m_ActualAttackType.m_Distance)
646 if (playerInBlockStance && (
Math.RAD2DEG *
Math.AbsFloat(
Math3D.AngleFromPosition(targetPos, MiscGameplayFunctions.GetHeadingVector(playerTarget), zombiePos))) <=
GameConstants.AI_MAX_BLOCKABLE_ANGLE)
649 if (m_ActualAttackType.m_IsHeavy == 1)
651 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
652 DamageSystem.CloseCombatDamageName(
this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(),
"MeleeZombie", hitPosWS);
657 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
658 DamageSystem.CloseCombatDamageName(
this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(),
"Dummy_Light", hitPosWS);
663 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
664 DamageSystem.CloseCombatDamageName(
this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), m_ActualAttackType.m_AmmoType, hitPosWS);
679 m_ActualTarget = pInputController.GetTargetEntity();
683 if ( pb && pb.GetCommand_Vehicle() )
688 if ( m_ActualTarget == NULL )
691 vector targetPos = m_ActualTarget.GetPosition();
692 if ( !CanAttackToPosition(targetPos) )
696 int pitch = GetAttackPitch(m_ActualTarget);
699 if (m_ActualAttackType)
703 if (m_ActualTarget != target)
709 StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
710 m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
720 m_ActualTarget = pInputController.GetTargetEntity();
724 if (pb && pb.GetCommand_Vehicle())
727 if (m_AttackCooldownTime > 0)
733 if (m_ActualTarget == null)
736 vector targetPos = m_ActualTarget.GetPosition();
738 int pitch = GetAttackPitch(m_ActualTarget);
740 if (!CanAttackToPosition(targetPos))
744 if (m_ActualAttackType)
754 StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
755 m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
766 attackRefPos = target.GetDefaultHitPosition();
768 if ( attackRefPos !=
vector.Zero )
770 attackRefPos = target.ModelToWorld(attackRefPos);
774 attackRefPos = target.GetPosition();
781 float diff =
Math.AbsFloat(attackRefPos[1] - headPosY);
786 if ( headPosY > attackRefPos[1] )
797 int m_CrawlTransition = -1;
801 if ( m_CrawlTransition != -1 )
803 StartCommand_Crawl(m_CrawlTransition);
805 m_CrawlTransition = -1;
817 if ( pComponent ==
"LeftLeg" && GetHealth(pComponent,
"Health") == 0 )
819 else if ( pComponent ==
"RightLeg" && GetHealth(pComponent,
"Health") == 0 )
822 if ( pAnimType != -1 )
824 vector targetDirection = GetDirection();
827 targetDirection[1] = 0;
828 toSourceDirection[1] = 0;
830 targetDirection.Normalize();
831 toSourceDirection.Normalize();
833 float cosFi =
vector.Dot(targetDirection, toSourceDirection);
838 return pAnimType != -1;
846 bool m_DamageHitToProcess =
false;
848 bool m_DamageHitHeavy =
false;
849 int m_DamageHitType = 0;
850 float m_ShockDamage = 0;
852 const float HIT_INTERVAL_MIN = 0.3;
853 float m_HitElapsedTime = HIT_INTERVAL_MIN;
860 if ( m_HitElapsedTime < HIT_INTERVAL_MIN )
862 m_HitElapsedTime += m_DeltaTime;
863 m_DamageHitToProcess =
false;
869 if ( m_DamageHitToProcess )
871 int randNum =
Math.RandomIntInclusive(0, 100);
872 float stunChange = SHOCK_TO_STUN_MULTIPLIER * m_ShockDamage;
876 StartCommand_Hit(m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection);
877 m_HitElapsedTime = 0;
880 m_DamageHitToProcess =
false;
882 m_HeavyHitOverride =
false;
892 int invertHitDir = 0;
895 pHeavyHit = ((
GetGame().ConfigGetInt(
"cfgAmmo " + pAmmoType +
" hitAnimation") > 0) || m_HeavyHitOverride);
896 invertHitDir =
GetGame().ConfigGetInt(
"cfgAmmo " + pAmmoType +
" invertHitDir");
903 if ( pComponent ==
"Torso" )
905 else if ( pComponent ==
"Head" )
911 pAnimHitDir = ComputeHitDirectionAngleEx(pSource, invertHitDir);
919 vector targetDirection = GetDirection();
922 targetDirection[1] = 0;
923 toSourceDirection[1] = 0;
925 targetDirection.Normalize();
926 toSourceDirection.Normalize();
928 float cosFi =
vector.Dot(targetDirection, toSourceDirection);
929 vector cross = targetDirection * toSourceDirection;
931 float dirAngle =
Math.Acos(cosFi) *
Math.RAD2DEG;
933 dirAngle = -dirAngle;
940 vector targetDirection = GetDirection();
943 targetDirection[1] = 0;
944 toSourceDirection[1] = 0;
946 targetDirection.Normalize();
947 toSourceDirection.Normalize();
949 float cosFi =
vector.Dot(targetDirection, toSourceDirection);
950 vector cross = targetDirection * toSourceDirection;
952 float dirAngle =
Math.Acos(cosFi) *
Math.RAD2DEG;
955 if ( invertHitDir > 0 )
959 dirAngle = -dirAngle;
971 super.EEHitBy(damageResult, damageType, source,
component, dmgZone, ammo, modelPos, speedCoef);
973 m_TransportHitRegistered =
false;
977 ZombieHitData data =
new ZombieHitData;
979 data.m_DamageZone = dmgZone;
980 data.m_AmmoType = ammo;
981 EvaluateDeathAnimationEx(source, data, m_DeathType, m_DamageHitDirection);
985 int crawlTransitionType = -1;
986 if ( EvaluateCrawlTransitionAnimation(source, dmgZone, ammo, crawlTransitionType) )
988 m_CrawlTransition = crawlTransitionType;
992 if ( EvaluateDamageHitAnimation(source, dmgZone, ammo, m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection) )
995 m_ShockDamage = damageResult.GetDamage( dmgZone,
"Shock" );
996 m_DamageHitToProcess =
true;
1004 super.EEHitByRemote(damageType, source,
component, dmgZone, ammo, modelPos);
1028 RegisterTransportHit(transport);
1039 return super.CanReceiveAttachment(attachment, slotId);
1050 return m_FinisherInProgress;
1056 GetAIAgent().SetKeepInIdle(
true);
1059 switch (backstabType)
1062 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_BACKSTAB;
1066 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_NECKSTAB;
1070 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_DEFAULT;
1074 m_FinisherInProgress =
true;
1080 return m_IsCrawling;
1087 GetAIAgent().SetKeepInIdle(
false);
1090 m_FinisherInProgress =
false;
1106 vector parentTransMat[4];
1111 GetTransformWS(parentTransMat);
1116 Math3D.YawPitchRollMatrix(closeBoneRotWS *
Math.RAD2DEG,rotMatrix);
1118 parentTransMat[0] = rotMatrix[0];
1119 parentTransMat[1] = rotMatrix[1];
1120 parentTransMat[2] = rotMatrix[2];
1121 parentTransMat[3] = closeBonePosWS;
1124 arrow.GetTransform(arrowTransMat);
1125 Math3D.MatrixInvMultiply4(parentTransMat, arrowTransMat, arrowTransMat);
1127 Math3D.MatrixOrthogonalize4(arrowTransMat);
1128 arrow.SetTransform(arrowTransMat);
1130 AddChild(arrow, pivot);
RepairTentActionReciveData m_DamageZone
ref ArrowManagerBase m_ArrowManager
void CommandHandler(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
override void OnSoundVoiceEvent(int event_id, string event_user_string)
override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
ref ArrowManagerBase m_ArrowManager
bool FightLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
ref InfectedSoundEventHandler m_InfectedSoundEventHandler
void CommandHandlerDebug(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
override bool IsManagingArrows()
bool HandleVault(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
override array< string > GetSuitableFinisherHitComponents()
returns suitable hit components for finisher attacks; DEPRECATED
override bool CanReceiveAttachment(EntityAI attachment, int slotId)
void ProcessSoundVoiceEvent(AnimSoundVoiceEvent sound_event, out AbstractWave aw)
int GetOrientationSynced()
returns rounded zombie yaw for sync purposes
bool IsCrawling()
returns true if crawling; 'DayZInfectedCommandCrawl' is only for the transition, after that it remain...
override bool IsSelfAdjustingTemperature()
override void EOnInit(IEntity other, int extra)
override void AddArrow(Object arrow, int componentIndex, vector closeBonePosWS, vector closeBoneRotWS)
void OnRecoverFromDeath()
override void EEHitByRemote(int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos)
ref array< Object > m_AllTargetObjects
AbstractWave ProcessVoiceFX(string pSoundSetName)
void HandleOrientation(float pDt, int pCurrentCommandID)
override bool CanBeSkinned()
bool HandleDamageHit(int pCurrentCommandID)
bool EvaluateCrawlTransitionAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType)
vector SetDefaultHitPosition(string pSelection)
AbstractWave m_LastSoundVoiceAW
override AnimBootsType GetBootsType()
bool FightAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
bool HandleCrawlTransition(int pCurrentCommandID)
void HandleMove(int pCurrentCommandID)
void DebugSound(string s)
sound debug messages
vector m_DefaultHitPosition
override bool IsHealthVisible()
bool EvaluateDeathAnimationEx(EntityAI pSource, ZombieHitData data, out int pAnimType, out float pAnimHitDir)
override bool IsRefresherSignalingViable()
bool EvaluateDamageHitAnimation(EntityAI pSource, string pComponent, string pAmmoType, out bool pHeavyHit, out int pAnimType, out float pAnimHitDir)
selects animation type and direction based on damage system data
override string GetDefaultHitComponent()
returns default hit component (fallback)
override bool IsBeingBackstabbed()
returns true if backstab is in progress; used for suspending of AI targeting and other useful things ...
void EOnContact(IEntity other, Contact extra)
override vector GetCenter()
bool HandleDeath(int pCurrentCommandID)
ref array< typename > m_TargetableObjects
override void OnVariablesSynchronized()
synced variable(s) handler
override string GetHitComponentForAI()
returns hit component for attacking AI
int GetAttackPitch(EntityAI target)
float ComputeHitDirectionAngleEx(EntityAI pSource, int invertHitDir=0)
override void SetBeingBackstabbed(int backstabType)
override bool IsZombieMilitary()
override bool CanBeBackstabbed()
int GetVaultType(float height)
override vector GetDefaultHitPosition()
bool EvaluateDeathAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType, out float pAnimHitDir)
bool HandleMindStateChange(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
float ComputeHitDirectionAngle(EntityAI pSource)
override ArrowManagerBase GetArrowManager()
bool ChaseAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
Native class for boats - handles physics simulation.
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
bool ModCommandHandlerInside(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
proto native int GetBoneIndexByName(string pBoneName)
returns bone index for a name (-1 if pBoneName doesn't exist)
bool ModCommandHandlerBefore(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
bool ModCommandHandlerAfter(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
DayZInfectedAttackGroupType
string GetDefaultHitPositionComponent()
ref array< Object > m_AllTargetObjects
All potential targets found during most recent TargetSelection.
ref array< typename > m_TargetableObjects
Typenames of all directly/preferred targetable objects (1st Pass + 2nd Pass)
proto native CGame GetGame()
EntityEvent
Entity events for event-mask, or throwing event from code.
proto void dBodyApplyImpulse(notnull IEntity body, vector impulse)
Applies impuls on a rigidbody (origin)
class AbstractSoundScene SoundObjectBuilder(SoundParams soundParams)
class JsonUndergroundAreaTriggerData GetPosition
class SoundObject SoundParams(string name)
void InfectedSoundEventHandler(ZombieBase pInfected)
class BoxCollidingParams component
ComponentInfo for BoxCollidingResult.
PluginManager GetPluginManager()
Returns registred plugin by class type, better is to use global funtion GetPlugin(typename plugin_typ...
class ZombieBase extends DayZInfected m_Component
an extendable data container