aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_trigger_utility.go
diff options
context:
space:
mode:
authorworkhorse <workhorse@localhost.localdomain>2026-06-19 20:24:52 -0400
committerworkhorse <workhorse@localhost.localdomain>2026-06-19 20:24:52 -0400
commit8ee8982b8759bcae116647cc993867f4c8b0a6ce (patch)
treeee01f7b1d745cbc94d9981108a1209527487b3e5 /internal/game/cmd_trigger_utility.go
parent2bec24859af8f03c80a0a58e3240519942450167 (diff)
downloadthehouseoficarus-8ee8982b8759bcae116647cc993867f4c8b0a6ce.tar.gz
reorganized items, objects, and rooms in directories. oranized module names. added startup checks.
Diffstat (limited to 'internal/game/cmd_trigger_utility.go')
-rw-r--r--internal/game/cmd_trigger_utility.go397
1 files changed, 397 insertions, 0 deletions
diff --git a/internal/game/cmd_trigger_utility.go b/internal/game/cmd_trigger_utility.go
new file mode 100644
index 0000000..efb23e7
--- /dev/null
+++ b/internal/game/cmd_trigger_utility.go
@@ -0,0 +1,397 @@
+package game
+
+import (
+ "fmt"
+ "strings"
+
+ "thehouseoficarus/internal/combat"
+ "thehouseoficarus/internal/net"
+ "thehouseoficarus/internal/player"
+)
+
+func (g *Game) triggerUtility(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
+ switch mod.ID {
+ case "low_process", "high_process":
+ g.triggerProcessing(sess, p, mod, targetArg)
+ case "bones_to_nutrients":
+ g.triggerBonesToNutrients(sess, p, mod)
+ case "em_grab":
+ g.triggerEmGrab(sess, p, mod, targetArg)
+ case "superheat":
+ g.triggerSuperheat(sess, p, mod, targetArg)
+ case "plank_make":
+ g.triggerPlankMake(sess, p, mod, targetArg)
+ }
+}
+
+func (g *Game) triggerProcessing(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
+ if combat.GetCombat(p.Name) != nil {
+ sess.WriteLine("You can't do that during combat!")
+ return
+ }
+
+ if targetArg == "" {
+ sess.WriteLine(fmt.Sprintf("Usage: trigger %s <item>", strings.ReplaceAll(mod.ID, "_", " ")))
+ return
+ }
+
+ slot, inv := g.findInventoryItem(p, targetArg)
+ if slot < 0 {
+ sess.WriteLine("You don't have that item.")
+ return
+ }
+
+ itemDef, err := g.ItemStore.Load(inv.ItemID)
+ if err != nil || itemDef.Value <= 0 {
+ sess.WriteLine("That item has no value.")
+ return
+ }
+
+ if p.Action != nil {
+ g.cancelAction(p)
+ }
+
+ g.consumeJunkCost(p, mod)
+
+ creditValue := itemDef.Value
+ if mod.ID == "low_process" {
+ creditValue = itemDef.Value / 2
+ if creditValue < 1 {
+ creditValue = 1
+ }
+ }
+
+ if inv.Quantity > 1 {
+ inv.Quantity--
+ } else {
+ p.SetInvSlot(slot, nil)
+ }
+
+ p.Credits += creditValue
+
+ sciXP := mod.BaseXP
+ g.awardSkillXP(sess, p, player.Science, sciXP)
+ g.AccountStore.SaveCharacter(p)
+
+ sess.WriteLine(fmt.Sprintf("You process the %s. You receive %s credits.",
+ itemDef.Name, g.colorize(sess, "credits_pickup", fmt.Sprint(creditValue))))
+
+ if p.OptionBool("xp_drops") {
+ sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
+ }
+}
+
+func (g *Game) triggerBonesToNutrients(sess *net.Session, p *player.Player, mod *ModDef) {
+ if combat.GetCombat(p.Name) != nil {
+ sess.WriteLine("You can't do that during combat!")
+ return
+ }
+
+ boneCount := p.CountItem("bones")
+ if boneCount == 0 {
+ sess.WriteLine("You don't have any bones.")
+ return
+ }
+
+ if p.Action != nil {
+ g.cancelAction(p)
+ }
+
+ g.consumeJunkCost(p, mod)
+
+ for i := 0; i < 28; i++ {
+ slot := p.InvSlot(i)
+ if slot != nil && slot.ItemID == "bones" {
+ slot.ItemID = "nutrient_bar"
+ }
+ }
+
+ sciXP := mod.BaseXP * boneCount
+ g.awardSkillXP(sess, p, player.Science, sciXP)
+ g.AccountStore.SaveCharacter(p)
+
+ sess.WriteLine(fmt.Sprintf("You convert %d bones into nutrient bars.", boneCount))
+ if p.OptionBool("xp_drops") {
+ sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
+ }
+}
+
+func (g *Game) triggerEmGrab(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
+ if targetArg == "" {
+ sess.WriteLine("Grab what? Usage: trigger em grab <item>")
+ return
+ }
+
+ if p.FirstFreeSlot() < 0 {
+ sess.WriteLine("Your inventory is full.")
+ return
+ }
+
+ groundItems := g.World.GroundItems(p.RoomID)
+ var matchedID string
+ for itemID := range groundItems {
+ def, _ := g.ItemStore.Load(itemID)
+ if def != nil && def.MatchesName(targetArg) {
+ matchedID = itemID
+ break
+ }
+ if strings.HasPrefix(itemID, strings.ToLower(targetArg)) {
+ matchedID = itemID
+ break
+ }
+ }
+
+ if matchedID == "" {
+ sess.WriteLine("You don't see that here.")
+ return
+ }
+
+ if p.Action != nil {
+ g.cancelAction(p)
+ }
+
+ g.consumeJunkCost(p, mod)
+
+ qty := groundItems[matchedID]
+ g.World.RemoveGroundItem(p.RoomID, matchedID, qty)
+
+ def, _ := g.ItemStore.Load(matchedID)
+ name := matchedID
+ if def != nil {
+ name = def.Name
+ }
+
+ freeSlot := p.FirstFreeSlot()
+ p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: matchedID, Quantity: qty})
+
+ sciXP := mod.BaseXP
+ g.awardSkillXP(sess, p, player.Science, sciXP)
+ g.AccountStore.SaveCharacter(p)
+
+ sess.WriteLine(fmt.Sprintf("You magnetically pull the %s toward you.", name))
+ if p.OptionBool("xp_drops") {
+ sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP)))
+ }
+}
+
+func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
+ if combat.GetCombat(p.Name) != nil {
+ sess.WriteLine("You can't do that during combat!")
+ return
+ }
+
+ if targetArg == "" {
+ sess.WriteLine("Superheat what? Usage: trigger superheat <ore>")
+ return
+ }
+
+ slot, inv := g.findInventoryItem(p, targetArg)
+ if slot < 0 {
+ sess.WriteLine("You don't have that item.")
+ return
+ }
+
+ recipe := g.RecipeStore.FindByInput("smelt", inv.ItemID)
+ if recipe == nil {
+ sess.WriteLine("You can't superheat that.")
+ return
+ }
+
+ if recipe.Level > 0 && p.Level(player.SkillName(recipe.Skill)) < recipe.Level {
+ sess.WriteLine(fmt.Sprintf("You need level %d %s to smelt that.", recipe.Level, recipe.Skill))
+ return
+ }
+
+ for _, e := range recipe.Consume {
+ for _, itemID := range e.Items {
+ qty := e.Quantity
+ if qty <= 0 {
+ qty = 1
+ }
+ if p.CountItem(itemID) < qty {
+ def, _ := g.ItemStore.Load(itemID)
+ name := itemID
+ if def != nil {
+ name = def.Name
+ }
+ sess.WriteLine(fmt.Sprintf("You need %d %s.", qty, name))
+ return
+ }
+ }
+ }
+
+ if p.Action != nil {
+ g.cancelAction(p)
+ }
+
+ g.consumeJunkCost(p, mod)
+
+ for _, e := range recipe.Consume {
+ for _, itemID := range e.Items {
+ qty := e.Quantity
+ if qty <= 0 {
+ qty = 1
+ }
+ p.RemoveItem(itemID, qty)
+ }
+ }
+
+ outputQty := recipe.OutputQty
+ if outputQty <= 0 {
+ outputQty = 1
+ }
+ placed := false
+ for i := 0; i < 28; i++ {
+ slot := p.InvSlot(i)
+ if slot != nil && slot.ItemID == recipe.Output {
+ slot.Quantity += outputQty
+ placed = true
+ break
+ }
+ }
+ if !placed {
+ freeSlot := p.FirstFreeSlot()
+ p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty})
+ }
+
+ sciXP := mod.BaseXP
+ g.awardSkillXP(sess, p, player.Science, sciXP)
+ if recipe.XP > 0 {
+ g.awardSkillXP(sess, p, player.SkillName(recipe.Skill), recipe.XP)
+ }
+ g.AccountStore.SaveCharacter(p)
+
+ outputDef, _ := g.ItemStore.Load(recipe.Output)
+ outputName := recipe.Output
+ if outputDef != nil {
+ outputName = outputDef.Name
+ }
+ inputDef, _ := g.ItemStore.Load(inv.ItemID)
+ inputName := inv.ItemID
+ if inputDef != nil {
+ inputName = inputDef.Name
+ }
+
+ sess.WriteLine(fmt.Sprintf("You superheat the %s and produce a %s.", inputName, outputName))
+ if p.OptionBool("xp_drops") {
+ parts := []string{fmt.Sprintf("+%dxp sci", sciXP)}
+ if recipe.XP > 0 {
+ parts = append(parts, fmt.Sprintf("+%dxp %s", recipe.XP, player.SkillAbbr[player.SkillName(recipe.Skill)]))
+ }
+ sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")"))
+ }
+}
+
+func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) {
+ if combat.GetCombat(p.Name) != nil {
+ sess.WriteLine("You can't do that during combat!")
+ return
+ }
+
+ logTypes := map[string]struct {
+ plankID string
+ name string
+ cost int
+ }{
+ "logs": {"planks", "planks", 3},
+ "oak_logs": {"oak_planks", "oak planks", 7},
+ "teak_logs": {"teak_planks", "teak planks", 14},
+ "mahogany_logs": {"mahogany_planks", "mahogany planks", 28},
+ }
+
+ if targetArg != "" {
+ slot, inv := g.findInventoryItem(p, targetArg)
+ if slot < 0 {
+ sess.WriteLine("You don't have that item.")
+ return
+ }
+ info, ok := logTypes[inv.ItemID]
+ if !ok {
+ sess.WriteLine("You can't turn that into planks.")
+ return
+ }
+
+ if p.Credits < info.cost {
+ sess.WriteLine(fmt.Sprintf("You need %d credits for Plank Make (70%% of sawmill cost).", info.cost))
+ return
+ }
+
+ if p.Action != nil {
+ g.cancelAction(p)
+ }
+
+ g.consumeJunkCost(p, mod)
+
+ p.RemoveItem(inv.ItemID, 1)
+ p.Credits -= info.cost
+
+ freeSlot := p.FirstFreeSlot()
+ if freeSlot == -1 {
+ sess.WriteLine("Your inventory is full.")
+ return
+ }
+ p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1})
+
+ sciXP := mod.BaseXP
+ g.awardSkillXP(sess, p, player.Science, sciXP)
+ g.awardSkillXP(sess, p, player.Construction, 10)
+ g.AccountStore.SaveCharacter(p)
+
+ sess.WriteLine(fmt.Sprintf("You convert the log into %s.", info.name))
+ if p.OptionBool("xp_drops") {
+ parts := []string{fmt.Sprintf("+%dxp sci", sciXP), "+10xp con"}
+ sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")"))
+ }
+ return
+ }
+
+ for logID, info := range logTypes {
+ qty := p.CountItem(logID)
+ if qty == 0 {
+ continue
+ }
+
+ totalCost := info.cost * qty
+ if p.Credits < totalCost {
+ continue
+ }
+
+ if p.Action != nil {
+ g.cancelAction(p)
+ }
+
+ g.consumeJunkCost(p, mod)
+
+ p.RemoveItem(logID, qty)
+ p.Credits -= totalCost
+
+ processed := 0
+ for i := 0; i < qty; i++ {
+ freeSlot := p.FirstFreeSlot()
+ if freeSlot == -1 {
+ g.World.AddGroundItem(p.RoomID, info.plankID, qty-i)
+ break
+ }
+ p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1})
+ processed++
+ }
+
+ sciXP := mod.BaseXP * qty
+ g.awardSkillXP(sess, p, player.Science, sciXP)
+ conXP := 10 * qty
+ g.awardSkillXP(sess, p, player.Construction, conXP)
+ g.AccountStore.SaveCharacter(p)
+
+ sess.WriteLine(fmt.Sprintf("You convert %d logs into %s for %d credits.", processed, info.name, totalCost))
+ if processed < qty {
+ sess.WriteLine(fmt.Sprintf("Your inventory is full. The remaining %d planks fall to the ground.", qty-processed))
+ }
+ if p.OptionBool("xp_drops") {
+ parts := []string{fmt.Sprintf("+%dxp sci", sciXP), fmt.Sprintf("+%dxp con", conXP)}
+ sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")"))
+ }
+ return
+ }
+
+ sess.WriteLine("You don't have any logs to convert.")
+}