aboutsummaryrefslogtreecommitdiff
path: root/go/game/playerControl.go
blob: 94c8be7e7d39fd2e868796ce8bac3111ce35ab55 (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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package game

import (
	"fmt"
	"log"
)

type PlayerNotificationType int

const (
	DeclaredActionNotification PlayerNotificationType = iota
	ResolvedActionNotification
	PriorityNotification
	TargetSelectionPrompt
	DeclareTriggeredActionsPrompt
)

func (n PlayerNotificationType) String() string {
	switch n {
	case DeclaredActionNotification:
		return "DeclaredActionNotification"
	case ResolvedActionNotification:
		return "ResolvedActionNotification"
	case PriorityNotification:
		return "PriorityNotification"
	case TargetSelectionPrompt:
		return "TargetSelectionPrompt"
	case DeclareTriggeredActionsPrompt:
		return "DeclareTriggeredActionsPrompt"
	default:
		log.Panicf("Unhandled notification %d", n)
		return ""
	}
}

func (n PlayerNotification) IsPriorityNotification() bool {
	return n.Notification == PriorityNotification
}

type PlayerNotification struct {
	Notification PlayerNotificationType
	Context      interface{}
	Error        error
}

func (n *PlayerNotification) String() string {
	if n.Error != nil {
		return fmt.Sprintf("error %v: %v", n.Notification, n.Error)
	}

	return fmt.Sprintf("%v: %v", n.Notification, n.Context)
}

type TargetSelectionCtx struct {
	Action Action
	Prompt string
}

func newPriorityNotification() PlayerNotification {
	return PlayerNotification{PriorityNotification, nil, nil}
}

func newDeclaredActionNotification(a Action, err error) PlayerNotification {
	return PlayerNotification{DeclaredActionNotification, a, err}
}

func newResolvedActionNotification(a Action, err error) PlayerNotification {
	return PlayerNotification{ResolvedActionNotification, a, err}
}

func newTargetSelectionPrompt(a Action, desc string) PlayerNotification {
	return PlayerNotification{TargetSelectionPrompt, TargetSelectionCtx{a, desc}, nil}
}

func newUpkeepPrompt(p *Player) PlayerNotification {
	a := newUpkeepAction(p)
	return newTargetSelectionPrompt(a, "Select units to disband")
}

func newBuyPrompt(p *Player) PlayerNotification {
	a := newBuyAction(p)
	prompt := newTargetSelectionPrompt(a, "Select a card to buy")
	return prompt
}

func newHandCardSelectionPrompt(p *Player, min, max int) PlayerNotification {
	a := newHandCardSelection(p, min, max)
	desc := fmt.Sprintf("Select between %d and %d hand cards", min, max)
	return newTargetSelectionPrompt(a, desc)
}

func newDeclareTriggeredActionsPrompt(triggeredActions []*TriggeredAction) PlayerNotification {
	return PlayerNotification{DeclareTriggeredActionsPrompt, triggeredActions, nil}
}

type PlayerControl interface {
	Player() *Player
	RecvAction() Action
	SendNotification(PlayerNotification)
}

type ChanPlayerControl struct {
	player        *Player
	actions       chan Action
	notifications chan PlayerNotification
}

func (c *ChanPlayerControl) Player() *Player                       { return c.player }
func (c *ChanPlayerControl) SendAction(a Action)                   { c.actions <- a }
func (c *ChanPlayerControl) RecvAction() Action                    { return <-c.actions }
func (c *ChanPlayerControl) SendNotification(n PlayerNotification) { c.notifications <- n }
func (c *ChanPlayerControl) RecvNotification() *PlayerNotification {
	select {
	case n := <-c.notifications:
		return &n
	default:
		return nil
	}
}

func NewChanPlayerControl(p *Player) *ChanPlayerControl {
	a := make(chan Action)
	n := make(chan PlayerNotification)
	return &ChanPlayerControl{p, a, n}
}

func prompt(ctrl PlayerControl, notification PlayerNotification) Action {
	ctrl.SendNotification(notification)
	return ctrl.RecvAction()
}

func promptBuy(ctrl PlayerControl) Action {
	return prompt(ctrl, newBuyPrompt(ctrl.Player()))
}

func promptAction(ctrl PlayerControl) Action {
	return prompt(ctrl, newPriorityNotification())
}