- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| .github/workflows | ||
| docs | ||
| melee | ||
| scripts | ||
| test_artifacts | ||
| .gitignore | ||
| .readthedocs.yaml | ||
| AGENTS.md | ||
| example.py | ||
| example_file.py | ||
| LICENSE.txt | ||
| pyproject.toml | ||
| README.md | ||
| test.py | ||
| test_framedata_resolution.py | ||
| test_hitbox_phases.py | ||
| test_live.py | ||
| uv.lock | ||
libmelee
This is a fork of libmelee geared toward machine learning.
Differences from upstream
- Gamestates match raw values from slp files, allowing faster tools such as peppi to be used to process replays for imitation learning without risking mismatch between replay data and live data. Upstream on the other hand preprocesses some values to make them more legible, e.g. sets intangibility for ledge grabbing.
- A separate process is used to keep the enet connection to dolphin alive. Otherwise, it will time out after one minute of inactivity.
- Sets up gecko codes for exi-inputs/fast-forward mode, which allows the game to run much faster than normal. These codes internally disable melee's rendering in the same way that is used to fast-forward a replay during playback. A custom dolphin build is required for this (see below).
- Fixes input stick and analog trigger values to match what the game outputs. This makes imitation-trained bots behave correctly. See this commit for details.
- Various other miscellaneous improvements, such as being able to control dolphin's debug logging, interfacing with mainline slippi-dolphin, setting infinite time mode, and playing as Sheik.
Installing Libmelee
This fork is now the source for the melee package on pypi, starting with version 0.45.0, and so can be installed with
pip install melee
To upgrade, run
pip install -U melee
Setup Instructions
Linux / OSX / Windows
-
You can install and configure Slippi just like you would for rollback netplay -- see https://slippi.gg for instructions. If you want to use fast-forward mode, you will need to use my fork of slippi-Ishiiruka. A prebuilt Linux AppImage is available here, which can be used like a regular executable. This build is also headless, meaning it has no graphical elements at all. There is also a Linux mainline build that can run either headless or with graphics (but not in fast-forward mode).
-
If you want to play interactively with or against your AI, you'll probably want a GameCube Adapter, available on Amazon. Alternatively the HitBox adapter works well too.
-
Run the example script:
./example.py -e PATH_TO_SLIPPI_FOLDER_OR_EXE
Fast-Forward Mode
To use fast-forward mode, set these arguments in the Console constructor:
console = melee.Console(
path="PATH_TO_CUSTOM_DOLPHIN",
gfx_backend="Null",
disable_audio=True,
use_exi_inputs=True,
enable_ffw=True,
)
Known Issues
- On MacOS, mainline slippi dolphin crashes (segfaults) for unknown reasons. You should use Ishiiruka instead, or you can try building a "nogui" executable (this is what I use).
Playing Online
Do not play on Unranked There is no libmelee option for it, but don't try. Eventually we'll have a way to register an account as a "bot account" that others will have the ability to opt in or out of playing against. But we don't have it yet. Until then, do not play any bots on Unranked. If you do, we'll know about it, ban your account, overcook all of your food, and seed you against a campy Luigi every tournament. Don't do it.
Quickstart Video
Here's a ~10 minute video that will show you how easy it can be to write a Melee AI from scratch.

Some of the minor aspects of the API have changed since this video was made, but it's still a good resource.
The API
This readme will give you a very high level overview of the API. For a more detailed view into specific functions and their params, check out the ReadTheDocs page here: https://libmelee.readthedocs.io/
GameState
The GameState represents the current state of the game as a snapshot in time. It's your primary way to view what's happening in the game, holding all the information about the game that you probably care about including things like:
- Current frame count
- Current stage
Also a list of PlayerState objects that represent the state of the 4 players:
- Character X,Y coordinates
- Animation of each character
- Which frame of the animation the character is in
The GameState object should be treated as immutable. Changing it won't have any effect on the game, and you'll receive a new copy each frame anyway.
Invulnerability Telemetry
PlayerState.invulnerable reports whether Slippi's current hurtbox collision state is invulnerable or intangible. PlayerState.invulnerability_left is retained for historical API compatibility, but the current Slippi protocol does not provide a remaining-frame countdown and libmelee leaves it at its compatibility default of 0. Use invulnerable for live decisions; do not infer a countdown from action states.
Note About Consistency and Binary Compatibility
Libmelee tries to create a sensible and intuitive API for Melee. So it may break with some low-level binary structures that the game creates. Some examples:
- Melee is wildly inconsistent with whether animations start at 0 or 1. For some animations, the first frame is 0, for others the first frame is 1. This is very annoying when trying to program a bot. So libmelee re-indexes all animations to start at 1. This way the math is always simple and consistent. IE: If grab comes out on "frame 7", you can reliably check
character.animation_frame == 7. - Libmelee treats Sheik and Zelda as one character that transforms back and forth. This is actually not how the game stores the characters internally, though. Internally to Melee, Sheik and Zelda are the same as Ice Climbers: there's always two of them. One just happens to be invisible and intangible at a time. But dealing with that would be a pain.
Some Values are Unintuitive but Unavoidable
Other values in Melee are unintuitive, but are a core aspect of how the game works so we can't abstract it away.
- Melee doesn't have just two velocity values (X, Y) it has five! In particular, the game tracks separately your speed "due to being hit" versus "self-induced" speed. This is why after an Amsah tech, you can still go flying off stage. Because your "attack based speed" was high despite not moving anywhere for a while. Libmelee could produce a single X,Y speed pair but this would not accurately represent the game state. (For example, SmashBot fails at tech chasing without these 5 speed values)
- Melee tracks whether or not you're "on ground" separately from your character's Y position. It's entirely possible to be "in the air" but be below the stage, and also possible to be "on ground" but have a positive Y value. This is just how the game works and we can't easily abstract this away.
- Your character model can be in a position very different from the X, Y coordinates. A great example of this is Marth's Forward Smash. Marth leans WAAAAY forward when doing this attack, but his X position never actually changes. This is why Marth can smash off the stage and be "standing" on empty air in the middle of it. (Because the game never actually moves Marth's position forward)
Controller
Libmelee lets you programatically press buttons on a virtual controller via Dolphin's named pipes input mechanism. The interface for this is pretty simple, after setting up a controller and connecting it, you can:
controller.press_button(melee.enums.BUTTON_A)
or
controller.release_button(melee.enums.BUTTON_A)
Or tilt one of the analog sticks by:
controller.tilt_analog(melee.enums.BUTTON_MAIN, X, Y)
(X and Y are numbers between 0->1. Where 0 is left/down and 1 is right/up. 0.5 is neutral)
Bots can express an absolute direction and radial strength with
melee.bot.stick_coordinates(reference_axis, angle_degrees, magnitude=...), or
apply it with SimpleControls.tilt_stick. SimpleControls.tilt_analog accepts
raw normalized (x, y) coordinates for either stick and validates both values
before forwarding them to the controller. Positive angles rotate
counter-clockwise from the reference axis, following the conventional signed
angle direction (RIGHT=0°, UP=90°, LEFT=180°, DOWN=270°). magnitude
is keyword-only, finite, and ranges from 0.0
(neutral) through 1.0 (the unit circle in centered processed-stick space);
omitting it preserves unit-magnitude behavior. The helper computes centered
radial components with sine and cosine, then maps each component independently
into the desired processed-stick/Console.step coordinates normalized to
[0, 1]. For example, centered components (0.8, 0.6) become (0.9, 0.8).
Pass that pair uncorrected to Controller.tilt_analog exactly once. The
controller applies libmelee's existing per-axis fix_analog_stick correction
when enabled. These are desired processed-stick coordinates, not predicted
emulator, game, hardware, or physical-gate outputs. Exact downstream output is
outside stick_coordinates' contract; the helper performs no gate calibration
or downstream-processing emulation.
HorizontalStickReferenceAxis is the strict LEFT | RIGHT subset used by
horizontal-only APIs. CharacterState.forward_axis() and backward_axis()
return this type, and SimpleControls.dodge() requires it, so strict type
checking rejects UP and DOWN before runtime.
Note on Controller Input
Dolphin will accept whatever your last button input was each frame. So if you press A, and then release A on the same frame, only the last action will matter and A will never be seen as pressed to the game.
Also, if you don't press a button, Dolphin will just use whatever you pressed last frame. So for example, if on frame 1 you press A, and on frame 2 you press Y, both A and Y will be pressed. The controller does not release buttons for you between frames. Though there is a helper function:
controller.release_all()
which will release all buttons and set all sticks / shoulders to neutral.
Simple Controls
melee.bot.SimpleControls.attack supports facing-relative attacks as well as
absolute horizontal variants. Use LTILT/RTILT, LSMASH/RSMASH,
and LSPECIAL/RSPECIAL when a bot should attack toward a screen direction without
translating through PlayerState.facing. Existing FTILT, FSMASH, and
SIDE_B requests remain facing-relative. Aerials intentionally provide only
facing-relative FAIR/BAIR, since their move behavior depends on character
facing. Ground tilts use a 0.35 centered cardinal magnitude (0.325/0.675
request coordinates), while smashes use full deflection. With default analog
correction, the game observes -0.35/+0.35; without correction, Dolphin's pipe
quantization yields approximately -0.5625/+0.55. Both remain strictly above
the directional -0.25/+0.25 tilt thresholds while staying inside the
-0.8/+0.8 horizontal, +0.6625 up-smash, and -0.6625 down-smash
boundaries. These are integer-quantized raw-stick values with at least eight raw
units of margin, not values placed directly on a floating-point threshold.
Standing input handling checks smashes before tilts. Directional aerial attacks
are issued through the C-stick only while
retaining matching horizontal main-stick drift. NAIR uses A with neutral
sticks because Melee has no neutral C-stick aerial input. Aerial requests start
only from actionable air states. Grounded states, including KNEE_BEND jump
startup, reject them so their inputs cannot become grounded moves; Melee begins
processing aerial inputs after jump squat ends.
CharacterState.can_attack(attack_type) uses the same move-specific eligibility
as SimpleControls.attack(), including ground/air compatibility, throws, tether
Z-air, and jump-cancel options. During KNEE_BEND, only UP_B, USMASH, and
GRAB are accepted. Common movement states use their own direct IASA rules:
turning excludes neutral-B, dash permits horizontal smash and side-B, running
permits dash attack and specials, and full crouch/crouch release permit normals
plus up/down-special but not grab. Landing states remain locked. Throws start
from GRAB_WAIT, not the pummel animation. DK's FTHROW enters Kong Karry;
from actionable cargo states, all four throw types release with a fresh A edge
and a facing-relative or vertical direction. Character-owned action states are
reported conservatively. Grounded DK Hand Slap is supported as DOWN_B; its
nonexistent aerial form is rejected. The no-argument can_attack(),
can_air_attack(), and can_grab() forms are deprecated; pass the intended
AttackType instead.
LEFT_B and RIGHT_B remain deprecated aliases for LSPECIAL and RSPECIAL.
SimpleControls.press_button() and the raw stick methods mutate pending input
and return None; they do not infer actions from the pending controller packet.
Semantic helpers retain their existing return values, including the Hold
lifecycle and AttackFrameData returned by attack().
IceClimbersControls applies one-frame input immediately for Popo and evaluates
Nana's delayed result from her actual Slippi pre-frame controller packet and
observed post-frame action six frames later. Attribution requires her consecutive
processed fighter inputs to select the same intent as the queued Popo delta;
physical pad buttons and a matching animation alone are insufficient. Delayed
evaluation never writes or replays controller input. Multiple calls in one frame describe one physical final
packet and therefore receive the same observed delayed result. The facade remains
hold-free; use a montage for multi-frame ownership.
Popo's raw button and stick methods return None, while defense, platform-drop,
ledge, and taunt helpers return input-application booleans. Only Nana's delayed
predictor infers ActionFrameData from the final committed inputs.
Unsupported diagonal directions return None from the predictor, not a
neutral-attack prediction.
Charging smashes and supported neutral-B moves return a Hold. Do not call
SimpleControls.release(hold) in the frame that created it: pending controller
input is committed on the next Console.step(), so same-frame release neutralizes
the attack before Dolphin sees it. Smash holds remain active through startup and
count their 60-frame limit only while the engine charge window is observed. On a
later frame, release() acknowledges the
release command but may return AttackFrameData seeded with the hold's expected
action before PlayerState.action reports the move. Confirm startup from a later
game-state snapshot when observed startup matters. An accepted release marks the
token as released and records release_frame; do not reuse it.
CharacterState.can_jump() (also available as melee.bot.can_jump) reports
direct common ground jumps and remaining aerial jumps, including tumble,
platform drop, Jigglypuff's five character-owned aerial jumps, and helpless
DEAD_FALL / SPECIAL_FALL_*. It also follows each character's NTSC 1.02
normal-landing attribute and returns True during late actionable LANDING
frames. LANDING_SPECIAL and aerial landing lag remain blocked. It returns True
throughout common shield start, hold, reflect, and release. Yoshi can jump only
from its character-owned GuardOn_1 powershield state. Shield stun and hitlag are
not actionable, and jump squat itself cannot begin another jump.
CharacterState.can_dodge() reports direct ground Escape paths from standing,
early dash, and eligible shield phases; shield stun and KNEE_BEND are excluded.
Early-dash and shield-release results are action-level eligibility because their
remaining engine windows are not exposed by PlayerState.
CharacterState.can_airdodge() accepts normal JUMPING_* / FALLING* actions
plus PLATFORM_DROP and Jigglypuff's character-owned aerial jumps, and rejects
active attacks, tumble, AIRDODGE, and helpless post-Up-B DEAD_FALL /
SPECIAL_FALL_* states.
SimpleControls.shield(strength) applies analog shield pressure without replacing
stick or non-shoulder button input. 0 always releases; positive values below
Melee's first usable trigger step (43/140, after its inclusive 0.3 deadzone)
clamp to exported MIN_SHIELD, while values through 1 are preserved with analog
input correction enabled or disabled. Full
depression also presses digital L; positive requests act only when shielding can
start or continue.
SimpleControls.dodge(GroundDodgeStickReferenceAxis) sets absolute roll input
for LEFT/RIGHT or spot-dodge input for DOWN on the next committed frame
when can_dodge() succeeds. During early dash it accepts only the absolute
forward direction because Melee forces a forward roll; during shield release it
accepts only DOWN for spot dodge, and Yoshi's GuardOff state likewise permits
only the DOWN spot-dodge path.
SimpleControls.air_dodge(axis, angle_degrees=0, magnitude=1) sets the
corresponding absolute main-stick vector when can_airdodge() succeeds. Both
reset pending inputs before pressing digital L by
default, optionally accept digital R, return whether input was applied, and never
flush the controller. Their stick and shoulder remain latched until the caller
replaces or clears them on a later frame.
For a short hop, press X or Y and release it before the character's
Action.KNEE_BEND jump-squat animation ends. A character with N jump-squat
frames has an N - 1 frame short-hop hold window. Holding jump through the final
jump-squat frame produces a full hop. Controller input persists until explicitly
changed, and pending input is committed on the next Console.step(), so count
committed game frames when scheduling the release.
Strategies and Listeners
Strategy[A] is a stateful abstract base for compartmentalized in-game logic.
Implementations pass name and description to the constructor and implement
tick(...) -> Continue | Exit. game_tick(...) delegates to tick; an Exit
contains a reason and is sent to listeners registered with add_exit_listener.
get_exit_listeners() returns the private collection. Strategies also own an
optional active montage through the same getter, setter, and identity-sensitive
change-listener API as BaseBot. Selecting a strategy makes BaseBot subscribe
to that montage state and mirror it until the strategy is replaced or cleared.
The bot logs strategy changes, strategy exit reasons, and montage name changes at
DEBUG. Every montage abort returns Abort(reason) and logs its name and reason at
WARNING.
The same strategy class may be instantiated multiple times during one match,
with each instance retaining independent state.
Listener[P, R] adds a stable string identifier to a typed callable.
Listener.create(identifier, callback) constructs a SimpleListener. Listeners
keeps unique identifiers in execution order with O(1) identifier lookup and O(1)
access to its cached immutable ordered tuple. Adding the same identifier replaces
the callback in place; plain callables receive generated UUID identifiers.
Listener registration signatures use the shared ListenerOrCallable[P, R] alias.
SimpleControls.tilt_turn() requests a half-strength backward main-stick input;
Melee reverses facing on character-dependent turn frames 5 through 9.
SimpleControls.smash_turn() requests full backward input, reversing facing on
turn frame 1 and starting a dash if held. Neither helper flushes or clears other
pending inputs.
Input Montages
melee.bot.InputMontage is the base class for short-lived controller sequences
that need coordinated input over multiple game ticks. Each montage accepts an
optional name that defaults to its concrete class name. A bot creates a new montage
for each attempt, calls tick(simple_controls, player_state, opponent_state, game_state) every tick, and retains the returned montage while work continues.
- The current montage returns itself while it is waiting or active.
- Returning another
InputMontagefinishes the current node and hands control to a follow-up or branch. - Returning
Truefinishes successfully. ReturningAbort(reason)aborts and returns the same value to the caller; cancelling or timing out uses its own distinct terminal state. ReturningFalsefromon_tick()is deprecated but remains compatible with a framework-generated abort reason. Booleanshould_abort()results are likewise deprecated; returnAbort(reason)orNoneinstead. Deprecated result forms emitDeprecationWarning. add_abort_listener(listener)registers an identifier-aware callback that receives the sameAbort(reason)when the montage entersAborted.get_abort_listeners()exposes that collection. Timeout and cancellation do not notify abort listeners.add_pre_tick_listener(listener)adds an observer with the same four inputs ason_tick. Listeners run in insertion order immediately beforeon_tickand returnPreTickResult.CONTINUE,EARLY_COMPLETION, orPreTickResult.Aborted(reason). Every listener runs; precedence is abort, early completion, then continue. The first abort reason wins, neutralizes input, and skipson_tick; early completion skipson_tickand follows the normal successful branch-selection path. LegacyPreTickResult.ABORTEDis deprecated but remains accepted with a framework-generated reason and warning.PreTickResult.combine()exposes enum-only pairwise precedence. Named listeners replace an existing callback with the same identifier at its original position; plain callables remain supported with generated IDs.get_pre_tick_listeners()returns the private collection.frame_limitcounts activeon_tickcalls only. It is a safety boundary, not a substitute for an implementation detecting failure and returningAbort(reason).cancel(...)only cancels an active montage and returns its configured fallback, if any. It neutralizes pending input before handoff; implementations may override it to choose a state-dependent cancellation montage.StatefulInputMontage.add_stateful_pre_tick_listener(listener)preserves the same ordering and precedence while adding the current typed state as the fifth callback argument. Named listener identifiers survive this adapter.
Montages are intentionally single-use and should model relatively short sequences
such as a multishine cycle, charge cancel, or one link in a combo. An implementation
may retain the match's shared FrameData when it needs framedata queries.
Libmelee includes concrete technique montages:
InitiateDashMontage(direction)starts while grounded and on stage. It requests a neutral reset frame only when already moving in the requested direction; stationary or opposite-direction movement goes directly to one maximum left or right main-stick frame. After observingDASHING, it succeeds with that direction still held. The caller or anadd_branch()continuation must reset the stick once the player reaches the desired location. Direction is an absoluteStickReferenceAxis.LEFTorStickReferenceAxis.RIGHT.MultishineMontage(shine_count=2)performs the requested number of consecutive Fox or Falco shines using the same core action sequence as the historicaltechskill.multishinehelper.shine_countmust be at least two; when no explicitframe_limitis supplied, its baseline safety budget allows the normal cycle plus transition slack per shine. It uses Fox's three-frame or Falco's five-frame jump squat. Each observed rise in shine attacker hitlag adds only the newly observed frames to either the default or an explicit budget. It holds B through attacker hitlag and through non-final projectile-reflection hit animations so they return to the jump-cancelable loop; release and final states are held neutral until the sequence can retry or complete. Fresh Reflector hit and release frames extend the safety budget one-for-one, bounded by one complete hit-plus-release wait per requested shine.QuickAttackMontage(initial_direction)performs Pikachu's Quick Attack or Pichu's Agility with one or two continuous full-circle directions. The move itself starts with cardinal up+B before holding the initial zip vector. Queue the optional second zip with fluentadd_segment(direction)before activation or reactively during startup, the first zip, or through inter-segment frame 7. Frame 8 remains available only while hitlag defers the animation callback.can_add_segment()reports whether the remaining slot and input window are open. The first request is sticky. Pikachu's directions must differ by more than 38 degrees and Pichu's by more than 5; a rejected requested zip aborts unless the move reaches the ledge first.SwordDanceMontage(initial_direction)performs Marth's Dancing Blade or Roy's Double-Edge Dance from an absolute left/right starter. Queue up to three follow-ups withadd_segment(axis), which returns whether the direction was accepted. Every follow-up accepts all four cardinal axes; down selects the side branch on hit two, while hits three and four have distinct down branches. Left and right both select side after startup. Segments may be preconfigured or added reactively before each character- and branch-specific input window closes, and every continuation uses one fresh B edge.WavedashMontagesupports every standard character's jump-squat duration and requests the down-diagonal air dodge on the finalKNEE_BENDframe. Callers must choose the angle explicitly; 17.1 degrees is the shallow boundary. Boundary values and one adjacent float of roundoff are clamped one representable value inside the accepted interval. It succeeds only afterLANDING_SPECIALends in an actionable grounded state and aborts if the observed state skips past jump squat before the air-dodge request.SuperWavedashMontage(direction)performs Samus's standard grounded bomb super wavedash. It schedules opposite and desired horizontal inputs for bomb animation frames 41 and 42, then returns the stick to neutral for maximum travel. Standing and crouched bomb starts use the same animation-frame window; the height-dependent falling variant is intentionally unsupported.DoubleJumpCancelMontage(attack_type, attack_delay_frames=0)supports Yoshi, Ness, Peach, and Mewtwo with any standard aerial. It can own the first jump or start in air, forces a fresh double-jump edge, and confirms the aerial throughSimpleControls. Zero requests an instant cancel; delay later when a low aerial otherwise lands before its hitbox becomes active.frame_limitmust be at leastattack_delay_frames + 9so every supported grounded route can finish.LedgedashMontagereleases with the C-stick away, double-jumps inward on the first falling frame, and air dodges down-inward after the character's world-space ECB bottom clears a configurable threshold. The default0.25world-Y threshold follows the proven SmashBot standard-stage heuristic; override it for other geometry or character-specific routes. Once the double jump is confirmed, later falling or apex frames do not invalidate that completed phase.SimpleControls.platform_drop()requests one main-stick-down input only whenCharacterState.can_platform_drop()confirms an actionable grounded semisolid. It intentionally does not fast fall.PlatformDropFastFallMontageobservesPLATFORM_DROP, commits neutral to reset Melee's down-tap timer, presses down again, and succeeds at the character'sFastFallSpeed.SDIMontageidentifies damage victims instead of reacting to attacker or grab hitlag. During damage hitlag it alternates full-stick diagonals around a requested cardinal for one regular SDI pulse per frame. Horizontal shield SDI alternates the target direction with neutral because shield displacement ignores the vertical axis; vertical requests ignore shield windows and remain waiting for damage hitlag. Damage hitlag exits with cardinal C-stick ASDI without assuming trajectory DI; shield hitlag exits with the horizontal main-stick input its callback reads.PerfectPivotMontagesmash turns out of a grounded initial dash and attacks on the resulting one-frame turn state.SmashAttackMontage(axis, max_charge_frames=60)maps cardinal axes to up, down, absolute-left, and absolute-right smashes. Zero requests minimum charge; values 2 through 60 bound the engine charge counter without counting startup animation. One tick cannot be requested because Melee increments before consuming released A. Character-owned Ness, Peach, and Game & Watch smash states are recognized.release_charge()queues an earlier release on the next active tick without cancelling the montage.current_power()reports the projected1.0through1.3671damage multiplier that the released smash uses. Losing ground while charging aborts and neutralizes rather than issuing an aerial.get_framedata()exposes typed attack metadata after initiation.LinkBowMontage()starts Link or Young Link's grounded or aerial neutral-B.release()queues the shot for the first safe active tick,can_release()reports when that transition is available, andcurrent_power()reports the normalized power that a release queued on the current tick will fire, including the game's final IASA counter increment. Full power does not force release; the montage can hold through its one-minute safety window.YoshiEggThrowMontage(aim)starts Yoshi's grounded or aerial Up-B with one B-release packet before cardinal up+B to guarantee a fresh edge. Running starts retain their forward stick during that packet so RunBrake cannot consume the setup.aimreceives(player_state, opponent_state, game_state)and returns raw normalized main-stick(x, y)coordinates. It is evaluated on every active tick through action states 364 and 365, so a lambda can continuously retarget the egg from current state. B remains held until stickyrelease_charge()stops further charge accumulation; the callback continues running and its aim remains applied through the script-owned egg launch. No current-power API is exposed because libmelee does not report Egg Throw's private charge counter.JigglypuffRolloutMontage()gives grounded and aerial Rollout the same stickyrelease(),can_release(), and normalizedcurrent_power()interface. Full Rollout remains held until release, with the same one-minute safety window.LuigiGreenMissileMontage(direction, use_smash_bonus=True)andSkullBashMontage(direction, use_smash_bonus=True)own an absolute left/right side-B charge. The default commits one neutral preparation frame so the next horizontal+B input receives its native 20-count smash bonus. PassingFalsepre-holds the direction through the tap window before B for a zero-count start. Luigi, Pikachu, and Pichu auto-launch at full power.ShieldBreakerMontage()andFlareBladeMontage()provide the same caller- released interface for Marth and Roy on the ground or in air. Melee itself auto-releases their distinct full-charge attacks.DonkeyKongGiantPunchMontage,SamusChargeShotMontage,SheikNeedleStormMontage, andMewtwoShadowBallMontageuse exactPlayerState.neutral_b_chargetelemetry. Theirfire()andstore(ChargeStoreInput)requests are sticky; usecan_fire(),can_store(...), and normalizedcurrent_power()to gate decisions. Shield and grab storage are available except Mewtwo rejects grab; grounded rolls are available except for Sheik. Samus can fire, but cannot continue charging, in air. Charge states that Melee permits retaining use the one-minute safety window.LinkForwardSmashMontage(direction, max_charge_frames=0)specializes that lifecycle for Link and Young Link. Chained.followup()requests the fastest second slash. For caller-delayed timing, a pre-tick listener checkscan_followup(player_state)before calling.followup(). Link's observable request window is frames 18-48; Young Link's is 19-48. Inputs commit during their script/decomp-backed game windows at 19-49 and 20-49 respectively; shared character-relative action 341 confirms the second slash.SmashTurnJumpMontageuses the same pivot but jumps, retaining dash momentum while reversing facing for movement such as back-air setups. It finishes after confirming jump squat with its jump button still held. The caller or anadd_branch()continuation must hold or release that button for the intended short-hop or full-hop timing. "Smash turn jump" and "perfect pivot jump" are two names for this same technique.
The execution model follows the technical descriptions in SmashWiki's wavedash guide, jump-squat table, and ledgedash guide. The ECB-based ledgedash trigger is adapted from SmashBot's implementation.
API Changes
Each of these old values will be removed in version 1.0.0. So update your programs!
gamestate.playerhas been changed togamestate.players(plural) to be more Pythonic.gamestate.xandgamestate.yhave been combined into a named tuple:gamestate.position. So you can now access it viagamestate.position.x.projectile.xandprojectile.yhave been combined into a named tuple:projectile.position. So you can now access it viaprojectile.position.x.projectile.x_speedandprojectile.y_speedhave been combined into a named tuple:projectile.speed. So you can now access it viaprojectile.speed.xgamestate.stage_select_cursor_xandgamestate.stage_select_cursor_xhave both been combined into the PlayerStatecursor. It makes the API cleaner to just have cursor be separate for each player, even though it's a shared cursor there.playerstate.character_selectedhas been combined intoplayerstate.charcter. Just use the menu to know the context.playerstate.ecb_leftand the rest have been combined into named tuples like:playerstate.ecb.left.xfor each ofleft,right,top,bottom. Andx,ycoords.hitlagboolean has been changed tohitlag_leftintProjectileSubtypehas been renamed toProjectileTypeto refer to its primary type enum. There is a newsubtypeint that refers to a subtype.
OpenAI Gym
libmelee is inspired by, but not exactly conforming to, the OpenAI Gym API.