fix: game balance — gold scaling, solo DEF, floor-scaled items, healer targeting, AI fallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 11:17:23 +09:00
parent ee9aec0b32
commit 01edb488f7
3 changed files with 65 additions and 12 deletions

View File

@@ -97,14 +97,17 @@ func MonsterAI(m *entity.Monster, players []*entity.Player, turnNumber int) (tar
}
if rand.Float64() < 0.3 {
minHP := int(^uint(0) >> 1)
minIdx := 0
minIdx := -1
for i, p := range players {
if !p.IsDead() && p.HP < minHP {
minHP = p.HP
minIdx = i
}
}
return minIdx, false
if minIdx >= 0 {
return minIdx, false
}
// Fall through to default targeting if no alive player found
}
for i, p := range players {
if !p.IsDead() {

View File

@@ -88,6 +88,7 @@ func (s *GameSession) spawnMonsters() {
m.HP = 1
}
m.MaxHP = m.HP
m.DEF = m.DEF / 2
}
s.state.Monsters[i] = m
}
@@ -111,21 +112,25 @@ func (s *GameSession) spawnBoss() {
if s.state.SoloMode {
boss.HP = boss.HP / 2
boss.MaxHP = boss.HP
boss.DEF = boss.DEF / 2
}
s.state.Monsters = []*entity.Monster{boss}
}
func (s *GameSession) grantTreasure() {
floor := s.state.FloorNum
for _, p := range s.state.Players {
if rand.Float64() < 0.5 {
bonus := 3 + rand.Intn(6) + floor/3
item := entity.Item{
Name: "Iron Sword", Type: entity.ItemWeapon, Bonus: 3 + rand.Intn(6),
Name: weaponName(floor), Type: entity.ItemWeapon, Bonus: bonus,
}
p.Inventory = append(p.Inventory, item)
s.addLog(fmt.Sprintf("%s found %s (ATK+%d)", p.Name, item.Name, item.Bonus))
} else {
bonus := 2 + rand.Intn(4) + floor/4
item := entity.Item{
Name: "Iron Shield", Type: entity.ItemArmor, Bonus: 2 + rand.Intn(4),
Name: armorName(floor), Type: entity.ItemArmor, Bonus: bonus,
}
p.Inventory = append(p.Inventory, item)
s.addLog(fmt.Sprintf("%s found %s (DEF+%d)", p.Name, item.Name, item.Bonus))
@@ -134,10 +139,48 @@ func (s *GameSession) grantTreasure() {
}
func (s *GameSession) generateShopItems() {
floor := s.state.FloorNum
// Weapon bonus scales: base 3-8 + floor/3
weaponBonus := 3 + rand.Intn(6) + floor/3
// Armor bonus scales: base 2-5 + floor/4
armorBonus := 2 + rand.Intn(4) + floor/4
// Prices scale with power
weaponPrice := 40 + weaponBonus*5
armorPrice := 30 + armorBonus*5
// Potion heals more on higher floors
potionHeal := 30 + floor
potionPrice := 20 + floor/2
s.state.ShopItems = []entity.Item{
{Name: "HP Potion", Type: entity.ItemConsumable, Bonus: 30, Price: 20},
{Name: "Iron Sword", Type: entity.ItemWeapon, Bonus: 3 + rand.Intn(6), Price: 40 + rand.Intn(41)},
{Name: "Iron Shield", Type: entity.ItemArmor, Bonus: 2 + rand.Intn(4), Price: 30 + rand.Intn(31)},
{Name: "HP Potion", Type: entity.ItemConsumable, Bonus: potionHeal, Price: potionPrice},
{Name: weaponName(floor), Type: entity.ItemWeapon, Bonus: weaponBonus, Price: weaponPrice},
{Name: armorName(floor), Type: entity.ItemArmor, Bonus: armorBonus, Price: armorPrice},
}
}
func weaponName(floor int) string {
switch {
case floor >= 15:
return "Mythril Blade"
case floor >= 10:
return "Steel Sword"
case floor >= 5:
return "Bronze Sword"
default:
return "Iron Sword"
}
}
func armorName(floor int) string {
switch {
case floor >= 15:
return "Mythril Shield"
case floor >= 10:
return "Steel Shield"
case floor >= 5:
return "Bronze Shield"
default:
return "Iron Shield"
}
}

View File

@@ -117,9 +117,19 @@ func (s *GameSession) resolvePlayerActions() {
case entity.ClassHealer:
targetIdx := action.TargetIdx
if targetIdx < 0 || targetIdx >= len(s.state.Players) {
targetIdx = 0 // heal self by default
targetIdx = 0
}
target := s.state.Players[targetIdx]
if target.IsDead() {
// Find first alive player to heal instead
for j, candidate := range s.state.Players {
if !candidate.IsOut() {
target = candidate
targetIdx = j
break
}
}
}
before := target.HP
target.Heal(30)
s.addLog(fmt.Sprintf("%s healed %s for %d HP", p.Name, target.Name, target.HP-before))
@@ -203,10 +213,7 @@ func (s *GameSession) resolvePlayerActions() {
// Award gold only for monsters that JUST died this turn
for i, m := range s.state.Monsters {
if m.IsDead() && aliveBeforeTurn[i] {
goldReward := 5 + s.state.FloorNum
if goldReward > 15 {
goldReward = 15
}
goldReward := 5 + s.state.FloorNum*2
for _, p := range s.state.Players {
if !p.IsOut() {
bonus := 0