Reversible policies
This commit is contained in:
parent
825ee8d053
commit
0e1f5ff246
@ -8,3 +8,4 @@ import "git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
|
||||
type Player = cardsim.Player[*KoboldMine]
|
||||
type Card = cardsim.Card[*KoboldMine]
|
||||
type InfoPanel = cardsim.InfoPanel[*KoboldMine]
|
||||
type CardOption = cardsim.CardOption[*KoboldMine]
|
||||
|
147
koboldsim/cardtypes.go
Normal file
147
koboldsim/cardtypes.go
Normal file
@ -0,0 +1,147 @@
|
||||
package koboldsim
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOptionNotEnabled = errors.New("option not enabled")
|
||||
ErrPolicyNotEnacted = errors.New("cannot unenact policy that is not enacted")
|
||||
)
|
||||
|
||||
type Policy interface {
|
||||
cardsim.CardOption[*KoboldMine]
|
||||
// Unenact reverses the previous enactment of this policy.
|
||||
Unenact(p *Player) error
|
||||
|
||||
// LastEnacted informs this Policy which choice was last enacted; it will
|
||||
// need to prepare to describe itself differently depending on whether
|
||||
// this is itself or not. The policy must return the CardOption that should
|
||||
// be used further, which is usually self.
|
||||
//
|
||||
// The Card that would present this Policy as an option must use this,
|
||||
// and provide the active policy that this is a candidate to replace,
|
||||
LastEnacted(CardOption) CardOption
|
||||
}
|
||||
|
||||
// A SwitchingCard is an issue card that remembers which option was selected
|
||||
// previously, and undoes it before doing a different one. It is always valid
|
||||
// to draw.
|
||||
type SwitchingCard struct {
|
||||
Name cardsim.Message
|
||||
Desc cardsim.Message
|
||||
IsUrgent bool
|
||||
After func(*SwitchingCard, *Player, CardOption) error
|
||||
Policies []Policy
|
||||
lastPolicy CardOption
|
||||
}
|
||||
|
||||
// Title implements Card.
|
||||
func (s *SwitchingCard) Title(*Player) cardsim.Message {
|
||||
return s.Name
|
||||
}
|
||||
|
||||
// Urgent implements Card.
|
||||
func (s *SwitchingCard) Urgent(*Player) bool {
|
||||
return s.IsUrgent
|
||||
}
|
||||
|
||||
// Drawn implements Card.
|
||||
func (s *SwitchingCard) Drawn(*Player) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// EventText implements Card.
|
||||
func (s *SwitchingCard) EventText(*Player) (cardsim.Message, error) {
|
||||
return s.Desc, nil
|
||||
}
|
||||
|
||||
// Options implements Card.
|
||||
func (s *SwitchingCard) Options(p *Player) ([]CardOption, error) {
|
||||
ret := make([]CardOption, len(s.Policies))
|
||||
for i, p := range s.Policies {
|
||||
ret[i] = p.LastEnacted(s.lastPolicy)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Then implements Card.
|
||||
func (s *SwitchingCard) Then(p *Player, o CardOption) error {
|
||||
s.lastPolicy = o
|
||||
if s.After != nil {
|
||||
return s.After(s, p, o)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BasicPolicy is a straightfoward implementation of Policy.
|
||||
type BasicPolicy struct {
|
||||
UnenactedDesc cardsim.Message
|
||||
EnactedDesc cardsim.Message
|
||||
NothingChanged cardsim.Message
|
||||
Do func(*Player) (cardsim.Message, error)
|
||||
Undo func(*Player) error
|
||||
CanDo func(*Player) bool
|
||||
|
||||
currentlyEnacted bool
|
||||
}
|
||||
|
||||
// YesWeCan returns true. It's the default value for BasicPolicy.CanDo / BasicPolicy.CanUndo.
|
||||
func YesWeCan(*Player) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// lastEnacted notifies b about the last-enacted policy in its group. It updates
|
||||
// b.currentlyEnacted accordingly and returns itself as a generic CardOption.
|
||||
//
|
||||
// It also installs placeholders if CanDo or CanUndo is unspecified.
|
||||
func (b *BasicPolicy) LastEnacted(c CardOption) CardOption {
|
||||
b.currentlyEnacted = false
|
||||
if o, ok := c.(*BasicPolicy); ok && o == b {
|
||||
b.currentlyEnacted = true
|
||||
}
|
||||
if b.CanDo == nil {
|
||||
b.CanDo = YesWeCan
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// OptionText implements CardOption.
|
||||
func (b *BasicPolicy) OptionText(*Player) (cardsim.Message, error) {
|
||||
if b.currentlyEnacted {
|
||||
return b.EnactedDesc, nil
|
||||
}
|
||||
return b.UnenactedDesc, nil
|
||||
}
|
||||
|
||||
// Enact implements CardOption.
|
||||
func (b *BasicPolicy) Enact(p *Player) (cardsim.Message, error) {
|
||||
if b.currentlyEnacted {
|
||||
return b.NothingChanged, nil
|
||||
}
|
||||
if !b.CanDo(p) {
|
||||
return nil, ErrOptionNotEnabled
|
||||
}
|
||||
return b.Do(p)
|
||||
}
|
||||
|
||||
// Unenact implements Policy.
|
||||
func (b *BasicPolicy) Unenact(p *Player) error {
|
||||
if !b.currentlyEnacted {
|
||||
return ErrPolicyNotEnacted
|
||||
}
|
||||
return b.Undo(p)
|
||||
}
|
||||
|
||||
// Enabled implements CardOption.
|
||||
func (b *BasicPolicy) Enabled(p *Player) bool {
|
||||
if b.currentlyEnacted {
|
||||
return true
|
||||
}
|
||||
if b.CanDo == nil {
|
||||
b.CanDo = YesWeCan
|
||||
}
|
||||
return b.CanDo(p)
|
||||
}
|
Loading…
Reference in New Issue
Block a user