Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
zombiebase.c
Go to the documentation of this file.
1 class ZombieBase extends DayZInfected
2 {
3  const float TARGET_CONE_ANGLE_CHASE = 20;
4  const float TARGET_CONE_ANGLE_FIGHT = 30;
5  const float ORIENTATION_SYNC_THRESHOLD = 30; //threshold for local heading/orientation sync
6 
7  const float SHOCK_TO_STUN_MULTIPLIER = 2.82;
8 
10  protected int m_StanceVariation = 0;
11  protected int m_LastMindState = -1;
12  protected float m_LastMovementSpeed = -1;
13 
14  protected bool m_KnuckleLand = false;
15  protected float m_KnuckleOutTimer = 0;
16 
17  protected int m_MindState = -1;
18  protected int m_OrientationLocal = -1; //local 'companion' value for sync checking
19  protected int m_OrientationSynced = -1;
20  protected float m_OrientationTimer;
21  protected float m_MovementSpeed = -1;
22 
23  protected vector m_DefaultHitPosition;
24  protected float m_DeltaTime;
25 
26  protected AbstractWave m_LastSoundVoiceAW;
27  protected ref InfectedSoundEventHandler m_InfectedSoundEventHandler;
28 
29  protected ref array<Object> m_AllTargetObjects;
31 
32  //static ref map<int,ref array<string>> m_FinisherSelectionMap; //! which selections in the FireGeometry trigger which finisher on hit (when applicable)
33 
34  protected bool m_IsCrawling; //'DayZInfectedCommandCrawl' is transition to crawl only, 'DayZInfectedCommandMove' used after that, hence this VARIABLE_WET
35 
36  protected bool m_FinisherInProgress = false; //is this object being backstabbed?
37 
38  protected ref ArrowManagerBase m_ArrowManager;
39 
40 
41 
42  //-------------------------------------------------------------
43  void ZombieBase()
44  {
45  Init();
46  }
47 
48  void Init()
49  {
50  SetEventMask(EntityEvent.INIT);
51 
52  m_IsCrawling = false;
53 
54  RegisterNetSyncVariableInt("m_MindState", -1, 4);
55  RegisterNetSyncVariableInt("m_OrientationSynced", 0, 359);
56  RegisterNetSyncVariableFloat("m_MovementSpeed", -1, 3);
57  RegisterNetSyncVariableBool("m_IsCrawling");
58 
60  m_DefaultHitPosition = SetDefaultHitPosition(GetDayZInfectedType().GetDefaultHitPositionComponent());
61 
63  if ( !GetGame().IsDedicatedServer() )
64  {
65  m_LastSoundVoiceAW = null;
66  m_InfectedSoundEventHandler = new InfectedSoundEventHandler(this);
67  }
68 
73 
74  m_OrientationTimer = 0;
75 
76  m_ArrowManager = new ArrowManagerBase(this);
77  }
78 
80  override void OnVariablesSynchronized()
81  {
82  DebugSound("[Infected @ " + this + "][OnVariablesSynchronized]");
83  HandleSoundEvents();
84 
85  if ( m_OrientationLocal != m_OrientationSynced )
86  {
87  m_OrientationLocal = m_OrientationSynced;
88  }
89  }
90 
91  //-------------------------------------------------------------
92  override void EOnInit(IEntity other, int extra)
93  {
94  if ( !GetGame().IsMultiplayer() || GetGame().IsServer() )
95  {
96  m_StanceVariation = Math.RandomInt(0, 4);
97 
99  moveCommand.SetStanceVariation(m_StanceVariation);
100  }
101  }
102 
103  override bool IsZombie()
104  {
105  return true;
106  }
107 
108  override bool IsDanger()
109  {
110  return true;
111  }
112 
113  override bool IsZombieMilitary()
114  {
115  return false;
116  }
117 
118  bool IsMale()
119  {
120  return true;
121  }
122 
123  override bool CanBeBackstabbed()
124  {
125  return true;
126  }
127 
128  //-------------------------------------------------------------
129  override AnimBootsType GetBootsType()
130  {
131  return AnimBootsType.Boots;
132  }
133 
134  override bool CanBeSkinned()
135  {
136  return false;
137  }
138  //-------------------------------------------------------------
139  override bool IsHealthVisible()
140  {
141  return false;
142  }
143  //-------------------------------------------------------------
144  override bool IsRefresherSignalingViable()
145  {
146  return false;
147  }
148 
150  override string GetHitComponentForAI()
151  {
152  return GetDayZInfectedType().GetHitComponentForAI();
153  }
154 
156  override string GetDefaultHitComponent()
157  {
158  return GetDayZInfectedType().GetDefaultHitComponent();
159  }
160 
161  override vector GetDefaultHitPosition()
162  {
163  return m_DefaultHitPosition;
164  }
165 
166  protected vector SetDefaultHitPosition(string pSelection)
167  {
168  return GetSelectionPositionMS(pSelection);
169  }
170 
173  {
174  return GetDayZInfectedType().GetSuitableFinisherHitComponents();
175  }
176 
177  int GetMindStateSynced()
178  {
179  return m_MindState;
180  }
181 
183  int GetOrientationSynced()
184  {
185  return m_OrientationSynced;
186  }
187 
188  //-------------------------------------------------------------
192 
193  void CommandHandler(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
194  {
195  m_DeltaTime = pDt;
196 
198  if ( ModCommandHandlerBefore(pDt, pCurrentCommandID, pCurrentCommandFinished) )
199  {
200  return;
201  }
202 
204  if ( pCurrentCommandID != DayZInfectedConstants.COMMANDID_DEATH )
205  {
206  if ( HandleDeath(pCurrentCommandID) )
207  return;
208  }
209  else if (!pCurrentCommandFinished)
210  {
211  return;
212  }
213 
214 
216  HandleMove(pCurrentCommandID);
217  HandleOrientation(pDt,pCurrentCommandID);
218 
220  if (pCurrentCommandFinished)
221  {
224  moveCommand.SetStanceVariation(m_StanceVariation);
225 
226  return;
227  }
228 
230  if ( ModCommandHandlerInside(pDt, pCurrentCommandID, pCurrentCommandFinished) )
231  {
232  return;
233  }
234 
236  if ( HandleCrawlTransition(pCurrentCommandID) )
237  {
238  return;
239  }
240 
242  if ( HandleDamageHit(pCurrentCommandID) )
243  {
244  return;
245  }
246 
248  if ( inputController )
249  {
250  if ( HandleVault(pCurrentCommandID, inputController, pDt) )
251  {
252  return;
253  }
254 
255  if ( HandleMindStateChange(pCurrentCommandID, inputController, pDt) )
256  {
257  return;
258  }
259 
260  if ( FightLogic(pCurrentCommandID, inputController, pDt) )
261  {
262  return;
263  }
264  }
265 
267  if ( ModCommandHandlerAfter(pDt, pCurrentCommandID, pCurrentCommandFinished) )
268  {
269  return;
270  }
271  }
272 
273  //-------------------------------------------------------------
277 
278  void CommandHandlerDebug(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
279  {
280  if ( GetPluginManager() )
281  {
282  PluginDayZInfectedDebug infectedDebug = PluginDayZInfectedDebug.Cast(GetPluginManager().GetPluginByType(PluginDayZInfectedDebug));
283  if ( infectedDebug )
284  infectedDebug.CommandHandler(this);
285  }
286  }
287  //-------------------------------------------------------------
291 
292  void HandleMove(int pCurrentCommandID)
293  {
295  m_MovementSpeed = ic.GetMovementSpeed();
296  if (Math.AbsFloat(m_LastMovementSpeed - m_MovementSpeed) >= 0.9 && m_LastMovementSpeed != m_MovementSpeed)
297  {
298  SetSynchDirty();
299  }
300 
301  m_LastMovementSpeed = m_MovementSpeed;
302  }
303 
304  //-------------------------------------------------------------
308 
309  void HandleOrientation(float pDt, int pCurrentCommandID)
310  {
311  m_OrientationTimer += pDt;
312 
313  int yaw = Math.Round(GetOrientation()[0]);
314  yaw = Math.NormalizeAngle(yaw);
315 
316  //atan2(sin(x-y), cos(x-y))
317  float angleSourceRad = m_OrientationSynced * Math.DEG2RAD;
318  float angleTargetRad = yaw * Math.DEG2RAD;
319 
320  float angleDiffRad = Math.Atan2(Math.Sin(angleTargetRad - angleSourceRad), Math.Cos(angleSourceRad - angleTargetRad));
321  angleDiffRad *= Math.RAD2DEG;
322  angleDiffRad = Math.Round(angleDiffRad);
323 
324  if (m_OrientationTimer >= 2.0 || m_OrientationSynced == -1 || Math.AbsInt(angleDiffRad) > ORIENTATION_SYNC_THRESHOLD)
325  {
326  m_OrientationTimer = 0.0;
327 
328  if (m_OrientationSynced == -1 || Math.AbsInt(angleDiffRad) > 5)
329  {
330  //Print("DbgSyncOrientation | HandleMove | original: " + m_OrientationSynced + " | target: " + yaw + " | diff: " + angleDiffRad);
331  m_OrientationSynced = yaw;
332  SetSynchDirty();
333  }
334  }
335  }
336 
337  //-------------------------------------------------------------
341 
342  float m_DamageHitDirection = 0;
343  int m_DeathType = 0;
344 
345  bool HandleDeath(int pCurrentCommandID)
346  {
347  if ( !IsAlive() || m_FinisherInProgress )
348  {
349  StartCommand_Death(m_DeathType, m_DamageHitDirection);
350  m_MovementSpeed = -1;
351  m_MindState = -1;
352  SetSynchDirty();
353  return true;
354  }
355 
356  return false;
357  }
358 
359  bool EvaluateDeathAnimationEx(EntityAI pSource, ZombieHitData data, out int pAnimType, out float pAnimHitDir)
360  {
361  bool ret = EvaluateDeathAnimation(pSource,data.m_DamageZone,data.m_AmmoType,pAnimType,pAnimHitDir);
362 
363  return ret;
364  }
365 
366  bool EvaluateDeathAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType, out float pAnimHitDir)
367  {
369  bool doPhxImpulse = GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " doPhxImpulse") > 0;
370 
372  pAnimType = doPhxImpulse;
373 
375  pAnimHitDir = ComputeHitDirectionAngle(pSource);
376 
378  if ( doPhxImpulse )
379  {
380  vector impulse = 80 * m_TransportHitVelocity;
381  impulse[1] = 80 * 1.5;
382  //Print("Impulse: " + impulse.ToString());
383 
384  dBodyApplyImpulse(this, impulse);
385  }
386 
387  return true;
388  }
389 
390  //-------------------------------------------------------------
394 
395  int m_ActiveVaultType = -1;
396 
397  int GetVaultType(float height)
398  {
399  if ( height <= 0.6 )
400  return 0;
401  else if ( height <= 1.1 )
402  return 1;
403  else if ( height <= 1.6 )
404  return 2;
405  else
406  return 3;
407  }
408 
409  bool HandleVault(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
410  {
411  if ( pCurrentCommandID == DayZInfectedConstants.COMMANDID_VAULT )
412  {
413  DayZInfectedCommandVault vaultCmd = GetCommand_Vault();
414  if ( vaultCmd && vaultCmd.WasLand() )
415  {
416  m_KnuckleOutTimer = 0;
417  m_KnuckleLand = true;
418  }
419  if ( m_KnuckleLand )
420  {
421  m_KnuckleOutTimer += pDt;
422  if ( m_KnuckleOutTimer > 2.0 )
423  StartCommand_Vault(-1);
424  }
425 
426  return true;
427  }
428 
429  if ( pInputController.IsVault() )
430  {
431  float vaultHeight = pInputController.GetVaultHeight();
432  int vaultType = GetVaultType(vaultHeight);
433  m_KnuckleLand = false;
434  StartCommand_Vault(vaultType);
435  return true;
436  }
437 
438  return false;
439  }
440 
441  //-------------------------------------------------------------
445 
446  bool HandleMindStateChange(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
447  {
449 
450  m_MindState = pInputController.GetMindState();
451  if ( m_LastMindState != m_MindState )
452  {
453  switch ( m_MindState )
454  {
455  case DayZInfectedConstants.MINDSTATE_CALM:
456  if ( moveCommand && !moveCommand.IsTurning() )
457  moveCommand.SetIdleState(0);
458  break;
459 
460  case DayZInfectedConstants.MINDSTATE_DISTURBED:
461  if ( moveCommand && !moveCommand.IsTurning() )
462  moveCommand.SetIdleState(1);
463  break;
464 
465  case DayZInfectedConstants.MINDSTATE_CHASE:
466  if ( moveCommand && !moveCommand.IsTurning() && (m_LastMindState < DayZInfectedConstants.MINDSTATE_CHASE) )
467  moveCommand.SetIdleState(2);
468  break;
469  }
470 
471  m_LastMindState = m_MindState;
472  m_AttackCooldownTime = 0.0;
473  SetSynchDirty();
474  }
475  return false;
476  }
477 
478  //-------------------------------------------------------------
482 
483  protected void HandleSoundEvents()
484  {
486  if ( !m_InfectedSoundEventHandler )
487  {
488  return;
489  }
490 
492  if ( !IsAlive() )
493  {
495  m_InfectedSoundEventHandler.Stop();
496  return;
497  }
498 
499  switch ( m_MindState )
500  {
501  case DayZInfectedConstants.MINDSTATE_CALM:
502  m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_CALM_MOVE);
503  break;
504  case DayZInfectedConstants.MINDSTATE_ALERTED:
505  m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_ALERTED_MOVE);
506  break;
507  case DayZInfectedConstants.MINDSTATE_DISTURBED:
508  m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_DISTURBED_IDLE);
509  break
510  case DayZInfectedConstants.MINDSTATE_CHASE:
511  m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_CHASE_MOVE);
512  break;
513  default:
514  m_InfectedSoundEventHandler.Stop();
515  break;
516  }
517 
518  DebugSound("[Infected @ " + this + "][MindState]" + typename.EnumToString(DayZInfectedConstants, m_MindState));
519  DebugSound("[Infected @ " + this + "][SoundEventID]" + typename.EnumToString(EInfectedSoundEventID, m_InfectedSoundEventHandler.GetCurrentStateEventID()));
520  }
521 
522  AbstractWave ProcessVoiceFX(string pSoundSetName)
523  {
524  SoundParams soundParams;
525  SoundObjectBuilder soundObjectBuilder;
526  SoundObject soundObject;
527  if (!GetGame().IsDedicatedServer())
528  {
529  soundParams = new SoundParams( pSoundSetName );
530  if ( !soundParams.IsValid() )
531  {
532  //SoundError("Invalid sound set.");
533  return null;
534  }
535 
536  soundObjectBuilder = new SoundObjectBuilder( soundParams );
537  soundObject = soundObjectBuilder.BuildSoundObject();
538  AttenuateSoundIfNecessary(soundObject);
539 
540  return PlaySound(soundObject, soundObjectBuilder);
541  }
542 
543  return null;
544  }
545 
546  override void OnSoundVoiceEvent(int event_id, string event_user_string)
547  {
548  //super.OnSoundVoiceEvent(event_id, event_user_string);
549  AnimSoundVoiceEvent voice_event = GetCreatureAIType().GetSoundVoiceEvent(event_id);
550  if (voice_event != null)
551  {
553  if (m_InfectedSoundEventHandler) // && m_InfectedSoundEventHandler.IsPlaying())
554  {
555  m_InfectedSoundEventHandler.Stop();
556  DebugSound("[Infected @ " + this + "][SoundEvent] InfectedSoundEventHandler - stop all");
557  }
558 
560  if (m_LastSoundVoiceAW != null)
561  {
562  DebugSound("[Infected @ " + this + "][AnimVoiceEvent] Stopping LastAW");
563  m_LastSoundVoiceAW.Stop();
564  }
565 
567  ProcessSoundVoiceEvent(voice_event, m_LastSoundVoiceAW);
568 
569  HandleSoundEvents();
570  }
571  }
572 
573  protected void ProcessSoundVoiceEvent(AnimSoundVoiceEvent sound_event, out AbstractWave aw)
574  {
575  if (!GetGame().IsDedicatedServer())
576  {
577  SoundObjectBuilder objectBuilder = sound_event.GetSoundBuilder();
578  if (NULL != objectBuilder)
579  {
580  objectBuilder.AddEnvSoundVariables(GetPosition());
581  SoundObject soundObject = objectBuilder.BuildSoundObject();
582  AttenuateSoundIfNecessary(soundObject);
583  aw = PlaySound(soundObject, objectBuilder);
584  }
585  }
586 
587  if (GetGame().IsServer())
588  {
589  if (sound_event.m_NoiseParams != NULL)
590  GetGame().GetNoiseSystem().AddNoise(this, sound_event.m_NoiseParams);
591  }
592  }
593 
594  //-------------------------------------------------------------
598 
599  EntityAI m_ActualTarget = null;
600  float m_AttackCooldownTime = 0;
601  DayZInfectedAttackType m_ActualAttackType = null;
602 
603  bool FightLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
604  {
605  if (pCurrentCommandID == DayZInfectedConstants.COMMANDID_MOVE)
606  {
607  // we attack only in chase & fight state
608  int mindState = pInputController.GetMindState();
609  if (mindState == DayZInfectedConstants.MINDSTATE_CHASE)
610  {
611  return ChaseAttackLogic(pCurrentCommandID, pInputController, pDt);
612  }
613  else if (mindState == DayZInfectedConstants.MINDSTATE_FIGHT)
614  {
615  return FightAttackLogic(pCurrentCommandID, pInputController, pDt);
616  }
617  }
618  else if (pCurrentCommandID == DayZInfectedConstants.COMMANDID_ATTACK)
619  {
620  DayZInfectedCommandAttack attackCommand = GetCommand_Attack();
621  if (attackCommand && attackCommand.WasHit())
622  {
623  if (m_ActualTarget != null)
624  {
625  if (m_ActualTarget.GetMeleeTargetType() == EMeleeTargetType.NONALIGNABLE)
626  return false;
627 
628  bool playerInBlockStance = false;
629  vector targetPos = m_ActualTarget.GetPosition();
630  vector hitPosWS = targetPos;
631  vector zombiePos = GetPosition();
632 
633  PlayerBase playerTarget = PlayerBase.Cast(m_ActualTarget);
634  if (playerTarget)
635  {
636  playerInBlockStance = playerTarget.GetMeleeFightLogic() && playerTarget.GetMeleeFightLogic().IsInBlock();
637  }
638 
639  if (vector.DistanceSq(targetPos, zombiePos) <= m_ActualAttackType.m_Distance * m_ActualAttackType.m_Distance)
640  {
642  if (playerInBlockStance && (Math.RAD2DEG * Math.AbsFloat(Math3D.AngleFromPosition(targetPos, MiscGameplayFunctions.GetHeadingVector(playerTarget), zombiePos))) <= GameConstants.AI_MAX_BLOCKABLE_ANGLE)
643  {
645  if (m_ActualAttackType.m_IsHeavy == 1)
646  {
647  hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
648  DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), "MeleeZombie", hitPosWS);
649  }
650  else
651  {
653  hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
654  DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), "Dummy_Light", hitPosWS);
655  }
656  }
657  else
658  {
659  hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
660  DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), m_ActualAttackType.m_AmmoType, hitPosWS);
661  }
662  }
663  }
664  }
665 
666  return true;
667  }
668 
669  return false;
670  }
671 
672  bool ChaseAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
673  {
674  // always update target - it can be destroyed
675  m_ActualTarget = pInputController.GetTargetEntity();
676 
678  PlayerBase pb = PlayerBase.Cast(m_ActualTarget);
679  if ( pb && pb.GetCommand_Vehicle() )
680  {
681  return false;
682  }
683 
684  if ( m_ActualTarget == NULL )
685  return false;
686 
687  vector targetPos = m_ActualTarget.GetPosition();
688  if ( !CanAttackToPosition(targetPos) )
689  return false;
690 
691  float targetDist = vector.Distance(targetPos, this.GetPosition());
692  int pitch = GetAttackPitch(m_ActualTarget);
693 
694  m_ActualAttackType = GetDayZInfectedType().ChooseAttack(DayZInfectedAttackGroupType.CHASE, targetDist, pitch);
695  if (m_ActualAttackType)
696  {
697  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);
699  if (m_ActualTarget != target)
700  {
701  m_AllTargetObjects.Clear();
702  return false;
703  }
704 
705  StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
706  m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
707  return true;
708  }
709 
710  return false;
711  }
712 
713  bool FightAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
714  {
715  // always update target - it can be destroyed
716  m_ActualTarget = pInputController.GetTargetEntity();
717 
719  PlayerBase pb = PlayerBase.Cast(m_ActualTarget);
720  if (pb && pb.GetCommand_Vehicle())
721  return false;
722 
723  if (m_AttackCooldownTime > 0)
724  {
725  m_AttackCooldownTime -= pDt * GameConstants.AI_ATTACKSPEED;
726  return false;
727  }
728 
729  if (m_ActualTarget == null)
730  return false;
731 
732  vector targetPos = m_ActualTarget.GetPosition();
733  float targetDist = vector.Distance(targetPos, this.GetPosition());
734  int pitch = GetAttackPitch(m_ActualTarget);
735 
736  if (!CanAttackToPosition(targetPos))
737  return false;
738 
739  m_ActualAttackType = GetDayZInfectedType().ChooseAttack(DayZInfectedAttackGroupType.FIGHT, targetDist, pitch);
740  if (m_ActualAttackType)
741  {
742  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);
744  if (m_AllTargetObjects.Count() > 0 && m_AllTargetObjects[0] != m_ActualTarget)
745  {
746  m_AllTargetObjects.Clear();
747  return false;
748  }
749 
750  StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
751  m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
752  return true;
753  }
754 
755  return false;
756  }
757 
758  int GetAttackPitch(EntityAI target)
759  {
760  vector attackRefPos;
761 
762  attackRefPos = target.GetDefaultHitPosition();
764  if ( attackRefPos != vector.Zero )
765  {
766  attackRefPos = target.ModelToWorld(attackRefPos);
767  }
768  else
769  {
770  attackRefPos = target.GetPosition();
771  }
772 
773  // Now we have only erect stance, we need to get head position later too
774  float headPosY = GetPosition()[1];
775  headPosY += 1.8;
776 
777  float diff = Math.AbsFloat(attackRefPos[1] - headPosY);
778 
779  if ( diff < 0.3 )
780  return 0;
781 
782  if ( headPosY > attackRefPos[1] )
783  return -1;
784  else
785  return 1;
786  }
787 
788  //-------------------------------------------------------------
792 
793  int m_CrawlTransition = -1;
794 
795  bool HandleCrawlTransition(int pCurrentCommandID)
796  {
797  if ( m_CrawlTransition != -1 )
798  {
799  StartCommand_Crawl(m_CrawlTransition);
800 
801  m_CrawlTransition = -1;
802  m_IsCrawling = true;
803  SetSynchDirty();
804  return true;
805  }
806 
807  return pCurrentCommandID == DayZInfectedConstants.COMMANDID_CRAWL;
808  }
809 
810  bool EvaluateCrawlTransitionAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType)
811  {
812  pAnimType = -1;
813  if ( pComponent == "LeftLeg" && GetHealth(pComponent, "Health") == 0 )
814  pAnimType = 0;
815  else if ( pComponent == "RightLeg" && GetHealth(pComponent, "Health") == 0 )
816  pAnimType = 2;
817 
818  if ( pAnimType != -1 )
819  {
820  vector targetDirection = GetDirection();
821  vector toSourceDirection = (pSource.GetPosition() - GetPosition());
822 
823  targetDirection[1] = 0;
824  toSourceDirection[1] = 0;
825 
826  targetDirection.Normalize();
827  toSourceDirection.Normalize();
828 
829  float cosFi = vector.Dot(targetDirection, toSourceDirection);
830  if ( cosFi >= 0 ) // front
831  pAnimType++;
832  }
833 
834  return pAnimType != -1;
835  }
836 
837  //-------------------------------------------------------------
841 
842  bool m_DamageHitToProcess = false;
843 
844  bool m_DamageHitHeavy = false;
845  int m_DamageHitType = 0;
846  float m_ShockDamage = 0;
847 
848  const float HIT_INTERVAL_MIN = 0.3; // Minimum time in seconds before a COMMANDID_HIT to COMMANDID_HIT transition is allowed
849  float m_HitElapsedTime = HIT_INTERVAL_MIN;
850 
851  bool HandleDamageHit(int pCurrentCommandID)
852  {
853  if ( pCurrentCommandID == DayZInfectedConstants.COMMANDID_HIT )
854  {
855  // Throttle hit command up to a fixed rate
856  if ( m_HitElapsedTime < HIT_INTERVAL_MIN )
857  {
858  m_HitElapsedTime += m_DeltaTime;
859  m_DamageHitToProcess = false;
860  m_ShockDamage = 0;
861  return false;
862  }
863  }
864 
865  if ( m_DamageHitToProcess )
866  {
867  int randNum = Math.RandomIntInclusive(0, 100);
868  float stunChange = SHOCK_TO_STUN_MULTIPLIER * m_ShockDamage;
869 
870  if ( m_DamageHitHeavy || randNum <= stunChange || ( m_MindState == DayZInfectedConstants.MINDSTATE_CALM || m_MindState == DayZInfectedConstants.MINDSTATE_DISTURBED ) )
871  {
872  StartCommand_Hit(m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection);
873  m_HitElapsedTime = 0;
874  }
875 
876  m_DamageHitToProcess = false;
877  m_ShockDamage = 0;
878  m_HeavyHitOverride = false;
879  return true;
880  }
881 
882  return false;
883  }
884 
886  bool EvaluateDamageHitAnimation(EntityAI pSource, string pComponent, string pAmmoType, out bool pHeavyHit, out int pAnimType, out float pAnimHitDir)
887  {
888  int invertHitDir = 0; //Used to flip the heavy hit animation direction
889 
891  pHeavyHit = ((GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " hitAnimation") > 0) || m_HeavyHitOverride);
892  invertHitDir = GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " invertHitDir");
893 
895  pAnimType = 0; // belly
896 
897  if ( !pHeavyHit )
898  {
899  if ( pComponent == "Torso" ) // body
900  pAnimType = 1;
901  else if ( pComponent == "Head" ) // head
902  pAnimType = 2;
903  }
904 
906  //pAnimHitDir = ComputeHitDirectionAngle(pSource);
907  pAnimHitDir = ComputeHitDirectionAngleEx(pSource, invertHitDir);
909  //m_ShockDamage = GetGame().ConfigGetFloat( "CfgAmmo " + pAmmoType + " DamageApplied " + "Shock " + "damage");
910  return true;
911  }
912 
913  float ComputeHitDirectionAngle(EntityAI pSource)
914  {
915  vector targetDirection = GetDirection();
916  vector toSourceDirection = (pSource.GetPosition() - GetPosition());
917 
918  targetDirection[1] = 0;
919  toSourceDirection[1] = 0;
920 
921  targetDirection.Normalize();
922  toSourceDirection.Normalize();
923 
924  float cosFi = vector.Dot(targetDirection, toSourceDirection);
925  vector cross = targetDirection * toSourceDirection;
926 
927  float dirAngle = Math.Acos(cosFi) * Math.RAD2DEG;
928  if ( cross[1] < 0 )
929  dirAngle = -dirAngle;
930 
931  return dirAngle;
932  }
933 
934  float ComputeHitDirectionAngleEx(EntityAI pSource, int invertHitDir = 0)
935  {
936  vector targetDirection = GetDirection();
937  vector toSourceDirection = (pSource.GetPosition() - GetPosition());
938 
939  targetDirection[1] = 0;
940  toSourceDirection[1] = 0;
941 
942  targetDirection.Normalize();
943  toSourceDirection.Normalize();
944 
945  float cosFi = vector.Dot(targetDirection, toSourceDirection);
946  vector cross = targetDirection * toSourceDirection;
947 
948  float dirAngle = Math.Acos(cosFi) * Math.RAD2DEG;
949 
950  // We will invert direction of the hit
951  if ( invertHitDir > 0 )
952  dirAngle -= 180;
953 
954  if ( cross[1] < 0 )
955  dirAngle = -dirAngle;
956 
957  return dirAngle;
958  }
959 
960  //-------------------------------------------------------------
964 
965  override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
966  {
967  super.EEHitBy(damageResult, damageType, source, component, dmgZone, ammo, modelPos, speedCoef);
968 
969  m_TransportHitRegistered = false;
970 
971  if ( !IsAlive() )
972  {
973  ZombieHitData data = new ZombieHitData;
974  data.m_Component = component;
975  data.m_DamageZone = dmgZone;
976  data.m_AmmoType = ammo;
977  EvaluateDeathAnimationEx(source, data, m_DeathType, m_DamageHitDirection);
978  }
979  else
980  {
981  int crawlTransitionType = -1;
982  if ( EvaluateCrawlTransitionAnimation(source, dmgZone, ammo, crawlTransitionType) )
983  {
984  m_CrawlTransition = crawlTransitionType;
985  return;
986  }
987 
988  if ( EvaluateDamageHitAnimation(source, dmgZone, ammo, m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection) )
989  {
990  if ( dmgZone )
991  m_ShockDamage = damageResult.GetDamage( dmgZone, "Shock" );
992  m_DamageHitToProcess = true;
993  return;
994  }
995  }
996  }
997 
998  override void EEHitByRemote(int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos)
999  {
1000  super.EEHitByRemote(damageType, source, component, dmgZone, ammo, modelPos);
1001  }
1002 
1004  protected void DebugSound(string s)
1005  {
1006  //Print(s);
1007  }
1008 
1009  //-------------------------------------------------------------
1013 
1014  override protected void EOnContact(IEntity other, Contact extra)
1015  {
1016  if ( !IsAlive() )
1017  return;
1018 
1019  Transport transport = Transport.Cast(other);
1020  if ( transport )
1021  {
1022  if ( GetGame().IsServer() )
1023  {
1024  RegisterTransportHit(transport);
1025  }
1026  }
1027  }
1028 
1029  override bool CanReceiveAttachment(EntityAI attachment, int slotId)
1030  {
1031  if ( !IsAlive() )
1032  {
1033  return false;
1034  }
1035  return super.CanReceiveAttachment(attachment, slotId);
1036  }
1037 
1038  override vector GetCenter()
1039  {
1040  return GetBonePositionWS( GetBoneIndexByName( "spine3" ) );
1041  }
1042 
1044  override bool IsBeingBackstabbed()
1045  {
1046  return m_FinisherInProgress;
1047  }
1048 
1049  override void SetBeingBackstabbed(int backstabType)
1050  {
1051  // disable AI simulation
1052  GetAIAgent().SetKeepInIdle(true);
1053 
1054  // select death animation
1055  switch (backstabType)
1056  {
1057  case EMeleeHitType.FINISHER_LIVERSTAB:
1058  m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_BACKSTAB;
1059  break;
1060 
1061  case EMeleeHitType.FINISHER_NECKSTAB:
1062  m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_NECKSTAB;
1063  break;
1064 
1065  default:
1066  m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_DEFAULT;
1067  }
1068 
1069  // set flag - death command will be executed
1070  m_FinisherInProgress = true;
1071 
1072  //Print("DbgZombies | DumbZombie on: " + GetGame().GetTime());
1073  }
1074 
1076  bool IsCrawling()
1077  {
1078  return m_IsCrawling;
1079  }
1080 
1081  // called from command death when stealth attack wan't successful
1082  void OnRecoverFromDeath()
1083  {
1084  // enable AI simulation again
1085  GetAIAgent().SetKeepInIdle(false);
1086 
1087  // reset flag
1088  m_FinisherInProgress = false;
1089 
1090  //Print("DbgZombies | DumbZombie off: " + GetGame().GetTime());
1091  }
1092 
1093  override void AddArrow(Object arrow, int componentIndex, vector closeBonePosWS, vector closeBoneRotWS)
1094  {
1095  CachedObjectsArrays.ARRAY_STRING.Clear();
1096  GetActionComponentNameList(componentIndex, CachedObjectsArrays.ARRAY_STRING, "fire");
1097 
1098  int pivot = -1;
1099 
1100 
1101  for (int i = 0; i < CachedObjectsArrays.ARRAY_STRING.Count() && pivot == -1; i++)
1102  {
1103  pivot = GetBoneIndexByName(CachedObjectsArrays.ARRAY_STRING.Get(i));
1104  }
1105 
1106  vector parentTransMat[4];
1107  vector arrowTransMat[4];
1108 
1109  if (pivot == -1)
1110  {
1111  GetTransformWS(parentTransMat);
1112  }
1113  else
1114  {
1115  vector rotMatrix[3];
1116  Math3D.YawPitchRollMatrix(closeBoneRotWS * Math.RAD2DEG,rotMatrix);
1117 
1118  parentTransMat[0] = rotMatrix[0];
1119  parentTransMat[1] = rotMatrix[1];
1120  parentTransMat[2] = rotMatrix[2];
1121  parentTransMat[3] = closeBonePosWS;
1122  }
1123 
1124  arrow.GetTransform(arrowTransMat);
1125  Math3D.MatrixInvMultiply4(parentTransMat, arrowTransMat, arrowTransMat);
1126  // orthogonalize matrix - parent might be skewed
1127  Math3D.MatrixOrthogonalize4(arrowTransMat);
1128  arrow.SetTransform(arrowTransMat);
1129 
1130  AddChild(arrow, pivot);
1131  }
1132 
1133  override bool IsManagingArrows()
1134  {
1135  return true;
1136  }
1137 
1139  {
1140  return m_ArrowManager;
1141  }
1142 }
1143 
1145 class ZombieHitData
1146 {
1147  int m_Component;
1149  string m_AmmoType;
1150 }
GetGame
proto native CGame GetGame()
DayZInfectedInputController
Definition: dayzinfectedinputcontroller.c:1
IsManagingArrows
override bool IsManagingArrows()
Definition: dayzanimal.c:70
GetBoneIndexByName
proto native int GetBoneIndexByName(string pBoneName)
returns bone index for a name (-1 if pBoneName doesn't exist)
DayZPlayerUtils
private void DayZPlayerUtils()
cannot be instantiated
Definition: dayzplayerutils.c:461
GetSuitableFinisherHitComponents
array< string > GetSuitableFinisherHitComponents()
Definition: dayzplayer.c:507
ModCommandHandlerAfter
bool ModCommandHandlerAfter(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
Definition: dayzanimal.c:136
dBodyApplyImpulse
proto void dBodyApplyImpulse(notnull IEntity body, vector impulse)
Applies impuls on a rigidbody (origin)
SoundObject
class SoundObjectBuilder SoundObject(SoundParams soundParams)
EEHitByRemote
override void EEHitByRemote(int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos)
Definition: clockbase.c:128
OnVariablesSynchronized
override void OnVariablesSynchronized()
Definition: anniversarymusicsource.c:42
CommandHandler
void CommandHandler(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
-------------— command handling ----------------------—
DayZInfected
Definition: zombiebase.c:1
GetTransformWS
enum HumanMoveCommandID GetTransformWS(out vector pTm[4])
gets human transform in World Space
component
class BoxCollidingParams component
ComponentInfo for BoxCollidingResult.
CanBeSkinned
override bool CanBeSkinned()
Definition: dayzanimal.c:60
SoundObjectBuilder
void SoundObjectBuilder(SoundParams soundParams)
DayZInfectedCommandMove
Definition: dayzinfectedimplement.c:1
EOnInit
protected override void EOnInit(IEntity other, int extra)
Definition: testframework.c:235
m_AmmoType
string m_AmmoType
Definition: zombiebase.c:1149
AnimBootsType
AnimBootsType
Definition: dayzanimevents.c:97
IEntity
Definition: enentity.c:164
EOnContact
override void EOnContact(IEntity other, Contact extra)
Definition: easteregg.c:112
DayZInfectedAttackGroupType
DayZInfectedAttackGroupType
Definition: dayzinfectedtype.c:13
ModCommandHandlerInside
bool ModCommandHandlerInside(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
Definition: dayzanimal.c:131
AnimalBase
Definition: animalbase.c:77
SoundParams
Definition: sound.c:100
GetPosition
class JsonUndergroundAreaTriggerData GetPosition
Definition: undergroundarealoader.c:9
PlayerBase
Definition: playerbaseclient.c:1
vector
Definition: enconvert.c:105
Init
class InventoryGridController extends ScriptedWidgetEventHandler Init
Definition: uihintpanel.c:46
TotalDamageResult
Definition: damagesystem.c:1
GetHitComponentForAI
string GetHitComponentForAI()
Definition: dayzplayer.c:485
GetArrowManager
override ArrowManagerBase GetArrowManager()
Definition: animalbase.c:9
GetInputController
proto native HumanInputController GetInputController()
returns human input controller
Object
Definition: objecttyped.c:1
DayZInfectedConstants
DayZInfectedConstants
Definition: dayzinfected.c:1
Transport
Base native class for all motorized wheeled vehicles.
Definition: car.c:79
IsDanger
override bool IsDanger()
Definition: animalbase.c:61
Contact
Definition: enphysics.c:300
EEHitBy
override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
Definition: broom.c:43
AddArrow
override void AddArrow(Object arrow, int componentIndex, vector closeBonePosWS, vector closeBoneRotWS)
Definition: dayzanimal.c:75
GetPluginManager
PluginManager GetPluginManager()
Returns registred plugin by class type, better is to use global funtion GetPlugin(typename plugin_typ...
Definition: pluginmanager.c:274
EMeleeHitType
EMeleeHitType
Definition: dayzplayerimplementmeleecombat.c:1
DayZInfectedAttackType
Definition: dayzinfectedtype.c:1
array< Object >
GetDefaultHitPosition
override vector GetDefaultHitPosition()
Definition: carscript.c:2592
m_TargetableObjects
protected ref array< typename > m_TargetableObjects
Typenames of all directly/preferred targetable objects (1st Pass + 2nd Pass)
Definition: dayzplayerimplementmeleecombat.c:49
StartCommand_Move
proto native HumanCommandMove StartCommand_Move()
--— MOVE --—
m_ArrowManager
protected ref ArrowManagerBase m_ArrowManager
Definition: animalbase.c:2
GameConstants
Definition: constants.c:612
StartCommand_Death
proto native HumanCommandDeathCallback StartCommand_Death(int pType, float pDirection, typename pCallbackClass, bool pKeepInLocalSpaceAfterLeave=false)
--— Death --—
ModCommandHandlerBefore
bool ModCommandHandlerBefore(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
Definition: dayzanimal.c:126
SoundObjectBuilder
Definition: sound.c:45
AddChild
proto native void AddChild(Widget child, bool immedUpdate=true)
PlaySound
void PlaySound()
Definition: hungersoundhandler.c:38
GetDefaultHitComponent
string GetDefaultHitComponent()
Definition: dayzplayer.c:497
InfectedSoundEventHandler
void InfectedSoundEventHandler(ZombieBase pInfected)
Definition: infectedsoundeventhandler.c:21
m_AllTargetObjects
protected ref array< Object > m_AllTargetObjects
All potential targets found during most recent TargetSelection.
Definition: dayzplayerimplementmeleecombat.c:42
GetDefaultHitPositionComponent
string GetDefaultHitPositionComponent()
Definition: dayzplayer.c:502
Math
Definition: enmath.c:6
m_Component
class ZombieBase extends DayZInfected m_Component
an extendable data container
EntityEvent
EntityEvent
Entity events for event-mask, or throwing event from code.
Definition: enentity.c:44
m_DamageZone
string m_DamageZone
Definition: zombiebase.c:1148
AbstractWave
Definition: sound.c:118
IsRefresherSignalingViable
override bool IsRefresherSignalingViable()
Definition: animalbase.c:14
EInfectedSoundEventID
EInfectedSoundEventID
Definition: infectedsoundeventhandler.c:1
CanReceiveAttachment
override bool CanReceiveAttachment(EntityAI attachment, int slotId)
Definition: basebuildingbase.c:895
ArrowManagerBase
Definition: arrowmanagerbase.c:1
ZombieBase
Definition: zombiefemalebase.c:1
EntityAI
Definition: building.c:5
Math3D
Definition: enmath3d.c:27
CachedObjectsArrays
Definition: utilityclasses.c:40
GetCommand_Move
proto native HumanCommandMove GetCommand_Move()
EMeleeTargetType
EMeleeTargetType
Definition: emeleetargettype.c:1
GetOrientation
vector GetOrientation()
Definition: areadamagemanager.c:306