Arts command gauge - weapon-specialty arm width
When a character's turn opens the Arts input, the battle UI draws an action gauge: a fixed AP pool the player spends by pressing directional commands. The weapon-hand swing costs more with an off-class weapon - the "longer arm input" players see. Two myths fall on this page: the off-class penalty is not a flat ×2, and the cost is not computed at runtime at all - it is per-(character, weapon) data on the disc, which is what makes it editable.
At a glance
- Cost byte
- Runtime command record
DAT_801C9360[char][cmd] + 0x74- one byte is both the AP price and the pennant width - Budget
- The character's AGL stat seeds the turn pool at
ctx+0x6DC; input ends when the next command would not fit - Disc source
- The equipped weapon's section in the character's player battle file (extraction 863..866), copied verbatim at battle load
- Tiers
- 30 favored / 42 off-class / 54 far tier - authored data, no class comparison in code
- Editor
- The ROM patcher's equipment editor and the randomizer's
--weapon-specialtyrewrite these bytes in place - Confidence
- Confirmed - live-pinned and byte-validated against the disc; "command
0x0C= the arm" is Inferred (how we know)
What the AP bar does
On your turn the Arts bar fills with a row of pennants, one per direction you press, and stops accepting input when the next pennant would not fit. Every direction has a price; three of the four never change. The fourth - the weapon-hand swing - is authored per weapon, and because the price is also the pennant's width, an off-class weapon looks wider and fits fewer commands in the same turn.
| Tier | Arm cost | Over base | Who lands here |
|---|---|---|---|
| Favored class | 30 | - | Vahn with a sword, Noa with a claw, Gala with a club |
| Off-class | 42 | +12 (×1.4) | e.g. Gala holding a claw |
| Far tier | 54 | +24 (×1.8) | Noa with any club or axe; Vahn's Astral Sword |
Only the weapon hand depends on equipment - Left for Vahn and Gala, Right for Noa. The Ra-Seru arm and the two leg commands are always 30. The "off-class doubles the arm" folklore counts penalties: the Astral penalty (+24) is twice the off-class penalty (+12); the cost itself is ×1.4, not ×2.
How the gauge consumes it
The gauge is assembled by the battle action handler; one case reads the cost, another spends it:
// gauge build (case 9 / 0x2C)
cost = command_record[cmd] + 0x74; // the arm width / AP cost byte
gauge_slot.width = cost - 6; // visual width on the bar
// press (case 0xB)
if (pool < cost) return; // not enough AP - input ends
pool -= cost; // ctx+0x6DC, seeded from AGL
One byte is both price and width - a larger button and a more expensive command are the same value. The pennant is a text window and its label has to fit: 30 is retail's floor, 24 is still legible, below that the label smears (the patcher refuses costs below 24). Two neighbours share the machinery:
- The Muscle Dome hand deals and spends the same records: a dome card is a direction command, its cost is the same byte, the commit debits the same pool (minigames).
- The enemy analogue: a monster fills its per-turn action queue by paying each move's
+0x74cost out of its per-round AGL gauge - the same "wider cost = fewer commands" mechanic on the AI side (battle action).
Two budgets, not one
The AP pool bounds a turn by cost; the committed command buffer (actor+0x1DF..+0x1EE) bounds it by count - sixteen bytes. A plain press is one byte; a matched art replaces its last arrow with a two-byte starter pair, so an N-arrow art occupies N+1 bytes. At retail costs the pool binds long before sixteen tokens do; a mod that prices commands low enough hits the buffer instead.
Where the cost comes from
The game performs no class comparison. The cost is written once at battle load as a verbatim 43-word block copy out of the assembled battle-character buffer - no arithmetic between load and store, confirmed by a live write-watch across a field→battle transition. The source is the equipped weapon's section of the character's player battle file:
section (LZS-decoded)
+0x04 u32 swing_rec ; offset to the swing/arm command record
swing_rec + 0x74 ; u8 arm cost ← the weapon-specialty byte
The descriptor table keys sections by item id, so each weapon has its own swing record per character's file - a claw is cheap in Noa's file and expensive in Gala's. Decoding all four files gives the byte-exact picture:
| Character (file) | Favored → 30 | Off-class → 42 | Far → 54 |
|---|---|---|---|
| Vahn (863) | blade / knife / sword / fist | claw, axe | Astral Sword only |
| Noa (864) | claw / feral / fang (+ knife) | sword / blade | club / axe |
| Gala (865) | club / axe / mace | claw, knife | - |
Cross-checked live: Gala + Nail Glove reads 42, Gala + Ra-Seru Club reads 30, matching his file's sections. The cost lives inside an LZS-compressed stream, so an editor decompresses the section, rewrites one byte, recompresses, and writes back within the slot footprint.
"Off-class" itself is legible from the static item records: the description pointer is shared per weapon class and carries a Best:<character> token - knife/sword → Vahn, claw → Noa, club/axe → Gala. The Astral Sword has its own description, matches no character, and simply sits on the tier Noa reaches with any club.
Every weapon, every character
Weapon-hand swing cost from each character's file; all other commands read 30. A dash means the file has no section for the weapon (the equip mask stops them equipping it anyway). Classes are finer than blade / claw / club: Gala swings a Short Sword at 30 but a knife at 42; Vahn swings light clubs at 30 but the Power Club and every axe at 42.
| Weapon | Vahn (Left) | Noa (Right) | Gala (Left) |
|---|---|---|---|
| Survival Knife, Battle Knife | 30 | 30 | 42 |
| Short Sword, Force Blade | 30 | 42 | 30 |
| Beast Buster, Chaos Breaker | 30 | - | 30 |
| Nail Glove, Crimson Nails, Fighter Claw, Bloody Claw | 42 | 30 | 42 |
| Survival Club, Red Club | 30 | 54 | 30 |
| Power Club, Survival Axe, Battle Axe, Great Axe | 42 | 54 | 30 |
| Astral Sword | 54 | - | - |
| Character-locked gear (Ra-Seru weapons, Feral / Hard Beat / Heavy Strike, Holy / Golden Claw, Mace) | 30 | 30 | 30 |
If the Astral Sword is forced onto another character
The value 54 exists in exactly one place on the disc - the Astral section of Vahn's file - and the other files have no section for that id. Forced into Noa's slot by a cheat, the section selector finds no match and takes the id-0 default entry: default mesh, default swing record, cost 30. She swings at the favored price and does not visibly hold the sword; the attack bonus still applies, because attack folds in at execution from the static equipment table, keyed by item id alone. A mod that wants the penalty to travel would have to add a section, and there is no room - every player file ends flush against its last slot. The in-place knob is the default record's own cost, which the ROM patcher's equipment editor exposes per section (not yet confirmed with a live capture of an edited save).
Status limb gating
A Rot-class status grays individual command arrows and refuses their input. The gray-draw pass and the input gate read the same status bits, bit-for-bit - and the retail assignment is not one bit per arrow:
| Status bit | Grays | Blocks |
|---|---|---|
0x08 (limb 0) | LEFT arrow | Square / dir 0 |
0x10 (limb 1) | RIGHT arrow | Circle / dir 3 |
0x20 (limb 2) | UP and DOWN | Triangle and Cross |
0x1000 (Curse) | the whole MAGIC command | Magic |
With all three limb bits set, Attack is unusable. Rot rolls exactly one of the three limb bits per application.
At execution: a different weapon read
Once a combo is committed, the execution resolver replays it one command per step and folds half the equipment slot's attack into the working ATK per swing - a read distinct from the gauge cost, covered in full on battle formulas. The battle loader deliberately folds no ATK at load; the fold happens here, per committed command.
Deep dive: dispatch bounds and the admission gate
The resolver FUN_801EC3E4 advances the input cursor at actor+0x1F4 and dispatches through PTR_801CF4B4[(actor+0x1D9) - 0xC], bounded at six arms (commands 0x0C..=0x11). The head admission gate tests a different band from a different place - (cmd - 0x0C) < 0x14 - so a command in 0x12..=0x1F is admitted and then folds nothing. 0x0E/0x0F share an arm; 0x10's slot is the same address the bounds check bails to - a live table entry that folds nothing. Retail applies no empty-slot test here. The call comes from SCUS_942.54 at 0x800478A0, which is why the resolver has no caller inside the overlay.
Common misconceptions
| Claim | What the bytes say |
|---|---|
| "An off-class weapon doubles the arm command." | Off-class is 30 → 42 (×1.4); the far tier is 30 → 54 (×1.8). The "double" counts penalties: +24 is twice +12. |
| "The game checks the weapon's class against the character." | No comparison exists; the value is authored data. The equipment, item-property and accessory tables were each checked - none carries the cost. |
| "The cost is recalculated when equipment changes." | Changing equipment alters only id bytes in the character record; the cost is read from the disc at the next battle load. |
| "The Astral Sword has a unique penalty." | Its 54 is the same far tier Noa receives from any club or axe. |
| "The AP shown next to an art is what the bar charges." | Two different gauges: a named art is paid from the Spirit gauge (actor+0x170), not the bar's pool. |
How we know
| Function / data | Address | What it proves |
|---|---|---|
| Gauge build + press | FUN_801D388C (overlay 0898) | Case 9 / 0x2C reads +0x74 (store at 0x801D3B3C); case 0xB debits ctx+0x6DC; one byte is width and price. |
| Command menu SM | FUN_801D0748 | State 0x50 Arts input; limb-bit gray and gate agree bit-for-bit. |
| Load-time writer | FUN_800557B8 (SCUS) | Verbatim 43-word copy; the single cost write fires at 0x80055810 under a live write-watch. |
| Character assembly | FUN_80052770 / FUN_80052FA0 | Section selection from the record's equip bytes; swing-record splice; id-0 default fallback. |
| Execution resolver | FUN_801EC3E4 | Per-command fold into working ATK; called from SCUS 0x800478A0. |
| Enemy budget | FUN_801E9FD4 | The AI pays the same +0x74 costs from its AGL gauge. |
| Disc bytes | PROT 863..866 | asset battle-data-pack decode of every weapon section's swing_rec + 0x74 - the tier tables above. |
| Live RAM | DAT_801C9360[char][cmd]+0x74 | Gala + Nail Glove = 42, + Ra-Seru Club = 30, matching the file bytes. |
Address appendix: records, context fields, static tables
Character records (stride 0x414 from 0x80084708): equip slots at +0x196..+0x19A (body, head, index 2, index 3, footwear), name at +0x2A7, accessories at +0x19B..+0x19D. Index 2 / 3 hold the weapon and Ra-Seru in the order the character's file expects: weapon in slot 2 for Vahn and Gala, slot 3 for Noa - the cheat-database "weapon = +0x198" label is Vahn's and Gala's layout.
| Address / field | Meaning |
|---|---|
0x8007BD24 | Pointer to the battle context struct |
0x801C9360 | Per-party-member pointer to the command-record pointer array; [char][cmd] + 0x74 is the cost byte |
0x801F4B8C / 0x801F4B94 | Displayed command codes 0C 0F 0E 0D / icon bases 0D 10 11 0C; 0x0C is the arm whose cost tracks the weapon |
ctx+0x06 / +0x13 / +0x14..17 / +0x19 | Menu flow byte; active slot; per-command AP costs; commands committed |
ctx+0x6DC | Turn pool, seeded from actor AGL (+0x154) |
actor+0x158 / +0x16E / +0x170 | Working ATK; status word (limb bits); Spirit gauge (where a named art's cost lands, via the accumulator at +0x224) |
0x80074368 (12-byte stride) | Item property records; +1 equipment-row index, +8 shared per-class description pointer |
0x80074F68 (8-byte stride) | Equipment stat rows; +1 attack, +6 equip-character mask |
0x80075EC4 (0x14 stride) | Arts-name table; +2 is the menu's displayed art AP (the Spirit charge) |
An emulator sweep of injected +0x74 values established the pennant legibility floor (24). A separate +2 in the build case is an empty-slot icon tweak, not the class penalty.
The full doc adds the gauge pool's AGL seed and Spirit refill, what a named art costs and where it is charged, the arts-AP override hook, and the port's input session: docs/subsystems/arts-command-gauge.md.