Compare commits
	
		
			2 Commits
		
	
	
		
			22c4718faf
			...
			8d1aa0141f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						8d1aa0141f
	
				 | 
					
					
						|||
| 
						
						
							
						
						74fac625f2
	
				 | 
					
					
						
@@ -101,6 +101,54 @@ func (b *BasicCard[C]) Drawn(_ *Player[C]) bool {
 | 
				
			|||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A PanelCard is a Card that takes its title and text from an InfoPanel,
 | 
				
			||||||
 | 
					// while options, urgency, and the post-option callback are specified
 | 
				
			||||||
 | 
					// (like a BasicCard). It never does anything in particular when drawn.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Omitting all options yields an inactionable card, which can be displayed
 | 
				
			||||||
 | 
					// but not played. This can be useful for adding an info panel as a debug action.
 | 
				
			||||||
 | 
					type PanelCard[C StatsCollection] struct {
 | 
				
			||||||
 | 
						Panel       InfoPanel[C]
 | 
				
			||||||
 | 
						IsUrgent    bool
 | 
				
			||||||
 | 
						CardOptions []CardOption[C]
 | 
				
			||||||
 | 
						// AfterOption is given the card itself as its first argument.
 | 
				
			||||||
 | 
						AfterOption func(c Card[C], p *Player[C], option CardOption[C]) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Title implements Card.
 | 
				
			||||||
 | 
					func (c *PanelCard[C]) Title(p *Player[C]) Message {
 | 
				
			||||||
 | 
						return c.Panel.Title(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Urgent implements Card.
 | 
				
			||||||
 | 
					func (c *PanelCard[C]) Urgent(_ *Player[C]) bool {
 | 
				
			||||||
 | 
						return c.IsUrgent
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EventText implements Card.
 | 
				
			||||||
 | 
					func (c *PanelCard[C]) EventText(p *Player[C]) (Message, error) {
 | 
				
			||||||
 | 
						msgs, err := c.Panel.Info(p)
 | 
				
			||||||
 | 
						return MultiMessage(msgs), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Options implements Card.
 | 
				
			||||||
 | 
					func (c *PanelCard[C]) Options(_ *Player[C]) ([]CardOption[C], error) {
 | 
				
			||||||
 | 
						return c.CardOptions, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Then implements Card.
 | 
				
			||||||
 | 
					func (c *PanelCard[C]) Then(p *Player[C], option CardOption[C]) error {
 | 
				
			||||||
 | 
						if c.AfterOption == nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return c.AfterOption(c, p, option)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Drawn implements Card.
 | 
				
			||||||
 | 
					func (c *PanelCard[C]) Drawn(_ *Player[C]) bool {
 | 
				
			||||||
 | 
						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.
 | 
					// It's always enabled.
 | 
				
			||||||
type BasicOption[C StatsCollection] struct {
 | 
					type BasicOption[C StatsCollection] struct {
 | 
				
			||||||
@@ -151,3 +199,17 @@ func (o *optionFunc[C]) Enact(p *Player[C]) (Message, error) {
 | 
				
			|||||||
func (o *optionFunc[C]) Enabled(p *Player[C]) bool {
 | 
					func (o *optionFunc[C]) Enabled(p *Player[C]) bool {
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// OnlyDiscardFree returns a []CardOption[C] providing a single option, which
 | 
				
			||||||
 | 
					// returns the action point. It does not shuffle the card back into the deck
 | 
				
			||||||
 | 
					// or draw a replacement (consider the AfterFunc for that if needed). This
 | 
				
			||||||
 | 
					// can be used for cards that are displayable but not actionable, but show up
 | 
				
			||||||
 | 
					// as cards rather than permanent or debug actions for some reason.
 | 
				
			||||||
 | 
					func OnlyDiscardFree[C StatsCollection](msg Message) []CardOption[C] {
 | 
				
			||||||
 | 
						return []CardOption[C]{
 | 
				
			||||||
 | 
							OptionFunc(msg, func(p *Player[C]) (Message, error) {
 | 
				
			||||||
 | 
								p.ActionsRemaining++
 | 
				
			||||||
 | 
								return MsgStr("Okay."), nil
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										142
									
								
								cardsim/deck.go
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								cardsim/deck.go
									
									
									
									
									
								
							@@ -279,3 +279,145 @@ func (d *Deck[C]) Strip(shouldRemove func(idx int, c Card[C]) bool) int {
 | 
				
			|||||||
	d.cards = Strip(d.cards, shouldRemove)
 | 
						d.cards = Strip(d.cards, shouldRemove)
 | 
				
			||||||
	return origLen - d.Len()
 | 
						return origLen - d.Len()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeckDebugger is a Card[C], intended for use only as a debug action, that
 | 
				
			||||||
 | 
					// lists the top 10 cards of the deck (without checking if they are drawable)
 | 
				
			||||||
 | 
					// and allows various sorts of deck manipulation for free. It can't be drawn.
 | 
				
			||||||
 | 
					type DeckDebugger[C StatsCollection] struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Title implements Card[C].
 | 
				
			||||||
 | 
					func (DeckDebugger[C]) Title(p *Player[C]) Message {
 | 
				
			||||||
 | 
						return MsgStr("Debug Mode Deck Controls")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Urgent implements Card[C] as used in permanent actions. It's always valid
 | 
				
			||||||
 | 
					// to use the deck debugger. Debug actions do not check urgency flags, but this
 | 
				
			||||||
 | 
					// marks itself as urgent-compatible just in case.
 | 
				
			||||||
 | 
					func (DeckDebugger[C]) Urgent(p *Player[C]) bool {
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Drawn implements Card[C]. It can't be drawn.
 | 
				
			||||||
 | 
					func (DeckDebugger[C]) Drawn(p *Player[C]) bool {
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EventText implements Card[C]. It lists the top ten cards of the deck and
 | 
				
			||||||
 | 
					// a few deck-related and hand-related stats.
 | 
				
			||||||
 | 
					func (DeckDebugger[C]) EventText(p *Player[C]) (Message, error) {
 | 
				
			||||||
 | 
						var msgs []Message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgs = append(msgs, Msgf("The Deck contains %d cards.", p.Deck.Len()))
 | 
				
			||||||
 | 
						if p.Deck.Len() > 0 {
 | 
				
			||||||
 | 
							portion := p.Deck.cards
 | 
				
			||||||
 | 
							msgs = append(msgs, nil)
 | 
				
			||||||
 | 
							topness := "All"
 | 
				
			||||||
 | 
							if p.Deck.Len() > 10 {
 | 
				
			||||||
 | 
								portion = p.Deck.cards[:10]
 | 
				
			||||||
 | 
								topness = "Top 10"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							msgs = append(msgs, Msgf("%s cards in the Deck:", topness))
 | 
				
			||||||
 | 
							for i, c := range portion {
 | 
				
			||||||
 | 
								urgency := " "
 | 
				
			||||||
 | 
								if c.Urgent(p) {
 | 
				
			||||||
 | 
									urgency = "!"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								msgs = append(msgs, Msgf(" %s %2d) %v", urgency, i+1, c.Title(p)))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgs = append(msgs, nil)
 | 
				
			||||||
 | 
						msgs = append(msgs, Msgf("At the start of each turn, the Player draws to %d cards. The player has %d cards in hand.", p.HandLimit, len(p.Hand)))
 | 
				
			||||||
 | 
						return MultiMessage(msgs), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Options implements Card[C]. It offers many possible actions.
 | 
				
			||||||
 | 
					func (DeckDebugger[C]) Options(p *Player[C]) ([]CardOption[C], error) {
 | 
				
			||||||
 | 
						ret := []CardOption[C]{
 | 
				
			||||||
 | 
							&BasicOption[C]{
 | 
				
			||||||
 | 
								Text: MsgStr("Draw a card."),
 | 
				
			||||||
 | 
								Effect: func(p *Player[C]) error {
 | 
				
			||||||
 | 
									return p.Draw()
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Output: MsgStr("Done."),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							&BasicOption[C]{
 | 
				
			||||||
 | 
								Text: MsgStr("Shuffle the deck."),
 | 
				
			||||||
 | 
								Effect: func(p *Player[C]) error {
 | 
				
			||||||
 | 
									return p.Deck.Shuffle()
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Output: MsgStr("Done."),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							&BasicOption[C]{
 | 
				
			||||||
 | 
								Text: MsgStr("Shuffle top half."),
 | 
				
			||||||
 | 
								Effect: func(p *Player[C]) error {
 | 
				
			||||||
 | 
									return p.Deck.ShuffleTop(0.5)
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Output: MsgStr("Done."),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							&BasicOption[C]{
 | 
				
			||||||
 | 
								Text: MsgStr("Shuffle bottom half."),
 | 
				
			||||||
 | 
								Effect: func(p *Player[C]) error {
 | 
				
			||||||
 | 
									return p.Deck.ShuffleBottom(0.5)
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Output: MsgStr("Done."),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, n := range []int{1, 3, 5, 10} {
 | 
				
			||||||
 | 
							if p.Deck.Len() <= n {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// We don't want the functions we're creating to all share the same "n"
 | 
				
			||||||
 | 
							// field -- we want to create distinct functions that move distinct
 | 
				
			||||||
 | 
							// numbers of cards. For more information on what's going on here, see
 | 
				
			||||||
 | 
							// https://eli.thegreenplace.net/2019/go-internals-capturing-loop-variables-in-closures/
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							// For the curious, the Go developers don't like the gotcha that
 | 
				
			||||||
 | 
							// this "shadow variable with itself" workaround patches over either.
 | 
				
			||||||
 | 
							// Here's the guy who implemented apologizing for it and discussing
 | 
				
			||||||
 | 
							// changing it: https://github.com/golang/go/discussions/56010
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							// "Loop variables being per-loop instead of per-iteration is the only
 | 
				
			||||||
 | 
							//  design decision I know of in Go that makes programs incorrect more
 | 
				
			||||||
 | 
							//  often than it makes them correct." -- Russ Cox (rsc)
 | 
				
			||||||
 | 
							n := n
 | 
				
			||||||
 | 
							invN := p.Deck.Len() - n
 | 
				
			||||||
 | 
							ret = append(ret,
 | 
				
			||||||
 | 
								&BasicOption[C]{
 | 
				
			||||||
 | 
									Text: Msgf("Move the top %d card(s) to the bottom of the deck, in order.", n),
 | 
				
			||||||
 | 
									Effect: func(p *Player[C]) error {
 | 
				
			||||||
 | 
										p.Deck.cards = append(p.Deck.cards, p.Deck.cards[:n]...)
 | 
				
			||||||
 | 
										p.Deck.cards = p.Deck.cards[n:]
 | 
				
			||||||
 | 
										return nil
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Output: MsgStr("Done."),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								&BasicOption[C]{
 | 
				
			||||||
 | 
									Text: Msgf("Move the bottom %d card(s) to the top of the deck, in order.", n),
 | 
				
			||||||
 | 
									Effect: func(p *Player[C]) error {
 | 
				
			||||||
 | 
										p.Deck.cards = append(p.Deck.cards, p.Deck.cards[:invN]...)
 | 
				
			||||||
 | 
										p.Deck.cards = p.Deck.cards[invN:]
 | 
				
			||||||
 | 
										return nil
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Output: MsgStr("Done."),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if n > 1 {
 | 
				
			||||||
 | 
								ret = append(ret, &BasicOption[C]{
 | 
				
			||||||
 | 
									Text: Msgf("Shuffle the top %d card(s) of the deck.", n),
 | 
				
			||||||
 | 
									Effect: func(p *Player[C]) error {
 | 
				
			||||||
 | 
										return p.Deck.ShufflePart(0, n)
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Output: MsgStr("Done."),
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Then implements Card[C]. It refunds the action point.
 | 
				
			||||||
 | 
					func (DeckDebugger[C]) Then(p *Player[C], o CardOption[C]) error {
 | 
				
			||||||
 | 
						p.ActionsRemaining++
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,7 +106,7 @@ type Player[C StatsCollection] struct {
 | 
				
			|||||||
	PermanentActions []Card[C]
 | 
						PermanentActions []Card[C]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// DebugActions are PermanentActions only available when the player is in
 | 
						// DebugActions are PermanentActions only available when the player is in
 | 
				
			||||||
	// debug mode.
 | 
						// debug mode. InitPlayer adds some standard debugging actions by default.
 | 
				
			||||||
	DebugActions []Card[C]
 | 
						DebugActions []Card[C]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// InfoPanels lists informational views available to the player. The Prompt
 | 
						// InfoPanels lists informational views available to the player. The Prompt
 | 
				
			||||||
@@ -175,6 +175,10 @@ func InitPlayer[C StatsCollection](stats C) *Player[C] {
 | 
				
			|||||||
		HandLimit:      1,
 | 
							HandLimit:      1,
 | 
				
			||||||
		ActionsPerTurn: 1,
 | 
							ActionsPerTurn: 1,
 | 
				
			||||||
		Rules:          NewRuleCollection[C](),
 | 
							Rules:          NewRuleCollection[C](),
 | 
				
			||||||
 | 
							DebugActions: []Card[C]{
 | 
				
			||||||
 | 
								&DeckDebugger[C]{},
 | 
				
			||||||
 | 
								&PanelCard[C]{Panel: RuleDumper[C]{}},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@ import (
 | 
				
			|||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/kr/pretty"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A Rule implements an operation run on every game turn.
 | 
					// A Rule implements an operation run on every game turn.
 | 
				
			||||||
@@ -402,3 +404,14 @@ func (r *RuleCollection[C]) applyDelayedUpdates() {
 | 
				
			|||||||
		r.RemoveID(id)
 | 
							r.RemoveID(id)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RuleDumper is an InfoPanel[C] that dumps all rules in P.
 | 
				
			||||||
 | 
					type RuleDumper[C StatsCollection] struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (RuleDumper[C]) Title(p *Player[C]) Message {
 | 
				
			||||||
 | 
						return MsgStr("Rule Dumper")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (RuleDumper[C]) Info(p *Player[C]) ([]Message, error) {
 | 
				
			||||||
 | 
						return []Message{Msgf("%# v", pretty.Formatter(p.Rules))}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,3 +145,21 @@ func Strip[T any](slice []T, removeWhen func(idx int, t T) bool) []T {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return slice[:to]
 | 
						return slice[:to]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EnsureCapacity checks if `cap(slice)` is at least req. If so, it returns
 | 
				
			||||||
 | 
					// slice unchanged. Otherwise, it copies `slice` to a new slice that is at least
 | 
				
			||||||
 | 
					// capacity `req` (but may be larger) and returns the copy.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It is reasonably efficient to use EnsureCapacity consecutively without
 | 
				
			||||||
 | 
					// regard for the final overall capacity that a specific slice will need to be.
 | 
				
			||||||
 | 
					func EnsureCapacity[T any](slice []T, req int) []T {
 | 
				
			||||||
 | 
						if cap(slice) >= req {
 | 
				
			||||||
 | 
							return slice
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if req < 2*cap(slice) {
 | 
				
			||||||
 | 
							req = 2 * cap(slice)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret := make([]T, len(slice), req)
 | 
				
			||||||
 | 
						copy(ret, slice)
 | 
				
			||||||
 | 
						return ret
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -142,25 +142,3 @@ func installPermanentActions(pa *[]card) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func installDebugActions(pa *[]card) {
 | 
					 | 
				
			||||||
	*pa = []card{
 | 
					 | 
				
			||||||
		&cardsim.BasicCard[*SmokeTestCollection]{
 | 
					 | 
				
			||||||
			CardTitle: cardsim.MsgStr("Draw a card"),
 | 
					 | 
				
			||||||
			CardText:  cardsim.MsgStr("Draw an extra card."),
 | 
					 | 
				
			||||||
			CardOptions: []cardOption{
 | 
					 | 
				
			||||||
				&cardsim.BasicOption[*SmokeTestCollection]{
 | 
					 | 
				
			||||||
					Text: cardsim.MsgStr("Draw an extra card."),
 | 
					 | 
				
			||||||
					Effect: func(p *player) error {
 | 
					 | 
				
			||||||
						return p.Draw()
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
					Output: cardsim.MsgStr("Drawn. Probably."),
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			AfterOption: func(c card, p *player, option cardOption) error {
 | 
					 | 
				
			||||||
				p.ActionsRemaining++
 | 
					 | 
				
			||||||
				return nil
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,6 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
 | 
						"git.chromaticdragon.app/kistaro/CardSimEngine/cardsim"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/kr/pretty"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
@@ -40,13 +38,11 @@ func main() {
 | 
				
			|||||||
	installRules(p.Rules)
 | 
						installRules(p.Rules)
 | 
				
			||||||
	initDeck(p.Deck)
 | 
						initDeck(p.Deck)
 | 
				
			||||||
	installPermanentActions(&p.PermanentActions)
 | 
						installPermanentActions(&p.PermanentActions)
 | 
				
			||||||
	installDebugActions(&p.DebugActions)
 | 
					 | 
				
			||||||
	p.InfoPanels = []cardsim.InfoPanel[*SmokeTestCollection]{
 | 
						p.InfoPanels = []cardsim.InfoPanel[*SmokeTestCollection]{
 | 
				
			||||||
		&cardsim.BasicStatsPanel[*SmokeTestCollection]{
 | 
							&cardsim.BasicStatsPanel[*SmokeTestCollection]{
 | 
				
			||||||
			Name:  cardsim.MsgStr("Stats"),
 | 
								Name:  cardsim.MsgStr("Stats"),
 | 
				
			||||||
			Intro: cardsim.MsgStr("Hi! These are the smoke test stats."),
 | 
								Intro: cardsim.MsgStr("Hi! These are the smoke test stats."),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		ruledumper{},
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.Prompt = prompt{}
 | 
						p.Prompt = prompt{}
 | 
				
			||||||
	p.DebugLevel = 5
 | 
						p.DebugLevel = 5
 | 
				
			||||||
@@ -73,13 +69,3 @@ func (prompt) Info(p *cardsim.Player[*SmokeTestCollection]) ([]cardsim.Message,
 | 
				
			|||||||
		cardsim.Msgf("The current Number is %d. It tastes like %s.", p.Stats.Number.Value, p.Stats.Flavor.Value),
 | 
							cardsim.Msgf("The current Number is %d. It tastes like %s.", p.Stats.Number.Value, p.Stats.Flavor.Value),
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
type ruledumper struct{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ruledumper) Title(p *player) cardsim.Message {
 | 
					 | 
				
			||||||
	return cardsim.MsgStr("Rule Dumper")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ruledumper) Info(p *player) ([]cardsim.Message, error) {
 | 
					 | 
				
			||||||
	return []cardsim.Message{cardsim.Msgf("%# v", pretty.Formatter(p.Rules))}, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user