For those fluent in inform7, how long would it take you to implement Cloak of Darkness?

Dang, Otis, why you gotta be sayin’ true things?

2 Likes

[spits tea]

4 Likes

I think this thread is it. Interestingly, every entry so far has at least one unique feature:

  • Emily Short?: scoring, control of Bar lighting based on actions taken with cloak instead of cloak’s position in world model
  • Draconis: less than half the size and taking less than half the time of any other entry
  • Zed: use of backdrops, scope modification, and visibility rules
  • drpeterbatesuk: implements background props for player interaction in Bar, uses understand ... as a mistake, implements verb word synonym
  • otistdog: uses standalone rule, uses I6 inclusion
  • FLACRabbit: specialized report rule for hanging the cloak, suppresses a Standard Rule, humor-oriented responses to nonsensical actions, pokes fun at absurdities of scenario instead of trying to justify them to player
  • mathbrush: compliance with specified spatial structure of scenario provable using topological cohomologies, surrealist/psychological horror interpretation

(@mathbrush: Forgive me if my mathematical technobabble for humor’s sake is inaccurate. Forgive me even more if it isn’t.)

5 Likes

Creating a minimal implementation for the speedrunning challenge took me just about 11 minutes and 4 seconds, including setting up the project file and “testing.”

It is (as far as I can tell) feature-complete, but probably riddled with bugs and unexpected behavior.

I7 source code - 487 words
"Cloak" by "FLACRabbit"

The Foyer of the Opera House is a room. "It is the foyer of the opera house. Doors lead south, west, and north."

Instead of going north in the Foyer, try entering the fakedoor.

The fakedoor is a scenery fixed in place thing in the Foyer. Understand "door" as the fakedoor. It has printed name "north door". Instead of entering the fakedoor, say "It's just a stage prop." Instead of opening the fakedoor, say "It's just a stage prop." Understand "north" as the fakedoor.

The Cloakroom is a room. "It is a small room with a sign that reads 'Cloak Room' and a hook on the wall."

A sign is a scenery thing in the Cloakroom. It has description "It tells you just what kind of room this is."

A hook is a scenery supporter in the Cloakroom. Instead of taking the hook, say "You're not that strong." Instead of entering the hook, say "That sounds painful."

The player wears a thing called a black velvet cloak. The cloak has description "Light-absorbent velvet - the latest in inconvenient but expensive technology." Instead of dropping the cloak when the player is not in the Cloakroom, say "It's not proper to drop your cloak in anything other than a designated Cloakroom."

Understand the command "hang" as "put".

Report putting the cloak on the hook: say "You hang the cloak on the hook. Now it won't bother you."

The west door is a scenery door. It is west of the Foyer and east of the Cloakroom.

The Bar is a room. "Maybe it used to be a bar, but now it's just dusty and abandoned. There is some writing on the floor." The south door is a scenery door. It is south of the Foyer and north of the Bar. The bar is dark.

Carry out going south in the Foyer:
	if the player encloses the cloak, now the bar is dark;
	if the player does not enclose the cloak, now the bar is lit.

There is a scenery thing called a message. It is in the bar. Understand "writing" or "word" or "words" or "dust" as the message. The message can be pristine or disturbed. The message is pristine.

The standard report putting rule does nothing when the noun is the cloak.

Instead of doing anything other than going north when the player is in the Bar and the Bar is dark:
	say "You aren't sure of anything in the dark. You scuffle around and then decide it's probably best to go north, back into the foyer.";
	now the message is disturbed.
	
The message has description "[if the message is disturbed]Somehow, your scuffling has made it say 'You have lost.'[otherwise]It reads 'You have won'. And so you have![end if][final]"

To say final:
	if the message is disturbed:
		end the story saying "Well, I guess you lost then!";
	otherwise:
		end the story finally saying "You have won!"
Implementation notes
  • I am aware that my doors are named after their direction from the Foyer. If I were to make a more polished version, I would use conditional “Understand” statements to (for example) understand the “west door” as the “east door” when in the Cloakroom, etc.
  • Many things, alas, have default descriptions. No time for such matters! (Of course, there is plenty of time to make a sign object just because I mentioned it in the description [an automatic reflex by now], implement custom responses for entering and taking the hook, and obsess over the phrasing of the cloak’s description.)
  • “Carry out going south in the Foyer” is a fragile way to implement the light-switching (by which I mean that it would break if the scenario were extended - say by adding more exits, or a magical portal). But as it’s currently the only way to enter the Bar, there is no functional difference between this and a more sophisticated solution.
2 Likes

The fake-door kind of backdrop was a misstep. I should have used a conventional door for the cloakroom and probably also for the bar.

Another offering- this time in Basic Inform, offered as the fruits of an exercise in self-flagellation and in exploring the minimalist limits of a world model (if you can call it that) and parser (if you can call it that) which fit the specs and nevertheless allow a reasonable player experience.

Two hours to knock up the code, scenario, messages, scoring;
An hour to debug;
An hour to polish and refine (mostly fancy text effects and the help messages);

This version has to be compiled for Glulx (Z-machine handles some arrays differently, and this has consequences for the I6 inclusions relating to getting keyboard input)

"Cloak_Basic" by PB

[#### NB due to differences in array structure between Glulx and Z-machine, this version needs to be compiled for Glulx ####]

Section - Setup

Room is a kind of value. rooms are Foyer of the Opera House, Cloakroom, Bar. A room has a text called description.
The description of Foyer of the Opera House is "An echoing, empty space with open doorways leading west to the cloakroom and south to the dimly lit bar. To the north, the open doors of the grand entrance lead back onto dark and rain-lashed streets.". ['dimly lit'-a feeble justification for why the cloak makes the bar dark but not the foyer or cloakroom]
The description of Cloakroom is "The walls of this small anteroom are bare, apart from a small brass hook[if cloak-position of the Cloakroom is hung] from which hangs a black velvet cloak[else if cloak-position of the Cloakroom is dropped]. Crumpled on the floor is a black velvet cloak[end if].".
The description of Bar is "Rows of gleaming glasses and  bottles line the polished mahogany bartop.[paragraph break]Your attention is drawn to a message scrawled [if the sawdust-disturbance of the Bar is not destroyed]into the sawdust [end if]on the floor.".



Cloak-position is a kind of value. The cloak-positions are player, dropped, hung.
The Cloakroom has a cloak-position.
Sawdust-disturbance is a kind of value. The sawdust-disturbances are pristine, scuffed, disturbed, destroyed.
The Bar has a sawdust-disturbance.
The location is initially Foyer of the Opera House.
The player-command is initially "".
Game-over is initially false.

Section - Main

To begin:
	say "[fixed letter spacing]";
	say "##################################################[line break]";
	say "#                                                #[line break]";
	say "#  WELCOME TO *BASIC INFORM* CLOAK OF DARKNESS!  #[line break]";
	say "#         (an exercise in retro fun)             #[line break]";
	say "#                                                #[line break]";
	say "#     You can enter one word commands only.      #[line break]";
	say "#                                                #[line break]";
	say "#                 Good luck!                     #[line break]";
	say "#      (type HELP for further information)       #[line break]";
	say "#                                                #[line break]";
	say "#         (c) 2023 Black Toad Software           #[line break]";
	say "#                                                #[line break]";
	say "##################################################[roman type][paragraph break]";
	look;
	while game-over is false:
		follow the turn sequence rules;
	say "[paragraph break][bracket]PRESS A KEY[close bracket][line break]";
	wait for a keypress;
	clear the screen;
	say "[fixed letter spacing]";
	say "############################[line break]";
	say "#                          #[line break]";	
	say "#    ***  THE END  ***     #[line break]";
	say "#                          #[line break]";	
	say "############################[line break]";
	
Section - Turn Sequence
	
The turn sequence rules are a rulebook.
rule for turn sequence:
	read the player_command;
	if player-command is "": [invalid input]
		do nothing;
	[deal with meta commands first so they don't cause a disturbance in the Bar]
	else if the player-command is "help":
		[self-justificatory preamble]
		clear the screen;
		say "[line break][bold type]ABOUT THIS STORY[roman type][paragraph break]";
		say "This is an implementation of the [']Cloak of Darkness['] example story, written (as an exercise in self-flagellation) in Basic Inform 7 (i.e. without Inform's built-in parser or the world model) and without using Basic Inform's object framework, in order to approximate the experience of coding in a general purpose rather than domain-specific language idiom.[paragraph break]The tightly limited parameters of the scenario allow it to be played out using single word commands, making implementing the parser relatively straightforward- the game logic similarly so, as the range of world-states permitted by the scenario is extraordinarily circumscribed.[paragraph break]Indeed, the greatest challenge was the ordinarily trivial task of getting user input from the keyboard, which I was surprised to find Basic Inform does not natively support and therefore required a little I6 hacking.[paragraph break]For once I followed my own advice- [']Don't simulate what doesn't need simulation['], so no doors for example (heh, heh) but I did try to deliberately take advantage of some elements of Inform that make for readable code and to minimise use of global variables.[paragraph break][bracket]PRESS A KEY[close bracket][line break]";
		wait for a keypress;
		clear the screen;
		[playing the game]
		say "[bold type]PLAYING THE GAME[roman type][paragraph break]";
		say "[line break][bold type]Your goal is simply to get to the bar for a drink... or so it seems at first![roman type][paragraph break]";
		say "You can move around by typing a cardinal compass direction- e.g. [bold type]n[roman type] or [bold type]north[roman type] (likewise [bold type]e[roman type] ,[bold type]s[roman type] ,[bold type]w[roman type])[paragraph break]";
		say "Some other commands you can use are:[line break]";
		say "    [bold type]inventory[roman type] (or [bold type]i[roman type] for short) - which lists everything you are carrying[line break]";
		say "    [bold type]examine[roman type] (or [bold type]x[roman type] for short) - which will tell you more about something nearby[line break]";
		say "    [bold type]take[roman type] or [bold type]get[roman type]  - which will allow you to pick up something nearby[line break]";
		say "    [bold type]wear[roman type] - which will allow you to put on something nearby[line break]";
		say "    [bold type]drop[roman type] - which will allow you put down something you are carrying or wearing[line break]";
		say "    [bold type]look[roman type] (or [bold type]l[roman type] for short) - which describes your immediate surroundings[paragraph break]";
		say "    [bold type]again[roman type] (or [bold type]g[roman type] for short) - repeats the last command you typed[paragraph break]";
		say "There is at least one other command you'll need to end the game in glory- that's for you to discover![paragraph break]";
		say "[bracket]PRESS A KEY[close bracket][line break]";
		wait for a keypress;
		clear the screen;
		look;
	else if the player-command is "score":
		say "Hmm.. How do [italic type]you[roman type] think you are doing?";
	[unimplemented meta commands]
	else if the player-command is "undo":
		say "This is BASIC Inform. Sadly, there's no UNDO command. But you really shouldn't need it!";
	else if the player-command is "save":
		say "This is BASIC Inform. Sadly, there's no SAVE command. But you really shouldn't need it!";
	[action-processing (ha, ha)]
	[deal with the special case of doing stuff in a dark Bar]
	else if the location is the Bar and the cloak-position of the Cloakroom is player and the player-command is not "n":
		say "Scuffling around in the dark is not going to further your cause!";
		if the sawdust-disturbance of the Bar is not destroyed:
			now the sawdust-disturbance of the Bar is the sawdust-disturbance after the sawdust-disturbance of the Bar;
	[deal with the rest]
	else if the player-command is "look" or the player-command is "l":
		look;
	else if the player-command is "inventory" or the player-command is "i":
		if the cloak-position of the Cloakroom is player:
			say "You are wearing a cloak of velvet, so black and dense it seems almost to suck the light from its surroundings.";
		else:
			say "You are disrobed.";
	else if the player-command is "n" or the player-command is "north":
		if the location is the Foyer of the Opera House:
			say "It's too early in the evening to be leaving without a drink!  Also- that rain!";
		else if the location is the Bar:
			go to Foyer of the Opera House;
		else:
			say "[cant_go].";
	else if the player-command is "e" or the player-command is "east":
		if the location is the Cloakroom:
			go to Foyer of the Opera House;
		else:
			say "[cant_go].";
	else if the player-command is "s" or the player-command is "south":
		if the location is the Foyer of the Opera House:
			go to Bar;
		else:
			say "[cant_go].";
	else if the player-command is "w" or the player-command is "west":
		if the location is the Foyer of the Opera House:
			go to Cloakroom;
		else:
			say "[cant_go].";
	else if the player-command is "x" or the player-command is "examine":
		if the location is the Foyer of the Opera House:
			if the cloak-position of the Cloakroom is player:
				say "You are wearing a cloak of velvet, so black and dense it seems almost to suck the light from its surroundings.";
			else:
				say "You are disrobed.";
		else if the location is the Bar:
			if the sawdust-disturbance of the Bar is:
				-- pristine:
					say "Scrawled into the";
				-- scuffed:
					say "Scrawled into the scuffed";
				-- disturbed:
					say "Scrawled into the badly scuffed";
				-- destroyed:
					say "Written on the floorboards  (revealed by your inept blunderings which have swept aside a thin layer of sawdust) is the timeless epigram 'You have lost!'";
			unless the sawdust-disturbance of the Bar is destroyed:
				say " sawdust is the timeless epigram 'You have won ";
				if the cloak-position of the Cloakroom is hung:
					say "magnificently";
				else:
					say "mundanely";
				say "!'";
			now game-over is true;
		else if the location is the Cloakroom:
			if the cloak-position of the Cloakroom is:
				-- player:
					say "The hook is bare.";
				-- hung:
					say "Your velvet cloak hangs from the brass hook.";
				-- dropped:
					say "Your velvet cloak lies crumpled on the floor below the brass hook.";
	else if the player-command is "drop" or  the player-command is "disrobe":
		if the cloak-position of the Cloakroom is player:
			if the location is Cloakroom:
				now the cloak-position of the Cloakroom is dropped;
				say "You drop the cloak to the floor, where it lies in a crumpled heap.";
			else:
				say "There surely must be somewhere more appropriate to leave it?";
		else:
			say "You are empty-handed.";
	else if the player-command is "hang" or  player-command is "put" or player-command is "place" or player-command is "drape":
		if the cloak-position of the Cloakroom is player:
			if the location is Cloakroom:
				now the cloak-position of the Cloakroom is hung;
				say "You hang the cloak from the brass hook.";
			else:
				say "There surely must be somewhere more appropriate to leave it?";
		else:
			say "You are empty-handed.";
	else if the player-command is "take" or the player-command is "wear" or the player-command is "get":
		if the location is Cloakroom and the cloak-position of the Cloakroom is hung or the cloak-position of the Cloakroom is dropped:
			say "You slip the velvet cloak back over your shoulders.";
			now the cloak-position of the Cloakroom is player;
		else:
			say "There's nothing available.";
	else:
		say "Sorry, I don't recognise the command '[player-command]'. Please try something different.";
		
Section - Reading the Player's Command

To read the player_command:
	say ">";
	read input;
	let pc be "";
	if the word-count is not 1: [entered no words or more than one word]
		say "Please enter a single-word command.[paragraph break]";
		now player-command is "";
	else: [construct command word]
		repeat with cx running from start-char to start-char + len-char - 1:
			now pc is the substituted form of "[pc][the character at position cx as a character]";
		unless pc is "g" or pc is "again":
			now player-command is pc;
			
Section - General Functions

To say cant_go: say "You can't go that way".

To go to (r - a room):
	now the location is r;
	look;
	
To look:
	if the location is the Bar and the cloak-position of the Cloakroom is player:
		say "[line break][bold type]In The Dark[roman type][line break]It's pitch dark and you can't see a thing- apart from a faint light from the foyer to the north.[paragraph break]";
	else:
		say "[line break][bold type][location][roman type][line break][description of the location][paragraph break]";

Section - I6		

To read input: (- VM_ReadKeyboard(buffer, parse) -).
To wait for a keypress: (- VM_KeyChar() -).
To clear the screen: (- VM_ClearScreen(WIN_MAIN) -).
To decide what number is the word-count: (- (parse-->0) -).
To decide what number is the start-char: (- (parse-->3) -).
To decide what number is the len-char: (- (parse-->2) -).
To decide what number is the/-- character at position/-- (n - a number): (- (buffer->{n}) -).
To say (n - a number) as a character: (- print (char) {n}; -).

Section - walkthrough
[
n/e/s/light/n/w/x/drop/l/take/suspend/hang/l/x/e/s/x  [to win magnificently]
n/e/s/light/n/w/x/drop/l/x/e/s/x  [to win mundanely]
n/e/s/light/w/help/drink/n/w/hang/e/s/x [to lose]
]
6 Likes

You know cohomology actually fits really well here, that’s pretty funny (I’m not great at it, but I think it involves trading the roles of functions and objects as opposed to regular homology).

1 Like

No disparagement intended; we’re in the same boat! (And we both enjoy I7 as a game, anyway.)

3 Likes

I think the main takeaway from this thread is that Interactive Fiction languages aren’t particularly well-suited at recreating Cloak of Darkness. I look at all the Inform 7 examples and their verbosity makes me shudder. If you had used a real programming language, you could have created Cloak of Darkness in under 1kb, like I have :upside_down_face:

<html><script>b=function(){q=document.getElementById("q");act(q.value)};d=s=0,r=3,l="n#r==1#%#r=3#Foyer~s#r==3#d#s>2#%#Light Bar. You lost.~s#r==3#d#%#Light Bar. You won.~s#r==3#%#r=1#Dark Bar~w#r==3#%#r=2#Cloakroom~e#r==2#%#r=3#Foyer~#r==1#%#Do not disturb things in the dark!#s++~n,e,s,w#%#No exit~i#d#%#Nothing~i#!d#%#Wearing a cloak~xho,xcl#%#Looks normal.~drcl,hacl#%#Ok#d=1~#What?".split("~"),act=n=>{for(x of(o=0,w=n.split(" "),n=w[0].substr(0,2)+(w[1]?w[1].substr(0,2):""),l))for(y of(p=x.split("#"),p[0].split(",")))if(!y||y==n){for(c of(p.shift(),p))if("%"==c)o=1;else if(c[0].toUpperCase()==c[0]&&"!"!==c[0])document.getElementById("o").innerHTML=c;else if(z=eval(c),!z)break;if(o)return}};</script><input id="q" onchange="b()"><p id="o"></p></html>

Test with: n/i/s/e/n/w/hang cloak on hook/i/e/s

7 Likes

That’s the way Inform 7 is.

3 Likes

Yeah, the primary goal of Inform 7 is readability, and it sacrifices conciseness for that. Everything’s a tradeoff!

4 Likes

Oh, jeez. I was joking. :smiley: Please do not take my attempt at COD posted above seriously.

4 Likes

As a TADS dev: The code you’ve submitted directly supports the reason why Inform 7 is so verbose, lmao. That’s a game written with the aesthetic of a malware payload.

(Also, looking this over, I’m getting more and more certain that this was written for comedy/satire.)

Ah! I was correct, then!! Finally, all that social-reading practice is finally paying off!

EDIT: Bravo, @chance_the_ripper. The more I inspect the code you posted, the more humor I’m finding. How much time did you spend on this?

5 Likes

:smiley: You put my self-flagellation to shame

I reckon something similar could run on an unexpanded ZX80 :thinking:

4 Likes

Now we just need a Cloak of Darkness esolang like the Hello language for Hello World:
https://esolangs.org/wiki/Hello

3 Likes

To make a more serious point, which I tried much less successfully to do with my Basic Inform effort, the reverse is probably more apposite- the Cloak of Darkness scenario is intentionally so limited that you don’t need (or greatly benefit from) any kind of domain-specific language or IF coding framework to implement it- it’s trivial to do in any general purpose programming language. Which is the reason it is as it is. However, being what it is it doesn’t (as suggested elsewhere in this thread) imho much show off the features of an IF domain-specific language, coding framework or development environment- it deliberately obscures them.

As a sort of lowest-common-denominator exercise, it’s a bit like comparing different kitchen ranges by how well they can boil an egg. Any range should be able to do it well, and you won’t notice much difference in the end product.

Unless, that is, you assess on the basis of inspection of the coding itself- regarding such things as ease, elegance, conciseness and readability of coding.

2 Likes

~ 2 hours.

1 Like

Agreed, I found it simple to program even in BASIC. Problem is, you need to re-invent the wheel every time, where IF languages are re-usable.

I still think that Cloak of Darkness is pretty good for showing off the capabilities of an IF creation system. Certainly a lot better than what programmers have been throwing around for decades: “Hello World”, “Bottles of Beer on a Wall”, “Fibonacci”: those usually tell you very little about what it’s really like to use a certain programming language.

1 Like

Agreed, but I don’t think that COD is meant to show off the capabilities of a language, but rather to expose limitations of languages, some of which don’t even have a working version of COD.

1 Like