package client import ( "fmt" "image/color" "log" "strings" "github.com/chompy/roguelike_rpg/internal/client/gfx" "github.com/chompy/roguelike_rpg/internal/client/hud" nbattle "github.com/chompy/roguelike_rpg/lib/nbattle" "github.com/hajimehoshi/ebiten/v2" ) type Combatant struct { Role *Role Sprite *gfx.Sprite Pos [2]int EXP int Level int Team int HP int MP int Alive bool Actions []string Inventory []string Artifacts []string HasActiveAnimation bool HpBar *hud.Bar MpBar *hud.Bar ctx *GameContext nb *nbattle.Combatant time float32 } func NewCombatant(ctx *GameContext, role *Role, team int) (*Combatant, error) { actions := make([]string, 0) for _, a := range role.Actions { actions = append(actions, a) } return &Combatant{ Role: role, Pos: [2]int{0, 0}, EXP: 0, Level: 1, Team: team, HP: role.Stats["hp"][0], MP: role.Stats["mp"][0], Alive: true, HasActiveAnimation: false, Sprite: nil, Actions: actions, Artifacts: make([]string, 0), HpBar: hud.NewBar(hud.BarConfig{ Width: 64, Height: 6, Color: color.NRGBA{0x40, 0xc0, 0x40, 0xff}, }), MpBar: hud.NewBar(hud.BarConfig{ Width: 64, Height: 6, Color: color.NRGBA{0x40, 0x40, 0xc0, 0xff}, }), ctx: ctx, }, nil } func (c *Combatant) GetID() int { if c.nb != nil { return c.nb.GetID() } return 0 } func (c *Combatant) String() string { ID := c.GetID() if ID > 0 { return fmt.Sprintf("%s (%d)", c.Role.Name, ID) } return c.Role.Name } func (c *Combatant) Draw(time float32, screen *ebiten.Image) { if c.Sprite == nil { return } frame := c.Sprite.GetAnimationFrame(time - c.time) if frame == nil { return } op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(c.Pos[0]-(frame.Bounds().Size().X/2)+4), float64(c.Pos[1]+16)) hasAnimation, err := c.Sprite.Draw(time-c.time, screen, op) if err != nil { return } c.HasActiveAnimation = hasAnimation } func (c *Combatant) SetSprite(names ...string) error { log.Printf("CLIENT: Set combatant %s sprite to %s", c.String(), strings.Join(names, ",")) sprite, err := c.ctx.Gfx.SpriteLibrary.GetFirst(names...) if err != nil { return nil } c.time = c.ctx.Time() c.HasActiveAnimation = true c.Sprite = sprite return nil } func (c *Combatant) TriggerSprite(trigger TriggerEvent) error { return c.SetSprite(GetTriggersForCombatant(c, trigger)...) } func (c *Combatant) TriggerEffectSprite(trigger TriggerEvent, effect string) error { return c.SetSprite(GetTriggersForCombatantEffect(c, effect, trigger)...) } func (c *Combatant) SetBattleCombatant(nbCombatant *nbattle.Combatant) { c.nb = nbCombatant for statName, statValue := range c.Role.GetStatsForLevel(c.Level) { switch statName { case "hp": statName = "max_hp" case "mp": statName = "max_mp" } stat, err := nbCombatant.GetStat(statName) if err == nil { stat.SetBase(statValue) } } hpStat, err := nbCombatant.GetStat("hp") if err == nil { hpStat.SetBase(c.HP) } mpStat, err := nbCombatant.GetStat("mp") if err == nil { mpStat.SetBase(c.MP) } } func (c *Combatant) IsPlayer() bool { return c.Team == 1 } func (c *Combatant) GetCurrentHP() int { if c.nb == nil { return c.HP } stat, err := c.nb.GetStat("hp") if err != nil { return c.HP } return stat.GetBase() } func (c *Combatant) GetMaxHP() int { if c.nb == nil { return c.Role.Stats["hp"][c.Level-1] } stat, err := c.nb.GetStat("max_hp") if err != nil { return c.Role.Stats["hp"][c.Level-1] } return stat.GetBase() } func (c *Combatant) GetCurrentMP() int { if c.nb == nil { return c.MP } stat, err := c.nb.GetStat("mp") if err != nil { return c.MP } return stat.GetBase() } func (c *Combatant) GetMaxMP() int { if c.nb == nil { return c.Role.Stats["mp"][c.Level-1] } stat, err := c.nb.GetStat("max_mp") if err != nil { return c.Role.Stats["mp"][c.Level-1] } return stat.GetBase() }