Two questions: choosing rows and empty commands

Question 1:

I7 has a myriad way of choosing rows. Clearly, there’s some sort of hidden variable that tracks what row is currently being worked on. But I’d like to make my own. I’m trying to make a table of status effects that looks something like this:

Table of Status Effects effect person effected duration drowsy Bob 3 drowsy Bill 4 foo Bob 2 bar Bill 2 unwashed Bob 10 unwashed Bill 8

I’d like it so that I7 chooses a row that has the appropriate status effect and person at the same time.

Question 2:

I’m trying to make it so that, when the player is asked for their name, if they type in nothing they are supplied with a default name, say, “Joey”. I tried doing it with something like this (not tested):

After reading a command when naming mode is true: if the player's command is "": now the player's name is "Joey"; reject the player's command; else: now the player's name is the player's command; reject the player's command.

Unfortunately, I can’t get I7 to accept empty texts like “”. Is there any way to do this?

Unfortunately, most of the behavior for empty commands is coded into the parser in a way that can’t easily be exposed to I7. Looking at Ron’s Original Parser extension, it looks as if the code that checks for an empty command, and gives the I beg your pardon parser error if the command is empty, is part of a “For reading the command” rule, meaning that things cut off before you get to an “After reading the command” rule.

One thing you could probably do is have your behavior run from a “Rule for printing a parser error when the latest parser error is the I beg your pardon error” (haven’t double-checked the syntax there). There can be weird effects from running code that changes the game state from parser errors – I think they don’t run the advance time rules and it’s hard to end the game in the middle of one – but for the behavior you describe it shouldn’t be so bad (since you’re rejecting the command anyway). There’s also some I6 code that Victor Gijsbers (I think; might have been Juhana Leinonen) wrote for me to redirect the empty command behavior:

[spoiler][code]Section Intercepting Blank Commands

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:
	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
	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;
	!	if (ForActivity(PRINTING_A_PARSER_ERROR_ACT) == false) L__M(##Miscellany,10);
	!	@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;
		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;
		! Work out the position in the buffer of the word to be corrected:
		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.
			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

	if ((w == UNDO1__WD or UNDO2__WD or UNDO3__WD) && (nw==1)) {
	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) {
		SL_Location(); print "^";
		! print (name) location, "^";
		L__M(##Miscellany, 13);
	return nw;

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

After reading a command (this is the blank line = xyzzy rule):
let T be indexed text;
now T is the player’s command;
if T is “”, change the text of the player’s command to “xyzzy”.[/code][/spoiler]

which will let you write an “after reading the command” rule that works when the player’s command is “”. (But when the new I7 comes out, you will probably need a new parser hack.) I think this allows all blank commands through; if you do this and you only want to allow blank commands some of the time, then you would have to find a way to have this rule invoke the I beg your pardon error when naming mode wasn’t true.

As for your other question, I fear there is also no easy way to do this. The only thing I can think of to do is repeat through the table, checking whether each row fits your specification, and when you find that row choose it and break. (But someone else might have a better idea.)

I was in the middle of typing when mattw said everything I was going to say…

Any solution will boil down to this, anyhow.

Sorry I haven’t responded, I’ve been busy.

Thank you for the code, I’ll try it when I next have the chance to work on my game. The thing about the not being able to choose rows is disappointing, but not unexpected.

Anyways, thanks a bunch!