285 lines
5.7 KiB
Go
285 lines
5.7 KiB
Go
package items
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"dk/internal/database"
|
|
)
|
|
|
|
// Item represents an item in the game
|
|
type Item struct {
|
|
ID int `db:"id"`
|
|
Type int `db:"type"`
|
|
Name string `db:"name"`
|
|
Lore string `db:"lore"`
|
|
Value int `db:"value"`
|
|
Attack int `db:"attack"`
|
|
Defense int `db:"defense"`
|
|
Strength int `db:"strength"`
|
|
Dexterity int `db:"dexterity"`
|
|
MaxHP int `db:"max_hp"`
|
|
MaxMP int `db:"max_mp"`
|
|
ExpBonus int `db:"exp_bonus"`
|
|
GoldBonus int `db:"gold_bonus"`
|
|
Special string `db:"special"`
|
|
}
|
|
|
|
// ItemType constants for item types
|
|
const (
|
|
TypeWeapon = 1
|
|
TypeArmor = 2
|
|
TypeShield = 3
|
|
TypeAccessory = 4
|
|
)
|
|
|
|
// New creates a new Item with sensible defaults
|
|
func New() *Item {
|
|
return &Item{
|
|
Type: TypeWeapon,
|
|
Name: "",
|
|
Lore: "",
|
|
Value: 0,
|
|
Attack: 0,
|
|
Defense: 0,
|
|
Strength: 0,
|
|
Dexterity: 0,
|
|
MaxHP: 0,
|
|
MaxMP: 0,
|
|
ExpBonus: 0,
|
|
GoldBonus: 0,
|
|
Special: "",
|
|
}
|
|
}
|
|
|
|
// Validate checks if item has valid values
|
|
func (i *Item) Validate() error {
|
|
if i.Name == "" {
|
|
return fmt.Errorf("item name cannot be empty")
|
|
}
|
|
if i.Type < TypeWeapon || i.Type > TypeAccessory {
|
|
return fmt.Errorf("invalid item type: %d", i.Type)
|
|
}
|
|
if i.Value < 0 {
|
|
return fmt.Errorf("item value cannot be negative")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CRUD operations
|
|
func (i *Item) Delete() error {
|
|
return database.Exec("DELETE FROM items WHERE id = %d", i.ID)
|
|
}
|
|
|
|
func (i *Item) Insert() error {
|
|
id, err := database.Insert("items", i, "id")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
i.ID = int(id)
|
|
return nil
|
|
}
|
|
|
|
func (i *Item) Update() error {
|
|
fields := map[string]any{
|
|
"type": i.Type,
|
|
"name": i.Name,
|
|
"lore": i.Lore,
|
|
"value": i.Value,
|
|
"attack": i.Attack,
|
|
"defense": i.Defense,
|
|
"strength": i.Strength,
|
|
"dexterity": i.Dexterity,
|
|
"max_hp": i.MaxHP,
|
|
"max_mp": i.MaxMP,
|
|
"exp_bonus": i.ExpBonus,
|
|
"gold_bonus": i.GoldBonus,
|
|
"special": i.Special,
|
|
}
|
|
return database.Update("items", fields, "id", i.ID)
|
|
}
|
|
|
|
// Query functions
|
|
func Find(id int) (*Item, error) {
|
|
var item Item
|
|
err := database.Get(&item, "SELECT * FROM items WHERE id = %d", id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("item with ID %d not found", id)
|
|
}
|
|
return &item, nil
|
|
}
|
|
|
|
func All() ([]*Item, error) {
|
|
var items []*Item
|
|
err := database.Select(&items, "SELECT * FROM items ORDER BY type ASC, value ASC, id ASC")
|
|
return items, err
|
|
}
|
|
|
|
func ByType(itemType int) ([]*Item, error) {
|
|
var items []*Item
|
|
err := database.Select(&items, "SELECT * FROM items WHERE type = %d ORDER BY value ASC, id ASC", itemType)
|
|
return items, err
|
|
}
|
|
|
|
func ByValueRange(minValue, maxValue int) ([]*Item, error) {
|
|
var items []*Item
|
|
err := database.Select(&items, "SELECT * FROM items WHERE value >= %d AND value <= %d ORDER BY value ASC, id ASC", minValue, maxValue)
|
|
return items, err
|
|
}
|
|
|
|
func ByName(name string) (*Item, error) {
|
|
var item Item
|
|
err := database.Get(&item, "SELECT * FROM items WHERE name = %s COLLATE NOCASE", name)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("item with name '%s' not found", name)
|
|
}
|
|
return &item, nil
|
|
}
|
|
|
|
// Helper methods
|
|
func (i *Item) IsWeapon() bool {
|
|
return i.Type == TypeWeapon
|
|
}
|
|
|
|
func (i *Item) IsArmor() bool {
|
|
return i.Type == TypeArmor
|
|
}
|
|
|
|
func (i *Item) IsShield() bool {
|
|
return i.Type == TypeShield
|
|
}
|
|
|
|
func (i *Item) IsAccessory() bool {
|
|
return i.Type == TypeAccessory
|
|
}
|
|
|
|
func (i *Item) TypeName() string {
|
|
switch i.Type {
|
|
case TypeWeapon:
|
|
return "Weapon"
|
|
case TypeArmor:
|
|
return "Armor"
|
|
case TypeShield:
|
|
return "Shield"
|
|
case TypeAccessory:
|
|
return "Accessory"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
func (i *Item) HasSpecial() bool {
|
|
return i.Special != ""
|
|
}
|
|
|
|
func (i *Item) IsEquippable() bool {
|
|
return i.Type >= TypeWeapon && i.Type <= TypeShield
|
|
}
|
|
|
|
func (i *Item) IsSlottable() bool {
|
|
return i.Type == TypeAccessory
|
|
}
|
|
|
|
func (i *Item) HasLore() bool {
|
|
return i.Lore != ""
|
|
}
|
|
|
|
// Stat bonus methods
|
|
func (i *Item) HasAttackBonus() bool {
|
|
return i.Attack != 0
|
|
}
|
|
|
|
func (i *Item) HasDefenseBonus() bool {
|
|
return i.Defense != 0
|
|
}
|
|
|
|
func (i *Item) HasStrengthBonus() bool {
|
|
return i.Strength != 0
|
|
}
|
|
|
|
func (i *Item) HasDexterityBonus() bool {
|
|
return i.Dexterity != 0
|
|
}
|
|
|
|
func (i *Item) HasHPBonus() bool {
|
|
return i.MaxHP != 0
|
|
}
|
|
|
|
func (i *Item) HasMPBonus() bool {
|
|
return i.MaxMP != 0
|
|
}
|
|
|
|
func (i *Item) HasExpBonus() bool {
|
|
return i.ExpBonus != 0
|
|
}
|
|
|
|
func (i *Item) HasGoldBonus() bool {
|
|
return i.GoldBonus != 0
|
|
}
|
|
|
|
// Returns true if the item provides any stat bonuses
|
|
func (i *Item) HasStatBonuses() bool {
|
|
return i.Attack != 0 || i.Defense != 0 || i.Strength != 0 ||
|
|
i.Dexterity != 0 || i.MaxHP != 0 || i.MaxMP != 0 ||
|
|
i.ExpBonus != 0 || i.GoldBonus != 0
|
|
}
|
|
|
|
func (i *Item) GetStatBonuses() map[string]int {
|
|
bonuses := make(map[string]int)
|
|
|
|
if i.Attack != 0 {
|
|
bonuses["Attack"] = i.Attack
|
|
}
|
|
if i.Defense != 0 {
|
|
bonuses["Defense"] = i.Defense
|
|
}
|
|
if i.Strength != 0 {
|
|
bonuses["Strength"] = i.Strength
|
|
}
|
|
if i.Dexterity != 0 {
|
|
bonuses["Dexterity"] = i.Dexterity
|
|
}
|
|
if i.MaxHP != 0 {
|
|
bonuses["Max HP"] = i.MaxHP
|
|
}
|
|
if i.MaxMP != 0 {
|
|
bonuses["Max MP"] = i.MaxMP
|
|
}
|
|
if i.ExpBonus != 0 {
|
|
bonuses["Exp Bonus"] = i.ExpBonus
|
|
}
|
|
if i.GoldBonus != 0 {
|
|
bonuses["Gold Bonus"] = i.GoldBonus
|
|
}
|
|
|
|
return bonuses
|
|
}
|
|
|
|
// GetPrimaryStatBonus returns the main stat bonus for the item type
|
|
func (i *Item) GetPrimaryStatBonus() int {
|
|
switch i.Type {
|
|
case TypeWeapon:
|
|
return i.Attack
|
|
case TypeArmor, TypeShield:
|
|
return i.Defense
|
|
case TypeAccessory:
|
|
// For accessories, return the highest stat bonus
|
|
max := 0
|
|
stats := []int{i.Attack, i.Defense, i.Strength, i.Dexterity, i.MaxHP, i.MaxMP}
|
|
for _, stat := range stats {
|
|
if abs(stat) > abs(max) {
|
|
max = stat
|
|
}
|
|
}
|
|
return max
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func abs(x int) int {
|
|
if x < 0 {
|
|
return -x
|
|
}
|
|
return x
|
|
}
|