diff options
| author | historia <[not public]> | 2026-06-16 01:59:27 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-16 01:59:27 -0400 |
| commit | 43f21aabae8924f35c12c8485e690aeefe0089fb (patch) | |
| tree | b5fbadb89df3cf4ffec86503bb8e2d7e52b27454 /internal/game/cmd_look.go | |
| parent | 4cc1ddcd185509080b4b3e15d1646567edd51c9d (diff) | |
| download | thehouseoficarus-43f21aabae8924f35c12c8485e690aeefe0089fb.tar.gz | |
feat: overhauled ansi color, added prompt options
Diffstat (limited to 'internal/game/cmd_look.go')
| -rw-r--r-- | internal/game/cmd_look.go | 124 |
1 files changed, 94 insertions, 30 deletions
diff --git a/internal/game/cmd_look.go b/internal/game/cmd_look.go index 992f3d0..bd738be 100644 --- a/internal/game/cmd_look.go +++ b/internal/game/cmd_look.go @@ -2,13 +2,14 @@ package game import ( "fmt" + "regexp" "sort" "strconv" "strings" - "thirdcollapse/internal/color" "thirdcollapse/internal/combat" "thirdcollapse/internal/net" + "thirdcollapse/internal/object" "thirdcollapse/internal/player" "thirdcollapse/internal/world" ) @@ -21,17 +22,20 @@ func (g *Game) doLook(sess *net.Session) { return } - mode := g.colorMode(sess) sess.WriteLines( "", - fmt.Sprintf("%s (#%d)", color.Wrap(mode, "cyan", room.Name), room.ID), + fmt.Sprintf("%s (%s)", g.colorize(sess, "room_name", room.Name), g.colorize(sess, "room_number", fmt.Sprintf("#%d", room.ID))), ) descWidth := p.OptionInt("room_desc_width") if descWidth <= 0 { descWidth = 70 } - descLines := wrapText(g.colorTag(sess, room.Description), descWidth) + rawLines := wrapText(room.Description, descWidth) + descLines := make([]string, len(rawLines)) + for i, l := range rawLines { + descLines[i] = g.colorize(sess, "room_desc", l) + } wroteDesc := false if p.OptionString("tiny_map") != "off" { mapLines := buildTinyMap(g, p.RoomID, mapGlyphsForPlayer(p.OptionBool("unicode"))) @@ -46,7 +50,7 @@ func (g *Game) doLook(sess *net.Session) { } } - mobs := g.MobStore.MobsInRoom(p.RoomID) + mobs := g.MobStore.MobsInRoom(p.RoomID) if len(mobs) > 0 { sort.Slice(mobs, func(i, j int) bool { iDamaged := mobs[i].HP < mobs[i].MaxHP @@ -57,10 +61,11 @@ func (g *Game) doLook(sess *net.Session) { return mobs[i].InstanceID < mobs[j].InstanceID }) sess.WriteLine("") + playerLevel := p.CombatLevel() for _, m := range mobs { hp := "" if m.HP < m.MaxHP { - hp = fmt.Sprintf(" [%d/%dhp]", m.HP, m.MaxHP) + hp = fmt.Sprintf(" [%s/%dhp]", g.colorize(sess, "enemy_hp", fmt.Sprint(m.HP)), m.MaxHP) } var desc string if combat.IsMobInCombat(m.InstanceID) { @@ -77,7 +82,13 @@ func (g *Game) doLook(sess *net.Session) { if !m.Unique { displayName = "A " + m.Name } - sess.WriteLine(fmt.Sprintf(" %s (level %d)%s%s", displayName, mobCombatLevel(m), hp, desc)) + npcColor := "hostile_npc" + if m.Protected { + npcColor = "friendly_npc" + } + mobLevel := mobCombatLevel(m) + levelStr := g.levelColorize(sess, playerLevel, mobLevel, fmt.Sprintf("(level %d)", mobLevel)) + sess.WriteLine(fmt.Sprintf(" %s %s%s%s", g.colorize(sess, npcColor, displayName), levelStr, hp, desc)) } } @@ -138,15 +149,17 @@ func (g *Game) doLook(sess *net.Session) { } roomDesc := def.InRoomDescription + coloredName := g.objColorize(sess, def, def.Name) + coloredPlural := g.objColorize(sess, def, def.Name+"s") if len(freshIdxs) > 0 { var line string if roomDesc != "" { line = roomDesc } else if len(freshIdxs) == 1 { - line = "A " + def.Name + " is here." + line = fmt.Sprintf("A %s is here.", coloredName) } else { - line = fmt.Sprintf("%d %ss are here.", len(freshIdxs), def.Name) + line = fmt.Sprintf("%d %s are here.", len(freshIdxs), coloredPlural) } var suffix string if multi && (len(timed) > 0 || len(depleted) > 0) { @@ -164,7 +177,7 @@ func (g *Game) doLook(sess *net.Session) { if roomDesc != "" { line = roomDesc } else { - line = "A " + def.Name + " is here." + line = fmt.Sprintf("A %s is here.", coloredName) } tag := "" if multi { @@ -182,7 +195,7 @@ func (g *Game) doLook(sess *net.Session) { if roomDesc != "" { line = roomDesc } else { - line = "A " + def.Name + " is here." + line = fmt.Sprintf("A %s is here.", coloredName) } tag := "" if multi { @@ -227,14 +240,15 @@ func (g *Game) doLook(sess *net.Session) { if err == nil { name = def.Name } + coloredName := g.itemColorize(sess, def, name) prefix := "" if info.Quantity > 1 { - prefix = fmt.Sprintf(" %d x %s", info.Quantity, name) + prefix = fmt.Sprintf(" %d x %s", info.Quantity, coloredName) } else { - prefix = fmt.Sprintf(" %s", name) + prefix = fmt.Sprintf(" %s", coloredName) } - if len(prefix) > maxPrefix { - maxPrefix = len(prefix) + if visibleLen(prefix) > maxPrefix { + maxPrefix = visibleLen(prefix) } var parts []string if info.ReservedFor != "" { @@ -256,7 +270,8 @@ func (g *Game) doLook(sess *net.Session) { for _, l := range lines { if l.reserved != "" { - sess.WriteLine(fmt.Sprintf("%-*s%s", maxPrefix+1, l.prefix, l.reserved)) + pad := maxPrefix + 1 + (len(l.prefix) - visibleLen(l.prefix)) + sess.WriteLine(fmt.Sprintf("%-*s%s", pad, l.prefix, l.reserved)) } else { sess.WriteLine(l.prefix) } @@ -265,22 +280,36 @@ func (g *Game) doLook(sess *net.Session) { if len(room.Exits) > 0 { sess.WriteLine("") - if p.OptionBool("exits") { + if p.OptionBool("exits") { sess.WriteLine("Exits:") + type exitLine struct { + dir string + targetName string + } + var lines []exitLine + maxDirLen := 0 for _, dir := range world.ExitOrder { exitDef, ok := room.Exits[dir] if !ok { continue } + coloredDir := g.colorize(sess, "exit_direction", string(dir)) targetRoom, err := g.World.LoadRoom(exitDef.Room) - targetName := fmt.Sprintf("#%d", exitDef.Room) + targetName := g.colorize(sess, "room_number", fmt.Sprintf("#%d", exitDef.Room)) if err == nil { - targetName = targetRoom.Name + targetName = g.colorize(sess, "exit_name", targetRoom.Name) } if exitDef.Condition != nil && !g.checkCondition(sess, exitDef.Condition) { targetName += " (blocked)" } - sess.WriteLine(fmt.Sprintf(" %-6s - %s", dir, targetName)) + lines = append(lines, exitLine{coloredDir, targetName}) + if visibleLen(coloredDir) > maxDirLen { + maxDirLen = visibleLen(coloredDir) + } + } + for _, l := range lines { + pad := maxDirLen + (len(l.dir) - visibleLen(l.dir)) + sess.WriteLine(fmt.Sprintf(" %-*s - %s", pad, l.dir, l.targetName)) } } else { sess.Write("Exits: ") @@ -290,7 +319,7 @@ func (g *Game) doLook(sess *net.Session) { if !first { sess.Write(", ") } - sess.Write(string(dir)) + sess.Write(g.colorize(sess, "exit_direction", string(dir))) first = false } } @@ -355,9 +384,15 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { } } if best != nil { + npcColor := "hostile_npc" + if best.Protected { + npcColor = "friendly_npc" + } + mobLevel := mobCombatLevel(best) + levelStr := g.levelColorize(sess, p.CombatLevel(), mobLevel, fmt.Sprintf("(level %d)", mobLevel)) sess.WriteLines( "", - fmt.Sprintf("%s (level %d)", best.Name, mobCombatLevel(best)), + fmt.Sprintf("%s %s", g.colorize(sess, npcColor, best.Name), levelStr), ) if best.IdleDescription != "" { sess.WriteLine(fmt.Sprintf(" %s", best.IdleDescription)) @@ -423,7 +458,7 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { } sess.WriteLines( "", - def.Name, + g.itemColorize(sess, def, def.Name), fmt.Sprintf(" %s", def.Description), fmt.Sprintf(" Value: %d credits", def.Value), ) @@ -469,10 +504,13 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { } func showPlayerInfo(g *Game, sess *net.Session, p *player.Player) { + myP := sess.Player.(*player.Player) + theirLevel := p.CombatLevel() + levelStr := g.levelColorize(sess, myP.CombatLevel(), theirLevel, fmt.Sprint(theirLevel)) sess.WriteLines( "", p.Name, - fmt.Sprintf(" Combat Level: %d", p.CombatLevel()), + fmt.Sprintf(" Combat Level: %s", levelStr), fmt.Sprintf(" HP: %d/%d", p.HP, p.MaxHP()), "", ) @@ -490,10 +528,12 @@ func showPlayerInfo(g *Game, sess *net.Session, p *player.Player) { continue } name := itemID + var itemDef *object.ItemDef if def, err := g.ItemStore.Load(itemID); err == nil { name = def.Name + itemDef = def } - sess.WriteLine(fmt.Sprintf(" %-12s %s", slot, name)) + sess.WriteLine(fmt.Sprintf(" %-12s %s", slot, g.itemColorize(sess, itemDef, name))) } if p.Description != "" { @@ -509,17 +549,31 @@ func (g *Game) doExits(sess *net.Session) { sess.WriteLine("There are no exits here.") return } + type exitLine struct { + dir string + name string + } + var lines []exitLine + maxDirLen := 0 for _, dir := range world.ExitOrder { exitDef, ok := room.Exits[dir] if !ok { continue } + coloredDir := g.colorize(sess, "exit_direction", string(dir)) targetRoom, err := g.World.LoadRoom(exitDef.Room) - targetName := fmt.Sprintf("#%d", exitDef.Room) + targetName := g.colorize(sess, "room_number", fmt.Sprintf("#%d", exitDef.Room)) if err == nil { - targetName = targetRoom.Name + targetName = g.colorize(sess, "exit_name", targetRoom.Name) + } + lines = append(lines, exitLine{coloredDir, targetName}) + if visibleLen(coloredDir) > maxDirLen { + maxDirLen = visibleLen(coloredDir) } - sess.WriteLine(fmt.Sprintf(" %-6s - %s", dir, targetName)) + } + for _, l := range lines { + pad := maxDirLen + (len(l.dir) - visibleLen(l.dir)) + sess.WriteLine(fmt.Sprintf(" %-*s - %s", pad, l.dir, l.name)) } } @@ -552,6 +606,12 @@ func mobInstanceIdx(mob *world.MobInstance, roomMobs []*world.MobInstance) int { return 0 } +var ansiRe = regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`) + +func visibleLen(s string) int { + return len(ansiRe.ReplaceAllString(s, "")) +} + func wrapText(text string, width int) []string { if width <= 0 { return []string{text} @@ -563,7 +623,7 @@ func wrapText(text string, width int) []string { var lines []string current := words[0] for _, word := range words[1:] { - if len(current)+1+len(word) <= width { + if visibleLen(current)+1+visibleLen(word) <= width { current += " " + word } else { lines = append(lines, current) @@ -596,7 +656,11 @@ func (g *Game) writeLookSideBySide(sess *net.Session, p *player.Player, descLine if leftMap { sess.WriteLine(fmt.Sprintf("%s %s", mapLine, desc)) } else { - sess.WriteLine(fmt.Sprintf("%-*s %s", mapWidth, desc, mapLine)) + pad := mapWidth + (len(desc) - visibleLen(desc)) + if pad < 0 { + pad = 0 + } + sess.WriteLine(fmt.Sprintf("%-*s %s", pad, desc, mapLine)) } } } |
