Inform Tape Deck: Help making an in-game media player that responds to different input

Hello all, I am relatively new to using I7 for IF. I have scoured the internet for an answer to my question but I haven’t been able to find one so here I am.

My main goal is to have a tape player that the player can play tapes with different recordings on. I took some inspiration from the book reading example to give things a recording. This way the output changes based on the unique recording of each tape. I’ve been able to hack it all together and it works relatively smoothly, but I can only manage to make it work when there is a single tape player in the entire world. What I would like is to have a set of rules that allow any tape be played in any tape deck from inside cars to heavy stereo units to small portable decks. I would appreciate any advice that you have!

Here is the working code that I have built so far:

Rule for implicitly taking something (called the target):
	Try silently taking the target;
	If the player carries the target, say "You first take the [the target].[paragraph break]"
A tape is a kind of thing. Understand "tape" as tape. A tape has some text called recording.

Understand the command "play" as something new. Understand "play [something]" as playing. Playing is an action applying to one thing and requiring light.
	
Check playing something:
	If the noun is not a tape, say "What is that supposed to accomplish?" instead;
	If the Tape Deck contains the noun, say "The tape spins for a moment then you hear:[line break][recording][line break]" instead;
	If the Tape Deck contains something (called the active), carry out the implicitly taking activity with the active;
	If the Tape Deck contains nothing, try silently inserting the noun into the Tape Deck;
		say "The tape spins for a moment then you hear:[line break][recording][line break]".

Tape Deck is a transparent container. The carrying capacity of Tape Deck is 1. The description is "Old reliable."
Check inserting noun into the Tape Deck:
	If the noun is not a tape, say "What is that supposed to accomplish?" instead.
	
Cassette is an object. It is a tape. The description is "Awesome Mix". The recording of Cassette is "Hooked on a feeling."
1 Like

Here’s one way to do it. The main ideas are:

  1. Create a new kind “tape-player”, so you can have various decks in the world.

  2. Since you probably want the game to respond to commands like “play cassette on stereo”, it can make sense to define the action as applying to two things, and then treat the case where the player just types “play cassette” as a special case of that.

A tape is a kind of thing. Understand "tape" as a tape.
A tape has some text called recording.

A tape-player is a kind of transparent container.

Check inserting something into a tape-player:
	if the noun is not a tape, say "What is that supposed to accomplish?" instead.

Playing it with is an action applying to two things. Understand "play [something] with/in/on [something]" as playing it with.

Check playing it with:
	if the noun is not a tape, say "What is that supposed to accomplish?" instead;
	if the second noun is not a tape-player, say "That's not something you can play [the noun] on." instead.

Carry out playing it with:
	if the second noun contains something (called the current content):
		if the current content is not the noun:
			carry out the implicitly taking activity with the current content;
	if the second noun contains nothing, try inserting the noun into the second noun.

Report playing it with:
	say "The tape spins for a moment, then you hear:[line break][recording][line break]".

Understand "play [something]" as playing it with.

Rule for supplying a missing second noun while playing:
	if the player can touch a tape-player (called T):
		say "(on [the T])[line break]";
		now the second noun is T;
	otherwise:
		say "There's no tape player nearby.".

The tape deck is a tape-player. The carrying capacity of the tape deck is 1. The description is "Old reliable."

The pop mix cassette is a tape. The description is "Awesome Mix". The recording of the pop mix cassette is "Hooked on a feeling".
The metal mix cassette is a tape. The description is "It rocks." The recording of the metal mix cassette is "Painkiller".

The Storeroom is a room.
The tape deck is in the Storeroom.
The microwave is in the Storeroom.

The player carries the pop mix cassette and the metal mix cassette.
The player carries a laserdisc.

The Living Room is west of the Storeroom.
The big stereo unit is a tape-player in the Living Room. The carrying capacity of the stereo unit is 1.

Test me with "play laserdisc/put laserdisc in deck/play metal mix on microwave/play pop/play metal/get deck/w/play pop on stereo/play metal".

As usual, there are probably various ways in which this could be refined or approached differently. Also worth checking out in the docs: chapter 12.10, “Action Variables”.

8 Likes

After hours upon hours of pulling my hair out over this you have solved my problem. I had tried making a tape-player kind but I could never get it to work. It must be that I had playing as applying to one thing and I was putting in checks to make a tape-player required. Thank you so much, now I can get to the actual content of the game.

1 Like

I recently implemented a cassette (or tape) player for The Seeds of Evil and it reappears in The Horror of Goldmine City. These games were written by @g0blin for The BDB Project. This doesn’t help you, as it’s implemented in Inform 6 using the PunyInform library, but it sounds very similar to what you were looking for, so you might like to take a look at it.

First of all, you need a parse_name routine to distinguish between the cassette and the cassette player.

The cassette has two sides labelled side A and side B. You can examine each side to see what’s written on the label. You can insert side A or side B and turn it over to play the other side.

The cassette player is portable, so it requires a battery to be inserted before you can use it. It has three buttons: PLAY, REWIND and EJECT. (There’s no FAST FORWARD, as I was trying to keep it simple. There’s no RECORD, as it’s a player, not a recorder. Think Sony Walkman.) You can press the PLAY button to play the cassette or just PLAY CASSETTE. Similar logic for rewind and eject.

The cassette remembers its state. Once you’ve played the cassette, you have to rewind it to play the same side again. To play the other side, you can either eject it and insert the other side or flip it over.

4 Likes

This has obviously been answered very satisfactorily, but still, this is a shout out to @improvmonster for the wonderful and almost tactile implementation of a Walkman in the Candy Striper of St. Asterix. It’s also in Puny Inform but well worth checking out.

That is definitely a more thorough option. I had initially toyed around with the tape player being a device so it could be switched on/off or require a battery, but with Inform 7s complicated device-container relationships I figured it wasn’t worth the effort. A and B sides would certainly give me more room to provide lore. I’ll have to look into it. Thanks Garry!

1 Like

I’m not sure what you mean here. If you are referring to multiple inheritance, it’s true that Inform does not have that, but it’s unnecessary in this case; all you need to do is add:

A tape-player can be switched on or switched off.

to @StJohnLimbo 's code and you’ll have all the same switching on/off behavior that devices have. That is, the switching it on and switching it off actions will work as expected and the description of the deck will have the “The tape deck is currently switched on/off” message tacked onto it automatically.

Obviously, you’d still have to handle what to do about the other actions, like “playing it with” when the deck is off, but you would have had to do that with a device as well.

EDIT: adding a separate battery compartment would be a little bit more complicated though.

@BadParser You know what, you’re totally right. I hadn’t even given it more thought since dismissing the idea. That changes things.

1 Like

Yeah, Inform 7 kinds are odd like that—sometimes the behavior is baked into the kind, like “container” or “supporter”, and sometimes the behavior is baked into properties the kind supplies, like “switched on” or “lockable”. And since you can add properties to any kind, this lets you mix and match more than the documentation might suggest.

On the I6 level, basically everything depends on properties rather than kind, which is how extensions like Rideable Vehicles can combine “vehicle” and “supporter”. But this isn’t recommended unless you know exactly what you’re doing.

1 Like