diff options
Diffstat (limited to 'internal/game/cmd_hide.go')
| -rw-r--r-- | internal/game/cmd_hide.go | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/internal/game/cmd_hide.go b/internal/game/cmd_hide.go new file mode 100644 index 0000000..9445949 --- /dev/null +++ b/internal/game/cmd_hide.go @@ -0,0 +1,171 @@ +package game + +import ( + "fmt" + "strings" + + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/world" +) + +func (g *Game) executeHide(sess *net.Session, args []string, rawInput string) { + p := sess.Player + + if len(args) == 0 { + sess.WriteLine("Hide behind what?") + return + } + + // Skip optional "behind" + target := strings.Join(args, " ") + if args[0] == "behind" { + if len(args) < 2 { + sess.WriteLine("Hide behind what?") + return + } + target = strings.Join(args[1:], " ") + } + + instances := g.World.FindObjInstances(p.RoomID, target) + if len(instances) == 0 { + sess.WriteLine("You don't see that here.") + return + } + + if len(instances) > 1 && objectInstancesNeedDisambiguation(instances) { + sess.WriteLines( + "That's ambiguous, which one?", + formatObjInstanceChoices(instances), + ) + return + } + + objDef, err := g.ObjectStore.Load(instances[0].DefID) + if err != nil || !objDef.IsSafespot() { + sess.WriteLine("You can't hide behind that.") + return + } + + cfg := objDef.Safespot + st := g.World.GetObjState(p.RoomID, objDef.ID, instances[0].Index) + if st == nil { + sess.WriteLine("You can't hide behind that.") + return + } + + g.safespotMu.Lock() + existingSS, alreadyHiding := g.safespotStates[p.Name] + g.safespotMu.Unlock() + + if alreadyHiding && existingSS.Active { + if existingSS.ObjectDefID == objDef.ID && existingSS.ObjectIndex == instances[0].Index { + if existingSS.HideCountdown > 0 { + sess.WriteLine("You're already moving into position there.") + } else { + sess.WriteLine("You're already hiding there.") + } + return + } + g.leaveSafespot(sess, p) + } + + if g.safespotTier(p) < cfg.Tier { + sess.WriteLine("You can't figure out how to use this as effective cover.") + return + } + + if cfg.MaxOccupants > 0 && len(st.SafespotOccupants) >= cfg.MaxOccupants { + sess.WriteLines( + "", + fmt.Sprintf("%s already hiding there!", + joinSafespotOccupants(st.SafespotOccupants)), + ) + return + } + + if st.SafespotLevel <= 0 { + if cfg.RespawnTicks > 0 { + sess.WriteLine(fmt.Sprintf("The %s has been destroyed and hasn't reformed yet.", objDef.Name)) + } else { + sess.WriteLine(fmt.Sprintf("The %s has been completely destroyed.", objDef.Name)) + } + return + } + + inCombat := combat.GetCombat(p.Name) != nil + hideCountdown := 1 + if inCombat { + hideCountdown = 4 + } + + g.safespotMu.Lock() + g.safespotStates[p.Name] = &SafespotState{ + Active: true, + ObjectDefID: objDef.ID, + ObjectIndex: instances[0].Index, + RoomID: p.RoomID, + HideCountdown: hideCountdown, + } + g.safespotMu.Unlock() + + p.ActionState = &ActionState{Type: ActionHiding, TargetName: objDef.Name} + + if inCombat { + sess.WriteLine(fmt.Sprintf("\nYou try to get behind the %s for cover...", objDef.Name)) + } else { + sess.WriteLine(fmt.Sprintf("You position yourself behind the %s.", objDef.Name)) + } +} + +func (g *Game) executeUnhide(sess *net.Session, args []string, rawInput string) { + p := sess.Player + + g.safespotMu.Lock() + ss, ok := g.safespotStates[p.Name] + g.safespotMu.Unlock() + + if !ok || !ss.Active { + sess.WriteLine("You're not hiding behind anything.") + return + } + + if ss.HideCountdown > 0 { + g.safespotMu.Lock() + delete(g.safespotStates, p.Name) + g.safespotMu.Unlock() + p.ActionState = nil + sess.WriteLine("You stop trying to hide.") + return + } + + g.leaveSafespot(sess, p) +} + +func objectInstancesNeedDisambiguation(instances []world.ObjState) bool { + if len(instances) < 2 { + return false + } + first := instances[0].DefID + for i := 1; i < len(instances); i++ { + if instances[i].DefID != first { + return true + } + } + return false +} + +func formatObjInstanceChoices(instances []world.ObjState) string { + var lines []string + for _, inst := range instances { + lines = append(lines, fmt.Sprintf(" %d.%s", inst.Index+1, inst.Name)) + } + return strings.Join(lines, "\n") +} + +func joinSafespotOccupants(names []string) string { + if len(names) == 1 { + return fmt.Sprintf("%s is", names[0]) + } + return fmt.Sprintf("%s are", strings.Join(names, ", ")) +} |
