Repository navigation
Use every attack routine a monster has in battle - #192
Merged
Merged
Conversation
Battle resolves only a monster's first attack routine. This commit fixes the contract for using the others and the tests the implementation must pass. RoutineUse labels each routine. The first is primary. A later one is alternative when the OSE SRD offers it as a free choice each round, situational when the SRD ties it to a situation osrlib doesn't model, and special when it is a breath, a gaze, or a spell. AttackRoutine.use carries the label and MonsterAction.routine names a routine by index. Both are stubs with no behavior yet. The generated data is regenerated through the compiler because the new field changes the dump. Every routine now reads "use": "primary" until the implementation labels the later ones. The tests pin the label of every routine in the catalog, a compiler that refuses an unlabelled later routine, a default policy that picks only among primary and alternative routines, and a game policy that can name a situational routine. They also pin that a special routine or an out-of-range index rolls nothing and that a replay gives the same events. The tests that fail today are marked as expected failures for the attack-routines chunk. The tests that pass today guard behavior the chunk must keep, such as a monster without an alternative drawing exactly as before. Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
Battle resolved only a monster's first attack routine, so a thoul never used a weapon, a mule never bit, and an effect in a later routine never applied. Now every routine carries a label, the default policy picks among the free choices, and a game's own policy can name any routine. The SRD compiler labels every routine after the overrides apply, so the bone golem's override-split routines are labelled too. A later routine whose attacks are a breath, a gaze, or a spell is special by its name. Every other later routine takes its label from the _ROUTINE_USES table in tools/srd_compile/monsters.py, keyed by template id and the routine's attack name, with the OSE SRD text that justifies it. The compiler fails the build on a later routine with no label, naming the monster, and the conjured monsters on spell pages go through the same function. monsters.json was regenerated with the compiler, and only the labels of later routines changed. spells.json didn't change, because the conjured snake has one routine. ScriptedPolicy picks a melee routine after its target, on the monster-action stream, with equal chance among the primary and alternative routines. A monster with one such routine draws nothing for the pick. Battle resolves the routine a melee action names. It resolves nothing for a special routine or an index the template doesn't have, and it never rolls an attack entry named gaze or breath. A confused monster's attack still uses its first routine. No golden file moved. None of the goldens contains a monster with an alternative routine, and every other monster draws exactly as before. Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
mmacy
force-pushed
the
chunk/attack-routines
branch
from
October 30, 2026 21:11
4f8eff7 to
99124fc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Battle used only the first attack routine in a monster's stat block. A thoul never used a weapon, a mule never bit, an elephant never trampled, and an effect in a later routine never applied. Now battle uses every routine.
What changed
The SRD compiler labels each routine with a
RoutineUse:PRIMARY: the first routine.ALTERNATIVE: a free choice the OSE SRD prints with "or". Five monsters have one: the spitting cobra, thoul, mule, minotaur, and wererat.SITUATIONAL: tied to something osrlib doesn't model, like a trample, a thrown boulder, or a ship. There are 24.SPECIAL: a breath, a gaze, or a spell. There are 21.The compiler stops the build when a later routine has no label, so a new SRD monster can't arrive unlabelled. Each table entry quotes the SRD text behind it.
ScriptedPolicypicks a routine with one draw on the monster-action stream, among the primary and alternative routines. A monster with only one candidate makes no draw, so no golden file changed.MonsterAction.routinelets a game's own policy name any routine, including a situational one. Battle never rolls a special routine, or an entry namedgazeorbreath, and it skips an index the template doesn't have.The adaptations register, the RNG stream reference, and the changelog describe the rule.
What to check
tools/srd_compile/monsters.py. The test file'sEXPECTED_USEStable lists all 48 monsters that have more than one routine. The white ape's thrown rock isSITUATIONAL, as a missile attack. The SRD gives it no situation either way.PRIMARY, and the default policy picks it as often as the first. The changelog tells game developers to label later routines.https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD