CardSimEngine/cardsim/card.go
Kistaro Windrider 8153a7c083
Card.Then
Add a callback to the Card interface to be invoked after an option is selected. This will most frequently be used for cards that always want to shuffle themselves back into the deck regardless of the Option selected.
2023-03-27 20:21:57 -07:00

107 lines
3.6 KiB
Go

package cardsim
// A Card represents an option available to the player. Its methods may be
// called many times per turn as the player considers their options.
type Card[C StatsCollection] interface {
// Title is the short name of the card displayed in the hand
// and at the top of the card output. It receives the current
// player as an argument. If it returns an error that is not
// a warning, the game crashes.
Title(p *Player[C]) (Message, error)
// EventText returns the text to display on the card. If it returns an
// error that is not a warning, the game crashes.
EventText(p *Player[C]) (Message, error)
// Options returns the possible actions the player can take for this card.
// There must be at least one option.
Options(p *Player[C]) ([]CardOption[C], error)
// Then is invoked after an option is selected and executed. The selected
// option is provided as an argument. This allows cards to do certain
// cleanup for every action -- for example, returning to the deck.
Then(p *Player[C], option CardOption[C]) error
}
// A CardOption represents a choice a player could make for some card.
type CardOption[C StatsCollection] interface {
// OptionText returns the text displayed for this option. It may be called
// many times within a turn as the player considers their options. If it
// returns an error that is not a warning, the game crashes.
OptionText(p *Player[C]) (Message, error)
// Enact is called exactly once if the player chooses the option. It is
// expected to update values in `p`. It returns the text displayed to the
// player as a result of their action. If it returns an error that is not
// a warning, the game crashes.
//
// After an option is enacted, the card is deleted. If a card should be
// repeatable, Enact must return it to the deck (on every option).
Enact(p *Player[C]) (Message, error)
}
// A BasicCard is a Card with fixed title, text, options, and optional post-option callback.
type BasicCard[C StatsCollection] struct {
CardTitle Message
CardText Message
CardOptions []CardOption[C]
AfterOption func(p *Player[C], option CardOption[C]) error
}
func (b *BasicCard[C]) Title(p *Player[C]) (Message, error) {
return b.CardTitle, nil
}
func (b *BasicCard[C]) EventText(p *Player[C]) (Message, error) {
return b.CardText, nil
}
func (b *BasicCard[C]) Options(_ *Player[C]) ([]CardOption[C], error) {
return b.CardOptions, nil
}
func (b *BasicCard[C]) Then(p *Player[C], option CardOption[C]) error {
if b.AfterOption == nil {
return nil
}
return b.AfterOption(p, option)
}
// A BasicOption is a CardOption with fixed text, effects, and output.
type BasicOption[C StatsCollection] struct {
Text Message
Effect func(*Player[C]) error
Output Message
}
// OptionText implements CardOption.
func (b *BasicOption[C]) OptionText(p *Player[C]) (Message, error) {
return b.Text, nil
}
// Enact implements CardOption.
func (b *BasicOption[C]) Enact(p *Player[C]) (Message, error) {
return b.Output, b.Effect(p)
}
// OptionFunc attaches a fixed prompt to an Enact-like function. Unlike
// BasicOption, the enactment function provided to OptionFunc returns
// the text that should be output as a result of the action, so it is
// possible to dynamically generate this text.
func OptionFunc[C StatsCollection](text Message, f func(*Player[C]) (Message, error)) CardOption[C] {
return &optionFunc[C]{text, f}
}
type optionFunc[C StatsCollection] struct {
text Message
f func(*Player[C]) (Message, error)
}
func (o *optionFunc[C]) OptionText(p *Player[C]) (Message, error) {
return o.text, nil
}
func (o *optionFunc[C]) Enact(p *Player[C]) (Message, error) {
return o.f(p)
}