From beb188ce050fb76cdddc0bbeedee7ec608e47995 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 14 Jul 2026 17:13:18 -0400 Subject: feat: unicode hitsplat symbol, area name in look --- internal/config/config.go | 12 ------------ internal/game/act_agility.go | 2 +- internal/game/cmd_trigger_combat.go | 2 +- internal/game/combat_attack.go | 6 +++--- internal/game/combat_mob.go | 10 +++++----- internal/game/look_room.go | 20 +++++++++++++++++++- internal/game/render_combat.go | 12 +++++++++--- internal/game/sys_hazard.go | 2 +- 8 files changed, 39 insertions(+), 27 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 2892338..3b182ff 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -31,18 +31,6 @@ type GameConstants struct { type ColorsConfig map[string]string -// DefaultColors returns the built-in "muted/desaturated" theme: a restricted -// ~15-color palette built from an analogous teal base plus a warm amber accent. -// Emphasis is carried by value ramps + bold within a hue, not by new hues. -// Indices are hex (00-FF); xterm256 decimal shown in parens. -// -// Neutrals (60%): FF(255) FA(250) F5(245) F0(240) ED(237) -// Primary teal (30%): 74(116 bright) 49(73 mid) 42(66 dim) -// Amber accent (10%): B4(180 bright) B3(179 mid) 89(137 dim/tan) -// Danger red: A7(167 mid) 83(131 dim) -// Success green: 6C(108 sage) 41(65 dim) -// Info blue: 6E(110 steel) 43(67 dim) -// Special mauve: 8B(139) func DefaultColors() ColorsConfig { return ColorsConfig{ "room_name": "74 bold", diff --git a/internal/game/act_agility.go b/internal/game/act_agility.go index 5fbff48..68ecaab 100644 --- a/internal/game/act_agility.go +++ b/internal/game/act_agility.go @@ -160,7 +160,7 @@ func (g *Game) obstacleFail(sess *net.Session, p *player.Player, d *behavior.Obs p.HP = 1 } sess.WriteLine(g.colorize(sess, "damage_taken", - fmt.Sprintf("You take %d damage. HP: %d/%d", damage, p.HP, p.MaxHP()))) + fmt.Sprintf("You take %s damage. HP: %d/%d", g.dmgDisplay(sess, damage), p.HP, p.MaxHP()))) g.AccountStore.SaveCharacter(p) g.cancelAction(p) diff --git a/internal/game/cmd_trigger_combat.go b/internal/game/cmd_trigger_combat.go index ecb4fbb..2f51057 100644 --- a/internal/game/cmd_trigger_combat.go +++ b/internal/game/cmd_trigger_combat.go @@ -84,7 +84,7 @@ func (g *Game) scienceAttack(sess *net.Session, p *player.Player, mob *world.Mob prefix := fmt.Sprintf("%s hits %s for %s damage.", g.colorize(sess, "science_mod", mod.Name), g.colorize(sess, "mob", mobName), - g.colorize(sess, "damage_dealt", fmt.Sprint(dmg))) + g.colorize(sess, "damage_dealt", g.dmgDisplay(sess, dmg))) hpSuffix := fmt.Sprintf("%s [%2d/%d]", g.hpBar(sess, mob.HP, mob.MaxHP), mob.HP, mob.MaxHP) line := prefix + " " + hpSuffix + g.formatXpDrop(sess, p, gains) sess.WriteLine(line) diff --git a/internal/game/combat_attack.go b/internal/game/combat_attack.go index 6c314ff..11be7f7 100644 --- a/internal/game/combat_attack.go +++ b/internal/game/combat_attack.go @@ -405,10 +405,10 @@ func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.Mo } else { mobName := mobDisplayName(mob, true) attacker := mobDisplayNameCap(mob, true) - prefix := fmt.Sprintf("You hit %s for %s damage.", g.colorize(sess, "mob", mobName), g.colorize(sess, "damage_dealt", fmt.Sprint(dmg))) + prefix := fmt.Sprintf("You hit %s for %s damage.", g.colorize(sess, "mob", mobName), g.colorize(sess, "damage_dealt", g.dmgDisplay(sess, dmg))) prefix = padCombatPrefix(prefix, - fmt.Sprintf("You hit %s for %d damage.", mobName, 999), - fmt.Sprintf("%s hits you for %d damage.", attacker, 999)) + fmt.Sprintf("You hit %s for > %d < damage.", mobName, 999), + fmt.Sprintf("%s hits you for > %d < damage.", attacker, 999)) hpSuffix := fmt.Sprintf("%s [%2d/%d]", g.hpBar(sess, mob.HP, mob.MaxHP), mob.HP, mob.MaxHP) line := prefix + hpSuffix + g.formatXpDrop(sess, p, gains) sess.WriteLine(line) diff --git a/internal/game/combat_mob.go b/internal/game/combat_mob.go index 9affede..55a2ea3 100644 --- a/internal/game/combat_mob.go +++ b/internal/game/combat_mob.go @@ -156,10 +156,10 @@ func (g *Game) applyMobHit(sess *net.Session, p *player.Player, mob *world.MobIn attacker := mobDisplayNameCap(mob, true) mobName := mobDisplayName(mob, true) - prefix := fmt.Sprintf("%s hits you for %s damage.", g.colorize(sess, "mob", attacker), g.colorize(sess, "damage_taken", fmt.Sprint(dmg))) + prefix := fmt.Sprintf("%s hits you for %s damage.", g.colorize(sess, "mob", attacker), g.colorize(sess, "damage_taken", g.dmgDisplay(sess, dmg))) prefix = padCombatPrefix(prefix, - fmt.Sprintf("%s hits you for %d damage.", attacker, 999), - fmt.Sprintf("You hit %s for %d damage.", mobName, 999)) + fmt.Sprintf("%s hits you for > %d < damage.", attacker, 999), + fmt.Sprintf("You hit %s for > %d < damage.", mobName, 999)) hpSuffix := fmt.Sprintf("%s [%2d/%d]", g.hpBar(sess, p.HP, p.MaxHP()), p.HP, p.MaxHP()) sess.WriteLine(prefix + hpSuffix) @@ -336,8 +336,8 @@ func (g *Game) killPlayer(sess *net.Session, p *player.Player, mob *world.MobIns if mob.HP < 0 { mob.HP = 0 } - sess.WriteLine(fmt.Sprintf("Dead Man's Switch activates! %s takes %d damage!", - mobDisplayName(mob, true), retDmg)) + sess.WriteLine(fmt.Sprintf("Dead Man's Switch activates! %s takes %s damage!", + mobDisplayName(mob, true), g.dmgDisplay(sess, retDmg))) } } } diff --git a/internal/game/look_room.go b/internal/game/look_room.go index 7fe527f..dc488f0 100644 --- a/internal/game/look_room.go +++ b/internal/game/look_room.go @@ -2,6 +2,8 @@ package game import ( "fmt" + "path/filepath" + "strings" "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" @@ -11,13 +13,29 @@ import ( ) func (g *Game) showRoomName(sess *net.Session, p *player.Player, room *world.Room) { - title := fmt.Sprintf("%s (%s)", g.colorize(sess, "room_name", room.Name), g.colorize(sess, "room_number", fmt.Sprintf("#%d", room.ID))) + roomIDStr := fmt.Sprintf("#%d", room.ID) + if area := g.getRoomArea(room.ID); area != "" { + roomIDStr = fmt.Sprintf("%s, #%d", area, room.ID) + } + title := fmt.Sprintf("%s (%s)", g.colorize(sess, "room_name", room.Name), g.colorize(sess, "room_number", roomIDStr)) if bracket := g.roomSymbolBracket(sess, p, room); bracket != "" { title += " " + bracket } sess.WriteLines("", title) } +func (g *Game) getRoomArea(roomID int) string { + path, ok := g.World.GetRoomPath(roomID) + if !ok { + return "" + } + rel, err := filepath.Rel(filepath.Join(g.DataDir, "rooms"), filepath.Dir(path)) + if err != nil || rel == "." { + return "" + } + return strings.ReplaceAll(rel, "_", " ") +} + // roomSymbolBracket renders a dim-bracketed colored symbol (e.g. "[D]") when the // player has set a custom symbol for this room, else "". func (g *Game) roomSymbolBracket(sess *net.Session, p *player.Player, room *world.Room) string { diff --git a/internal/game/render_combat.go b/internal/game/render_combat.go index c3c594c..e4a0d55 100644 --- a/internal/game/render_combat.go +++ b/internal/game/render_combat.go @@ -1,13 +1,19 @@ package game import ( + "fmt" + "thehouseoficarus/internal/net" "thehouseoficarus/internal/ui" ) -// renderBar is the shared bar renderer for both HP bars and task-progress bars. -// lowColor is the color used when the value falls below 40% (167 dusty red for -// HP, 67 steel blue for progress) -- both palette colors. +func (g *Game) dmgDisplay(sess *net.Session, dmg int) string { + if sess.Player != nil && sess.Player.OptionBool("unicode") { + return fmt.Sprintf("\U0001FB38 %d \U0001FB34", dmg) + } + return fmt.Sprintf("> %d <", dmg) +} + func (g *Game) renderBar(sess *net.Session, current, max, lowColor int) string { if max <= 0 { max = 1 diff --git a/internal/game/sys_hazard.go b/internal/game/sys_hazard.go index 40455fc..3d51b6d 100644 --- a/internal/game/sys_hazard.go +++ b/internal/game/sys_hazard.go @@ -128,7 +128,7 @@ func (g *Game) applyHazardHit(sess *net.Session, p *player.Player, hz *world.Haz msg := hz.HitMessage switch { case msg == "": - msg = fmt.Sprintf("The %s hits you for %d damage.", hz.Name, dmg) + msg = fmt.Sprintf("The %s hits you for %s damage.", hz.Name, g.dmgDisplay(sess, dmg)) case strings.Contains(msg, "%d"): msg = fmt.Sprintf(msg, dmg) } -- cgit v1.2.3