Skip to content

SetText lifecycle

This will describe at a high level the full processing steps of SetText when the last entry point executes.

Setup

This phase happens at the start of every call. It mainly initialises Commands specific temporary values and saves some fields that can change during the course of this call for restore later in the cleanup phase. It also perform universal initialization logic such as setting up defaults values.

Here are the values saved for restoring them in cleanup:

  • MainManager's camoffset This can be changed using the cameraoffset parameter in Dialogue mode or the camoffset command in any call, but the latter is only restored in dialogue cleanup in Dialogue mode.
  • MainManager's overridefollower. This can changed using the overfollower command, but it is only restored in dialogue cleanup in Dialogue mode and the restore can be forced to true by using the Event command in syntax (1).

The call starts with the current bleep sound volume set to the size's parameter's magnitude.

The fonttype parameter is overridden in some languages if BubblegumSans was sent:

  • Japanese: Uzura
  • Korean: ONEMobilePOP
  • Russian: BalsamiqSans

Then, the textholder is initialized where its parent and position is set to their respective parameters. Finally, all line endings of the input string are normalized to LF if any were in CRLF and OrganiseLines is called if the linebreak parameter wasn't null.

Dialogue setup

This phase only occurs if we are in Dialogue mode, otherwise, a |spd,0| is prepended to the input string which disables the wait times by default

This phase is where all the initialization logic needed for Dialogue mode are done as well as some defaults values logic. The nature of this phase is why only a single Dialogue mode call can be running at a given time with the narrow exception of the battle and cardbattle commands during the yield.

To enforce this and to setup some logic needed during the dialogue, this phase grabs/releases locks as well as interacts with entities:

  • message lock is grabbed which is the main one that enforces one SetText call in Dialogue mode at a time.
  • minipause lock is also grabbed,
  • waitinput lock is released here which resets it from a previous call.
  • StopMovingEntities is called on the map if it isn't null. This would pause most activities on the map while the dialogue is ongoing.
  • The whole party and their followers's forcemove are stopped with the exception of the player and every party's entity's sprite is enabled except the lead.
  • Make the player stop moving if it isn't null.

This phase also sets some values as defaults:

  • |size,0.8,0.9| gets prepended to the input string if languageid is Japanese (this doesn't affect OrganiseLines because it is disabled in that language)
  • speed / spd: 0.02 or 0.03 in Japanese
  • The current Prompt, NumberPrompt and LetterPrompt's promptpick is reset to -1 which allows a fresh prompt to be used.
  • The cameraoffset's parameter is added to the current camoffset if its magnitude is large enough (0.1).
  • tailtarget: Set to the parent's parameter.
  • bleep: The pitch and type are set from the parent's paremeter if it exists.
  • textbox: It is initialized here with the default boxstyle with the ability to be hidden/shrunk and revealed/grown using DialogueAnim:
    • Parent: the GUICamera
    • No angle and scale
    • Position at (0.0, 3.25, 10.0)
  • textholder: Has different defaults than setup:
    • Parent: textbox
    • No angles and scale
    • Position at (-5.5, 0.9, 0.0) or the position parameter if its magnitude is large enough (0.1)
  • The MainManager's version of textbox: The textholder which allows global access.
  • blinker: Initialized here.

Additionally, this phase includes some logic about the HUD: all of them are hidden except the berry count only if the caller's parameter isn't null, its interacttype is Shop or CaravanBadge and its dialogues[1].y isn't 1, but it is hidden otherwise

Some special logic also happens if the player isn't null and we're not in an event:

  • Make the player face the caller (or the caller's shopkeeper if its interacttype is Shop or CaravanBadge)
  • Set initialflip to the player's flip.
  • Saves the player's rigid body's constraints to a temporary variable.
  • if the caller's parameter isn't null, teleport following players and chompy closer to caller? (2.55 max distance, 1.5 away?). After, yield for a frame.

Finally, this phase also does the following:

  • Apply an inputcooldown of 10 frames.
  • Setup the GlobalCommand system if the current map isn't null and supports it.

Before going to the char loop, this will yield until the switchcooldown expires if there is one.

Char loop

The char loop is the heart of SetText. It's a for loop on each char of the input string. It is not a linear loop however: Commands have the ability to not only reprocess the same index when the command's text is replaced and resume from there, but it is also possible to replace the entire input string and resume processing at the start of it. That action action is known as a redirect. It is up to the command to decide what to signal the char loop which will be taken into account on the next iteration.

Dialogue preprocessing

This phase of the char loop only occurs in Dialogue mode. This is where the current horizontal size, the fonttype and the line break values are saved into MainManager's fields. This is needed by the backtracking system to add the OrganiseLines version of the current accumulator if we initiate a backtracking because OrganiseLines needs the values at the start of the char loop, not the ones once a next is yielding because they could have changed.

if we are processing one of the first 10 characters, the player isn't null and we are not in an event, sets the player's entity's flip to its initial value that was set during the dialogue setup or the last align command (TODO: why the first 10?)

LF processing

This phase of the loop happens if the current char is a \n.

The current offset will be reset to 0.0 (the start of the line) and the current line to 0.7 * the vertical size's value (On Japanese, this is also multiplied by 1.25).

Vertical bar processing

This phase of the loop happens if the current char is a | which is the delimiter for a Commands. The command is first parsed into 2 parts: its enum value (case insensitive) and its syntax string (which includes both |, the command's name and all its parameters split by ,). The command text is then accumulated to the backtracking system if the command supports it.

Not all commands will be processed. Notably, if ignorenext is active, the command will be ignored. Same goes for testdiag which restricts commands processing to only work in Dialogue mode and to commands that it supports. For the actual command's processing, check the Commands documentation to learn more about each of them.

After the command has been processed (or ignored), this is where the next position of the char loop is managed. Normally, it increments, but if the command changes it or wish to resume at the same position, it will not be incremented.

Space processing

This phase of the loop happens if the current char is a . The space is accumulated in the backtracking system as well as in the current letter slot if we are using Single Letter Rendering. The current offset is incremented by 0.3 * the horizontal size's value which will essentially the next letter with a physical gap in Regular Letter Rendering. Finally, written is incremented ??? and the tailtarget is set to be talking if we were in Dialogue mode.

Letter processing

This phase of the loop occurs for everything else that isn't a \n, |, or \r (the last one isn't processed in general). This is where the letter gets rendered as well as some additional logic.

The first thing it does is if we had speed set to 0 (instant text scrolling) in Dialogue mode, am inputcooldown of 5 frames is applied. This enforces a wait of at least 5 frames before the next waitinput can be passed even if the scrolling speed is instant.

Next, the fonttype is overridden again when in Dialogue mode and not in a NumberPrompt using a similar logic than the setup phase and the languageid, but this time, this will take into consideration the font locking feature of the font command. If the lock was enabled, this will not do the override:

  • Japanese and the letter being processed character IsHiragana, IsKatakana, IsKangxiRadicals or IsCJKUnifiedIdeographs: Uzura
  • Russian and the letter being processed IsCyrillic: BalsamiqSans
  • Korean and the letter being processed character IsHangulJamo, IsHangulSyllables or IsHangulCompatibilityJamo: ONEMobilePOP

From there, the rendering of the letter occurs. There are 2 rendering methods and it depends on the current state of single. Each method is documented in its own page:

After the render is done, if a backbox was processed, the position of the backbox is set to (current offset / 2.0, size.y / 2.0 + 0.1, -5.0) and its scale to (current offset / 5.0 * size.x, size.y * 1.5, 1.0)

Dialogue post-processing

This phase of the loop only occurs in Dialogue mode. It mainly includes special handling logic which mostly takes effect after specific commands as well as interact with with the tailtarget:

From there, there are 2 special handlers that run when applicalble: prompt handling and Pickitem handling, but no matter which one is ran, the following happens after:

  • Sets the tailtarget to be talking again.
  • Reset ItemList's inlist to false.
  • If the player isn't null, sets its NPC to a new list

Prompt handling

The prompt handler is run if the promptpick is higher than -1 with more than one promptpointers which only happens after the prompt, whatever its type, just went inactive, but still needs to be handled:

  • if it was a LetterPrompt (usingflagvar 0 being -555 as a check), set the textbox to unhide itself.
  • Perform a redirection where the input string is the selected prompt's choice's text prepended with |blank|.
  • OrganiseLines the input string appended with the questprompt string if applicable.
  • Sets the promptbox to hide itself and be destroyed in 0.5 seconds
  • Reset the promptpick to -1
  • Signal SetText to resume processing at the start of the new input string.
  • yield a frame

ItemList handling

For the ItemList handler, it only runs if inlist is true and listredirect isn't null or -1 which normally happens when the ItemList of a pickitem command goes inactive, but still needs to be handled. Beware that this inlist value isn't guaranteed to be correct, see inlist issue for more details.

Normal sub-handler

This sub-handler happens if listredirect isn't -2 or -3 (either gets handled by the other sub handler). It performs a redirect using an OrganiseLines version of the dialogue line where the Dialogue line id is listredirect prepanded with a |blank|. From there, processing resumes at the start of this new input string.

additemtoss Special sub-handler

There is a special case if listredirect is -2 or -3 which should only happens through the pickitem that comes from a toss prompt from an additemtoss command. For these 2 values, the handler is the following (for context, by this point, the caller should be an Items, flagvar 1 is the selected item if applicable and flagvar 0 is the tossed item):

  • On the caller, enable its gravity and its ccol, freeze all rotations on is rigid, set its bounces to 0 and child it to the current map.
  • Start a LateVelocity (velocity applied after a frame) to RandomItemBounce(6.0, 12.0). This will make the item toss in a random direction.
  • Destroys the first child of the caller's entity's sprite
  • Force unfix the caller's entity, apply a touchcooldown on it of 70 frames, set its tossed to true and is timer to 600 frames (which is the time it takes before the item disappears)
  • If listredirect is -2 (The toss was confirmed to swap the item, -3 has this part omitted as it means the toss was cancelled which means to not swap the item)
    • Set the caller's entity's animstate, itemstate and basestate to flagvar 1 (this changes what the caller's item is to the swapped one)
    • Remove the item from the inventory matching the listtype used whose id is in flagvar 1
    • Add the item to the inventory matching the listtype used whose id is in flagvar 0
  • Set end to true
  • Reset listredirect to null
  • Apply an actioncooldown of 30 frames
  • If eventtoss is above -1, set eventcall to it

Dialogue Cleanup

This phase only occurs if we are in Dialogue mode. It tries to mostly do the reverse of dialogue setup, but with some added logic.

The first thing it will do is If we are using a transfer or a Warp command and the current caller isn't null, set the caller.interactcd to 15.0. After, it will set the tailtarget to stop talking if it isn't null and remove the Text advance's skiptext.

After, it will grab the waitinput lock and yield until it goes to false. One exception to this is if an end was processed since it serve as a bypass to this. In either case, the lock is released after as well as the message lock.

From there, it's mostly cleaning up:

  • Stops looping the bleep if it was playing and fade its sound to silence.
  • Free all the letter slots of the textholder and destroy it.
  • The minipause lock is released If event's inevent is false and we are not in an actual event.
  • Restores the camoffset to its original value if it was changed in dialogue setup.
  • overridefollower is restored to its original value or to true if Event's inevent is true.
  • If the textbox isn't null, hide it with a shrink animation and Destroys the textbox in 1 second.

Special cleanup logic if the player isn't null and we aren't in an event:

  • Restores the player rigid body constraints to its original value.
  • Apply an actioncooldown of 20 frames
  • Stops ignoring every collisions between the player's ccol and each entities that were ignored using any igcolmove commands.

The last step of this phase is If we are not in an event and battle is null, call EndOfMessage which does some final logic:

  • if flag 347 (start of ch6) is true, sets the corresponding badgeshop's all bought flags to true (from 587 to 588) if the corresponding shop has 0 medals in stock. NOTE: 589 corresponds to an unused medal shop.
  • If flag 470 (Examined the view of Termite Capitol for the first time at the Forsaken Lands) is true and the Termite Kingdom discovery isn't unlocked, unlock it (TODO: recheck this and determine why?)
  • if flag 351 (Talked to the person in front of the Termacade for the first time) is true and the Termacade discovery isn't unlocked, unlock it. TODO: recheck this
  • if flag 605 (Completed the Lost Books quest) is true and the Lost Book quests isn't in the completed array of boardQuests, complete it.
  • if the map isn't null, sets map.currentline to -1
  • Check the achievements completion.

Cleanup

This phase happens at the end of every SetText call. This is where some cleanups logic are performed, but also some Commands that needs some processing done at the very end rather than during the char loop:

  • If we are in a minibubble command's inner call, the minibubble is destroyed.
  • A frame is yielded here.
  • This is where the warp or transfer are started if applicable.
  • Something with additemtoss ??? TODO: recheck this
  • If this call had a showtokens command, the Game Token HUD element is destroyed.
  • If for some reasons, there was a Game Token in key Items, it is removed there.
  • If the caller was an Items object, it is destroyed there.

Finally, flag 349 is set to false if ItemList's inlist (check inlist issue) is false and we weren't in a Prompt, NumberPrompt or LetterPrompt.