@makefully/platypus 4.1.4 → 4.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +4 -2
  3. package/lib/platypus.js +1 -1
  4. package/package.json +7 -2
  5. package/src/AABB.js +685 -0
  6. package/src/ActionState.js +121 -0
  7. package/src/AssetManager.js +206 -0
  8. package/src/CollisionData.js +96 -0
  9. package/src/CollisionDataContainer.js +127 -0
  10. package/src/CollisionShape.js +315 -0
  11. package/src/Component.js +231 -0
  12. package/src/Data.js +64 -0
  13. package/src/DataMap.js +204 -0
  14. package/src/Entity.js +404 -0
  15. package/src/EntityLinker.js +113 -0
  16. package/src/EventHandler.js +115 -0
  17. package/src/EventHandlerList.js +251 -0
  18. package/src/Game.js +840 -0
  19. package/src/Gamepad.js +175 -0
  20. package/src/ID3CaptionPlayer.js +61 -0
  21. package/src/Messenger.js +365 -0
  22. package/src/PIXIAnimation.js +622 -0
  23. package/src/RandomSet.js +140 -0
  24. package/src/SFXPlayer.js +120 -0
  25. package/src/StateMap.js +252 -0
  26. package/src/Storage.js +152 -0
  27. package/src/TickerClient.js +48 -0
  28. package/src/TickerServer.js +23 -0
  29. package/src/TimeEvent.js +50 -0
  30. package/src/TimeEventList.js +100 -0
  31. package/src/VOPlayer.js +684 -0
  32. package/src/Vector.js +702 -0
  33. package/src/components/AIChaser.js +161 -0
  34. package/src/components/AIPacer.js +107 -0
  35. package/src/components/AudioMusic.js +151 -0
  36. package/src/components/AudioSFX.js +673 -0
  37. package/src/components/AudioVO.js +301 -0
  38. package/src/components/CollisionBasic.js +826 -0
  39. package/src/components/CollisionFilter.js +74 -0
  40. package/src/components/CollisionGroup.js +448 -0
  41. package/src/components/CollisionTiles.js +608 -0
  42. package/src/components/ComponentSwitcher.js +173 -0
  43. package/src/components/ControllerInput.js +65 -0
  44. package/src/components/Counter.js +165 -0
  45. package/src/components/EntityCamera.js +215 -0
  46. package/src/components/EntityContainer.js +549 -0
  47. package/src/components/EntityController.js +541 -0
  48. package/src/components/HandlerCamera.js +1052 -0
  49. package/src/components/HandlerCollision.js +1318 -0
  50. package/src/components/HandlerController.js +291 -0
  51. package/src/components/HandlerLogic.js +394 -0
  52. package/src/components/HandlerRender.js +217 -0
  53. package/src/components/Interactive.js +502 -0
  54. package/src/components/LevelBuilder.js +524 -0
  55. package/src/components/LogicAngularMovement.js +154 -0
  56. package/src/components/LogicAttachment.js +265 -0
  57. package/src/components/LogicButton.js +466 -0
  58. package/src/components/LogicCarrier.js +39 -0
  59. package/src/components/LogicDestroyMe.js +58 -0
  60. package/src/components/LogicDirectionalMovement.js +325 -0
  61. package/src/components/LogicDragDrop.js +371 -0
  62. package/src/components/LogicImpactLaunch.js +144 -0
  63. package/src/components/LogicPacingPlatform.js +64 -0
  64. package/src/components/LogicPortable.js +112 -0
  65. package/src/components/LogicPortal.js +115 -0
  66. package/src/components/LogicPushable.js +98 -0
  67. package/src/components/LogicRebounder.js +136 -0
  68. package/src/components/LogicRegionSpawner.js +139 -0
  69. package/src/components/LogicRotationalMovement.js +205 -0
  70. package/src/components/LogicSpawner.js +159 -0
  71. package/src/components/LogicStateMachine.js +382 -0
  72. package/src/components/LogicSwitch.js +77 -0
  73. package/src/components/LogicTeleportee.js +68 -0
  74. package/src/components/LogicTeleporter.js +93 -0
  75. package/src/components/LogicTimer.js +178 -0
  76. package/src/components/LogicWindUpRacer.js +179 -0
  77. package/src/components/Motion.js +371 -0
  78. package/src/components/Mover.js +566 -0
  79. package/src/components/Node.js +289 -0
  80. package/src/components/NodeMap.js +295 -0
  81. package/src/components/NodeResident.js +636 -0
  82. package/src/components/Orientation.js +697 -0
  83. package/src/components/RandomEvents.js +73 -0
  84. package/src/components/RelativePosition.js +204 -0
  85. package/src/components/RelayFamily.js +106 -0
  86. package/src/components/RelayGame.js +53 -0
  87. package/src/components/RelayLinker.js +94 -0
  88. package/src/components/RelayParent.js +57 -0
  89. package/src/components/RelaySelf.js +55 -0
  90. package/src/components/Render.js +178 -0
  91. package/src/components/RenderAnimator.js +275 -0
  92. package/src/components/RenderContainer.js +646 -0
  93. package/src/components/RenderDebug.js +319 -0
  94. package/src/components/RenderDestroyMe.js +59 -0
  95. package/src/components/RenderLottie.js +149 -0
  96. package/src/components/RenderProgress.js +120 -0
  97. package/src/components/RenderSpine.js +833 -0
  98. package/src/components/RenderSprite.js +527 -0
  99. package/src/components/RenderText.js +147 -0
  100. package/src/components/RenderTiles.js +1391 -0
  101. package/src/components/SceneChanger.js +128 -0
  102. package/src/components/TiledLoader.js +1451 -0
  103. package/src/components/Timeline.js +314 -0
  104. package/src/components/Tutorial.js +267 -0
  105. package/src/components/Tween.js +296 -0
  106. package/src/components/VoiceOver.js +373 -0
  107. package/src/components/XHR.js +129 -0
  108. package/src/components/index.js +79 -0
  109. package/src/factory.js +305 -0
  110. package/src/index.js +159 -0
  111. package/src/mixins/PIXI.Graphics.js +41 -0
  112. package/src/platypus.css +68 -0
  113. package/src/sayHello.js +50 -0
  114. package/src/shapes/Capsule.js +74 -0
  115. package/src/shapes/Circle.js +43 -0
  116. package/src/shapes/Ellipse.js +117 -0
  117. package/src/shapes/Point.js +191 -0
  118. package/src/shapes/Polygon.js +112 -0
  119. package/src/shapes/Polyline.js +97 -0
  120. package/src/shapes/Rectangle.js +78 -0
  121. package/src/shapes/RoundedRectangle.js +33 -0
  122. package/src/shapes/Segment.js +346 -0
  123. package/src/shapes/adjustedXY.js +19 -0
  124. package/src/shapes/castFromBox2D.js +92 -0
  125. package/src/shapes/castFromObject.js +53 -0
  126. package/src/shapes/castFromPixiGraphics.js +6 -0
  127. package/src/shapes/castFromPixiShape.js +89 -0
  128. package/src/shapes/castToBox2D.js +190 -0
  129. package/src/shapes/castToPixiGraphics.js +100 -0
  130. package/src/shapes/castToPixiShape.js +61 -0
  131. package/src/shapes/checkPointsMap.js +313 -0
  132. package/src/shapes/index.js +35 -0
  133. package/src/utils/array.js +73 -0
  134. package/src/utils/string.js +39 -0
@@ -0,0 +1,684 @@
1
+ /* global platypus */
2
+ import {arrayCache, greenSlice, greenSplice} from './utils/array.js';
3
+ import Data from './Data.js';
4
+ import Messenger from './Messenger.js';
5
+ import TimeEventList from './TimeEventList.js';
6
+
7
+ /**
8
+ * This class is used to create `platypus.game.voPlayer` and manages playback by only playing one at a time, playing a list, and even handling captions at the same time.
9
+ *
10
+ * This class borrows heavily from SpringRoll v1 to match the original capabilities exposed for Platypus v1.
11
+ *
12
+ * @memberof platypus
13
+ * @class VOPlayer
14
+ * @extends platypus.Messenger
15
+ * @param {Game} game The game instance for which to play audio.
16
+ * @param {assetManager} assetCache The Platypus assetManager used to load and unload VO clips.
17
+ */
18
+ class VOPlayer extends Messenger {
19
+ constructor (game, assetCache) {
20
+ super();
21
+
22
+ this.game = game;
23
+ this.assetCache = assetCache;
24
+ this.tagReader = game.options.modules?.jsmediatags ?? null;
25
+
26
+ //Bound method calls
27
+ this._onSoundFinished = this._onSoundFinished.bind(this);
28
+ this._updateSilence = this._updateSilence.bind(this);
29
+ this._syncCaptionToSound = this._syncCaptionToSound.bind(this);
30
+
31
+ /**
32
+ * Preloading next sound.
33
+ * @property {String} preloadingNextSound
34
+ * @private
35
+ */
36
+ this.preloadingNextSound = '';
37
+
38
+ /**
39
+ * If the sound is currently paused. Setting this has no effect - use pause()
40
+ * and resume().
41
+ * @property {Boolean} paused
42
+ * @public
43
+ * @readOnly
44
+ */
45
+ this.paused = false;
46
+
47
+ /**
48
+ * The current list of audio/silence times/functions.
49
+ * Generally you will not need to modify this.
50
+ * @property {Array} voList
51
+ * @public
52
+ */
53
+ this.voList = null;
54
+
55
+ /**
56
+ * The current position in voList.
57
+ * @property {int} _listCounter
58
+ * @private
59
+ */
60
+ this._listCounter = 0;
61
+
62
+ /**
63
+ * The current audio alias being played.
64
+ * @property {String} _currentVO
65
+ * @private
66
+ */
67
+ this._currentVO = null;
68
+
69
+ /**
70
+ * The current audio instance being played.
71
+ * @property {SoundInstance} _soundInstance
72
+ * @private
73
+ */
74
+ this._soundInstance = null;
75
+
76
+ /**
77
+ * The callback for when the list is finished.
78
+ * @property {Function} _callback
79
+ * @private
80
+ */
81
+ this._callback = null;
82
+
83
+ /**
84
+ * The callback for when the list is interrupted for any reason.
85
+ * @property {Function} _cancelledCallback
86
+ * @private
87
+ */
88
+ this._cancelledCallback = null;
89
+
90
+ /**
91
+ * A timer for silence entries in the list, in milliseconds.
92
+ * @property {int} _timer
93
+ * @private
94
+ */
95
+ this._timer = 0;
96
+
97
+ /**
98
+ * The captions object
99
+ * @property {springroll.Captions} _captions
100
+ * @private
101
+ */
102
+ this._captions = null;
103
+
104
+ this.masterVolume = 1;
105
+ this.volume = 1;
106
+ this.captionMute = true;
107
+ this.currentlyLoadingAudio = false;
108
+ this.interruptable = true;
109
+ this.playQueue = arrayCache.setUp();
110
+ }
111
+
112
+ /**
113
+ * If VOPlayer is currently playing (audio or silence).
114
+ * @property {Boolean} playing
115
+ * @public
116
+ * @readOnly
117
+ */
118
+ get playing () {
119
+ return this._currentVO !== null || this._timer > 0;
120
+ }
121
+
122
+ /**
123
+ * The current VO alias that is playing, even if it is just a caption. If a silence timer
124
+ * is running, currentVO will be null.
125
+ * @property {Boolean} currentVO
126
+ * @public
127
+ * @readOnly
128
+ */
129
+ get currentVO () {
130
+ return this._currentVO;
131
+ }
132
+
133
+ /**
134
+ * The springroll.Captions object used for captions. The developer is responsible for initializing this with a captions dictionary config file and a reference to a text field.
135
+ * @property {Captions} captions
136
+ * @public
137
+ */
138
+ set captions (captions) {
139
+ this._captions = captions;
140
+ if (captions) {
141
+ captions.selfUpdate = false;
142
+ this.setCaptionMute(this.captionMute);
143
+ }
144
+ }
145
+
146
+ get captions () {
147
+ return this._captions;
148
+ }
149
+
150
+ /**
151
+ * The amount of time elapsed in the currently playing item of audio/silence in milliseconds
152
+ * @property {int} currentPosition
153
+ */
154
+ get currentPosition () {
155
+ if (!this.playing) return 0;
156
+ //active audio
157
+ if (this._soundInstance)
158
+ return this._soundInstance.position;
159
+ //captions only
160
+ else if (this._currentVO)
161
+ return this._timer;
162
+ //silence timer
163
+ else
164
+ return this.voList[this._listCounter] - this._timer;
165
+ }
166
+
167
+ /**
168
+ * The duration of the currently playing item of audio/silence in milliseconds. If this is waiting on an audio file to load for the first time, it will be 0, as there is no duration data to give.
169
+ * @property {int} currentDuration
170
+ */
171
+ get currentDuration () {
172
+ if (!this.playing) {
173
+ return 0;
174
+ }
175
+
176
+ //active audio
177
+ if (this._soundInstance) {
178
+ return this._soundInstance.duration;
179
+ } else if (this._currentVO && this._captions) { //captions only
180
+ return this._captions.currentDuration;
181
+ } else { //silence timer
182
+ return this.voList[this._listCounter];
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Calculates the amount of time elapsed in the current playlist of audio/silence.
188
+ * @method platypus.VOPlayer#getElapsed
189
+ * @return {int} The elapsed time in milliseconds.
190
+ */
191
+ getElapsed () {
192
+ const
193
+ {assetCache} = platypus;
194
+ let index = 0,
195
+ total = 0;
196
+
197
+ if (!this.voList)
198
+ {
199
+ return 0;
200
+ }
201
+
202
+ for (let i = 0; i < this._listCounter; ++i) {
203
+ const item = this.voList[i];
204
+ if (typeof item === "string") {
205
+ total += assetCache.get(assetCache.getFileId(item)).duration * 1000;
206
+ }
207
+ else if (typeof item === "number")
208
+ {
209
+ total += item;
210
+ }
211
+ }
212
+
213
+ //get the current item
214
+ index = this._listCounter;
215
+ if (index < this.voList.length) {
216
+ const item = this.voList[index];
217
+ if (typeof item === "string") {
218
+ if (this._soundInstance) {
219
+ total += this._soundInstance._elapsed * 1000;
220
+ } // Otherwise it's not yet loaded so progress is `0`
221
+ } else if (typeof item === "number") {
222
+ total += item - this._timer;
223
+ }
224
+ }
225
+ return total;
226
+ }
227
+
228
+ /**
229
+ * Pauses the current VO, caption, or silence timer if the VOPlayer is playing.
230
+ * @method platypus.VOPlayer#pause
231
+ * @public
232
+ */
233
+ pause () {
234
+ if (this.paused || !this.playing) return;
235
+
236
+ this.paused = true;
237
+
238
+ if (this._soundInstance)
239
+ this._soundInstance.pause();
240
+
241
+ //remove any update callback
242
+ this.game.off("tick", this._syncCaptionToSound);
243
+ this.game.off("tick", this._updateSilence);
244
+ }
245
+
246
+ /**
247
+ * Resumes the current VO, caption, or silence timer if the VOPlayer was paused.
248
+ * @method platypus.VOPlayer#resume
249
+ * @public
250
+ * @listens platypus.Game#tick
251
+ */
252
+ resume () {
253
+ if (!this.paused) return;
254
+
255
+ this.paused = false;
256
+ if (this._soundInstance)
257
+ this._soundInstance.resume();
258
+ //captions for solo captions or VO
259
+ if (this._captions.activeCaption) {
260
+ if (this._soundInstance) {
261
+ this.game.on("tick", this._syncCaptionToSound);
262
+ }
263
+
264
+ //timer
265
+ } else {
266
+ this.game.on("tick", this._updateSilence);
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Plays a single audio alias, interrupting any current playback.
272
+ * Alternatively, plays a list of audio files, timers, and/or functions.
273
+ * Audio in the list will be preloaded to minimize pauses for loading.
274
+ * @method platypus.VOPlayer#play
275
+ * @public
276
+ * @param {String|Array} idOrList The alias of the audio file to play or the
277
+ * array of items to play/call in order.
278
+ * @param {Function} [callback] The function to call when playback is complete.
279
+ * @param {Function|Boolean} [cancelledCallback] The function to call when playback
280
+ * is interrupted with a stop() or play() call. If this value is a boolean
281
+ * <code>true</code> then callback will be used instead.
282
+ */
283
+ play (idOrList, callback, cancelledCallback, interruptable = true) {
284
+ if (!this.startingNewTrack) {
285
+ if (this.currentlyLoadingAudio || (!this.interruptable && this.playing)) {
286
+ this.playQueue.push(Data.setUp(
287
+ 'idOrList', idOrList,
288
+ 'callback', callback,
289
+ 'cancelledCallback', cancelledCallback,
290
+ 'interruptable', interruptable
291
+ ));
292
+ return;
293
+ }
294
+ this.startingNewTrack = true;
295
+ this.stop();
296
+ this.startingNewTrack = false;
297
+
298
+ this.interruptable = interruptable;
299
+
300
+ this._listCounter = -1;
301
+ if (typeof idOrList === "string") {
302
+ this.voList = arrayCache.setUp(0, idOrList);
303
+ } else {
304
+ this.voList = greenSlice(idOrList);
305
+ this.voList.unshift(0);
306
+ }
307
+ this._callback = callback;
308
+ this._cancelledCallback = cancelledCallback === true ? callback : cancelledCallback;
309
+ this._onSoundFinished();
310
+
311
+ } else {
312
+ platypus.debug.warn('VOPlayer: Tried playing a new track while a new track was starting up.');
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Callback for when audio/timer is finished to advance to the next item in the list.
318
+ * @private
319
+ */
320
+ _onSoundFinished (audio) {
321
+ if (this._listCounter >= 0) {
322
+ const currentVO = this._currentVO;
323
+
324
+ /**
325
+ * Fired when a new VO, caption, or silence timer completes
326
+ * @event platypus.VOPlayer#end
327
+ * @param {String} currentVO The alias of the VO or caption that has begun, or null if it is a silence timer.
328
+ */
329
+ this.trigger("end", currentVO);
330
+ if (typeof currentVO === "string") {
331
+ this.voList[0] += (audio?.duration ?? 0) * 1000;
332
+ this.unloadSound(currentVO);
333
+ greenSplice(this.voList, 1);
334
+ this._listCounter -= 1;
335
+ } else if (typeof this._currentVO === "function") {
336
+ greenSplice(this.voList, 1);
337
+ this._listCounter -= 1;
338
+ } else {
339
+ this.voList[0] += this.voList[1];
340
+ greenSplice(this.voList, 1);
341
+ this._listCounter -= 1;
342
+ }
343
+ } else {
344
+ this._listCounter = 0; // bump past elapsed storage index.
345
+ }
346
+ //remove any update callback
347
+ this.game.off("tick", this._syncCaptionToSound);
348
+ this.game.off("tick", this._updateSilence);
349
+
350
+ //if we have captions and an audio instance, set the caption time to the length of the audio
351
+ if (this._captions && this._captions.activeCaption && this._soundInstance) {
352
+ const activeCaption = this._captions.activeCaption;
353
+
354
+ activeCaption.lineIndex = activeCaption.lines.length;
355
+ }
356
+ this._soundInstance = null; //clear the audio instance
357
+ this._listCounter++; //advance list
358
+
359
+ //if the list is complete
360
+ if (this._listCounter >= this.voList.length) {
361
+ const c = this._callback;
362
+
363
+ if (this._captions) {
364
+ this._captions.stop();
365
+ }
366
+ this._currentVO = null;
367
+ this._cancelledCallback = null;
368
+ this._callback = null;
369
+ arrayCache.recycle(this.voList);
370
+ this.voList = null;
371
+ if (c) {
372
+ c();
373
+ }
374
+ if (this.interruptable) {
375
+ this.clearQueue();
376
+ } else {
377
+ this.checkQueue();
378
+ }
379
+ } else {
380
+ /**
381
+ * Fired when a new VO, caption, or silence timer begins
382
+ * @event platypus.VOPlayer#start
383
+ * @param {String} currentVO The alias of the VO or caption that has begun, or null if it is a silence timer.
384
+ */
385
+ this._currentVO = this.voList[this._listCounter];
386
+ if (typeof this._currentVO === "string") {
387
+ //If the sound doesn't exist, then we play it and let it fail,
388
+ //an error should be shown and playback will continue
389
+ this._playSound();
390
+ this.trigger("start", this._currentVO);
391
+ } else if (typeof this._currentVO === "function") {
392
+ this._currentVO(); //call function
393
+ this._onSoundFinished(); //immediately continue
394
+ } else {
395
+ this._timer = this._currentVO; //set up a timer to wait
396
+ this._currentVO = null;
397
+ this.game.on("tick", this._updateSilence);
398
+ this.trigger("start", null);
399
+ }
400
+ }
401
+ }
402
+
403
+ /**
404
+ * The update callback used for silence timers.
405
+ * This method is bound to the VOPlayer instance.
406
+ * @private
407
+ * @param {int} elapsed The time elapsed since the previous frame, in milliseconds.
408
+ */
409
+ _updateSilence (tick) {
410
+ this._timer -= tick.delta;
411
+
412
+ if (this._timer <= 0) {
413
+ this._onSoundFinished();
414
+ }
415
+ }
416
+
417
+ /**
418
+ * The update callback used for updating captions with active audio.
419
+ * This method is bound to the VOPlayer instance.
420
+ * @private
421
+ * @param {int} elapsed The time elapsed since the previous frame, in milliseconds.
422
+ */
423
+ _syncCaptionToSound (tick) {
424
+ if (!this._soundInstance) return;
425
+
426
+ const
427
+ {_soundInstance, audioEventQueue} = this,
428
+ elapsed = _soundInstance._elapsed * 1000;
429
+
430
+ if (elapsed > 0) { // we don't want to trigger things if audio is still being loaded.
431
+ this._captions.update(tick.delta / 1000);
432
+
433
+ if (audioEventQueue) {
434
+ audioEventQueue.getEvents(elapsed).forEach((entry) => this.trigger(entry));
435
+ }
436
+ }
437
+ }
438
+
439
+ /**
440
+ * Plays the current audio item and begins preloading the next item.
441
+ * @private
442
+ */
443
+ async _playSound () {
444
+ const
445
+ play = () => {
446
+ const
447
+ sound = platypus.assetCache.get(soundId);
448
+
449
+ this._soundInstance = sound.play({
450
+ complete: this._onSoundFinished,
451
+ volume: this.volume * this.masterVolume
452
+ });
453
+ this.audioEventQueue = null;
454
+ if (this.tagReader) {
455
+ this.tagReader.read(sound.media?.file ?? sound.url, {
456
+ onSuccess: ({tags}) => {
457
+ const
458
+ {SYLT} = tags;
459
+
460
+ if (SYLT) {
461
+ const
462
+ list = Array.isArray(SYLT) ? SYLT : [SYLT],
463
+ combinedEventList = list.reduce((events, {data}) => {
464
+ events.push(...data.synchronisedText.map(({text: content, timeStamp: time}) => ({
465
+ event: 'lyric',
466
+ time,
467
+ message: {
468
+ language: data.language,
469
+ descriptor: data.descriptor,
470
+ contentType: data.contentType,
471
+ content
472
+ },
473
+ interruptable: true
474
+ })));
475
+ return events;
476
+ }, []);
477
+
478
+ this.audioEventQueue = this.audioEventQueue || TimeEventList.setUp();
479
+ this.audioEventQueue.addEvents(combinedEventList);
480
+ }
481
+ },
482
+ onError: (error) => platypus.debug.warn(error)
483
+ });
484
+ }
485
+ if (this._captions) {
486
+ this._captions.start(sound, soundId, 0);
487
+ this.game.on("tick", this._syncCaptionToSound);
488
+ }
489
+ if (this.playQueue.length && this.interruptable) { // We need to skip on ahead, because new VO was played while this or a prior one was loading.
490
+ this.checkQueue();
491
+ } else {
492
+ for (let i = this._listCounter + 1; i < this.voList.length; ++i) {
493
+ const next = this.voList[i];
494
+ if (typeof next === "string") {
495
+ const
496
+ arr = arrayCache.setUp({
497
+ id: this._currentVO,
498
+ src: this._currentVO
499
+ });
500
+
501
+ this.assetCache.load(arr);
502
+
503
+ arrayCache.recycle(arr);
504
+
505
+ if (this.preloadingNextSound) {
506
+ this.unloadSound(this.preloadingNextSound);
507
+ }
508
+ this.preloadingNextSound = next;
509
+ break;
510
+ }
511
+ }
512
+ }
513
+ },
514
+ currentVO = this._currentVO,
515
+ soundId = platypus.assetCache.getFileId(currentVO),
516
+ arr = arrayCache.setUp({
517
+ alias: [soundId],
518
+ src: `${currentVO}`
519
+ });
520
+
521
+ this.currentlyLoadingAudio = true;
522
+
523
+ try {
524
+ await this.assetCache.load(arr, null, () => {
525
+ this.currentlyLoadingAudio = false;
526
+ if (this.stoppedWhileLoading) {
527
+ this.stoppedWhileLoading = false;
528
+ if (this.playQueue.length) { // Already more queued up, so we'll roll the stop into it here
529
+ play();
530
+ } else {
531
+ play();
532
+ this.stop();
533
+ }
534
+ } else if (currentVO === this._currentVO) {
535
+ play();
536
+ } else {
537
+ platypus.debug.warn('VOPlayer: Asset loading out of order.');
538
+ }
539
+ });
540
+ } catch (e) {
541
+ platypus.debug.warn('Unable to load voice-over.', e);
542
+ }
543
+
544
+ arrayCache.recycle(arr);
545
+ }
546
+
547
+ checkQueue () {
548
+ if (this.playQueue.length) {
549
+ const
550
+ vo = greenSplice(this.playQueue, 0);
551
+
552
+ this.play(vo.idOrList, vo.callback, vo.cancelledCallback, vo.interruptable);
553
+
554
+ vo.recycle();
555
+ }
556
+ }
557
+
558
+ clearQueue () {
559
+ while (this.playQueue.length) {
560
+ greenSplice(this.playQueue, 0).recycle();
561
+ }
562
+ }
563
+
564
+ /**
565
+ * Stops playback of any audio/timer.
566
+ * @method platypus.VOPlayer#stop
567
+ * @public
568
+ */
569
+ stop (completeStop = false) {
570
+ if (!this.startingNewTrack && (this.interruptable || completeStop)) {
571
+ this.clearQueue();
572
+ }
573
+
574
+ if (this.currentlyLoadingAudio) {
575
+ this.stoppedWhileLoading = true;
576
+ return;
577
+ }
578
+ const c = this._cancelledCallback;
579
+
580
+ this.paused = false;
581
+ if (this._soundInstance) {
582
+ this._soundInstance.stop();
583
+ this.unloadSound(this._currentVO);
584
+ this._soundInstance = null;
585
+ }
586
+
587
+ if (this._currentVO) {
588
+ if (typeof this._currentVO === "string") {
589
+ this.trigger("stop", this._currentVO);
590
+ } else if (typeof this._currentVO !== "function") {
591
+ this.trigger("stop", null);
592
+ }
593
+ }
594
+
595
+ this._currentVO = null;
596
+ if (this._captions && this._captions.activeCaption) {
597
+ this._captions.stop();
598
+ }
599
+ this.game.off("tick", this._syncCaptionToSound);
600
+ this.game.off("tick", this._updateSilence);
601
+ if (this.voList) {
602
+ for (let i = this._listCounter + 1; i < this.voList.length; i++) {
603
+ if (typeof this.voList[i] === 'function') {
604
+ this.voList[i](); // Make sure all events are triggered.
605
+ }
606
+ }
607
+ this.voList = null;
608
+ }
609
+ this._timer = 0;
610
+ this._callback = null;
611
+
612
+ this._cancelledCallback = null;
613
+ if (c) {
614
+ c();
615
+ }
616
+ if (!this.startingNewTrack && !this.interruptable && !completeStop) {
617
+ this.checkQueue();
618
+ }
619
+ }
620
+
621
+ /**
622
+ * Sets the volume of VO playback.
623
+ *
624
+ * @method platypus.VOPlayer#setVolume
625
+ * @param {Number} volume
626
+ */
627
+ setVolume (volume) {
628
+ this.volume = volume;
629
+ if (this._soundInstance) {
630
+ this._soundInstance.volume = this.volume * this.masterVolume;
631
+ }
632
+ }
633
+
634
+ /**
635
+ * Sets the master volume of VO playback.
636
+ *
637
+ * @method platypus.VOPlayer#setMasterVolume
638
+ * @param {Number} volume
639
+ */
640
+ setMasterVolume (volume) {
641
+ this.masterVolume = volume;
642
+ this.setVolume(this.volume);
643
+ }
644
+
645
+ /**
646
+ * Whether to mute captions.
647
+ *
648
+ * @method platypus.VOPlayer#setCaptionMute
649
+ * @param {Boolean} muted
650
+ */
651
+ setCaptionMute (muted) {
652
+ this.captionMute = muted;
653
+ if (this._captions) {
654
+ this._captions.renderer.renderTarget.style.display = muted ? 'none' : 'block';
655
+ }
656
+ }
657
+
658
+ /**
659
+ * Unloads an audio track this VOPlayer has played.
660
+ * @method platypus.VOPlayer#unloadSound
661
+ * @param sound {string} Sound to unload.
662
+ * @public
663
+ */
664
+ unloadSound (sound) {
665
+ this.assetCache.delete(sound);
666
+ }
667
+
668
+ /**
669
+ * Cleans up this VOPlayer.
670
+ * @method platypus.VOPlayer#destroy
671
+ * @public
672
+ */
673
+ destroy () {
674
+ this.stop();
675
+ this.voList = null;
676
+ this._currentVO = null;
677
+ this._soundInstance = null;
678
+ this._callback = null;
679
+ this._cancelledCallback = null;
680
+ this._captions = null;
681
+ }
682
+ };
683
+
684
+ export default VOPlayer;