diff options
| author | historia <[not public]> | 2026-06-25 15:40:48 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-25 15:40:48 -0400 |
| commit | abd612c15799f604e671e83dc7c410ed2b44185f (patch) | |
| tree | 0597ca92350de73aac2a7cf26b2f2d6595dac0cc /internal/game/action.go | |
| parent | 2725e2927a1595c7b100d942d1f14146252adeb7 (diff) | |
| download | thehouseoficarus-abd612c15799f604e671e83dc7c410ed2b44185f.tar.gz | |
slop refactor
Diffstat (limited to 'internal/game/action.go')
| -rw-r--r-- | internal/game/action.go | 377 |
1 files changed, 0 insertions, 377 deletions
diff --git a/internal/game/action.go b/internal/game/action.go deleted file mode 100644 index 19e79cf..0000000 --- a/internal/game/action.go +++ /dev/null @@ -1,377 +0,0 @@ -package game - -import ( - "fmt" - "sort" - "strconv" - "strings" - - "thehouseoficarus/internal/action" - "thehouseoficarus/internal/combat" - "thehouseoficarus/internal/net" - "thehouseoficarus/internal/object" - "thehouseoficarus/internal/player" - "thehouseoficarus/internal/world" -) - -var verbAliases = map[string]string{ - "mine": "gather", - "chop": "gather", - "fish": "gather", - "cut": "gather", - "shear": "gather", - "talk": "talk", - "speak": "talk", - "ask": "talk", - "steal": "steal", - "thieve": "steal", - "hide": "safespot", -} - -var verbSkill = map[string]string{ - "mine": "mining", - "chop": "woodcutting", - "cut": "woodcutting", - "fish": "fishing", - "shear": "crafting", - "steal": "thieving", - "thieve": "thieving", -} - -func normalizeVerb(v string) string { - if a, ok := verbAliases[v]; ok { - return a - } - return v -} - -func (g *Game) startAction(sess *net.Session, verb, target string) { - p := sess.Player - - verb = normalizeVerb(verb) - - if combat.GetCombat(p.Name) != nil { - sess.WriteLine("You can't do that during combat!") - return - } - - if p.Action != nil { - g.cancelAction(p) - } - g.cancelBgAction(p) - - lower := strings.ToLower(target) - instanceIdx := -1 - if dotPos := strings.Index(lower, "."); dotPos > 0 { - if n, err := strconv.Atoi(lower[:dotPos]); err == nil && n > 0 { - instanceIdx = n - 1 - lower = lower[dotPos+1:] - } - } - - instances := g.World.FindObjInstances(p.RoomID, lower) - sort.Slice(instances, func(i, j int) bool { - return instances[i].Index < instances[j].Index - }) - - var obj *object.ObjectDef - var mob *world.MobInstance - var chosen *world.ObjState - - if len(instances) > 0 { - uniqueDefs := make(map[string]bool) - for _, ist := range instances { - uniqueDefs[ist.DefID] = true - } - if len(uniqueDefs) > 1 { - sess.WriteLine("That's ambiguous, which one?") - return - } - - if instanceIdx >= 0 && instanceIdx < len(instances) { - chosen = &instances[instanceIdx] - } else { - for i := range instances { - if !instances[i].Depleted { - chosen = &instances[i] - break - } - } - if chosen == nil { - chosen = &instances[0] - } - } - if chosen == nil { - sess.WriteLine(fmt.Sprintf("There's nothing here to %s.", verb)) - return - } - var err error - obj, err = g.ObjectStore.Load(chosen.DefID) - if err != nil || !obj.IsInteractable() { - sess.WriteLine(fmt.Sprintf("You can't %s the %s.", verb, obj.Name)) - return - } - } else { - mobs := g.MobStore.MobsInRoom(p.RoomID) - var candidates []*world.MobInstance - for _, m := range mobs { - if !m.IsTalkable() { - continue - } - if q := m.MatchQuality(lower); q >= world.MatchPrefix { - candidates = append(candidates, m) - } - } - if len(candidates) == 0 { - sess.WriteLine(fmt.Sprintf("There's nothing here to %s.", verb)) - return - } - sort.Slice(candidates, func(i, j int) bool { - return candidates[i].InstanceID < candidates[j].InstanceID - }) - if instanceIdx >= 0 && instanceIdx < len(candidates) { - mob = candidates[instanceIdx] - } else if len(candidates) == 1 { - mob = candidates[0] - } else { - sess.WriteLine("Which one?") - return - } - } - - if obj != nil && obj.ID == "estate_directory" { - g.startEstateDirectory(sess, verb) - return - } - - bhType := "" - if obj != nil { - bhType = obj.BehaviorType() - } else if mob != nil { - if mob.IsTalkable() { - bhType = "talk" - } - } - - if bhType != verb { - if obj != nil { - sess.WriteLine(fmt.Sprintf("You can't %s the %s.", verb, obj.Name)) - } else { - sess.WriteLine(fmt.Sprintf("You can't %s that.", verb)) - } - return - } - - switch bhType { - case "gather": - if obj == nil || chosen == nil { - sess.WriteLine(fmt.Sprintf("You can't %s that.", verb)) - return - } - g.startGather(sess, p, obj, chosen) - case "talk": - if mob != nil { - g.startMobTalk(sess, p, mob) - } else { - g.startTalk(sess, p, obj) - } - case "use": - g.startUse(sess, p, obj) - default: - sess.WriteLine(fmt.Sprintf("You can't %s that.", verb)) - } -} - -func (g *Game) cancelAction(p *player.Player) { - p.Action = nil - p.WalkSequence = nil - p.ClearMoveState() -} - -func (g *Game) cancelBgAction(p *player.Player) { - p.BackgroundAction = nil -} - -func (g *Game) AdvanceActions() { - if g.Hub == nil { - return - } - for _, sess := range g.Hub.AllSessions() { - p := sess.Player - if p == nil || p.Action == nil { - continue - } - if !p.Action.Advance() { - continue - } - switch p.Action.Type { - case "gather": - g.advanceGather(sess, p) - case "use": - g.advanceUse(sess, p) - case "burn": - g.advanceBurn(sess, p) - case "stoke": - g.advanceStoke(sess, p) - case "search": - g.advanceSearch(sess, p) - case "identify": - g.advanceIdentify(sess, p) - case "steal": - g.advanceSteal(sess, p) - case "plant": - g.advancePlant(sess, p) - case "harvest": - g.advanceHarvest(sess, p) - case "rake": - g.advanceRake(sess, p) - case "water": - g.advanceWater(sess, p) - case "cure": - g.advanceCure(sess, p) - case "obstacle": - g.advanceObstacle(sess, p) - default: - if productionActionTypes[string(p.Action.Type)] { - g.advanceProduction(sess, p) - } - } - if p.Action == nil { - g.writePrompt(sess) - } - } - - for _, sess := range g.Hub.AllSessions() { - p := sess.Player - if p == nil || p.BackgroundAction == nil { - continue - } - if !p.BackgroundAction.Advance() { - continue - } - switch p.BackgroundAction.Type { - case "fletch": - g.advanceFletch(sess, p) - case "clean": - g.advanceClean(sess, p) - } - if p.BackgroundAction == nil { - g.writePrompt(sess) - } - } -} - -func (g *Game) checkCondition(sess *net.Session, c *action.Condition) bool { - p := sess.Player - - if c.AllOf != nil { - for _, sub := range c.AllOf { - if !g.checkCondition(sess, &sub) { - return false - } - } - return true - } - if c.AnyOf != nil { - for _, sub := range c.AnyOf { - if g.checkCondition(sess, &sub) { - return true - } - } - return false - } - - if c.PlayerFlag != "" { - var val any - present := false - if p != nil && p.Flags != nil { - val, present = p.Flags[c.PlayerFlag] - } - return flagMatches(present, val, c.Value, c.Not) - } - - if c.Flag != "" { - val, present := g.Flags.Get(c.Flag) - return flagMatches(present, val, c.Value, c.Not) - } - if c.HasItem != "" { - has := p != nil && p.HasItem(c.HasItem) - if c.Not { - return !has - } - return has - } - if c.MinCredits > 0 { - has := p != nil && p.Credits >= c.MinCredits - if c.Not { - return !has - } - return has - } - return true -} - -// flagMatches evaluates a flag/player_flag condition. -// -// If the condition specifies no `value`, the flag matches when it is present -// and truthy (so `{player_flag: x}` means "x is set" and -// `{player_flag: x, not: true}` means "x is not set"). If a `value` is given, -// the flag must be present and equal to it. `not` inverts the result. Numeric -// values are compared by coercing both sides through a common numeric type so -// that an int flag set in code matches an int64/float64 decoded from YAML. -func flagMatches(present bool, val, want any, not bool) bool { - var match bool - if want == nil { - match = present && isTruthy(val) - } else { - match = present && valuesEqual(val, want) - } - if not { - return !match - } - return match -} - -// valuesEqual compares two any-typed values, normalizing numeric types (int, -// int64, float64) so that e.g. int(3) == int64(3) == float64(3). Non-numeric -// types fall back to ==. -func valuesEqual(a, b any) bool { - ai, aok := numericValue(a) - bi, bok := numericValue(b) - if aok && bok { - return ai == bi - } - return a == b -} - -// numericValue returns the value as a float64 if it is a numeric type. -func numericValue(v any) (float64, bool) { - switch x := v.(type) { - case int: - return float64(x), true - case int64: - return float64(x), true - case float64: - return x, true - } - return 0, false -} - -func isTruthy(v any) bool { - switch x := v.(type) { - case nil: - return false - case bool: - return x - case int: - return x != 0 - case int64: - return x != 0 - case float64: - return x != 0 - case string: - return x != "" - default: - return true - } -} |
