public async Task SayAsync(string text, PointF?textPosition = null, PointF?portraitPosition = null) { if (_state.Cutscene.IsSkipping) { if (_outfit != null) { await setAnimation(_outfit.Outfit[AGSOutfit.Idle]); } return; } if (_outfit != null) { await setAnimation(_outfit.Outfit[AGSOutfit.Speak]); } await Task.Delay(1); var speech = await _speechCache.GetSpeechLineAsync(_characterName, text); text = speech.Text; ISayLocation location = getLocation(text); var textLocation = textPosition ?? location.TextLocation; portraitPosition = portraitPosition ?? location.PortraitLocation; IObject portrait = showPortrait(portraitPosition); ILabel label = _factory.UI.GetLabel($"Say: {text}", text, SpeechConfig.LabelSize.Width, SpeechConfig.LabelSize.Height, textLocation.X, textLocation.Y, config: SpeechConfig.TextConfig, addToUi: false); label.RenderLayer = AGSLayers.Speech; label.Border = SpeechConfig.Border; label.Tint = SpeechConfig.BackgroundColor; TaskCompletionSource <object> externalSkipToken = new TaskCompletionSource <object> (null); BeforeSayEventArgs args = new BeforeSayEventArgs(label, () => externalSkipToken.TrySetResult(null)); OnBeforeSay.Invoke(args); label = args.Label; _state.UI.Add(label); ISound sound = null; if (speech.AudioClip != null) { _emitter.AudioClip = speech.AudioClip; sound = _emitter.Play(); } await waitForText(text, externalSkipToken.Task, sound); _state.UI.Remove(label); label.Dispose(); if (portrait != null) { portrait.Visible = false; } if (_outfit != null) { await setAnimation(_outfit.Outfit[AGSOutfit.Idle]); } }
public async Task SayAsync(string text, PointF?textPosition = null, PointF?portraitPosition = null) { var outfit = _outfit; var walkComponent = _walkComponent; var previousAnimation = _faceDirection.CurrentDirectionalAnimation; var speakAnimation = outfit == null ? null : outfit.Outfit[AGSOutfit.Speak]; bool wasWalking = false; if (walkComponent?.IsWalking ?? false) { if (outfit?.Outfit[AGSOutfit.SpeakAndWalk] == null) { await walkComponent.StopWalkingAsync(); previousAnimation = _outfit.Outfit[AGSOutfit.Idle]; } else { wasWalking = true; speakAnimation = outfit.Outfit[AGSOutfit.SpeakAndWalk]; } } if (_state.Cutscene.IsSkipping) { if (outfit != null) { await setAnimation(previousAnimation); } return; } if (speakAnimation != null) { await setAnimation(speakAnimation); } await Task.Delay(1); var speech = await _speechCache.GetSpeechLineAsync(_characterName, text); text = speech.Text; ISayLocation location = getLocation(text); var textLocation = textPosition ?? location.TextLocation; portraitPosition = portraitPosition ?? location.PortraitLocation; IObject portrait = showPortrait(portraitPosition); ILabel label = _factory.UI.GetLabel($"Say: {text} {Guid.NewGuid().ToString()}", text, SpeechConfig.LabelSize.Width, SpeechConfig.LabelSize.Height, textLocation.X, textLocation.Y, config: SpeechConfig.TextConfig, addToUi: false); label.RenderLayer = AGSLayers.Speech; label.Border = SpeechConfig.Border; label.Tint = SpeechConfig.BackgroundColor; TaskCompletionSource <object> externalSkipToken = new TaskCompletionSource <object> (null); BeforeSayEventArgs args = new BeforeSayEventArgs(label, () => externalSkipToken.TrySetResult(null)); OnBeforeSay.Invoke(args); label = args.Label; _state.UI.Add(label); ISound sound = null; if (speech.AudioClip != null) { _emitter.AudioClip = speech.AudioClip; sound = _emitter.Play(); } await waitForText(text, externalSkipToken.Task, sound); _state.UI.Remove(label); label.Dispose(); if (portrait != null) { portrait.Visible = false; } if (outfit != null) { if (wasWalking && !walkComponent.IsWalking) { previousAnimation = outfit.Outfit[AGSOutfit.Idle]; //If we were in the middle of a walk but walk was completed before speech, then instead of revert to the previous animation (walk) we need to go to idle. } await setAnimation(previousAnimation); } }