Repository navigation
Sitting, bows on the shared cooldown, reserved ceilings, beast copy (#637 #265 #285 #631) - #638
Merged
Merged
Conversation
…he claws
claws.yaml narrates every claws species (birds, bats, skeletons, the
smoke-wrought Elemental Prince), none of which can pounce: three prepare
and wait records now promise a strike. Two claws and two bite fumble
records made the body part the subject of FUMBLE ("A figure's claws
FUMBLE pathetically as they stumble!"); the attacker fumbles now, per the
#455 rule. Guards: no body part before a FUMBLE banner in any natural
pool, and no pounce in the claws pool.
Refs #631
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The double-fumble comedy lines are picked without looking at either side's gear, so "Your weapon slips at the exact moment Steppe Wolf trips over their own guard!" reached an unarmed admin. The record now reads "attack goes wide" in all three roles; a test fails any line that names a weapon. Refs #631 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ow lunge
"You hardly need to move, the attack is so far off!" named no attacker;
the record now names {actor} for the defender and the room. A defended
hamstring read "sweeps aside the fumbled hamstring slash", the command
name, beside store lines that narrate a low lunge at the legs; the
defence label is now "low lunge", and a test holds the label to words
the hamstring store already shows the reader.
Refs #631
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#631 reported eight "Blood seeps from your wounds!" lines and no end line. Driving the round tick and the turn prune together shows the stack ticking once per round and the end line arriving once; this pins it. The run length is HamstringBleedRounds (12) / ThrottleBleedRounds (8) at a 1-point floor, a balance setting. Refs #631 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Sentinel (9552) never shot: the warbow (10046) was carried loot, never wielded, it had no arrows, and its per-mob tree had no try_fire. It now wields the bow (keeping the 60% drop chance on the equipped item), carries a Quiver of Arrows (30062), and its tree runs try_fire on mob_combat_round, the archer archetype's shot without the keep_distance kite. When the quiver runs dry the round falls through to its combat commands and melee as before. try_fire now fails when the mob cannot see clearly into the target's room, the same messaging.CanSeeClearly test actions.ExecuteFire refuses a shot on (TooDarkToAim / Blinded). Before, the tree claimed the round with a shot the fire rule then refused, so an archer in the dark did nothing at all; now it falls through to melee. Archer tests stand in lamp-lit rooms accordingly. Closes #265 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restores capped at the raw max and only the RecalculateStats reservation clamp knew about reservation, so regen, potion and heal ticks, drain and the lifesteal proc filled a reserved pool past what it could hold, and the prompt, status and GMCP showed the inflated value until the next clamp pulled it back. PoolCeiling (raw max less GetPoolReservation, floored at 1 for health and 0 otherwise) is now the one ceiling: applyVitalChange caps every ApplyRestore at it (never lowering a pool already above it), the RecalculateStats reservation clamp uses it, and the new SetPoolFraction caps spawn, respawn, companion summon and recovery, ReviveOnDeath and admin restore at it. Heal, which capped at raw HealthMax, is retired; its five callers pass positive amounts and now call ApplyRestore. Players and mobs share the rule. Nine files leave the pool-mutation guard's exemption list. Closes #285 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…layers and mobs alike (#265) Owner ruling 2026-10-19: bows were always meant to fire on the shared special-move cooldown. ExecuteFire claimed the timer on every shot but never waited for it, so a shooter could fire every round. It now asks SpecialMoveReady before the auto-chamber and before admission (a shot refused for the timer spends no stamina, arrow or round) and takes the timer with ClaimSpecialMove after admission and the stale-weapon check, the order bash and trip use. FireResult.OnCooldown reports a refusal. The player fire/shoot command answers with refusal.CooldownAfterCost, the line bash and trip give; the mob shoot command stays silent. The ambush is gated like any shot. try_fire fails while the timer runs, on the same SpecialMoveReady helper, so the Sentinel and every archer mob melee and use their other moves between shots. Tests: the ungated-opener test flipped to the ruling, the admission guard now pins two cooldown sites (ask, then claim), a second shot inside the cooldown is refused at no cost and fires once it clears, the player and mob wrappers refuse on the cooldown, and the Sentinel holds its bow for exactly the cooldown and then fires again. Help for fire, special, ambush, ranged-combat and cooldowns says so. Closes #265 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
) CommandIsReady and specialMoveVerbs had no fire entry, so a caller that asks before issuing a command (behaviour-tree command_best_of, the AI companion, gmcp CharOp) could issue a shot that ExecuteFire then refused on the shared special-move cooldown. Both now carry fire and its alias shoot. Beyond the universal activity and cooldown gates, a shot reads not ready with no ranged weapon, or with an empty one and nothing to chamber: the verb-level refusals ExecuteFire gives (NoWeapon, NotLoaded). The ammo lookup is now one helper, findAmmoBundle, shared with chamberNextRound. Drift rows cover fire and shoot on crafting, cooldown, no weapon and no ammo, and TestCommandIsReady_ShotWaitsForTheCooldown proves readiness and the fire rule agree before, during and after the cooldown. Closes #265 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sitting is a new Position state (appended, nothing renumbers), shared by players and mobs. `sit` and `rest` are one command (players: rest is a keywords.yaml command alias; mobs: both registered). The old `sit` emote alias is gone. - Edges: Standing -> Sitting; Sitting -> Standing (stand, walking off, or combat), Sitting -> Prone/Supine (a knockdown landing on a sitter). - Combat never runs against a sitter: Character.RiseForCombat stands one who is attacked (RevealForCombat) or enters combat (CombatPhase Idle->Engaging observer, hooks/Position_SitRise.go), narrated once. Not in CancelCombatConditions, so a dying sitter is not narrated up. - Refusals: asleep, already sitting, in combat, grappled, on the floor. - stand from a seat is free; go stands a sitter after the step is paid. - Regen: Balance.SitRegenMultiplier, shipped 2.0, below sleep; never stacks with sleep. SleepRegenMultiplier now shipped (5.0) too. - Not a knockdown: AttemptRecovery and the #398 guard ignore it. - Look lists "(sitting)"; {pos} prompt shows it in white; help sit/rest. Closes #637 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urns TestRunScenario_WallClockIncomplete advanced its manual clock fifty times and stopped. On a loaded machine (the full suite) RunScenario could set its deadline after the advancing ended, so the deadline never arrived and the test hung until the 10-minute package timeout. It now uses the package's pumpClock helper on the pumpCtx it already built, which advances until the run returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ints (#637) Teleport, recall, summon and the other forced moves left a sitter seated in the new room; only go stood them. The stand now lives in the two room choke points, so every move path, present or future, is covered: rooms.MoveToRoom (every player move) and Room.AddMob (every mob room entry) call Character.StandForMove, which stands a sitter silently under the new position.TriggerMoveStand. The combat-rise narration keys on TriggerCombatRise only, so no move (respawn included) narrates rising. The go wrappers' own narrated stand is removed: MoveToRoom and AddMob run after the step is paid, so a refused step still leaves a sitter seated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Stealth: sit, stand and the combat leap send their room line through actions.SendSeen, which is silent for a hidden actor (#274, owner R3); a hidden player who sits or stands is told "No one sees it; you are hidden." RevealForCombat now reveals before it stands a sitter, so the leap never names a hider. - Sleep (owner ruling 2026-10-19): sit never wakes a sleeper. The refusal now reads "You're asleep. Type 'wake' to wake up." and players can reach it: sit (and rest, its alias) is the one command in keepsSleep, which the dispatcher's cancel-on-action wake skips. Mobs are refused silently, as before. - Busy: the busy refusal moved into actions.Sit, so a casting, crafting or salvaging mob is refused as a player is. - Area attacks leave a sitter seated: owner ruling, working as intended. - Prompt comment counts 15 states; patch notes mention "Sitting" in the prompt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner ruling on #631: a line that tells the defender or the room about a defended attack names the attacker, so a defender facing two foes and a room watching a crowd know whose attack was stopped. 232 lines change (113 defender, 119 room) across block, dodge, parry, defy, quell and one counter-parry line; each keeps its meaning and voice and follows its file's colour convention. TestDefenceLinesNameTheAttacker holds every shipped defence store to the rule (it flags all 232 on the old files). Refs #631 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner ruling on #631: one outcome is told in one tier. A special move a defence blunted but did not stop swapped its room line for the defence triad's, so the room read "Ordel Quist smoothly sweeps aside the fumbled low lunge." while the defender read that the lunge still caught them. sendPartialMove (skill_move_defence.go, a twin in mobcommands and usercommands as moveDefenceLines already is) is the one rule: every role reads the store's partial event; only the defender's shortage note comes from the defence. All 12 mob moves and 9 player moves call it. Guards: TestSpecialMoveStoresCarryEveryTierTheRuleDraws (each partial event tells every role its hit tells; every rule caller has a partial), TestPartialMovesNarrateThroughTheRule (no hand-rendered partial outside shoot and throw, each exempted with its reason), and a behaviour test per package that the attacker, defender and room read the partial line. The two root guards that recognise move call-site helpers now know the new one. Refs #631 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… rule Owner rulings on #631. A partial is one tier told for every defence that can blunt the move, so every partial line in the special-move stores now says the move was blunted ("gets mostly clear", "stops most of it", "only half lands") and never how: no dodge, sidestep, roll, twist, block, guard or miss framing. Eleven stores change; bash and trip already read true. The firebomb's defended partial now goes through sendPartialMove: the thrower and the room read partial_hit, which gains its room line, "The edge of {actor}'s blast still catches {actee}!". The defence triad speaks only when the defence took the whole blast. The guard's throw exemption is gone; shoot's stays (its store has no room role to swap). Guards: defenceWordInPartial fails a partial line that names a defence (it flags 87 lines in the old stores), and the firebomb behaviour test drives the real Throw (it fails on the old throw.go, where the room read "Target withstands Thrower's firebomb."). Refs #631 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two grappling knee lines put "who" after "the grapple", so the grapple read as the thing that stopped the knee; the clause now leads. The throttle line names the throat as the target's own. Owner-approved wording. Refs #631 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Closes #637. Closes #265. Closes #285. Closes #631.
The last small-fix batch of 2026-10-19: a real Sitting position, bows on the shared cooldown, pools that respect their reserved ceiling, and the beast-copy leftovers from the #541 slice 2 playtest. Every player-facing line here is owner-approved.
#637 Sitting (
sit/rest)Sittingposition (appended to the enum, never persisted).sitandrestare synonyms for players and mobs;standgets up for free.SitRegenMultiplier2.0, belowSleepRegenMultiplier5.0 (now shipped explicitly); the two never stack.RiseForCombat); the reveal comes first, so a hidden sitter is never named before it is revealed. Death never narrates rising. Area attacks leave a sitter seated (owner: working as intended).rooms.MoveToRoom(players) andRoom.AddMob(mobs).actions.SendSeen, so a hidden actor's sit or stand reaches no one.sitis the only command that does not wake a sleeper, via thekeepsSleepset), already sitting, fighting, grappled, on the floor, busy. Busy is now shared by players and mobs inactions.Sit.#265 Sentinel warbow, bows on the shared cooldown
ExecuteFirechecksSpecialMoveReadybefore chambering and stamina, and claims the cooldown after. A refused shot spends nothing. Player line: "You need a moment to recover before you can shoot."; mobs are refused silently.CommandIsReadyandspecialMoveVerbsknowfireandshoot, so companions, behaviour trees and the client's readiness request wait instead of issuing a refused shot. Readiness and chambering sharefindAmmoBundle.try_fire.#285 Reserved ceiling
Character.PoolCeiling(raw max lessGetPoolReservation) is the one ceiling: every restore, the recalculation clamp, and the newSetPoolFractionstop at it.Healis retired in favour ofApplyRestore. PowerScore'satFullPoolsis unchanged (owner's call).#631 Combat copy
TestDefenceLinesNameTheAttacker).sendPartialMove(mobcommands and usercommands): all three roles read the move's partial tier, for 12 mob moves, 9 player moves and the firebomb. Every partial line is defence-neutral (guard over a defence-word list). Guards cover store tiers and call sites.Also
TestRunScenario_WallClockIncompletenow pumps its manual clock until the run returns; a bounded advance could end before a loaded machine set the deadline, hanging the package for 10 minutes.Gate (on the batch head)
gofmt -lempty;go build ./...; fullgo test . ./internal/... ./modules/... -count=1with no failures;golangci-lint run --new-from-merge-base=origin/master0 issues; boot check exit 124, 0 panics,Server Readyonce. Each task's tests were null-probed (the fix removed, the test seen to fail, restored). A separate review of #637 found four issues; three were fixed, and the fourth (area attacks) was ruled working as intended.Patch notes:
## 2026-10-19: Take a seatand## 2026-10-19: Bows wait their turn, and fights read true.🤖 Generated with Claude Code