From 6e603b6ba18d851bc9085ea541c7bde145557314 Mon Sep 17 00:00:00 2001 From: JOY Date: Tue, 19 May 2026 09:27:59 +0700 Subject: [PATCH] feat: promote eight core character stats --- CHANGELOG.md | 13 ++--- ROADMAP.md | 4 +- .../Scripts/AI/AgentContextDto.cs | 3 ++ .../Scripts/AI/CharacterMemorySync.cs | 5 +- .../Scripts/AI/PrototypeAgentBrain.cs | 11 ++-- .../Scripts/Networking/NetworkPlayer.cs | 15 +++++- .../_SecondSpawn/Scripts/UI/HUDController.cs | 3 +- backend/nakama/modules/index.ts | 21 ++++++-- .../tests/supabase_custom_auth.test.mjs | 11 +++- docs/design/02-vertical-slice-spec.md | 2 +- docs/design/04-cultivation-system.md | 5 +- .../10-character-profile-agent-memory.md | 26 +++++---- docs/design/12-game-design-document.md | 18 ++++--- ...-character-stat-and-relationship-system.md | 54 +++++++++++-------- 14 files changed, 128 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 625c65c..44c94e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ versioned release tag yet, so entries are organized as pre-alpha snapshots. - Character-model taxonomy covering core stats, derived stats, social attributes, body presentation, identity fields, and multi-axis relationships for NPC-like Frames and player-inhabitable bodies. -- Character stat and relationship system GDD covering the six-stat MVP backend +- Character stat and relationship system GDD covering the eight-stat MVP backend contract, deferred stat candidates, secondary stat direction, presentation attributes, relationship axes, and reincarnation carryover boundaries. - Human-believable NPC agent design doc covering trait axes, relationship @@ -19,7 +19,7 @@ versioned release tag yet, so entries are organized as pre-alpha snapshots. - Unity `NetworkPlayer` now carries prototype level, combat stats, BodyTime, lifecycle, SECOND balance, reincarnation count, visual key, and agent-control state as networked fields. -- Prototype HUD now shows level, HP, energy, attack, defense, agility, +- Prototype HUD now shows level, HP, energy, attack, defense, dexterity, BodyTime, lifecycle, SECOND balance, and reincarnation count. - Unity `CharacterMemorySync` now applies Nakama profile body state onto the authoritative local player after profile load. @@ -182,10 +182,11 @@ versioned release tag yet, so entries are organized as pre-alpha snapshots. visible in Play Mode. - Nakama agent decisions now default to the `dos-ai` model on `api.dos.ai`; Claude aliases are not the default path for the prototype NPC brain. -- Nakama character stats now use the six canonical MVP core stats: - `strength`, `agility`, `endurance`, `perception`, `focus`, and `presence`. - Legacy `force`, `vitality`, and `resilience` fields remain as compatibility - aliases for the current Unity prototype. +- Nakama character stats now use the eight canonical MVP core stats: + `strength`, `dexterity`, `endurance`, `perception`, `focus`, `presence`, + `intelligence`, and `luck`. Legacy `force`, `agility`, `vitality`, and + `resilience` fields remain as compatibility aliases for the current Unity + prototype. - Removed the in-repo Second Spawn Go LLM adapter. Durable profile, soul, stats, memory, BodyTime, activity state, and model-backed intent validation now stay on the Nakama side of the backend boundary. diff --git a/ROADMAP.md b/ROADMAP.md index cfa444e..d1c2b3a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -76,7 +76,7 @@ Recommended views: AI offline control, agent workflow, and backend boundaries. - [x] Character-model taxonomy documented for core stats, secondary stats, social attributes, body presentation, identity, and multi-axis relationships. -- [x] Character stat and relationship system GDD added for the six-stat MVP +- [x] Character stat and relationship system GDD added for the eight-stat MVP backend contract, secondary stat direction, presentation attributes, and reincarnation carryover boundaries. - [x] Backend tests for Nakama runtime behavior and model-backed fallback. @@ -90,7 +90,7 @@ Recommended views: - [x] `ZoneTest_Hub` enters Play Mode with a Fusion-spawned local player. - [x] The spawned player has networked level, combat stats, BodyTime, lifecycle, SECOND balance, reincarnation count, visual key, and agent-control flag. -- [x] Unity prototype HUD shows level, HP, energy, attack, defense, agility, +- [x] Unity prototype HUD shows level, HP, energy, attack, defense, dexterity, BodyTime, lifecycle, SECOND balance, and reincarnation count. - [x] Unity prototype HUD shows synced agent runtime counters and recent activity rows from the Nakama body profile. diff --git a/Unity/Assets/_SecondSpawn/Scripts/AI/AgentContextDto.cs b/Unity/Assets/_SecondSpawn/Scripts/AI/AgentContextDto.cs index 69a05dc..1644aa9 100644 --- a/Unity/Assets/_SecondSpawn/Scripts/AI/AgentContextDto.cs +++ b/Unity/Assets/_SecondSpawn/Scripts/AI/AgentContextDto.cs @@ -141,8 +141,11 @@ public sealed class CharacterStatsDto public int endurance = 10; public int perception = 8; public int presence = 5; + public int intelligence = 8; + public int luck = 5; public int vitality = 10; public int force = 8; + public int dexterity = 8; public int agility = 8; public int focus = 8; public int resilience = 8; diff --git a/Unity/Assets/_SecondSpawn/Scripts/AI/CharacterMemorySync.cs b/Unity/Assets/_SecondSpawn/Scripts/AI/CharacterMemorySync.cs index 50a9cc7..930aa0e 100644 --- a/Unity/Assets/_SecondSpawn/Scripts/AI/CharacterMemorySync.cs +++ b/Unity/Assets/_SecondSpawn/Scripts/AI/CharacterMemorySync.cs @@ -231,15 +231,18 @@ private void ApplyStats(NetworkPlayer player, BodyProfileDto body) var time = body.time ?? new BodyTimeDto(); var account = _context?.player ?? new PlayerProfileDto(); var strength = ResolveStat(stats.strength, stats.force, 8); + var dexterity = ResolveStat(stats.dexterity, stats.agility, 8); var endurance = ResolveStat(stats.endurance, stats.vitality, 10); var resilience = ResolveStat(stats.resilience, endurance, 8); player.ApplyProfileStats( stats.level, endurance, strength, - stats.agility, + dexterity, stats.focus, resilience, + stats.intelligence, + stats.luck, stats.max_health, stats.max_energy, stats.attack_power, diff --git a/Unity/Assets/_SecondSpawn/Scripts/AI/PrototypeAgentBrain.cs b/Unity/Assets/_SecondSpawn/Scripts/AI/PrototypeAgentBrain.cs index c3f403b..53d0ab3 100644 --- a/Unity/Assets/_SecondSpawn/Scripts/AI/PrototypeAgentBrain.cs +++ b/Unity/Assets/_SecondSpawn/Scripts/AI/PrototypeAgentBrain.cs @@ -1034,13 +1034,18 @@ private void ApplyContextToPrototypeBody() var stats = body.stats; if (stats != null) { - _moveSpeed = Mathf.Max(0.1f, _baseMoveSpeed * CalculateAgilitySpeedMultiplier(stats.agility)); + _moveSpeed = Mathf.Max(0.1f, _baseMoveSpeed * CalculateDexteritySpeedMultiplier(ResolveStat(stats.dexterity, stats.agility, 8))); } } - private static float CalculateAgilitySpeedMultiplier(int agility) + private static int ResolveStat(int primary, int legacy, int fallback) { - return Mathf.Clamp(agility / 8f, 0.75f, 1.4f); + return primary > 0 ? primary : legacy > 0 ? legacy : fallback; + } + + private static float CalculateDexteritySpeedMultiplier(int dexterity) + { + return Mathf.Clamp(dexterity / 8f, 0.75f, 1.4f); } private void LogPhase(BrainPhase phase, string detail) diff --git a/Unity/Assets/_SecondSpawn/Scripts/Networking/NetworkPlayer.cs b/Unity/Assets/_SecondSpawn/Scripts/Networking/NetworkPlayer.cs index 9529316..e69abaa 100644 --- a/Unity/Assets/_SecondSpawn/Scripts/Networking/NetworkPlayer.cs +++ b/Unity/Assets/_SecondSpawn/Scripts/Networking/NetworkPlayer.cs @@ -26,9 +26,12 @@ public sealed class NetworkPlayer : NetworkBehaviour [Networked] public int Level { get; set; } [Networked] public int Vitality { get; set; } [Networked] public int Force { get; set; } + [Networked] public int Dexterity { get; set; } [Networked] public int Agility { get; set; } [Networked] public int Focus { get; set; } [Networked] public int Resilience { get; set; } + [Networked] public int Intelligence { get; set; } + [Networked] public int Luck { get; set; } [Networked] public int MaxHealth { get; set; } [Networked] public int MaxEnergy { get; set; } [Networked] public int AttackPower { get; set; } @@ -216,9 +219,11 @@ public void ApplyProfileStats( int level, int vitality, int force, - int agility, + int dexterity, int focus, int resilience, + int intelligence, + int luck, int maxHealth, int maxEnergy, int attackPower, @@ -246,9 +251,12 @@ public void ApplyProfileStats( Level = Mathf.Max(1, level); Vitality = Mathf.Clamp(vitality, 1, 999); Force = Mathf.Clamp(force, 1, 999); - Agility = Mathf.Clamp(agility, 1, 999); + Dexterity = Mathf.Clamp(dexterity, 1, 999); + Agility = Dexterity; Focus = Mathf.Clamp(focus, 1, 999); Resilience = Mathf.Clamp(resilience, 1, 999); + Intelligence = Mathf.Clamp(intelligence, 1, 999); + Luck = Mathf.Clamp(luck, 1, 999); MaxHealth = Mathf.Max(1, maxHealth); MaxEnergy = Mathf.Max(1, maxEnergy); AttackPower = Mathf.Max(0, attackPower); @@ -279,9 +287,12 @@ private void ApplyDefaultStats() Level = 1; Vitality = 10; Force = 8; + Dexterity = 8; Agility = 8; Focus = 8; Resilience = 8; + Intelligence = 8; + Luck = 5; MaxHealth = 100; MaxEnergy = 50; AttackPower = 10; diff --git a/Unity/Assets/_SecondSpawn/Scripts/UI/HUDController.cs b/Unity/Assets/_SecondSpawn/Scripts/UI/HUDController.cs index 5491783..a6ee9dd 100644 --- a/Unity/Assets/_SecondSpawn/Scripts/UI/HUDController.cs +++ b/Unity/Assets/_SecondSpawn/Scripts/UI/HUDController.cs @@ -114,7 +114,8 @@ private void DrawStats(NetworkPlayer player) GUILayout.Label($"Level {player.Level}", _labelStyle); GUILayout.Label($"HP {player.Hp:0}/{player.MaxHealth} | Energy {player.Stamina:0}/{player.MaxEnergy}", _labelStyle); - GUILayout.Label($"ATK {player.AttackPower} | DEF {player.DefensePower} | AGI {player.Agility}", _labelStyle); + GUILayout.Label($"ATK {player.AttackPower} | DEF {player.DefensePower} | DEX {player.Dexterity}", _labelStyle); + GUILayout.Label($"INT {player.Intelligence} | LUCK {player.Luck} | FOC {player.Focus}", _labelStyle); GUILayout.Label($"TIME {FormatSeconds(player.BodyTimeRemainingSeconds)} / {FormatSeconds(player.BodyTimeMaxSeconds)}", _labelStyle); GUILayout.Label($"Lifecycle {(player.IsBodyDead ? "dead" : "alive")} | Drain {player.BodyTimeDangerDrainRate}s/tick", _labelStyle); GUILayout.Label($"SECOND {FormatSeconds(player.SecondBalanceSeconds)} | Reincarnations {player.ReincarnationCount}", _labelStyle); diff --git a/backend/nakama/modules/index.ts b/backend/nakama/modules/index.ts index 3508d41..ff0c3c1 100644 --- a/backend/nakama/modules/index.ts +++ b/backend/nakama/modules/index.ts @@ -2575,11 +2575,14 @@ function defaultCharacterStats(): any { return { level: 1, strength: 8, + dexterity: 8, agility: 8, endurance: 10, perception: 8, focus: 8, presence: 5, + intelligence: 8, + luck: 5, vitality: 10, force: 8, resilience: 8, @@ -2593,19 +2596,24 @@ function defaultCharacterStats(): any { function normalizeStatsWithDefaults(stats: any, defaults: any): any { var base = normalizeStats(defaults || {}); var strength = clampNumber(numberOrDefault(firstDefined(stats.strength, stats.force), base.strength), 1, 9999); - var agility = clampNumber(numberOrDefault(stats.agility, base.agility), 1, 9999); + var dexterity = clampNumber(numberOrDefault(firstDefined(stats.dexterity, stats.agility), base.dexterity), 1, 9999); var endurance = clampNumber(numberOrDefault(firstDefined(stats.endurance, firstDefined(stats.vitality, stats.resilience)), base.endurance), 1, 9999); var perception = clampNumber(numberOrDefault(stats.perception, base.perception), 1, 9999); var focus = clampNumber(numberOrDefault(stats.focus, base.focus), 1, 9999); var presence = clampNumber(numberOrDefault(stats.presence, base.presence), 1, 9999); + var intelligence = clampNumber(numberOrDefault(stats.intelligence, base.intelligence), 1, 9999); + var luck = clampNumber(numberOrDefault(stats.luck, base.luck), 1, 9999); return { level: clampNumber(numberOrDefault(stats.level, base.level), 1, 100), strength: strength, - agility: agility, + dexterity: dexterity, + agility: dexterity, endurance: endurance, perception: perception, focus: focus, presence: presence, + intelligence: intelligence, + luck: luck, vitality: clampNumber(numberOrDefault(stats.vitality, endurance), 1, 9999), force: clampNumber(numberOrDefault(stats.force, strength), 1, 9999), resilience: clampNumber(numberOrDefault(stats.resilience, endurance), 1, 9999), @@ -2619,19 +2627,24 @@ function normalizeStatsWithDefaults(stats: any, defaults: any): any { function normalizeStats(stats: any): any { var defaults = defaultCharacterStats(); var strength = clampNumber(numberOrDefault(firstDefined(stats.strength, stats.force), defaults.strength), 1, 9999); - var agility = clampNumber(numberOrDefault(stats.agility, defaults.agility), 1, 9999); + var dexterity = clampNumber(numberOrDefault(firstDefined(stats.dexterity, stats.agility), defaults.dexterity), 1, 9999); var endurance = clampNumber(numberOrDefault(firstDefined(stats.endurance, firstDefined(stats.vitality, stats.resilience)), defaults.endurance), 1, 9999); var perception = clampNumber(numberOrDefault(stats.perception, defaults.perception), 1, 9999); var focus = clampNumber(numberOrDefault(stats.focus, defaults.focus), 1, 9999); var presence = clampNumber(numberOrDefault(stats.presence, defaults.presence), 1, 9999); + var intelligence = clampNumber(numberOrDefault(stats.intelligence, defaults.intelligence), 1, 9999); + var luck = clampNumber(numberOrDefault(stats.luck, defaults.luck), 1, 9999); return { level: clampNumber(numberOrDefault(stats.level, defaults.level), 1, 100), strength: strength, - agility: agility, + dexterity: dexterity, + agility: dexterity, endurance: endurance, perception: perception, focus: focus, presence: presence, + intelligence: intelligence, + luck: luck, vitality: clampNumber(numberOrDefault(stats.vitality, endurance), 1, 9999), force: clampNumber(numberOrDefault(stats.force, strength), 1, 9999), resilience: clampNumber(numberOrDefault(stats.resilience, endurance), 1, 9999), diff --git a/backend/nakama/tests/supabase_custom_auth.test.mjs b/backend/nakama/tests/supabase_custom_auth.test.mjs index 674a14f..7a5c58c 100644 --- a/backend/nakama/tests/supabase_custom_auth.test.mjs +++ b/backend/nakama/tests/supabase_custom_auth.test.mjs @@ -417,9 +417,12 @@ assert.equal(profile.body.stats.level, 1); assert.equal(profile.body.stats.strength, 10); assert.equal(profile.body.stats.endurance, 9); assert.equal(profile.body.stats.vitality, 9); +assert.equal(profile.body.stats.dexterity, 9); assert.equal(profile.body.stats.agility, 9); assert.equal(profile.body.stats.perception, 8); assert.equal(profile.body.stats.presence, 5); +assert.equal(profile.body.stats.intelligence, 8); +assert.equal(profile.body.stats.luck, 5); assert.equal(profile.body.stats.max_health, 100); assert.equal(profile.body.stats.attack_power, 12); assert.equal(profile.body.time.remaining_seconds, 86400); @@ -581,7 +584,7 @@ const npcProfile = JSON.parse(harness.registeredRpcs.get("secondspawn_actor_prof actor_id: "npc-guide", actor_type: "npc", display_name: "Mira Guide", - stats: { level: 0, strength: 12, endurance: 14, agility: 10, perception: 11, focus: 9, presence: 8, max_health: 0, max_energy: 0, attack_power: 0 }, + stats: { level: 0, strength: 12, endurance: 14, dexterity: 10, perception: 11, focus: 9, presence: 8, intelligence: 13, luck: 4, max_health: 0, max_energy: 0, attack_power: 0 }, characteristics: { curiosity: 8, sociability: 9 }, time: { remaining_seconds: 0, max_seconds: 0, danger_drain_rate: 0 }, soul: { core_drive: "help new bodies survive the hub" } @@ -596,6 +599,8 @@ assert.equal(npcProfile.body.soul.core_drive, "help new bodies survive the hub") assert.equal(npcProfile.body.stats.level, 1); assert.equal(npcProfile.body.stats.strength, 12); assert.equal(npcProfile.body.stats.endurance, 14); +assert.equal(npcProfile.body.stats.dexterity, 10); +assert.equal(npcProfile.body.stats.agility, 10); assert.equal(npcProfile.body.stats.max_health, 1); assert.equal(npcProfile.body.stats.max_energy, 0); assert.equal(npcProfile.body.stats.attack_power, 0); @@ -604,6 +609,8 @@ assert.equal(npcProfile.body.stats.vitality, 14); assert.equal(npcProfile.body.stats.resilience, 14); assert.equal(npcProfile.body.stats.perception, 11); assert.equal(npcProfile.body.stats.presence, 8); +assert.equal(npcProfile.body.stats.intelligence, 13); +assert.equal(npcProfile.body.stats.luck, 4); assert.equal(npcProfile.body.characteristics.sociability, 9); assert.equal(npcProfile.body.time.remaining_seconds, 0); assert.equal(npcProfile.body.time.max_seconds, 1); @@ -637,6 +644,8 @@ assert.equal(permanentNpcProfile.body.stats.strength, 6); assert.equal(permanentNpcProfile.body.stats.endurance, 10); assert.equal(permanentNpcProfile.body.stats.perception, 8); assert.equal(permanentNpcProfile.body.stats.presence, 5); +assert.equal(permanentNpcProfile.body.stats.intelligence, 8); +assert.equal(permanentNpcProfile.body.stats.luck, 5); assert.equal(permanentNpcProfile.body.characteristics.discipline, 9); assert.equal(permanentNpcProfile.body.soul.name, "Clinic-0819 Craft"); assert.equal(permanentNpcProfile.memory[0].id, "memory-repair-bench"); diff --git a/docs/design/02-vertical-slice-spec.md b/docs/design/02-vertical-slice-spec.md index f91ad9e..90577e3 100644 --- a/docs/design/02-vertical-slice-spec.md +++ b/docs/design/02-vertical-slice-spec.md @@ -45,7 +45,7 @@ Already implemented: - The spawned player has networked level, combat stats, prototype `BodyTime` / TIME, lifecycle, SECOND balance, reincarnation count, visual key, and agent-control state. -- Prototype HUD displays level, HP, energy, attack, defense, agility, +- Prototype HUD displays level, HP, energy, attack, defense, dexterity, prototype `BodyTime` / TIME, lifecycle, SECOND balance, and reincarnation count. - Nakama profile bootstrap persists player profile, current body, stats, traits, soul, memory, agent policy, runtime, activity, prototype `BodyTime` / TIME, diff --git a/docs/design/04-cultivation-system.md b/docs/design/04-cultivation-system.md index 2da27e0..bcf4693 100644 --- a/docs/design/04-cultivation-system.md +++ b/docs/design/04-cultivation-system.md @@ -17,8 +17,9 @@ or Cultivation Master progression in the current vertical slice. The slice uses: - `CharacterStats.level` as the baseline progression value. -- Body-bound stats such as strength, agility, endurance, perception, focus, - presence, max health, max energy, attack power, and defense power. +- Body-bound stats such as strength, dexterity, endurance, perception, focus, + presence, intelligence, luck, max health, max energy, attack power, and + defense power. - TIME / SECOND and reincarnation as the signature systemic loop. Advanced body or soul progression remains a future design space, but it needs a diff --git a/docs/design/10-character-profile-agent-memory.md b/docs/design/10-character-profile-agent-memory.md index cc33cf2..7dde08f 100644 --- a/docs/design/10-character-profile-agent-memory.md +++ b/docs/design/10-character-profile-agent-memory.md @@ -238,13 +238,16 @@ Current prototype runtime contract: | ---- | ---- | | `level` | Local body level | | `strength` | Physical power, melee force, carry, heavy weapons, and forceful body actions | -| `agility` | Current movement and attack cadence prototype stat | +| `dexterity` | Movement quality, handling, precision, attack cadence, and dodge scaling | | `endurance` | Health, energy reserve, body durability, recovery, and BodyTime efficiency hooks | | `perception` | Sensor quality, threat detection, stealth detection, weak-point read, and social or environmental cue input | | `focus` | Current energy and ability-use prototype stat | | `presence` | Active social pressure, confidence, command weight, negotiation posture, and intimidation attempts | +| `intelligence` | Technical literacy, planning surface, analysis, and system understanding | +| `luck` | Strictly capped variance for fortunate openings and backend-approved rolls | | `vitality` | Legacy compatibility alias for endurance-oriented health scaling | | `force` | Legacy compatibility alias for strength-oriented physical power | +| `agility` | Legacy compatibility alias for dexterity-oriented movement | | `resilience` | Legacy compatibility alias for endurance-oriented mitigation | | `max_health` | Current derived or cached health cap | | `max_energy` | Current derived or cached energy cap | @@ -252,9 +255,9 @@ Current prototype runtime contract: | `defense_power` | Current derived or cached defense output | These keys are implemented today by the gateway, Nakama runtime, and Unity -prototype HUD. The six core stats are the canonical backend contract. The older -serialized keys remain in runtime payloads as aliases until the Unity networked -prototype stats are renamed in a coordinated compatibility pass. +prototype HUD. The eight core stats are the canonical backend contract. The +older serialized keys remain in runtime payloads as aliases until the Unity +networked prototype stats are renamed in a coordinated compatibility pass. See [14-character-stat-and-relationship-system.md](14-character-stat-and-relationship-system.md) for the system-level stat, secondary stat, presentation, and relationship @@ -266,11 +269,13 @@ MVP core stat taxonomy: | ---- | ---- | | `level` | Local body level | | `strength` | Physical power, melee force, carry, heavy weapons, and forceful body actions | -| `agility` | Movement, handling, precision, attack cadence, and dodge scaling | +| `dexterity` | Movement, handling, precision, attack cadence, and dodge scaling | | `endurance` | Health, energy reserve, body durability, recovery, and BodyTime efficiency hooks | | `perception` | Sensor quality, threat detection, stealth detection, weak-point read, and social or environmental cue input | | `focus` | Concentration, panic resistance, noise resistance, status pressure, and agent instruction stability | | `presence` | Active social influence such as persuasion, negotiation, leadership, command weight, and intimidation attempts | +| `intelligence` | Technical literacy, planning surface, analysis, crafting, hacking, and system understanding | +| `luck` | Strictly capped variance for fortunate openings, crit variance hooks, salvage bias, and backend-approved rolls | BodyTime is not a primary stat. It is a lifecycle and economy resource that may later read endurance, injuries, hazards, and stress when computing drains or @@ -335,11 +340,10 @@ Design notes: mechanics. - `focus` must never be connected to prompt-injection defense. Security and moderation are harness constants, not stats. -- Deferred candidate stats such as `intelligence`, `charisma`, `luck`, and - `dexterity` are not part of the MVP backend contract. If added later, they - must remain server-owned and must never grant new authority. -- `luck`, if revived, must never mint loot, TIME, or SECOND directly. It can - only bias backend-approved rolls inside strict caps. +- `intelligence` must never make the model smarter or grant new authority. It + can only affect server-approved technical actions and rolls inside policy. +- `luck` must never mint loot, TIME, or SECOND directly. It can only bias + backend-approved rolls inside strict caps. --- @@ -689,7 +693,7 @@ Implemented surfaces: capability flags onto the authoritative local `NetworkPlayer`. - The current player prototype starts at level 1 with stats selected from the server-owned body archetype pool instead of one fixed stat line. -- The prototype HUD shows level, HP, energy, attack, defense, agility, +- The prototype HUD shows level, HP, energy, attack, defense, dexterity, prototype `BodyTime` / TIME, lifecycle, SECOND balance, and reincarnation count. - The current prototype account reserve starts with 604800 SECOND seconds and reincarnation costs 432000 SECOND seconds. diff --git a/docs/design/12-game-design-document.md b/docs/design/12-game-design-document.md index 76194f5..576b423 100644 --- a/docs/design/12-game-design-document.md +++ b/docs/design/12-game-design-document.md @@ -54,7 +54,7 @@ promise that the same UI or tuning will ship. | Area | Current State | | ---- | ---- | | Unity scene | `ZoneTest_Hub` can enter Play Mode and spawn a Fusion local player. | -| Player visible stats | The prototype HUD shows level, HP, energy, attack, defense, agility, prototype `BodyTime` / TIME, lifecycle, SECOND balance, and reincarnation count. | +| Player visible stats | The prototype HUD shows level, HP, energy, attack, defense, dexterity, prototype `BodyTime` / TIME, lifecycle, SECOND balance, and reincarnation count. | | Player profile sync | Unity loads the Nakama profile and applies current-body stats, prototype `BodyTime` / TIME, lifecycle, SECOND balance, reincarnation count, and visual key to the authoritative local `NetworkPlayer`. | | Default player body | New profiles start at level 1 with server-selected stats from the prototype body archetype pool. | | TIME loop | Nakama supports prototype earn, spend, drain, duplicate-earn cooldown, zero-time death, and activity logging. Current implementation field names still use `BodyTime`. | @@ -411,16 +411,18 @@ mood or stress context, body presentation data, and validated action surface. Se Target character-model taxonomy: -The MVP backend uses six canonical body-bound core stats: `strength`, `agility`, -`endurance`, `perception`, `focus`, and `presence`. The older serialized keys -`vitality`, `force`, and `resilience` remain compatibility aliases until the -Unity networked prototype stats are renamed safely. See +The MVP backend uses eight canonical body-bound core stats: `strength`, +`dexterity`, `endurance`, `perception`, `focus`, `presence`, `intelligence`, +and `luck`. The older serialized keys `vitality`, `force`, `agility`, and +`resilience` remain compatibility aliases until the Unity networked prototype +stats are renamed safely. See [14-character-stat-and-relationship-system.md](14-character-stat-and-relationship-system.md) for the detailed stat, secondary stat, presentation, and relationship baseline. -- Core stats: body-bound gameplay numbers such as strength, agility, endurance, - perception, focus, and presence. Do not add wisdom as a core stat and do not - expose accuracy as a player-facing stat for MVP. +- Core stats: body-bound gameplay numbers such as strength, dexterity, + endurance, perception, focus, presence, intelligence, and luck. Do not add + wisdom as a core stat and do not expose accuracy as a player-facing stat for + MVP. - Secondary stats: derived gameplay values such as HP, energy, attack power, skill power, armor rating, five elemental resistance ratings, dodge rating, dodge chance, crit chance, crit damage, attack speed, move speed, cooldown diff --git a/docs/design/14-character-stat-and-relationship-system.md b/docs/design/14-character-stat-and-relationship-system.md index d2c572e..7f09360 100644 --- a/docs/design/14-character-stat-and-relationship-system.md +++ b/docs/design/14-character-stat-and-relationship-system.md @@ -48,25 +48,30 @@ authority. It is a design contract, not a final combat spreadsheet. ## Current Source of Truth -The MVP backend uses six canonical body-bound core stats: +The MVP backend uses eight canonical body-bound core stats: - `strength` -- `agility` +- `dexterity` - `endurance` - `perception` - `focus` - `presence` +- `intelligence` +- `luck` Older serialized prototype fields remain compatibility aliases until Unity networked stats are renamed safely: - `force` +- `agility` - `vitality` - `resilience` -The broader brainstorm candidates `intelligence`, `charisma`, `luck`, and -`dexterity` are not current MVP backend contract fields. They are documented -below as deferred candidates so the design discussion is not lost. +`wisdom` is intentionally not a core stat. The design treats wisdom-like +reading, judgment, and awareness as a mix of `perception`, `focus`, +`SoulProfile`, `CharacterTraits`, `FrameMemory`, and `RelationshipLedger`. +`charisma` remains folded into `presence` for MVP, and `appeal` remains a +presentation attribute, not a core stat. --- @@ -74,7 +79,7 @@ below as deferred candidates so the design discussion is not lost. | Layer | Examples | Authority | | ---- | ---- | ---- | -| Core Stats | `strength`, `agility`, `endurance`, `perception`, `focus`, `presence` | Game backend, then Fusion server for live combat | +| Core Stats | `strength`, `dexterity`, `endurance`, `perception`, `focus`, `presence`, `intelligence`, `luck` | Game backend, then Fusion server for live combat | | Secondary Stats | HP, energy, attack power, armor, elemental resistance, dodge, crit | Derived or cached by backend and server simulation | | Social Attributes | Appeal band, reputation, faction standing | Backend-owned profile and presentation data | | Body Presentation | Visual tags, intimidation tags, style, voice profile | Backend-owned, Unity-rendered | @@ -94,12 +99,15 @@ The current prototype runtime should keep these fields stable: | ---- | ---- | ---- | | `level` | integer | Current body level, not durable soul level | | `strength` | integer | Canonical core stat | -| `agility` | integer | Canonical core stat | +| `dexterity` | integer | Canonical core stat | | `endurance` | integer | Canonical core stat | | `perception` | integer | Canonical core stat | | `focus` | integer | Canonical core stat | | `presence` | integer | Canonical core stat | +| `intelligence` | integer | Canonical core stat | +| `luck` | integer | Canonical core stat | | `force` | integer | Legacy alias for prototype compatibility | +| `agility` | integer | Legacy alias for prototype compatibility | | `vitality` | integer | Legacy alias for prototype compatibility | | `resilience` | integer | Legacy alias for prototype compatibility | | `max_health` | integer | Derived or cached | @@ -107,8 +115,8 @@ The current prototype runtime should keep these fields stable: | `attack_power` | integer | Derived or cached | | `defense_power` | integer | Derived or cached | -New gameplay systems should read the canonical six. Legacy aliases should only -exist at compatibility boundaries. +New gameplay systems should read the canonical eight. Legacy aliases should +only exist at compatibility boundaries. --- @@ -117,11 +125,13 @@ exist at compatibility boundaries. | Stat | Meaning | Main Use | | ---- | ---- | ---- | | `strength` | Physical output, heavy weapon force, carry capacity, brute impact | Melee damage, stagger pressure, heavy tool use | -| `agility` | Movement quality, handling, reaction, attack cadence, dodge scaling | Move speed, dodge rating, attack speed hooks | +| `dexterity` | Movement quality, handling, reaction, attack cadence, dodge scaling | Move speed, dodge rating, attack speed hooks | | `endurance` | Body durability, recovery, energy reserve, survival tolerance | HP, energy, recovery, BodyTime efficiency hooks | -| `perception` | Sensor quality and awareness input, not LLM intelligence | Detection, weak-point reads, social cue input, threat awareness | +| `perception` | Sensor quality, awareness input, and wisdom-like reading of the world | Detection, weak-point reads, social cue input, threat awareness | | `focus` | Concentration, panic resistance, instruction stability, pressure tolerance | Channeling, interruption resistance, agent consistency under stress | | `presence` | Active social force and command weight | Persuasion, negotiation, leadership, intimidation, crowd effect hooks | +| `intelligence` | Reasoning surface, technical literacy, planning, and system understanding | Hacking, crafting, analysis, tool use checks, tactical options | +| `luck` | Controlled variance and fortunate openings | Rare event bias, crit variance hooks, salvage roll bias, strict server-capped outcomes | ### Why Not Wisdom @@ -144,12 +154,9 @@ contract without a migration and balance pass. | Candidate | Current MVP Placement | Revisit When | | ---- | ---- | ---- | -| `intelligence` | Represented through profession, skill, memory, and agent context, not body core stats | Technical builds need a readable stat for hacking, crafting, analysis, or device use | | `charisma` | Folded into `presence` | Social builds need a clear split between influence, command, intimidation, and charm | -| `luck` | Deferred | Loot, crit variance, rare events, and TIME rewards need a server-owned variance stat with strict caps | -| `dexterity` | Folded into `agility` | Precision weapons, finesse tools, or handling builds need separation from raw movement | -If `luck` is added later, it must never mint loot, TIME, or SECOND directly. It +`luck` is a core stat, but it must never mint loot, TIME, or SECOND directly. It can only bias backend-approved rolls inside explicit caps. --- @@ -374,10 +381,13 @@ Rules: - `focus` must never weaken prompt-injection defense. - `presence` and `appeal` must never bypass consent, moderation, or faction rules. -- `perception` controls what context is available, not how intelligent the - model is. +- `perception` controls what sensory, social, and environmental context is + available. +- `intelligence` controls technical and tactical options inside server-approved + checks. It does not make the model smarter or grant new authority. - A stronger LLM provider must not turn a low-perception Frame into an omniscient character. +- `luck` can only bias server-approved rolls inside strict caps. - Tool access lives in `AgentPolicy` and server validation, not stats. - Memory and relationship writes are accepted only through backend rules. @@ -387,7 +397,7 @@ Rules: For the vertical slice: -- Ship the canonical six core stats. +- Ship the canonical eight core stats. - Keep legacy aliases only at compatibility boundaries. - Use existing derived fields: `max_health`, `max_energy`, `attack_power`, and `defense_power`. @@ -397,8 +407,9 @@ For the vertical slice: `respect`, `debt`, and `familiarity`. - Add `appeal_band` and simple presentation tags when the body profile schema is migrated. -- Do not add `luck`, `charisma`, `intelligence`, or `dexterity` as MVP backend - contract fields. +- Keep `wisdom` out of MVP because `perception` covers the useful gameplay + portion. +- Keep `charisma` folded into `presence` for MVP. --- @@ -422,7 +433,8 @@ For the vertical slice: - Should `presence` remain the single social core stat, or should a future system split it into `presence` and `charisma`? -- Should `luck` exist at all, given economy, loot, TIME, and SECOND risk? +- Which `luck` effects are allowed without damaging loot, TIME, and SECOND + balance? - Which relationship axes survive reincarnation, and how much decay should apply? - Should Appeal be visible in player-facing UI, debug-only, or only used for