feat: stats & use-based skills, skill-based hit chance (#8) #34
No reviewers
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!34
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/stats-skills"
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?
Closes #8.
Summary
Character progression (M6): primary stats + use-based skills, wired into combat as a hit-chance roll.
Mobile. HP derives from STR (STR 50 → 50 HP; rat 20 → 20). Stamina/Mana (DEX/INT) are present + derived but not yet combat-wired (declared follow-up).SkillNameenum +SkillCatalog+SkillSet, values in tenths, 1000 = 100.0). v1 skills: Wrestling (unarmed) + Swordsmanship (sword). Train use-based: each swing may raise the weapon skill, slower as it climbs (SkillFormulas, quadratic falloff to the cap) — the UO grind. On a gain the player gets aSystemMessage("Swordsmanship increased 0.1 — now 30.1").CombatFormulas): equal skill = base, a big skill edge can guarantee the hit, a deficit floors at a sliver. Swings can miss → a floatingmissinstead of a damage number.PlayerSkillstable, Sqlite+Postgres migrations); stats are config-constant in v1 so re-seeded on connect.Design decisions (agreed in-thread)
BaseItem → BaseWeapon → Sword;Armor,Coin), each declaringKind+Graphic(art id, likeBaseCreature.Body) + stats, discovered by reflection (ItemCatalog) — replaced thestring→WeaponStatsdictionary.CombatSystem; World only delegates. Added a hard gate in CLAUDE.md ("World.cs does not receive logic") + a one-type-per-file rule.How it was tested
Unit:
HitChance(base/advantage/floor),SkillFormulas.GainChance(falloff + zero at cap),SkillSet.TryGain(+0.1, stops at cap). World: attacking trains the weapon skill, STR sets MaxHits, plus the existing combat-loop tests (updated: skill gaps make hits deterministic where needed). Persistence: skills round-trip through the store. 206 tests green, zero warnings, CSharpier clean.Needs your eyes (GUI)
Fight a rat unarmed: you should see occasional
miss, and a stream of "Wrestling increased 0.1 — now 30.x" over your character as it trains. Equip the sword and the messages switch to Swordsmanship. Tell me if the gain rate / hit-chance feel right (all tunable inCombatOptions).Checklist
just lintclean · [x]just testgreen (206) · [x] whole solution builds, 0 warnings · [x] multi-platform preserved · [x] tests added · [x] EF migrations both providersPrimary stats (STR/DEX/INT) on every Mobile; HP derives from STR (Stamina/Mana present, not yet combat-wired). A data-driven skill system (SkillName enum + SkillCatalog + SkillSet, values in tenths) that trains use-based: on each swing the attacker's weapon skill may rise, slower as it climbs (SkillFormulas), and the player gets a SystemMessage ("Swordsmanship increased 0.1 — now 30.1"). Combat now rolls to hit: weapon skill (attacker vs defender) drives hit chance (CombatFormulas), so swings can miss — a miss shows a floating "miss" instead of a damage number. All server-authoritative; the client never sets stats/skills. Skills persist across reconnect (dedicated PlayerSkills table, dual-provider migration); stats are config-constant in v1 so re-seeded on connect. Items become a class hierarchy (BaseItem -> BaseWeapon -> Sword; Armor, Coin), each declaring its Kind + Graphic + stats, discovered by reflection (ItemCatalog) — replacing the string->WeaponStats dictionary, mirroring BaseCreature. World stays a thin facade: all combat/skill/death logic lives in CombatSystem; World only delegates. Adds a hard gate in CLAUDE.md against putting logic in World, plus a one-type-per-file rule. Hardened token validation to pin HS256.