Streamlining repetitive actions

I’m trying to build an achievements/quests log in Inform 7 using tables, but am having to write nearly identical code once each goal has been achieved.

How would I simplify everything but the first two lines of this:

After taking the toothpick for the first time: choose the row with a goal of "toothpick" in the Table of Achievements; now the flag entry is 1; increase the points by bonus entry; say "[b][if quest entry is 1]Quest complete[otherwise]Achievement unlocked[end if]:[/b] [achievement entry] [i]([bonus entry] points)[/i][/n]"; continue the action.

so that I can just call it whenever I’m writing some new achievement code?

You can create a phrase and call it up every time you need those batch of lines processed.

If you don’t know how to create a phrase, it’s easy. For general purposes, it just takes something like this:

To calculate hats:
	some code here;
	even more code;
	last bit of code.

And now every time you want to process this code, you just slip “calculate hats” wherever it needs to go.

Your achievement stuff is just a little more complicated, because it won’t do to just have a simple phrase like the one above. You’ll want a phrase that can accept input data. So here’s the new code:

To show achievement (hooray - a text):
	choose the row with a goal of hooray in the Table of Achievements;
	now flag entry is 1;
	increase bonus points by bonus entry;
	say "[b][if quest entry is 1]Quest complete[otherwise]Achievement unlocked[end if]:[/b] [achievement entry] [i]([bonus entry] points)[/i][/n]".

As you can see, (hooray - a text) is what instructs this phrase to accept the text as input.

There should be minimal code repetition now. The only thing you would really have to repeat is the “show achievement” line for every particular achievement-causing event:

After taking toothpick for the first time: show achievement "toothpick"; continue the action.

There are other ways to do this, too. Inform is pretty flexible in how you can approach many situations.

You might like to have a look at Kerkerkruip’s achievement system too: … 20Data.i7x

Amazing. Thanks abjectadjective, it works perfectly. Is there any reason the final ‘continue the action’ has to be called in the initial ‘After taking the toothpick’ code? I tried tucking it into the ‘show achievement’ code, but your way was indeed the only way that worked.

Dannii, thanks for the link. I’ve been trying to follow Kerkerkruip and ATTACK but get pretty lost whenever I try to wade my own way through, but the achievement section looks really useful.

“Continue the action” must be in the rule that requires it, but you don’t have to use after rules. You can change it to Carry out or Report where the action continues by default. (After rules are most useful when you want to replace the default output.)

I second the suggestion of using report, at least when it comes to achievements caused by simple events like picking an item up.

Try this:

Report taking toothpick for the first time: show achievement "toothpick".

This way, you won’t have to use “continue the action” at all, because report rules will not interrupt the flow of action processing in the way that “after” does. You also gain the ability to switch around the achievement and “taken” messages by using “Last Report” if you desire.

You should be careful when dealing with after and report rules for the first time because if taking the toothpick for the first time ends in failure, this rule will never fire. Try this instead.

Report taking the unhandled toothpick: show achievement "toothpick".

Hope this helps.

I suggest that you track in the table whether the achevement has already been awarded and have the “to show achievement” phrase do nothing if so. Then you can use the phrase whenever and don’t have to handle it in the rules that call it.

(Perhaps that’s what the flag entry is for?)

You can use the handled property instead of creating the flag entry here. It’s a built in property in Inform 7 testing whether the player has ever held something. It changes to “handled” when the player successfully takes the item in question for the first time.

Sure, but that’s only if achievements are earned only from picking up stuff. A flag would be a more general solution.

This is great, I was trying to do something similar. If you wanted to have different tables -

choose the row with a goal of "toothpick" in the Table of Achievements;

How would you send that to this routine?

Tables formally have the kind “table name”, so that’s the syntax you need to use tables as values of a phrase parameter:

To show achievement (hooray - a text) from (tabula - a table name):

A bit off topic maybe, but if you wanted to pass a row of a table to a rule or action, what would be the best way to do it? In an ordinary case I guess you can pass the table name and the row number (as a number), but what if you’ve just chosen a row – is there anyway to get back the number of the row that you’ve just chosen?

There’s a global Inform 6 variable that holds the number of the chosen row: ct_1. You could access it in Inform 7 in the usual way: The current table row is a number that varies. The current table row variable translates into I6 as "ct_1". It seems that this variable can lose its information pretty quickly, however; so you should probably always store its value in some independent variable for future use.