TOTK EventFlow Editor
Vanilla RomFS Rule
Use a vanilla TOTK romfs path already supplied in the current turn or registered project guidance. Otherwise ask the user for it before inspecting game files. Treat the path as read-only; do not search unrelated folders or guess a location.
Core Workflow
Use this skill for EVFL work, but keep totk-local-operator loaded for compact file inspection and totk-toolkit loaded for shared file plumbing. Use totk-msbt-mals-editor for Mals/MSBT text wrapping, control tags, and EventTalk blank-slot padding.
- Identify the gameplay trigger:
AIScheduleParamEventEntrymaps interaction hooks such asOnPlayerTalkandOnNearPlayerto anEventName.RSDB/EventSetting.Product.*.rstbl.byml.zsmapsEventNametoFlowchartFileNameandEntryPoint.RSDB/GameAnalyzedEventInfo.Product.*.rstbl.byml.zsmust include the event and every subflow the event needs loaded. This is not recursive: if a custom flow calls a custom common flow that calls a vanilla flow, also include that vanilla flow and the vanilla flow's own listed dependencies.
- Inspect the target flow before editing:
- List actors, entry points, actions, queries, and reachable events from the edited entry point.
- Trace from the exact entry point (
Talk,Near, custom quest entry, etc.), not merely from the file root. - Search vanilla for the same actor action/query before inventing parameter shapes.
- Patch the smallest surface:
- Add action/query names to the actor's declared action/query list before using them in events.
- When creating
evfl.Actor()declarations, clone a vanilla declaration for the same performer when possible. For every actor record synthesized from scratch, populate all six safe-default event-member params: integerEventMemberCreateMethod = 0; booleansIsGrounding = false,IsWorld = false, andIsBindNearestActor = false; and stringsUseEventModelAnime = ""andUseEventAS = "". Do not emitparams = Noneor an empty params container ({}). Newly added actor rows without a minimally populated parameter table can crash the game even when the file parses and reopens successfully. The mandatory minimal subset has not been isolated; no penalty is currently known for including all six, so builders must include the full set. Preserve or add actor-specific fields where vanilla uses them, such asExceptionalBindType = 1for commonNpc_EventStarterspeaker patterns. Also set the correctconcurrent_clips;Npc_EventStarterandGameDataActortalk-flow examples commonly use1. - Use
scripts/eventflow_actor_params.pyfrom builders and validators instead of retyping the six-field table. Callensure_safe_actor_params()when synthesizing an actor andassert_safe_actor_params()on the written/reopened flow, scoped to the actor records the builder added. - For actor event-root AINB action/query work, trace the runtime actor's
EventPerformerParam.EventUniqueAin; an EVFL actor declaration such asNpc_EventStartermay be a relay/facade and not the AINB owner that must be patched. - Preserve existing parameter keys and scalar types by cloning a nearby vanilla or local event when possible.
- For
EventTalk, update the referenced Mals/MSBT label in the same task as the EVFL edit.
- Validate from written output:
- Decompress and reparse the patched
.bfevfl.zs. - Trace the edited entry point and confirm branch targets, params, and terminal events.
- Read back
EventSettingandGameAnalyzedEventInfo; confirm the event row names the intended entry point and includes the complete non-recursive subflow preload set. - For minimal/generated one-entry flows, also confirm there are no stale entry points or unreachable template events left in the written flow.
- For vanilla-preserved flows, confirm retained vanilla events are reachable from explicit entry points. If the original
Talkbranch is kept whileTalkis redirected, preserve the original branch asvanillaTalkinstead of leaving it as a disconnected root. - Decompress and search the patched Mals archive for each new
MessageId. - Validate every newly synthesized actor declaration after reopening the written output. Require all six safe-default keys with the expected scalar types; for blank-authored defaults, also require the expected values. Additional vanilla-derived keys are allowed.
- Confirm the overlay contains only intentional files.
- Decompress and reparse the patched
Runtime Debugging Procedure
Use this procedure whenever an EventFlow parses but does not run, stops before an expected branch, or behaves differently in game than static inspection suggests.
- Separate launch failures from logic failures:
- If the actor exists but the event never starts, first verify
AIScheduleParamhook,EventSetting,GameAnalyzedEventInfo, target flow name, entry point, actor declarations, and Mals availability. - If any debug
EventTalkappears, the event launched; debug from the last visible message forward instead of reworking actor/schedule wiring.
- If the actor exists but the event never starts, first verify
- Build from a proven baseline:
- Preserve the last mod folder that ran in game.
- Create fresh versioned test overlays instead of mutating failed builds in place.
- Keep source overlays read-only and write only the new test folder.
- Use cropped breakpoint variants:
- Physically remove every event after the chosen breakpoint and remove unrelated/unreachable late events from the test file.
- Do not merely disconnect, bypass, or rewire around suspected nodes. A malformed unreachable node can still make the EventFlow fail at load time, so disconnected content can invalidate the test.
- Keep only the entry path, required actors, required subflow entries, and the next small EventFlow surface under test.
- Add diagnostic
EventTalknodes:- Put a short debug talk immediately before and after the newly tested section, plus branch-case talks where case meaning is uncertain.
- Add matching Mals/MSBT labels in the same build, enforce the dialogue line-length rule, and verify labels after recompressing.
- Once earlier sections are proven, put debug talks only in the newly added section so playtest output stays readable.
- Advance in a ladder:
- Add one class of surface per variant: direct
EventTalk, a subflow call, a self-subflow with literal args, a GameData int/bool branch, a player equipment query, an attachment query, an item remove/award action, etc. - If a later variant reaches its after-debug message, earlier variants in the same ladder are normally proven and do not need more testing.
- If a variant never starts, suspect load metadata or a malformed node still present in the cropped file. If it starts and stops, the failing surface is between the last visible debug talk and the next expected one.
- Add one class of surface per variant: direct
- Control stateful confounders:
- Reset or explicitly read back GameData work variables before relying on them.
- Add debug readouts before and after reset/classification branches when stale values could mimic a valid result.
- Do not infer actor/query semantics from names alone; use debug branches to prove case meanings in the exact player state being tested.
Editing Rules
- Prefer a task-local Python builder script for binary edits. Do not hand-edit hex or rely on one-off GUI state for repeatable mod builds.
- Use the vanilla
Pack/ZsDic.pack.zszs.zsdicdictionary for.bfevfl.zs, Mals.sarc.zs, RSDB, and most compressed BYML files unless a known file type requires a different dictionary. - Keep source mod files read-only when building tests; write outputs to a separate overlay folder.
- Use event numbers that do not collide with existing names. Reparse after writing because EVFL index tables are easy to corrupt silently.
- Be suspicious of event parameter types. In event-editor, write vector params as arrays like
[0,0,0]when floats are intended; a string that looks like a vector is wrong. - For new or changed text, patch the correct locale archive, usually
Mals/USen.Product.*.sarc.zs, underEventFlowMsg/<FlowchartName>.msbt. - Keep generated EventFlow dialogue lines short and validate every changed MSBT label before packaging. Use the established 48 UI-rendered character line limit for each line, excluding MSBT tags/markup from the count; insert explicit line breaks instead of leaving one long unwrapped line, preserve balanced tags, and pad intentional one-line EventTalk bubbles as
line\n\nand two-line bubbles asline 1\nline 2\n. - When cloning an EventFlow to a new file, set both the EventFlow root name and
flowchart.nameto the new flow name if the editor library exposes both. EventSetting still points atWork/Event/EventFlow/<FlowchartName>.evfc, while the overlay file is normallyEvent/EventFlow/<FlowchartName>.bfevfl.zs. - Add the full transitive subflow set to
EventSettingandGameAnalyzedEventInfo. Subflow preload does not cascade; include child subflows even from branches you do not expect to reach. Missing subflow load data can prevent the event from running even when the EVFL file itself parses.- Do not guess the closure from direct EVFL calls alone. Trace every custom subflow until it reaches vanilla flowcharts; for each vanilla flowchart you call, inspect its vanilla
GameAnalyzedEventInforow and copy/merge itsSubFlowListinto the custom event's row. For example, a custom flow that calls a custom common flow, which then calls vanillaGetPouchContent, must also includeGetPouchContentand the vanillaGetPouchContentdependencies such asCommonandOpenActionGuideScreen. - If the user is testing runtime behavior, follow the Runtime Debugging Procedure above: use cropped breakpoint variants, not rewired full graphs, and do not leave disconnected later events in the file.
- Build breakpoint ladders from a proven minimal baseline. Each new variant should add one class of EventFlow surface at a time, such as a subflow call, a literal self-subflow, an int/bool branch, a player equipment query, an attachment query, or an award/remove action. If a later variant reaches its after-debug talk, earlier variants in the same ladder are normally redundant.
- Do not guess the closure from direct EVFL calls alone. Trace every custom subflow until it reaches vanilla flowcharts; for each vanilla flowchart you call, inspect its vanilla
- When an EventFlow task reaches into actor event-root AINB files to add or expose actions/queries, validate the AINB with more than the same writer that produced it. AINB round-trips can preserve parseability while corrupting unmodelled selector-default string fields, including Japanese "other" default labels on F32/String selectors. Cross-check untouched default selector labels and string-pool fields with a second parser/export or raw scan before handing back a test mod.
Minimal Talk Flow Pattern
For a simple placed NPC that only needs one custom Talk line:
- Reuse a vanilla talk EventFlow as a template and keep the
Npc_EventStarteractor plus itsEventTalkaction. - Start with the vanilla
InitTalksubflow when the template uses it; wire itsnxtto a new singleEventTalkaction whoseMessageIdisEventFlowMsg/<FlowchartName>:<Label>. - Clone an existing
EventTalkparameter container from the same flow, then change only choice fields andMessageIdunless the requested behavior needs more. - When the output only needs a single
Talkline, do not leave the rest of the vanilla template graph inflowchart.events. After cloning the actor/action/parameter shape, prune the flow to the intended entry point(s) and reachable events only, usuallyTalk -> InitTalk -> EventTalk. - If the user asks to preserve the vanilla template graph, keep the old
Talkbranch reachable by renaming its entry point tovanillaTalkbefore repointingTalkto the customInitTalk -> EventTalkchain. - For a one-line
Talkflow, validate a compact graph shape after writing: oneTalkentry point, anInitTalksubflow as the entry event, oneEventTalkspeech event, and zero events unreachable fromTalk. This avoids editor tools showing disconnected leftover template nodes even when the game can run the flow. - For blank-authored talk flows, also re-open the written flow and confirm generated actor declarations have valid flowchart performer metadata: used actor rows should have non-empty event-member params with the standard keys, and
Npc_EventStarter/GameDataActorshould use the sameconcurrent_clipsand params shape as a comparable vanilla flow. Do not treat successful EVFL parse/readback alone as runtime-safe. - In Python
evfl, look actors up withActorIdentifier("Npc_EventStarter"), not a generic string holder. - If the source flow contains an actor identifier for the base NPC and the clone has a new actor name, rename that identifier in the cloned flow even when no event currently references it. This keeps future edits and diagnostics coherent.
- For the matching Mals archive, add
EventFlowMsg/<FlowchartName>.msbtand verify the label bytes and UTF-16LE message text after recompressing.
Common Patterns
- Start NPC talk with
InitTalksubflows when vanilla examples do so. UseArg_GreetingandArg_Turn; pair talk usesInitTalk_Pairwith actor params. - Use
GameDataActorbool/int/enum queries for quest state, remembered dialogue, and branch gating. - For
GameDataActor.EventQueryIsGameDataBool, case0means the bool is true and case1means the bool is false. Do not treat this like ordinary false/true integer ordering. - Use
ChallengeSystemActoractions for quest step progress; persistent quest progress also needs theStep_<ChallengeName>enum inGameDataList. - Use
PouchSystemActorfor adding/removing/checking inventory contents; useGetPouchContentsubflows for item get windows. - Use
EventRequestQuitonly when you want to terminate the playable event deliberately. Vanilla examples vary inSpecialEventActionType; verify with a minimal test.
References
- Read
references/eventflow-working-model.mdfirst when authoring or substantially changing EventFlows. It gives the mental map for EVFL graph structure, external wiring, common recipes, validation, and failure modes. - Read
references/player-state-query.mdwhen usingPlayer.EventQueryCheckPlayerState, interpretinggame::player::EventQueryPlayerStatevalues, or debugging player-state branch behavior. - Read
references/action-query-catalog.mdwhen choosing actor actions, queries, or parameters from observed vanilla examples. - Read
references/quest-wiring.mdwhen creating or debugging the full chain from Banc actor placement to AISchedule, EventSetting, GameData, Challenge, Mals, and EventFlow. - Read
references/vanilla-eventflow-patterns.mdwhen designing new dialogue/content-selection behavior or interpreting vanilla flow logic such as ordered branches, missing cases, recent-talk variants, and reusable story barks. - Read
references/research-findings.mdwhen answering open-ended questions about what vanilla evidence supports, especially NPC behind-talk, actor event-root AINB command injection, relative orientation, AISchedule versus EventFlow responsibilities, and promising query/action families.