KoboldSim/koboldsim/cardtypes.go

148 lines
3.6 KiB
Go
Raw Normal View History

2023-04-03 07:17:01 +00:00
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)
}