Prompt for player choices on cards.

Also handles errors in the display/prompt logic somewhat better.
This commit is contained in:
Kistaro Windrider 2023-04-02 12:44:29 -07:00
parent 592c877852
commit 25a9eed3f0
Signed by: kistaro
SSH Key Fingerprint: SHA256:TBE2ynfmJqsAf0CP6gsflA0q5X5wD5fVKWPsZ7eVUg8

View File

@ -16,7 +16,14 @@ func RunSimpleTerminalUI[C StatsCollection](p *Player[C]) error {
p.ReportError(err)
for p.CanAct() {
isCard, cardIdx, choiceIdx := pickNextAction(p)
isCard, cardIdx, choiceIdx, err := pickNextAction(p)
p.ReportError(err)
if IsSeriousError(err) {
if p.DebugLevel < 1 {
return err
}
continue
}
var msg Message
if isCard {
msg, err = p.EnactCard(cardIdx, choiceIdx)
@ -24,8 +31,11 @@ func RunSimpleTerminalUI[C StatsCollection](p *Player[C]) error {
msg, err = p.EnactPermanentAction(cardIdx, choiceIdx)
}
p.ReportError(err)
if p.DebugLevel < 1 && IsSeriousError(err) {
return err
if IsSeriousError(err) {
if p.DebugLevel < 1 {
return err
}
continue
}
display(msg)
wait()
@ -57,7 +67,7 @@ func wait() {
fmt.Scanln()
}
func pickNextAction[C StatsCollection](p *Player[C]) (isCard bool, cardIdx int, choiceIdx int) {
func pickNextAction[C StatsCollection](p *Player[C]) (isCard bool, cardIdx int, choiceIdx int, err error) {
for {
cls()
needsDivider := displayMessageSection(p)
@ -77,22 +87,19 @@ func pickNextAction[C StatsCollection](p *Player[C]) (isCard bool, cardIdx int,
max := displayHandMenu(p, handOffset)
divider()
var input string
fmt.Printf("Show just (M)essages, (S)tats, (A)ctions, make a choice (1-%d), or (Q)uit? >", max+1)
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.ToLower(input)
input := getResponse()
switch input {
// Special cases
case "m":
case "m", "msg", "message", "messages":
cls()
displayMessageSection(p)
wait()
case "s":
case "s", "stat", "stats":
statsMode(p)
case "a":
case "a", "act", "actions":
actionsMode(p)
case "q":
case "q", "quit", "exit":
confirmQuit()
default:
i, err := strconv.Atoi(input)
@ -114,16 +121,16 @@ func pickNextAction[C StatsCollection](p *Player[C]) (isCard bool, cardIdx int,
} else if i < handOffset {
cls()
i -= actionsOffset
option, ok := promptPermanentAction(p, i)
if ok {
return false, i, option
option, promptErr := promptCard(p, p.PermanentActions[i])
if option >= 0 || IsSeriousError(promptErr) {
return false, i, option, promptErr
}
} else {
cls()
i -= handOffset
option, ok := promptCard(p, i)
if ok {
return true, i, option
option, promptErr := promptCard(p, p.Hand[i])
if option >= 0 || IsSeriousError(promptErr) {
return true, i, option, nil
}
}
}
@ -134,6 +141,14 @@ func cls() {
fmt.Println("\033[H\033[2J")
}
func getResponse() string {
var input string
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.ToLower(input)
return input
}
func divider() {
fmt.Println()
fmt.Println(SectionBreak.String())
@ -143,11 +158,8 @@ func divider() {
func confirmQuit() {
divider()
fmt.Println("Are you sure you want to quit? (Y/N) ")
var s string
fmt.Scanln(&s)
s = strings.TrimSpace(s)
s = strings.ToLower(s)
if strings.HasPrefix(s, "y") {
s := getResponse()
if s == "y" || s == "yes" {
fmt.Println("Bye!")
os.Exit(0)
}
@ -211,3 +223,94 @@ func displayHandMenu[C StatsCollection](p *Player[C], offset int) int {
}
return offset + len(p.Hand)
}
// promptCard asks the player to take an action on a card. Returns the option
// they chose, or -1 if there was a serious error or they cancelled selection.
func promptCard[C StatsCollection](p *Player[C], card Card[C]) (optionIdx int, err error) {
// Iterate until the player makes a valid choice.
for {
opts, valid, err := displayCard(p, card)
if IsSeriousError(err) {
return -1, err
}
fmt.Println()
if valid {
fmt.Printf("Go (B)ack, (Q)uit, or enact a choice (1 - %d)? >", len(opts)+1)
} else {
fmt.Print("Go (B)ack or (Q)uit? >")
}
read := getResponse()
switch read {
case "b", "back":
return -1, err
case "q", "quit":
confirmQuit()
default:
i, convErr := strconv.Atoi(read)
if convErr != nil {
fmt.Println("Sorry, I don't understand.")
wait()
} else if !valid {
fmt.Println("You can't enact anything here.")
wait()
} else if i <= 0 || i > len(opts) {
fmt.Println("That's not one of the options.")
wait()
} else if !opts[i-1].Enabled(p) {
fmt.Println("That option is not available to you right now.")
wait()
} else {
return i - 1, err
}
}
// Invalid selection made -- loop to prompt again.
}
}
func displayCard[C StatsCollection](p *Player[C], card Card[C]) ([]CardOption[C], bool, error) {
cls()
t := card.Title(p).String()
urgent := card.Urgent(p)
if urgent {
t = "[URGENT!] " + t
}
fmt.Println(t)
fmt.Println(strings.Repeat("-", len(t)))
fmt.Println()
event, err := card.EventText(p)
if IsSeriousError(err) {
return nil, false, err
}
var errs ErrorCollector
errs.Add(err)
fmt.Println(event.String())
fmt.Println()
fmt.Println(SectionBreak.String())
fmt.Println()
lockout := false
if !urgent && p.HasUrgentCards() {
fmt.Println("<You have more urgent matters to attend to! You cannot act on this right now.>")
fmt.Println()
lockout = true
}
opts, optErr := card.Options(p)
errs.Add(optErr)
if IsSeriousError(optErr) {
return nil, false, errs.Emit()
}
valid := false
for i, opt := range opts {
pfx := "[xx]:"
if !lockout && opt.Enabled(p) {
pfx = fmt.Sprintf("[%2d]:", i+1)
valid = true
}
t, err := opt.OptionText(p)
errs.Add(err)
if IsSeriousError(err) {
return nil, false, errs.Emit()
}
fmt.Println(pfx, t.String())
}
return opts, valid, errs.Emit()
}