aboutsummaryrefslogtreecommitdiff
path: root/internal/game/game.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-15 02:57:35 -0400
committerhistoria <[not public]>2026-06-15 02:58:50 -0400
commit4cc1ddcd185509080b4b3e15d1646567edd51c9d (patch)
tree2a564846ad4fd159a2d7e55451bfa9569fe8c0b8 /internal/game/game.go
parent445c4612cc5cf2c226f85894b6ad1e2419a374e2 (diff)
downloadthehouseoficarus-4cc1ddcd185509080b4b3e15d1646567edd51c9d.tar.gz
removed game speed for being broken and an antifeature anyway. added color support.
Diffstat (limited to 'internal/game/game.go')
-rw-r--r--internal/game/game.go114
1 files changed, 78 insertions, 36 deletions
diff --git a/internal/game/game.go b/internal/game/game.go
index b08c97e..3c00d7e 100644
--- a/internal/game/game.go
+++ b/internal/game/game.go
@@ -8,6 +8,7 @@ import (
"time"
"thirdcollapse/internal/action"
+ "thirdcollapse/internal/combat"
"thirdcollapse/internal/engine"
"thirdcollapse/internal/net"
"thirdcollapse/internal/object"
@@ -21,6 +22,7 @@ const (
ClassInstant CommandClass = iota
ClassFree
ClassActive
+ ClassUnknown
)
type QueuedCommand struct {
@@ -45,7 +47,6 @@ type Game struct {
charsMu sync.Mutex
loggedInChars map[string]*net.Session
combatPadWidth int
- GameSpeed float64
freeQueue map[string][]QueuedCommand
activeQueue map[string]*QueuedCommand
pendingDepletions []pendingDepletion
@@ -126,14 +127,40 @@ func classifyCommand(cmd string) CommandClass {
return ClassInstant
case "wear", "wield", "remove", "unwear", "unwield", "style":
return ClassFree
- default:
+ case "get", "take", "grab", "pick", "drop",
+ "attack", "kill",
+ "north", "n", "south", "s", "east", "e",
+ "west", "w", "up", "u", "down", "d",
+ "quit", "use", "burn", "stoke", "search", "walk":
+ return ClassActive
+ }
+ if _, ok := verbAliases[cmd]; ok {
return ClassActive
}
+ return ClassUnknown
+}
+
+func (g *Game) promptStr(sess *net.Session) string {
+ prompt := "> "
+ if p, ok := sess.Player.(*player.Player); ok && p != nil {
+ if custom := p.OptionString("prompt"); custom != "" {
+ prompt = custom
+ }
+ }
+ return g.colorTag(sess, prompt)
+}
+
+func (g *Game) writePrompt(sess *net.Session) {
+ sess.Write("\r\n" + g.promptStr(sess))
+}
+
+func (g *Game) reprompt(sess *net.Session) {
+ sess.Write(g.promptStr(sess))
}
func (g *Game) handleGameCommand(sess *net.Session, input string) {
if input == "" {
- sess.Write("> ")
+ g.reprompt(sess)
return
}
@@ -161,7 +188,7 @@ func (g *Game) handleGameCommand(sess *net.Session, input string) {
if class == ClassInstant {
g.executeCommand(sess, cmd, parts[1:], input)
- sess.Write("\r\n> ")
+ g.writePrompt(sess)
return
}
@@ -183,6 +210,12 @@ func (g *Game) handleGameCommand(sess *net.Session, input string) {
return
}
+ if class == ClassUnknown {
+ sess.WriteLine("Unknown command.")
+ g.writePrompt(sess)
+ return
+ }
+
g.activeQueue[p.Name] = &QueuedCommand{
Session: sess,
Command: cmd,
@@ -224,9 +257,6 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
g.doDrop(sess, strings.Join(args, " "))
}
case "attack", "kill":
- if p == nil {
- return
- }
if len(args) == 0 {
target := g.resolveDefaultMob(p.RoomID)
if target == "" {
@@ -290,9 +320,6 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
g.doHelp(sess, strings.Join(args, " "))
}
case "mine", "chop", "fish", "cut", "use", "pull", "push":
- if p == nil {
- return
- }
g.CancelAction(p)
if len(args) == 0 {
target := g.resolveDefaultTarget(p.RoomID, cmd)
@@ -307,9 +334,6 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
return
}
case "talk", "speak", "ask":
- if p == nil {
- return
- }
g.CancelAction(p)
if len(args) == 0 {
sess.WriteLine("Talk to whom?")
@@ -318,16 +342,10 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
return
}
case "burn":
- if p == nil {
- return
- }
g.CancelAction(p)
g.doBurn(sess, p, strings.Join(args, " "))
return
case "stoke":
- if p == nil {
- return
- }
g.CancelAction(p)
g.doStoke(sess, p, strings.Join(args, " "))
return
@@ -338,9 +356,6 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
g.doUnalias(sess, args)
return
case "search":
- if p == nil {
- return
- }
g.CancelAction(p)
if len(args) == 0 {
sess.WriteLine("Search what?")
@@ -349,25 +364,41 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
}
return
case "walk":
- if p == nil {
- return
- }
g.doWalk(sess, args)
return
case "wear", "wield":
- if p == nil {
- return
- }
g.doWear(sess, strings.Join(args, " "))
return
case "remove", "unwear", "unwield":
- if p == nil {
- return
- }
g.doRemove(sess, strings.Join(args, " "))
return
default:
- sess.WriteLine("Unknown command.")
+ if a, ok := verbAliases[cmd]; ok {
+ g.CancelAction(p)
+ switch a {
+ case "gather", "toggle":
+ if len(args) == 0 {
+ target := g.resolveDefaultTarget(p.RoomID, cmd)
+ if target == "" {
+ sess.WriteLine(fmt.Sprintf("%s what?", cmd))
+ break
+ }
+ g.StartAction(sess, cmd, target)
+ return
+ }
+ g.StartAction(sess, cmd, strings.Join(args, " "))
+ return
+ case "talk":
+ if len(args) == 0 {
+ sess.WriteLine("Talk to whom?")
+ } else {
+ g.StartAction(sess, "talk", strings.Join(args, " "))
+ return
+ }
+ }
+ } else {
+ sess.WriteLine("Unknown command.")
+ }
}
}
@@ -405,7 +436,7 @@ func (g *Game) ProcessQueuedCommands() {
if len(parts) > 0 {
g.executeCommand(qc.Session, parts[0], parts[1:], qc.Command+" "+qc.Args)
}
- qc.Session.Write("\r\n> ")
+ g.writePrompt(qc.Session)
}
delete(g.freeQueue, p.Name)
}
@@ -420,10 +451,18 @@ func (g *Game) ProcessQueuedCommands() {
for _, qc := range actives {
parts := strings.Fields(qc.Command + " " + qc.Args)
+ p, ok := qc.Session.Player.(*player.Player)
+ if !ok || p == nil {
+ continue
+ }
+ wasBusy := p.Action != nil || len(p.WalkSequence) > 0 || combat.GetCombat(p.Name) != nil
if len(parts) > 0 {
g.executeCommand(qc.Session, parts[0], parts[1:], qc.Command+" "+qc.Args)
}
- qc.Session.Write("\r\n> ")
+ isBusy := p.Action != nil || len(p.WalkSequence) > 0 || combat.GetCombat(p.Name) != nil
+ if wasBusy || !isBusy {
+ g.writePrompt(qc.Session)
+ }
}
g.activeQueue = make(map[string]*QueuedCommand)
@@ -433,6 +472,9 @@ func (g *Game) ProcessQueuedCommands() {
continue
}
g.advanceWalk(sess, p)
+ if len(p.WalkSequence) == 0 {
+ g.writePrompt(sess)
+ }
}
g.flushPendingDepletions()
@@ -445,6 +487,6 @@ type pendingDepletion struct {
playerNames []string
}
-func (g *Game) computeTicks(base float64) int {
- return engine.FractionalTicks(base, g.GameSpeed)
+func (g *Game) TickCombat() {
+ combat.TickCombat()
}