diff options
Diffstat (limited to 'internal/game/craft_index.go')
| -rw-r--r-- | internal/game/craft_index.go | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/internal/game/craft_index.go b/internal/game/craft_index.go new file mode 100644 index 0000000..078ec3c --- /dev/null +++ b/internal/game/craft_index.go @@ -0,0 +1,234 @@ +package game + +import ( + "sync" + + "thehouseoficarus/internal/object" +) + +type CraftIndex struct { + mu sync.RWMutex + byType map[string][]*object.ItemDef + byInput map[string][]*object.ItemDef + byStation map[string][]*object.ItemDef +} + +func NewCraftIndex() *CraftIndex { + return &CraftIndex{ + byType: make(map[string][]*object.ItemDef), + byInput: make(map[string][]*object.ItemDef), + byStation: make(map[string][]*object.ItemDef), + } +} + +func (idx *CraftIndex) Build(items []*object.ItemDef) { + idx.mu.Lock() + defer idx.mu.Unlock() + + idx.byType = make(map[string][]*object.ItemDef) + idx.byInput = make(map[string][]*object.ItemDef) + idx.byStation = make(map[string][]*object.ItemDef) + + for _, def := range items { + if len(def.Craft) == 0 { + continue + } + for ci := range def.Craft { + craft := &def.Craft[ci] + t := craft.Type + if t == "" { + t = "combine" + } + idx.byType[t] = appendUnique(idx.byType[t], def) + + for _, e := range craft.Consume { + for _, id := range e.Items { + idx.byInput[id] = appendUnique(idx.byInput[id], def) + } + } + + for _, sid := range craft.Station { + idx.byStation[sid] = appendUnique(idx.byStation[sid], def) + } + } + } +} + +func appendUnique(items []*object.ItemDef, item *object.ItemDef) []*object.ItemDef { + for _, existing := range items { + if existing == item { + return items + } + } + return append(items, item) +} + +func (idx *CraftIndex) ByType(craftType string) []*object.ItemDef { + idx.mu.RLock() + defer idx.mu.RUnlock() + items := idx.byType[craftType] + out := make([]*object.ItemDef, len(items)) + copy(out, items) + return out +} + +func (idx *CraftIndex) ByStation(stationDefID string) []*object.ItemDef { + idx.mu.RLock() + defer idx.mu.RUnlock() + items := idx.byStation[stationDefID] + out := make([]*object.ItemDef, len(items)) + copy(out, items) + return out +} + +func (idx *CraftIndex) ByInput(itemID string) []*object.ItemDef { + idx.mu.RLock() + defer idx.mu.RUnlock() + items := idx.byInput[itemID] + out := make([]*object.ItemDef, len(items)) + copy(out, items) + return out +} + +func (idx *CraftIndex) FindByTwoInputs(itemA, itemB string) []*object.ItemDef { + idx.mu.RLock() + defer idx.mu.RUnlock() + + candidatesA := idx.byInput[itemA] + if len(candidatesA) == 0 { + return nil + } + + candidateSetB := make(map[string]bool) + for _, def := range idx.byInput[itemB] { + candidateSetB[def.ID] = true + } + + var results []*object.ItemDef + for _, def := range candidatesA { + if !candidateSetB[def.ID] { + continue + } + for _, craft := range def.Craft { + entryA := craftEntry(craft, itemA) + entryB := craftEntry(craft, itemB) + if entryA >= 0 && entryB >= 0 && entryA != entryB { + results = append(results, def) + break + } + } + } + return results +} + +func (idx *CraftIndex) FindByStationInput(stationDefID, itemID string) []*object.ItemDef { + idx.mu.RLock() + defer idx.mu.RUnlock() + + var results []*object.ItemDef + for _, def := range idx.byStation[stationDefID] { + for _, craft := range def.Craft { + if craftMatchesEntry(&craft, itemID) { + results = append(results, def) + break + } + } + } + return results +} + +func craftEntryFor(def *object.ItemDef, itemID string) int { + for _, craft := range def.Craft { + if ei := craftEntry(craft, itemID); ei >= 0 { + return ei + } + } + return -1 +} + +func craftEntry(craft object.CraftDef, itemID string) int { + for ei, e := range craft.Consume { + for _, id := range e.Items { + if id == itemID { + return ei + } + } + } + return -1 +} + +func craftMatchesEntry(c *object.CraftDef, itemID string) bool { + if c == nil { + return false + } + for _, e := range c.Consume { + for _, id := range e.Items { + if id == itemID { + return true + } + } + } + return false +} + +func craftHasAllItems(c *object.CraftDef, hasItem func(string) bool) bool { + if c == nil { + return false + } + for _, e := range c.Consume { + found := false + for _, id := range e.Items { + if hasItem(id) { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +func craftHasAllItemsQty(c *object.CraftDef, countItem func(string) int) bool { + if c == nil { + return false + } + for _, e := range c.Consume { + found := false + for _, id := range e.Items { + qty := e.Quantity + if qty <= 0 { + qty = 1 + } + if countItem(id) >= qty { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +func craftConsumeAll(c *object.CraftDef, hasItem func(string) bool, removeItem func(string, int) bool) bool { + if c == nil { + return false + } + for _, e := range c.Consume { + found := false + for _, id := range e.Items { + if hasItem(id) { + removeItem(id, e.Quantity) + found = true + break + } + } + if !found { + return false + } + } + return true +} |
