diff --git a/Packages/vr.teachr.structuretree/Runtime/Scripts/ImpulseController.cs b/Packages/vr.teachr.structuretree/Runtime/Scripts/ImpulseController.cs index 20bc006e595ad1c39f5383dcbfd9fc1b8bcb5b27..3f6c2e76a92862d872a0bd3b394005a253e229b7 100644 --- a/Packages/vr.teachr.structuretree/Runtime/Scripts/ImpulseController.cs +++ b/Packages/vr.teachr.structuretree/Runtime/Scripts/ImpulseController.cs @@ -44,7 +44,7 @@ namespace TeachR.StructureTree private ConfigLoader config; #region utility vars - private static readonly HashSet<string> StudentreeKeywords = new HashSet<string> { "Stö", "StöEx", "Int", "anim", "KM", null }; // this exists to check if a node is an audiofile + private static readonly HashSet<string> StudentreeKeywords = new HashSet<string> {"randstö", "randint", "stö", "stöex", "int", "anim", "KM", null }; // this exists to check if a node is an audiofile private static readonly string followedByAudioNode = "followedByAudioNode"; private static readonly string InitialAudioChainNode = "initialAudioChainNode"; @@ -174,7 +174,7 @@ namespace TeachR.StructureTree Assert.IsTrue(_impulsedStudents.Count > 0); // evoke with empty list bricks the whole process without a usefull message - TODO: should be catched with a usefull message [FL] List<BehaviourController> bcList = new List<BehaviourController> { - _impulsedStudents[0].GetComponent<BehaviourController>() // TODO: if global Knowledge set all BehaviourControllers in this list [FL] + _impulsedStudents[0].GetComponent<BehaviourController>() }; GoToNextNode(bcList); // if there are several students selected, just let the first one answer @@ -324,7 +324,8 @@ namespace TeachR.StructureTree LogData($"{DateTime.Now.ToString(DateTimeFormat)};impulse:{impulse};nextNode:{nextNode.nodeId}"); if (bc.nextNode != null) { - if (nodeFlags[followedByAudioNode]) + if (nodeFlags[followedByAudioNode] + && !StructureTreeHandler.classHasGlobalKnowledge) // NOTE: Global Knowledge Scenarios needs to wait regardless of a node chain { if (nodeFlags[InitialAudioChainNode]) {//Start Student Node Chain @@ -335,7 +336,7 @@ namespace TeachR.StructureTree string soundFileFolder = StructureTreeHandler.stc[currentNode].soundFileName; string previousVoice = studentController.StudentObj.PreviousVoice; string pathOfAudioFile = StructureTreeHandler.GetPathOfAudioFile(soundFileFolder, studentController.IsMale, previousVoice); - Debug.Log($"{pathOfAudioFile}"); + //Debug.Log($"{pathOfAudioFile}"); StartCoroutine(GetAudioLength(pathOfAudioFile, length => { float audiolength = length; @@ -414,17 +415,11 @@ namespace TeachR.StructureTree private bool IsSoundfile(string name) {//the string in the Tag is neither part of defined Keywords nor used in the Tagconfiguration. //This makes sure audionodechain only executes if the studentnode is a audiofile - return !StudentreeKeywords.Contains(name) || StudentConfigurationHandler.possibleTags.Contains(name); + return !StudentreeKeywords.Contains(name.ToLower()) || StudentConfigurationHandler.possibleTags.Contains(name); } private void BranchPredictionInStructureTree(BehaviourController bc, GraphToTreeConverter.StructureTreeNode nextNode, string impulse, bool isInitiationInTree) { - // Was it the last node and negative? Start desaster! - if (nextNode.nextNodes.Count == 0 && impulse == "negative") - { - MenuDataHolder.IsNonScripted = true; - return; - } bool nextImpulseIsDelayed = false; @@ -435,30 +430,48 @@ namespace TeachR.StructureTree string keyword = StructureTreeHandler.stc[nextNode.nodeId].soundFileName.ToLower(); switch (keyword) { - case "stö": + case "stö": // a disturbance should be triggered - for all students if global knowledge is true else for a specific student GoToNextNode(bcs); - ClassController.SetRandomDisturbance(bc.gameObject, _levelOfDistortion); + if (StructureTreeHandler.classHasGlobalKnowledge) + ClassController.SetGlobalRandomDisturbance(_levelOfDistortion, maxDelayInAction); + else + ClassController.SetRandomDisturbance(bc.gameObject, _levelOfDistortion); _levelOfDistortion++; break; - case "stöex": + case "stöex": // like stö, but more extreme! GoToNextNode(bcs); _levelOfDistortion++; - ClassController.SetRandomDisturbance(bc.gameObject, _levelOfDistortion); + if (StructureTreeHandler.classHasGlobalKnowledge) + ClassController.SetGlobalRandomDisturbance(_levelOfDistortion, maxDelayInAction); + else + ClassController.SetRandomDisturbance(bc.gameObject, _levelOfDistortion); + _levelOfDistortion++; + break; + case "randstö": // multiple random disturbances should be triggered within the class + GoToNextNode(bcs); + ClassController.SetRandomDisturbance( _levelOfDistortion); _levelOfDistortion++; break; - case "int": + case "int": // resolves all or a specific Disruption, based on global knowledge + GoToNextNode(bcs); + if (StructureTreeHandler.classHasGlobalKnowledge) + ClassController.SolveGlobalDisturbances(maxDelayInAction); + else + ClassController.SolveSpecificDisturbance(bc); + break; + case "randint": // some random Disturbance should bes stopped (to decrease the overall stress I guess) GoToNextNode(bcs); ClassController.SolveRandomDisturbance(); break; - case "anim": + case "anim": // animation based on the structuretree is triggered GoToNextNode(bcs); float maximumDelay = !isInitiationInTree ? maxDelayInAction : maxInitialDelay; HandleAnimations(bcs, chanceToMisbehave, nextNode, maximumDelay); nextImpulseIsDelayed = true; break; default: - PrepareImpulse(bc); - return; + PrepareImpulse(bc); + return; } // this code just happens, if impulse does not need to be prepared diff --git a/Packages/vr.teachr.students/Runtime/SingleStudent/Scripts/BehaviourController.cs b/Packages/vr.teachr.students/Runtime/SingleStudent/Scripts/BehaviourController.cs index 201ace7b1aa1031be48564c31543a733e738695f..37a567a4bb930b270ebbc337e0137dc24bc8bb5f 100644 --- a/Packages/vr.teachr.students/Runtime/SingleStudent/Scripts/BehaviourController.cs +++ b/Packages/vr.teachr.students/Runtime/SingleStudent/Scripts/BehaviourController.cs @@ -221,6 +221,17 @@ namespace TeachR.Student CoachRtc.Send("behave", response); } + public void DelayedDisrupt(string behaviour, float delay, UnityEngine.Object sender = null, bool origin = true) + { + StartCoroutine(DelayAndDisrupt(behaviour, delay, sender, origin)); + } + + IEnumerator DelayAndDisrupt(string behaviour, float delay, UnityEngine.Object sender, bool origin) + { + yield return new WaitForSeconds(delay); + Disrupt(behaviour, sender, origin); + } + /// <summary> /// Lets student play out a given disruption. /// </summary> diff --git a/Packages/vr.teachr.students/Runtime/WholeClass/Scripts/ClassController.cs b/Packages/vr.teachr.students/Runtime/WholeClass/Scripts/ClassController.cs index fb632d846f47977551ae35f3b543d5f755ecd13c..9cf572e1f6455ec0cfc29fd10bcfad41fd5bb877 100644 --- a/Packages/vr.teachr.students/Runtime/WholeClass/Scripts/ClassController.cs +++ b/Packages/vr.teachr.students/Runtime/WholeClass/Scripts/ClassController.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; +using UnityEngine; using TeachR.ApplicationManager; using TeachR.WebCommunication; -using UnityEngine; namespace TeachR.Student { public static class ClassController @@ -27,8 +27,8 @@ namespace TeachR.Student { if (_behaviourControllers != null) return _behaviourControllers; _behaviourControllers = new List<BehaviourController>(); - foreach (GameObject s in AllStudentAttributes.FindStudentSlots()) - _behaviourControllers.Add(s.GetComponent<BehaviourController>()); + foreach (GameObject slot in AllStudentAttributes.FindStudentSlots()) + _behaviourControllers.Add(slot.GetComponent<BehaviourController>()); return _behaviourControllers; } @@ -95,6 +95,30 @@ namespace TeachR.Student { DisruptStudent(student.GetComponent<BehaviourController>(), behaviour); } + /// <summary> + /// Will trigger a Disruption random Disturbance from <class>SpecialBehaviours</class> for each Student in the Classroom. + /// </summary> + /// <param name="level">provides level of distortion, defaults to zero</param> + public static void SetGlobalRandomDisturbance(int level = 0, float delay = 0) + { + List<string> possibleDistortions = level switch + {//DISCUSS: [FL] Should this switchstatement be a Methon in SpecialBehaviours? + 0 => SpecialBehaviours._level0Distortion.ToList(), + 1 => SpecialBehaviours._level1Distortion.ToList(), + 2 => SpecialBehaviours._level2Distortion.ToList(), + _ => SpecialBehaviours._level0Distortion.ToList() + .Concat(SpecialBehaviours._level1Distortion) + .Concat(SpecialBehaviours._level2Distortion).ToList() + }; + + float rndDelay = Random.value * delay; + string rndDistortion = possibleDistortions[Random.Range(0, possibleDistortions.Count)]; + + AllStudentAttributes.BehaviourControllers + .ToList() + .ForEach(bc => bc.DelayedDisrupt(rndDistortion, rndDelay)); + } + public static GameObject GetRandomStudent() { int randomStudentSlot = Random.Range(0, AllStudentAttributes.StudentSlots.Length); @@ -131,5 +155,24 @@ namespace TeachR.Student { int rndDisturbance = Random.Range(0, countOfActiveDisturbances - 1); DisruptStudent(Behaviours[rndDisturbance], Behaviours[rndDisturbance].LastGoodBehaviour); } + + + /// <summary> + /// Will resolve Disturbance of a specific Student, if the Student is disturbing. + /// </summary> + /// <param name="bc"></param> + public static void SolveSpecificDisturbance(BehaviourController bc) + { + if (bc.IsDistorting) bc.Disrupt(bc.LastGoodBehaviour); + } + + /// <summary> + /// Will reset all Students to their last good behaviour. + /// </summary> + public static void SolveGlobalDisturbances(float delay = 0) + => AllStudentAttributes.BehaviourControllers + .Where(bc => bc.IsDistorting) + .ToList() + .ForEach(bc => bc.DelayedDisrupt(bc.LastGoodBehaviour, Random.value * delay)); } } \ No newline at end of file