Player Join Scripts
Join scripts are global event hooks that execute when a player completes an in-progress join and enters active play. OpenBOR provides numbered scripts for slot-specific behavior and a shared joinall.c script for handling every player through one event listener.
The numbered series consists of:
data/scripts/join1.cdata/scripts/join2.cdata/scripts/join3.cdata/scripts/join4.c
The shared listener is:
data/scripts/joinall.c
Join scripts execute after OpenBOR creates the joining player's entity. This makes them useful for party scaling, cooperative encounter adjustments, player-specific initialization, join effects, role assignment, shared objectives, statistics, announcements, and other systems that should react immediately when the active player group changes.
Usage
Create any desired join-script files in data/scripts. OpenBOR loads them automatically, so no model, level, or project command is required.
join#.c is documentation shorthand in which # represents the player number. Literal filenames use 1 through 4.
| File | Scope | Player identification |
|---|---|---|
data/scripts/join1.c
|
Player 1 | Filename - index 0
|
data/scripts/join2.c
|
Player 2 | Filename - index 1
|
data/scripts/join3.c
|
Player 3 | Filename - index 2
|
data/scripts/join4.c
|
Player 4 | Filename - index 3
|
data/scripts/joinall.c
|
Every player | Local variable playerindex
|
Projects may use only the numbered files, only joinall.c, or both layers together.
Join Event
Join scripts respond to the native in-progress join routine. The event occurs after a vacant player slot begins joining, completes its character or color selection as applicable, and confirms entry while joining is permitted.
The event does not represent every player entity creation. It is distinct from:
- Initial player creation when a level begins.
- Respawning an existing player after a lost life.
- Spawning an arbitrary player-type entity through level or script commands.
- Creating any other entity from a model that happens to use Onspawnscript.
Each completed in-progress join executes the applicable join-script chain once.
Execution Order
OpenBOR performs the relevant join sequence in this order:
- The player confirms an allowed in-progress join.
- OpenBOR initializes the player's lives and stored spawn health and magic values.
- OpenBOR creates the player's entity with its native player-spawn routine.
- The corresponding numbered script,
join1.cthroughjoin4.c, executes when present. joinall.cexecutes when present and receivesplayerindex.- OpenBOR clears the player's pending join input.
- Native post-join behavior continues, including the configured enemy-drop and level-timer reset behavior.
The new player entity already exists when either join-script layer begins. Scripts may therefore retrieve the entity through the player property API and immediately inspect or configure it.
The numbered script always executes before joinall.c. Shared logic can consequently consume state established by the slot-specific script during the same event.
Numbered Join Scripts
Numbered join scripts are tied to the player slot identified by their filename. They receive no automatic event variables because the player identity is already fixed by that filename.
void main()
{
// join2.c always represents Player 2, player index 1.
setglobalvar("player_two_joined", 1);
setglobalvar("player_two_role", "support");
}
Slot-specific files are convenient when each player position has a distinct responsibility, starting package, interface, camera role, team assignment, or other fixed behavior.
Joinall
joinall.c is the shared listener for every player slot. OpenBOR supplies one automatic local variable:
| Variable | Type | Description |
|---|---|---|
playerindex
|
Integer | Zero-based index of the player who completed the join. Values range from 0 through 3 for Players 1 through 4.
|
void main()
{
setglobalvar("last_joined_playerindex", playerindex);
setglobalvar("party_changed", 1);
}
The zero-based index matches OpenBOR's player property and scripting conventions:
playerindex
|
Player label | Corresponding numbered script |
|---|---|---|
0
|
Player 1 | join1.c
|
1
|
Player 2 | join2.c
|
2
|
Player 3 | join3.c
|
3
|
Player 4 | join4.c
|
joinall.c does not receive an automatic entity reference. The joining entity is available from the player slot because native spawning has already completed:
void main()
{
void joined_entity = getplayerproperty(playerindex, "entity");
if (joined_entity)
{
setglobalvar("joined_player_ready", playerindex);
}
}
Creators can use joined_entity immediately with the entity property API, binding functions, visual effects, or other systems that operate on active entities.
Combining Numbered and Shared Logic
Both layers may participate in the same join. Their fixed execution order supports a useful division of responsibility:
- Numbered
join#.cperforms slot-specific setup. - Shared
joinall.cperforms project-wide reconciliation after that setup.
For example, numbered scripts might assign asymmetric cooperative roles while joinall.c recounts the active party, rescales an encounter, refreshes shared objectives, and displays a common join effect.
void main()
{
int active_players = 0;
int index = 0;
for (index = 0; index < 4; index++)
{
if (getplayerproperty(index, "entity"))
{
active_players++;
}
}
setglobalvar("active_player_count", active_players);
setglobalvar("rebalance_encounter", 1);
}
This compact shared listener responds to whichever slot joined without duplicating the party-reconciliation logic across four files.
Choosing a Join Script
| Need | Recommended hook |
|---|---|
| Behavior unique to one fixed player slot | Corresponding join#.c
|
| The same behavior for every joining player | joinall.c
|
| Fixed slot setup followed by common party handling | Numbered join#.c and joinall.c together
|
| Behavior whenever any entity using a model is created | Onspawnscript |
| Behavior when an existing player returns after losing a life | Respawn Scripts |
Other Uses
Quick applications include:
- Party scaling - Recalculate enemy counts, durability, aggression, hazards, rewards, or encounter phases when the party grows.
- Cooperative rules - Enable team mechanics, shared resources, revival systems, combined objectives, or multiplayer-only routes.
- Player setup - Assign slot-specific roles, starting equipment, colors, resources, control modes, or interface elements.
- Join presentation - Play sounds, queue visual effects, display announcements, or introduce the arriving player.
- Camera coordination - Recalculate camera targets, split attention, stage boundaries, or multiplayer tracking behavior.
- Objective reconciliation - Add the player to escorts, survival conditions, team counters, voting systems, or synchronized sequences.
- Statistics and achievements - Record participation, join timing, party composition, or cooperative milestones.
- Development tools - Log join order, inspect selected models, verify slot state, or test multiplayer entry conditions.
Related Scripts
| Script | Relationship |
|---|---|
| Respawn Scripts | Execute when an existing player returns after losing a life. The numbered script runs before respawnall.c.
|
| Die Scripts | Execute when a player loses a life. The numbered script runs before dieall.c.
|
| Onspawnscript | Model event that executes for entity creation generally, including entities that are not player-controlled joins. |
| Keyscript | Layered player-input events that may participate in beginning and confirming an in-progress join. |
| level.c | Global level-start event. Initial player creation is separate from the in-progress join event. |
| Score Scripts | Numbered and shared global listeners for player score adjustments. |