Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_VoiceoverSystem.c
Go to the documentation of this file.
1//------------------------------------------------------------------------------------------------
3{
4 override static void InitInfo(WorldSystemInfo outInfo)
5 {
6 outInfo
7 .SetAbstract(false)
8 .AddPoint(ESystemPoint.FixedFrame);
9 }
10
12
15
17
19
20 protected ref array<ref SCR_VoiceoverLine> m_aQueue = {};
21 protected ref array<IEntity> m_aActors = {};
22 protected ref array<SCR_CommunicationSoundComponent> m_aHandledComponents = {};
23
25
27
29
30 protected bool m_bSubtitlesHandled = true;
31
32 protected int m_iCurrentEndCommand = 0;
33
34 protected float m_fTimer;
35 protected float m_fCustomPause = -1;
36
37 protected string m_sCurrentSequence;
38 protected string m_sCurrentSoundEvent;
39 protected string m_sCurrentSubtitleEvent;
40 protected string m_sCurrentActorName;
41 protected string m_sCurrentSubtitle;
42
44
45 protected static const float PAUSE_BETWEEN_LINES = 0.5;
46
47 protected static const int SUBTITLE_VISIBILITY_DISTANCE_SQ = 30 * 30;
48 protected static const int SUBTITLE_FAILSAFE_TOGGLE_DELAY_MS = 15000;
49
50 protected static const string DEFAULT_ANIM_COMMAND = "CMD_Gesture_NPC";
51 protected static const string DEFAULT_ANIM_VARIABLE = "speech";
52
53 //------------------------------------------------------------------------------------------------
54 override event protected void OnStarted()
55 {
56 // Dedicated server doesn't have to process start event as no sound is supposed to be played there
57 if (System.IsConsoleApp())
58 return;
59
61
62 if (!gameMode)
63 return;
64
67
68 }
69
70 //------------------------------------------------------------------------------------------------
71 override event protected void OnStopped()
72 {
73 // Dedicated server doesn't have to process stop event as no sound is supposed to be played there
74 if (System.IsConsoleApp())
75 return;
76
78
79 if (!gameMode)
80 return;
81
84 }
85
86 //------------------------------------------------------------------------------------------------
87 override event protected void OnUpdatePoint(WorldUpdatePointArgs args)
88 {
89 // Dedicated server doesn't have to process update event as no sound is supposed to be played there
90 if (System.IsConsoleApp())
91 return;
92
94 {
95 m_fTimer = 0;
96 Enable(false);
97 OnFinished();
98 return;
99 }
100
101 if (m_iAudioHandle != AudioHandle.Invalid && !m_PlayingSoundComponent.IsFinishedPlaying(m_iAudioHandle))
102 return;
103
104 if (m_Data && m_CurrentActor)
105 {
106 SCR_VoiceoverLine line = m_Data.GetLineBySoundEvent(m_sCurrentSoundEvent);
107
108 if (!line)
109 line = m_Data.GetLineBySoundEvent(m_sCurrentSoundEvent, m_sCurrentSequence);
110
111 if (line && line.GetFinishAnimCommandParameter() != 0)
113 }
114
115 m_CurrentActor = null;
116
117 if (m_aQueue.IsEmpty())
118 {
119 // Unregister previous actor
122
123 m_fTimer = 0;
124 Enable(false);
125 OnFinished();
126 }
127 else
128 {
129 m_fTimer += GetWorld().GetFixedTimeSlice();
130 float pause;
131
132 if (m_fCustomPause >= 0)
133 pause = m_fCustomPause;
134 else
135 pause = PAUSE_BETWEEN_LINES;
136
137 if (m_fTimer >= pause)
138 {
139 m_fTimer = 0;
141 }
143 {
144 m_bSubtitlesHandled = true;
145
147 m_SubtitlesDisplay.Show(false);
148 }
149 }
150 }
151
152 //------------------------------------------------------------------------------------------------
153 override event bool ShouldBePaused()
154 {
155 return true;
156 }
157
158 //------------------------------------------------------------------------------------------------
160 {
161 World world = GetGame().GetWorld();
162
163 if (!world)
164 return null;
165
166 return SCR_VoiceoverSystem.Cast(world.FindSystem(SCR_VoiceoverSystem));
167 }
168
169 //------------------------------------------------------------------------------------------------
171 protected void OnControllableDestroyed(notnull SCR_InstigatorContextData instigatorContextData)
172 {
173 if (!IsPlaying())
174 return;
175
176 IEntity entity = instigatorContextData.GetVictimEntity();
177
178 if (!entity)
179 return;
180
182
183 if (!comp || comp != m_PlayingSoundComponent)
184 return;
185
186 Stop();
187 }
188
189 //------------------------------------------------------------------------------------------------
191 protected void OnControllableDeleted(IEntity entity)
192 {
193 if (!entity || !IsPlaying())
194 return;
195
197
198 if (!comp || comp != m_PlayingSoundComponent)
199 return;
200
201 Stop();
202 }
203
204 //------------------------------------------------------------------------------------------------
206 protected void OnActorLifeStateChanged()
207 {
208 IEntity currentActor = m_PlayingSoundComponent.GetOwner();
209
210 if (!currentActor)
211 return;
212
214
215 if (actorCharController && actorCharController.IsUnconscious())
216 Stop();
217 }
218
219 //------------------------------------------------------------------------------------------------
222 {
223 if (!m_OnFinished)
225
226 return m_OnFinished;
227 }
228
229 //------------------------------------------------------------------------------------------------
238
239 //------------------------------------------------------------------------------------------------
243 {
244 m_sDataResourceName = config;
245
246 if (RplSession.Mode() == RplMode.Dedicated)
247 return;
248
249 Resource container = BaseContainerTools.LoadContainer(config);
250 m_Data = SCR_VoiceoverData.Cast(BaseContainerTools.CreateInstanceFromContainer(container.GetResource().ToBaseContainer()));
251 }
252
253 //------------------------------------------------------------------------------------------------
255 {
256 return IsEnabled();
257 }
258
259 //------------------------------------------------------------------------------------------------
261 void SetActorName(SCR_EVoiceoverActor actor, string name)
262 {
263 m_mActorNames.Set(actor, name);
264 }
265
266 //------------------------------------------------------------------------------------------------
268 {
269 m_mActorNames.Clear();
270 }
271
272 //------------------------------------------------------------------------------------------------
273 protected void AddActorUnconsciousCheck(notnull IEntity actor)
274 {
276
277 if (!charController)
278 return;
279
280 charController.m_OnLifeStateChanged.Remove(OnActorLifeStateChanged); // Avoid duplicate calls
281 charController.m_OnLifeStateChanged.Insert(OnActorLifeStateChanged);
282 }
283
284 //------------------------------------------------------------------------------------------------
285 protected void RemoveActorUnconsciousCheck(notnull IEntity actor)
286 {
288
289 if (!charController)
290 return;
291
292 charController.m_OnLifeStateChanged.Remove(OnActorLifeStateChanged);
293 }
294
295 //------------------------------------------------------------------------------------------------
297 // \param sequenceName Name of the sequence as defined in SCR_VoiceoverData
298 // \param actor1 Entity playing the voiceover as defined in SCR_VoiceoverData by ACTOR enum (default: player character)
299 // \param playImmediately True to play straight away, cutting the currently spoken VO; false to wait until the current VO finishes
300 void PlaySequence(string sequenceName, IEntity actor1 = null, IEntity actor2 = null, IEntity actor3 = null, IEntity actor4 = null, IEntity actor5 = null, bool playImmediately = true)
301 {
302 if (!playImmediately && IsPlaying())
303 {
304 GetGame().GetCallqueue().CallLater(PlaySequence, PAUSE_BETWEEN_LINES, false, sequenceName, actor1, actor2, actor3, actor4, actor5, playImmediately);
305 return;
306 }
307
308 if (!m_Data)
309 return;
310
311 SCR_VoiceoverSequence sequence = m_Data.GetSequenceByName(sequenceName);
312
313 if (!sequence)
314 return;
315
316 m_sCurrentSequence = sequenceName;
317 sequence.GetLines(m_aQueue);
318 m_aActors = {actor1, actor2, actor3, actor4, actor5};
319
320 PlayFromQueue(true);
321 }
322
323 //------------------------------------------------------------------------------------------------
325 void PlaySequenceActorsArray(string sequenceName, notnull array<IEntity> actors, bool playImmediately = true)
326 {
327 if (!playImmediately && IsPlaying())
328 {
329 GetGame().GetCallqueue().CallLater(PlaySequenceActorsArray, PAUSE_BETWEEN_LINES, false, sequenceName, actors, playImmediately);
330 return;
331 }
332
333 if (!m_Data)
334 return;
335
336 SCR_VoiceoverSequence sequence = m_Data.GetSequenceByName(sequenceName);
337
338 if (!sequence)
339 return;
340
341 m_sCurrentSequence = sequenceName;
342 sequence.GetLines(m_aQueue);
343 m_aActors = actors;
344
345 PlayFromQueue(true);
346 }
347
348 //------------------------------------------------------------------------------------------------
350 void PlaySequenceGlobal(string sequenceName, notnull array<IEntity> actors, bool playImmediately = true)
351 {
352 array<RplId> actorIds = {};
353
354 foreach (IEntity actor : actors)
355 {
356 actorIds.Insert(Replication.FindItemId(actor));
357 }
358
359 Rpc(RpcDo_PlaySequence, m_sDataResourceName, sequenceName, actorIds, playImmediately);
360
361 if (RplSession.Mode() != RplMode.Dedicated)
362 RpcDo_PlaySequence(m_sDataResourceName, sequenceName, actorIds, playImmediately);
363 }
364
365 //------------------------------------------------------------------------------------------------
367 // \param targetPlayerIds array of player IDs to play the voiceover for
368 void PlaySequenceFor(string sequenceName, notnull array<IEntity> actors, notnull array<int> targetPlayerIds, bool playImmediately = true)
369 {
370 if (targetPlayerIds.IsEmpty())
371 return;
372
373 array<RplId> actorIds = {};
374
375 foreach (IEntity actor : actors)
376 {
377 actorIds.Insert(Replication.FindItemId(actor));
378 }
379
380 Rpc(RpcDo_PlaySequenceFor, m_sDataResourceName, sequenceName, actorIds, targetPlayerIds, playImmediately);
381
382 if (RplSession.Mode() != RplMode.Dedicated)
383 RpcDo_PlaySequenceFor(m_sDataResourceName, sequenceName, actorIds, targetPlayerIds, playImmediately);
384 }
385
386 //------------------------------------------------------------------------------------------------
387 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
388 protected void RpcDo_PlaySequence(string dataName, string sequenceName, array<RplId> actorIds, bool playImmediately)
389 {
390 array<IEntity> actors = {};
391
392 foreach (RplId actorId : actorIds)
393 {
394 actors.Insert(IEntity.Cast(Replication.FindItem(actorId)));
395 }
396
397 if (dataName != m_sDataResourceName)
398 SetData(dataName);
399
400 PlaySequenceActorsArray(sequenceName, actors, playImmediately);
401 }
402
403 //------------------------------------------------------------------------------------------------
404 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
405 protected void RpcDo_PlaySequenceFor(string dataName, string sequenceName, array<RplId> actorIds, array<int> targetPlayerIds, bool playImmediately)
406 {
407 if (!targetPlayerIds.Contains(SCR_PlayerController.GetLocalPlayerId()))
408 return;
409
410 array<IEntity> actors = {};
411
412 foreach (RplId actorId : actorIds)
413 {
414 actors.Insert(IEntity.Cast(Replication.FindItem(actorId)));
415 }
416
417 if (dataName != m_sDataResourceName)
418 SetData(dataName);
419
420 PlaySequenceActorsArray(sequenceName, actors, playImmediately);
421 }
422
423 //------------------------------------------------------------------------------------------------
425 // \param lineName Name of the line as defined in SCR_VoiceoverData
426 // \param actor1 Entity playing the voiceover (default: player character)
427 // \param playImmediately True to play straight away, cutting the currently spoken VO; false to wait until the current VO finishes
428 void PlayLine(string lineName, IEntity actor = null, bool playImmediately = true)
429 {
430 if (!playImmediately && IsPlaying())
431 {
432 GetGame().GetCallqueue().CallLater(PlayLine, PAUSE_BETWEEN_LINES, false, lineName, actor, playImmediately);
433 return;
434 }
435
436 if (!m_Data)
437 return;
438
439 SCR_VoiceoverLineStandalone line = m_Data.GetLineByName(lineName);
440
441 if (!line)
442 return;
443
444 m_aQueue.Clear();
445
446 int distanceThreshold = SUBTITLE_VISIBILITY_DISTANCE_SQ;
447 int customThreshold = line.GetCustomSubtitleDistanceThreshold();
448
449 if (customThreshold > 0)
450 distanceThreshold = customThreshold * customThreshold;
451
452 CameraBase playerCamera = GetGame().GetCameraManager().CurrentCamera();
453
454 if (!actor || (playerCamera && vector.DistanceSq(actor.GetOrigin(), playerCamera.GetOrigin()) <= distanceThreshold))
455 PlayLineActual(line.GetSoundEventName(), line.GetSubtitleText(), actor, line.GetActorName(), line.GetStartAnimCommandParameter(), line.InterruptCurrentLine(), line.GetFinishAnimCommandParameter());
456 else
457 PlayLineActual(line.GetSoundEventName(), string.Empty, actor, animCommandParam: line.GetStartAnimCommandParameter(), line.InterruptCurrentLine(), line.GetFinishAnimCommandParameter());
458 }
459
460 //------------------------------------------------------------------------------------------------
462 void PlayLineGlobal(string lineName, notnull IEntity actor, bool playImmediately = true)
463 {
464 Rpc(RpcDo_PlayLine, m_sDataResourceName, lineName, Replication.FindItemId(actor), playImmediately);
465
466 if (RplSession.Mode() != RplMode.Dedicated)
467 RpcDo_PlayLine(m_sDataResourceName, lineName, Replication.FindItemId(actor), playImmediately);
468 }
469
470 //------------------------------------------------------------------------------------------------
472 // \param targetPlayerIds array of player IDs to play the voiceover for
473 void PlayLineFor(string lineName, notnull IEntity actor, notnull array<int> targetPlayerIds, bool playImmediately = true)
474 {
475 if (targetPlayerIds.IsEmpty())
476 return;
477
478 Rpc(RpcDo_PlayLineFor, m_sDataResourceName, lineName, Replication.FindItemId(actor), targetPlayerIds, playImmediately);
479
480 if (RplSession.Mode() != RplMode.Dedicated)
481 RpcDo_PlayLineFor(m_sDataResourceName, lineName, Replication.FindItemId(actor), targetPlayerIds, playImmediately);
482 }
483
484 //------------------------------------------------------------------------------------------------
485 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
486 protected void RpcDo_PlayLine(string dataName, string lineName, RplId actorId, bool playImmediately)
487 {
488 if (dataName != m_sDataResourceName)
489 SetData(dataName);
490
491 PlayLine(lineName, IEntity.Cast(Replication.FindItem(actorId)), playImmediately);
492 }
493
494 //------------------------------------------------------------------------------------------------
495 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
496 protected void RpcDo_PlayLineFor(string dataName, string lineName, RplId actorId, array<int> targetPlayerIds, bool playImmediately)
497 {
498 if (!targetPlayerIds.Contains(SCR_PlayerController.GetLocalPlayerId()))
499 return;
500
501 if (dataName != m_sDataResourceName)
502 SetData(dataName);
503
504 PlayLine(lineName, IEntity.Cast(Replication.FindItem(actorId)), playImmediately);
505 }
506
507 //------------------------------------------------------------------------------------------------
509 // \param soundEventName Sound event name as defined in the appropriate .acp file in the actor's SCR_CommunicationSoundComponent
510 // \param actor Entity playing the voiceover (default: player character)
511 // \param playImmediately True to play straight away, cutting the currently spoken VO; false to wait until the current VO finishes
512 void PlayCustomLine(string soundEventName, string subtitle, IEntity actor = null, string actorName = string.Empty, bool playImmediately = true)
513 {
514 if (!playImmediately && IsPlaying())
515 {
516 GetGame().GetCallqueue().CallLater(PlayCustomLine, PAUSE_BETWEEN_LINES, false, soundEventName, subtitle, actor, actorName, playImmediately);
517 return;
518 }
519
520 PlayLineActual(soundEventName, subtitle, actor, actorName);
521 }
522
523 //------------------------------------------------------------------------------------------------
524 void Stop()
525 {
528
529 m_iAudioHandle = AudioHandle.Invalid;
530 }
531
532 //------------------------------------------------------------------------------------------------
533 protected void CallAnimCommand(IEntity actor, int commandParam)
534 {
535 if (!actor)
536 return;
537
538 ChimeraCharacter char = ChimeraCharacter.Cast(actor);
539
540 if (!char)
541 return;
542
543 CharacterAnimationComponent comp = char.GetAnimationComponent();
544
545 if (!comp)
546 return;
547
548 TAnimGraphCommand commandId = comp.BindCommand(DEFAULT_ANIM_COMMAND);
549 comp.CallCommand4I(commandId, 0, 0, commandParam, 0, 0);
550 }
551
552 //------------------------------------------------------------------------------------------------
556 void RegisterActor(notnull IEntity entity)
557 {
559
560 if (!playingSoundComponent || m_aHandledComponents.Contains(playingSoundComponent))
561 return;
562
563 m_aHandledComponents.Insert(playingSoundComponent);
564 playingSoundComponent.GetOnSoundEventStarted().Insert(OnSoundEventStarted);
565 playingSoundComponent.GetOnSoundEventFinished().Insert(OnSoundEventFinished);
566 }
567
568 //------------------------------------------------------------------------------------------------
569 protected void PlayFromQueue(bool start = false)
570 {
571 if (m_aQueue.IsEmpty())
572 return;
573
574 if (start)
575 {
576 m_fCustomPause = m_aQueue[0].GetPauseBeforeLine();
577
578 if (m_fCustomPause > 0)
579 {
580 // First line in the sequence has a custom pause added run it later
581 GetGame().GetCallqueue().CallLater(PlayFromQueue, m_fCustomPause * 1000, false, false);
582 return;
583 }
584 }
585
586 SCR_VoiceoverLine line = m_aQueue[0];
587 m_aQueue.RemoveOrdered(0);
588
589 string actorName = line.GetActorName();
590
591 if (actorName.IsEmpty())
592 actorName = m_mActorNames.Get(line.GetActor());
593
595 m_bSubtitlesHandled = false;
596
597 if (!m_aQueue.IsEmpty())
598 m_fCustomPause = m_aQueue[0].GetPauseBeforeLine();
599 }
600
601 //------------------------------------------------------------------------------------------------
602 protected void PlayLineActual(string eventName, string subtitle, IEntity actor = null, string actorName = string.Empty, int animCommandParam = 0, bool interruptCurrentLine = 1, int finishAnimCommandParam = -1)
603 {
604 if (!actor)
605 actor = GetDefaultActor();
606
607 if (!actor)
608 return;
609
610 // Unregister previous actor
613
615
617 return;
618
620
621 if (!comp || !comp.IsUnconscious())
622 {
623 if (interruptCurrentLine && m_iAudioHandle != AudioHandle.Invalid)
624 {
625 AudioSystem.TerminateSound(m_iAudioHandle);
626
628 }
629
630 m_iAudioHandle = m_PlayingSoundComponent.SoundEvent(eventName);
631 m_iCurrentEndCommand = finishAnimCommandParam;
632 m_sCurrentSoundEvent = eventName;
633 m_CurrentActor = actor;
634 m_sCurrentActorName = actorName;
635 m_sCurrentSubtitle = subtitle;
636
637 if (m_iAudioHandle != AudioHandle.Invalid && !subtitle.IsEmpty())
638 ShowSubtitle(subtitle, actorName, eventName);
639
641
642 if (animCommandParam > 0)
643 CallAnimCommand(actor, animCommandParam);
644 }
645
646 Enable(true);
647 }
648
649 //------------------------------------------------------------------------------------------------
650 protected void OnSoundEventStarted(SCR_CommunicationSoundComponent component, string eventName, AudioHandle handle, int priority)
651 {
652 if (!m_Data)
653 return;
654
655 SCR_VoiceoverLine line = m_Data.GetLineBySoundEvent(eventName);
656
657 if (!line)
658 return;
659
660 if (handle == AudioHandle.Invalid)
661 return;
662
663 m_iAudioHandle = handle;
664 m_PlayingSoundComponent = component;
665
668
669 CameraBase playerCamera = GetGame().GetCameraManager().CurrentCamera();
670
671 int distanceThreshold = SUBTITLE_VISIBILITY_DISTANCE_SQ;
672 int customThreshold = line.GetCustomSubtitleDistanceThreshold();
673
674 if (customThreshold > 0)
675 distanceThreshold = customThreshold * customThreshold;
676
677 if (playerCamera && vector.DistanceSq(component.GetOwner().GetOrigin(), playerCamera.GetOrigin()) <= distanceThreshold)
678 ShowSubtitle(line.GetSubtitleText(), line.GetActorName(), eventName);
679 }
680
681 //------------------------------------------------------------------------------------------------
682 protected void OnSoundEventFinished(SCR_CommunicationSoundComponent component, string eventName, AudioHandle handle, int priority, bool terminated)
683 {
686
687 // Hide the subtitle after desired delay
689 GetGame().GetCallqueue().CallLater(m_SubtitlesDisplay.Show, SCR_VoiceoverSubtitles.GetLingerDuration() * 1000, false, false, UIConstants.FADE_RATE_INSTANT, EAnimationCurve.LINEAR);
690
691 OnFinished(eventName, false);
692 }
693
694 //------------------------------------------------------------------------------------------------
695 protected void ShowSubtitle(string subtitle, string actorName, string eventName)
696 {
698 {
700
701 if (!hudManager)
702 return;
703
705
707 return;
708 }
709
710 GetGame().GetCallqueue().Remove(m_SubtitlesDisplay.Show);
711
712 if (actorName.IsEmpty())
713 m_SubtitlesDisplay.ShowSubtitle(subtitle);
714 else
715 m_SubtitlesDisplay.ShowSubtitle(actorName + ":<br/>" + subtitle);
716
717 m_sCurrentSubtitleEvent = eventName;
718
719 GetGame().GetCallqueue().Remove(FailsafeSubtitleToggle);
720 GetGame().GetCallqueue().CallLater(FailsafeSubtitleToggle, SUBTITLE_FAILSAFE_TOGGLE_DELAY_MS + (SCR_VoiceoverSubtitles.GetLingerDuration() * 1000), false, eventName);
721 }
722
723 //------------------------------------------------------------------------------------------------
724 protected void FailsafeSubtitleToggle(string eventName)
725 {
726 if (!m_SubtitlesDisplay || !m_SubtitlesDisplay.IsShown() || eventName != m_sCurrentSubtitleEvent)
727 return;
728
729 m_SubtitlesDisplay.Show(false);
730 }
731
732 //------------------------------------------------------------------------------------------------
734 {
735 PlayerController pc = GetGame().GetPlayerController();
736
737 if (!pc)
738 return null;
739
740 return pc.GetControlledEntity();
741 }
742
743 //------------------------------------------------------------------------------------------------
744 protected void OnFinished(string eventName = string.Empty, bool hideSubtitles = true)
745 {
746 m_iAudioHandle = AudioHandle.Invalid;
747 m_fCustomPause = -1;
748
749 if (m_OnFinished)
750 m_OnFinished.Invoke();
751
753 m_OnFinishedEvent.Invoke(eventName);
754
755 if (!m_SubtitlesDisplay || !hideSubtitles)
756 return;
757
758 // Hide the subtitle after desired delay
759 GetGame().GetCallqueue().Remove(m_SubtitlesDisplay.Show);
760 GetGame().GetCallqueue().CallLater(m_SubtitlesDisplay.Show, SCR_VoiceoverSubtitles.GetLingerDuration() * 1000, false, false, UIConstants.FADE_RATE_INSTANT, EAnimationCurve.LINEAR);
761 }
762
763 //------------------------------------------------------------------------------------------------
764 [Friend(SCR_VoiceoverSystemSerializer)]
765 protected SCR_VoiceoverSystemSnapshot CreateSnapshot()
766 {
767 SCR_VoiceoverSystemSnapshot snapshot = new SCR_VoiceoverSystemSnapshot();
768 snapshot.m_sData = m_sDataResourceName;
769
770 foreach (SCR_VoiceoverLine line : m_aQueue)
771 {
772 snapshot.m_aQueue.Insert(line);
773 }
774
775 snapshot.m_aActors.Copy(m_aActors);
776 snapshot.m_mActorNames.Copy(m_mActorNames);
777 snapshot.m_sCurrentSoundEvent = m_sCurrentSoundEvent;
778 snapshot.m_CurrentActor = m_CurrentActor;
779 snapshot.m_sCurrentActorName = m_sCurrentActorName;
780 snapshot.m_sCurrentSubtitle = m_sCurrentSubtitle;
781 snapshot.m_sCurrentSequence = m_sCurrentSequence;
782 return snapshot;
783 }
784
785 //------------------------------------------------------------------------------------------------
786 [Friend(SCR_VoiceoverSystemSerializer)]
787 protected void ApplySnapshot(notnull SCR_VoiceoverSystemSnapshot snapshot)
788 {
789 SetData(snapshot.m_sData);
790 Stop();
791 PlayCustomLine(snapshot.m_sCurrentSoundEvent, snapshot.m_sCurrentSubtitle, snapshot.m_CurrentActor, snapshot.m_sCurrentActorName, true);
792
793 m_aQueue.Clear();
794
795 foreach (SCR_VoiceoverLine line : snapshot.m_aQueue)
796 {
797 m_aQueue.Insert(line);
798 }
799
800 m_aActors.Copy(snapshot.m_aActors);
801 m_mActorNames.Copy(snapshot.m_mActorNames);
802 m_sCurrentSequence = snapshot.m_sCurrentSequence;
803
804 if (!m_aQueue.IsEmpty())
805 Enable(true);
806 }
807
808 //------------------------------------------------------------------------------------------------
810 {
811 // Unregister previous actor
814 }
815}
816
817class SCR_VoiceoverSystemSnapshot
818{
820 ref array<ref SCR_VoiceoverLine> m_aQueue = {};
821 ref array<IEntity> m_aActors = {};
828}
int TAnimGraphCommand
Definition ECommandIDs.c:1
ArmaReforgerScripted GetGame()
Definition game.c:1398
RplMode
Mode of replication.
Definition RplMode.c:9
SCR_BaseGameMode GetGameMode()
ScriptInvokerBase< ScriptInvokerVoidMethod > ScriptInvokerVoid
ScriptInvokerBase< ScriptInvokerStringMethod > ScriptInvokerString
SCR_EVoiceoverActor
SCR_VoiceoverSystem m_sData
string m_sCurrentSoundEvent
string m_sCurrentActorName
IEntity m_CurrentActor
ref array< IEntity > m_aActors
string m_sCurrentSequence
string m_sCurrentSubtitle
ref map< SCR_EVoiceoverActor, string > m_mActorNames
ref array< ref SCR_VoiceoverLine > m_aQueue
EAnimationCurve
proto external Managed FindComponent(typename typeName)
Main replication API.
Definition Replication.c:14
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
Replication item identifier.
Definition RplId.c:14
ScriptInvoker GetOnControllableDeleted()
ScriptInvokerBase< SCR_BaseGameMode_OnControllableDestroyed > GetOnControllableDestroyed()
ref OnLifeStateChangedInvoker m_OnLifeStateChanged
OnSoundEventFinishedInvoker GetOnSoundEventFinished()
OnSoundEventStartedInvoker GetOnSoundEventStarted()
SCR_InfoDisplay FindInfoDisplay(typename type)
Return hud component of given type.
static SCR_HUDManagerComponent GetHUDManager()
static int GetLocalPlayerId()
Returns either a valid ID of local player or 0.
int GetCustomSubtitleDistanceThreshold()
SCR_EVoiceoverActor GetActor()
ScriptInvokerVoid GetOnFinished()
Triggered when a line or sequence finishes playing.
static const string DEFAULT_ANIM_COMMAND
void OnSoundEventStarted(SCR_CommunicationSoundComponent component, string eventName, AudioHandle handle, int priority)
void RemoveActorUnconsciousCheck(notnull IEntity actor)
void ShowSubtitle(string subtitle, string actorName, string eventName)
void PlayCustomLine(string soundEventName, string subtitle, IEntity actor=null, string actorName=string.Empty, bool playImmediately=true)
Plays a custom voiceover line.
void FailsafeSubtitleToggle(string eventName)
void ApplySnapshot(notnull SCR_VoiceoverSystemSnapshot snapshot)
void OnControllableDeleted(IEntity entity)
Stop the voiceover when the speaker is deleted.
void PlaySequenceGlobal(string sequenceName, notnull array< IEntity > actors, bool playImmediately=true)
Same as PlaySequence but plays the VO for all clients. Has to be executed on server.
void OnControllableDestroyed(notnull SCR_InstigatorContextData instigatorContextData)
Stop the voiceover when the speaker dies.
ResourceName m_sDataResourceName
void OnActorLifeStateChanged()
Stop the voiceover when the speaker becomes unconscious.
ref ScriptInvokerVoid m_OnFinished
void AddActorUnconsciousCheck(notnull IEntity actor)
SCR_CommunicationSoundComponent m_PlayingSoundComponent
ref array< IEntity > m_aActors
void RegisterActor(notnull IEntity entity)
static const int SUBTITLE_FAILSAFE_TOGGLE_DELAY_MS
static SCR_VoiceoverSystem GetInstance()
void PlaySequence(string sequenceName, IEntity actor1=null, IEntity actor2=null, IEntity actor3=null, IEntity actor4=null, IEntity actor5=null, bool playImmediately=true)
Plays a sequence of voiceover lines defined in loaded config (see SetData).
void OnFinished(string eventName=string.Empty, bool hideSubtitles=true)
ref map< SCR_EVoiceoverActor, string > m_mActorNames
void PlaySequenceActorsArray(string sequenceName, notnull array< IEntity > actors, bool playImmediately=true)
Same as PlaySequence but accepts an array of actors.
void RpcDo_PlaySequence(string dataName, string sequenceName, array< RplId > actorIds, bool playImmediately)
void RpcDo_PlaySequenceFor(string dataName, string sequenceName, array< RplId > actorIds, array< int > targetPlayerIds, bool playImmediately)
SCR_VoiceoverSystemSnapshot CreateSnapshot()
ref SCR_VoiceoverData m_Data
void OnUpdatePoint(WorldUpdatePointArgs args)
void RpcDo_PlayLineFor(string dataName, string lineName, RplId actorId, array< int > targetPlayerIds, bool playImmediately)
void PlayLineGlobal(string lineName, notnull IEntity actor, bool playImmediately=true)
Same as PlayLine but plays the VO for all clients. Has to be executed on server.
void PlayLine(string lineName, IEntity actor=null, bool playImmediately=true)
Plays a voiceover line defined in loaded config (see SetData).
ref array< SCR_CommunicationSoundComponent > m_aHandledComponents
void PlaySequenceFor(string sequenceName, notnull array< IEntity > actors, notnull array< int > targetPlayerIds, bool playImmediately=true)
Same as PlaySequenceGlobal but plays the VO for clients defined by player IDs.
ref array< ref SCR_VoiceoverLine > m_aQueue
void SetActorName(SCR_EVoiceoverActor actor, string name)
Actor name associated with the given enum will be shown in the subtitle.
static const string DEFAULT_ANIM_VARIABLE
void PlayLineFor(string lineName, notnull IEntity actor, notnull array< int > targetPlayerIds, bool playImmediately=true)
Same as PlayLineGlobal but plays the VO for clients defined by player IDs.
ref ScriptInvokerString m_OnFinishedEvent
void PlayLineActual(string eventName, string subtitle, IEntity actor=null, string actorName=string.Empty, int animCommandParam=0, bool interruptCurrentLine=1, int finishAnimCommandParam=-1)
void CallAnimCommand(IEntity actor, int commandParam)
void SetData(ResourceName config)
static const int SUBTITLE_VISIBILITY_DISTANCE_SQ
ScriptInvokerString GetOnFinishedEvent()
Triggered when an event finishes playing.
void PlayFromQueue(bool start=false)
override event bool ShouldBePaused()
void RpcDo_PlayLine(string dataName, string lineName, RplId actorId, bool playImmediately)
ref SCR_VoiceoverSubtitles m_SubtitlesDisplay
void OnSoundEventFinished(SCR_CommunicationSoundComponent component, string eventName, AudioHandle handle, int priority, bool terminated)
static const float PAUSE_BETWEEN_LINES
Definition World.c:16
void Rpc(func method, void p0=NULL, void p1=NULL, void p2=NULL, void p3=NULL, void p4=NULL, void p5=NULL, void p6=NULL, void p7=NULL)
Structure holding world system meta-information required by the engine.
Structure holding extra data of WorldSystem update point.
Definition Types.c:486
WorldSystemPoint ESystemPoint
Definition gameLib.c:7
int IsEnabled()
Returns true if the light is enabled.
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
Definition EnNetwork.c:95
RplRcver
Definition RplRcver.c:59
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.
Definition RplChannel.c:14