aboutsummaryrefslogtreecommitdiff
path: root/internal/game/sys_science.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/sys_science.go')
-rw-r--r--internal/game/sys_science.go220
1 files changed, 220 insertions, 0 deletions
diff --git a/internal/game/sys_science.go b/internal/game/sys_science.go
new file mode 100644
index 0000000..23aeef4
--- /dev/null
+++ b/internal/game/sys_science.go
@@ -0,0 +1,220 @@
+package game
+
+import (
+ "fmt"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "gopkg.in/yaml.v3"
+
+ "thehouseoficarus/internal/action"
+ "thehouseoficarus/internal/object"
+ "thehouseoficarus/internal/player"
+)
+
+type ModCategory string
+
+const (
+ ModCombat ModCategory = "combat"
+ ModUtility ModCategory = "utility"
+ ModEnchant ModCategory = "enchant"
+ ModProcessing ModCategory = "processing"
+ ModTransport ModCategory = "transport"
+)
+
+type ModDef struct {
+ ID string `yaml:"id"`
+ Name string `yaml:"name"`
+ Level int `yaml:"level"`
+ MaxHit int `yaml:"max_hit"`
+ BaseXP int `yaml:"base_xp"`
+ JunkCost map[string]int `yaml:"junk_cost"`
+ Category ModCategory `yaml:"category"`
+ Element string `yaml:"element"`
+ Destination int `yaml:"destination"`
+}
+
+var AllMods []*ModDef
+
+var modByID map[string]*ModDef
+
+func (g *Game) LoadMods() error {
+ dir := filepath.Join(g.DataDir, "modules")
+ AllMods = nil
+ modByID = make(map[string]*ModDef)
+ action.WalkYAMLDir(dir, func(path, id string, data []byte) error {
+ var m ModDef
+ if err := yaml.Unmarshal(data, &m); err != nil {
+ return nil
+ }
+ AllMods = append(AllMods, &m)
+ return nil
+ })
+ modByID = make(map[string]*ModDef, len(AllMods))
+ for _, m := range AllMods {
+ modByID[m.ID] = m
+ }
+ return nil
+}
+
+func GetMod(id string) *ModDef {
+ return modByID[id]
+}
+
+func FindMod(input string) *ModDef {
+ if m, ok := modByID[input]; ok {
+ return m
+ }
+ lower := strings.ToLower(strings.ReplaceAll(input, " ", "_"))
+ for _, m := range AllMods {
+ if strings.HasPrefix(m.ID, lower) {
+ return m
+ }
+ }
+ lowerSpace := strings.ToLower(input)
+ for _, m := range AllMods {
+ if strings.HasPrefix(strings.ToLower(m.Name), lowerSpace) {
+ return m
+ }
+ }
+ return nil
+}
+
+type chipEntry struct {
+ Input string
+ Output string
+ Qty int
+}
+
+var enchantMap = map[string]map[string]string{
+ "enchant_1": {
+ "sapphire_ring": "ring_of_recoil",
+ "sapphire_necklace": "necklace_of_passage",
+ "sapphire_bracelet": "bracelet_of_clay",
+ },
+ "enchant_2": {
+ "emerald_ring": "ring_of_dueling",
+ "emerald_necklace": "binding_necklace",
+ "emerald_bracelet": "bracelet_of_slaughter",
+ },
+ "enchant_3": {
+ "ruby_ring": "ring_of_forging",
+ "ruby_necklace": "digsite_pendant",
+ "ruby_bracelet": "inoculation_bracelet",
+ },
+ "enchant_4": {
+ "diamond_ring": "ring_of_life",
+ "diamond_necklace": "phoenix_necklace",
+ "diamond_bracelet": "abyssal_bracelet",
+ },
+}
+
+var chipMap = map[string]chipEntry{
+ "chip_sapphire": {"sapphire_bolts", "sapphire_bolts_e", 10},
+ "chip_emerald": {"emerald_bolts", "emerald_bolts_e", 10},
+ "chip_ruby": {"ruby_bolts", "ruby_bolts_e", 10},
+ "chip_diamond": {"diamond_bolts", "diamond_bolts_e", 10},
+}
+
+func (g *Game) hasDeckEquipped(p *player.Player) bool {
+ itemID, ok := p.Equipment[object.SlotMainHand]
+ if !ok {
+ return false
+ }
+ def, err := g.ItemStore.Load(itemID)
+ if err != nil {
+ return false
+ }
+ return def.WeaponType == object.WeaponScience
+}
+
+func (g *Game) equippedProvidesJunk(p *player.Player) string {
+ itemID, ok := p.Equipment[object.SlotMainHand]
+ if !ok {
+ return ""
+ }
+ def, err := g.ItemStore.Load(itemID)
+ if err != nil {
+ return ""
+ }
+ return def.ProvidesJunk
+}
+
+func (g *Game) effectiveJunkCost(p *player.Player, mod *ModDef) map[string]int {
+ cost := make(map[string]int)
+ for k, v := range mod.JunkCost {
+ cost[k] = v
+ }
+
+ hasDeck := g.hasDeckEquipped(p)
+
+ if hasDeck {
+ delete(cost, "scrap_metal")
+ }
+
+ providesJunk := g.equippedProvidesJunk(p)
+ if providesJunk != "" {
+ delete(cost, providesJunk)
+ }
+
+ return cost
+}
+
+func (g *Game) hasJunkCost(p *player.Player, mod *ModDef) bool {
+ cost := g.effectiveJunkCost(p, mod)
+ for itemID, qty := range cost {
+ if p.CountItem(itemID) < qty {
+ return false
+ }
+ }
+ return true
+}
+
+func (g *Game) consumeJunkCost(p *player.Player, mod *ModDef) bool {
+ cost := g.effectiveJunkCost(p, mod)
+ for itemID, qty := range cost {
+ if !p.RemoveItem(itemID, qty) {
+ return false
+ }
+ }
+ g.AccountStore.SaveCharacter(p)
+ return true
+}
+
+func (g *Game) junkCostString(p *player.Player, mod *ModDef) string {
+ cost := g.effectiveJunkCost(p, mod)
+ delete(cost, "scrap_metal")
+ if len(cost) == 0 {
+ return "free"
+ }
+ var parts []string
+ for itemID, qty := range cost {
+ def, _ := g.ItemStore.Load(itemID)
+ name := itemID
+ if def != nil {
+ name = def.Name
+ }
+ name = strings.TrimSuffix(name, "junk")
+ if qty > 1 {
+ parts = append(parts, fmt.Sprintf("%d %s", qty, name))
+ } else {
+ parts = append(parts, name)
+ }
+ }
+ sort.Strings(parts)
+ return strings.Join(parts, ", ")
+}
+
+func (g *Game) totalEquipScienceAttack(p *player.Player) int {
+ total := 0
+ for _, itemID := range p.Equipment {
+ def, err := g.ItemStore.Load(itemID)
+ if err == nil {
+ total += def.Stats.ScienceAttack
+ }
+ }
+ return total
+}
+
+