Scene Node Definitions
✂️Cut Control
What it does
The scnCutControlNode
is a fundamental logic gate in the scene system. Its one and only function is to act as a simple, high-speed Result-Router. It's a signal splitter.
The node itself is "dumb," stateless, and contains no internal logic or data fields. Its power comes from its interaction with the signals it receives. Signals can be tagged with a SUCCESS
or FAILURE
state by a "smart" node that sent it.
If you're familiar with programming, a Cut Control is basically an if-else statement that operates the check on the signal.
The CutControlNode
's job is to inspect this tag on the incoming signal and route the execution flow down one of its two dedicated paths. This provides designers with a clean, reusable component to create conditional branches based on the outcome of a gameplay action or check.
Why the Name "CutControl"?
The name can be confusing. It does not mean it can only "cut" as in interrupt a node. Think of it like using scissors on a wire - the Cut Control node literally cuts the signal into two: the true signal via Out0 and the false signal via Out1.
To further add to the confusion: scnCutControlNode
works differently from it's quest node equivalent ie questCutControlNodeDefinition
questCutControlNodeDefinition
's job is to actually handle cuts as in interrupts. It first cuts all the assigned nodes from its CutSource
socket (which only go to CutDestination
of other sockets) and then fires its Out
socket
Sockets
Inputs
In (0,0
)
Input
The single entry point. It receives a signal that has been tagged with a SUCCESS
or FAILURE
state by an upstream node.
Outputs
Out0 (0, 1
)
Success / True
The path taken when the incoming signal is tagged with SUCCESS
.
Out1 (1, 0
)
Failure / False
The path taken when the incoming signal is tagged with FAILURE
.
The Source of the Logic: "Smart" Nodes
The conditional check does not happen inside the CutControlNode
. It happens in an upstream "smart" node that then generates the tagged signal. The most common state producers are:
scnChoiceNode
: A specific dialogue option can have a condition (like a stat check or payment) attached to it as a property. When the player selects that option, theChoiceNode
performs the check and tags its output signal with the result.scnQuestNode
->Condition
node: sometimes a Condition node is set upstream and at a later point, the signals are converged into a single output (via a Hub) - which then again at a later point is split into the true/false signals viaCutControlNode
Examples
Example 1: Narrative Branching (The Lifepath Check)
This is the clearest example of the node's primary purpose. Scene: base/open_world/street_stories/watson/kabuki/sts_wat_kab_04/scenes/sts_wat_kab_04_receptionist.scene
The Goal: Show a different version of a conversation based on V's Lifepath.
The Mechanism:
The player makes a dialogue choice. A
questConditionNode
upstream checks the player's lifepath and fires a signal taggedSUCCESS
for Corpo orFAILURE
for others.The
CutControlNode [84]
receives this tagged signal.It routes the flow:
Out0 (Success)
leads toSection [15]
, the professional "Corpo" dialogue.Out1 (Failure)
leads toSection [28]
, the rougher "Streetkid" dialogue.
Example 2: Looping Dialogue State (The Braindance Dealer)
This shows how the node is used to control a looping conversation. Scene: base/quest/main_quests/part1/q105/scenes/q105_04c_braindance_dealer.scene
The Goal: Keep the player in a conversation until they successfully purchase the required item.
The Mechanism:
After the player makes a choice, a linked
questConditionNode
checks if the objective is complete.It sends a
SUCCESS
orFAILURE
tagged signal to theCutControlNode [1437]
.The
CutControl
routes the flow:Out0 (Success)
breaks the loop and ends the conversation.Out1 (Failure)
routes the flow back to the start of the idle/choice loop, preventing the conversation from ending prematurely.
🔀Flow Control
scnFlowControlNode
and questFlowControlNodeDefinition
A compact gating tool that counts how many signals arrive while it is open and how many arrive while it is closed. It is a very stateful node. It is not dumb.
You steer it in two ways:
Window parameters
opensAt
/closesAt
– an automatic first-N / next-M limiter.Control pins
Open
/Close
/Switch
– instant manual override.
Because the node exists in both the Scene player and the Quest system, its counters live in different places, but the behaviour you see as a modder is identical.
What it does:
It maintains three state variables (or facts)
A count of signals received while the gate is open (let's call this internal counter:
openCounter
)A count of signals received while the gate is closed (let's call this internal counter
closedCounter
)The current open/closed state (this is stored in the node property:
isOpen
)
Every time a signals hits In the node of a Flow Control:
It checks the isOpen
property. One of the following things happen:
If it is set to true (i.e. it's opened) then the
openCounter
is incremented.Then a simple range check is done: has the
openCounter
we just incremented reached theclosesAt
yet?
If it is set to false (i.e. it's closed) then the
closeCounter
is incrementedThen a simple range check is done, has the
closeCounter
we just incremented reached theopensAt
yet?
If the answer is “No” to either question → the gate forwards the signal and keeps its current isOpen
state.
If the answer is “Yes” → the gate flips its isOpen state first and then re-checks:
if the currrent final flipped state = open → it forwards the signal via it's output socket
or if the final state is closed → it swallows/does not forward the signal
What do the sockets do then? They are overrides. You can just not use opensAt
and closesAt
params, and use Flow Control as a simple 'latch' with the sockets alone.
The Sockets always win
Open
sets state = open.Close
sets state = closed.Toggle
toggles the state.
Scope:
Scene runtime stores the counters in the scene resource and are reset outside the scene
Quest runtime stores them in a fact scoped to the Phase that owns the node
If you know how to code, you can also understand the Flow Control with this Python snippet:
class FlowControl:
def __init__(self, opens_at: int = 0, closes_at: int = 0,
start_open: bool = False):
self.opensAt = opens_at
self.closesAt = closes_at
self.isOpen = start_open # latch flag
self.openCounter = 0 # signals while open
self.closedCounter = 0 # signals while closed
self._override = None # None / True / False
# ─ pin handlers ────────────────────────────────────────────────
def pinOpen(self):
self._override = True # force state for THIS frame
def pinClose(self):
self._override = False
def pinSwitch(self):
self._override = not self.isOpen
# ─ main entry: returns True if signal forwarded ─────────────────
def signal(self) -> bool:
# 1) apply any override that came in earlier this frame
if self._override is not None:
self.isOpen = self._override
self._override = None # override lasts one frame
# 2) bump the appropriate counter
if self.isOpen:
self.openCounter += 1
# 3) test open-side limit
if self.openCounter >= self.closesAt and self.closesAt != 0:
self.isOpen = False # flip latch
else:
self.closedCounter += 1
# 3) test closed-side limit
if self.closedCounter >= self.opensAt:
self.isOpen = True # flip latch
# 4) forward or swallow
return self.isOpen
Sockets
In
✔
✔
Signal you want to gate
Out
✔
✔
Forwarded signal (if gate passes)
Open
should work¹
✔
Signal → state = open
Close
should work¹
✔
Signal → state = closed
Switch
should work¹
✔
Signal → state toggles
CutDestination
✔
✔
Standard interrupt used when you want to interrupt/bypass the entire check
Key properties
opensAt
Lower limit checked while gate is closed
0 (let the very first pulse open)
closesAt
Upper limit checked while gate is open
1 (one-shot), 2 (two-shot), 0 (infinite)
isOpen
Cached flag (true / false) saved with the scene/phase
You can pre-set to open or closed
Examples & Use-cases
One-shot VO – play once, never again
opensAt 0 / closesAt 1
same
Trigger → FlowCtrl → Section VO
Dual-shot – play twice, then stop
0 / 2
same
Distance Pause → FlowCtrl → animation
Auto-cap at N, but re-arm later
0 / N
, sockets optional
same + QuestEvent → Open
Timer loop → FlowCtrl → bark Section
Toggle every signal
numbers default, wire same signal to In & Switch
Event → (split) → Switch & In
Scene “bump” two-shot
0 / 2
n/a
Distance ≤ 2 m → 100 ms Pause → FlowCtrl → bump VO + anim
Scene capped bark loop
Two gates: [0-2)
and [2-3)
n/a
Randomizer → Hub → GateA / GateB → Pause → loop-back
Phase-scoped call-cap
n/a
opensAt 0 / closesAt 2
(no sockets)
PhaseOut → FlowCtrl → Output call
Manual latch
sockets only, numbers 0/0
QuestEvent.On → Open, QuestEvent.Off → Close
Choosing between numbers and sockets
“Fire a fixed N times, then never again.”
Just set opensAt / closesAt
and ignore sockets.
“Enable/disable it on command.”
Leave numbers at 0 / 0
and wire Open / Close sockets.
“Cap at N but allow re-arm.”
Window [0-N)
, plus Open pin to re-arm trigger.
Checklist
Scene logic – drop Flow Control where you need “play this node only the first N times.”
Quest logic – use it as a lightweight latch; sockets give you full control, numbers give you auto-limits.
Remember: the counters are scoped within a scene instance (for scenes) or the Phase node (for quests) ends.
🌐Hub
What it does
The Hub node is one of the simplest but most essential tools for organizing scene graphs. Its sole function is to be a signal merger or funnel. It takes any number of incoming execution paths and combines them into a single, unified output path.
Like the CutControlNode, the Hub is a "dumb," stateless node. It contains no internal logic. It doesn't care which input socket received a signal or how many signals it has received; it simply fires a signal from its Out socket every time any of its In sockets are triggered.
While the Hub's main job is to merge inputs, it's important to remember that its single Out socket can be connected to multiple downstream nodes. This allows a Hub to also act as a signal distributor, broadcasting a unified signal to several paths at once. This is often used to trigger multiple parallel events after a set of preceding conditions have been met and merged.
Sockets
In
, In1
, …
In
Execution
Any number of dynamically created input sockets. When you drag a connection to a Hub, a new input socket is automatically created.
Out
Out
Execution
A single output socket that fires whenever any input is triggered.
Examples & Use-cases
Example 1: Converging Logic Branches (The "Collector")
This is the most common use case: cleaning up the graph after several different logic branches have concluded.
The Goal: Ensure that multiple, mutually exclusive outcomes all lead to the same final step.
The Mechanism: As seen in the example image, a scene might have several FactsDBManager nodes that set different game states (holo_setup_active, holo_setup_started, holo_setup_ended). Each of these represents the end of a small logic branch. Instead of drawing a messy "spider web" of connections from all these nodes to a single End node, a Hub ([289]) is used as a collector. Each FactsDBManager connects to one of the Hub's input sockets. The Hub then provides a single, clean output connection to the final End node ([235]).

Example 2: Re-joining after a Condition
The Goal: After splitting the execution flow with a CutControlNode (e.g., for a lifepath-specific dialogue line), you often need to bring the paths back together to continue with actions that are common to all outcomes.
The Mechanism:
A CutControlNode splits the flow: Out0 (Success) goes to a "Corpo" dialogue Section, and Out1 (Failure) goes to the "Streetkid" dialogue Section.
The Out sockets of both the "Corpo" and "Streetkid" Section nodes are connected to the input sockets of a single Hub.
The Hub's single Out socket then connects to the next part of the scene that all players experience, regardless of which dialogue branch they took.
Checklist
Use a Hub whenever you need to merge two or more execution paths into a single path or when you need to split signals
It's an organizational tool: stateless, with no internal logic or properties.
It helps keep complex scene graphs tidy and easy to read by reducing visual clutter.
🚪Xor
scnXorNode
The Xor
node (short for Exclusive OR) is a 'first-come, first-served' gate. It's designed to solve a common problem: what to do when multiple different events could trigger the same outcome, and you need to ensure that outcome only happens once.
It listens to all its inputs, but only allows the very first signal that arrives to pass through to its Out
socket. Once it has fired, it enters a "latched" or "closed" state and will ignore all subsequent signals. This prevents unwanted "double triggers" from multiple sources.
Sockets
In
, In1
, ...
In
Execution
Any number of dynamically created input sockets.
Cancel
In
Out
Out
Execution
Fires a single time when the first signal is received on any In
socket.
Examples & Use-cases
Example 1: Player Action vs. Timer (The Holocall Race)
Scene:
ep1\quest\holocalls\alex\alex_holocall.scene

The Goal: A holocall is ringing. The scene must proceed if the player picks it up, OR if a certain amount of time passes and the player doesn't pick it up. We only care about whichever happens first.
The Mechanism:
The flow is broadcast to two
PauseCondition
nodes simultaneously.PauseCondition [326]
is aSystemCondition
waiting for the player to perform aPhonePickUp
.PauseCondition [22]
is aTimeCondition
acting as a timer (in this case, 4 seconds and 15 milliseconds).Both of these nodes feed into the inputs of the
Xor
node[104]
.Scenario A (Player is fast): The player picks up the phone. Node
[326]
fires, its signal passes throughXor [104]
, and the scene continues down the "answered call" path. A few moments later, the timer in[22]
finishes. Its signal hits the already-firedXor
node and is swallowed, preventing the "missed call" path from also triggering.Scenario B (Player is slow): The timer in
[22]
finishes first. Its signal passes throughXor [104]
and the scene proceeds down the "missed call" path. If the player eventually picks up the phone, the signal from[326]
hits theXor
and is ignored.
Example 2: Player Action vs. Proximity Trigger (The Cryo-Freezer Reveal)

Scene: base\quest\side_quests\sq021\scenes\sq021_03_trailer_park.scene
The Goal: After the player agrees to talk, a welcome scene should trigger as soon as either the player or Sobchak enters the trailer. The scene must not trigger twice if they both enter.
The Mechanism:
The player makes a Choice [1085]. The first option outputs to start two simultaneous checks.
Path 1 (Check NPC): PauseCondition [685] checks if Sobchak is IsInside the trailer's trigger area.
Path 2 (Check Player): PauseCondition [599] checks if the Player is IsInside the same trigger area.
Both conditions feed into the Xor node [1098].
The Xor's output starts the conversation Section [781].
Why the Xor is Necessary: The player and Sobchak can easily be inside the trigger area at the same time.
If a Hub were used, it would receive a signal from the player check and a signal from the Sobchak check, firing its output twice. This would cause the welcome dialogue in Section [781] to restart, creating a bug.
The Xor guarantees that the first entity detected - whether it's the player or the NPC, triggers the scene. The Xor immediately latches shut, and when the second entity is detected moments later, that signal is simply ignored. The conversation correctly starts only once.
Checklist
Use Xor whenever you need to ensure an action is triggered exactly once, especially when there are multiple possible triggers (e.g., player action, a timer, a proximity check).
It's a "one-shot" gate: it fires on the first signal it receives and then ignores everything else until it is reset.
🔗And
What it does
The And node is a synchronization point or a gatekeeper. Its purpose is to pause the execution flow until multiple, separate, parallel paths have all been completed.
It waits until it has received a signal on every single one of its input sockets. Only when the last required signal has arrived does the And node fire a single signal from its Out socket.
Sockets
Pin
Direction
Type
Description
In, In1, ...
In
Execution
The node will wait until a signal has been received on every one of these input sockets. The number of sockets is determined by how many connections are made to the node.
Out
Out
Execution
Fires a single time, only after all input sockets have received a signal.
Examples
Example 1: Waiting for Characters to Spawn
Scene: base/quest/side_quests/sq026/scenes/sq026_12_penthouse_gameplay.scene

This is the most common and critical use case for an And node: ensuring all necessary characters are present before a scene begins.
The Goal: Start a conversation in a penthouse, but only after two specific characters, Roxanne and Tom, have both finished spawning and are present in the scene.
The Mechanism:
The execution flow splits to start two simultaneous checks.
Path 1: PauseCondition [283] pauses the flow until the character roxanne has CharacterSpawned.
Path 2: PauseCondition [281] pauses the flow until the character tom has CharacterSpawned.
The outputs of both PauseCondition nodes are connected to the inputs of the And node [289].
The Out socket of the And node connects to the next part of the scene (e.g., the main dialogue Section).
Why the And is Necessary: Spawning characters can take a variable amount of time. Without the And node, the scene's timing would be unreliable.
If you only waited for Roxanne to spawn, the conversation could start while Tom is still invisible or not yet in the world, leading to characters talking to empty space or other visual bugs.
The And node acts as the rendezvous point. It doesn't matter if Roxanne spawns first or Tom spawns first. The And node will patiently wait, holding the scene, until it receives signals from both spawn checks. Only then does it allow the scene to proceed, guaranteeing that all participants are ready and the scene can play out correctly.
Last updated