package fights import ( "fmt" "time" "dk/internal/database" ) // Fight represents a fight, past or present type Fight struct { ID int UserID int MonsterID int MonsterHP int MonsterMaxHP int MonsterSleep int MonsterImmune int UberDamage int UberDefense int FirstStrike bool Turn int RanAway bool Victory bool Won bool RewardGold int RewardExp int Created int64 Updated int64 } // New creates a new Fight with sensible defaults func New(userID, monsterID int) *Fight { now := time.Now().Unix() return &Fight{ UserID: userID, MonsterID: monsterID, MonsterHP: 0, MonsterMaxHP: 0, MonsterSleep: 0, MonsterImmune: 0, UberDamage: 0, UberDefense: 0, FirstStrike: false, Turn: 0, RanAway: false, Victory: false, Won: false, RewardGold: 0, RewardExp: 0, Created: now, Updated: now, } } // Validate checks if fight has valid values func (f *Fight) Validate() error { if f.UserID <= 0 { return fmt.Errorf("fight UserID must be positive") } if f.MonsterID <= 0 { return fmt.Errorf("fight MonsterID must be positive") } if f.Turn < 0 { return fmt.Errorf("fight Turn cannot be negative") } if f.MonsterHP < 0 { return fmt.Errorf("fight MonsterHP cannot be negative") } if f.Created <= 0 { return fmt.Errorf("fight Created timestamp must be positive") } if f.Updated <= 0 { return fmt.Errorf("fight Updated timestamp must be positive") } return nil } // CRUD operations func (f *Fight) Delete() error { return database.Exec("DELETE FROM fights WHERE id = %d", f.ID) } func (f *Fight) Insert() error { f.Updated = time.Now().Unix() id, err := database.Insert("fights", f, "ID") if err != nil { return err } f.ID = int(id) return nil } func (f *Fight) Update() error { f.Updated = time.Now().Unix() return database.Update("fights", map[string]any{ "user_id": f.UserID, "monster_id": f.MonsterID, "monster_hp": f.MonsterHP, "monster_max_hp": f.MonsterMaxHP, "monster_sleep": f.MonsterSleep, "monster_immune": f.MonsterImmune, "uber_damage": f.UberDamage, "uber_defense": f.UberDefense, "first_strike": f.FirstStrike, "turn": f.Turn, "ran_away": f.RanAway, "victory": f.Victory, "won": f.Won, "reward_gold": f.RewardGold, "reward_exp": f.RewardExp, "created": f.Created, "updated": f.Updated, }, "id", f.ID) } // Query functions func Find(id int) (*Fight, error) { var fight Fight err := database.Get(&fight, "SELECT * FROM fights WHERE id = %d", id) if err != nil { return nil, fmt.Errorf("fight with ID %d not found", id) } return &fight, nil } func All() ([]*Fight, error) { var fights []*Fight err := database.Select(&fights, "SELECT * FROM fights ORDER BY created DESC, id DESC") return fights, err } func ByUserID(userID int) ([]*Fight, error) { var fights []*Fight err := database.Select(&fights, "SELECT * FROM fights WHERE user_id = %d ORDER BY created DESC, id DESC", userID) return fights, err } func ByMonsterID(monsterID int) ([]*Fight, error) { var fights []*Fight err := database.Select(&fights, "SELECT * FROM fights WHERE monster_id = %d ORDER BY created DESC, id DESC", monsterID) return fights, err } func ActiveByUserID(userID int) ([]*Fight, error) { var fights []*Fight err := database.Select(&fights, "SELECT * FROM fights WHERE user_id = %d AND ran_away = 0 AND victory = 0 ORDER BY created DESC, id DESC", userID) return fights, err } func Active() ([]*Fight, error) { var fights []*Fight err := database.Select(&fights, "SELECT * FROM fights WHERE ran_away = 0 AND victory = 0 ORDER BY created DESC, id DESC") return fights, err } func Recent(within time.Duration) ([]*Fight, error) { cutoff := time.Now().Add(-within).Unix() var fights []*Fight err := database.Select(&fights, "SELECT * FROM fights WHERE created >= %d ORDER BY created DESC, id DESC", cutoff) return fights, err } // Helper methods func (f *Fight) CreatedTime() time.Time { return time.Unix(f.Created, 0) } func (f *Fight) UpdatedTime() time.Time { return time.Unix(f.Updated, 0) } func (f *Fight) IsActive() bool { return !f.RanAway && !f.Victory } func (f *Fight) IsComplete() bool { return f.RanAway || f.Victory } func (f *Fight) GetStatus() string { if f.Won { return "Won" } if f.Victory && !f.Won { return "Lost" } if f.RanAway { return "Ran Away" } return "Active" } func (f *Fight) GetMonsterHealthPercent() float64 { if f.MonsterMaxHP <= 0 { return 0.0 } return float64(f.MonsterHP) / float64(f.MonsterMaxHP) * 100.0 } func (f *Fight) IsMonsterSleeping() bool { return f.MonsterSleep > 0 } func (f *Fight) IsMonsterImmune() bool { return f.MonsterImmune > 0 } func (f *Fight) HasUberBonus() bool { return f.UberDamage > 0 || f.UberDefense > 0 } func (f *Fight) GetDuration() time.Duration { return time.Unix(f.Updated, 0).Sub(time.Unix(f.Created, 0)) } func (f *Fight) EndFight(victory bool) { f.Victory = victory f.RanAway = !victory f.Updated = time.Now().Unix() } func (f *Fight) WinFight(goldReward, expReward int) { f.Victory = true f.Won = true f.RanAway = false f.RewardGold = goldReward f.RewardExp = expReward f.Updated = time.Now().Unix() } func (f *Fight) LoseFight() { f.Victory = true f.Won = false f.RanAway = false f.Updated = time.Now().Unix() } func (f *Fight) RunAway() { f.RanAway = true f.Victory = false f.Updated = time.Now().Unix() } func (f *Fight) IncrementTurn() { f.Turn++ f.Updated = time.Now().Unix() } func (f *Fight) SetMonsterHP(hp int) { f.MonsterHP = hp f.Updated = time.Now().Unix() } func (f *Fight) DamageMonster(damage int) { f.MonsterHP -= damage if f.MonsterHP < 0 { f.MonsterHP = 0 } f.Updated = time.Now().Unix() }