diff options
| author | historia <[not public]> | 2026-06-25 21:23:34 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-25 21:23:34 -0400 |
| commit | e2d5b081f27141bb3dd89dbe595860b8a1345d55 (patch) | |
| tree | 3090f8150580fe85a872caa04165ff70613bbaa8 /internal/game/act_room.go | |
| parent | 84d74ca4351a97148ad8339676f9df7946bc21fb (diff) | |
| download | thehouseoficarus-e2d5b081f27141bb3dd89dbe595860b8a1345d55.tar.gz | |
feat: on_enter features ported over to triggers, cosmetic fixes with trigger messages
Diffstat (limited to 'internal/game/act_room.go')
| -rw-r--r-- | internal/game/act_room.go | 104 |
1 files changed, 78 insertions, 26 deletions
diff --git a/internal/game/act_room.go b/internal/game/act_room.go index fec7304..ff7a780 100644 --- a/internal/game/act_room.go +++ b/internal/game/act_room.go @@ -4,13 +4,14 @@ import ( "fmt" "strings" + "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" "thehouseoficarus/internal/world" ) -// enterSeq is an in-flight on_enter cutscene for a single player. It is driven -// one step at a time by EnterSeqTick. +// enterSeq is an in-flight on_enter stepped sequence for a single player. It is +// driven one step at a time by EnterSeqTick. type enterSeq struct { sess *net.Session playerName string @@ -22,8 +23,8 @@ type enterSeq struct { // runEnterSteps evaluates a room's on_enter script for the player. Steps whose // condition fails are dropped. If none of the surviving steps are "timed" -// (no delay, no flag mutation) the messages are printed synchronously, exactly -// as before. Otherwise the surviving steps become a scheduled cutscene driven +// (no delay, no flag mutation) the messages are printed synchronously. +// Otherwise the surviving steps become a scheduled enter sequence driven // by EnterSeqTick. func (g *Game) runEnterSteps(sess *net.Session, roomID int) { room, err := g.World.LoadRoom(roomID) @@ -36,21 +37,21 @@ func (g *Game) runEnterSteps(sess *net.Session, roomID int) { } var steps []world.EnterStep - cutscene := false + sequenced := false for _, step := range room.OnEnter { if step.Condition != nil && !g.checkCondition(sess, step.Condition) { continue } steps = append(steps, step) if step.IsTimed() { - cutscene = true + sequenced = true } } if len(steps) == 0 { return } - if !cutscene { + if !sequenced { for _, step := range steps { if step.Message != "" { sess.WriteLine(step.Message) @@ -59,16 +60,16 @@ func (g *Game) runEnterSteps(sess *net.Session, roomID int) { return } - g.startEnterCutscene(sess, p, roomID, steps) + g.startEnterSeq(sess, p, roomID, steps) } -// startEnterCutscene registers a scheduled on_enter sequence and persists a -// marker on the player so the cutscene can be resumed on reconnect if it is -// interrupted (disconnect, server restart). -func (g *Game) startEnterCutscene(sess *net.Session, p *player.Player, roomID int, steps []world.EnterStep) { +// startEnterSeq registers a scheduled on_enter sequence and persists a marker +// on the player so the sequence can be resumed on reconnect if interrupted +// (disconnect, server restart). +func (g *Game) startEnterSeq(sess *net.Session, p *player.Player, roomID int, steps []world.EnterStep) { g.cancelEnterSeq(p.Name) - if p.CutsceneRoom != roomID { - p.CutsceneRoom = roomID + if p.EnterSeqRoom != roomID { + p.EnterSeqRoom = roomID g.AccountStore.SaveCharacter(p) } g.enterMu.Lock() @@ -82,9 +83,9 @@ func (g *Game) startEnterCutscene(sess *net.Session, p *player.Player, roomID in g.enterMu.Unlock() } -// EnterSeqTick advances every in-flight cutscene by one tick. Sequences for a -// player who is no longer connected are paused (left for resume); sequences are -// removed from the map on completion or cancellation. +// EnterSeqTick advances every in-flight enter sequence by one tick. Sequences +// for a player who is no longer connected are paused (left for resume); +// sequences are removed from the map on completion or cancellation. func (g *Game) EnterSeqTick() { g.enterMu.Lock() seqs := make([]*enterSeq, 0, len(g.enterSeqs)) @@ -137,20 +138,71 @@ func (g *Game) fireEnterStep(seq *enterSeq, step world.EnterStep) { if p == nil || p.RoomID != seq.roomID { return } + seqSpec := g.resolveColor(seq.sess, "sequence") + broadcastSpec := g.resolveColor(seq.sess, "broadcast") + mode := g.colorMode(seq.sess) if step.Message != "" { - // Break from the prompt on the first line only, so a multi-line - // cutscene reads as tight consecutive lines. + msg := expandTemplate(step.Message, p.Name, nil) + msg = color.ExpandTagsDefault(mode, seqSpec, msg) if !seq.started { - seq.sess.WriteLine("\n" + step.Message) + seq.sess.WriteLine("\n" + msg) seq.started = true } else { - seq.sess.WriteLine(step.Message) + seq.sess.WriteLine(msg) + } + } + if step.Broadcast != "" && g.Hub != nil { + msg := expandTemplate(step.Broadcast, p.Name, nil) + msg = color.ExpandTagsDefault(mode, broadcastSpec, msg) + for _, other := range g.Hub.PlayersInRoom(seq.roomID) { + other.WriteLine(g.colorize(other, "broadcast", "\n"+msg)) + } + } + if step.BroadcastGlobal != "" && g.Hub != nil { + msg := expandTemplate(step.BroadcastGlobal, p.Name, nil) + msg = color.ExpandTagsDefault(mode, broadcastSpec, msg) + for _, other := range g.Hub.AllSessions() { + if other.Player != nil { + other.WriteLine(g.colorize(other, "broadcast", "\n"+msg)) + } } } if len(step.SetFlags) > 0 || len(step.SetPlayerFlags) > 0 { g.applyFlagMutations(p, step.SetFlags, step.SetPlayerFlags) g.AccountStore.SaveCharacter(p) } + if step.SpawnMob != nil { + g.spawnTriggerMob(seq.sess, p, step.SpawnMob, seq.roomID) + } + if step.DespawnMob != "" { + g.despawnTriggerMobs(step.DespawnMob, p.Name) + } + if step.GiveItem != "" { + slot := p.FirstFreeSlot() + if slot == -1 { + seq.sess.WriteLine("Your inventory is too full to receive that.") + } else { + p.SetInvSlot(slot, &player.InventorySlot{ItemID: step.GiveItem, Quantity: 1}) + g.AccountStore.SaveCharacter(p) + } + } + if step.TakeItem != "" { + if p.HasItem(step.TakeItem) { + p.RemoveItem(step.TakeItem, 1) + g.AccountStore.SaveCharacter(p) + } + } + if step.Heal > 0 { + p.HP += step.Heal + if maxHP := p.MaxHP(); p.HP > maxHP { + p.HP = maxHP + } + g.AccountStore.SaveCharacter(p) + seq.sess.WriteLine(fmt.Sprintf("You regain %d hitpoints.", step.Heal)) + } + if step.Teleport > 0 { + g.teleportPlayer(seq.sess, p, step.Teleport) + } } func (g *Game) completeEnterSeq(seq *enterSeq) { @@ -161,16 +213,16 @@ func (g *Game) completeEnterSeq(seq *enterSeq) { if p == nil { return } - if p.CutsceneRoom == seq.roomID { - p.CutsceneRoom = 0 + if p.EnterSeqRoom == seq.roomID { + p.EnterSeqRoom = 0 g.AccountStore.SaveCharacter(p) } g.writePrompt(seq.sess) } -// cancelEnterSeq drops any in-flight cutscene for the player. It does not touch -// the persisted CutsceneRoom marker, so a cutscene cancelled by disconnect can -// still be resumed on reconnect. +// cancelEnterSeq drops any in-flight enter sequence for the player. It does not +// touch the persisted EnterSeqRoom marker, so a sequence cancelled by +// disconnect can still be resumed on reconnect. func (g *Game) cancelEnterSeq(name string) { g.enterMu.Lock() delete(g.enterSeqs, name) |
