/// <summary> /// Creates a thought balloon over a bot. This version is mostly for edit mode /// where you don't want the bot to play its speach sound. Note that this version /// also kills off any previous thought balloons since we only want one bot at a /// time to identify itself. /// </summary> /// <param name="thinker">The bot with the thought.</param> /// <param name="text">What he's thinking.</param> /// <param name="color">Color for balloon outline.</param> /// <param name="editMode">If true, don't play a bot speach sound.</param> /// <returns>True if acted upon, false if ignored.</returns> public static bool CreateThoughtBalloon(GameThing thinker, string text, Vector4 color, bool editMode) { //Debug.Print(text); // Early out if we have nothing to say. if (text == null || text == "") { return(true); } // The thought string may have text substitutions in in (eg <score red>) so // process those first so we can do vaild text string comparisons. string newText = TextHelper.ApplyStringSubstitutions(text, thinker as GameActor); string rawText = text; // Text before substitution. bool substitution = newText != text; text = newText; // If the current bot is already thinking this same thought then just // extend the time for the thought rather than creating a duplicate. // If the bot is already thinking another thought then ignore the new // thought. Always replace the string just in case a substitution // has take place. // Also use this opportunity to kill off thoughts from other bots if // we're in edit mode. for (int i = 0; i < activeBalloons.Count; i++) { ThoughtBalloon balloon = activeBalloons[i]; if (balloon.Thinker == thinker) { // Remove tags. Need to do this _before_ setting the text // on the balloon otherwise the tags can show up on screen. text = TextHelper.RemoveTags(text).Trim(); // If just thinking the same thought again, extend the time. if (balloon.RawText == rawText) { balloon.RestartTime(); balloon.Text = text; // Update the text in case of a substitution, eg a score changed. } // Check for message being sent. If so, don't return yet. if (text.Length > 0) { // Current thought has priority, so don't act on new changes. return(false); } } else { if (editMode) { balloon.Kill(); } } } int count = spareBalloons.Count; if (count > 0) { // Search the existing spares for one that already matches the string. ThoughtBalloon balloon = null; for (int i = 0; i < spareBalloons.Count; i++) { if (spareBalloons[i].Text == text) { // Found a match. balloon = spareBalloons[i]; spareBalloons.RemoveAt(i); break; } } if (InGame.inGame.CurrentUpdateMode == InGame.UpdateMode.RunSim) { SaidStringManager.AddEntry(thinker as GameActor, rawText, true); } string txt = TextHelper.RemoveTags(rawText).Trim(); if (txt == null || txt == string.Empty) { // Must have been just a pure (tag only) message. In that case, // also send it with atBeginning set to false. This lets the // user be a bit sloppy with the triggering. SaidStringManager.AddEntry(thinker as GameActor, rawText, false); return(true); } // If no match found, just grab one. if (balloon == null) { balloon = spareBalloons[0]; spareBalloons.RemoveAt(0); } // Also remove tags for non-raw text. text = TextHelper.RemoveTags(text); balloon.Activate(thinker, text, rawText, color); activeBalloons.Add(balloon); // Call update to set up the balloon for the // rendering of its first frame. balloon.Update(InGame.inGame.shared.camera); if (!editMode) { Foley.PlaySay(thinker); } return(true); } return(false); } // end of CreateThoughtBalloon()
/// <summary> /// Activates scrollable text display. /// </summary> /// <param name="text">Text to display.</param> /// <param name="useBackgroundThumbnail">Should the game thumbnail be used as a backdrop when rendering?</param> /// <param name="useRtCoords">Should hit testing be adjusted for rendering to an RT?</param> /// <param name="scrubText">Should text be scrubbed through bad word filter?</param> public void Activate(GameActor thinker, string text, UIGridElement.Justification justification, bool useBackgroundThumbnail, bool useRtCoords, bool scrubText) { if (text == null) { return; } if (state != States.Active) { this.useBackgroundThumbnail = useBackgroundThumbnail; this.useRtCoords = useRtCoords; // Do stack handling here. If we do it in the update object we have no // clue which order things get pushed and popped and madness ensues. CommandStack.Push(commandMap); state = States.Active; // Get the current scene thumbnail. If we're using this from the main menu (options) // then use the title screen image instead. if (InGame.inGame.State == InGame.States.Inactive) { thumbnail = BokuGame.bokuGame.mainMenu.BackgroundTexture; } else { thumbnail = InGame.inGame.SmallThumbNail; } // Tell InGame we're using the thumbnail so no need to do full render. prevRenderWorldAsThumbnail = InGame.inGame.RenderWorldAsThumbnail; if (!prevRenderWorldAsThumbnail) { InGame.inGame.RenderWorldAsThumbnail = true; } Time.Paused = true; HelpOverlay.Push(@"ScrollableTextDisplay"); // Get text string. if (thinker != null) { text = TextHelper.ApplyStringSubstitutions(text, thinker as GameActor); } rawText = text; text = TextHelper.RemoveTags(text); blob = new TextBlob(UI2D.Shared.GetGameFont20, text, textWidth); blob.Justification = justification; // By default TextBlob scrubs the text. If the scrubText is false // then set the text again via a path that doesn't do any scrub. if (!scrubText) { blob.RawTextNoScrub = text; } this.thinker = thinker; topLine = 0; textOffset = 0; // If a second button is needed, the text for it should be set after activation. textB = null; userHitA = true; PreRender(); // Set up text rendering for first frame. } } // end of Activate
public void Activate(GameActor thinker, string text, UIGridElement.Justification justification, bool useBackgroundThumbnail, bool useRtCoords) { if (text == null) { return; } if (state != States.Active) { this.useBackgroundThumbnail = useBackgroundThumbnail; this.useRtCoords = useRtCoords; // Do stack handling here. If we do it in the update object we have no // clue which order things get pushed and popped and madness ensues. CommandStack.Push(commandMap); state = States.Active; // Get the current scene thumbnail. If we're using this from the main menu (options) // then use the title screen image instead. if (InGame.inGame.State == InGame.States.Inactive) { thumbnail = BokuGame.bokuGame.mainMenu.BackgroundTexture; } else { thumbnail = InGame.inGame.SmallThumbNail; } // Tell InGame we're using the thumbnail so no need to do full render. prevRenderWorldAsThumbnail = InGame.inGame.RenderWorldAsThumbnail; if (!prevRenderWorldAsThumbnail) { InGame.inGame.RenderWorldAsThumbnail = true; } Time.Paused = true; HelpOverlay.Push(@"TextDisplay"); // Get text string. if (thinker != null) { text = TextHelper.ApplyStringSubstitutions(text, thinker as GameActor); } rawText = text; text = TextHelper.RemoveTags(text); blob = new TextBlob(Font, text, textWidth); blob.Justification = justification; this.thinker = thinker; // Render text into RT. RenderTarget2D rt = UI2D.Shared.RenderTarget512_512; InGame.SetRenderTarget(rt); InGame.Clear(Color.Transparent); Color greyTextColor = new Color(127, 127, 127); blob.RenderWithButtons(textPosition, greyTextColor); InGame.RestoreRenderTarget(); activationTime = Time.WallClockTotalSeconds; } } // end of Activate