private IEnumerator oneLine(string c_name, string content, string sprite_state, string display_spd, string not_found_param, string special_index, string param_1, string param_2, string param_3) { if (c_name == "") { c_name = prevChaName; //inherit prev char name (assumes it's the same character) if c_name is not provided } //sprite fixes size of background square AudioClip cVoiceClip = null; lineDone = false; //dialogue is shown one char at a time if (NAME) { NAME.text = c_name; } if (!prevChaName.Equals(c_name)) //if equal, no need to change animator { cIndex = -1; //cCode of the upcoming character cIndex = characterLoader.getIndex(c_name); //print("cIndex got from loader for " + c_name + ": " + cIndex); if (cIndex == -1) //not found, check for special param instructing which Animator to use { if (Invasion2000 != null && NAME) { NAME.font = Invasion2000; } int.TryParse(not_found_param, out cIndex); //if success, assign animator accordingly } else { if (ArcadeClassic != null && NAME) { NAME.font = ArcadeClassic; } } if (cIndex == -1) //not assigned, no animator { bgBox.color = new Color(0, 0, 0); //black } else { // assign animator character.GetComponent <Animator>().runtimeAnimatorController = characterLoader.getAnimatorByIndex(cIndex); cVoiceClip = characterLoader.getVoiceByIndex(cIndex); cVoiceSource.clip = cVoiceClip; Color c = bgBox.color; c = characterLoader.getColorByIndex(cIndex); bgBox.color = new Color(c.r, c.g, c.b); } prevChaName = c_name; } int SpriteStateNum; if (!int.TryParse(sprite_state, out SpriteStateNum)) { SpriteStateNum = 0; } //display speed float disp_spd; if (!float.TryParse(display_spd, out disp_spd)) { disp_spd = 1; //converts string to int } //format sentence string[] store; ArrayList result = new ArrayList(); List <(int[], string, string)> tags = GetFormattedText(DIALOGUE, content, result); store = result.ToArray(typeof(string)) as string[]; Canvas.ForceUpdateCanvases(); DIALOGUE.text = ""; //character start talking (default talking anim state); assumes part1 is always mouth setPartLayerParam(cIndex, character, 1, 2); //sets default base state setAnimBaseState(cIndex, character, SpriteStateNum); int special; int.TryParse(special_index, out special); /* * the params for special events could be int, could be int arrays, so to cover all * cases we create variables for all possibilities */ ArrayList PARAM1, PARAM2, PARAM3; PARAM1 = new ArrayList(); PARAM2 = new ArrayList(); PARAM3 = new ArrayList(); if (special != 0) //if there is special, parse params { parseDLGspecialParams(PARAM1, PARAM2, PARAM3, param_1, param_2, param_3); } //end parsing special param, start adding chars int wordCount = 1; int[] paramPointer = new int[4]; //paramPointer[2] would be pointer for special #2, pointer tracks curr position in string if (special == 3) //SPECIAL 3 disables users from clicking to proceed; will auto proceed after certain seconds { gameFlow.canMovePointer = false; //chains a WaitForSecond with <what should be done afterwards> StartCoroutine(Global.Chain(this, Global.WaitForSeconds((int)PARAM1[0]), Global.Do(() => { gameFlow.canMovePointer = true; gameFlow.incrementPointer(); }))); } else if (special == 6) { //SPECIAL 6: incrementPointer() will go to PARAM1[0] instead of the next line gameFlow.setSpecialGoToLine((int)PARAM1[0]); } int endSentencePartIDefaultBack = 0; int currOpenTagIndex = -1, currEndTagIndex = -1; string currOpenTag = "", currEndTag = ""; int currTagIndex = 0; //which tag are we adding in the tagsList if (tags.Count > currTagIndex + 1) //if has tags at all { currOpenTagIndex = tags[currTagIndex].Item1[0]; currEndTagIndex = tags[currTagIndex].Item1[2]; currOpenTag = tags[currTagIndex].Item2; currEndTag = tags[currTagIndex].Item3; } //loop through lines of this sentence for (int s = 0; s < store.Length; s++) { for (int n = 0; n < store[s].Length; n++) //loop through characters of each line { //tagging is for tags in rich text, not a part of the special effects system if (n == currOpenTagIndex) //we're at the first letter that needs to be tagged { DIALOGUE.text += currOpenTag; } else if (currOpenTagIndex != -1 && n > currOpenTagIndex && n <= currEndTagIndex) //remove previously added temp end tag, the last one won't be removed { DIALOGUE.text = DIALOGUE.text.Remove (DIALOGUE.text.Length - (currEndTag.Length)); } DIALOGUE.text += store[s][n]; //the actual adding of the char //Sound effect play if (cVoiceSource.clip && (n % 2 == 0)) { cVoiceSource.Play(); } if (store[s][n] == ' ') //if new word { wordCount++; } if (currOpenTagIndex != -1 && n >= currOpenTagIndex && n <= currEndTagIndex) { DIALOGUE.text += currEndTag; //add temp ending tag } if (n == currEndTagIndex) { currTagIndex++; //move on to next tag if (tags.Count > currTagIndex + 1) //see if next tag even exists { currOpenTagIndex = tags[currTagIndex].Item1[0]; currEndTagIndex = tags[currTagIndex].Item1[2]; currOpenTag = tags[currTagIndex].Item2; currEndTag = tags[currTagIndex].Item3; } else { currOpenTagIndex = -1; currEndTagIndex = -1; currOpenTag = ""; currEndTag = ""; } } switch (special) { /* * SPECIAL mode 1, changing of sprite of the speaking character * -param 1: indices of char count to change sprite * -param 2: number for State variable of the character (will assign sprite accordingly) */ case 1: if (paramPointer[1] < PARAM1.Count && n == (int)PARAM1[paramPointer[1]]) //if current char is char at which a switch should happen { setAnimBaseState(cIndex, character, (int)PARAM2[paramPointer[1]]); if (paramPointer[1] <= PARAM1.Count - 1) { paramPointer[1]++; } } break; /* * SPECIAL mode 2, the changing of motion states of the character's body parts (Part1, Part2, etc.) * -param 1: "which" state(s) to be set * - 1: part I layer * - 2: part II layer * the same state can appear for multiple times (e.g. 1, 2, 1 will set, for example, part1 twice and part2 once); * NOTE: this needs to match the number of items in param2/3; in other words, even "[1];[1]" is necessary * -param 2: value(s) to set those state(s), integer * -param 3: word count indices at which the state(s) are to be set, at least 1 * * e.g. [1,2];[3,5];[2,3] sets part 1 to "3" at word 2, sets part 2 to "5" at word 3 * * if part I state change happens at word -1 (should take place last), will change to provided state instead of recovering to default * part I layer state (only valid for this sentence). e.g. [1,1];[3,5];[2,-1] sets part 1 to "3" at word 2, sets part 1 to "5" after * sentence ends */ case 2: if (paramPointer[2] < PARAM3.Count && (int)PARAM3[paramPointer[2]] == -1) { endSentencePartIDefaultBack = (int)PARAM2[paramPointer[2]]; if (paramPointer[2] <= PARAM3.Count - 1) { paramPointer[2]++; } } while (paramPointer[2] < PARAM3.Count && wordCount == (int)PARAM3[paramPointer[2]]) //is at the right word and the first char { setPartLayerParam(cIndex, character, (int)PARAM1[paramPointer[2]], (int)PARAM2[paramPointer[2]]); if (paramPointer[2] <= PARAM3.Count - 1) { paramPointer[2]++; } } break; //SPECIAL mode 3 disables users from clicking to proceed, will auto proceed after certain seconds //-param 1: seconds to wait case 3: //called once above previous to the double for loop break; /* * SPECIAL mode 4, character speaking speed change in dialogue * -param 1: indices of char count to change dialogue speed * -param 2: spd(s) to change into */ case 4: if (paramPointer[4] < PARAM1.Count && n == (int)PARAM1[paramPointer[4]]) { disp_spd = (float)PARAM2[paramPointer[4]]; if (paramPointer[4] <= PARAM1.Count - 1) { paramPointer[4]++; } } break; /* * SPECIAL mode 5, opens up option prompt for user to choose after character finishes talking * -param 1: texts of choices, separated by comma * -param 2: lines to point to after selecting those choices */ case 5: //happens after the entire dialogue is displayed, so isn't called repetitively here break; /* * SPECIAL mode 6, directs pointer to provided line other than increment by 1 * -param 1: line to point to */ case 6: //needs only happen once, is invoked up above break; default: break; } if (!skipping) { if (store[s][n].Equals(',')) { //for break in between (half) sentences, give a longer wait time yield return(new WaitForSeconds(0.2f)); } else if (store[s][n].Equals('.')) { yield return(new WaitForSeconds(0.4f)); } else { yield return(new WaitForSeconds(-1.0333f * disp_spd + 1.07f)); } } } if (!(s == (store.Length - 1))) { DIALOGUE.text = ""; //reset and print the second section } } if (special == 5) { //only happens after entirety of text is up gameFlow.canMovePointer = false; int[] lines = new int[PARAM2.Count]; string[] messages = new string[PARAM1.Count]; for (int i = 0; i < PARAM2.Count; i++) { lines[i] = (int)PARAM2[i]; messages[i] = (string)PARAM1[i]; } dlgOptions.showOptions(PARAM1.Count, messages, lines); } //character stop talking (default talking anim state) setPartLayerParam(cIndex, character, 1, endSentencePartIDefaultBack); lineDone = true; skipping = false; }