CardOption.Enable
Make it possible for a card to display an option but not actually allow it to be selected. It's up to the UI layer to decide how to display options that are not enabled. The option text should probably contiain a note on why the option cannot be selected...
This commit is contained in:
parent
45e1eeebf7
commit
09fdf19948
@ -52,6 +52,9 @@ type CardOption[C StatsCollection] interface {
|
|||||||
// After an option is enacted, the card is deleted. If a card should be
|
// 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).
|
// repeatable, Enact must return it to the deck (on every option).
|
||||||
Enact(p *Player[C]) (Message, error)
|
Enact(p *Player[C]) (Message, error)
|
||||||
|
|
||||||
|
// Enabled returns whether this option can curently be enacted.
|
||||||
|
Enabled(p *Player[C]) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// A BasicCard is a Card with fixed title, text, options, and optional
|
// A BasicCard is a Card with fixed title, text, options, and optional
|
||||||
@ -64,22 +67,27 @@ type BasicCard[C StatsCollection] struct {
|
|||||||
AfterOption func(p *Player[C], option CardOption[C]) error
|
AfterOption func(p *Player[C], option CardOption[C]) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasicCard[C]) Title(p *Player[C]) (Message, error) {
|
// Title implements Card.
|
||||||
|
func (b *BasicCard[C]) Title(_ *Player[C]) (Message, error) {
|
||||||
return b.CardTitle, nil
|
return b.CardTitle, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Urgent implements Card.
|
||||||
func (b *BasicCard[C]) Urgent(_ *Player[C]) bool {
|
func (b *BasicCard[C]) Urgent(_ *Player[C]) bool {
|
||||||
return b.IsUrgent
|
return b.IsUrgent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasicCard[C]) EventText(p *Player[C]) (Message, error) {
|
// EventText implements Card.
|
||||||
|
func (b *BasicCard[C]) EventText(_ *Player[C]) (Message, error) {
|
||||||
return b.CardText, nil
|
return b.CardText, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Options implements Card.
|
||||||
func (b *BasicCard[C]) Options(_ *Player[C]) ([]CardOption[C], error) {
|
func (b *BasicCard[C]) Options(_ *Player[C]) ([]CardOption[C], error) {
|
||||||
return b.CardOptions, nil
|
return b.CardOptions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then implements Card.
|
||||||
func (b *BasicCard[C]) Then(p *Player[C], option CardOption[C]) error {
|
func (b *BasicCard[C]) Then(p *Player[C], option CardOption[C]) error {
|
||||||
if b.AfterOption == nil {
|
if b.AfterOption == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -87,11 +95,13 @@ func (b *BasicCard[C]) Then(p *Player[C], option CardOption[C]) error {
|
|||||||
return b.AfterOption(p, option)
|
return b.AfterOption(p, option)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BasicCard[C]) Drawn(p *Player[C]) bool {
|
// Drawn implements Card.
|
||||||
|
func (b *BasicCard[C]) Drawn(_ *Player[C]) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// A BasicOption is a CardOption with fixed text, effects, and output.
|
// A BasicOption is a CardOption with fixed text, effects, and output.
|
||||||
|
// It's always enabled.
|
||||||
type BasicOption[C StatsCollection] struct {
|
type BasicOption[C StatsCollection] struct {
|
||||||
Text Message
|
Text Message
|
||||||
Effect func(*Player[C]) error
|
Effect func(*Player[C]) error
|
||||||
@ -108,6 +118,11 @@ func (b *BasicOption[C]) Enact(p *Player[C]) (Message, error) {
|
|||||||
return b.Output, b.Effect(p)
|
return b.Output, b.Effect(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enabled implements CardOption.
|
||||||
|
func (b *BasicOption[C]) Enabled(p *Player[C]) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// OptionFunc attaches a fixed prompt to an Enact-like function. Unlike
|
// OptionFunc attaches a fixed prompt to an Enact-like function. Unlike
|
||||||
// BasicOption, the enactment function provided to OptionFunc returns
|
// BasicOption, the enactment function provided to OptionFunc returns
|
||||||
// the text that should be output as a result of the action, so it is
|
// the text that should be output as a result of the action, so it is
|
||||||
@ -121,10 +136,17 @@ type optionFunc[C StatsCollection] struct {
|
|||||||
f func(*Player[C]) (Message, error)
|
f func(*Player[C]) (Message, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OptionText implements CardOption.
|
||||||
func (o *optionFunc[C]) OptionText(p *Player[C]) (Message, error) {
|
func (o *optionFunc[C]) OptionText(p *Player[C]) (Message, error) {
|
||||||
return o.text, nil
|
return o.text, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enact implements CardOption.
|
||||||
func (o *optionFunc[C]) Enact(p *Player[C]) (Message, error) {
|
func (o *optionFunc[C]) Enact(p *Player[C]) (Message, error) {
|
||||||
return o.f(p)
|
return o.f(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enabled implements CardOption.
|
||||||
|
func (o *optionFunc[C]) Enabled(p *Player[C]) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -277,9 +277,10 @@ func (p *Player[C]) HasUrgentCards() bool {
|
|||||||
// EnactCardUnchecked executes a card choice, removes it from the hand, and
|
// EnactCardUnchecked executes a card choice, removes it from the hand, and
|
||||||
// decrements the ActionsRemaining. It does not check for conflicting Urgent
|
// decrements the ActionsRemaining. It does not check for conflicting Urgent
|
||||||
// cards or already being out of actions. If no such card or card choice
|
// cards or already being out of actions. If no such card or card choice
|
||||||
// exists, this returns nil and ErrInvalidCard/ErrInvalidChoice. Otherwise, this returns
|
// exists, or the specified choice is not enabled, this returns nil and
|
||||||
// the result of enacting the card. If enacting the card causes an error,
|
// ErrInvalidCard/ErrInvalidChoice without changing anything. Otherwise, this
|
||||||
// the State becomes GameCrashed.
|
// returns the result of enacting the card. If enacting the card causes a
|
||||||
|
// serious error, the State becomes GameCrashed.
|
||||||
func (p *Player[C]) EnactCardUnchecked(cardIdx, choiceIdx int) (Message, error) {
|
func (p *Player[C]) EnactCardUnchecked(cardIdx, choiceIdx int) (Message, error) {
|
||||||
if cardIdx < 0 || cardIdx >= len(p.Hand) {
|
if cardIdx < 0 || cardIdx >= len(p.Hand) {
|
||||||
return nil, fmt.Errorf("%w: no card #%d when %d cards in hand", ErrInvalidCard, cardIdx, len(p.Hand))
|
return nil, fmt.Errorf("%w: no card #%d when %d cards in hand", ErrInvalidCard, cardIdx, len(p.Hand))
|
||||||
@ -293,7 +294,13 @@ func (p *Player[C]) EnactCardUnchecked(cardIdx, choiceIdx int) (Message, error)
|
|||||||
}
|
}
|
||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
if choiceIdx < 0 || choiceIdx > len(options) {
|
if choiceIdx < 0 || choiceIdx > len(options) {
|
||||||
errs.Add(fmt.Errorf("%w: no option #%d on card #%d with %d options", ErrInvalidCard, choiceIdx, cardIdx, len(options)))
|
errs.Add(fmt.Errorf("%w: no option #%d on card #%d with %d options", ErrInvalidChoice, choiceIdx, cardIdx, len(options)))
|
||||||
|
return nil, errs.Emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
chosen := options[choiceIdx]
|
||||||
|
if !chosen.Enabled(p) {
|
||||||
|
errs.Add(fmt.Errorf("%w: option %d on card %d was not enabled", ErrInvalidChoice, choiceIdx, cardIdx))
|
||||||
return nil, errs.Emit()
|
return nil, errs.Emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,9 +342,10 @@ func (p *Player[C]) EnactCard(cardIdx, choiceIdx int) (Message, error) {
|
|||||||
// EnactPermanentActionUnchecked executes a permanently-available action and
|
// EnactPermanentActionUnchecked executes a permanently-available action and
|
||||||
// decrements the ActionsRemaining. It does not check for conflicting Urgent
|
// decrements the ActionsRemaining. It does not check for conflicting Urgent
|
||||||
// cards or already being out of actions. If no such action or card option
|
// cards or already being out of actions. If no such action or card option
|
||||||
// exists, this returns nil and ErrInvalidCard/ErrInvalidChoice. Otherwise, this returns
|
// exists, or the option is not enabled, this returns nil and ErrInvalidCard
|
||||||
// the result of enacting the permanent action. If enacting the card causes an error,
|
// or ErrInvalidChoice without changing anything. Otherwise, this returns the
|
||||||
// the State becomes GameCrashed.
|
// result of enacting the permanent action. If enacting the card causes a
|
||||||
|
// serious error, the State becomes GameCrashed.
|
||||||
func (p *Player[C]) EnactPermanentActionUnchecked(actionIdx, choiceIdx int) (Message, error) {
|
func (p *Player[C]) EnactPermanentActionUnchecked(actionIdx, choiceIdx int) (Message, error) {
|
||||||
if actionIdx < 0 || actionIdx >= len(p.PermanentActions) {
|
if actionIdx < 0 || actionIdx >= len(p.PermanentActions) {
|
||||||
return nil, fmt.Errorf("%w: no action #%d when %d permanent actions exist", ErrInvalidCard, actionIdx, len(p.PermanentActions))
|
return nil, fmt.Errorf("%w: no action #%d when %d permanent actions exist", ErrInvalidCard, actionIdx, len(p.PermanentActions))
|
||||||
@ -354,17 +362,22 @@ func (p *Player[C]) EnactPermanentActionUnchecked(actionIdx, choiceIdx int) (Mes
|
|||||||
errs.Add(fmt.Errorf("%w: no option #%d on permanent action #%d with %d options", ErrInvalidChoice, choiceIdx, actionIdx, len(options)))
|
errs.Add(fmt.Errorf("%w: no option #%d on permanent action #%d with %d options", ErrInvalidChoice, choiceIdx, actionIdx, len(options)))
|
||||||
return nil, errs.Emit()
|
return nil, errs.Emit()
|
||||||
}
|
}
|
||||||
|
chosen := options[choiceIdx]
|
||||||
|
if !chosen.Enabled(p) {
|
||||||
|
errs.Add(fmt.Errorf("%w: option #%d on permanent action #%d is not enabled", ErrInvalidChoice, choiceIdx, actionIdx))
|
||||||
|
return nil, errs.Emit()
|
||||||
|
}
|
||||||
|
|
||||||
p.ActionsRemaining--
|
p.ActionsRemaining--
|
||||||
|
|
||||||
ret, err := options[choiceIdx].Enact(p)
|
ret, err := chosen.Enact(p)
|
||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
if IsSeriousError(err) {
|
if IsSeriousError(err) {
|
||||||
p.State = GameCrashed
|
p.State = GameCrashed
|
||||||
return ret, errs.Emit()
|
return ret, errs.Emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = card.Then(p, options[choiceIdx])
|
err = card.Then(p, chosen)
|
||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
if IsSeriousError(err) {
|
if IsSeriousError(err) {
|
||||||
p.State = GameCrashed
|
p.State = GameCrashed
|
||||||
|
Loading…
Reference in New Issue
Block a user