Dayz Explorer 1.28.160049
Loading...
Searching...
No Matches
zombiebase.c
Go to the documentation of this file.
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
24 protected float m_DeltaTime;
25
28
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
39
40
41
42 //-------------------------------------------------------------
44 {
45 Init();
46 }
47
48 void Init()
49 {
50 SetEventMask(EntityEvent.INIT | EntityEvent.CONTACT);
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
77 }
78
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
98 DayZInfectedCommandMove moveCommand = GetCommand_Move();
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 //-------------------------------------------------------------
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 //-------------------------------------------------------------
145 {
146 return false;
147 }
148
150 {
151 return IsAlive();
152 }
153
155 override string GetHitComponentForAI()
156 {
157 return GetDayZInfectedType().GetHitComponentForAI();
158 }
159
161 override string GetDefaultHitComponent()
162 {
163 return GetDayZInfectedType().GetDefaultHitComponent();
164 }
165
167 {
168 return m_DefaultHitPosition;
169 }
170
171 protected vector SetDefaultHitPosition(string pSelection)
172 {
173 return GetSelectionPositionMS(pSelection);
174 }
175
178 {
179 return GetDayZInfectedType().GetSuitableFinisherHitComponents();
180 }
181
183 {
184 return m_MindState;
185 }
186
189 {
190 return m_OrientationSynced;
191 }
192
193 //-------------------------------------------------------------
197
198 void CommandHandler(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
199 {
200 m_DeltaTime = pDt;
201
203 if ( ModCommandHandlerBefore(pDt, pCurrentCommandID, pCurrentCommandFinished) )
204 {
205 return;
206 }
207
209 if ( pCurrentCommandID != DayZInfectedConstants.COMMANDID_DEATH )
210 {
211 if ( HandleDeath(pCurrentCommandID) )
212 return;
213 }
214 else if (!pCurrentCommandFinished)
215 {
216 return;
217 }
218
219
221 HandleMove(pCurrentCommandID);
222 HandleOrientation(pDt,pCurrentCommandID);
223
225 if (pCurrentCommandFinished)
226 {
228 DayZInfectedCommandMove moveCommand = StartCommand_Move();
229 moveCommand.SetStanceVariation(m_StanceVariation);
230
231 return;
232 }
233
235 if ( ModCommandHandlerInside(pDt, pCurrentCommandID, pCurrentCommandFinished) )
236 {
237 return;
238 }
239
241 if ( HandleCrawlTransition(pCurrentCommandID) )
242 {
243 return;
244 }
245
247 if ( HandleDamageHit(pCurrentCommandID) )
248 {
249 return;
250 }
251
252 DayZInfectedInputController inputController = GetInputController();
253 if ( inputController )
254 {
255 if ( HandleVault(pCurrentCommandID, inputController, pDt) )
256 {
257 return;
258 }
259
260 if ( HandleMindStateChange(pCurrentCommandID, inputController, pDt) )
261 {
262 return;
263 }
264
265 if ( FightLogic(pCurrentCommandID, inputController, pDt) )
266 {
267 return;
268 }
269 }
270
272 if ( ModCommandHandlerAfter(pDt, pCurrentCommandID, pCurrentCommandFinished) )
273 {
274 return;
275 }
276 }
277
278 //-------------------------------------------------------------
282
283 void CommandHandlerDebug(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
284 {
285 if ( GetPluginManager() )
286 {
287 PluginDayZInfectedDebug infectedDebug = PluginDayZInfectedDebug.Cast(GetPluginManager().GetPluginByType(PluginDayZInfectedDebug));
288 if ( infectedDebug )
289 infectedDebug.CommandHandler(this);
290 }
291 }
292 //-------------------------------------------------------------
296
297 void HandleMove(int pCurrentCommandID)
298 {
299 DayZInfectedInputController ic = GetInputController();
300 m_MovementSpeed = ic.GetMovementSpeed();
301 if (Math.AbsFloat(m_LastMovementSpeed - m_MovementSpeed) >= 0.9 && m_LastMovementSpeed != m_MovementSpeed)
302 {
303 SetSynchDirty();
304 }
305
306 m_LastMovementSpeed = m_MovementSpeed;
307 }
308
309 //-------------------------------------------------------------
313
314 void HandleOrientation(float pDt, int pCurrentCommandID)
315 {
316 m_OrientationTimer += pDt;
317
318 int yaw = Math.Round(GetOrientation()[0]);
319 yaw = Math.NormalizeAngle(yaw);
320
321 //atan2(sin(x-y), cos(x-y))
322 float angleSourceRad = m_OrientationSynced * Math.DEG2RAD;
323 float angleTargetRad = yaw * Math.DEG2RAD;
324
325 float angleDiffRad = Math.Atan2(Math.Sin(angleTargetRad - angleSourceRad), Math.Cos(angleSourceRad - angleTargetRad));
326 angleDiffRad *= Math.RAD2DEG;
327 angleDiffRad = Math.Round(angleDiffRad);
328
329 if (m_OrientationTimer >= 2.0 || m_OrientationSynced == -1 || Math.AbsInt(angleDiffRad) > ORIENTATION_SYNC_THRESHOLD)
330 {
331 m_OrientationTimer = 0.0;
332
333 if (m_OrientationSynced == -1 || Math.AbsInt(angleDiffRad) > 5)
334 {
335 m_OrientationSynced = yaw;
336 SetSynchDirty();
337 }
338 }
339 }
340
341 //-------------------------------------------------------------
345
346 float m_DamageHitDirection = 0;
347 int m_DeathType = 0;
348
349 bool HandleDeath(int pCurrentCommandID)
350 {
351 if ( !IsAlive() || m_FinisherInProgress )
352 {
353 StartCommand_Death(m_DeathType, m_DamageHitDirection);
354 m_MovementSpeed = -1;
355 m_MindState = -1;
356 SetSynchDirty();
357 return true;
358 }
359
360 return false;
361 }
362
363 bool EvaluateDeathAnimationEx(EntityAI pSource, ZombieHitData data, out int pAnimType, out float pAnimHitDir)
364 {
365 bool ret = EvaluateDeathAnimation(pSource,data.m_DamageZone,data.m_AmmoType,pAnimType,pAnimHitDir);
366
367 return ret;
368 }
369
370 bool EvaluateDeathAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType, out float pAnimHitDir)
371 {
373 bool doPhxImpulse = GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " doPhxImpulse") > 0;
374
376 pAnimType = doPhxImpulse;
377
379 pAnimHitDir = ComputeHitDirectionAngle(pSource);
380
382 if ( doPhxImpulse )
383 {
384 vector impulse = 80 * m_TransportHitVelocity;
385 impulse[1] = 80 * 1.5;
386 //Print("Impulse: " + impulse.ToString());
387
388 dBodyApplyImpulse(this, impulse);
389 }
390
391 return true;
392 }
393
394 //-------------------------------------------------------------
398
399 int m_ActiveVaultType = -1;
400
401 int GetVaultType(float height)
402 {
403 if ( height <= 0.6 )
404 return 0;
405 else if ( height <= 1.1 )
406 return 1;
407 else if ( height <= 1.6 )
408 return 2;
409 else
410 return 3;
411 }
412
413 bool HandleVault(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
414 {
415 if ( pCurrentCommandID == DayZInfectedConstants.COMMANDID_VAULT )
416 {
417 DayZInfectedCommandVault vaultCmd = GetCommand_Vault();
418 if ( vaultCmd && vaultCmd.WasLand() )
419 {
420 m_KnuckleOutTimer = 0;
421 m_KnuckleLand = true;
422 }
423 if ( m_KnuckleLand )
424 {
425 m_KnuckleOutTimer += pDt;
426 if ( m_KnuckleOutTimer > 2.0 )
427 StartCommand_Vault(-1);
428 }
429
430 return true;
431 }
432
433 if ( pInputController.IsVault() )
434 {
435 float vaultHeight = pInputController.GetVaultHeight();
436 int vaultType = GetVaultType(vaultHeight);
437 m_KnuckleLand = false;
438 StartCommand_Vault(vaultType);
439 return true;
440 }
441
442 return false;
443 }
444
445 //-------------------------------------------------------------
449
450 bool HandleMindStateChange(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
451 {
452 DayZInfectedCommandMove moveCommand = GetCommand_Move();
453
454 m_MindState = pInputController.GetMindState();
455 if ( m_LastMindState != m_MindState )
456 {
457 switch ( m_MindState )
458 {
459 case DayZInfectedConstants.MINDSTATE_CALM:
460 if ( moveCommand && !moveCommand.IsTurning() )
461 moveCommand.SetIdleState(0);
462 break;
463
464 case DayZInfectedConstants.MINDSTATE_DISTURBED:
465 if ( moveCommand && !moveCommand.IsTurning() )
466 moveCommand.SetIdleState(1);
467 break;
468
469 case DayZInfectedConstants.MINDSTATE_CHASE:
470 if ( moveCommand && !moveCommand.IsTurning() && (m_LastMindState < DayZInfectedConstants.MINDSTATE_CHASE) )
471 moveCommand.SetIdleState(2);
472 break;
473 }
474
475 m_LastMindState = m_MindState;
476 m_AttackCooldownTime = 0.0;
477 SetSynchDirty();
478 }
479 return false;
480 }
481
482 //-------------------------------------------------------------
486
487 protected void HandleSoundEvents()
488 {
490 if ( !m_InfectedSoundEventHandler )
491 {
492 return;
493 }
494
496 if ( !IsAlive() )
497 {
499 m_InfectedSoundEventHandler.Stop();
500 return;
501 }
502
503 switch ( m_MindState )
504 {
505 case DayZInfectedConstants.MINDSTATE_CALM:
506 m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_CALM_MOVE);
507 break;
508 case DayZInfectedConstants.MINDSTATE_ALERTED:
509 m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_ALERTED_MOVE);
510 break;
511 case DayZInfectedConstants.MINDSTATE_DISTURBED:
512 m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_DISTURBED_IDLE);
513 break
514 case DayZInfectedConstants.MINDSTATE_CHASE:
515 m_InfectedSoundEventHandler.PlayRequest(EInfectedSoundEventID.MINDSTATE_CHASE_MOVE);
516 break;
517 default:
518 m_InfectedSoundEventHandler.Stop();
519 break;
520 }
521
522 DebugSound("[Infected @ " + this + "][MindState]" + typename.EnumToString(DayZInfectedConstants, m_MindState));
523 DebugSound("[Infected @ " + this + "][SoundEventID]" + typename.EnumToString(EInfectedSoundEventID, m_InfectedSoundEventHandler.GetCurrentStateEventID()));
524 }
525
526 AbstractWave ProcessVoiceFX(string pSoundSetName)
527 {
528 SoundParams soundParams;
529 SoundObjectBuilder soundObjectBuilder;
530 SoundObject soundObject;
531 if (!GetGame().IsDedicatedServer())
532 {
533 soundParams = new SoundParams( pSoundSetName );
534 if ( !soundParams.IsValid() )
535 {
536 //SoundError("Invalid sound set.");
537 return null;
538 }
539
540 soundObjectBuilder = new SoundObjectBuilder( soundParams );
541 soundObject = soundObjectBuilder.BuildSoundObject();
542 AttenuateSoundIfNecessary(soundObject);
543
544 return PlaySound(soundObject, soundObjectBuilder);
545 }
546
547 return null;
548 }
549
550 override void OnSoundVoiceEvent(int event_id, string event_user_string)
551 {
552 //super.OnSoundVoiceEvent(event_id, event_user_string);
553 AnimSoundVoiceEvent voice_event = GetCreatureAIType().GetSoundVoiceEvent(event_id);
554 if (voice_event != null)
555 {
557 if (m_InfectedSoundEventHandler) // && m_InfectedSoundEventHandler.IsPlaying())
558 {
559 m_InfectedSoundEventHandler.Stop();
560 DebugSound("[Infected @ " + this + "][SoundEvent] InfectedSoundEventHandler - stop all");
561 }
562
564 if (m_LastSoundVoiceAW != null)
565 {
566 DebugSound("[Infected @ " + this + "][AnimVoiceEvent] Stopping LastAW");
567 m_LastSoundVoiceAW.Stop();
568 }
569
571 ProcessSoundVoiceEvent(voice_event, m_LastSoundVoiceAW);
572
573 HandleSoundEvents();
574 }
575 }
576
577 protected void ProcessSoundVoiceEvent(AnimSoundVoiceEvent sound_event, out AbstractWave aw)
578 {
579 if (!GetGame().IsDedicatedServer())
580 {
581 SoundObjectBuilder objectBuilder = sound_event.GetSoundBuilder();
582 if (NULL != objectBuilder)
583 {
584 objectBuilder.AddEnvSoundVariables(GetPosition());
585 SoundObject soundObject = objectBuilder.BuildSoundObject();
586 AttenuateSoundIfNecessary(soundObject);
587 aw = PlaySound(soundObject, objectBuilder);
588 }
589 }
590
591 if (GetGame().IsServer())
592 {
593 if (sound_event.m_NoiseParams != NULL)
594 GetGame().GetNoiseSystem().AddNoise(this, sound_event.m_NoiseParams, NoiseAIEvaluate.GetNoiseReduction(GetGame().GetWeather()));
595 }
596 }
597
598 //-------------------------------------------------------------
602
603 EntityAI m_ActualTarget = null;
604 float m_AttackCooldownTime = 0;
605 DayZInfectedAttackType m_ActualAttackType = null;
606
607 bool FightLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
608 {
609 if (pCurrentCommandID == DayZInfectedConstants.COMMANDID_MOVE)
610 {
611 // we attack only in chase & fight state
612 int mindState = pInputController.GetMindState();
613 if (mindState == DayZInfectedConstants.MINDSTATE_CHASE)
614 {
615 return ChaseAttackLogic(pCurrentCommandID, pInputController, pDt);
616 }
617 else if (mindState == DayZInfectedConstants.MINDSTATE_FIGHT)
618 {
619 return FightAttackLogic(pCurrentCommandID, pInputController, pDt);
620 }
621 }
622 else if (pCurrentCommandID == DayZInfectedConstants.COMMANDID_ATTACK)
623 {
624 DayZInfectedCommandAttack attackCommand = GetCommand_Attack();
625 if (attackCommand && attackCommand.WasHit())
626 {
627 if (m_ActualTarget != null)
628 {
629 if (m_ActualTarget.GetMeleeTargetType() == EMeleeTargetType.NONALIGNABLE)
630 return false;
631
632 bool playerInBlockStance = false;
633 vector targetPos = m_ActualTarget.GetPosition();
634 vector hitPosWS = targetPos;
635 vector zombiePos = GetPosition();
636
637 PlayerBase playerTarget = PlayerBase.Cast(m_ActualTarget);
638 if (playerTarget)
639 {
640 playerInBlockStance = playerTarget.GetMeleeFightLogic() && playerTarget.GetMeleeFightLogic().IsInBlock();
641 }
642
643 if (vector.DistanceSq(targetPos, zombiePos) <= m_ActualAttackType.m_Distance * m_ActualAttackType.m_Distance)
644 {
646 if (playerInBlockStance && (Math.RAD2DEG * Math.AbsFloat(Math3D.AngleFromPosition(targetPos, MiscGameplayFunctions.GetHeadingVector(playerTarget), zombiePos))) <= GameConstants.AI_MAX_BLOCKABLE_ANGLE)
647 {
649 if (m_ActualAttackType.m_IsHeavy == 1)
650 {
651 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
652 DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), "MeleeZombie", hitPosWS);
653 }
654 else
655 {
657 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
658 DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), "Dummy_Light", hitPosWS);
659 }
660 }
661 else
662 {
663 hitPosWS = m_ActualTarget.ModelToWorld(m_ActualTarget.GetDefaultHitPosition());
664 DamageSystem.CloseCombatDamageName(this, m_ActualTarget, m_ActualTarget.GetHitComponentForAI(), m_ActualAttackType.m_AmmoType, hitPosWS);
665 }
666 }
667 }
668 }
669
670 return true;
671 }
672
673 return false;
674 }
675
676 bool ChaseAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
677 {
678 // always update target - it can be destroyed
679 m_ActualTarget = pInputController.GetTargetEntity();
680
682 PlayerBase pb = PlayerBase.Cast(m_ActualTarget);
683 if ( pb && pb.GetCommand_Vehicle() )
684 {
685 return false;
686 }
687
688 if ( m_ActualTarget == NULL )
689 return false;
690
691 vector targetPos = m_ActualTarget.GetPosition();
692 if ( !CanAttackToPosition(targetPos) )
693 return false;
694
695 float targetDist = vector.Distance(targetPos, this.GetPosition());
696 int pitch = GetAttackPitch(m_ActualTarget);
697
698 m_ActualAttackType = GetDayZInfectedType().ChooseAttack(DayZInfectedAttackGroupType.CHASE, targetDist, pitch);
699 if (m_ActualAttackType)
700 {
701 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);
703 if (m_ActualTarget != target)
704 {
705 m_AllTargetObjects.Clear();
706 return false;
707 }
708
709 StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
710 m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
711 return true;
712 }
713
714 return false;
715 }
716
717 bool FightAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
718 {
719 // always update target - it can be destroyed
720 m_ActualTarget = pInputController.GetTargetEntity();
721
723 PlayerBase pb = PlayerBase.Cast(m_ActualTarget);
724 if (pb && pb.GetCommand_Vehicle())
725 return false;
726
727 if (m_AttackCooldownTime > 0)
728 {
729 m_AttackCooldownTime -= pDt * GameConstants.AI_ATTACKSPEED;
730 return false;
731 }
732
733 if (m_ActualTarget == null)
734 return false;
735
736 vector targetPos = m_ActualTarget.GetPosition();
737 float targetDist = vector.Distance(targetPos, this.GetPosition());
738 int pitch = GetAttackPitch(m_ActualTarget);
739
740 if (!CanAttackToPosition(targetPos))
741 return false;
742
743 m_ActualAttackType = GetDayZInfectedType().ChooseAttack(DayZInfectedAttackGroupType.FIGHT, targetDist, pitch);
744 if (m_ActualAttackType)
745 {
746 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);
748 if (m_AllTargetObjects.Count() > 0 && m_AllTargetObjects[0] != m_ActualTarget)
749 {
750 m_AllTargetObjects.Clear();
751 return false;
752 }
753
754 StartCommand_Attack(m_ActualTarget, m_ActualAttackType.m_Type, m_ActualAttackType.m_Subtype);
755 m_AttackCooldownTime = m_ActualAttackType.m_Cooldown;
756 return true;
757 }
758
759 return false;
760 }
761
763 {
764 vector attackRefPos;
765
766 attackRefPos = target.GetDefaultHitPosition();
768 if ( attackRefPos != vector.Zero )
769 {
770 attackRefPos = target.ModelToWorld(attackRefPos);
771 }
772 else
773 {
774 attackRefPos = target.GetPosition();
775 }
776
777 // Now we have only erect stance, we need to get head position later too
778 float headPosY = GetPosition()[1];
779 headPosY += 1.8;
780
781 float diff = Math.AbsFloat(attackRefPos[1] - headPosY);
782
783 if ( diff < 0.3 )
784 return 0;
785
786 if ( headPosY > attackRefPos[1] )
787 return -1;
788 else
789 return 1;
790 }
791
792 //-------------------------------------------------------------
796
797 int m_CrawlTransition = -1;
798
799 bool HandleCrawlTransition(int pCurrentCommandID)
800 {
801 if ( m_CrawlTransition != -1 )
802 {
803 StartCommand_Crawl(m_CrawlTransition);
804
805 m_CrawlTransition = -1;
806 m_IsCrawling = true;
807 SetSynchDirty();
808 return true;
809 }
810
811 return pCurrentCommandID == DayZInfectedConstants.COMMANDID_CRAWL;
812 }
813
814 bool EvaluateCrawlTransitionAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType)
815 {
816 pAnimType = -1;
817 if ( pComponent == "LeftLeg" && GetHealth(pComponent, "Health") == 0 )
818 pAnimType = 0;
819 else if ( pComponent == "RightLeg" && GetHealth(pComponent, "Health") == 0 )
820 pAnimType = 2;
821
822 if ( pAnimType != -1 )
823 {
824 vector targetDirection = GetDirection();
825 vector toSourceDirection = (pSource.GetPosition() - GetPosition());
826
827 targetDirection[1] = 0;
828 toSourceDirection[1] = 0;
829
830 targetDirection.Normalize();
831 toSourceDirection.Normalize();
832
833 float cosFi = vector.Dot(targetDirection, toSourceDirection);
834 if ( cosFi >= 0 ) // front
835 pAnimType++;
836 }
837
838 return pAnimType != -1;
839 }
840
841 //-------------------------------------------------------------
845
846 bool m_DamageHitToProcess = false;
847
848 bool m_DamageHitHeavy = false;
849 int m_DamageHitType = 0;
850 float m_ShockDamage = 0;
851
852 const float HIT_INTERVAL_MIN = 0.3; // Minimum time in seconds before a COMMANDID_HIT to COMMANDID_HIT transition is allowed
853 float m_HitElapsedTime = HIT_INTERVAL_MIN;
854
855 bool HandleDamageHit(int pCurrentCommandID)
856 {
857 if ( pCurrentCommandID == DayZInfectedConstants.COMMANDID_HIT )
858 {
859 // Throttle hit command up to a fixed rate
860 if ( m_HitElapsedTime < HIT_INTERVAL_MIN )
861 {
862 m_HitElapsedTime += m_DeltaTime;
863 m_DamageHitToProcess = false;
864 m_ShockDamage = 0;
865 return false;
866 }
867 }
868
869 if ( m_DamageHitToProcess )
870 {
871 int randNum = Math.RandomIntInclusive(0, 100);
872 float stunChange = SHOCK_TO_STUN_MULTIPLIER * m_ShockDamage;
873
874 if ( m_DamageHitHeavy || randNum <= stunChange || ( m_MindState == DayZInfectedConstants.MINDSTATE_CALM || m_MindState == DayZInfectedConstants.MINDSTATE_DISTURBED ) )
875 {
876 StartCommand_Hit(m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection);
877 m_HitElapsedTime = 0;
878 }
879
880 m_DamageHitToProcess = false;
881 m_ShockDamage = 0;
882 m_HeavyHitOverride = false;
883 return true;
884 }
885
886 return false;
887 }
888
890 bool EvaluateDamageHitAnimation(EntityAI pSource, string pComponent, string pAmmoType, out bool pHeavyHit, out int pAnimType, out float pAnimHitDir)
891 {
892 int invertHitDir = 0; //Used to flip the heavy hit animation direction
893
895 pHeavyHit = ((GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " hitAnimation") > 0) || m_HeavyHitOverride);
896 invertHitDir = GetGame().ConfigGetInt("cfgAmmo " + pAmmoType + " invertHitDir");
897
899 pAnimType = 0; // belly
900
901 if ( !pHeavyHit )
902 {
903 if ( pComponent == "Torso" ) // body
904 pAnimType = 1;
905 else if ( pComponent == "Head" ) // head
906 pAnimType = 2;
907 }
908
910 //pAnimHitDir = ComputeHitDirectionAngle(pSource);
911 pAnimHitDir = ComputeHitDirectionAngleEx(pSource, invertHitDir);
913 //m_ShockDamage = GetGame().ConfigGetFloat( "CfgAmmo " + pAmmoType + " DamageApplied " + "Shock " + "damage");
914 return true;
915 }
916
918 {
919 vector targetDirection = GetDirection();
920 vector toSourceDirection = (pSource.GetPosition() - GetPosition());
921
922 targetDirection[1] = 0;
923 toSourceDirection[1] = 0;
924
925 targetDirection.Normalize();
926 toSourceDirection.Normalize();
927
928 float cosFi = vector.Dot(targetDirection, toSourceDirection);
929 vector cross = targetDirection * toSourceDirection;
930
931 float dirAngle = Math.Acos(cosFi) * Math.RAD2DEG;
932 if ( cross[1] < 0 )
933 dirAngle = -dirAngle;
934
935 return dirAngle;
936 }
937
938 float ComputeHitDirectionAngleEx(EntityAI pSource, int invertHitDir = 0)
939 {
940 vector targetDirection = GetDirection();
941 vector toSourceDirection = (pSource.GetPosition() - GetPosition());
942
943 targetDirection[1] = 0;
944 toSourceDirection[1] = 0;
945
946 targetDirection.Normalize();
947 toSourceDirection.Normalize();
948
949 float cosFi = vector.Dot(targetDirection, toSourceDirection);
950 vector cross = targetDirection * toSourceDirection;
951
952 float dirAngle = Math.Acos(cosFi) * Math.RAD2DEG;
953
954 // We will invert direction of the hit
955 if ( invertHitDir > 0 )
956 dirAngle -= 180;
957
958 if ( cross[1] < 0 )
959 dirAngle = -dirAngle;
960
961 return dirAngle;
962 }
963
964 //-------------------------------------------------------------
968
969 override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
970 {
971 super.EEHitBy(damageResult, damageType, source, component, dmgZone, ammo, modelPos, speedCoef);
972
973 m_TransportHitRegistered = false;
974
975 if ( !IsAlive() )
976 {
977 ZombieHitData data = new ZombieHitData;
978 data.m_Component = component;
979 data.m_DamageZone = dmgZone;
980 data.m_AmmoType = ammo;
981 EvaluateDeathAnimationEx(source, data, m_DeathType, m_DamageHitDirection);
982 }
983 else
984 {
985 int crawlTransitionType = -1;
986 if ( EvaluateCrawlTransitionAnimation(source, dmgZone, ammo, crawlTransitionType) )
987 {
988 m_CrawlTransition = crawlTransitionType;
989 return;
990 }
991
992 if ( EvaluateDamageHitAnimation(source, dmgZone, ammo, m_DamageHitHeavy, m_DamageHitType, m_DamageHitDirection) )
993 {
994 if ( dmgZone )
995 m_ShockDamage = damageResult.GetDamage( dmgZone, "Shock" );
996 m_DamageHitToProcess = true;
997 return;
998 }
999 }
1000 }
1001
1002 override void EEHitByRemote(int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos)
1003 {
1004 super.EEHitByRemote(damageType, source, component, dmgZone, ammo, modelPos);
1005 }
1006
1008 protected void DebugSound(string s)
1009 {
1010 //Print(s);
1011 }
1012
1013 //-------------------------------------------------------------
1017
1018 override protected void EOnContact(IEntity other, Contact extra)
1019 {
1020 if ( !IsAlive() )
1021 return;
1022
1023 Transport transport = Transport.Cast(other);
1024 if ( transport )
1025 {
1026 if ( GetGame().IsServer() )
1027 {
1028 RegisterTransportHit(transport);
1029 }
1030 }
1031 }
1032
1033 override bool CanReceiveAttachment(EntityAI attachment, int slotId)
1034 {
1035 if ( !IsAlive() )
1036 {
1037 return false;
1038 }
1039 return super.CanReceiveAttachment(attachment, slotId);
1040 }
1041
1043 {
1044 return GetBonePositionWS( GetBoneIndexByName( "spine3" ) );
1045 }
1046
1048 override bool IsBeingBackstabbed()
1049 {
1050 return m_FinisherInProgress;
1051 }
1052
1053 override void SetBeingBackstabbed(int backstabType)
1054 {
1055 // disable AI simulation
1056 GetAIAgent().SetKeepInIdle(true);
1057
1058 // select death animation
1059 switch (backstabType)
1060 {
1061 case EMeleeHitType.FINISHER_LIVERSTAB:
1062 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_BACKSTAB;
1063 break;
1064
1065 case EMeleeHitType.FINISHER_NECKSTAB:
1066 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_NECKSTAB;
1067 break;
1068
1069 default:
1070 m_DeathType = DayZInfectedDeathAnims.ANIM_DEATH_DEFAULT;
1071 }
1072
1073 // set flag - death command will be executed
1074 m_FinisherInProgress = true;
1075 }
1076
1079 {
1080 return m_IsCrawling;
1081 }
1082
1083 // called from command death when stealth attack wan't successful
1085 {
1086 // enable AI simulation again
1087 GetAIAgent().SetKeepInIdle(false);
1088
1089 // reset flag
1090 m_FinisherInProgress = false;
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
1145class ZombieHitData
1146{
1150}
RepairTentActionReciveData m_DamageZone
ref ArrowManagerBase m_ArrowManager
Definition animalbase.c:41
vector GetOrientation()
void CommandHandler(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
Definition zombiebase.c:198
int GetMindStateSynced()
Definition zombiebase.c:182
bool m_IsCrawling
Definition zombiebase.c:34
override void OnSoundVoiceEvent(int event_id, string event_user_string)
Definition zombiebase.c:550
override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
Definition zombiebase.c:969
ref ArrowManagerBase m_ArrowManager
Definition zombiebase.c:38
bool FightLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
Definition zombiebase.c:607
ref InfectedSoundEventHandler m_InfectedSoundEventHandler
Definition zombiebase.c:27
void CommandHandlerDebug(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
Definition zombiebase.c:283
override bool IsManagingArrows()
bool HandleVault(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
Definition zombiebase.c:413
override array< string > GetSuitableFinisherHitComponents()
returns suitable hit components for finisher attacks; DEPRECATED
Definition zombiebase.c:177
override bool CanReceiveAttachment(EntityAI attachment, int slotId)
void ProcessSoundVoiceEvent(AnimSoundVoiceEvent sound_event, out AbstractWave aw)
Definition zombiebase.c:577
int GetOrientationSynced()
returns rounded zombie yaw for sync purposes
Definition zombiebase.c:188
float m_DeltaTime
Definition zombiebase.c:24
bool IsCrawling()
returns true if crawling; 'DayZInfectedCommandCrawl' is only for the transition, after that it remain...
override bool IsSelfAdjustingTemperature()
Definition zombiebase.c:149
void ZombieBase()
Definition zombiebase.c:43
override bool IsDanger()
Definition zombiebase.c:108
override void EOnInit(IEntity other, int extra)
Definition zombiebase.c:92
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
Definition zombiebase.c:29
AbstractWave ProcessVoiceFX(string pSoundSetName)
Definition zombiebase.c:526
void HandleOrientation(float pDt, int pCurrentCommandID)
Definition zombiebase.c:314
override bool CanBeSkinned()
Definition zombiebase.c:134
override bool IsZombie()
Definition zombiebase.c:103
bool HandleDamageHit(int pCurrentCommandID)
Definition zombiebase.c:855
void HandleSoundEvents()
Definition zombiebase.c:487
bool EvaluateCrawlTransitionAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType)
Definition zombiebase.c:814
vector SetDefaultHitPosition(string pSelection)
Definition zombiebase.c:171
AbstractWave m_LastSoundVoiceAW
Definition zombiebase.c:26
override AnimBootsType GetBootsType()
Definition zombiebase.c:129
bool FightAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
Definition zombiebase.c:717
bool HandleCrawlTransition(int pCurrentCommandID)
Definition zombiebase.c:799
void Init()
Definition zombiebase.c:48
void HandleMove(int pCurrentCommandID)
Definition zombiebase.c:297
void DebugSound(string s)
sound debug messages
vector m_DefaultHitPosition
Definition zombiebase.c:23
override bool IsHealthVisible()
Definition zombiebase.c:139
bool EvaluateDeathAnimationEx(EntityAI pSource, ZombieHitData data, out int pAnimType, out float pAnimHitDir)
Definition zombiebase.c:363
override bool IsRefresherSignalingViable()
Definition zombiebase.c:144
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
Definition zombiebase.c:890
override string GetDefaultHitComponent()
returns default hit component (fallback)
Definition zombiebase.c:161
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)
Definition zombiebase.c:349
ref array< typename > m_TargetableObjects
Definition zombiebase.c:30
override void OnVariablesSynchronized()
synced variable(s) handler
Definition zombiebase.c:80
override string GetHitComponentForAI()
returns hit component for attacking AI
Definition zombiebase.c:155
int GetAttackPitch(EntityAI target)
Definition zombiebase.c:762
float ComputeHitDirectionAngleEx(EntityAI pSource, int invertHitDir=0)
Definition zombiebase.c:938
override void SetBeingBackstabbed(int backstabType)
override bool IsZombieMilitary()
Definition zombiebase.c:113
bool IsMale()
Definition zombiebase.c:118
override bool CanBeBackstabbed()
Definition zombiebase.c:123
int GetVaultType(float height)
Definition zombiebase.c:401
override vector GetDefaultHitPosition()
Definition zombiebase.c:166
float m_OrientationTimer
Definition zombiebase.c:20
bool EvaluateDeathAnimation(EntityAI pSource, string pComponent, string pAmmoType, out int pAnimType, out float pAnimHitDir)
Definition zombiebase.c:370
bool HandleMindStateChange(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
Definition zombiebase.c:450
float ComputeHitDirectionAngle(EntityAI pSource)
Definition zombiebase.c:917
override ArrowManagerBase GetArrowManager()
bool ChaseAttackLogic(int pCurrentCommandID, DayZInfectedInputController pInputController, float pDt)
Definition zombiebase.c:676
Definition enmath.c:7
Native class for boats - handles physics simulation.
Definition boat.c:28
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
bool ModCommandHandlerInside(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
Definition dayzanimal.c:178
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)
Definition dayzanimal.c:173
bool ModCommandHandlerAfter(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished)
Definition dayzanimal.c:183
AnimBootsType
override Widget Init()
Definition dayzgame.c:127
DayZInfectedConstants
Definition dayzinfected.c:2
DayZInfectedAttackGroupType
string GetDefaultHitPositionComponent()
Definition dayzplayer.c:502
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)
EMeleeTargetType
proto native CGame GetGame()
EntityEvent
Entity events for event-mask, or throwing event from code.
Definition enentity.c:45
proto void dBodyApplyImpulse(notnull IEntity body, vector impulse)
Applies impuls on a rigidbody (origin)
class AbstractSoundScene SoundObjectBuilder(SoundParams soundParams)
class JsonUndergroundAreaTriggerData GetPosition
void AbstractWave()
Definition sound.c:167
class SoundObject SoundParams(string name)
void PlaySound()
string m_AmmoType
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