123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819 |
- package main
- import (
- "crypto/sha1"
- "encoding/binary"
- "fmt"
- "math/rand"
- "red-green/door"
- "strconv"
- "strings"
- "time"
- "unicode"
- )
- func StringToANSIColor(colorCode string) string {
- colors := []string{
- "BLUE",
- "BROWN",
- "RED",
- "CYAN",
- "GREEN",
- "MAGENTA",
- "WHITE",
- }
- code := strings.ToUpper(colorCode)
- for _, c := range colors {
- if c == code {
- return door.ColorText(code)
- }
- }
- if code == "ALL" {
- rand.Seed(time.Now().UnixNano())
- pos := rand.Intn(len(colors))
- return door.ColorText(colors[pos])
- }
- return door.ColorText("WHITE")
- }
- type PlayCards struct {
- Door *door.Door
- DB *DBData
- Config *map[string]string
- RNG *rand.Rand
- Seeds []int32
- Total_hands int
- Play_card int
- Current_streak int
- Best_streak int
- Select_card int
- Score int
- Play_day time.Time
- Play_day_t int64
- Days_played int
- Hand int
- Day_status [42]int
- SpaceAceTriPeaks door.Panel
- ScorePanel door.Panel
- StreakPanel door.Panel
- LeftPanel door.Panel
- CmdPanel door.Panel
- NextQuitPanel door.Panel
- Calendar door.Panel
- DeckPanel Deck
- Deck []DeckType
- State []DeckType
- Off_X int
- Off_Y int
- }
- // Adjust date to 2:00 AM
- func NormalizeDate(date *time.Time) {
- offset := time.Duration(date.Second())*time.Second +
- time.Duration(date.Minute())*time.Minute +
- time.Duration(date.Hour()-2)*time.Hour +
- time.Duration(date.Nanosecond())*time.Nanosecond
- *date = date.Add(-offset)
- }
- func cmdLineRender(bracket string, inner string, outer string) func(string) string {
- cmdRender := func(input string) string {
- var result string
- inOuter := true
- var lastColor string
- for _, c := range input {
- if c == '[' {
- inOuter = false
- if lastColor != bracket {
- result += bracket
- lastColor = bracket
- }
- result += string(c)
- continue
- }
- if c == ']' {
- inOuter = true
- if lastColor != bracket {
- result += bracket
- lastColor = bracket
- }
- result += string(c)
- continue
- }
- if inOuter {
- if lastColor != outer {
- result += outer
- lastColor = outer
- }
- } else {
- if lastColor != inner {
- result += inner
- lastColor = inner
- }
- }
- result += string(c)
- }
- return result
- }
- return cmdRender
- }
- func (pc *PlayCards) InitValues() {
- hands := pc.DB.GetSetting("hands_per_day", "3")
- pc.Total_hands, _ = strconv.Atoi(hands)
- pc.Play_card = 28
- pc.Current_streak = 0
- pc.Best_streak = 0
- best := pc.DB.GetSetting("best_streak", "0")
- pc.Best_streak, _ = strconv.Atoi(best)
- pc.Select_card = 23
- pc.Score = 0
- }
- func (pc *PlayCards) Init() {
- // init_values()
- pc.InitValues()
- // PlayCards::PlayCards()
- pc.Play_day = time.Now()
- NormalizeDate(&pc.Play_day)
- pc.Play_day_t = pc.Play_day.Unix()
- pc.DeckPanel.Init()
- var last_played int64
- last := pc.DB.GetSetting("last_played", "0")
- last_played, _ = strconv.ParseInt(last, 10, 64)
- days := pc.DB.GetSetting("days_played", "0")
- pc.Days_played, _ = strconv.Atoi(days)
- if last_played != pc.Play_day_t {
- pc.DB.SetSetting("last_played", strconv.FormatInt(pc.Play_day_t, 10))
- pc.DB.SetSetting("days_played", "0")
- pc.Days_played = 0
- }
- pc.Seeds = make([]int32, 0)
- // config _seed
- parts := strings.Split((*pc.Config)["_seed"], ",")
- for _, seed := range parts {
- i, _ := strconv.ParseInt(seed, 10, 32)
- pc.Seeds = append(pc.Seeds, int32(i))
- }
- pc.Hand = 0
- pc.Total_hands = 0
- // spaceAceTriPeaks = make_tripeaks();
- {
- tripeakstext := " " + SPACEACE + " - Tri-Peaks Solitaire v" + SPACEACE_VERSION + " "
- pc.SpaceAceTriPeaks = door.Panel{Width: len(tripeakstext),
- Style: door.SINGLE,
- BorderColor: door.ColorText("CYAN ON BLACK"),
- }
- pc.SpaceAceTriPeaks.Lines = append(pc.SpaceAceTriPeaks.Lines,
- door.Line{Text: tripeakstext})
- }
- svRender := RenderStatusValue(door.ColorText("BOLD WHITE ON BLUE"),
- door.ColorText("BOLD YELLOW ON BLUE"))
- // score_panel = make_score_panel();
- {
- W := 25
- pc.ScorePanel = door.Panel{Width: W}
- text := "Name: " + pc.Door.Config.Real_name
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: fmt.Sprintf("%*s", -W, text), RenderF: svRender})
- scoreUpdate := func() string {
- txt := fmt.Sprintf("Score: %d", pc.Score)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: scoreUpdate(),
- UpdateF: scoreUpdate,
- RenderF: svRender,
- })
- timeUpdate := func() string {
- var left int = int(pc.Door.TimeLeft().Minutes())
- var used int = int(pc.Door.TimeUsed().Minutes())
- txt := fmt.Sprintf("Time used: %3d / %3d", used, left)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: timeUpdate(),
- UpdateF: timeUpdate,
- RenderF: svRender,
- })
- handUpdate := func() string {
- txt := fmt.Sprintf("Playing Hand %d of %d", pc.Hand, pc.Total_hands)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.ScorePanel.Lines = append(pc.ScorePanel.Lines,
- door.Line{Text: handUpdate(),
- UpdateF: handUpdate,
- RenderF: svRender,
- })
- }
- // streak_panel = make_streak_panel();
- {
- W := 20
- pc.StreakPanel = door.Panel{Width: W}
- dateUpdate := func() string {
- format, ok := (*pc.Config)["date_format"]
- if !ok {
- format = "January 2"
- }
- txt := fmt.Sprintf("Playing: %s", pc.Play_day.Format(format))
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.StreakPanel.Lines = append(pc.StreakPanel.Lines,
- door.Line{Text: dateUpdate(),
- UpdateF: dateUpdate,
- RenderF: svRender,
- })
- currentUpdate := func() string {
- txt := fmt.Sprintf("Current Streak: %d", pc.Current_streak)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.StreakPanel.Lines = append(pc.StreakPanel.Lines,
- door.Line{Text: currentUpdate(),
- UpdateF: currentUpdate,
- RenderF: svRender,
- })
- longestUpdate := func() string {
- txt := fmt.Sprintf("Longest Streak: %d", pc.Best_streak)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.StreakPanel.Lines = append(pc.StreakPanel.Lines,
- door.Line{Text: longestUpdate(),
- UpdateF: longestUpdate,
- RenderF: svRender,
- })
- }
- // left_panel = make_left_panel();
- {
- W := 13
- pc.LeftPanel = door.Panel{Width: W}
- leftUpdate := func() string {
- txt := fmt.Sprintf("Cards left:%d", 51-pc.Play_card)
- txt += strings.Repeat(" ", W-len(txt))
- return txt
- }
- pc.LeftPanel.Lines = append(pc.LeftPanel.Lines,
- door.Line{Text: leftUpdate(),
- UpdateF: leftUpdate,
- RenderF: svRender,
- })
- }
- // cmd_panel = make_command_panel();
- {
- W := 76
- pc.CmdPanel = door.Panel{Width: W}
- var commands string
- if door.Unicode {
- commands = "[4/\u25c4] Left [6/\u25ba] Right [Space] Play Card [Enter] Draw [Q]uit [R]edraw [H]elp"
- commands += strings.Repeat(" ", W-len([]rune(commands)))
- } else {
- commands = "[4/\x11] Left [6/\x10] Right [Space] Play Card [Enter] Draw [Q]uit [R]edraw [H]elp"
- commands += strings.Repeat(" ", W-len(commands))
- }
- cmdRender := cmdLineRender(door.ColorText("BOLD YELLOW ON BLUE"),
- door.ColorText("BOLD CYAN ON BLUE"),
- door.ColorText("BOLD GREEN ON BLUE"))
- pc.CmdPanel.Lines = append(pc.CmdPanel.Lines,
- door.Line{Text: commands,
- RenderF: cmdRender})
- }
- // next_quit_panel = make_next_panel();
- {
- W := 50
- pc.NextQuitPanel = door.Panel{Width: W,
- Style: door.DOUBLE,
- BorderColor: door.ColorText("BOLD YELLOW ON BLUE"),
- }
- nextUpdate := func() string {
- var text string
- if pc.Select_card != -1 {
- text = "[C]ontinue this hand"
- }
- if pc.Hand < pc.Total_hands {
- text += " [N]ext Hand [Q]uit"
- } else {
- text += " [D]one [Q]uit"
- }
- text = " " + text + " "
- text += strings.Repeat(" ", W-len(text))
- return text
- }
- pc.NextQuitPanel.Lines = append(pc.NextQuitPanel.Lines,
- door.Line{Text: nextUpdate(),
- UpdateF: nextUpdate,
- RenderF: cmdLineRender(door.ColorText("BOLD YEL ON BLU"),
- door.ColorText("BOLD CYAN ON BLU"),
- door.ColorText("BOLD GREE ON BLUE"))})
- }
- // calendar = make_calendar();
- {
- W := 41
- pc.Calendar = door.Panel{Width: W,
- Style: door.DOUBLE,
- BorderColor: door.ColorText("CYAN ON BLACK")}
- calendarRender := func(text string) string {
- // var result string
- // var lastColor string
- result := door.Render{Line: text}
- digits := door.ColorText("CYAN ON BLACK")
- digits_play := door.ColorText("BOLD CYAN ON BLACK")
- spaces := door.ColorText("WHITE ON BLACK")
- open := door.ColorText("BOLD GREEN ON BLACK")
- hands := door.ColorText("BOLD YELLOW ON BLACK")
- full := door.ColorText("RED ON BLACK")
- nny := door.ColorText("BOLD BLACK ON BLACK")
- for days := 0; days < 7; days++ {
- var dayText string
- if days == 0 {
- result.Append(spaces, 1)
- }
- dayText = text[1+days*6 : (1+days*6)+3]
- if dayText[1] == ' ' {
- result.Append(spaces, 3)
- } else {
- // Something is here
- cday := dayText[2]
- if cday == 'o' || cday == 'h' {
- result.Append(digits_play, 2)
- } else {
- result.Append(digits, 2)
- }
- switch cday {
- case 'o':
- result.Append(open, 1)
- case 'h':
- result.Append(hands, 1)
- case 'x':
- result.Append(full, 1)
- case 'u':
- result.Append(nny, 1)
- }
- }
- if days == 6 {
- result.Append(spaces, 1)
- } else {
- result.Append(spaces, 3)
- }
- }
- return result.Result
- }
- for row := 0; row < 6; row++ {
- calendarUpdate := func() string {
- var text string
- for d := 0; d < 7; d++ {
- text += " "
- v := pc.Day_status[(row*7)+d]
- if v == 0 {
- text += " "
- } else {
- text += fmt.Sprintf("%-2d", v)
- status := pc.Day_status[v-1]
- switch status {
- case 0:
- text += "o"
- case 1:
- text += "h"
- case 2:
- text += "x"
- case 3:
- text += "u"
- }
- }
- if d == 6 {
- text += " "
- } else {
- text += " "
- }
- }
- return text
- }
- pc.Calendar.Lines = append(pc.Calendar.Lines,
- door.Line{Text: calendarUpdate(),
- UpdateF: calendarUpdate,
- RenderF: calendarRender})
- }
- }
- }
- func (pc *PlayCards) Play() {
- // this defaults (for now) to playing today (if unplayed).
- // Otherwise display calendar.
- pc.Play_day = time.Now()
- NormalizeDate(&pc.Play_day)
- pc.Play_day_t = pc.Play_day.Unix()
- // played := db.HandsPlayedOnDay(pc.Play_day_t)
- played := 0
- var r int
- if played == 0 {
- pc.Door.Write("Let's play today..." + door.CRNL)
- time.Sleep(time.Second)
- pc.Hand = 1
- r = pc.PlayCards()
- if r != 'D' {
- return
- }
- } else {
- if played < pc.Total_hands {
- // let's finish today...
- pc.Hand = played + 1
- r = pc.PlayCards()
- if r != 'D' {
- return
- }
- }
- }
- /*
- CALENDAR_UPDATE:
- pc.UpdateCalendarDays()
- pc.Calendar.Update()
- pc.Door.Write(pc.Calendar.Output())
- */
- }
- func int32toByteArray(i int32) (arr [4]byte) {
- binary.BigEndian.PutUint32(arr[0:4], uint32(i))
- return
- }
- func int64toByteArray(i int64) (arr [8]byte) {
- binary.BigEndian.PutUint64(arr[0:8], uint64(i))
- return
- }
- func (pc *PlayCards) PlayCards() int {
- pc.InitValues()
- var game_width int
- var game_height int = 20
- pos := CardPos[27]
- game_width = pos.X + 5
- MX := door.Width
- MY := door.Height
- pc.Off_X = (MX - game_width) / 2
- pc.Off_Y = (MY - game_height) / 2
- // _ = off_x
- // We can now position things properly centered
- pc.SpaceAceTriPeaks.X = (MX - pc.SpaceAceTriPeaks.Width) / 2
- pc.SpaceAceTriPeaks.Y = pc.Off_Y
- pc.Off_Y += 3
- currentDefault := pc.DB.GetSetting("DeckColor", "ALL")
- Next_Hand:
- deck_color := StringToANSIColor(currentDefault)
- pc.DeckPanel.SetBackColor(deck_color)
- pc.Play_card = 28
- pc.Select_card = 23
- pc.Score = 0
- pc.Current_streak = 0
- // Use play day to seed RNG
- {
- // Secret Squirrel method of seeding the RNG
- sha1 := sha1.New()
- seed_seq := make([]byte, 0)
- for _, seed := range pc.Seeds {
- ba := int32toByteArray(seed)
- seed_seq = append(seed_seq, ba[:]...)
- // sha1.Sum(ba[:])
- }
- pd := int64toByteArray(pc.Play_day_t)
- seed_seq = append(seed_seq, pd[:]...)
- // We also need the hand # that we're playing.
- seed_seq = append(seed_seq, byte(pc.Hand))
- result := sha1.Sum(seed_seq)
- var seed int64 = int64(binary.BigEndian.Uint64(result[0:8]))
- pc.RNG.Seed(seed)
- pc.Deck = ShuffleCards(pc.RNG, 1)
- pc.State = MakeCardStates(1)
- }
- // Position the panels
- {
- off_yp := pc.Off_Y + 11
- left_panel_x := CardPos[18].X
- right_panel_x := CardPos[15].X
- pc.ScorePanel.X = left_panel_x + pc.Off_X
- pc.ScorePanel.Y = off_yp
- pc.StreakPanel.X = right_panel_x + pc.Off_X
- pc.StreakPanel.Y = off_yp
- pc.CmdPanel.X = left_panel_x + pc.Off_X
- pc.CmdPanel.Y = off_yp + 5
- next_off_x := (MX - pc.NextQuitPanel.Width) / 2
- pc.NextQuitPanel.X = next_off_x
- pc.NextQuitPanel.Y = CardPos[10].Y + pc.Off_Y
- }
- var Dealing bool = true
- var r int = 0
- pc.Redraw(Dealing)
- Dealing = false
- pc.LeftPanel.Update()
- pc.Door.Write(door.Reset)
- var c *door.Panel
- var in_game bool = true
- var save_streak bool = false
- var waiting int = 0
- for in_game {
- var output string
- output = pc.ScorePanel.Update()
- if output != "" {
- pc.Door.Write(output)
- {
- // Redisplay Mark / Selected Card
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X
- c.Y = Pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- }
- if save_streak {
- save_streak = false
- pc.DB.SetSetting("best_streak", strconv.Itoa(pc.Best_streak))
- }
- waiting = 0
- for waiting < int(door.Inactivity) {
- r = pc.Door.WaitKey(1, 0)
- if r == -1 {
- // TIMEOUT is expected here
- waiting++
- output = pc.ScorePanel.Update()
- if output != "" {
- pc.Door.Write(output)
- {
- // Redisplay Mark / Selected Card
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X
- c.Y = Pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- }
- } else {
- break
- }
- }
- if r > 0 {
- // Not a timeout
- if r < 0x1000 {
- // not a function key
- switch unicode.ToUpper(rune(r)) {
- case '\x0d':
- // Next Card
- if pc.Current_streak > pc.Best_streak {
- pc.Best_streak = pc.Current_streak
- save_streak = true
- pc.Door.Write(pc.StreakPanel.Update())
- }
- if pc.Play_card < 51 {
- pc.Play_card++
- pc.Current_streak = 0
- pc.Door.Write(pc.StreakPanel.Update())
- pc.Door.Write(pc.LeftPanel.Update())
- // Deal the next card
- if pc.Play_card == 51 {
- // out of cards
- cpos := &CardPos[29]
- c = &pc.DeckPanel.Backs[0]
- c.X = cpos.X + pc.Off_X
- c.Y = cpos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- cpos := &CardPos[28]
- c = &pc.DeckPanel.Cards[pc.Deck[pc.Play_card]]
- c.X = cpos.X + pc.Off_X
- c.Y = cpos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- case 'R':
- pc.Redraw(false)
- case 'Q':
- // Possibly prompt here for [N]ext hand or [Q]uit
- if pc.Current_streak > pc.Best_streak {
- pc.Best_streak = pc.Current_streak
- pc.Door.Write(pc.StreakPanel.Update())
- }
- pc.NextQuitPanel.Update()
- pc.Door.Write(pc.NextQuitPanel.Output())
- if pc.State[26] == 2 {
- pc.Door.Write(door.ColorText("BLACK"))
- } else {
- pc.Door.Write(door.Reset)
- }
- if pc.Hand < pc.Total_hands {
- r = pc.Door.GetOneOf("CNQ")
- } else {
- r = pc.Door.GetOneOf("CDQ")
- }
- if r == 'C' {
- // Continue
- pc.Redraw(false)
- } else {
- if r == 'D' || r == 'Q' {
- if pc.Score >= 50 {
- // pc.DB.SaveScore(now, pc.Time_T, .. pc.Score)
- _ = pc.Score
- }
- in_game = false
- } else {
- if r == 'N' {
- // pc.DB.SaveScore(...)
- _ = pc.Score
- pc.Hand++
- goto Next_Hand
- }
- }
- }
- }
- }
- }
- }
- return 0
- }
- func (pc *PlayCards) Redraw(Dealing bool) {
- // stars.display()
- pc.Door.Write(door.Clrscr + door.Reset)
- pc.Door.Write(pc.SpaceAceTriPeaks.Output())
- var c *door.Panel
- {
- // Step 1: Draw the deck "source"
- pos := CardPos[29]
- if pc.Play_card == 51 {
- // out of cards
- pos.Level = 0
- }
- c = &pc.DeckPanel.Backs[pos.Level]
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.LeftPanel.X = pos.X + pc.Off_X
- pc.LeftPanel.Y = pos.Y + pc.Off_Y + 3 // const height see deck
- pc.ScorePanel.Update()
- pc.LeftPanel.Update()
- pc.StreakPanel.Update()
- pc.CmdPanel.Update()
- pc.Door.Write(pc.ScorePanel.Output())
- pc.Door.Write(pc.LeftPanel.Output())
- pc.Door.Write(pc.StreakPanel.Output())
- pc.Door.Write(pc.CmdPanel.Output())
- pc.Door.Write(c.Output())
- if Dealing {
- time.Sleep(time.Second)
- }
- }
- var x_max int = 29
- if Dealing {
- x_max = 28
- }
- for x := 0; x < x_max; x++ {
- pos := CardPos[x]
- if Dealing {
- time.Sleep(time.Duration(75) * time.Millisecond)
- }
- if Dealing {
- c = &pc.DeckPanel.Backs[pos.Level]
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- } else {
- switch pc.State[x] {
- case 0:
- c = &pc.DeckPanel.Backs[pos.Level]
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- case 1:
- if x == 28 {
- c = &pc.DeckPanel.Cards[pc.Deck[pc.Play_card]]
- } else {
- c = &pc.DeckPanel.Cards[pc.Deck[x]]
- }
- c.X = pos.X + pc.Off_X
- c.Y = pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- case 2:
- // no card to draw.
- case 3:
- // peak cleared, draw bonus
- var output string = door.Goto(pos.X+pc.Off_X, pos.Y+pc.Off_Y)
- output += Bonus()
- pc.Door.Write(output)
- }
- }
- }
- if Dealing {
- for x := 18; x < 29; x++ {
- pc.State[x] = 1
- // CardPos[x] X Y Level
- Pos := &CardPos[x]
- time.Sleep(time.Duration(200) * time.Millisecond)
- c = &pc.DeckPanel.Cards[pc.Deck[x]]
- c.X = Pos.X + pc.Off_X
- c.Y = Pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- }
- {
- Pos := &CardPos[pc.Select_card]
- c = &pc.DeckPanel.Mark[1]
- c.X = Pos.X + pc.Off_X
- c.Y = Pos.Y + pc.Off_Y
- pc.Door.Write(c.Output())
- }
- }
- func Bonus() string {
- return door.ColorText("BOLD YELLOW") + "BONUS"
- }
|