Stamina economy: running drains stamina, fatigue forces walk #178
Labels
No labels
alpha:wave-0
alpha:wave-1
alpha:wave-2
alpha:wave-3
area:assets
area:combat
area:ecology
area:infra
area:render
area:scripting
area:ui
area:world
enhancement
epic
migration
post-alpha
roadmap
tech-debt
type:bug
type:chore
type:design
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
marco/IsoMmo#178
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to the run/walk gait feature: make running cost stamina so it isn't free, the way UO does.
Background
The gait feature ships run/walk as two speeds with no cost (run is strictly faster, walk is a deliberate-slow choice). Today
Mobile.Stamina => Dexis a read-only stub ("not yet wired"). This issue turns stamina into a real drainable pool and gates running on it.Scope (proposed — needs its own design review)
Mobile(max from DEX), draining per run step and regenerating over time / while walking or standing (server-tick paced, like mana regen).Runningflag (server-authoritative; a modified client can't run on empty).SystemMessageIdcue ("too winded to run") — new catalog entry, no loose string.PlayerMobile).Definition of Done (delta)
World).Parent/prereq: #177 (run/walk gaits).
Agreed design (reviewed with
critical-design-review)Motivation from the owner: running through marsh should cost stamina — otherwise marsh is merely "slower" instead of a real decision. Stamina is what turns the run gait (#177/#180) and the marsh move-cost (#138) into a trade-off.
Blocked on sequencing: this sits on top of two unmerged branches — the run gait (#180) and the marsh move-cost (#138, on
feat/biomes-art/#155). Terrain-scaled drain needsTerrainDef.MoveCost, gating the run needs the gait. Agreed order: merge #180 and #155 first, then build stamina on a cleanmain(an integration branch stacking all three would carry the 4 known conflicts and be redone at merge time anyway).Design
Mobile.Stamina => Dexstub toMaxStam => Dex, add a currentStamwith an intrinsic clamped setterSetStam(mirrorsSetHits/SetMana). State lives on the entity; no side collection.max(cost(from), cost(into))), so a marsh run step drains more. Tracked in tenths (like skills) so marsh costs 1.6x rather than 2x through integer rounding.StamRegenTicks, mirroring the existing mana regen (currentTick % n), and only when the player did not run this tick (sprinting never regenerates).Runningflag. A hysteresis threshold (~15% of max) is required before running resumes, so the gait doesn't flip every regen tick.SystemMessageId, e.g. "too winded to run") when the server downgrades the gait, plus an optional client-derived "winded" hint (the client knows it requested a run and seesRunning=falsecome back — no new wire field). The real fix, a vitals HUD, is a separate follow-up (it also finally surfaces HP/mana).StamRegenTicks, run drain per step, resume threshold: allGameOptionsfields, default in one place.Invariants Check
Running— a modified client can't run exhausted. GM auth ✓/set stamreusesMobileStat+CanExecute. Identity N/A (no account/claim change). Protocol versioned ✓ the newSystemMessageIdis a protocol enum → bump in the same change. String catalog ✓ cue is an id + catalog template, no literal. Single-threaded sim ✓ drain/regen run in the tick on the sim thread, no lock.World.csHARD GATE ✓ no formula inWorld— drain lives inMovementSystem/a vitals component,Worldonly delegates.ScreenHARD GATE ✓ client side is just an existingSystemNoticepath; nothing added toGameScreen. Client engine-independence N/A for the MVP (no new client logic beyond a catalog template, already in Client.Core and tested). Gameplay/Networking separation ✓ rule inGameplay/, cue leaves via the existing notice path. Act on the instance ✓Stam+SetStamon the entity, no per-id dictionary. Extend by type not switch ✓ stamina is a vital like the others;/set stamis one moreMobileStatvalue, not a new type switch. Server-paced actions ✓ drain and regen advance per tick; a client can neither suppress the drain nor speed the regen. Persistence (GameServer) ✓ transient in the MVP → no format change; if persisted later it is one field + that entity's version bump. Persistence (Auth) N/A. Process separation N/A. Typed options ✓ the three tunables areGameOptionsfields. Broadcasts/AoI ✓ no new observable event; the cue goes only to the affected player, positions stay absolute. Multi-platform ✓ pure .NET tick logic. Assets N/A (no new art). Asset naming N/A (no pack entries). ModernUO ✓ follow its stamina-gates-running model; diverge by not replicating weight/hunger-linked regen tables we don't have. Docs & DoD ✓ architecture movement note + the tunables + this DoD.No
✗, no HARD GATE tripped.Verification plan
World— sustained running drains stamina and the player drops to walk at zero; withRunning=trueand 0 stamina the step uses the walk cooldown (the trust-boundary case); regen only rises when not running; hysteresis prevents per-tick gait flapping.SystemMessageIdhas a template (the existing completeness test enforces it).Definition of Done (delta)
World).Runningflag).SystemMessageId(no loose string) and is throttled so held movement can't flood the journal.Vitals HUD (the visibility gap this design leans on) tracked separately in #181.
Marco aiutami invece di farti le unghie a tema pokemon 💅
Risolta: stamina economy (run drena, esaurimento forza a camminare) su main (#185).