From cd2013a9173146db170ba859c047b078b6f203b4 Mon Sep 17 00:00:00 2001 From: tolelom <98kimsungmin@naver.com> Date: Tue, 24 Mar 2026 10:47:38 +0900 Subject: [PATCH] feat: multiplayer flee marks player as out for current combat Co-Authored-By: Claude Sonnet 4.6 --- entity/player.go | 5 +++++ game/turn.go | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/entity/player.go b/entity/player.go index 2f597c3..5a71cf4 100644 --- a/entity/player.go +++ b/entity/player.go @@ -34,6 +34,7 @@ type Player struct { Inventory []Item Relics []Relic Dead bool + Fled bool } func NewPlayer(name string, class Class) *Player { @@ -67,6 +68,10 @@ func (p *Player) IsDead() bool { return p.Dead } +func (p *Player) IsOut() bool { + return p.Dead || p.Fled +} + func (p *Player) Revive(hpPercent float64) { p.Dead = false p.HP = int(float64(p.MaxHP) * hpPercent) diff --git a/game/turn.go b/game/turn.go index 2e649a5..2064f56 100644 --- a/game/turn.go +++ b/game/turn.go @@ -20,7 +20,7 @@ func (s *GameSession) RunTurn() { s.actions = make(map[string]PlayerAction) aliveCount := 0 for _, p := range s.state.Players { - if !p.IsDead() { + if !p.IsOut() { aliveCount++ } } @@ -52,7 +52,7 @@ resolve: // Default action for players who didn't submit: Wait for _, p := range s.state.Players { - if !p.IsDead() { + if !p.IsOut() { if _, ok := s.actions[p.Name]; !ok { s.actions[p.Name] = PlayerAction{Type: ActionWait} } @@ -76,7 +76,7 @@ func (s *GameSession) resolvePlayerActions() { } for _, p := range s.state.Players { - if p.IsDead() { + if p.IsOut() { continue } action, ok := s.actions[p.Name] @@ -149,6 +149,7 @@ func (s *GameSession) resolvePlayerActions() { s.state.Phase = PhaseExploring return } + p.Fled = true } else { s.addLog(fmt.Sprintf("%s failed to flee!", p.Name)) } @@ -157,6 +158,24 @@ func (s *GameSession) resolvePlayerActions() { } } + // Check if all alive players have fled + allFled := true + for _, p := range s.state.Players { + if !p.IsDead() && !p.Fled { + allFled = false + break + } + } + if allFled && !s.state.SoloMode { + s.state.Phase = PhaseExploring + s.state.Floor.Rooms[s.state.Floor.CurrentRoom].Cleared = true + s.addLog("All players fled!") + for _, p := range s.state.Players { + p.Fled = false + } + return + } + if len(intents) > 0 && len(s.state.Monsters) > 0 { results := combat.ResolveAttacks(intents, s.state.Monsters) for i, r := range results { @@ -186,7 +205,7 @@ func (s *GameSession) resolvePlayerActions() { goldReward = 15 } for _, p := range s.state.Players { - if !p.IsDead() { + if !p.IsOut() { bonus := 0 for _, r := range p.Relics { if r.Effect == entity.RelicGoldBoost { @@ -220,6 +239,9 @@ func (s *GameSession) resolvePlayerActions() { if len(s.state.Monsters) == 0 { s.state.Floor.Rooms[s.state.Floor.CurrentRoom].Cleared = true s.addLog("Room cleared!") + for _, p := range s.state.Players { + p.Fled = false + } if s.state.Floor.Rooms[s.state.Floor.CurrentRoom].Type == dungeon.RoomBoss { s.advanceFloor() } else { @@ -245,6 +267,7 @@ func (s *GameSession) advanceFloor() { if p.IsDead() { p.Revive(0.30) } + p.Fled = false } } @@ -256,7 +279,7 @@ func (s *GameSession) grantBossRelic() { {Name: "Gold Charm", Effect: entity.RelicGoldBoost, Value: 5, Price: 150}, } for _, p := range s.state.Players { - if !p.IsDead() { + if !p.IsOut() { r := relics[rand.Intn(len(relics))] p.Relics = append(p.Relics, r) s.addLog(fmt.Sprintf("%s obtained relic: %s", p.Name, r.Name)) @@ -275,7 +298,7 @@ func (s *GameSession) resolveMonsterActions() { targetIdx, isAoE := combat.MonsterAI(m, s.state.Players, s.state.CombatTurn) if isAoE { for _, p := range s.state.Players { - if !p.IsDead() { + if !p.IsOut() { dmg := combat.CalcDamage(m.ATK, p.EffectiveDEF(), 0.5) p.TakeDamage(dmg) s.addLog(fmt.Sprintf("%s AoE hits %s for %d dmg", m.Name, p.Name, dmg)) @@ -284,7 +307,7 @@ func (s *GameSession) resolveMonsterActions() { } else { if targetIdx >= 0 && targetIdx < len(s.state.Players) { p := s.state.Players[targetIdx] - if !p.IsDead() { + if !p.IsOut() { dmg := combat.CalcDamage(m.ATK, p.EffectiveDEF(), 1.0) p.TakeDamage(dmg) s.addLog(fmt.Sprintf("%s attacks %s for %d dmg", m.Name, p.Name, dmg)) @@ -296,7 +319,7 @@ func (s *GameSession) resolveMonsterActions() { allPlayersDead := true for _, p := range s.state.Players { - if !p.IsDead() { + if !p.IsOut() { allPlayersDead = false break }