203 lines
5.0 KiB
Go

package control
import (
"fmt"
"dk/internal/database"
"zombiezen.com/go/sqlite"
)
// Control represents the game control settings in the database
// There is only ever one control record with ID 1
type Control struct {
ID int `json:"id"`
WorldSize int `json:"world_size"`
Open int `json:"open"`
AdminEmail string `json:"admin_email"`
Class1Name string `json:"class_1_name"`
Class2Name string `json:"class_2_name"`
Class3Name string `json:"class_3_name"`
db *database.DB
}
// Find retrieves the control record by ID (typically only ID 1 exists)
func Find(db *database.DB, id int) (*Control, error) {
control := &Control{db: db}
query := "SELECT id, world_size, open, admin_email, class_1_name, class_2_name, class_3_name FROM control WHERE id = ?"
err := db.Query(query, func(stmt *sqlite.Stmt) error {
control.ID = stmt.ColumnInt(0)
control.WorldSize = stmt.ColumnInt(1)
control.Open = stmt.ColumnInt(2)
control.AdminEmail = stmt.ColumnText(3)
control.Class1Name = stmt.ColumnText(4)
control.Class2Name = stmt.ColumnText(5)
control.Class3Name = stmt.ColumnText(6)
return nil
}, id)
if err != nil {
return nil, fmt.Errorf("failed to find control: %w", err)
}
if control.ID == 0 {
return nil, fmt.Errorf("control with ID %d not found", id)
}
return control, nil
}
// Get retrieves the main control record (ID 1)
func Get(db *database.DB) (*Control, error) {
return Find(db, 1)
}
// Save updates the control record in the database
func (c *Control) Save() error {
if c.ID == 0 {
return fmt.Errorf("cannot save control without ID")
}
query := `UPDATE control SET world_size = ?, open = ?, admin_email = ?, class_1_name = ?, class_2_name = ?, class_3_name = ? WHERE id = ?`
return c.db.Exec(query, c.WorldSize, c.Open, c.AdminEmail, c.Class1Name, c.Class2Name, c.Class3Name, c.ID)
}
// IsOpen returns true if the game world is open for new players
func (c *Control) IsOpen() bool {
return c.Open == 1
}
// SetOpen sets whether the game world is open for new players
func (c *Control) SetOpen(open bool) {
if open {
c.Open = 1
} else {
c.Open = 0
}
}
// Close closes the game world to new players
func (c *Control) Close() {
c.Open = 0
}
// OpenWorld opens the game world to new players
func (c *Control) OpenWorld() {
c.Open = 1
}
// GetClassNames returns all class names as a slice
func (c *Control) GetClassNames() []string {
classes := make([]string, 0, 3)
if c.Class1Name != "" {
classes = append(classes, c.Class1Name)
}
if c.Class2Name != "" {
classes = append(classes, c.Class2Name)
}
if c.Class3Name != "" {
classes = append(classes, c.Class3Name)
}
return classes
}
// SetClassNames sets all class names from a slice
func (c *Control) SetClassNames(classes []string) {
// Reset all class names
c.Class1Name = ""
c.Class2Name = ""
c.Class3Name = ""
// Set provided class names
if len(classes) > 0 {
c.Class1Name = classes[0]
}
if len(classes) > 1 {
c.Class2Name = classes[1]
}
if len(classes) > 2 {
c.Class3Name = classes[2]
}
}
// GetClassName returns the name of a specific class (1-3)
func (c *Control) GetClassName(classNum int) string {
switch classNum {
case 1:
return c.Class1Name
case 2:
return c.Class2Name
case 3:
return c.Class3Name
default:
return ""
}
}
// SetClassName sets the name of a specific class (1-3)
func (c *Control) SetClassName(classNum int, name string) bool {
switch classNum {
case 1:
c.Class1Name = name
return true
case 2:
c.Class2Name = name
return true
case 3:
c.Class3Name = name
return true
default:
return false
}
}
// IsValidClassName returns true if the given name matches one of the configured classes
func (c *Control) IsValidClassName(name string) bool {
if name == "" {
return false
}
return name == c.Class1Name || name == c.Class2Name || name == c.Class3Name
}
// GetClassNumber returns the class number (1-3) for a given class name, or 0 if not found
func (c *Control) GetClassNumber(name string) int {
if name == c.Class1Name && name != "" {
return 1
}
if name == c.Class2Name && name != "" {
return 2
}
if name == c.Class3Name && name != "" {
return 3
}
return 0
}
// HasAdminEmail returns true if an admin email is configured
func (c *Control) HasAdminEmail() bool {
return c.AdminEmail != ""
}
// IsWorldSizeValid returns true if the world size is within reasonable bounds
func (c *Control) IsWorldSizeValid() bool {
return c.WorldSize > 0 && c.WorldSize <= 10000
}
// GetWorldRadius returns the world radius (half the world size)
func (c *Control) GetWorldRadius() int {
return c.WorldSize / 2
}
// IsWithinWorldBounds returns true if the given coordinates are within world bounds
func (c *Control) IsWithinWorldBounds(x, y int) bool {
radius := c.GetWorldRadius()
return x >= -radius && x <= radius && y >= -radius && y <= radius
}
// GetWorldBounds returns the minimum and maximum coordinates for the world
func (c *Control) GetWorldBounds() (minX, minY, maxX, maxY int) {
radius := c.GetWorldRadius()
return -radius, -radius, radius, radius
}