feat: multiplayer flee marks player as out for current combat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ type Player struct {
|
|||||||
Inventory []Item
|
Inventory []Item
|
||||||
Relics []Relic
|
Relics []Relic
|
||||||
Dead bool
|
Dead bool
|
||||||
|
Fled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlayer(name string, class Class) *Player {
|
func NewPlayer(name string, class Class) *Player {
|
||||||
@@ -67,6 +68,10 @@ func (p *Player) IsDead() bool {
|
|||||||
return p.Dead
|
return p.Dead
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Player) IsOut() bool {
|
||||||
|
return p.Dead || p.Fled
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Player) Revive(hpPercent float64) {
|
func (p *Player) Revive(hpPercent float64) {
|
||||||
p.Dead = false
|
p.Dead = false
|
||||||
p.HP = int(float64(p.MaxHP) * hpPercent)
|
p.HP = int(float64(p.MaxHP) * hpPercent)
|
||||||
|
|||||||
39
game/turn.go
39
game/turn.go
@@ -20,7 +20,7 @@ func (s *GameSession) RunTurn() {
|
|||||||
s.actions = make(map[string]PlayerAction)
|
s.actions = make(map[string]PlayerAction)
|
||||||
aliveCount := 0
|
aliveCount := 0
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if !p.IsDead() {
|
if !p.IsOut() {
|
||||||
aliveCount++
|
aliveCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ resolve:
|
|||||||
|
|
||||||
// Default action for players who didn't submit: Wait
|
// Default action for players who didn't submit: Wait
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if !p.IsDead() {
|
if !p.IsOut() {
|
||||||
if _, ok := s.actions[p.Name]; !ok {
|
if _, ok := s.actions[p.Name]; !ok {
|
||||||
s.actions[p.Name] = PlayerAction{Type: ActionWait}
|
s.actions[p.Name] = PlayerAction{Type: ActionWait}
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ func (s *GameSession) resolvePlayerActions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if p.IsDead() {
|
if p.IsOut() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
action, ok := s.actions[p.Name]
|
action, ok := s.actions[p.Name]
|
||||||
@@ -149,6 +149,7 @@ func (s *GameSession) resolvePlayerActions() {
|
|||||||
s.state.Phase = PhaseExploring
|
s.state.Phase = PhaseExploring
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
p.Fled = true
|
||||||
} else {
|
} else {
|
||||||
s.addLog(fmt.Sprintf("%s failed to flee!", p.Name))
|
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 {
|
if len(intents) > 0 && len(s.state.Monsters) > 0 {
|
||||||
results := combat.ResolveAttacks(intents, s.state.Monsters)
|
results := combat.ResolveAttacks(intents, s.state.Monsters)
|
||||||
for i, r := range results {
|
for i, r := range results {
|
||||||
@@ -186,7 +205,7 @@ func (s *GameSession) resolvePlayerActions() {
|
|||||||
goldReward = 15
|
goldReward = 15
|
||||||
}
|
}
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if !p.IsDead() {
|
if !p.IsOut() {
|
||||||
bonus := 0
|
bonus := 0
|
||||||
for _, r := range p.Relics {
|
for _, r := range p.Relics {
|
||||||
if r.Effect == entity.RelicGoldBoost {
|
if r.Effect == entity.RelicGoldBoost {
|
||||||
@@ -220,6 +239,9 @@ func (s *GameSession) resolvePlayerActions() {
|
|||||||
if len(s.state.Monsters) == 0 {
|
if len(s.state.Monsters) == 0 {
|
||||||
s.state.Floor.Rooms[s.state.Floor.CurrentRoom].Cleared = true
|
s.state.Floor.Rooms[s.state.Floor.CurrentRoom].Cleared = true
|
||||||
s.addLog("Room cleared!")
|
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 {
|
if s.state.Floor.Rooms[s.state.Floor.CurrentRoom].Type == dungeon.RoomBoss {
|
||||||
s.advanceFloor()
|
s.advanceFloor()
|
||||||
} else {
|
} else {
|
||||||
@@ -245,6 +267,7 @@ func (s *GameSession) advanceFloor() {
|
|||||||
if p.IsDead() {
|
if p.IsDead() {
|
||||||
p.Revive(0.30)
|
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},
|
{Name: "Gold Charm", Effect: entity.RelicGoldBoost, Value: 5, Price: 150},
|
||||||
}
|
}
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if !p.IsDead() {
|
if !p.IsOut() {
|
||||||
r := relics[rand.Intn(len(relics))]
|
r := relics[rand.Intn(len(relics))]
|
||||||
p.Relics = append(p.Relics, r)
|
p.Relics = append(p.Relics, r)
|
||||||
s.addLog(fmt.Sprintf("%s obtained relic: %s", p.Name, r.Name))
|
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)
|
targetIdx, isAoE := combat.MonsterAI(m, s.state.Players, s.state.CombatTurn)
|
||||||
if isAoE {
|
if isAoE {
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if !p.IsDead() {
|
if !p.IsOut() {
|
||||||
dmg := combat.CalcDamage(m.ATK, p.EffectiveDEF(), 0.5)
|
dmg := combat.CalcDamage(m.ATK, p.EffectiveDEF(), 0.5)
|
||||||
p.TakeDamage(dmg)
|
p.TakeDamage(dmg)
|
||||||
s.addLog(fmt.Sprintf("%s AoE hits %s for %d dmg", m.Name, p.Name, 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 {
|
} else {
|
||||||
if targetIdx >= 0 && targetIdx < len(s.state.Players) {
|
if targetIdx >= 0 && targetIdx < len(s.state.Players) {
|
||||||
p := s.state.Players[targetIdx]
|
p := s.state.Players[targetIdx]
|
||||||
if !p.IsDead() {
|
if !p.IsOut() {
|
||||||
dmg := combat.CalcDamage(m.ATK, p.EffectiveDEF(), 1.0)
|
dmg := combat.CalcDamage(m.ATK, p.EffectiveDEF(), 1.0)
|
||||||
p.TakeDamage(dmg)
|
p.TakeDamage(dmg)
|
||||||
s.addLog(fmt.Sprintf("%s attacks %s for %d dmg", m.Name, p.Name, 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
|
allPlayersDead := true
|
||||||
for _, p := range s.state.Players {
|
for _, p := range s.state.Players {
|
||||||
if !p.IsDead() {
|
if !p.IsOut() {
|
||||||
allPlayersDead = false
|
allPlayersDead = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user