`CastSpellByName(name, onSelf)` dropped its second argument, and `CastSpell(slot, book, onSelf)` read only two. So a self-cast macro line such as `CastSpellByName("Power Word: Fortitude", 1)` buffed the selected friend instead of you. With no friendly target and `autoSelfCast` off, it did not cast at all.
In the reference, `CastSpellByName` (`0x4b4ab0`) reads its second argument through `GetBoolOrDefault(L, 2, 0)` (`0x4b4aea`-`0x4b4af1`). `CastSpell` (`0x4b42f0`) reads its third the same way (`0x4b4333`-`0x4b433c`). When the value is nonzero, the active player's guid replaces the selection as the guid handed to the dispatcher `0x4b3300` (`0x4b4afa`, `0x4b4345`). The player's book then binds it through `ArmCast`'s explicit-guid leg (`0x6e5393`). The pet book sends it as `CMSG_PET_ACTION`'s target (`0x4b34ce`).
- `ScriptCall::CastSpell` and `CastPetSpell` now carry `on_self`, read with `binding_abi::bool_or_default`. That is not Lua truthiness: `"0"`, `"false"` and `0.5` are false; `"yes"`, `"on"` and `1` are true.
- The action bar's self-bind swap is now `CastContext::self_bound`, which `UseAction`'s `onSelf` and the two script casts share. `ui_spellbook::cast_spell` applies it and hands `on_self` to the attack pick.
- The pet book's `CMSG_PET_ACTION` aims at the player under `onSelf`.
Tests:
- `cast_spell_by_name_reads_on_self_as_the_reference_coerces_it` and `cast_spell_reads_on_self_from_its_third_argument` cover the coercion.
- `on_self_casts_at_the_player_and_leaves_the_selection`, `on_self_binds_the_player_where_the_selection_is_not_assistable` and `a_pet_book_cast_on_self_aims_at_the_player` check the wire target through `apply_script_calls`.
Fixes#446🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>