split builder components out
This commit is contained in:
parent
53d131a96e
commit
89af7644ba
88
internal/drops/builder.go
Normal file
88
internal/drops/builder.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package drops
|
||||||
|
|
||||||
|
import (
|
||||||
|
"dk/internal/database"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"zombiezen.com/go/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builder provides a fluent interface for creating drops
|
||||||
|
type Builder struct {
|
||||||
|
drop *Drop
|
||||||
|
db *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuilder creates a new drop builder
|
||||||
|
func NewBuilder(db *database.DB) *Builder {
|
||||||
|
return &Builder{
|
||||||
|
drop: &Drop{db: db},
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithName sets the drop name
|
||||||
|
func (b *Builder) WithName(name string) *Builder {
|
||||||
|
b.drop.Name = name
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLevel sets the drop level requirement
|
||||||
|
func (b *Builder) WithLevel(level int) *Builder {
|
||||||
|
b.drop.Level = level
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithType sets the drop type
|
||||||
|
func (b *Builder) WithType(dropType int) *Builder {
|
||||||
|
b.drop.Type = dropType
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAtt sets the attributes
|
||||||
|
func (b *Builder) WithAtt(att string) *Builder {
|
||||||
|
b.drop.Att = att
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create saves the drop to the database and returns it
|
||||||
|
func (b *Builder) Create() (*Drop, error) {
|
||||||
|
// Use a transaction to ensure we can get the ID
|
||||||
|
var drop *Drop
|
||||||
|
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||||
|
query := `INSERT INTO drops (name, level, type, att)
|
||||||
|
VALUES (?, ?, ?, ?)`
|
||||||
|
|
||||||
|
if err := tx.Exec(query, b.drop.Name, b.drop.Level, b.drop.Type, b.drop.Att); err != nil {
|
||||||
|
return fmt.Errorf("failed to insert drop: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the last inserted ID within the same transaction
|
||||||
|
var lastID int
|
||||||
|
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
||||||
|
lastID = stmt.ColumnInt(0)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get last insert ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the drop with the ID
|
||||||
|
drop = &Drop{
|
||||||
|
ID: lastID,
|
||||||
|
Name: b.drop.Name,
|
||||||
|
Level: b.drop.Level,
|
||||||
|
Type: b.drop.Type,
|
||||||
|
Att: b.drop.Att,
|
||||||
|
db: b.db,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create drop: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return drop, nil
|
||||||
|
}
|
@ -124,86 +124,6 @@ func ByType(db *database.DB, dropType int) ([]*Drop, error) {
|
|||||||
return drops, nil
|
return drops, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builder provides a fluent interface for creating drops
|
|
||||||
type Builder struct {
|
|
||||||
drop *Drop
|
|
||||||
db *database.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBuilder creates a new drop builder
|
|
||||||
func NewBuilder(db *database.DB) *Builder {
|
|
||||||
return &Builder{
|
|
||||||
drop: &Drop{db: db},
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithName sets the drop name
|
|
||||||
func (b *Builder) WithName(name string) *Builder {
|
|
||||||
b.drop.Name = name
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLevel sets the drop level requirement
|
|
||||||
func (b *Builder) WithLevel(level int) *Builder {
|
|
||||||
b.drop.Level = level
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithType sets the drop type
|
|
||||||
func (b *Builder) WithType(dropType int) *Builder {
|
|
||||||
b.drop.Type = dropType
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithAtt sets the attributes
|
|
||||||
func (b *Builder) WithAtt(att string) *Builder {
|
|
||||||
b.drop.Att = att
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create saves the drop to the database and returns it
|
|
||||||
func (b *Builder) Create() (*Drop, error) {
|
|
||||||
// Use a transaction to ensure we can get the ID
|
|
||||||
var drop *Drop
|
|
||||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
|
||||||
query := `INSERT INTO drops (name, level, type, att)
|
|
||||||
VALUES (?, ?, ?, ?)`
|
|
||||||
|
|
||||||
if err := tx.Exec(query, b.drop.Name, b.drop.Level, b.drop.Type, b.drop.Att); err != nil {
|
|
||||||
return fmt.Errorf("failed to insert drop: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the last inserted ID within the same transaction
|
|
||||||
var lastID int
|
|
||||||
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
|
||||||
lastID = stmt.ColumnInt(0)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get last insert ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the drop with the ID
|
|
||||||
drop = &Drop{
|
|
||||||
ID: lastID,
|
|
||||||
Name: b.drop.Name,
|
|
||||||
Level: b.drop.Level,
|
|
||||||
Type: b.drop.Type,
|
|
||||||
Att: b.drop.Att,
|
|
||||||
db: b.db,
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create drop: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return drop, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save updates an existing drop in the database
|
// Save updates an existing drop in the database
|
||||||
func (d *Drop) Save() error {
|
func (d *Drop) Save() error {
|
||||||
if d.ID == 0 {
|
if d.ID == 0 {
|
||||||
|
95
internal/items/builder.go
Normal file
95
internal/items/builder.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package items
|
||||||
|
|
||||||
|
import (
|
||||||
|
"dk/internal/database"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"zombiezen.com/go/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builder provides a fluent interface for creating items
|
||||||
|
type Builder struct {
|
||||||
|
item *Item
|
||||||
|
db *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuilder creates a new item builder
|
||||||
|
func NewBuilder(db *database.DB) *Builder {
|
||||||
|
return &Builder{
|
||||||
|
item: &Item{db: db},
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithType sets the item type
|
||||||
|
func (b *Builder) WithType(itemType int) *Builder {
|
||||||
|
b.item.Type = itemType
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithName sets the item name
|
||||||
|
func (b *Builder) WithName(name string) *Builder {
|
||||||
|
b.item.Name = name
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValue sets the item value
|
||||||
|
func (b *Builder) WithValue(value int) *Builder {
|
||||||
|
b.item.Value = value
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAtt sets the item attack/defense value
|
||||||
|
func (b *Builder) WithAtt(att int) *Builder {
|
||||||
|
b.item.Att = att
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSpecial sets the item special attributes
|
||||||
|
func (b *Builder) WithSpecial(special string) *Builder {
|
||||||
|
b.item.Special = special
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create saves the item to the database and returns it
|
||||||
|
func (b *Builder) Create() (*Item, error) {
|
||||||
|
// Use a transaction to ensure we can get the ID
|
||||||
|
var item *Item
|
||||||
|
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||||
|
query := `INSERT INTO items (type, name, value, att, special)
|
||||||
|
VALUES (?, ?, ?, ?, ?)`
|
||||||
|
|
||||||
|
if err := tx.Exec(query, b.item.Type, b.item.Name, b.item.Value, b.item.Att, b.item.Special); err != nil {
|
||||||
|
return fmt.Errorf("failed to insert item: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the last inserted ID within the same transaction
|
||||||
|
var lastID int
|
||||||
|
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
||||||
|
lastID = stmt.ColumnInt(0)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get last insert ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the item with the ID
|
||||||
|
item = &Item{
|
||||||
|
ID: lastID,
|
||||||
|
Type: b.item.Type,
|
||||||
|
Name: b.item.Name,
|
||||||
|
Value: b.item.Value,
|
||||||
|
Att: b.item.Att,
|
||||||
|
Special: b.item.Special,
|
||||||
|
db: b.db,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create item: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return item, nil
|
||||||
|
}
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"dk/internal/database"
|
"dk/internal/database"
|
||||||
|
|
||||||
"zombiezen.com/go/sqlite"
|
"zombiezen.com/go/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ type Item struct {
|
|||||||
Value int `json:"value"`
|
Value int `json:"value"`
|
||||||
Att int `json:"att"`
|
Att int `json:"att"`
|
||||||
Special string `json:"special"`
|
Special string `json:"special"`
|
||||||
|
|
||||||
db *database.DB
|
db *database.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ const (
|
|||||||
// Find retrieves an item by ID
|
// Find retrieves an item by ID
|
||||||
func Find(db *database.DB, id int) (*Item, error) {
|
func Find(db *database.DB, id int) (*Item, error) {
|
||||||
item := &Item{db: db}
|
item := &Item{db: db}
|
||||||
|
|
||||||
query := "SELECT id, type, name, value, att, special FROM items WHERE id = ?"
|
query := "SELECT id, type, name, value, att, special FROM items WHERE id = ?"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
item.ID = stmt.ColumnInt(0)
|
item.ID = stmt.ColumnInt(0)
|
||||||
@ -40,22 +41,22 @@ func Find(db *database.DB, id int) (*Item, error) {
|
|||||||
item.Special = stmt.ColumnText(5)
|
item.Special = stmt.ColumnText(5)
|
||||||
return nil
|
return nil
|
||||||
}, id)
|
}, id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to find item: %w", err)
|
return nil, fmt.Errorf("failed to find item: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.ID == 0 {
|
if item.ID == 0 {
|
||||||
return nil, fmt.Errorf("item with ID %d not found", id)
|
return nil, fmt.Errorf("item with ID %d not found", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// All retrieves all items
|
// All retrieves all items
|
||||||
func All(db *database.DB) ([]*Item, error) {
|
func All(db *database.DB) ([]*Item, error) {
|
||||||
var items []*Item
|
var items []*Item
|
||||||
|
|
||||||
query := "SELECT id, type, name, value, att, special FROM items ORDER BY id"
|
query := "SELECT id, type, name, value, att, special FROM items ORDER BY id"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
item := &Item{
|
item := &Item{
|
||||||
@ -70,18 +71,18 @@ func All(db *database.DB) ([]*Item, error) {
|
|||||||
items = append(items, item)
|
items = append(items, item)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve all items: %w", err)
|
return nil, fmt.Errorf("failed to retrieve all items: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByType retrieves items by type
|
// ByType retrieves items by type
|
||||||
func ByType(db *database.DB, itemType int) ([]*Item, error) {
|
func ByType(db *database.DB, itemType int) ([]*Item, error) {
|
||||||
var items []*Item
|
var items []*Item
|
||||||
|
|
||||||
query := "SELECT id, type, name, value, att, special FROM items WHERE type = ? ORDER BY id"
|
query := "SELECT id, type, name, value, att, special FROM items WHERE type = ? ORDER BY id"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
item := &Item{
|
item := &Item{
|
||||||
@ -96,107 +97,20 @@ func ByType(db *database.DB, itemType int) ([]*Item, error) {
|
|||||||
items = append(items, item)
|
items = append(items, item)
|
||||||
return nil
|
return nil
|
||||||
}, itemType)
|
}, itemType)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve items by type: %w", err)
|
return nil, fmt.Errorf("failed to retrieve items by type: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builder provides a fluent interface for creating items
|
|
||||||
type Builder struct {
|
|
||||||
item *Item
|
|
||||||
db *database.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBuilder creates a new item builder
|
|
||||||
func NewBuilder(db *database.DB) *Builder {
|
|
||||||
return &Builder{
|
|
||||||
item: &Item{db: db},
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithType sets the item type
|
|
||||||
func (b *Builder) WithType(itemType int) *Builder {
|
|
||||||
b.item.Type = itemType
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithName sets the item name
|
|
||||||
func (b *Builder) WithName(name string) *Builder {
|
|
||||||
b.item.Name = name
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithValue sets the item value
|
|
||||||
func (b *Builder) WithValue(value int) *Builder {
|
|
||||||
b.item.Value = value
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithAtt sets the item attack/defense value
|
|
||||||
func (b *Builder) WithAtt(att int) *Builder {
|
|
||||||
b.item.Att = att
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSpecial sets the item special attributes
|
|
||||||
func (b *Builder) WithSpecial(special string) *Builder {
|
|
||||||
b.item.Special = special
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create saves the item to the database and returns it
|
|
||||||
func (b *Builder) Create() (*Item, error) {
|
|
||||||
// Use a transaction to ensure we can get the ID
|
|
||||||
var item *Item
|
|
||||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
|
||||||
query := `INSERT INTO items (type, name, value, att, special)
|
|
||||||
VALUES (?, ?, ?, ?, ?)`
|
|
||||||
|
|
||||||
if err := tx.Exec(query, b.item.Type, b.item.Name, b.item.Value, b.item.Att, b.item.Special); err != nil {
|
|
||||||
return fmt.Errorf("failed to insert item: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the last inserted ID within the same transaction
|
|
||||||
var lastID int
|
|
||||||
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
|
||||||
lastID = stmt.ColumnInt(0)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get last insert ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the item with the ID
|
|
||||||
item = &Item{
|
|
||||||
ID: lastID,
|
|
||||||
Type: b.item.Type,
|
|
||||||
Name: b.item.Name,
|
|
||||||
Value: b.item.Value,
|
|
||||||
Att: b.item.Att,
|
|
||||||
Special: b.item.Special,
|
|
||||||
db: b.db,
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create item: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return item, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save updates an existing item in the database
|
// Save updates an existing item in the database
|
||||||
func (i *Item) Save() error {
|
func (i *Item) Save() error {
|
||||||
if i.ID == 0 {
|
if i.ID == 0 {
|
||||||
return fmt.Errorf("cannot save item without ID")
|
return fmt.Errorf("cannot save item without ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `UPDATE items SET type = ?, name = ?, value = ?, att = ?, special = ? WHERE id = ?`
|
query := `UPDATE items SET type = ?, name = ?, value = ?, att = ?, special = ? WHERE id = ?`
|
||||||
return i.db.Exec(query, i.Type, i.Name, i.Value, i.Att, i.Special, i.ID)
|
return i.db.Exec(query, i.Type, i.Name, i.Value, i.Att, i.Special, i.ID)
|
||||||
}
|
}
|
||||||
@ -206,7 +120,7 @@ func (i *Item) Delete() error {
|
|||||||
if i.ID == 0 {
|
if i.ID == 0 {
|
||||||
return fmt.Errorf("cannot delete item without ID")
|
return fmt.Errorf("cannot delete item without ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
query := "DELETE FROM items WHERE id = ?"
|
query := "DELETE FROM items WHERE id = ?"
|
||||||
return i.db.Exec(query, i.ID)
|
return i.db.Exec(query, i.ID)
|
||||||
}
|
}
|
||||||
@ -238,4 +152,4 @@ func (i *Item) TypeName() string {
|
|||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
117
internal/monsters/builder.go
Normal file
117
internal/monsters/builder.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package monsters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"dk/internal/database"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"zombiezen.com/go/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Builder provides a fluent interface for creating monsters
|
||||||
|
type Builder struct {
|
||||||
|
monster *Monster
|
||||||
|
db *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuilder creates a new monster builder
|
||||||
|
func NewBuilder(db *database.DB) *Builder {
|
||||||
|
return &Builder{
|
||||||
|
monster: &Monster{db: db},
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithName sets the monster name
|
||||||
|
func (b *Builder) WithName(name string) *Builder {
|
||||||
|
b.monster.Name = name
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxHP sets the monster's maximum hit points
|
||||||
|
func (b *Builder) WithMaxHP(maxHP int) *Builder {
|
||||||
|
b.monster.MaxHP = maxHP
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxDmg sets the monster's maximum damage
|
||||||
|
func (b *Builder) WithMaxDmg(maxDmg int) *Builder {
|
||||||
|
b.monster.MaxDmg = maxDmg
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithArmor sets the monster's armor value
|
||||||
|
func (b *Builder) WithArmor(armor int) *Builder {
|
||||||
|
b.monster.Armor = armor
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLevel sets the monster's level
|
||||||
|
func (b *Builder) WithLevel(level int) *Builder {
|
||||||
|
b.monster.Level = level
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxExp sets the monster's maximum experience reward
|
||||||
|
func (b *Builder) WithMaxExp(maxExp int) *Builder {
|
||||||
|
b.monster.MaxExp = maxExp
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxGold sets the monster's maximum gold reward
|
||||||
|
func (b *Builder) WithMaxGold(maxGold int) *Builder {
|
||||||
|
b.monster.MaxGold = maxGold
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithImmunity sets the monster's immunity type
|
||||||
|
func (b *Builder) WithImmunity(immunity int) *Builder {
|
||||||
|
b.monster.Immune = immunity
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create saves the monster to the database and returns it
|
||||||
|
func (b *Builder) Create() (*Monster, error) {
|
||||||
|
// Use a transaction to ensure we can get the ID
|
||||||
|
var monster *Monster
|
||||||
|
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||||
|
query := `INSERT INTO monsters (name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
|
|
||||||
|
if err := tx.Exec(query, b.monster.Name, b.monster.MaxHP, b.monster.MaxDmg, b.monster.Armor,
|
||||||
|
b.monster.Level, b.monster.MaxExp, b.monster.MaxGold, b.monster.Immune); err != nil {
|
||||||
|
return fmt.Errorf("failed to insert monster: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the last inserted ID within the same transaction
|
||||||
|
var lastID int
|
||||||
|
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
||||||
|
lastID = stmt.ColumnInt(0)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get last insert ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the monster with the ID
|
||||||
|
monster = &Monster{
|
||||||
|
ID: lastID,
|
||||||
|
Name: b.monster.Name,
|
||||||
|
MaxHP: b.monster.MaxHP,
|
||||||
|
MaxDmg: b.monster.MaxDmg,
|
||||||
|
Armor: b.monster.Armor,
|
||||||
|
Level: b.monster.Level,
|
||||||
|
MaxExp: b.monster.MaxExp,
|
||||||
|
MaxGold: b.monster.MaxGold,
|
||||||
|
Immune: b.monster.Immune,
|
||||||
|
db: b.db,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create monster: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return monster, nil
|
||||||
|
}
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"dk/internal/database"
|
"dk/internal/database"
|
||||||
|
|
||||||
"zombiezen.com/go/sqlite"
|
"zombiezen.com/go/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,21 +19,21 @@ type Monster struct {
|
|||||||
MaxExp int `json:"max_exp"`
|
MaxExp int `json:"max_exp"`
|
||||||
MaxGold int `json:"max_gold"`
|
MaxGold int `json:"max_gold"`
|
||||||
Immune int `json:"immune"`
|
Immune int `json:"immune"`
|
||||||
|
|
||||||
db *database.DB
|
db *database.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// Immunity constants for monster immunity types
|
// Immunity constants for monster immunity types
|
||||||
const (
|
const (
|
||||||
ImmuneNone = 0
|
ImmuneNone = 0
|
||||||
ImmuneHurt = 1 // Immune to Hurt spells
|
ImmuneHurt = 1 // Immune to Hurt spells
|
||||||
ImmuneSleep = 2 // Immune to Sleep spells
|
ImmuneSleep = 2 // Immune to Sleep spells
|
||||||
)
|
)
|
||||||
|
|
||||||
// Find retrieves a monster by ID
|
// Find retrieves a monster by ID
|
||||||
func Find(db *database.DB, id int) (*Monster, error) {
|
func Find(db *database.DB, id int) (*Monster, error) {
|
||||||
monster := &Monster{db: db}
|
monster := &Monster{db: db}
|
||||||
|
|
||||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE id = ?"
|
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE id = ?"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
monster.ID = stmt.ColumnInt(0)
|
monster.ID = stmt.ColumnInt(0)
|
||||||
@ -46,22 +47,22 @@ func Find(db *database.DB, id int) (*Monster, error) {
|
|||||||
monster.Immune = stmt.ColumnInt(8)
|
monster.Immune = stmt.ColumnInt(8)
|
||||||
return nil
|
return nil
|
||||||
}, id)
|
}, id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to find monster: %w", err)
|
return nil, fmt.Errorf("failed to find monster: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if monster.ID == 0 {
|
if monster.ID == 0 {
|
||||||
return nil, fmt.Errorf("monster with ID %d not found", id)
|
return nil, fmt.Errorf("monster with ID %d not found", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return monster, nil
|
return monster, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// All retrieves all monsters
|
// All retrieves all monsters
|
||||||
func All(db *database.DB) ([]*Monster, error) {
|
func All(db *database.DB) ([]*Monster, error) {
|
||||||
var monsters []*Monster
|
var monsters []*Monster
|
||||||
|
|
||||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters ORDER BY level, id"
|
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters ORDER BY level, id"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
monster := &Monster{
|
monster := &Monster{
|
||||||
@ -79,18 +80,18 @@ func All(db *database.DB) ([]*Monster, error) {
|
|||||||
monsters = append(monsters, monster)
|
monsters = append(monsters, monster)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve all monsters: %w", err)
|
return nil, fmt.Errorf("failed to retrieve all monsters: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return monsters, nil
|
return monsters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByLevel retrieves monsters by level
|
// ByLevel retrieves monsters by level
|
||||||
func ByLevel(db *database.DB, level int) ([]*Monster, error) {
|
func ByLevel(db *database.DB, level int) ([]*Monster, error) {
|
||||||
var monsters []*Monster
|
var monsters []*Monster
|
||||||
|
|
||||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE level = ? ORDER BY id"
|
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE level = ? ORDER BY id"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
monster := &Monster{
|
monster := &Monster{
|
||||||
@ -108,18 +109,18 @@ func ByLevel(db *database.DB, level int) ([]*Monster, error) {
|
|||||||
monsters = append(monsters, monster)
|
monsters = append(monsters, monster)
|
||||||
return nil
|
return nil
|
||||||
}, level)
|
}, level)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve monsters by level: %w", err)
|
return nil, fmt.Errorf("failed to retrieve monsters by level: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return monsters, nil
|
return monsters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByLevelRange retrieves monsters within a level range (inclusive)
|
// ByLevelRange retrieves monsters within a level range (inclusive)
|
||||||
func ByLevelRange(db *database.DB, minLevel, maxLevel int) ([]*Monster, error) {
|
func ByLevelRange(db *database.DB, minLevel, maxLevel int) ([]*Monster, error) {
|
||||||
var monsters []*Monster
|
var monsters []*Monster
|
||||||
|
|
||||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE level BETWEEN ? AND ? ORDER BY level, id"
|
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE level BETWEEN ? AND ? ORDER BY level, id"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
monster := &Monster{
|
monster := &Monster{
|
||||||
@ -137,18 +138,18 @@ func ByLevelRange(db *database.DB, minLevel, maxLevel int) ([]*Monster, error) {
|
|||||||
monsters = append(monsters, monster)
|
monsters = append(monsters, monster)
|
||||||
return nil
|
return nil
|
||||||
}, minLevel, maxLevel)
|
}, minLevel, maxLevel)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve monsters by level range: %w", err)
|
return nil, fmt.Errorf("failed to retrieve monsters by level range: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return monsters, nil
|
return monsters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByImmunity retrieves monsters by immunity type
|
// ByImmunity retrieves monsters by immunity type
|
||||||
func ByImmunity(db *database.DB, immunityType int) ([]*Monster, error) {
|
func ByImmunity(db *database.DB, immunityType int) ([]*Monster, error) {
|
||||||
var monsters []*Monster
|
var monsters []*Monster
|
||||||
|
|
||||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE immune = ? ORDER BY level, id"
|
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE immune = ? ORDER BY level, id"
|
||||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||||
monster := &Monster{
|
monster := &Monster{
|
||||||
@ -166,129 +167,20 @@ func ByImmunity(db *database.DB, immunityType int) ([]*Monster, error) {
|
|||||||
monsters = append(monsters, monster)
|
monsters = append(monsters, monster)
|
||||||
return nil
|
return nil
|
||||||
}, immunityType)
|
}, immunityType)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve monsters by immunity: %w", err)
|
return nil, fmt.Errorf("failed to retrieve monsters by immunity: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return monsters, nil
|
return monsters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builder provides a fluent interface for creating monsters
|
|
||||||
type Builder struct {
|
|
||||||
monster *Monster
|
|
||||||
db *database.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBuilder creates a new monster builder
|
|
||||||
func NewBuilder(db *database.DB) *Builder {
|
|
||||||
return &Builder{
|
|
||||||
monster: &Monster{db: db},
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithName sets the monster name
|
|
||||||
func (b *Builder) WithName(name string) *Builder {
|
|
||||||
b.monster.Name = name
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxHP sets the monster's maximum hit points
|
|
||||||
func (b *Builder) WithMaxHP(maxHP int) *Builder {
|
|
||||||
b.monster.MaxHP = maxHP
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxDmg sets the monster's maximum damage
|
|
||||||
func (b *Builder) WithMaxDmg(maxDmg int) *Builder {
|
|
||||||
b.monster.MaxDmg = maxDmg
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithArmor sets the monster's armor value
|
|
||||||
func (b *Builder) WithArmor(armor int) *Builder {
|
|
||||||
b.monster.Armor = armor
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLevel sets the monster's level
|
|
||||||
func (b *Builder) WithLevel(level int) *Builder {
|
|
||||||
b.monster.Level = level
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxExp sets the monster's maximum experience reward
|
|
||||||
func (b *Builder) WithMaxExp(maxExp int) *Builder {
|
|
||||||
b.monster.MaxExp = maxExp
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxGold sets the monster's maximum gold reward
|
|
||||||
func (b *Builder) WithMaxGold(maxGold int) *Builder {
|
|
||||||
b.monster.MaxGold = maxGold
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithImmunity sets the monster's immunity type
|
|
||||||
func (b *Builder) WithImmunity(immunity int) *Builder {
|
|
||||||
b.monster.Immune = immunity
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create saves the monster to the database and returns it
|
|
||||||
func (b *Builder) Create() (*Monster, error) {
|
|
||||||
// Use a transaction to ensure we can get the ID
|
|
||||||
var monster *Monster
|
|
||||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
|
||||||
query := `INSERT INTO monsters (name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
||||||
|
|
||||||
if err := tx.Exec(query, b.monster.Name, b.monster.MaxHP, b.monster.MaxDmg, b.monster.Armor,
|
|
||||||
b.monster.Level, b.monster.MaxExp, b.monster.MaxGold, b.monster.Immune); err != nil {
|
|
||||||
return fmt.Errorf("failed to insert monster: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the last inserted ID within the same transaction
|
|
||||||
var lastID int
|
|
||||||
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
|
||||||
lastID = stmt.ColumnInt(0)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get last insert ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the monster with the ID
|
|
||||||
monster = &Monster{
|
|
||||||
ID: lastID,
|
|
||||||
Name: b.monster.Name,
|
|
||||||
MaxHP: b.monster.MaxHP,
|
|
||||||
MaxDmg: b.monster.MaxDmg,
|
|
||||||
Armor: b.monster.Armor,
|
|
||||||
Level: b.monster.Level,
|
|
||||||
MaxExp: b.monster.MaxExp,
|
|
||||||
MaxGold: b.monster.MaxGold,
|
|
||||||
Immune: b.monster.Immune,
|
|
||||||
db: b.db,
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create monster: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return monster, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save updates an existing monster in the database
|
// Save updates an existing monster in the database
|
||||||
func (m *Monster) Save() error {
|
func (m *Monster) Save() error {
|
||||||
if m.ID == 0 {
|
if m.ID == 0 {
|
||||||
return fmt.Errorf("cannot save monster without ID")
|
return fmt.Errorf("cannot save monster without ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `UPDATE monsters SET name = ?, max_hp = ?, max_dmg = ?, armor = ?, level = ?, max_exp = ?, max_gold = ?, immune = ? WHERE id = ?`
|
query := `UPDATE monsters SET name = ?, max_hp = ?, max_dmg = ?, armor = ?, level = ?, max_exp = ?, max_gold = ?, immune = ? WHERE id = ?`
|
||||||
return m.db.Exec(query, m.Name, m.MaxHP, m.MaxDmg, m.Armor, m.Level, m.MaxExp, m.MaxGold, m.Immune, m.ID)
|
return m.db.Exec(query, m.Name, m.MaxHP, m.MaxDmg, m.Armor, m.Level, m.MaxExp, m.MaxGold, m.Immune, m.ID)
|
||||||
}
|
}
|
||||||
@ -298,7 +190,7 @@ func (m *Monster) Delete() error {
|
|||||||
if m.ID == 0 {
|
if m.ID == 0 {
|
||||||
return fmt.Errorf("cannot delete monster without ID")
|
return fmt.Errorf("cannot delete monster without ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
query := "DELETE FROM monsters WHERE id = ?"
|
query := "DELETE FROM monsters WHERE id = ?"
|
||||||
return m.db.Exec(query, m.ID)
|
return m.db.Exec(query, m.ID)
|
||||||
}
|
}
|
||||||
@ -356,4 +248,4 @@ func (m *Monster) GoldPerHP() float64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return float64(m.MaxGold) / float64(m.MaxHP)
|
return float64(m.MaxGold) / float64(m.MaxHP)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user