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;
20 protected float m_OrientationTimer;
21 protected float m_MovementSpeed = -1;
23 protected vector m_DefaultHitPosition;
24 protected float m_DeltaTime;
34 protected bool m_IsCrawling;
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);
103 override bool IsZombie()
113 override bool IsZombieMilitary()
123 override bool CanBeBackstabbed()
139 override bool IsHealthVisible()
152 return GetDayZInfectedType().GetHitComponentForAI();
158 return GetDayZInfectedType().GetDefaultHitComponent();
163 return m_DefaultHitPosition;
166 protected vector SetDefaultHitPosition(
string pSelection)
168 return GetSelectionPositionMS(pSelection);
174 return GetDayZInfectedType().GetSuitableFinisherHitComponents();
177 int GetMindStateSynced()
183 int GetOrientationSynced()
185 return m_OrientationSynced;
193 void CommandHandler(
float pDt,
int pCurrentCommandID,
bool pCurrentCommandFinished)
206 if ( HandleDeath(pCurrentCommandID) )
209 else if (!pCurrentCommandFinished)
216 HandleMove(pCurrentCommandID);
217 HandleOrientation(pDt,pCurrentCommandID);
220 if (pCurrentCommandFinished)
224 moveCommand.SetStanceVariation(m_StanceVariation);
236 if ( HandleCrawlTransition(pCurrentCommandID) )
242 if ( HandleDamageHit(pCurrentCommandID) )
248 if ( inputController )
250 if ( HandleVault(pCurrentCommandID, inputController, pDt) )
255 if ( HandleMindStateChange(pCurrentCommandID, inputController, pDt) )
260 if ( FightLogic(pCurrentCommandID, inputController, pDt) )
278 void CommandHandlerDebug(
float pDt,
int pCurrentCommandID,
bool pCurrentCommandFinished)
282 PluginDayZInfectedDebug infectedDebug = PluginDayZInfectedDebug.Cast(
GetPluginManager().GetPluginByType(PluginDayZInfectedDebug));
284 infectedDebug.CommandHandler(
this);
292 void HandleMove(
int pCurrentCommandID)
295 m_MovementSpeed = ic.GetMovementSpeed();
296 if (
Math.AbsFloat(m_LastMovementSpeed - m_MovementSpeed) >= 0.9 && m_LastMovementSpeed != m_MovementSpeed)
301 m_LastMovementSpeed = m_MovementSpeed;
309 void HandleOrientation(
float pDt,
int pCurrentCommandID)
311 m_OrientationTimer += pDt;
314 yaw =
Math.NormalizeAngle(yaw);
317 float angleSourceRad = m_OrientationSynced *
Math.DEG2RAD;
318 float angleTargetRad = yaw *
Math.DEG2RAD;
320 float angleDiffRad =
Math.Atan2(
Math.Sin(angleTargetRad - angleSourceRad),
Math.Cos(angleSourceRad - angleTargetRad));
321 angleDiffRad *=
Math.RAD2DEG;
322 angleDiffRad =
Math.Round(angleDiffRad);
324 if (m_OrientationTimer >= 2.0 || m_OrientationSynced == -1 ||
Math.AbsInt(angleDiffRad) > ORIENTATION_SYNC_THRESHOLD)
326 m_OrientationTimer = 0.0;
328 if (m_OrientationSynced == -1 ||
Math.AbsInt(angleDiffRad) > 5)
331 m_OrientationSynced = yaw;
342 float m_DamageHitDirection = 0;
345 bool HandleDeath(
int pCurrentCommandID)
347 if ( !IsAlive() || m_FinisherInProgress )
350 m_MovementSpeed = -1;
359 bool EvaluateDeathAnimationEx(
EntityAI pSource, ZombieHitData data, out
int pAnimType, out
float pAnimHitDir)
361 bool ret = EvaluateDeathAnimation(pSource,data.m_DamageZone,data.m_AmmoType,pAnimType,pAnimHitDir);
366 bool EvaluateDeathAnimation(
EntityAI pSource,
string pComponent,
string pAmmoType, out
int pAnimType, out
float pAnimHitDir)
369 bool doPhxImpulse =
GetGame().ConfigGetInt(
"cfgAmmo " + pAmmoType +
" doPhxImpulse") > 0;
372 pAnimType = doPhxImpulse;
375 pAnimHitDir = ComputeHitDirectionAngle(pSource);
380 vector impulse = 80 * m_TransportHitVelocity;
381 impulse[1] = 80 * 1.5;
395 int m_ActiveVaultType = -1;
397 int GetVaultType(
float height)
401 else if ( height <= 1.1 )
403 else if ( height <= 1.6 )
413 DayZInfectedCommandVault vaultCmd = GetCommand_Vault();
414 if ( vaultCmd && vaultCmd.WasLand() )
416 m_KnuckleOutTimer = 0;
417 m_KnuckleLand =
true;
421 m_KnuckleOutTimer += pDt;
422 if ( m_KnuckleOutTimer > 2.0 )
423 StartCommand_Vault(-1);
429 if ( pInputController.IsVault() )
431 float vaultHeight = pInputController.GetVaultHeight();
432 int vaultType = GetVaultType(vaultHeight);
433 m_KnuckleLand =
false;
434 StartCommand_Vault(vaultType);
450 m_MindState = pInputController.GetMindState();
451 if ( m_LastMindState != m_MindState )
453 switch ( m_MindState )
456 if ( moveCommand && !moveCommand.IsTurning() )
457 moveCommand.SetIdleState(0);
461 if ( moveCommand && !moveCommand.IsTurning() )
462 moveCommand.SetIdleState(1);
466 if ( moveCommand && !moveCommand.IsTurning() && (m_LastMindState <
DayZInfectedConstants.MINDSTATE_CHASE) )
467 moveCommand.SetIdleState(2);
471 m_LastMindState = m_MindState;
472 m_AttackCooldownTime = 0.0;
483 protected void HandleSoundEvents()
486 if ( !m_InfectedSoundEventHandler )
495 m_InfectedSoundEventHandler.Stop();
499 switch ( m_MindState )
514 m_InfectedSoundEventHandler.Stop();
518 DebugSound(
"[Infected @ " +
this +
"][MindState]" +
typename.EnumToString(
DayZInfectedConstants, m_MindState));
519 DebugSound(
"[Infected @ " +
this +
"][SoundEventID]" +
typename.EnumToString(
EInfectedSoundEventID, m_InfectedSoundEventHandler.GetCurrentStateEventID()));
527 if (!
GetGame().IsDedicatedServer())
530 if ( !soundParams.IsValid() )
537 soundObject = soundObjectBuilder.BuildSoundObject();
538 AttenuateSoundIfNecessary(soundObject);
540 return PlaySound(soundObject, soundObjectBuilder);
546 override void OnSoundVoiceEvent(
int event_id,
string event_user_string)
549 AnimSoundVoiceEvent voice_event = GetCreatureAIType().GetSoundVoiceEvent(event_id);
550 if (voice_event !=
null)
553 if (m_InfectedSoundEventHandler)
555 m_InfectedSoundEventHandler.Stop();
556 DebugSound(
"[Infected @ " +
this +
"][SoundEvent] InfectedSoundEventHandler - stop all");
560 if (m_LastSoundVoiceAW !=
null)
562 DebugSound(
"[Infected @ " +
this +
"][AnimVoiceEvent] Stopping LastAW");
563 m_LastSoundVoiceAW.Stop();
567 ProcessSoundVoiceEvent(voice_event, m_LastSoundVoiceAW);
573 protected void ProcessSoundVoiceEvent(AnimSoundVoiceEvent sound_event, out
AbstractWave aw)
575 if (!
GetGame().IsDedicatedServer())
578 if (NULL != objectBuilder)
581 SoundObject soundObject = objectBuilder.BuildSoundObject();
582 AttenuateSoundIfNecessary(soundObject);
583 aw =
PlaySound(soundObject, objectBuilder);
589 if (sound_event.m_NoiseParams != NULL)
590 GetGame().GetNoiseSystem().AddNoise(
this, sound_event.m_NoiseParams);
600 float m_AttackCooldownTime = 0;
608 int mindState = pInputController.GetMindState();
611 return ChaseAttackLogic(pCurrentCommandID, pInputController, pDt);
615 return FightAttackLogic(pCurrentCommandID, pInputController, pDt);
620 DayZInfectedCommandAttack attackCommand = GetCommand_Attack();
621 if (attackCommand && attackCommand.WasHit())
623 if (m_ActualTarget !=
null)
628 bool playerInBlockStance =
false;
629 vector targetPos = m_ActualTarget.GetPosition();
630 vector hitPosWS = targetPos;
636 playerInBlockStance = playerTarget.GetMeleeFightLogic() && playerTarget.GetMeleeFightLogic().IsInBlock();
639 if (
vector.DistanceSq(targetPos, zombiePos) <= m_ActualAttackType.m_Distance * m_ActualAttackType.m_Distance)
642 if (playerInBlockStance && (
Math.RAD2DEG *
Math.AbsFloat(
Math3D.AngleFromPosition(targetPos, MiscGameplayFunctions.GetHeadingVector(playerTarget), zombiePos))) <=
GameConstants.AI_MAX_BLOCKABLE_ANGLE)
645 if (m_ActualAttackType.m_IsHeavy == 1)
647 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
648 DamageSystem.CloseCombatDamageName(
this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(),
"MeleeZombie", hitPosWS);
653 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
654 DamageSystem.CloseCombatDamageName(
this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(),
"Dummy_Light", hitPosWS);
659 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
660 DamageSystem.CloseCombatDamageName(
this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), m_ActualAttackType.m_AmmoType, hitPosWS);
675 m_ActualTarget = pInputController.GetTargetEntity();
679 if ( pb && pb.GetCommand_Vehicle() )
684 if ( m_ActualTarget == NULL )
687 vector targetPos = m_ActualTarget.GetPosition();
688 if ( !CanAttackToPosition(targetPos) )
692 int pitch = GetAttackPitch(m_ActualTarget);
695 if (m_ActualAttackType)
699 if (m_ActualTarget != target)
705 StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
706 m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
716 m_ActualTarget = pInputController.GetTargetEntity();
720 if (pb && pb.GetCommand_Vehicle())
723 if (m_AttackCooldownTime > 0)
729 if (m_ActualTarget ==
null)
732 vector targetPos = m_ActualTarget.GetPosition();
734 int pitch = GetAttackPitch(m_ActualTarget);
736 if (!CanAttackToPosition(targetPos))
740 if (m_ActualAttackType)
750 StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
751 m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
762 attackRefPos = target.GetDefaultHitPosition();
764 if ( attackRefPos !=
vector.Zero )
766 attackRefPos = target.ModelToWorld(attackRefPos);
770 attackRefPos = target.GetPosition();
777 float diff =
Math.AbsFloat(attackRefPos[1] - headPosY);
782 if ( headPosY > attackRefPos[1] )
793 int m_CrawlTransition = -1;
795 bool HandleCrawlTransition(
int pCurrentCommandID)
797 if ( m_CrawlTransition != -1 )
799 StartCommand_Crawl(m_CrawlTransition);
801 m_CrawlTransition = -1;
810 bool EvaluateCrawlTransitionAnimation(
EntityAI pSource,
string pComponent,
string pAmmoType, out
int pAnimType)
813 if ( pComponent ==
"LeftLeg" && GetHealth(pComponent,
"Health") == 0 )
815 else if ( pComponent ==
"RightLeg" && GetHealth(pComponent,
"Health") == 0 )
818 if ( pAnimType != -1 )
820 vector targetDirection = GetDirection();
823 targetDirection[1] = 0;
824 toSourceDirection[1] = 0;
826 targetDirection.Normalize();
827 toSourceDirection.Normalize();
829 float cosFi =
vector.Dot(targetDirection, toSourceDirection);
834 return pAnimType != -1;
842 bool m_DamageHitToProcess =
false;
844 bool m_DamageHitHeavy =
false;
845 int m_DamageHitType = 0;
846 float m_ShockDamage = 0;
848 const float HIT_INTERVAL_MIN = 0.3;
849 float m_HitElapsedTime = HIT_INTERVAL_MIN;
851 bool HandleDamageHit(
int pCurrentCommandID)
856 if ( m_HitElapsedTime < HIT_INTERVAL_MIN )
858 m_HitElapsedTime += m_DeltaTime;
859 m_DamageHitToProcess =
false;
865 if ( m_DamageHitToProcess )
867 int randNum =
Math.RandomIntInclusive(0, 100);
868 float stunChange = SHOCK_TO_STUN_MULTIPLIER * m_ShockDamage;
872 StartCommand_Hit(m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection);
873 m_HitElapsedTime = 0;
876 m_DamageHitToProcess =
false;
878 m_HeavyHitOverride =
false;
886 bool EvaluateDamageHitAnimation(
EntityAI pSource,
string pComponent,
string pAmmoType, out
bool pHeavyHit, out
int pAnimType, out
float pAnimHitDir)
888 int invertHitDir = 0;
891 pHeavyHit = ((
GetGame().ConfigGetInt(
"cfgAmmo " + pAmmoType +
" hitAnimation") > 0) || m_HeavyHitOverride);
892 invertHitDir =
GetGame().ConfigGetInt(
"cfgAmmo " + pAmmoType +
" invertHitDir");
899 if ( pComponent ==
"Torso" )
901 else if ( pComponent ==
"Head" )
907 pAnimHitDir = ComputeHitDirectionAngleEx(pSource, invertHitDir);
913 float ComputeHitDirectionAngle(
EntityAI pSource)
915 vector targetDirection = GetDirection();
918 targetDirection[1] = 0;
919 toSourceDirection[1] = 0;
921 targetDirection.Normalize();
922 toSourceDirection.Normalize();
924 float cosFi =
vector.Dot(targetDirection, toSourceDirection);
925 vector cross = targetDirection * toSourceDirection;
927 float dirAngle =
Math.Acos(cosFi) *
Math.RAD2DEG;
929 dirAngle = -dirAngle;
934 float ComputeHitDirectionAngleEx(
EntityAI pSource,
int invertHitDir = 0)
936 vector targetDirection = GetDirection();
939 targetDirection[1] = 0;
940 toSourceDirection[1] = 0;
942 targetDirection.Normalize();
943 toSourceDirection.Normalize();
945 float cosFi =
vector.Dot(targetDirection, toSourceDirection);
946 vector cross = targetDirection * toSourceDirection;
948 float dirAngle =
Math.Acos(cosFi) *
Math.RAD2DEG;
951 if ( invertHitDir > 0 )
955 dirAngle = -dirAngle;
967 super.EEHitBy(damageResult, damageType, source,
component, dmgZone, ammo, modelPos, speedCoef);
969 m_TransportHitRegistered =
false;
973 ZombieHitData data =
new ZombieHitData;
975 data.m_DamageZone = dmgZone;
976 data.m_AmmoType = ammo;
977 EvaluateDeathAnimationEx(source, data, m_DeathType, m_DamageHitDirection);
981 int crawlTransitionType = -1;
982 if ( EvaluateCrawlTransitionAnimation(source, dmgZone, ammo, crawlTransitionType) )
984 m_CrawlTransition = crawlTransitionType;
988 if ( EvaluateDamageHitAnimation(source, dmgZone, ammo, m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection) )
991 m_ShockDamage = damageResult.GetDamage( dmgZone,
"Shock" );
992 m_DamageHitToProcess =
true;
1000 super.EEHitByRemote(damageType, source,
component, dmgZone, ammo, modelPos);
1004 protected void DebugSound(
string s)
1024 RegisterTransportHit(transport);
1035 return super.CanReceiveAttachment(attachment, slotId);
1038 override vector GetCenter()
1044 override bool IsBeingBackstabbed()
1046 return m_FinisherInProgress;
1049 override void SetBeingBackstabbed(
int backstabType)
1052 GetAIAgent().SetKeepInIdle(
true);
1055 switch (backstabType)
1058 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_BACKSTAB;
1062 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_NECKSTAB;
1066 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_DEFAULT;
1070 m_FinisherInProgress =
true;
1078 return m_IsCrawling;
1082 void OnRecoverFromDeath()
1085 GetAIAgent().SetKeepInIdle(
false);
1088 m_FinisherInProgress =
false;
1106 vector parentTransMat[4];
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);