[I7] Proper names of Rooms

Let’s say I have a room I call “Billiard Room”, and I am using one of the many extensions to list exits (in this case, Andre Kosmos’ Exit Lister).

If I leave the Billiard Room, I’ll have a message like “You can go north to Billiard Room or south from here.”

If I call it “The Billiard Room”, I’ll have a message like “You can go north to The Billiard Room or south from here.”

If I call it “the Billiard Room” my message will be case correct, but the room description will be wonky, like “the Billiard Room”.

If I try calling it the Billiard Room (as in, The Billiard Room is a room.) and don’t use a printed name statement, it has no helpful effect.

Is there a way to properly manipulate the case of leading articles when naming a room?

I’ll take a shot–I doubt this is the best solution, but I’d be curious to see where my thinking’s wrong, too.

[code]“billiards” by andrew

include Exit Lister by Andre Kosmos.

room 1 is a room.

bil-room is a privately-named room. the printed name of bil-room is “[conditional-the of bil-room] Billiards Room”.

bil-room is north of room 1.

to say conditional-the of (a - a room):
say “[if player is in a]T[otherwise]t[end if]he”

test bils with “l/n/l/s/l”
[/code]

Seems to do the job. It may be a pain to put conditional text in for every room beginning with “the.” So others may have a better idea.

Maybe you could hack into the extension, replacing the regular expression “[a-z,] The” with “[a-z,] the”, too, but that’s trickier.

So, I’d have to rename the room every time it was written to screen? That seems… unelegant.

I haven’t looked at the extension code, but it looks like the best place for “the” manipulation would be there, not in your code.

Although if you have rooms like “Below the Stairs”, you’re going to need some kind of conditional anyway.

Huh, Andrew’s code did the trick. Thanks.

Yay! Unfortunately, it is a trick, and it doesn’t provide a general way to work through things. There’s also a bug when a passage loops back around to itself–though that sort of thing is frowned on, and if you’re making exits easy to follow, you probably aren’t going to try anything like that.

I suppose if you really wanted to, you could poke into the standard rules and print the room’s name in sentence case when looking.

If I understand correctly, your mistake is in your expected prose. “You can go north to the Billiard Room or south from here.” is incorrect English: “the billiard room” shouldn’t be capitalized at all.

The correct way to handle the general case of having your room names appear in prose is to name the room in code as it should appear in the prose. The billiard room is a room. or The billiard room is north of the foozball tables.

Although this does create a problem in that the bold-ed heading when one enters a room won’t be in title-caps, it’s much easier to replace the room description heading rule with your own that puts the printed name in title caps.

The only issue remaining with that is if acronyms appear in room names, such as a room called “beside the EVO machine”, which your new rule can easily special-case.

The reason Inform teaches writing room names in title case in source code is because the names don’t traditionally appear in prose except as a heading, which is supposed to be title-cased. This incidentally trains us to be blind to it when we print a room name to the screen outside headings.

So, you’re saying my room names should not be title cased at all?

Correct. Headings in bold print should be title-cased, regardless whether they’re a room name or not.

I’ve been working on code for a similar issue in my WIP. It turns out it’s tricky because when you UNDO an action, the room name is printed by some I6 code, and ends up in lower case instead of title case. I came up with an I6 inclusion to work around that, but it’s kind of gross. If anyone can suggest a more elegant/future-proof/sane method, I’d be much obliged.

[code]Section - Printing the name of a room

[If the name of a room is printed in some ordinary text, it should be printed as, e.g. “the nursery”, not just “Nursery”.]

A room has some text called the lower case name.
The lower case name of a room is usually “the [printed name of the item described in lower case]”.
[Some rooms, e.g. the Sunday School room, might need some upper case letters in their lower case name, or might need a more complicated lower case name, or something. We can fix them by giving them the appropriate lower case name.]

Rule for printing the name of a room (called the place):
if the constructing the status line activity is going on or the current action is looking or currently undoing is true:
say “[printed name of the place]”;
otherwise:
say “[lower case name of the place]”.

[Apparently the only way to figure out if we’re in the middle of undoing a command is to replace a bunch of I6 template code with a new version including just a couple of trivial changes? Okay then.]
Currently undoing is a truth state that varies. Currently undoing is false.

Include (-
[ Keyboard a_buffer a_table nw i w w2 x1 x2;
sline1 = score; sline2 = turns;

while (true) {
	! Save the start of the buffer, in case "oops" needs to restore it
	for (i=0 : i<64 : i++) oops_workspace->i = a_buffer->i;

	! In case of an array entry corruption that shouldn't happen, but would be
	! disastrous if it did:
	#Ifdef TARGET_ZCODE;
	a_buffer->0 = INPUT_BUFFER_LEN;
	a_table->0 = 15;  ! Allow to split input into this many words
	#Endif; ! TARGET_

	! Print the prompt, and read in the words and dictionary addresses
	PrintPrompt();
	DrawStatusLine();
	KeyboardPrimitive(a_buffer, a_table);

	! Set nw to the number of words
	#Ifdef TARGET_ZCODE; nw = a_table->1; #Ifnot; nw = a_table-->0; #Endif;

	! If the line was blank, get a fresh line
	if (nw == 0) {
		@push etype; etype = BLANKLINE_PE;
		players_command = 100;
		BeginActivity(PRINTING_A_PARSER_ERROR_ACT);
		if (ForActivity(PRINTING_A_PARSER_ERROR_ACT) == false) L__M(##Miscellany,10);
		EndActivity(PRINTING_A_PARSER_ERROR_ACT);
		@pull etype;
		continue;
	}

	! Unless the opening word was OOPS, return
	! Conveniently, a_table-->1 is the first word on both the Z-machine and Glulx

	w = a_table-->1;
	if (w == OOPS1__WD or OOPS2__WD or OOPS3__WD) {
		if (oops_from == 0) { L__M(##Miscellany, 14); continue; }
		if (nw == 1) { L__M(##Miscellany, 15); continue; }
		if (nw > 2) { L__M(##Miscellany, 16); continue; }
	
		! So now we know: there was a previous mistake, and the player has
		! attempted to correct a single word of it.
	
		for (i=0 : i<INPUT_BUFFER_LEN : i++) buffer2->i = a_buffer->i;
		#Ifdef TARGET_ZCODE;
		x1 = a_table->9;  ! Start of word following "oops"
		x2 = a_table->8;  ! Length of word following "oops"
		#Ifnot; ! TARGET_GLULX
		x1 = a_table-->6; ! Start of word following "oops"
		x2 = a_table-->5; ! Length of word following "oops"
		#Endif; ! TARGET_
	
		! Repair the buffer to the text that was in it before the "oops"
		! was typed:
		for (i=0 : i<64 : i++) a_buffer->i = oops_workspace->i;
		VM_Tokenise(a_buffer,a_table);
	
		! Work out the position in the buffer of the word to be corrected:
		#Ifdef TARGET_ZCODE;
		w = a_table->(4*oops_from + 1); ! Start of word to go
		w2 = a_table->(4*oops_from);    ! Length of word to go
		#Ifnot; ! TARGET_GLULX
		w = a_table-->(3*oops_from);      ! Start of word to go
		w2 = a_table-->(3*oops_from - 1); ! Length of word to go
		#Endif; ! TARGET_
	
		! Write spaces over the word to be corrected:
		for (i=0 : i<w2 : i++) a_buffer->(i+w) = ' ';
	
		if (w2 < x2) {
			! If the replacement is longer than the original, move up...
			for (i=INPUT_BUFFER_LEN-1 : i>=w+x2 : i-- )
				a_buffer->i = a_buffer->(i-x2+w2);
	
			! ...increasing buffer size accordingly.
			#Ifdef TARGET_ZCODE;
			a_buffer->1 = (a_buffer->1) + (x2-w2);
			#Ifnot; ! TARGET_GLULX
			a_buffer-->0 = (a_buffer-->0) + (x2-w2);
			#Endif; ! TARGET_
		}
	
		! Write the correction in:
		for (i=0 : i<x2 : i++) a_buffer->(i+w) = buffer2->(i+x1);
	
		VM_Tokenise(a_buffer, a_table);
		#Ifdef TARGET_ZCODE; nw = a_table->1; #Ifnot; nw = a_table-->0; #Endif;
	
		return nw;
	}

	! Undo handling

	(+ currently undoing +) = true;	! now we're undoing a thing, possibly
	if ((w == UNDO1__WD or UNDO2__WD or UNDO3__WD) && (nw==1)) {
		Perform_Undo();
		continue;
	}
	i = VM_Save_Undo();
	#ifdef PREVENT_UNDO; undo_flag = 0; #endif;
	#ifndef PREVENT_UNDO; undo_flag = 2; #endif;
	if (i == -1) undo_flag = 0;
	if (i == 0) undo_flag = 1;
	if (i == 2) {
		VM_RestoreWindowColours();
		VM_Style(SUBHEADER_VMSTY);
		SL_Location(); print "^";
		! print (name) location, "^";
		VM_Style(NORMAL_VMSTY);
		L__M(##Miscellany, 13);
		continue;
	}
	(+ currently undoing +) = false;	! we've finished undoing a thing
	return nw;
}

];
-) instead of “Reading the Command” in “Parser.i6t”.[/code]

I was looking at it again just now and wondering if it might be better to replace SL_Location instead of Keyboard, but it looks like then I’d have to copy-paste a bunch of other I6 functions from that section of the templates, just to change one of them? I can’t decide if that’s more or less terrible than replacing Keyboard (probably less?). I really don’t know enough about what goes on under I7’s bonnet, I’m just flailing about here.

Well, that’s more absolute than it needs to be. (Last month I went to an event in MIT’s Wong Auditorium, and I hope that doesn’t unnerve you.) In IF – and Clue – it’s common enough to talk about “the Billiard Room” that I think it’s stylistically okay. Although if you want to go lowercase, that’s fine too.

If you do want to go lowercase, I’d leave the room name properties as they are (for simplicity) and add “A room has some text called the lowercase-name.” (And then have all the lowercase-names look like “the billiard room”. I don’t expect your exit-lister extension won’t try to start a sentence with one.)

(You’d have to hack the extension, of course, to use this property.)

Well, my game takes place in a house with numerous bedrooms and bathrooms. So theres like “a bedroom” and “a guest room” and I was starting to think it was inconsistent to have “a bedroom” and “the Dining Room” so I made an executive decision to make all the rooms lowercase.

I hope I didn’t make the Wong choice.

Try this.

[code]“Test”

Include Case Conversion by Climbing Stars.

Include (-

[ SL_Score_Moves;
if (not_yet_in_play) return;
#ifdef NO_SCORING; print sline2; #ifnot; print sline1, “/”, sline2; #endif;
];

[ SL_Location;
if (not_yet_in_play) return;
ProcessRulebook((+ the print player’s surroundings rule +));
];

-) instead of “Status Line Utilities” in “Printing.i6t”.

This is the print player’s surroundings rule:
calculate visibility ceiling at low level;
if in darkness begin;
carry out the printing the name of a dark room activity;
otherwise if the visibility ceiling calculated provides the property articled and the visibility ceiling calculated is articled;
say the visibility ceiling calculated in title case;
otherwise if the visibility ceiling calculated provides the property articled and the visibility ceiling calculated is unarticled;
say visibility ceiling calculated in title case;
otherwise;
say “(ERROR - [the visibility ceiling calculated in upper case])”;
end if.

Last for printing the name of a dark room: say “Darkness”.

A room is either articled or unarticled. A room is usually unarticled. A container is either articled or unarticled. A container is usually unarticled. An enterable container is usually articled.

Carry out looking (this is the new room description heading rule):
say bold type;
if in darkness begin;
carry out the printing the name of a dark room activity;
otherwise if the visibility ceiling provides the property articled and the visibility ceiling is articled;
say the visibility ceiling in title case;
otherwise if the visibility ceiling provides the property articled and the visibility ceiling is unarticled;
say visibility ceiling in title case;
otherwise;
say “(ERROR - [the visibility ceiling in upper case])”;
end if;
let the current item be the holder of the player;
while the current item is not the visibility ceiling begin;
if the current item is a supporter (called the chosen supporter) begin;
say " (on [the chosen supporter])“;
otherwise if the current item is a container (called the chosen container);
say " (in [the chosen container])”;
otherwise;
say “(ERROR - [the current item in upper case])”;
end if;
let the current item be the not-counting-parts holder of the current item;
end while;
say roman type;
say line break;
say run paragraph on with special look spacing.

The new room description heading rule is listed instead of the room description heading rule in the carry out looking rulebook.

The Testing Room is A Room. A big brown box is an enterable openable lit container in the testing room.

Test me with “enter box / close box / l”.[/code]

This is the most elegant solution I can think of since it uses an I7 rule to do all of the work. It also allows article flexibility, so you can choose whether you want “the” to show up or not. You’ll need the small case conversion extension for it to work.
Hope this helps.
Case Conversion.i7x (2.65 KB)

I didn’t know about the UNDO exception. huh.

Well, Inform 6 has a handy directive called REPLACE that will ignore the first time it sees a function of that name. Put that together with your intuition about SL_Location and your answer becomes a mere:


Include (-
Replace SL_Location;
-) before "Printing.i6t".

Include (-
[ SL_Location; 
	if (not_yet_in_play) return; 
	if (location == thedark) { 
		BeginActivity(PRINTING_NAME_OF_DARK_ROOM_ACT); 
		if (ForActivity(PRINTING_NAME_OF_DARK_ROOM_ACT) == false) 
			L__M(##Miscellany, 71); 
		EndActivity(PRINTING_NAME_OF_DARK_ROOM_ACT); 
	} else { 
		FindVisibilityLevels(); 
		if (visibility_ceiling == location) 
			CarryOutActivity((+ the printing the name activity +), location); 
		else 
			CarryOutActivity((+ the printing the name activity +), visibility_ceiling);
	} 
]; 
-) after "Printing.i6t".

…and then amend your name-printing rule with or the reading a command activity is going on. (I modified the I6 already to simply call out to Printing The Name… which it should probably do in the first place.)

Proper names are always capitalized. Why would that unnerve me?

It’s also why I suggest defining room names in lower-case (or mixed case) and then title-casing them as needed, rather that going the other way around. For a room called “the alley behind the Wong Auditorium”, Inform’s [in title case] phrase will correctly change it for use in headings, but to go the other way – creating “The Alley Behind the Wong Auditorium” and lower-casing it – means you can’t do it automatically.

Well, the sane method would probably be to use the “Undo Output Control by Erik Temple” extension with a “report undoing an action” rule, but where’s the fun in that! :smiley:

Thanks for the help, Melvin and Ron!

I’m feeling pretty silly now, because it turns out that it isn’t necessary to use any I6 code to fix this. The I6 code that prints the room name after an undo actually already calls the printing the name of activity (which I should have realised, because otherwise it wouldn’t be using the lower case name). Which means that I can just alter the printing the name of a room rule to check if the reading a command activity is going on, without any messing about. Like so:

[code]A room has some text called the lower case name.
The lower case name of a room is usually “the [printed name of the item described in lower case]”.
[Some rooms, e.g. the Sunday School room, might need some upper case letters in their lower case name, or might need a more complicated lower case name, or something. We can fix them by giving them the appropriate lower case name.]

Rule for printing the name of a room (called the place):
if the constructing the status line activity is going on or the current action is looking or the reading a command activity is going on: [the reading a command activity is what runs the UNDO code]
say “[printed name of the place]”;
otherwise:
say “[lower case name of the place]”.[/code]

It just never occurred to me that I could check for the reading a command activity, until Ron pointed it. So thanks again!

That does indeed work, but only for rooms. It won’t deal with the case where the player is in a lit closed opaque container where the visibility ceiling is the container rather than the room. This is where “the location” and “the player’s surroundings” vary with the former giving the room and the latter giving the visibility ceiling. However, if this doesn’t occur, then all should be well.