package factions import ( "fmt" "eq2emu/internal/database" ) // Faction represents a single faction with its properties and embedded database operations type Faction struct { ID int32 // Faction ID Name string // Faction name Type string // Faction type/category Description string // Faction description NegativeChange int16 // Amount faction decreases by default PositiveChange int16 // Amount faction increases by default DefaultValue int32 // Default faction value for new characters db *database.Database isNew bool } // New creates a new faction with the given database connection func New(db *database.Database) *Faction { return &Faction{ db: db, isNew: true, } } // Load loads a faction from the database by ID func Load(db *database.Database, id int32) (*Faction, error) { faction := &Faction{ db: db, isNew: false, } query := `SELECT id, name, type, description, negative_change, positive_change, default_value FROM factions WHERE id = ?` row := db.QueryRow(query, id) err := row.Scan(&faction.ID, &faction.Name, &faction.Type, &faction.Description, &faction.NegativeChange, &faction.PositiveChange, &faction.DefaultValue) if err != nil { return nil, fmt.Errorf("failed to load faction %d: %w", id, err) } return faction, nil } // NewFaction creates a new faction with the given parameters (legacy helper) func NewFaction(id int32, name, factionType, description string) *Faction { return &Faction{ ID: id, Name: name, Type: factionType, Description: description, NegativeChange: 0, PositiveChange: 0, DefaultValue: 0, isNew: true, } } // GetID returns the faction ID func (f *Faction) GetID() int32 { return f.ID } // GetName returns the faction name func (f *Faction) GetName() string { return f.Name } // GetType returns the faction type func (f *Faction) GetType() string { return f.Type } // GetDescription returns the faction description func (f *Faction) GetDescription() string { return f.Description } // GetNegativeChange returns the default decrease amount func (f *Faction) GetNegativeChange() int16 { return f.NegativeChange } // GetPositiveChange returns the default increase amount func (f *Faction) GetPositiveChange() int16 { return f.PositiveChange } // GetDefaultValue returns the default faction value func (f *Faction) GetDefaultValue() int32 { return f.DefaultValue } // SetNegativeChange sets the default decrease amount func (f *Faction) SetNegativeChange(amount int16) { f.NegativeChange = amount } // SetPositiveChange sets the default increase amount func (f *Faction) SetPositiveChange(amount int16) { f.PositiveChange = amount } // SetDefaultValue sets the default faction value func (f *Faction) SetDefaultValue(value int32) { f.DefaultValue = value } // Save saves the faction to the database func (f *Faction) Save() error { if f.db == nil { return fmt.Errorf("no database connection available") } if f.isNew { return f.insert() } return f.update() } // Delete deletes the faction from the database func (f *Faction) Delete() error { if f.db == nil { return fmt.Errorf("no database connection available") } if f.isNew { return fmt.Errorf("cannot delete unsaved faction") } _, err := f.db.Exec(`DELETE FROM factions WHERE id = ?`, f.ID) if err != nil { return fmt.Errorf("failed to delete faction %d: %w", f.ID, err) } return nil } // Reload reloads the faction from the database func (f *Faction) Reload() error { if f.db == nil { return fmt.Errorf("no database connection available") } if f.isNew { return fmt.Errorf("cannot reload unsaved faction") } reloaded, err := Load(f.db, f.ID) if err != nil { return err } // Copy reloaded data f.Name = reloaded.Name f.Type = reloaded.Type f.Description = reloaded.Description f.NegativeChange = reloaded.NegativeChange f.PositiveChange = reloaded.PositiveChange f.DefaultValue = reloaded.DefaultValue return nil } // IsNew returns true if this is a new faction not yet saved to database func (f *Faction) IsNew() bool { return f.isNew } // Clone creates a copy of the faction func (f *Faction) Clone() *Faction { return &Faction{ ID: f.ID, Name: f.Name, Type: f.Type, Description: f.Description, NegativeChange: f.NegativeChange, PositiveChange: f.PositiveChange, DefaultValue: f.DefaultValue, db: f.db, isNew: true, // Clone is always new } } // insert inserts a new faction into the database func (f *Faction) insert() error { query := `INSERT INTO factions (id, name, type, description, negative_change, positive_change, default_value) VALUES (?, ?, ?, ?, ?, ?, ?)` _, err := f.db.Exec(query, f.ID, f.Name, f.Type, f.Description, f.NegativeChange, f.PositiveChange, f.DefaultValue) if err != nil { return fmt.Errorf("failed to insert faction %d: %w", f.ID, err) } f.isNew = false return nil } // update updates an existing faction in the database func (f *Faction) update() error { query := `UPDATE factions SET name = ?, type = ?, description = ?, negative_change = ?, positive_change = ?, default_value = ? WHERE id = ?` result, err := f.db.Exec(query, f.Name, f.Type, f.Description, f.NegativeChange, f.PositiveChange, f.DefaultValue, f.ID) if err != nil { return fmt.Errorf("failed to update faction %d: %w", f.ID, err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rowsAffected == 0 { return fmt.Errorf("faction %d not found for update", f.ID) } return nil } // IsValid returns true if the faction has valid data func (f *Faction) IsValid() bool { return f.ID > 0 && len(f.Name) > 0 } // IsSpecialFaction returns true if this is a special faction (ID <= 10) func (f *Faction) IsSpecialFaction() bool { return f.ID <= SpecialFactionIDMax } // CanIncrease returns true if this faction can be increased func (f *Faction) CanIncrease() bool { return !f.IsSpecialFaction() && f.PositiveChange != 0 } // CanDecrease returns true if this faction can be decreased func (f *Faction) CanDecrease() bool { return !f.IsSpecialFaction() && f.NegativeChange != 0 }