aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go/game/action.go23
-rw-r--r--go/game/state.go47
-rw-r--r--go/game/trigger.go90
3 files changed, 159 insertions, 1 deletions
diff --git a/go/game/action.go b/go/game/action.go
index fbabb06b..4f433845 100644
--- a/go/game/action.go
+++ b/go/game/action.go
@@ -79,6 +79,29 @@ func (a *ActionBase) CheckTargets(s *State) error {
return a.targets.CheckTargets(s)
}
+type TriggeredAction struct {
+ ActionBase
+ event Event
+}
+
+func newTriggeredAction(event Event, source Trigger, resolveFunc ActionResolveFunc,
+ costFunc ActionCostFunc,
+) *TriggeredAction {
+ return &TriggeredAction{
+ ActionBase: ActionBase{
+ source: source,
+ Card: source.Card(),
+ resolveFunc: resolveFunc,
+ costFunc: costFunc,
+ },
+ event: event,
+ }
+}
+
+func (a *TriggeredAction) String() string {
+ return fmt.Sprintf("%v ! %v", a.event, a.source)
+}
+
type PileDropAction struct {
ActionBase
pile []Permanent
diff --git a/go/game/state.go b/go/game/state.go
index 49ee0c06..6bb3dbf0 100644
--- a/go/game/state.go
+++ b/go/game/state.go
@@ -9,6 +9,7 @@ import (
"time"
"golang.org/x/exp/slices"
+ "muhq.space/muhqs-game/go/utils"
)
type State struct {
@@ -24,6 +25,8 @@ type State struct {
Rand *rand.Rand
eotEffects []effect
outstandingEquipment []*Card
+ events []Event
+ triggers []Trigger
}
func NewState() *State {
@@ -96,6 +99,39 @@ func (s *State) Loop() []*Player {
return winners
}
+func (s *State) removeTriggers(triggers []Trigger) {
+ for _, t := range triggers {
+ s.triggers = utils.RemoveFromUnorderedSlice(s.triggers, t)
+ }
+}
+
+func (s *State) handleTriggers() {
+ var actions []Action
+ var triggersToRemove []Trigger
+
+ for _, e := range s.events {
+ for _, t := range s.triggers {
+ a, remove := t.trigger(s, e)
+ if a != nil {
+ actions = append(actions, a...)
+ }
+ if remove {
+ triggersToRemove = append(triggersToRemove, t)
+ }
+ }
+ }
+
+ // Reset occured events
+ s.events = nil
+
+ s.removeTriggers(triggersToRemove)
+
+ orderedActions := s.orderTriggeredActions(actions)
+ for _, a := range orderedActions {
+ s.declareAction(a)
+ }
+}
+
func (s *State) stateBasedActions() {
for _, p := range s.Permanents {
p.Card().Impl.stateBasedActions(s, p)
@@ -104,6 +140,8 @@ func (s *State) stateBasedActions() {
s.destroyPermanent(p)
}
}
+
+ s.handleTriggers()
}
func (s *State) IsValidPlay(a *PlayAction) error {
@@ -322,6 +360,11 @@ func (s *State) declareAction(a Action) {
s.broadcastNotification(newDeclaredActionNotification(a, err))
}
+func (s *State) orderTriggeredActions(actions []Action) []Action {
+ // TODO: implement ordering
+ return actions
+}
+
func (s *State) allPassing(skipFirst bool) bool {
nPlayers := len(s.Players)
i := 0
@@ -600,6 +643,8 @@ func (s *State) endOfTurn() {
for _, e := range s.eotEffects {
e.end(s)
}
+ s.eotEffects = nil
- s.eotEffects = []effect{}
+ s.events = append(s.events, newEotEvent())
+ s.stateBasedActions()
}
diff --git a/go/game/trigger.go b/go/game/trigger.go
new file mode 100644
index 00000000..39901d71
--- /dev/null
+++ b/go/game/trigger.go
@@ -0,0 +1,90 @@
+package game
+
+import (
+ "fmt"
+ "log"
+)
+
+type eventType int
+
+const (
+ destruction eventType = iota
+ eot
+ sacrifice
+ play
+)
+
+var EventTypes = struct {
+ Destruction eventType
+ Eot eventType
+ Sacrifice eventType
+ Play eventType
+}{
+ Destruction: destruction,
+ Eot: eot,
+ Play: play,
+}
+
+func (e eventType) String() string {
+ switch e {
+ case destruction:
+ return "destruction"
+ case eot:
+ return "eot"
+ case sacrifice:
+ return "sacrifice"
+ case play:
+ return "play"
+ }
+
+ log.Panicf("Unknown evenType", e)
+ return ""
+}
+
+type Event struct {
+ eventType eventType
+ sources []interface{}
+}
+
+func (e Event) String() string {
+ if len(e.sources) == 0 {
+ return e.eventType.String()
+ }
+
+ return fmt.Sprintf("%v:%v", e.sources, e.eventType)
+}
+
+func newEotEvent() Event {
+ return Event{eventType: eot}
+}
+
+type Trigger interface {
+ Card() *Card
+ String() string
+ trigger(*State, Event) ([]Action, bool)
+}
+
+type triggerBase struct {
+ card *Card
+ condition func(*State, Event) (bool, bool)
+ resolveFunc ActionResolveFunc
+ costFunc ActionCostFunc
+ desc string
+}
+
+func (t *triggerBase) Card() *Card {
+ return t.card
+}
+
+func (t *triggerBase) String() string {
+ return t.desc
+}
+
+func (t *triggerBase) trigger(s *State, e Event) ([]Action, bool) {
+ triggered, remove := t.condition(s, e)
+ if !triggered {
+ return nil, remove
+ }
+
+ return []Action{newTriggeredAction(e, t, t.resolveFunc, t.costFunc)}, remove
+}