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/look_entities.go | |
| parent | 2725e2927a1595c7b100d942d1f14146252adeb7 (diff) | |
| download | thehouseoficarus-abd612c15799f604e671e83dc7c410ed2b44185f.tar.gz | |
slop refactor
Diffstat (limited to 'internal/game/look_entities.go')
| -rw-r--r-- | internal/game/look_entities.go | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/internal/game/look_entities.go b/internal/game/look_entities.go new file mode 100644 index 0000000..f9412d4 --- /dev/null +++ b/internal/game/look_entities.go @@ -0,0 +1,347 @@ +package game + +import ( + "fmt" + "sort" + "strings" + + "thehouseoficarus/internal/color" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" + "thehouseoficarus/internal/world" +) + +func (g *Game) showRoomMobs(sess *net.Session, p *player.Player, room *world.Room) []string { + mobs := g.MobStore.MobsInRoom(p.RoomID) + if len(mobs) == 0 { + return nil + } + sort.Slice(mobs, func(i, j int) bool { + iDamaged := mobs[i].HP < mobs[i].MaxHP + jDamaged := mobs[j].HP < mobs[j].MaxHP + if iDamaged != jDamaged { + return iDamaged + } + return mobs[i].InstanceID < mobs[j].InstanceID + }) + var lines []string + lines = append(lines, "") + playerLevel := p.CombatLevel() + for _, m := range mobs { + hp := "" + if m.HP < m.MaxHP { + if m.IsTask() { + pct := 0 + if m.MaxHP > 0 { + pct = (m.MaxHP - m.HP) * 100 / m.MaxHP + } + hp = fmt.Sprintf(" [%d%% complete]", pct) + } else { + hp = fmt.Sprintf(" [%s/%dhp]", color.Render(g.colorMode(sess), color.Parse("167"), fmt.Sprint(m.HP)), m.MaxHP) + } + } + var desc string + if g.Combat.IsMobInCombat(m.InstanceID) { + def, err := g.MobStore.LoadDef(m.DefID) + if err == nil && len(def.CombatDescriptions) > 0 { + target := g.Combat.MobTarget(m.InstanceID) + pattern := def.CombatDescriptions[randInt(len(def.CombatDescriptions))] + desc = " " + fmt.Sprintf(pattern, target) + } + } else if m.IdleDescription != "" { + desc = fmt.Sprintf(" %s", m.IdleDescription) + } + displayName := m.Name + if !m.Unique { + displayName = "A " + m.Name + } + mobColor := "mob" + if m.Protected { + mobColor = "protected_mob" + } + mobLevel := mobCombatLevel(m) + levelStr := g.levelColorize(sess, playerLevel, mobLevel, fmt.Sprintf("(level %d)", mobLevel)) + lines = append(lines, fmt.Sprintf("%s %s%s%s", g.colorize(sess, mobColor, displayName), levelStr, hp, desc)) + } + return lines +} + +func (g *Game) showRoomObjects(sess *net.Session, p *player.Player, room *world.Room) []string { + objs := g.World.AllObjInstances(p.RoomID) + if len(objs) == 0 { + return g.showFarmPatches(sess, p) + } + var lines []string + lines = append(lines, "") + grouped := make(map[string]int) + var order []string + for _, o := range objs { + if _, ok := grouped[o.DefID]; !ok { + order = append(order, o.DefID) + } + grouped[o.DefID]++ + } + for _, objID := range order { + count := grouped[objID] + def, err := g.ObjectStore.Load(objID) + if err != nil { + continue + } + + if def.Hidden { + continue + } + + if farmPatchDefIDs[objID] { + continue + } + + type instInfo struct { + idx int + depleted bool + sharedMax int + sharedCur int + respawnIn int + quality int + } + var instances []instInfo + for i := 0; i < count; i++ { + st := g.World.GetObjState(p.RoomID, objID, i) + if st == nil { + continue + } + instances = append(instances, instInfo{ + idx: i + 1, + depleted: st.Depleted, + sharedMax: int(st.SharedMax), + sharedCur: st.SharedTimer, + respawnIn: int(st.DepleteTimer), + quality: int(st.Quality), + }) + } + multi := len(instances) > 1 + showTimers := p.OptionBool("depletion") + + var freshIdxs []int + var timed, depleted []instInfo + for _, ins := range instances { + if ins.depleted { + depleted = append(depleted, ins) + } else if ins.sharedMax > 0 && ins.sharedCur < ins.sharedMax { + timed = append(timed, ins) + } else { + freshIdxs = append(freshIdxs, ins.idx) + } + } + + roomDesc := def.InRoomDescription + if roomDesc != "" { + roomDesc = color.ExpandTags(g.colorMode(sess), roomDesc) + } + 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 = fmt.Sprintf("A %s is here.", coloredName) + } else { + line = fmt.Sprintf("%d %s are here.", len(freshIdxs), coloredPlural) + } + var suffix string + if multi && (len(timed) > 0 || len(depleted) > 0) { + suffix = fmt.Sprintf(" [%s]", joinInts(freshIdxs)) + } + qualityTimer := "" + if showTimers && len(instances) > 0 && instances[0].quality > 0 { + qualityTimer = fmt.Sprintf(" (Burning for %d more ticks)", instances[0].quality) + } + lines = append(lines, fmt.Sprintf("%s%s%s", line, suffix, qualityTimer)) + } + + for _, ins := range timed { + var line string + if roomDesc != "" { + line = roomDesc + } else { + line = fmt.Sprintf("A %s is here.", coloredName) + } + tag := "" + if multi { + tag = fmt.Sprintf(" [%d]", ins.idx) + } + timer := "" + if showTimers { + timer = fmt.Sprintf(" (despawn: %d/%d)", ins.sharedCur, ins.sharedMax) + } + lines = append(lines, fmt.Sprintf("%s%s%s", line, tag, timer)) + } + + for _, ins := range depleted { + var line string + if roomDesc != "" { + line = roomDesc + } else { + line = fmt.Sprintf("A %s is here.", coloredName) + } + tag := "" + if multi { + tag = fmt.Sprintf(" [%d]", ins.idx) + } + timer := "" + if showTimers { + timer = fmt.Sprintf(" (respawns in %d ticks)", ins.respawnIn) + } + lines = append(lines, fmt.Sprintf("%s (depleted)%s%s", line, tag, timer)) + } + } + + lines = append(lines, g.showFarmPatches(sess, p)...) + return lines +} + +func (g *Game) showGroundItems(sess *net.Session, p *player.Player, room *world.Room) []string { + ground := g.World.GroundItemsDetailed(p.RoomID) + if len(ground) == 0 { + return nil + } + showDespawn := p.OptionBool("despawn") + showReserve := p.OptionBool("reserve") + + type displayLine struct { + name string + quantity int + colorName string + annotation string + } + + type groupKey struct { + itemID string + despawnTimer int + } + + var lines []displayLine + groups := make(map[groupKey]*displayLine) + var groupOrder []groupKey + + for _, info := range ground { + def, err := g.ItemStore.Load(info.ItemID) + name := info.ItemID + if err == nil { + name = def.Name + } + coloredName := g.itemColorize(sess, def, name) + + if info.ReservedFor != "" { + var parts []string + if showReserve { + parts = append(parts, fmt.Sprintf("reserved for %s %dt", info.ReservedFor, info.ReserveTimer)) + } else { + parts = append(parts, "reserved") + } + if showDespawn && !info.IsSpawn { + parts = append(parts, fmt.Sprintf("despawns %dt", info.DespawnTimer)) + } + annotation := "" + if len(parts) > 0 { + annotation = fmt.Sprintf(" (%s)", strings.Join(parts, ", ")) + } + lines = append(lines, displayLine{ + name: name, + quantity: info.Quantity, + colorName: coloredName, + annotation: annotation, + }) + continue + } + + timerKey := -1 + if showDespawn && !info.IsSpawn { + timerKey = info.DespawnTimer + } + key := groupKey{itemID: info.ItemID, despawnTimer: timerKey} + + if existing, ok := groups[key]; ok { + existing.quantity += info.Quantity + } else { + annotation := "" + if showDespawn && !info.IsSpawn { + annotation = fmt.Sprintf(" (despawns %dt)", info.DespawnTimer) + } + dl := &displayLine{ + name: name, + quantity: info.Quantity, + colorName: coloredName, + annotation: annotation, + } + groups[key] = dl + groupOrder = append(groupOrder, key) + } + } + + for _, key := range groupOrder { + lines = append(lines, *groups[key]) + } + + sort.Slice(lines, func(i, j int) bool { + return strings.ToLower(lines[i].name) < strings.ToLower(lines[j].name) + }) + + var out []string + out = append(out, "") + out = append(out, "On the ground:") + + type fmtLine struct { + prefix string + annotation string + } + var fmtLines []fmtLine + maxPrefix := 0 + + for _, dl := range lines { + prefix := "" + if dl.quantity > 1 { + prefix = fmt.Sprintf(" %d x %s", dl.quantity, dl.colorName) + } else { + prefix = fmt.Sprintf(" %s", dl.colorName) + } + if visibleLen(prefix) > maxPrefix { + maxPrefix = visibleLen(prefix) + } + fmtLines = append(fmtLines, fmtLine{prefix, dl.annotation}) + } + + for _, l := range fmtLines { + if l.annotation != "" { + pad := maxPrefix + 1 + (len(l.prefix) - visibleLen(l.prefix)) + out = append(out, fmt.Sprintf("%-*s%s", pad, l.prefix, l.annotation)) + } else { + out = append(out, l.prefix) + } + } + return out +} + +func (g *Game) showRoomPlayers(sess *net.Session, p *player.Player, room *world.Room) { + others := g.Hub.PlayersInRoom(p.RoomID) + for _, other := range others { + if other != sess && other.Player != nil { + op := other.Player + line := fmt.Sprintf("\n%s is here", g.colorize(sess, "player_name", op.Name)) + if cs := g.Combat.Get(op.Name); cs != nil { + if mob := g.MobStore.GetInstance(cs.MobID); mob != nil && mob.HP > 0 { + name := mobDisplayName(mob, false) + if idx := mobInstanceIdx(mob, g.MobStore.MobsInRoom(p.RoomID)); idx > 0 { + name += fmt.Sprintf(" [%d]", idx) + } + line += fmt.Sprintf(" (fighting %s)", name) + } + } else if desc := g.playerActionDisplay(op); desc != "" { + line += ", " + desc + } + sess.WriteLine(line + ".") + } + } +} |
