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-specialty rewrite 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.

Arm pennant width by weapon class tier favored (30)off-class (42)far tier (54) arm 30high 30low 30arm 30high 30 arm 42high 30low 30arm 30 arm 54high 30low 30arm 30 AGL budget
Same AGL, three weapons. Only the weapon-hand arm changes width; the wider it is, the fewer commands the turn admits.
TierArm costOver baseWho lands here
Favored class30-Vahn with a sword, Noa with a claw, Gala with a club
Off-class42+12 (×1.4)e.g. Gala holding a claw
Far tier54+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 +0x74 cost 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 → 30Off-class → 42Far → 54
Vahn (863)blade / knife / sword / fistclaw, axeAstral Sword only
Noa (864)claw / feral / fang (+ knife)sword / bladeclub / axe
Gala (865)club / axe / maceclaw, 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.

WeaponVahn (Left)Noa (Right)Gala (Left)
Survival Knife, Battle Knife303042
Short Sword, Force Blade304230
Beast Buster, Chaos Breaker30-30
Nail Glove, Crimson Nails, Fighter Claw, Bloody Claw423042
Survival Club, Red Club305430
Power Club, Survival Axe, Battle Axe, Great Axe425430
Astral Sword54--
Character-locked gear (Ra-Seru weapons, Feral / Hard Beat / Heavy Strike, Holy / Golden Claw, Mace)303030
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 bitGraysBlocks
0x08 (limb 0)LEFT arrowSquare / dir 0
0x10 (limb 1)RIGHT arrowCircle / dir 3
0x20 (limb 2)UP and DOWNTriangle and Cross
0x1000 (Curse)the whole MAGIC commandMagic

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

ClaimWhat 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 / dataAddressWhat it proves
Gauge build + pressFUN_801D388C (overlay 0898)Case 9 / 0x2C reads +0x74 (store at 0x801D3B3C); case 0xB debits ctx+0x6DC; one byte is width and price.
Command menu SMFUN_801D0748State 0x50 Arts input; limb-bit gray and gate agree bit-for-bit.
Load-time writerFUN_800557B8 (SCUS)Verbatim 43-word copy; the single cost write fires at 0x80055810 under a live write-watch.
Character assemblyFUN_80052770 / FUN_80052FA0Section selection from the record's equip bytes; swing-record splice; id-0 default fallback.
Execution resolverFUN_801EC3E4Per-command fold into working ATK; called from SCUS 0x800478A0.
Enemy budgetFUN_801E9FD4The AI pays the same +0x74 costs from its AGL gauge.
Disc bytesPROT 863..866asset battle-data-pack decode of every weapon section's swing_rec + 0x74 - the tier tables above.
Live RAMDAT_801C9360[char][cmd]+0x74Gala + 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 / fieldMeaning
0x8007BD24Pointer to the battle context struct
0x801C9360Per-party-member pointer to the command-record pointer array; [char][cmd] + 0x74 is the cost byte
0x801F4B8C / 0x801F4B94Displayed 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 / +0x19Menu flow byte; active slot; per-command AP costs; commands committed
ctx+0x6DCTurn pool, seeded from actor AGL (+0x154)
actor+0x158 / +0x16E / +0x170Working 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.

See also