Card-based skill checks

One cool thing about Inform 7 is you can actually implement physical cards - whether the player interacts with them or not. You can have an off-stage container called “the deck” and and off-stage container called “your hand”.

You can write things like “now a random card in the deck is in your hand” and “if the five of clubs is in your hand”…etc.

1 Like

Is there a way to display the cards contained in the hand in the parser?

I have an object-based card-dealing script half-written, but I can’t seem to affect the cards unless I’m in the same room as them. The following code did not help:

Encounter is a scene. Encounter begins when play begins.
	
After deciding the scope of the player during Encounter:
	place backstage in scope;
	place the contents of the hand in scope.

I’m also getting a weird bug where entering the name of any card makes it impossible to send commands to Inform, the parser just treats the enter-key as meaning line break. I know from commenting out bits of code that this code is the problem, but I have no idea why:

After reading a command:
	if the player's command includes "of [suit]":
		while the player's command includes "of":
			cut the matched text;
	repeat through the Table of Card Names:
		while the player's command includes topic entry:
			replace the matched text with "[value entry]".

EDIT: The second bug was due to how the topic was set up. I was able to fix it. The first one is still a problem.

The Game Room is a room.

Your hand is a container.

The deck is a container.

A card is a kind of thing. An ace is a card in the deck. A king is a card in the deck. A queen is a card in the deck. A joker is a card in the deck. 

A four of clubs is a card in your hand. A three of diamonds is a card in your hand.

Report taking inventory:
	say "In your hand of cards is [a list of cards in your hand]."

Every turn:
	now a random card in the deck is in your hand;
	now a random card in your hand is in the deck;
Result:

i

You are carrying nothing.

In your hand of cards is a four of clubs and a three of diamonds.

i

You are carrying nothing.

In your hand of cards is a queen and a three of diamonds.

i

You are carrying nothing.

In your hand of cards is a joker and a queen

This might be useful; it’s an implementation of Autumn Leaves (a solitaire card game) in Inform 7, which uses physical objects to represent cards and only lets players refer to them when they’re face-up.

3 Likes

I have a mostly object based version that’s mostly working, but I still can’t find a way to get the contents of the hand into the parser without relying on the table. The problem there is, I don’t know how to update the table when a card is played in order to update the parser. I’d like to avoid just using the inventory to keep track of the hand if possible. Having the hand constantly in front of the player helps streamline the system and makes it more intuitive.

EDIT: Here is what I have right now, for reference. Warning: Big.

Big
Section 1 - Card Stats and Conditions

A person has a number called will. The will of the player is 7.

A person has a number called focus. The focus of the player is 7.

A person has a number called work. The work of the player is 0.

A person has a number called difficulty. The difficulty of the player is 0.

A person has a number called success. The success of the player is 0.

A person can be either safe or imperiled. The player is safe.

A person can be either engaged or unengaged. The player is unengaged.

A person can be either cornered or uncornered. The player is uncornered.

[The WILL is the maximum hand draw the player is restored to when they are refreshed by a consumable or by visiting a refreshing location.

The FOCUS is the maximum hand draw the player has right now. When an encounter begins, they draw this many cards, and when they redraw, their focus drops by one.

The WORK is the total point value from all played cards in the current engagement.

The DIFFICULTY is the current amount of points the player must exceed to complete the current engagement.

While SAFE, the player has no cards. While IMPERILED, the player has cards. The player gets cards equal to their focus whenever they become imperiled, so most perilous encounters should consist of multiple different engagements or else one really big engagement.

While ENGAGED, the player cannot move, and instead can only play cards, redraw, or retreat. When UNENGAGED, the player can move normally. The player should never be engaged without being imperiled.

When CORNERED, the player cannot retreat. When uncornered, they can retreat normally. The player should never be cornered without being engaged.]

Suit is a kind of value. The suits are widows, spiders, tears, bats, and suitless. Understand "widow" as widows. Understand "spider" as spiders. Understand "bat" as bats. Understand "tear" as tears.

A card is a kind of thing. A card can be written or unwritten. A card is usually unwritten. A card has a suit. A card has a number called rank. Understand the suit property as describing a card. Understand the rank property as describing a card.

To say (count - a number) as a card name:
	choose row count minus one in the Table of Card Names;
	say "[card name entry]".

Rule for printing the name of a card (called target):
	say "[rank of the target as a card name] of [suit of the target]"

Table of Card Names
Topic	Card Name	Abbrev	Value	Written Value	Suit
"Two/Deuce"	"Two"	"2"	2	"2"	Widows
"Three"	"Three"	"3"	3	"3"	Widows
"Four"	"Four"	"4"	4	"4"	Widows
"Five"	"Five"	"5"	5	"5"	Widows
"Six"	"Six"	"6"	6	"6"	Widows
"Seven"	"Seven"	"7"	7	"7"	Widows
"Eight"	"Eight"	"8"	8	"8"	Widows
"Nine"	"Nine"	"9"	9	"9"	Widows
"Ten"	"Ten"	"10"	10	"10"	Widows
"Jack/J"	"Jack"	"J"	11	"11"	Widows
"Queen/Q"	"Queen"	"Q"	12	"12"	Widows
"King/K"	"King"	"K"	13	"13"	Widows
"Ace/A"	"Ace"	"A"	14	"14"	Widows

Table of the Player's Hand
Topic	Card Name	Abbrev	Value	Suit
"-"	some text	some text	a number	a suit
with 13 blank rows

Table of an Empty Hand
Topic	Card Name	Abbrev	Value	Suit
"-"	some text	some text	a number	a suit

Section 2 - Drawing Cards

Redrawing is an action applying to nothing. Understand "redraw" as redrawing.

Carry out redrawing:
	now every card is in the discard;
	now every card is unwritten;
	sort the Table of Card Names in random order;
	repeat with N running from 1 to the focus of the player:
		now the card name in row N of the Table of the Player's Hand is the card name in row N of the Table of Card Names;
		now the abbrev in row N of the Table of the Player's Hand is the abbrev in row N of the Table of Card Names;
		now the value in row N of the Table of the Player's Hand is the value in row N of the Table of Card Names;
		now the suit in row N of the Table of the Player's Hand is the suit in row N of the Table of Card Names;
	decrease the focus of the player by 1;
	repeat with N running from the focus of the player plus one to the number of rows in the Table of the Player's Hand:
		now the card name in row N of the Table of the Player's Hand is "None";
		now the abbrev in row N of the Table of the Player's Hand is "-";
		now the value in row N of the Table of the Player's Hand is 0;
		now the suit in row N of the Table of the Player's Hand is suitless;
	sort the Table of Card Names in value order;
	repeat with N running from 1 to the focus of the player:
		let C be a random card that is unwritten;
		now the suit of C is the suit in row N of the Table of the Player's Hand;
		now the rank of C is the value in row N of the Table of the Player's Hand;
		now the player has C;
		now C is written.

Section 3 - Playing Cards

Encounter is a recurring scene. Encounter begins when the player is engaged. Encounter ends when the player is safe.

When Encounter begins:
	now every card is in the discard;
	now every card is unwritten;
	sort the Table of Card Names in random order;
	repeat with N running from 1 to the focus of the player:
		now the topic in row N of the Table of the Player's Hand is the topic in row N of the Table of Card Names;
		now the card name in row N of the Table of the Player's Hand is the card name in row N of the Table of Card Names;
		now the abbrev  in row N of the Table of the Player's Hand is the abbrev in row N of the Table of Card Names;
		now the value in row N of the Table of the Player's Hand is the value in row N of the Table of Card Names;
		now the suit in row N of the Table of the Player's Hand is the suit in row N of the Table of Card Names;
	repeat with N running from the focus of the player plus one to the number of rows in the Table of the Player's Hand:
		now the topic in row N of the Table of the Player's Hand is the topic in row 1 of the Table of an Empty Hand;
		now the card name in row N of the Table of the Player's Hand is "None";
		now the abbrev in row N of the Table of the Player's Hand is "-";
		now the value in row N of the Table of the Player's Hand is 0;
		now the suit in row N of the Table of the Player's Hand is suitless;
	sort the Table of Card Names in value order;
	repeat with N running from 1 to the focus of the player:
		let C be a random card that is unwritten;
		now the suit of C is the suit in row N of the Table of the Player's Hand;
		now the rank of C is the value in row N of the Table of the Player's Hand;
		now the player has C;
		now C is written.

Every turn during Encounter:
	now the command prompt is "Play a card: [abbrev in row 1 of the Table of the Player's Hand] [abbrev in row 2 of the Table of the Player's Hand] [abbrev in row 3 of the Table of the Player's Hand] [abbrev in row 4 of the Table of the Player's Hand] [abbrev in row 5 of the table of the Player's Hand] [abbrev in row 6 of the Table of the Player's Hand] [abbrev in row 7 of the Table of the Player's Hand]>";
	if the work of the player is greater than the difficulty of the player:
		say "Success! The difficulty of this challenge was [difficulty of the player], and you put down [work of the player] points from your cards.";
		now the player is unengaged;
		increase the success of the player by 1;
		now the difficulty of the player is 0;
		now the work of the player is 0.

After reading a command while the player is imperiled:
	if the player's command includes "of [suit]":
		while the player's command includes "of":
			cut the matched text;
	repeat through the Table of Card Names:
		while the player's command includes topic entry:
			replace the matched text with written value entry.

After reading a command while the player is engaged:
	if the player's command does not match "play [card]":
		if the player's command does not match "redraw":
			If the player's command does not match "retreat":
				say "Redraw, retreat, or play a card.";
				reject the player's command.

Instead of dropping a card, say "Best to hang onto that until you need it."

When Encounter ends:
	now the command prompt is ">";
	say "You have succeeded!";
	now every card is in the discard;
	now every card is unwritten;
	now the player is uncornered;
	now the player is unengaged.

Playing a card is an action applying to one thing. Understand "play [card]" as playing a card.

Before playing a card:
	if the player does not have the noun:
		say "You don't have that card in your hand.";
		reject the player's command;
	if the player is not engaged:
		say "There's no immediate obstacle to play the card against. Hold onto your cards until you find one.";
		reject the player's command.

Carry out playing a card:
	now the noun is in the discard;
	increase the work of the player by the rank of the noun;
	if there is a topic corresponding to a value of the rank of the noun in the Table of the Player's Hand:
		now the topic corresponding to the value of the rank of the noun in the Table of the Player's Hand is the topic in row 1 of the Table of an Empty Hand;
		now the card name corresponding to the value of the rank of the noun in the Table of the Player's Hand is "None";
		now the abbrev corresponding to the value of the rank of the noun in the Table of the Player's Hand is "-";
		now the suit corresponding to the value of the rank of the noun in the Table of the Player's Hand is suitless;
		now the value corresponding to the value of the rank of the noun in the Table of the Player's Hand is 0.

Report playing a card:
	say "You play [the noun]."

Retreating is an action applying to nothing. Understand "retreat" as retreating.

Check retreating:
	if the player is cornered:
		say "You can't back out of this one." instead.

Check retreating:
	if the player is unengaged:
		say "There's nothing to retreat from." instead.

Carry out retreating:
	say "You abandon your efforts.";
	now the work of the player is 0;
	now the player is unengaged.

Section 4 - Miscellanea

The test chamber is a room. "Current work is [the work of the player]."

Backstage is east of the test chamber. The discard is a container in Backstage. The deck is a container in Backstage. The hand is a container in Backstage. It is openable and open. There are 13 cards in the discard.

A spider is an animal. It is in Backstage.

Instead of attacking a spider:
	say "The spider becomes angry!";
	now the difficulty of the player is 8;
	now the player is imperiled;
	now the player is engaged.
	
After reading a command when the success of the player is 3:
	now the spider is nowhere;
	now the tricky spider is in Backstage.

A tricky spider is an animal. It is nowhere.

Instead of attacking a tricky spider:
	say "The tricky spider holds you in place with webs!";
	now the difficulty of the player is 12;
	now the player is imperiled;
	now the player is engaged;
	now the player is cornered.
	
After reading a command when the success of the player is 4:
	if the tricky spider is in Backstage:
		say "You have slain the tricky spider!";
		now the tricky spider is nowhere;
		now the player is safe;
		now the player is unengaged;
		now the player is uncornered;
		reject the player's command.

This runs, you can go east, kick the spider until the tricky spider shows up, then kick the tricky spider at which point you win. There’s no victory screen or anything, you just wander around purgatory forever, you spider-kicking monster, but as a proof of concept, it all works except that when playing a card it only checks for a matching rank, not suit. I can’t figure out how to get it to check the table for something that matches both rank and suit, and I can’t figure out how to get the hand into the parser without using a table. I could give each card in the table a unique ID and then have it copy that unique ID onto the card objects along with the rank and the suit, I guess, but it’d be a lot less effort to just search the table for entries corresponding to both a value and a suit, since every card does have a unique rank/suit combination and each rank has a unique value.

More power to you if you like using tables - and most people do, I’m weirdly table-averse if I can help it. That’s why I am partial to the idea of simulating the cards physically, even if out-of-world because you can manipulate them like real cards rather than doing table-row reads, and also add properties like “a card has a number that varies called rank” and “cardsuit is a kind of value. The cardsuits are hearts, diamonds, clubs, and spades. Every card has a cardsuit.” Then you can do things like “If the cardsuit of a random card enclosed by the player is diamonds…”

(Not that I’m trying to convince you to change your system - I’m just fascinated by I7’s simulation capabilities.)

I’ve found Inform’s tables really hard to work with and prefer using objects, but I can’t figure out any way to get a summary of the cards into the command prompt while using objects, so I have a table that sends information to the prompt and is also used to import rank and suit values onto the card objects. And I still can’t figure out how to tell Inform to find a row matching both rank and suit without having to create a whole new column with a list of unique IDs.

The only way to do this is to repeat through the table, stopping when your condition is fulfilled. There’s no built-in phrase to do this.

Unique IDs is also a reasonable approach.

1 Like

I’ve already got a working version with unique IDs, so it’s not a big deal either way, but I tried for like an hour to get checking for two separate conditions to work and wasn’t able to. How do you do this?

I mean this sort of thing:

Table of Coordinates
x-axis	y-axis	label
1	3	"One three"
1	4	"One four"
1	6	"One six"
2	2	"Two two"
2	5	"Two five"
2	6	"Two six"

To decide what text is the label corresponding to (X - number) and (Y - number):
	repeat through the table of coordinates:
		if the x-axis entry is X and the y-axis entry is Y:
			decide on the label entry;
	decide on "Nothing"

When play begins:
	let L1 be the label corresponding to 1 and 6;
	let L2 be the label corresponding to 2 and 5;
	say "[L1]. [L2].";

You should be able to do something like this:

Every turn during Encounter:
	now the command prompt is "Play a card: [list of cards held by the player]>";

(I don’t know if you saw my post in the other thread but there’s some stuff in there about implementing cards as objects. I mentioned the documentation example “Tilt 1” but from some of your code here I’m guessing you’ve already seen it?)

(Note that you don’t have to do that every turn: the text will get re-evaluated every time, so you can just set it once, and it’ll keep changing on its own from there on out.)

1 Like

I did end up using a lot of Tilt, yeah. And as a related question, I copy/pasted this almost exactly from Tilt:

After reading a command:
	if the player's command includes "of [suit]":
		while the player's command includes "of":
			cut the matched text;
	repeat through the Table of Card Names:
		while the player's command includes topic entry:
			replace the matched text with written value entry.

It worked for a while, but something seems to have broken it and I don’t know what. Inform no longer recognizes Jack, Ace, etc. Does anyone have any idea why this might have stopped working?

EDIT: I have discovered several incorrect ways of solving this problem. It’s not because of the table being set up wrong. Even when mapped to a table identical to the one found in Tilt, it still doesn’t work.

It’s definitely something to do with my code, specifically, because copying Tilt exactly with nothing else works fine.

It’s not because of some kind of conflict with other “After reading a command” code, because there’s only one other part of the code that uses that syntax and the problem persists even when that part is commented out.

Wherever the problem is, it exists in the encounter code, because it persists even in the encounter demo project I created to test the code in isolation from the rest of my story.

It’s not a problem with recognizing the existence of face cards at all. Trying to play an 11 works just fine, but trying to play a jack does not.

EDIT 2: It’s also not a problem with Inform failing to read the entire block of code entirely. Editing the code to this:

After reading a command while the player is imperiled:
	if the player's command includes "of [suit]":
		while the player's command includes "of":
			cut the matched text;
	repeat through the Table of Card Names:
		while the player's command includes Topic entry:
			replace the matched text with Written Value entry;
	if the player's command includes "fizzbop":
		showme the contents of the Table of Card Names.

Causes the story to show the contents of the table properly when “fizzbop” is entered.

It’s not a problem with the table or the way that specific code block is written. Copying the table and the code block from Tilt exactly does not solve the problem.

So Inform knows that “play 11” means to play the jack. It’s reading this code block. The table is formatted properly and the entries we’re looking for all match. But for some reason, it’s not replacing “play jack” with “play 11.”

EDIT 3: Copy/pasting the table from Tilt didn’t work the first time, but while flailing about hoping to get insight into what the bug actually was, I tried it again and now it works. So, problem solved, but also, huh?

I’m kind of going to recommend that you change your system here, because it seems like some of the things you’re having trouble with would be easier if you implement the cards as objects with properties instead of using tables. And tables are pretty annoying, as you’re finding–plus they’re creating large blocks of identical code, which is dangerous, because if you change something in one place you have to make sure to change it everywhere.

Specifically: when you’re talking about getting the card names from the parser, that’s something you can do fairly readily using the properties of the cards and using synonyms. And when you want to list the cards, that’s something you can do by repeating through the cards the player has and writing a routine to translate the card into a short form.

Another thing is that in general you want to avoid processing commands using “After reading a command” rules. It’s usually less fragile to use the parser and action machinery. For this code I even found a way to avoid the After reading a command rule that deletes “of,” by just defining “of spiders” as a synonym for spiders, etc. (This would be something that you might not want to do if you had lots and lots of suits, because you have to type these synonyms for hand by each suit, but with five suits it seems doable.)

That said, I had to tweak this a bit, though part of it was because one time I straight up forgot to add “Jack” as a synonym for jacks. Also the behavior of “play A Bats” is a bit strange, because Inform wants to interpret “A” as the indefinite article. That might be hard to work around.

Anyway, here’s what I have, not a table in sight:

click here for long code thing
Section 1 - Card Stats and Conditions

A person has a number called will. The will of the player is 7.

A person has a number called focus. The focus of the player is 7.

A person has a number called work. The work of the player is 0.

A person has a number called difficulty. The difficulty of the player is 0.

A person has a number called success. The success of the player is 0.

A person can be either safe or imperiled. The player is safe.

A person can be either engaged or unengaged. The player is unengaged.

A person can be either cornered or uncornered. The player is uncornered.

[The WILL is the maximum hand draw the player is restored to when they are refreshed by a consumable or by visiting a refreshing location.

The FOCUS is the maximum hand draw the player has right now. When an encounter begins, they draw this many cards, and when they redraw, their focus drops by one.

The WORK is the total point value from all played cards in the current engagement.

The DIFFICULTY is the current amount of points the player must exceed to complete the current engagement.

While SAFE, the player has no cards. While IMPERILED, the player has cards. The player gets cards equal to their focus whenever they become imperiled, so most perilous encounters should consist of multiple different engagements or else one really big engagement.

While ENGAGED, the player cannot move, and instead can only play cards, redraw, or retreat. When UNENGAGED, the player can move normally. The player should never be engaged without being imperiled.

When CORNERED, the player cannot retreat. When uncornered, they can retreat normally. The player should never be cornered without being engaged.]

Suit is a kind of value. The suits are widows, spiders, tears, bats, and suitless. Understand "widow" and "of widows" and "Wi" as widows. Understand "spider" and "of spiders" and "Sp" as spiders. Understand "bat" and "of bats" and "Ba" as bats. Understand "tear" and "of tears" and "Te" as tears. Understand "Su" and "of suitless" as suitless.

A suit has some text called the abbreviation. The abbreviation of widows is "Wi". The abbreviation of spiders is "Sp". The abbreviation of tears is "Te". The abbreviation of bats is "Ba". The abbreviation of suitless is "Su".

A card is a kind of thing. A card can be written or unwritten. A card is usually unwritten. A card has a suit. A card has a number called rank. Understand the suit property as describing a card. Understand the rank property as describing a card.

Understand "A/Ace" as a card when the rank of the item described is 14. Understand "K/King" as a card when the rank of the item described is 13. Understand "Q/Queen" as a card when the rank of the item described is 12. Understand "J/Jack" as a card when the rank of the item described is 11.

To say (count - number) as a card name:
	let T be some text;
	if count is:
		-- 14: now T is "Ace";
		-- 11: now T is  "Jack";
		-- 12: now T is "Queen";
		-- 13: now T is "King";
		-- otherwise: now T is "[count in words]";
	say T in sentence case. ["sentence case" capitalizes the first letter]

To say (count - a number) as an abbreviated card name:
	if count is:
		-- 14: say "A";
		-- 11: say "J";
		-- 12: say "Q";
		-- 13: say "K";
		-- otherwise: say "[count]". 

		
Rule for printing the name of a card (called target):
	say "[rank of the target as a card name] of [suit of the target]".
	
Identity relates a card (called X) to a card (called Y) when the rank of X is the rank of Y and the suit of X is the suit of Y. The verb to be identical to means the identity relation. [will be used to prevent making two identical cards]

Section 2 - Drawing Cards

Redrawing is an action applying to nothing. Understand "redraw" as redrawing.

Carry out redrawing:
	now every card is in the discard;
	now every card is unwritten;
	repeat with N running from 1 to the focus of the player:
		if there is a card (called the draw) in the discard:
			initialize the draw;
			now the player has the draw;
		otherwise:
			say "The discard has been exhausted.";
			break. [this stops the loop so the message doesn't repeat--not that it should be possible to get here anyway!]
		
To initialize (flop - a card):
	now the suit of flop is a random suit;
	now the rank of the flop is a random number between 2 and 14;
	while the flop is identical to a written card:
		now the suit of the flop is a random suit;
		now the rank of the flop is a random number between 2 and 14; [we will have to be careful not to let the number of cards in the game get anywhere near the total number of possible cards, or this could take a long time or even go into an infinite loop. But if that's an issue, we should just generate all 65 possible cards at the beginning.]
	now the flop is written.

Section 3 - Playing Cards

Encounter is a recurring scene. Encounter begins when the player is engaged. Encounter ends when the player is safe.

When Encounter begins:
	try redrawing.

Every turn during Encounter:
	now the command prompt is "Play a card: [abbreviated description of the player's hand]>";
	if the work of the player is greater than the difficulty of the player:
		say "Success! The difficulty of this challenge was [difficulty of the player], and you put down [work of the player] points from your cards.";
		now the player is unengaged;
		now the player is safe;
		increase the success of the player by 1;
		now the difficulty of the player is 0;
		now the work of the player is 0.

To say abbreviated description of the player's hand:
	repeat with flop running through cards held by the player:
		say "[rank of flop as an abbreviated card name] [abbreviation of suit of flop] ".

Before doing anything other than redrawing or retreating or playing a card while the player is engaged:
	say "Redraw, retreat, or play a card." instead.

Instead of dropping a card, say "Best to hang onto that until you need it."

When Encounter ends:
	now the command prompt is ">";
	say "You have succeeded!";
	now every card is in the discard;
	now every card is unwritten;
	now the player is uncornered;
	now the player is unengaged.

Playing a card is an action applying to one thing. Understand "play [card]" as playing a card.

Check playing a card:
	if the player does not have the noun:
		say "You don't have that card in your hand." instead;
	if the player is not engaged:
		say "There's no immediate obstacle to play the card against. Hold onto your cards until you find one." instead.

Carry out playing a card:
	now the noun is in the discard;
	increase the work of the player by the rank of the noun.

Report playing a card:
	say "You play [the noun]."

Retreating is an action applying to nothing. Understand "retreat" as retreating.

Check retreating:
	if the player is cornered:
		say "You can't back out of this one." instead.

Check retreating:
	if the player is unengaged:
		say "There's nothing to retreat from." instead.

Carry out retreating:
	say "You abandon your efforts.";
	now the work of the player is 0;
	now the player is unengaged.

Section 4 - Miscellanea

The test chamber is a room. "Current work is [the work of the player]."

Backstage is east of the test chamber. The discard is a container in Backstage. The deck is a container in Backstage. The hand is a container in Backstage. It is openable and open. There are 13 cards in the discard.

A spider is an animal. It is in Backstage.

Instead of attacking a spider:
	say "The spider becomes angry!";
	now the difficulty of the player is 8;
	now the player is imperiled;
	now the player is engaged.
	
Every turn when the success of the player is 3 and the spider is in Backstage:
	now the spider is nowhere;
	now the tricky spider is in Backstage.

A tricky spider is an animal. It is nowhere.

Instead of attacking a tricky spider:
	say "The tricky spider holds you in place with webs!";
	now the difficulty of the player is 12;
	now the player is imperiled;
	now the player is engaged;
	now the player is cornered.
	
Every turn when the success of the player is 4:
	if the tricky spider is in Backstage:
		say "You have slain the tricky spider!";
		now the tricky spider is nowhere;
		now the player is safe;
		now the player is unengaged;
		now the player is uncornered;
		reject the player's command.
1 Like

Is there a way to make blank cards show up in the command prompt with this method? One thing I like about the way it works now is that when you play a card, it leaves behind a dash mark, and then when you redraw, the final card spot also has a dash mark. This makes it intuitive that using redraw causes the total hand size to shrink by one, whereas just printing the number of cards requires the player to notice that the total hand size is shrinking, something which doesn’t become obvious until you’ve already redrawn down to five or four cards or so.

Right now, the system requires no tutorializing at all. The command prompt switches to a hand of cards and the player is told to play one, so they PLAY JACK or whatever, and it works. Then they notice that the report is “You play the Jack of Widows,” so later on when the suit of Bats is added, they won’t be confused by 10-Wi and J-Bat. All they need to be told is that the suit of Bats has been added, and then they can work out that “Bat” is short for the Bats suit and therefore “Wi” must be short for the Widows suit they’ve been using all along. I’m really eager to get rid of this tottering pile of tables I’ve got duct-taped together right now, but it’s important to me that this system remain something a player can fairly easily figure out by playing, without me having to stop and dump a tutorial on them.

I think so! If I’m following what you need, basically you need to print a number of dashes at the end of the hand that is equal to the max number of cards minus the number the player actually has. You can do that with a simple loop at the end of the phrase for saying the abbreviated description of the player’s hand:

To say abbreviated description of the player's hand:
	repeat with flop running through cards held by the player:
		say "[rank of flop as an abbreviated card name] [abbreviation of suit of flop] ";
	repeat with index running from 1 to (focus of the player minus number of cards held by the player):
		say "-- ".

When the player’s hand is full, the last loop runs from 1 to 0, which means it doesn’t run at all! As we want.

A couple other notes about the code:

  1. I couldn’t ever get out of combat even after defeating the spider–I had to add a “now the player is safe” rule to that.
  2. Possibly because of that tweak, it is now possible to redraw even when not in combat. Which then leads to a bad thing when you have a spider card in your hand, if you want to hit the spider the game asks you which you mean, and there’s no way to specify the spider without getting the same question again.
  3. As Daniel said, we really don’t need to change the command prompt every turn–just change it at the beginning of the combat scene.
  4. But it looks kind of weird to me to have the whole hand print for a disambiguation question! I think this could be handled by changing the prompt in a “Before asking which do you mean” rule and then changing it back (during an appropriate scene) in an “After asking which do you mean” rule.
  5. Also I think at the moment we don’t have the rule that makes the focus drop by one when you redraw! (I do think that it’d be good to explicitly tell the player that this decreased their focus.)

This whole concept seems neat! I like your idea of avoiding the tutorial.

Can we get cards played to be replaced with a “-” too? That gets players to make the connection between the - and an empty spot in their hand when they first play a card, that way when they first redraw they know they have an empty spot at the end.

On the notes:

  1. In test encounter, you have to attack the spider three times. After defeating it three times, it spawns the tricky spider. Only when the tricky spider is beaten does the encounter end and things go back to normal. This isn’t obvious at all from the “attack the spider” instruction at the beginning, so an actual finished story definitely needs to be more clear with objectives, but in this case I just needed to be able to test my ability to string multiple engagements together into one encounter. It’s intentionally true that you can move around during an encounter so long as you aren’t engaged, and that your hand doesn’t refresh until you’re completely safe, even if you’re not being attacked right this second. In the actual spider-kicking segment of the story I’m working on, individual spiders are pushovers but you can burn through a redraw or two if you fight each one individually. You can save yourself a bit of trouble by turning the heat on to the pipes and boiling all the spiders who haven’t exited into the cellar, but it’s also possible to brute force your way through if you want. Since it’s the introduction of the whole system, I wanted to make it forgiving enough that players should have enough raw power to be able to blunder their way through.

  2. This bug was in the original version, too! It’s fixed now. Redrawing now checks to make sure you’re engaged first. I’ve also changed all the enemy spiders in the actual story to giant spiders to make it easy to distinguish them from the suit, plus, the spiders in the story are aggressive and will engage the player automatically.

  3. I’ve moved the command prompt change to the “when Encounter begins” rules. While I was there, I added something that keeps track of the current work of the player, to help make it clear that playing a small card does have some effect even when it doesn’t end the engagement immediately.

  4. Generally speaking, I want the hand printed whenever the player is engaged in an encounter, regardless of whether they need to play a card right now. The command prompt got changed from “pick a card” to “Your hand:” to help make this clear. If players are confused when a hand of cards appears in the prompt for the very first time, the “retreat, redraw, or play a card” statement should orient them.

  5. This is why “carry out redrawing” and “when Encounter begins” have nearly identical code repeated in different places in my original code. Redrawing decreases the focus of the player by one, but beginning an encounter does not. That’s an easy fix to implement and it wasn’t really the point of your example code, so I didn’t bother nitpicking it earlier.

I think so–this takes a bit more trickery because we can’t just repeat through the cards, but we can assign places to the cards when we redraw and then use those places to list them (or dashes, if there’s nothing in the place).

Assigning places:

A card has a number called the hand order.

Carry out redrawing:
	now every card is in the discard;
	now every card is unwritten;
	repeat with N running from 1 to the focus of the player:
		if there is a card (called the draw) in the discard:
			initialize the draw;
			now the player has the draw;
			now the hand order of the draw is N; [new!]
		otherwise:
			say "The discard has been exhausted.";
			break. [this stops the loop so the message doesn't repeat--not that it should be possible to get here anyway!]

Listing:

Ordering relates a card (called X) to a number (called Y) when the hand order of X is Y. The verb to be ordered in means the ordering relation.

To say abbreviated description of the player's hand:
	repeat with index running from 1 to the focus of the player:
		if the player has a card (called flop) that is ordered in the index:
			say "[rank of flop as an abbreviated card name] [abbreviation of suit of flop] ";
		otherwise:
			say "-- ".

I feel like there should be some less roundabout way to check whether the player has a card with hand order index other than by defining a new relation, but I couldn’t think of one.

Oh OK! I get the logic now–I think there was some trickery with the command prompt that was confusing me, but that might be due to my changes too.

Also I think my “every turn” logic isn’t quite working. Probably what would work better than “every turn” is to put the check for whether you beat the spider in the carry out playing rules, and maybe change the report playing rules to report whether the spider is defeated.

Yes, adding an adjective to things to prevent disambiguation loops is very useful!

I see, that’s where I introduced the bug!

I just finished patching out all the tables with your new code! I did have to squish one bug:

	repeat with index running from 1 to (will of the player minus focus of the player):
		say "- ".

Originally it was focus of the player minus the cards held by the player, which just added a dash mark every time a card was played and reset them all at the end. I think this was just a typo, because will of the player minus focus of the player got exactly what I was looking for. Cards and spider AI are both working, so now I can move onto the upper floor and figuring out how to make logic puzzles.

EDIT: I went ahead and made Matt W’s last post the solution just to get this thread marked as solved, but really, the solution was cobbled together from like eight different posts, so thank you very much to everyone who helped me figure out this complex, multi-faceted system!

1 Like