aboutsummaryrefslogtreecommitdiff
path: root/internal/game/act_room.go
blob: 889ce85c439ac6de038764f89436c96d2c367bae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package game

import (
	"fmt"
	"strings"

	"thehouseoficarus/internal/net"
	"thehouseoficarus/internal/player"
)

// runEnterSteps evaluates a room's on_enter block for the player. The first
// trigger whose Condition passes wins; its Steps run as a scripted sequence
// (room-locked, so steps are skipped if the player immediately leaves).
func (g *Game) runEnterSteps(sess *net.Session, roomID int) {
	room, err := g.World.LoadRoom(roomID)
	if err != nil || len(room.OnEnter) == 0 {
		return
	}
	p := sess.Player
	if p == nil {
		return
	}
	g.runTrigger(sess, p, room.OnEnter, roomID, nil, true)
}

// runExitSteps evaluates a room's on_exit block for the player. It fires the
// first matching trigger as a non-room-locked sequence using the room being
// left as the reference room (broadcasts/spawn resolve to the old room). It is
// invoked before the player's RoomID is updated to the destination.
func (g *Game) runExitSteps(sess *net.Session, roomID int) {
	room, err := g.World.LoadRoom(roomID)
	if err != nil || len(room.OnExit) == 0 {
		return
	}
	p := sess.Player
	if p == nil {
		return
	}
	g.runTrigger(sess, p, room.OnExit, roomID, nil, false)
}

// applyFlagMutations sets global and player flags. It is the player-scoped
// flag step of applyStep, called once per step that carries set_global_flags
// and/or set_player_flags. scopeGlobal sets globals directly in applyStep
// instead (so world-scoped cascades don't reach back into this helper).
func (g *Game) applyFlagMutations(p *player.Player, setGlobalFlags, setPlayerFlags map[string]any) {
	g.GlobalFlags.SetAll(setGlobalFlags)
	if len(setPlayerFlags) > 0 {
		for k, v := range setPlayerFlags {
			g.setPlayerFlag(p, k, v)
		}
	}
}

func (g *Game) BroadcastRespawns() {
	respawns := g.World.FlushObjRespawns()
	for _, st := range respawns {
		def, err := g.ObjectStore.Load(st.DefID)
		if err != nil || !def.IsGatherable() {
			continue
		}
		cfg := def.Gather
		if cfg.RespawnBroadcast == "" {
			continue
		}
		name := def.Name
		if idx := st.Index + 1; len(g.World.FindObjInstances(st.RoomID, st.DefID)) > 1 {
			name += fmt.Sprintf(" [%d]", idx)
		}
		msg := strings.ReplaceAll(cfg.RespawnBroadcast, "{name}", name)
		if g.Hub != nil {
			for _, sess := range g.Hub.PlayersInRoom(st.RoomID) {
				sess.WriteLine(g.colorize(sess, "broadcast", msg))
			}
		}
	}
}

// isCharLive reports whether the named player is currently connected via the
// given session (used by older helpers that still reference it).
func (g *Game) isCharLive(name string, sess *net.Session) bool {
	g.charsMu.Lock()
	defer g.charsMu.Unlock()
	return g.loggedInChars[name] == sess
}