Files
Catacombs/entity/player.go
2026-03-24 14:49:55 +09:00

186 lines
3.3 KiB
Go

package entity
import "fmt"
type Class int
const (
ClassWarrior Class = iota
ClassMage
ClassHealer
ClassRogue
)
func (c Class) String() string {
return [...]string{"Warrior", "Mage", "Healer", "Rogue"}[c]
}
type classStats struct {
HP, ATK, DEF int
}
var classBaseStats = map[Class]classStats{
ClassWarrior: {120, 12, 8},
ClassMage: {70, 20, 3},
ClassHealer: {90, 8, 5},
ClassRogue: {85, 15, 4},
}
type StatusEffect int
const (
StatusPoison StatusEffect = iota
StatusBurn
StatusFreeze
)
type ActiveEffect struct {
Type StatusEffect
Duration int // remaining turns
Value int // damage per turn or effect strength
}
type Player struct {
Name string
Fingerprint string
Class Class
HP, MaxHP int
ATK, DEF int
Gold int
Inventory []Item
Relics []Relic
Effects []ActiveEffect
Dead bool
Fled bool
SkillUses int // remaining skill uses this combat
}
func NewPlayer(name string, class Class) *Player {
stats := classBaseStats[class]
return &Player{
Name: name,
Class: class,
HP: stats.HP,
MaxHP: stats.HP,
ATK: stats.ATK,
DEF: stats.DEF,
}
}
func (p *Player) TakeDamage(dmg int) {
p.HP -= dmg
if p.HP <= 0 {
p.HP = 0
p.Dead = true
}
}
func (p *Player) Heal(amount int) {
p.HP += amount
if p.HP > p.MaxHP {
p.HP = p.MaxHP
}
}
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)
if p.HP < 1 {
p.HP = 1
}
}
func (p *Player) EffectiveATK() int {
atk := p.ATK
for _, item := range p.Inventory {
if item.Type == ItemWeapon {
atk += item.Bonus
}
}
for _, r := range p.Relics {
if r.Effect == RelicATKBoost {
atk += r.Value
}
}
return atk
}
func (p *Player) EffectiveDEF() int {
def := p.DEF
for _, item := range p.Inventory {
if item.Type == ItemArmor {
def += item.Bonus
}
}
for _, r := range p.Relics {
if r.Effect == RelicDEFBoost {
def += r.Value
}
}
return def
}
func (p *Player) AddEffect(e ActiveEffect) {
// Check relic immunities
for _, r := range p.Relics {
if e.Type == StatusPoison && r.Effect == RelicPoisonImmunity {
return // immune
}
if e.Type == StatusBurn && r.Effect == RelicBurnResist {
e.Value = e.Value / 2 // halve burn damage
}
}
// Don't stack same type, refresh duration
for i, existing := range p.Effects {
if existing.Type == e.Type {
p.Effects[i] = e
return
}
}
p.Effects = append(p.Effects, e)
}
func (p *Player) HasEffect(t StatusEffect) bool {
for _, e := range p.Effects {
if e.Type == t {
return true
}
}
return false
}
func (p *Player) TickEffects() (damages []string) {
var remaining []ActiveEffect
for _, e := range p.Effects {
switch e.Type {
case StatusPoison:
p.HP -= e.Value
if p.HP <= 0 {
p.HP = 1 // Poison can't kill, leaves at 1 HP
}
damages = append(damages, fmt.Sprintf("%s takes %d poison damage", p.Name, e.Value))
case StatusBurn:
p.HP -= e.Value
if p.HP <= 0 {
p.HP = 0
p.Dead = true
}
damages = append(damages, fmt.Sprintf("%s takes %d burn damage", p.Name, e.Value))
}
e.Duration--
if e.Duration > 0 {
remaining = append(remaining, e)
}
}
p.Effects = remaining
return
}