235 lines
7.0 KiB
Go
235 lines
7.0 KiB
Go
package users
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"dk/internal/database"
|
|
|
|
"zombiezen.com/go/sqlite"
|
|
)
|
|
|
|
// Builder provides a fluent interface for creating users
|
|
type Builder struct {
|
|
user *User
|
|
db *database.DB
|
|
}
|
|
|
|
// NewBuilder creates a new user builder with default values
|
|
func NewBuilder(db *database.DB) *Builder {
|
|
now := time.Now().Unix()
|
|
return &Builder{
|
|
user: &User{
|
|
db: db,
|
|
Verified: 0, // Default unverified
|
|
Token: "", // Empty verification token
|
|
Registered: now, // Current time
|
|
LastOnline: now, // Current time
|
|
Auth: 0, // Default no special permissions
|
|
X: 0, // Default starting position
|
|
Y: 0, // Default starting position
|
|
ClassID: 1, // Default to class 1
|
|
Currently: "In Town", // Default status
|
|
Fighting: 0, // Default not fighting
|
|
HP: 15, // Default starting HP
|
|
MP: 0, // Default starting MP
|
|
TP: 10, // Default starting TP
|
|
MaxHP: 15, // Default starting max HP
|
|
MaxMP: 0, // Default starting max MP
|
|
MaxTP: 10, // Default starting max TP
|
|
Level: 1, // Default starting level
|
|
Gold: 100, // Default starting gold
|
|
Exp: 0, // Default starting exp
|
|
Strength: 5, // Default starting strength
|
|
Dexterity: 5, // Default starting dexterity
|
|
Attack: 5, // Default starting attack
|
|
Defense: 5, // Default starting defense
|
|
Spells: "", // No spells initially
|
|
Towns: "", // No towns visited initially
|
|
},
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// WithUsername sets the username
|
|
func (b *Builder) WithUsername(username string) *Builder {
|
|
b.user.Username = username
|
|
return b
|
|
}
|
|
|
|
// WithPassword sets the password
|
|
func (b *Builder) WithPassword(password string) *Builder {
|
|
b.user.Password = password
|
|
return b
|
|
}
|
|
|
|
// WithEmail sets the email address
|
|
func (b *Builder) WithEmail(email string) *Builder {
|
|
b.user.Email = email
|
|
return b
|
|
}
|
|
|
|
// WithVerified sets the verification status
|
|
func (b *Builder) WithVerified(verified bool) *Builder {
|
|
if verified {
|
|
b.user.Verified = 1
|
|
} else {
|
|
b.user.Verified = 0
|
|
}
|
|
return b
|
|
}
|
|
|
|
// WithToken sets the verification token
|
|
func (b *Builder) WithToken(token string) *Builder {
|
|
b.user.Token = token
|
|
return b
|
|
}
|
|
|
|
// WithAuth sets the authorization level
|
|
func (b *Builder) WithAuth(auth int) *Builder {
|
|
b.user.Auth = auth
|
|
return b
|
|
}
|
|
|
|
// AsAdmin sets the user as admin (auth = 4)
|
|
func (b *Builder) AsAdmin() *Builder {
|
|
b.user.Auth = 4
|
|
return b
|
|
}
|
|
|
|
// AsModerator sets the user as moderator (auth = 2)
|
|
func (b *Builder) AsModerator() *Builder {
|
|
b.user.Auth = 2
|
|
return b
|
|
}
|
|
|
|
// WithClassID sets the character class ID
|
|
func (b *Builder) WithClassID(classID int) *Builder {
|
|
b.user.ClassID = classID
|
|
return b
|
|
}
|
|
|
|
// WithPosition sets the starting coordinates
|
|
func (b *Builder) WithPosition(x, y int) *Builder {
|
|
b.user.X = x
|
|
b.user.Y = y
|
|
return b
|
|
}
|
|
|
|
// WithLevel sets the starting level
|
|
func (b *Builder) WithLevel(level int) *Builder {
|
|
b.user.Level = level
|
|
return b
|
|
}
|
|
|
|
// WithGold sets the starting gold amount
|
|
func (b *Builder) WithGold(gold int) *Builder {
|
|
b.user.Gold = gold
|
|
return b
|
|
}
|
|
|
|
// WithStats sets the core character stats
|
|
func (b *Builder) WithStats(strength, dexterity, attack, defense int) *Builder {
|
|
b.user.Strength = strength
|
|
b.user.Dexterity = dexterity
|
|
b.user.Attack = attack
|
|
b.user.Defense = defense
|
|
return b
|
|
}
|
|
|
|
// WithHP sets current and maximum HP
|
|
func (b *Builder) WithHP(hp, maxHP int) *Builder {
|
|
b.user.HP = hp
|
|
b.user.MaxHP = maxHP
|
|
return b
|
|
}
|
|
|
|
// WithMP sets current and maximum MP
|
|
func (b *Builder) WithMP(mp, maxMP int) *Builder {
|
|
b.user.MP = mp
|
|
b.user.MaxMP = maxMP
|
|
return b
|
|
}
|
|
|
|
// WithTP sets current and maximum TP
|
|
func (b *Builder) WithTP(tp, maxTP int) *Builder {
|
|
b.user.TP = tp
|
|
b.user.MaxTP = maxTP
|
|
return b
|
|
}
|
|
|
|
// WithCurrently sets the current status message
|
|
func (b *Builder) WithCurrently(currently string) *Builder {
|
|
b.user.Currently = currently
|
|
return b
|
|
}
|
|
|
|
// WithRegistered sets the registration timestamp
|
|
func (b *Builder) WithRegistered(registered int64) *Builder {
|
|
b.user.Registered = registered
|
|
return b
|
|
}
|
|
|
|
// WithRegisteredTime sets the registration timestamp from time.Time
|
|
func (b *Builder) WithRegisteredTime(t time.Time) *Builder {
|
|
b.user.Registered = t.Unix()
|
|
return b
|
|
}
|
|
|
|
// WithSpells sets the user's known spells
|
|
func (b *Builder) WithSpells(spells []string) *Builder {
|
|
b.user.SetSpellIDs(spells)
|
|
return b
|
|
}
|
|
|
|
// WithTowns sets the user's visited towns
|
|
func (b *Builder) WithTowns(towns []string) *Builder {
|
|
b.user.SetTownIDs(towns)
|
|
return b
|
|
}
|
|
|
|
// Create saves the user to the database and returns the created user with ID
|
|
func (b *Builder) Create() (*User, error) {
|
|
// Use a transaction to ensure we can get the ID
|
|
var user *User
|
|
err := b.db.Transaction(func(tx *database.Tx) error {
|
|
query := `INSERT INTO users (username, password, email, verified, token, registered, last_online, auth,
|
|
x, y, class_id, currently, fighting, monster_id, monster_hp, monster_sleep, monster_immune,
|
|
uber_damage, uber_defense, hp, mp, tp, max_hp, max_mp, max_tp, level, gold, exp,
|
|
gold_bonus, exp_bonus, strength, dexterity, attack, defense, weapon_id, armor_id, shield_id,
|
|
slot_1_id, slot_2_id, slot_3_id, weapon_name, armor_name, shield_name,
|
|
slot_1_name, slot_2_name, slot_3_name, drop_code, spells, towns)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
|
|
if err := tx.Exec(query, b.user.Username, b.user.Password, b.user.Email, b.user.Verified, b.user.Token,
|
|
b.user.Registered, b.user.LastOnline, b.user.Auth, b.user.X, b.user.Y, b.user.ClassID, b.user.Currently,
|
|
b.user.Fighting, b.user.MonsterID, b.user.MonsterHP, b.user.MonsterSleep, b.user.MonsterImmune,
|
|
b.user.UberDamage, b.user.UberDefense, b.user.HP, b.user.MP, b.user.TP, b.user.MaxHP, b.user.MaxMP, b.user.MaxTP,
|
|
b.user.Level, b.user.Gold, b.user.Exp, b.user.GoldBonus, b.user.ExpBonus, b.user.Strength, b.user.Dexterity,
|
|
b.user.Attack, b.user.Defense, b.user.WeaponID, b.user.ArmorID, b.user.ShieldID, b.user.Slot1ID,
|
|
b.user.Slot2ID, b.user.Slot3ID, b.user.WeaponName, b.user.ArmorName, b.user.ShieldName,
|
|
b.user.Slot1Name, b.user.Slot2Name, b.user.Slot3Name, b.user.DropCode, b.user.Spells, b.user.Towns); err != nil {
|
|
return fmt.Errorf("failed to insert user: %w", err)
|
|
}
|
|
|
|
// Get the last insert ID
|
|
var id int
|
|
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
|
id = stmt.ColumnInt(0)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get insert ID: %w", err)
|
|
}
|
|
|
|
b.user.ID = id
|
|
user = b.user
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return user, nil
|
|
} |