protected async Task PlaySpeech(string content, SoundOptions options) { UpdateInfo("Testing..."); await Speech.SayAllOf(content, options); UpdateInfo("Test complete."); }
protected override async Task startActionAsync() { foreach (var fx in ValidGlyphs.Select(s => GetFeedbackFX(s))) { fx.Play(0.0, true); } if (ValidGlyphs == null || ValidGlyphs.Count == 0) { await Speech.SayAllOf("Casting mistake. You don't know any spells which begin with that sequence of glyphs."); Deactivate(); } Task.Run(async() => { try { await Shaking.AwaitResult(); if (Shaking.AwaitableTask.Status != TaskStatus.RanToCompletion) { return; } abortAction(); Deactivate(); } catch (TaskCanceledException) { Log.Info("Atropos|GlyphCastStage", "Shaking monitor canceled."); } }, StopToken).LaunchAsOrphan(); }
protected override async void startAction() { sayIt = Speech.SayAllOf($"Hold device at each position until you hear the tone. Take your zero stance to begin.", volume: 0.5, cancelToken: StopToken); await sayIt; //Speech.Say("Hold device at each position yadda yadda."); await Task.Delay(1000); }
protected override async Task nextStageActionAsync() { await AttitudeProvider.SetFrameShiftFromCurrent(); SpellBeingTrained.ZeroStance = AttitudeProvider.FrameShift; Log.Debug("SpellTraining", $"Zero stance assigned at {SpellBeingTrained.ZeroStance.ToEulerAngles():f1}."); await Speech.SayAllOf("Begin"); //Speech.Say("Begin"); CurrentStage = new GlyphTrainingStage($"Glyph 0", Implement, AttitudeProvider); }
protected override async Task nextStageActionAsync() { Current.FormBeingTrained.Strokes.Add(thisStroke); int reps = Current.FormBeingTrained.Strokes.Count; await Speech.SayAllOf($"Data recorded. You now have {reps} reps saved."); await Task.Delay(500); await Speech.SayAllOf($"Return to your ahn garde to record another repetition for averaging, or use onscreen controls to fiddle with data."); Current.CheckStrokeCount(); CurrentStage = new EnGardeStage($"En Garde for rep {reps}", "Setting up another recording. Wait for it...", new StrokeTrainingStage($"{Current.FormBeingTrained.FormName} stroke, rep {reps}"), true); }
public async Task SynchSay(string verbal = null, IEffect aural = null, float?pitch = null, float?rate = null, float?FXvolume = null) { Verbal = verbal ?? Verbal; Aural = aural ?? Aural; SpeakPitch = pitch ?? SpeakPitch; SpeakRate = rate ?? SpeakRate; //await Speech.SayAllOf(Verbal, pitch: SpeakPitch, speakRate: SpeakRate, // doOnStart: () => { Aural.Play(FXvolume ?? defaultFXvolume); }); await Task.WhenAll(Speech.SayAllOf(Verbal, pitch: SpeakPitch, speakRate: SpeakRate), Aural.PlayToCompletion(FXvolume ?? defaultFXvolume)); //if (Aural.IsPlaying) Aural.Stop(); }
//protected override void prestartAction() //{ // AttitudeProvider = EnGardeStage.EngardeProvider ?? new FrameShiftedOrientationProvider( // Android.Hardware.SensorType.GameRotationVector, Blade.EnGardeOrientation.Average); // .Inverse()? // Log.Debug("Form training", $"Attitude Provider reference frame is {AttitudeProvider.FrameShift.ToStringFormatted("f4")}"); // if (!AttitudeProvider.IsActive) AttitudeProvider.Activate(); //} protected override async Task startActionAsync() { if (IsInitialPoseEstimate) { await Speech.SayAllOf("First we need approximate readings of where the stroke begins and ends."); await Task.Delay(500); await Speech.SayAllOf("Take a still pose at roughly the start of the smooth central portion of the stroke."); } else { await Speech.SayAllOf("Got it. Next, take a still pose at roughly the end of that smooth central part of the stroke."); } await SFX.PlayByID(Current, Resource.Raw._175949_clash_t).WhenFinishedPlaying; }
protected override async void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.MeleeTraining); currentSignalsDisplay = FindViewById <TextView>(Resource.Id.current_signals_text); bestSignalsDisplay = FindViewById <TextView>(Resource.Id.best_signals_text); resultsDisplay = FindViewById <TextView>(Resource.Id.result_text); SetUpFormButtons(); // See if the current sword is already in our (local, for now) library, and load it if so. Otherwise, create one. var swordString = Res.SpecificTags.Get(InteractionLibrary.CurrentSpecificTag); if (swordString != null && swordString.Length > 0) { ThePlayersSword = Sword.FromString(swordString, InteractionLibrary.CurrentSpecificTag); CurrentStage = GestureRecognizerStage.NullStage; return; } else if (InteractionLibrary.CurrentSpecificTag == InteractionLibrary.MeleeTeaching.Name + "0000") { Sword.InitMasterSword(); InteractionLibrary.CurrentSpecificTag = Sword.MasterSword.TagID; Log.Info("Training", "Using master sword."); ThePlayersSword = Sword.MasterSword; } else { ThePlayersSword = new Sword(InteractionLibrary.CurrentSpecificTag); } if (ThePlayersSword.EnGardeOrientation == null || ThePlayersSword.EnGardeOrientation.Average.AngleTo(Quaternion.Identity) < 1) { await Speech.SayAllOf("No pre-existing ahn garde stance found. Please take and hold your ahn garde stance to begin."); CurrentStage = new DefineEnGardeStage("Defining new en garde", true); } else { await Speech.SayAllOf("Confirm your saved ahn garde stance to begin."); setFormNameButton.Text = RetrainEnGardeText; CurrentStage = new EnGardeStage("Confirm en garde", "Okay. Use onscreen buttons to train specific forms.", GestureRecognizerStage.NullStage, true); } }
protected override async Task nextStageActionAsync() { if (IsInitialPoseEstimate) { Current.FormBeingTrained.InitialOrientation = AttitudeProvider.Quaternion; Log.Debug("Stroke still stances", $"Still position #1 set at {AttitudeProvider.Quaternion}, {AttitudeProvider.Quaternion.AngleTo(Quaternion.Identity)} degrees from En Garde."); CurrentStage = new FormSetupStage($"{Current.FormBeingTrained.FormName} form, second still pose", AttitudeProvider, true); } else { await Speech.SayAllOf("Thank you. Take your ahngarde stance again."); Current.FormBeingTrained.FinalOrientation = AttitudeProvider.Quaternion; Log.Debug("Stroke still stances", $"Still position #2 set at {AttitudeProvider.Quaternion}, {AttitudeProvider.Quaternion.AngleTo(Quaternion.Identity)} degrees from En Garde."); CurrentStage = new EnGardeStage("En Garde before stroke training", "Wait for the cue, then execute the form as you wish it to be judged in play.", new StrokeTrainingStage($"{Current.FormBeingTrained.FormName}, stroke training, rep 0"), true); } }
protected override async Task nextStageActionAsync() { //await AttitudeProvider.SetFrameShiftFromCurrent(); //Blade.EnGardeOrientation = new AdvancedRollingAverageQuat(10, null, AttitudeProvider.FrameShift.Inverse()); //Blade.EnGardeOrientation = new AdvancedRollingAverageQuat(10, null, AverageAttitude.Average, 1.0f); Blade.EnGardeOrientation = AverageAttitude; Blade.EnGardeOrientation.Update(AttitudeProvider.Quaternion); Log.Debug("Melee Training", $">>>> Setting en garde to {Blade.EnGardeOrientation.Average}, with sigma {Blade.EnGardeOrientation.Sigma}. In reference frame {AttitudeProvider.FrameShift}."); Blade.SaveSpecifics(); // Saves both the average attitude itself, and also the standard deviation of it. Important for later! await Speech.SayAllOf("Okay. Use the onscreen controls to train specific forms."); CurrentStage = GestureRecognizerStage.NullStage; Current.formNameTextbox.Enabled = true; //await Speech.SayAllOf("Begin"); //if (Current.AppendMode == null || Current.AppendMode == false) // CurrentStage = new FormSetupStage($"{Label} form prep", AttitudeProvider); //else // CurrentStage = new StrokeTrainingStage($"{Label} appending ({Current.FormBeingTrained.Strokes.Count})", AttitudeProvider); }
protected override async Task nextStageActionAsync() { if (Current.setFormNameButton.Text == RetrainEnGardeText) { Current.setFormNameButton.Text = "Random"; // Undoes our little textual flag that lets us retrain the en garde using this button instead of its usual function. } var oldOrientation = Blade.EnGardeOrientation.Average; Blade.EnGardeOrientation.Update(AttitudeProvider.Quaternion); // Subtle trick: we keep averaging the En Garde orientation so it "tracks" the player's shifts in taking it, over time. Log.Debug("EnGarde Stage", $"Updating the prior en garde ({oldOrientation}), using the new one ({AttitudeProvider.Quaternion}," + $" {AttitudeProvider.Quaternion.AngleTo(oldOrientation)} degrees away), producing a new one ({Blade.EnGardeOrientation.Average}," + $" {Blade.EnGardeOrientation.Average.AngleTo(oldOrientation)} degrees away from the prior one)."); //// In order to *pass along* a provider, to an arbitrary Gesture Stage which has already been created and passed to us //// (and which might or might not want to use our provider at all), we use this trick. Activate it in here, and during //// activation, a specific STATIC provider is made available. We lock so that (in theory) two EnGarde Stages which were //// running in separate threads wouldn't end up accessing the static value at the wrong times. //using (await _asyncLock.LockAsync()) //{ // //EngardeProvider = AttitudeProvider; // Can be referenced from inside the prestartAction of the provided stage, if desired. (Not during the ctor... that's already gone by!) // EngardeProvider = new FrameShiftedOrientationProvider(Android.Hardware.SensorType.GameRotationVector); // await Task.WhenAll(EngardeProvider.SetFrameShiftFromCurrent(), Speech.Say(NextStageCue)); // CurrentStage = NextStage; // CurrentStage.Activate(); // EngardeProvider = null; //} // Different approach to solving the above problem. var EngardeProvider = new FrameShiftedOrientationProvider(Android.Hardware.SensorType.GameRotationVector); await Task.WhenAll(EngardeProvider.SetFrameShiftFromCurrent(), Speech.SayAllOf(NextStageCue)); CurrentStage = NextStage; var cStage = CurrentStage as ITakeAnAttitudeProvider; if (cStage != null) { cStage.AttitudeProvider = EngardeProvider; } CurrentStage.Activate(); }
protected void CreateSpeechTests() { CategoryNames.Add("Speech Tests"); CreateTest("Simple", () => PlaySpeech("Some simple speech.", SoundOptions.Default)); CreateTest("OnHeadphones", () => PlaySpeech("Some simple speech.", SoundOptions.OnHeadphones)); CreateTest("OnSpeaker", () => PlaySpeech("Some simple speech.", SoundOptions.OnSpeakers)); CreateTest("Softer", () => PlaySpeech("Not exactly whispering, but as close as we get.", new SoundOptions() { Volume = 0.2 })); CreateTest("Plus SFX", async() => { UpdateInfo("Testing..."); await Task.WhenAll(Speech.SayAllOf("This is a clash; we'll use it in a parry cue in melee."), Task.Delay(500).ContinueWith(_ => { var eff = new Effect("Clash", Resource.Raw._175949_clash_t); return(eff.PlayToCompletion()); })); UpdateInfo("Test complete."); }); CreateTest("Overlapping*", async() => { UpdateInfo("Testing"); await Task.WhenAll(Speech.SayAllOf("This is stream number one."), Speech.SayAllOf("This is stream number two.")); UpdateInfo("Testing complete."); }); CreateTest("Pitch increase", () => PlaySpeech("Scaramouche, scaramouche, will you do the fandango?", new SoundOptions() { Pitch = 4.0 })); CreateTest("Pitch decrease", () => PlaySpeech("Figaro. Figaro figaro figaro.", new SoundOptions() { Pitch = 0.25 })); CreateTest("Rate increase", () => PlaySpeech("How much wood can a woodchuck chuck?", new SoundOptions() { Speed = 2.5 })); CreateTest("Rate decrease", () => PlaySpeech("Hobbits can be very hasty. Very hasty indeed.", new SoundOptions() { Speed = 0.35 })); CreateTest("Cancelled (Timed)", async() => { cts = new CancellationTokenSource(); UpdateInfo("Testing..."); var speechTask = Speech.SayAllOf("This sentence should end in silence before it reaches its end. Don't fret; this test is expected to fail.", new SoundOptions() { CancelToken = cts.Token }) .SwallowCancellations(); await Task.WhenAny( speechTask, Task.Delay(1500)); UpdateInfo("Interrupt token sent. Ideally, speech should stop; test continues."); cts.Cancel(); await speechTask; await Task.Delay(500); UpdateInfo("Test complete."); cts = null; }); CreateTest("Cancelled (Manual)", async() => { var token = SetupStopButtonOneShot("Interrupt token sent. Sound should stop; test continues."); UpdateInfo("Testing..."); var speechString = "This is a test of the interrupt mechanism. This is only a test. If this were a real interrupt, I would have stopped speaking by now, assuming you hit the stop button by this point. If not, you should, quick, before I'm done. I'm done."; await Speech.SayAllOf(speechString, new SoundOptions() { CancelToken = token }).SwallowCancellations(); UpdateInfo("Test complete."); }); CreateTest("Interrupted (Timed)", async() => { UpdateInfo("Testing..."); var speechTask = Speech.SayAllOf("This sentence should be interrupted before it reaches its end. If you're hearing this, the test has been failed.") .SwallowCancellations(); await Task.WhenAny( speechTask, Task.Delay(1500)); UpdateInfo("Interrupt speech sent. Ideally, speech should switch abruptly; test continues."); new Effect("Grunt", Resource.Raw._129346_male_grunt_1).Play(); var speechTask2 = Speech.SayAllOf("Aw, never mind.", new SoundOptions() { Interrupt = true }); await speechTask2; UpdateInfo("Test complete."); }); }
private void SetUpFormButtons() { var layoutpanel = FindViewById <LinearLayout>(Resource.Id.Form_list_layoutpane); formNameTextbox = FindViewById <EditText>(Resource.Id.form_name_textbox); setFormNameButton = FindViewById <Button>(Resource.Id.Set_form_name_button); strokeCountDisplay = FindViewById <TextView>(Resource.Id.stroke_count_display); reassessButton = FindViewById <Button>(Resource.Id.reassess_button); pauseButton = FindViewById <Button>(Resource.Id.pause_button); finalizeButton = FindViewById <Button>(Resource.Id.finalize_button); paramAbox = FindViewById <EditText>(Resource.Id.parameterAtextbox); paramBbox = FindViewById <EditText>(Resource.Id.parameterBtextbox); paramCbox = FindViewById <EditText>(Resource.Id.parameterCtextbox); foreach (string formName in MasterFechtbuch.formNames?.DefaultIfEmpty() ?? new string[0]) { var form = MasterFechtbuch.Get(formName); var formButton = new Button(this); var codicil = (form != null && form != Form.None) ? "" : " (Unknown)"; formButton.SetText(formName + codicil, TextView.BufferType.Normal); formButton.SetPadding(20, 20, 20, 20); layoutpanel.AddView(formButton); formButtons.Add(formButton); formButton.Click += async(o, e) => { if (FormBeingTrained != null) { return; // Debouncing, basically. } if (form != null && form != Form.None) // The target form does already exist in more than theory. { AppendMode = true; FormBeingRetrained = form; FormBeingTrained = form; foreach (Button btn in formButtons) { btn.Enabled = false; } setFormNameButton.Text = "Retrain Instead"; formNameTextbox.Text = formName; formNameTextbox.Focusable = false; CheckStrokeCount(); await Speech.SayAllOf($"Adding more training for {formName}. Ahn garde!"); CurrentStage = new EnGardeStage($"En Garde for rep {FormBeingTrained.Strokes.Count}", "Setting up another recording. Wait for the cue...", new StrokeTrainingStage($"{Current.FormBeingTrained.FormName} stroke, rep {FormBeingTrained.Strokes.Count}"), true); } else // It only existed as a theory - treat it as if the user had typed in the name. { formNameTextbox.Text = formName; setFormNameButton.CallOnClick(); } }; } formNameTextbox.KeyPress += (object sender, View.KeyEventArgs e) => { e.Handled = false; if (e.Event.Action == KeyEventActions.Down && e.KeyCode == Keycode.Enter && formNameTextbox.Text.Length > 0) { setFormNameButton.CallOnClick(); } if (formNameTextbox.Text.Length > 0) { setFormNameButton.Text = "Train"; } else { setFormNameButton.Text = "Random"; } }; setFormNameButton.Click += async(o, e) => { if (setFormNameButton.Text == RetrainEnGardeText) { CurrentStage.Deactivate(); setFormNameButton.Text = "Random"; CurrentStage = new DefineEnGardeStage("Redefining en garde", true); return; } if (FormBeingRetrained != null) { if (AppendMode == true) { AppendMode = false; FormBeingTrained = new Form(FormBeingRetrained.FormName, FormBeingRetrained.IsOffense); setFormNameButton.Text = "Erase form"; await Speech.SayAllOf("Retraining from start."); return; } else if (setFormNameButton.Text == "Erase form") { setFormNameButton.Text = "Confirm erasure"; return; } else if (setFormNameButton.Text == "Confirm erasure") { MasterFechtbuch.Erase(FormBeingRetrained.FormName); ThePlayersSword.ForgetForm(FormBeingRetrained.FormName); await Speech.SayAllOf($"Deleting {FormBeingRetrained.FormName} from the master library."); CurrentStage.Deactivate(); CurrentStage = GestureRecognizerStage.NullStage; Finish(); return; } } FormBeingRetrained = null; AppendMode = null; if (formNameTextbox.Text.Length == 0) { formNameTextbox.Text = GenerateRandomFormName(); } await Task.Delay(100); // Let the screen update. FormBeingTrained = new Form(formNameTextbox.Text, !(formNameTextbox.Text.EndsWith("Parry"))); foreach (Button btn in formButtons) { btn.Enabled = false; } formNameTextbox.Focusable = false; await Speech.SayAllOf($"Training {FormBeingTrained.FormName}. Ahn garde!"); CheckStrokeCount(); CurrentStage = new EnGardeStage("EnGarde pre-Form Setup", "", new FormSetupStage($"Init training for {FormBeingTrained.FormName}"), true); }; reassessButton.Click += (o, e) => { }; pauseButton.Click += async(o, e) => { if (pauseButton.Text == "Pause Sensors") { pauseButton.Text = "Resume Sensors"; Res.SFX.StopAll(); CurrentStage.Deactivate(); await Speech.SayAllOf($"Pausing sensors. Take your time and play with the parameter buttons."); CurrentStage = GestureRecognizerStage.NullStage; } else { pauseButton.Text = "Pause Sensors"; await Speech.SayAllOf($"Resume training for {FormBeingTrained.FormName}. Ahn garde!"); CurrentStage = new EnGardeStage($"En Garde for rep {FormBeingTrained.Strokes.Count}", "Setting up another recording. Wait for the cue...", new StrokeTrainingStage($"{Current.FormBeingTrained.FormName} stroke, rep {FormBeingTrained.Strokes.Count}"), true); } }; finalizeButton.Click += async(o, e) => { if (finalizeButton.Text == "Finalize") { // Halt ongoing processeses (if not already done via the Pause button). Res.SFX.StopAll(); CurrentStage.Deactivate(); CurrentStage = GestureRecognizerStage.NullStage; finalizeButton.Text = "Commit to Fechtbuch"; } else { // TODO: Stuff. MasterFechtbuch.Inscribe(FormBeingTrained); ThePlayersSword.LearnForm(FormBeingTrained); if (FormBeingRetrained == null) { await Speech.SayAllOf($"Adding {FormBeingTrained.FormName} to the master fechtbuch."); } else { await Speech.SayAllOf($"Updating form listing for {FormBeingTrained.FormName}."); } Log.Info("MeleeTraining", $"Here's the form string for copy-and-pasting as a constant: {FormBeingTrained.ToString()}"); Finish(); } }; }
// This is currently a bit of a hack, because we only support a single security panel. It's virtual, though, so... you do the math. public virtual void SetUpSecurity() { // Create all of the instances. Their ctors will take care of inserting them in the dictionaries. var A = new SecurityPanelNode("Upper Solenoid", "A", Resource.Drawable.securitypanel_overlay_topleft); // The one kept hot-meaning-unlocked so that the doors will auto-seal if power dies. var B = new SecurityPanelNode("Lower Solenoid", "B", Resource.Drawable.securitypanel_overlay_bottomleft); // The one kept cool-meaning-locked which is used to open them normally. var C = new SecurityPanelNode("Communications", "C", Resource.Drawable.securitypanel_overlay_bottom); var D = new SecurityPanelNode("Processor", "D", Resource.Drawable.securitypanel_overlay_center); Nodes.Add(A); Nodes.Add(B); Nodes.Add(C); Nodes.Add(D); var AtoB = new SecurityPanelNodeLink(A, B); var AtoC = new SecurityPanelNodeLink(A, C, true); var AtoD = new SecurityPanelNodeLink(A, D, true); var BtoA = new SecurityPanelNodeLink(B, A); var BtoC = new SecurityPanelNodeLink(B, C, true); var BtoD = new SecurityPanelNodeLink(B, D, true); var CtoA = new SecurityPanelNodeLink(C, A); var CtoB = new SecurityPanelNodeLink(C, B); var CtoD = new SecurityPanelNodeLink(C, D, true); var DtoA = new SecurityPanelNodeLink(D, A, true); var DtoB = new SecurityPanelNodeLink(D, B, true); var DtoC = new SecurityPanelNodeLink(D, C, true); // Define Examine strings A.Results[0] = "Clearly a solenoid used to shift the door's locking bolts. No way to tell if 'powered on' means the door is locked or unlocked, though."; A.Results[2] = "This one is hot to the touch - must be live and at fairly high voltage."; B.Results[0] = A.Results[0]; B.Results[2] = "This one is cool to the touch. Probably off at present."; C.Results[0] = "Fiber-optic communications line to elsewhere in the building."; C.Results[2] = "Not a lot of data flowing out right now, mostly just telemetry from the processor over on the right."; D.Results[0] = "The central processor for this panel. Not very smart, but smart enough."; D.Results[2] = ""; // Define Measure linkages AtoB.MeasureResults[0] = "There's no direct connection between the two solenoids."; AtoC.MeasureResults[0] = "Looks like there's a single status line running from the solenoid to the comm relay."; AtoC.MeasureResults[1] = "This one is showing 3.3V, steady. A pretty standard signal for 'on' or some other binary 'one'."; AtoD.MeasureResults[0] = "Looks like there's just a simple status line running back to the processor."; AtoD.MeasureResults[1] = AtoC.MeasureResults[2]; BtoA.MeasureResults[0] = AtoB.MeasureResults[0]; BtoC.MeasureResults[0] = AtoC.MeasureResults[0]; BtoC.MeasureResults[1] = "This line is rated for the usual few volts, but currently it just reads zero."; BtoD.MeasureResults[0] = AtoD.MeasureResults[0]; BtoD.MeasureResults[1] = BtoC.MeasureResults[1]; CtoA.MeasureResults[0] = "There's no sign of any data in this direction."; CtoB.MeasureResults[0] = CtoA.MeasureResults[0]; CtoD.MeasureResults[0] = "There's certainly some data flowing along this route, on an intermittent basis."; CtoD.MeasureResults[2] = "You do identify one channel here: an encrypyted data stream, probably from a card reader or some other access device. If we had implemented it, your decker might be able to hack this and fake a valid code, but that's not coded yet."; DtoA.MeasureResults[0] = "A 3.3 volt control signal is stepped up to plus sixty volts and a pretty high current in the solenoid."; DtoA.MeasureResults[2] = "The way they've engineered this link, it's pretty clear that it's intended to stay hot much if not most of the time."; DtoB.MeasureResults[0] = "The step-up transformers along this path seem to be sitting idle; the high voltage lines currently inactive."; DtoC.MeasureResults[0] = "A data bus carries several signals out to the comms relay from the processor."; DtoC.MeasureResults[2] = "You'd have to have access to the source code, or several hours to play with this, before you could make any sense of what's in this data stream."; // Wire Cutter results (where nontrivial). // Note that .IsLinked = False is automatically a result; this is apart from that, // and a check for .IsLinked that will send up a "nothing to cut" if relevant is likewise built in. AtoC.WirecutterResult = () => { SuspiciousInfoHasBeenSent = true; }; // Looks to the control panel like the backup locks just locked themselves. AtoD.WirecutterResult = () => { AlarmHasBeenRaised = true; Blare(AlarmFX); }; // The door knows IT didn't tell the backups to go dead, so someone's tampering. DtoC.WirecutterResult = () => { AlarmHasBeenRaised = true; Blare(AlarmFX); }; // Control just lost all communications with this door. DtoA.WirecutterResult = () => { SecondaryBoltsAreEngaged = true; Blare(BoltsClosingFX); }; // Congrats, you just screwed up and locked yourself out. DtoB.WirecutterResult = () => { DtoB.SolderingResult = AtoB.SolderingResult; }; // Soldering results - similar IsLinked comments as above. AtoB.SolderingResult = async() => { if (BtoC.IsLinked) { SuspiciousInfoHasBeenSent = true; } if (BtoD.IsLinked) { AlarmHasBeenRaised = true; Blare(AlarmFX); } ; Blare(BoltsOpeningFX); MainBoltsAreEngaged = false; await Speech.SayAllOf("Doors are now open; proceed."); }; BtoA.SolderingResult = async() => { await BoltsClosingFX.PlayToCompletion(10.0, true); SecondaryBoltsAreEngaged = true; await Speech.SayAllOf("Uh-oh. That was the secondary bolts engaging - and you're pretty sure the solenoid won't be capable of opening them again. Looks like Paper Crane is going to be making a service call... or two."); }; AtoC.SolderingResult = AtoD.SolderingResult = async() => { AlarmHasBeenRaised = true; await SparksFX.PlayToCompletion(1.0, true); await Speech.SayAllOf("You have managed to put about six amps through a delicate piece of circuitry. Congratulations - you just 'bricked' this door."); AlarmFX.Play(1.0, false, true); }; }
private void SetUpSpellButtons() { var layoutpanel = FindViewById <LinearLayout>(Resource.Id.Spell_casting_layoutpane); foreach (var spB in spellButtons) { spB.Visibility = ViewStates.Gone; } spellButtons.Clear(); foreach (string spellName in MasterSpellLibrary.spellNames?.DefaultIfEmpty() ?? new List <string>()) { if (spellName == Spell.None.SpellName) { continue; } var spell = MasterSpellLibrary.Get(spellName); var spellButton = new Button(this); spellButtons.Add(spellButton); spellButton.SetText(spellName + " (Retrain)", TextView.BufferType.Normal); spellButton.SetPadding(20, 20, 20, 20); layoutpanel.AddView(spellButton); spellButton.Click += (o, e) => { if (SpellBeingTrained != null) { return; // Debouncing, basically. } SpellBeingRetrained = spell; SpellBeingTrained = new Spell(spellName); foreach (Button btn in spellButtons) { btn.Visibility = ViewStates.Gone; } setSpellNameButton.Text = "Erase spell"; spellNameTextbox.Text = spellName; spellNameTextbox.Focusable = false; CheckGlyphCount(); Speech.Say($"Retraining {spellName}."); CurrentStage = new Spell_Training_TutorialStage($"Retraining {spellName}", ThePlayersFocus, true); }; } spellNameTextbox = FindViewById <EditText>(Resource.Id.spell_name_textbox); setSpellNameButton = FindViewById <Button>(Resource.Id.Set_spell_name_button); glyphCountDisplay = FindViewById <TextView>(Resource.Id.glyph_count_display); undoGlyphButton = FindViewById <Button>(Resource.Id.undo_glyph_button); inscribeButton = FindViewById <Button>(Resource.Id.inscribe_spell_button); spellNameTextbox.KeyPress += (object sender, View.KeyEventArgs e) => { e.Handled = false; if (e.Event.Action == KeyEventActions.Down && e.KeyCode == Keycode.Enter && spellNameTextbox.Text.Length > 0) { setSpellNameButton.CallOnClick(); } if (spellNameTextbox.Text.Length > 0) { setSpellNameButton.Text = "Train"; } else { setSpellNameButton.Text = "Random"; } }; spellNameTextbox.ClearFocus(); // Not working, dunno why. setSpellNameButton.Click += async(o, e) => { if (SpellBeingRetrained != null) { if (setSpellNameButton.Text == "Erase spell") { setSpellNameButton.Text = "Confirm erasure"; return; } else if (setSpellNameButton.Text == "Confirm erasure") { MasterSpellLibrary.Erase(SpellBeingRetrained.SpellName); ThePlayersFocus.ForgetSpell(SpellBeingRetrained.SpellName); CurrentStage.Deactivate(); await Speech.SayAllOf($"Deleting {SpellBeingRetrained.SpellName} from the master library."); CurrentStage = GestureRecognizerStage.NullStage; //SetUpSpellButtons(); Current.Finish(); return; } } SpellBeingRetrained = null; if (spellNameTextbox.Text.Length == 0) { spellNameTextbox.Text = GenerateRandomSpellName(); } Current.HideKeyboard(); await Task.Delay(100); // Let the screen update. SpellBeingTrained = new Spell(spellNameTextbox.Text); foreach (Button btn in spellButtons) { btn.Visibility = ViewStates.Gone; } //spellNameTextbox.Focusable = false; CheckGlyphCount(); await Speech.SayAllOf($"Training {SpellBeingTrained.SpellName}."); CurrentStage = new Spell_Training_TutorialStage($"Init training for {SpellBeingTrained.SpellName}", ThePlayersFocus, true); }; FindViewById <Button>(Resource.Id.glyph_training_btn).Click += async(o, e) => { var glyphText = Res.Storage.Get(NewGlyphTrainingStage.GlyphKey); if (glyphText != null) { Log.Debug("SpellTraining", "\n" + glyphText); } Current.HideKeyboard(); await Task.Delay(100); // Let the screen update. foreach (Button btn in spellButtons) { btn.Visibility = ViewStates.Gone; } await Speech.SayAllOf($"Training core glyphs."); //CurrentStage = new Spell_Training_TutorialStage($"Init training for {SpellBeingTrained.SpellName}", ThePlayersFocus, true); var provider = new GravityOrientationProvider(); provider.Activate(); Task.Delay(50) .ContinueWith(async _ => await SensorProvider.EnsureIsReady(provider)) .ContinueWith(_ => CurrentStage = new NewGlyphTrainingStage(0, ThePlayersFocus, provider)) .LaunchAsOrphan(); }; undoGlyphButton.Click += async(o, e) => { if (SpellBeingTrained.Glyphs.Count == 0) { foreach (Button btn in spellButtons) { btn.Enabled = true; } spellNameTextbox.Text = ""; spellNameTextbox.Focusable = true; setSpellNameButton.Enabled = true; setSpellNameButton.Text = "Random"; SpellBeingRetrained = null; SpellBeingTrained = null; CurrentStage.Deactivate(); CurrentStage = GestureRecognizerStage.NullStage; SetUpSpellButtons(); await Speech.SayAllOf("Aborting spell training."); } else { SpellBeingTrained.UndoAddGlyph(); await Speech.SayAllOf("Removing most recent glyph."); } CheckGlyphCount(); }; var feedbackSFXbtn = FindViewById <Button>(Resource.Id.spell_feedback_sfx_button); var progressSFXbtn = FindViewById <Button>(Resource.Id.spell_progress_sfx_button); var successSFXbtn = FindViewById <Button>(Resource.Id.spell_success_sfx_button); if (!MasterSpellLibrary.GetSFXReadyTask().Wait(5000)) { Log.Error("Spell training", "Can't prep the buttons (as is, anyway) without our SFX loaded, which doesn't seem to be happening."); } var feedbackSFXoptions = new SimpleCircularList <string>("Magic.Ethereal", "Magic.Aura", "Magic.DeepVenetian", "Magic.InfiniteAubergine", "Magic.Ommm", "Magic.AfricanDrums", "Magic.Rommble", "Magic.MidtonePianesque", "Magic.FemReverbDSharp", "Magic.FemReverbCSharp", "Magic.FemReverbF", "Magic.FemReverbE", "Magic.AlienTheremin", "Magic.TrompingBuzzPulse", "Magic.GrittyDrone", "Magic.Galewinds", "Magic.NanobladeLoop", "Magic.ViolinLoop", "Magic.StrongerThanTheDark", "Magic.MelodicPad"); var progressSFXoptions = new SimpleCircularList <string>(MasterSpellLibrary.SpellSFX.Keys.Where(sfx => !feedbackSFXoptions.Contains(sfx)).DefaultIfEmpty().ToArray()); var successSFXoptions = new SimpleCircularList <string>(MasterSpellLibrary.CastingResults.Keys.ToArray()); while (progressSFXoptions.Next != MasterSpellLibrary.defaultProgressSFXName) { } // Cycle the list to the correct starting point. while (successSFXoptions.Next != "Play " + MasterSpellLibrary.defaultSuccessSFXName) { } // Cycle the list to the correct starting point. inscribeButton.Click += async(o, e) => { if (inscribeButton.Text == "Inscribe Spell") { // Halt ongoing processeses MasterSpellLibrary.SpellFeedbackSFX.Deactivate(); CurrentStage.Deactivate(); CurrentStage = GestureRecognizerStage.NullStage; // Display SFX modification buttons feedbackSFXbtn.Visibility = ViewStates.Visible; progressSFXbtn.Visibility = ViewStates.Visible; successSFXbtn.Visibility = ViewStates.Visible; IEffect sampleSFX = null; Func <SimpleCircularList <string>, Button, string, EventHandler> HandlerFactory = (circList, btn, label) => { return((ob, ev) => { sampleSFX?.Stop(); btn.Text = $"{label} ('{circList.Next}')"; if (MasterSpellLibrary.SpellSFX.ContainsKey(circList.Current.Split(' ').Last())) { sampleSFX = MasterSpellLibrary.SpellSFX[circList.Current.Split(' ').Last()]; sampleSFX.Play(); } else { } }); }; feedbackSFXbtn.Click += HandlerFactory(feedbackSFXoptions, feedbackSFXbtn, "Feedback SFX"); progressSFXbtn.Click += HandlerFactory(progressSFXoptions, progressSFXbtn, "Progress SFX"); successSFXbtn.Click += HandlerFactory(successSFXoptions, successSFXbtn, "Success Func"); inscribeButton.Text = "Finish Inscribing"; } else { feedbackSFXbtn.Visibility = ViewStates.Gone; progressSFXbtn.Visibility = ViewStates.Gone; successSFXbtn.Visibility = ViewStates.Gone; SpellBeingTrained.CastingResult = MasterSpellLibrary.CastingResults[successSFXoptions.Current]; foreach (var glyph in SpellBeingTrained.Glyphs) { glyph.FeedbackSFXName = feedbackSFXoptions.Current; glyph.ProgressSFXName = progressSFXoptions.Current; } MasterSpellLibrary.Inscribe(SpellBeingTrained); ThePlayersFocus.LearnSpell(SpellBeingTrained); //ResetSpell(); if (SpellBeingRetrained == null) { await Speech.SayAllOf($"Adding {SpellBeingTrained.SpellName} to the master library."); } else { await Speech.SayAllOf($"Updating spell listing for {SpellBeingTrained.SpellName}."); } Log.Info("SpellTraining", $"Here's the spell string for copy-and-pasting as a constant: {SpellBeingTrained.ToString()}"); Current.Finish(); } }; }
protected override void startAction() { Speech.SayAllOf($"Train glyph {TargetGlyph.Name}. {TargetGlyph.Instruction_Short}.").Wait(); MasterSpellLibrary.SpellFeedbackSFX.Play(Volume, true); StopToken.Register(() => MasterSpellLibrary.SpellFeedbackSFX.Stop()); }