262 lines
5.8 KiB
Go

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()
}