-
Notifications
You must be signed in to change notification settings - Fork 0
02 6 Quick Start Bump N Jump
This page explains the game-level setup used for Bump N Jump.
{usb_root}\boosted\Bump N Jump_boost.toml
This example combines several Sprint Boost systems in one game:
- 2-player
game_infotracking (active player, lives, score, smashed cars) -
play_statspersistence across game sessions - Session-triggered play-stats rollovers when a game-over condition is detected
- On-screen leaderboards shown in a custom game layout (Score, Track Reached, Smashed)
- Player-specific visual switching based on whose turn is active
Bump N Jump extends the shared Display menu with a game-specific item:
[menu.menus.display.item9]
label = "Switch to Leaderboard View"
action = { command = "switch_layout", layout = "bnj_layout" }This keeps the base menu intact and adds one game-level action to jump into the custom leaderboard layout.
Bump N Jump uses game_info for both active-player stats and per-player score tracking.
[game_info.values.active_player]
address = "0x01A0"
decode = "u16"
transform = { op = "offset", value = 1 }
[game_info.values.active_lives]
address = "0x019C"
decode = "u16"
[game_info.values.active_smashed_cars]
address = "0x019D"
decode = "u16"
[game_info.values.active_score_low]
address = "0x0314"
decode = "u16"
[game_info.values.active_score_thousands]
address = "0x0315"
decode = "u16"
transform = { op = "mul", value = 1000 }
[game_info.derived.active_score]
op = "sum"
terms = ["active_score_low", "active_score_thousands"]
[game_info.values.active_track_number]
address = "0x0167"
decode = "u16"
[game_info.values.p1_lives]
address = "0x01A3"
decode = "u16"
[game_info.values.p2_lives]
address = "0x01AD"
decode = "u16"
[game_info.values.p1_score_low]
address = "0x01A9"
decode = "lo_bytes_le"
[game_info.values.p1_score_thousands]
address = "0x01AB"
decode = "u16"
transform = { op = "mul", value = 1000 }
[game_info.derived.p1_score]
op = "sum"
terms = ["p1_score_low", "p1_score_thousands"]
[game_info.values.p2_score_low]
address = "0x01B3"
decode = "lo_bytes_le"
[game_info.values.p2_score_thousands]
address = "0x01B5"
decode = "u16"
transform = { op = "mul", value = 1000 }
[game_info.derived.p2_score]
op = "sum"
terms = ["p2_score_low", "p2_score_thousands"]What this is doing:
-
active_playeris decoded from memory, then shifted withoffset = 1so values line up cleanly as player1and2. -
decode = "u16"reads a plain 16-bit value. -
decode = "lo_bytes_le"is used for split score values where the low bytes are stored separately in little-endian order. - The thousands value is normalized with
transform = { op = "mul", value = 1000 }. -
game_info.derived.*introduces computed values by combining terms. Here, each final score is rebuilt withop = "sum".
This derived-score pattern is important because Bump N Jump does not store every score as one simple memory value.
The play-stats section persists player totals across sessions.
[play_stats]
enabled = true
stats_file = "{gv.game_play_stats_path}"
auto_save_quit = true
auto_save_reset = true
[play_stats.session_triggers]
auto_save = true
[play_stats.session_triggers.p1_game_over]
game_info = "p1_lives"
trigger = { mode = "changes_to", value = 0 }
[[play_stats.session_triggers.p1_game_over.conditions]]
game_info = "p2_lives"
op = "eq"
value = 0
[play_stats.session_triggers.p2_game_over]
game_info = "p2_lives"
trigger = { mode = "changes_to", value = 0 }
[[play_stats.session_triggers.p2_game_over.conditions]]
game_info = "p1_lives"
op = "eq"
value = 0
[play_stats.players.p1]
label = "P1"
[[play_stats.players.p1.save_conditions]]
game_info = "p1_score"
op = "gt"
value = 0
[play_stats.players.p1.tracked.score]
game_info = "active_score"
mode = "amount_increased"
[[play_stats.players.p1.tracked.score.update_conditions]]
game_info = "active_player"
op = "eq"
value = 1
[play_stats.players.p1.tracked.smashed_cars]
game_info = "active_smashed_cars"
mode = "amount_increased"
[[play_stats.players.p1.tracked.smashed_cars.update_conditions]]
game_info = "active_player"
op = "eq"
value = 1
[play_stats.players.p1.tracked.track_number]
game_info = "active_track_number"
mode = "peak"
[[play_stats.players.p1.tracked.track_number.update_conditions]]
game_info = "active_player"
op = "eq"
value = 1
[play_stats.players.p2]
label = "P2"
[[play_stats.players.p2.save_conditions]]
game_info = "p2_score"
op = "gt"
value = 0
[play_stats.players.p2.tracked.score]
game_info = "active_score"
mode = "amount_increased"
[[play_stats.players.p2.tracked.score.update_conditions]]
game_info = "active_player"
op = "eq"
value = 2
[play_stats.players.p2.tracked.smashed_cars]
game_info = "active_smashed_cars"
mode = "amount_increased"
[[play_stats.players.p2.tracked.smashed_cars.update_conditions]]
game_info = "active_player"
op = "eq"
value = 2
[play_stats.players.p2.tracked.track_number]
game_info = "active_track_number"
mode = "peak"
[[play_stats.players.p2.tracked.track_number.update_conditions]]
game_info = "active_player"
op = "eq"
value = 2How to read these entries:
-
enabled = trueturns on stats tracking for this game. -
stats_filepoints to the per-game persistent stats file path from global variables. -
auto_save_quitandauto_save_resetsave automatically on quit/reset. -
session_triggersrolls to a new play-stats session when either player's lives change to0and the other player's lives are also0. -
session_triggers.auto_save = truesaves the finished session before rollover. -
players.p1andplayers.p2create separate tracked profiles. -
save_conditionsavoids saving empty runs (only save when score is greater than 0). -
tracked.score,tracked.smashed_cars, andtracked.track_numberdefine what to accumulate. -
mode = "amount_increased"records only positive increases. -
mode = "peak"fortrack_numberpreserves the highest track reached in that session. -
update_conditionsroutes shared active values to the correct player usingactive_player == 1or2.
Result: one set of in-game counters can drive clean per-player persistent history.
The custom layout is defined as the default and combines gameplay with persistent stat visuals.
[display]
default_layout = "bnj_layout"
[display.layouts.bnj_layout]
[[display.layouts.bnj_layout.elements]]
type = "leaderboard"
play_stat = "score"
order = "desc"
header = "High Scores"
include_players = ["p1", "p2"]
[[display.layouts.bnj_layout.elements]]
type = "leaderboard"
play_stat = "track_number"
order = "desc"
header = "Track Reached"
include_players = ["p1", "p2"]
[[display.layouts.bnj_layout.elements]]
type = "leaderboard"
play_stat = "smashed_cars"
order = "desc"
header = "Smashed"
include_players = ["p1", "p2"]
[[display.layouts.bnj_layout.elements]]
type = "image"
source = "{gv.assets_images}/bnj/bnj_p{gi:active_player}.png"
fallback = "none"What appears on screen:
- Three leaderboard panels (Score, Track Reached, and Smashed), all using persistent
play_statsdata. - A dynamic side image that switches with
active_player, so each player gets their own visual when it is their turn.
This pattern is a strong example of combining live memory reads, persistent tracking, and layout-driven UI in a single game profile.
Continue to the final Quick Start game page: