210 lines
4.3 KiB
Go
210 lines
4.3 KiB
Go
package monsters
|
|
|
|
import (
|
|
"dk/internal/store"
|
|
"fmt"
|
|
)
|
|
|
|
// Monster represents a monster in the game
|
|
type Monster struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
MaxHP int `json:"max_hp"`
|
|
MaxDmg int `json:"max_dmg"`
|
|
Armor int `json:"armor"`
|
|
Level int `json:"level"`
|
|
MaxExp int `json:"max_exp"`
|
|
MaxGold int `json:"max_gold"`
|
|
Immune int `json:"immune"`
|
|
}
|
|
|
|
func (m *Monster) Save() error {
|
|
return GetStore().UpdateWithRebuild(m.ID, m)
|
|
}
|
|
|
|
func (m *Monster) Delete() error {
|
|
GetStore().RemoveWithRebuild(m.ID)
|
|
return nil
|
|
}
|
|
|
|
// Creates a new Monster with sensible defaults
|
|
func New() *Monster {
|
|
return &Monster{
|
|
Name: "",
|
|
MaxHP: 10,
|
|
MaxDmg: 5,
|
|
Armor: 0,
|
|
Level: 1,
|
|
MaxExp: 10,
|
|
MaxGold: 5,
|
|
Immune: ImmuneNone,
|
|
}
|
|
}
|
|
|
|
// Validate checks if monster has valid values
|
|
func (m *Monster) Validate() error {
|
|
if m.Name == "" {
|
|
return fmt.Errorf("monster name cannot be empty")
|
|
}
|
|
if m.MaxHP < 1 {
|
|
return fmt.Errorf("monster MaxHP must be at least 1")
|
|
}
|
|
if m.Level < 1 {
|
|
return fmt.Errorf("monster Level must be at least 1")
|
|
}
|
|
if m.Immune < ImmuneNone || m.Immune > ImmuneSleep {
|
|
return fmt.Errorf("invalid immunity type: %d", m.Immune)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Immunity constants
|
|
const (
|
|
ImmuneNone = 0
|
|
ImmuneHurt = 1
|
|
ImmuneSleep = 2
|
|
)
|
|
|
|
// MonsterStore with enhanced BaseStore
|
|
type MonsterStore struct {
|
|
*store.BaseStore[Monster]
|
|
}
|
|
|
|
// Global store with singleton pattern
|
|
var GetStore = store.NewSingleton(func() *MonsterStore {
|
|
ms := &MonsterStore{BaseStore: store.NewBaseStore[Monster]()}
|
|
|
|
// Register indices
|
|
ms.RegisterIndex("byLevel", store.BuildIntGroupIndex(func(m *Monster) int {
|
|
return m.Level
|
|
}))
|
|
|
|
ms.RegisterIndex("byImmunity", store.BuildIntGroupIndex(func(m *Monster) int {
|
|
return m.Immune
|
|
}))
|
|
|
|
ms.RegisterIndex("allByLevel", store.BuildSortedListIndex(func(a, b *Monster) bool {
|
|
if a.Level == b.Level {
|
|
return a.ID < b.ID
|
|
}
|
|
return a.Level < b.Level
|
|
}))
|
|
|
|
return ms
|
|
})
|
|
|
|
// Enhanced CRUD operations
|
|
func (ms *MonsterStore) AddMonster(monster *Monster) error {
|
|
return ms.AddWithRebuild(monster.ID, monster)
|
|
}
|
|
|
|
func (ms *MonsterStore) RemoveMonster(id int) {
|
|
ms.RemoveWithRebuild(id)
|
|
}
|
|
|
|
func (ms *MonsterStore) UpdateMonster(monster *Monster) error {
|
|
return ms.UpdateWithRebuild(monster.ID, monster)
|
|
}
|
|
|
|
// Data persistence
|
|
func LoadData(dataPath string) error {
|
|
ms := GetStore()
|
|
return ms.BaseStore.LoadData(dataPath)
|
|
}
|
|
|
|
func SaveData(dataPath string) error {
|
|
ms := GetStore()
|
|
return ms.BaseStore.SaveData(dataPath)
|
|
}
|
|
|
|
// Query functions using enhanced store
|
|
func Find(id int) (*Monster, error) {
|
|
ms := GetStore()
|
|
monster, exists := ms.Find(id)
|
|
if !exists {
|
|
return nil, fmt.Errorf("monster with ID %d not found", id)
|
|
}
|
|
return monster, nil
|
|
}
|
|
|
|
func All() ([]*Monster, error) {
|
|
ms := GetStore()
|
|
return ms.AllSorted("allByLevel"), nil
|
|
}
|
|
|
|
func ByLevel(level int) ([]*Monster, error) {
|
|
ms := GetStore()
|
|
return ms.GroupByIndex("byLevel", level), nil
|
|
}
|
|
|
|
func ByLevelRange(minLevel, maxLevel int) ([]*Monster, error) {
|
|
ms := GetStore()
|
|
var result []*Monster
|
|
for level := minLevel; level <= maxLevel; level++ {
|
|
monsters := ms.GroupByIndex("byLevel", level)
|
|
result = append(result, monsters...)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func ByImmunity(immunityType int) ([]*Monster, error) {
|
|
ms := GetStore()
|
|
return ms.GroupByIndex("byImmunity", immunityType), nil
|
|
}
|
|
|
|
// Insert with ID assignment
|
|
func (m *Monster) Insert() error {
|
|
ms := GetStore()
|
|
if m.ID == 0 {
|
|
m.ID = ms.GetNextID()
|
|
}
|
|
return ms.AddMonster(m)
|
|
}
|
|
|
|
// Helper methods
|
|
func (m *Monster) IsHurtImmune() bool {
|
|
return m.Immune == ImmuneHurt
|
|
}
|
|
|
|
func (m *Monster) IsSleepImmune() bool {
|
|
return m.Immune == ImmuneSleep
|
|
}
|
|
|
|
func (m *Monster) HasImmunity() bool {
|
|
return m.Immune != ImmuneNone
|
|
}
|
|
|
|
func (m *Monster) ImmunityName() string {
|
|
switch m.Immune {
|
|
case ImmuneNone:
|
|
return "None"
|
|
case ImmuneHurt:
|
|
return "Hurt Spells"
|
|
case ImmuneSleep:
|
|
return "Sleep Spells"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
func (m *Monster) DifficultyRating() float64 {
|
|
if m.Level == 0 {
|
|
return 0
|
|
}
|
|
return float64(m.MaxHP+m.MaxDmg+m.Armor) / float64(m.Level)
|
|
}
|
|
|
|
func (m *Monster) ExpPerHP() float64 {
|
|
if m.MaxHP == 0 {
|
|
return 0
|
|
}
|
|
return float64(m.MaxExp) / float64(m.MaxHP)
|
|
}
|
|
|
|
func (m *Monster) GoldPerHP() float64 {
|
|
if m.MaxHP == 0 {
|
|
return 0
|
|
}
|
|
return float64(m.MaxGold) / float64(m.MaxHP)
|
|
}
|