feat: status effects (poison/burn), boss patterns, new relics

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 14:49:55 +09:00
parent 533e460968
commit d3d7e2a76a
8 changed files with 158 additions and 2 deletions

View File

@@ -114,6 +114,16 @@ func (s *GameSession) spawnBoss() {
mt = entity.MonsterBoss5
}
boss := entity.NewMonster(mt, s.state.FloorNum)
switch mt {
case entity.MonsterBoss5:
boss.Pattern = entity.PatternAoE
case entity.MonsterBoss10:
boss.Pattern = entity.PatternPoison
case entity.MonsterBoss15:
boss.Pattern = entity.PatternBurn
case entity.MonsterBoss20:
boss.Pattern = entity.PatternHeal
}
if s.state.SoloMode {
boss.HP = boss.HP / 2
boss.MaxHP = boss.HP

View File

@@ -220,6 +220,8 @@ func (s *GameSession) GetState() GameState {
copy(cp.Inventory, p.Inventory)
cp.Relics = make([]entity.Relic, len(p.Relics))
copy(cp.Relics, p.Relics)
cp.Effects = make([]entity.ActiveEffect, len(p.Effects))
copy(cp.Effects, p.Effects)
players[i] = &cp
}

View File

@@ -73,6 +73,19 @@ collecting:
}
func (s *GameSession) resolvePlayerActions() {
// Tick status effects
for _, p := range s.state.Players {
if !p.IsOut() {
msgs := p.TickEffects()
for _, msg := range msgs {
s.addLog(msg)
}
if p.IsDead() {
s.addLog(fmt.Sprintf("☠ %s has fallen!", p.Name))
}
}
}
var intents []combat.AttackIntent
var intentOwners []string // track who owns each intent
@@ -299,6 +312,9 @@ func (s *GameSession) grantBossRelic() {
{Name: "Power Amulet", Effect: entity.RelicATKBoost, Value: 3, Price: 120},
{Name: "Iron Ward", Effect: entity.RelicDEFBoost, Value: 2, Price: 100},
{Name: "Gold Charm", Effect: entity.RelicGoldBoost, Value: 5, Price: 150},
{Name: "Antidote Charm", Effect: entity.RelicPoisonImmunity, Value: 0, Price: 100},
{Name: "Flame Guard", Effect: entity.RelicBurnResist, Value: 0, Price: 120},
{Name: "Life Siphon", Effect: entity.RelicLifeSteal, Value: 10, Price: 150},
}
for _, p := range s.state.Players {
if !p.IsOut() {
@@ -329,6 +345,32 @@ func (s *GameSession) resolveMonsterActions() {
}
}
}
if m.IsBoss {
// Boss special pattern
switch m.Pattern {
case entity.PatternPoison:
for _, p := range s.state.Players {
if !p.IsOut() {
p.AddEffect(entity.ActiveEffect{Type: entity.StatusPoison, Duration: 3, Value: 5})
s.addLog(fmt.Sprintf("%s poisons %s!", m.Name, p.Name))
}
}
case entity.PatternBurn:
for _, p := range s.state.Players {
if !p.IsOut() {
p.AddEffect(entity.ActiveEffect{Type: entity.StatusBurn, Duration: 2, Value: 8})
s.addLog(fmt.Sprintf("%s burns %s!", m.Name, p.Name))
}
}
case entity.PatternHeal:
healAmt := m.MaxHP / 10
m.HP += healAmt
if m.HP > m.MaxHP {
m.HP = m.MaxHP
}
s.addLog(fmt.Sprintf("%s regenerates %d HP!", m.Name, healAmt))
}
}
} else {
if targetIdx >= 0 && targetIdx < len(s.state.Players) {
p := s.state.Players[targetIdx]