Refer to specific door as part of unsuccessful attempt?

I’m writing a game in which the player can give a list of explicit motion instructions to a robot NPC, and the robot tries to do them (instructions stored in a table internally).

The instructions are carried out by lines like “try asking the robot going north”.

What I’m trying to figure out how to do is to cause a specific change to the obstructing door when the reason for not being able to go is because there is a closed door. I want to check the material property I’ve added to the door–if it is a steel door, nothing happens. If it is a wooden door, I want the door to break (by making it open and not openable).

Unsuccessful attempt by the robot going:
if the reason the action failed is the can’t go through closed doors rule:
if the door is wooden:
now the door is open;
now the door is not openable;

I thought that “the door” here might be inferred to be referring to the door which is obstructing the path forward, but it doesn’t compile, it says:

So the problem seems to be that it isn’t able to figure out what door “the door” is referring to in the two “now” lines. But then how is it able to compile “if the door is wooden”?

Is there a good way to refer to the specific door here so I can make these changes?

It interprets this as “if a door is wooden”. That test makes sense with an indefinite description, whereas “Now a door is open” is too vague. But obviously neither is what you want.

I think you want “the door gone through”, although I haven’t tested it.

ON POSTING: Preempted by zarf, but I did test it and it should work.

Currently Inform treats “the door” as if it were “a door,” so “if the door is wooden” gets parsed as “if a door is wooden,” but “now the door is open” won’t work because Inform treats it as “now a door is open” and doesn’t know which door to treat. (This I believe is going to be changed in the next release, so that “the door” always fails to compile.)

In this case, the going action has what’s called an action variable (I think) called the “door gone through,” which is the door that the actor tried to go through if the actor tried to go through a door, and nothing otherwise. (See the “standard set going variables” rule in the Standard Rules.) So you could change “the door” to “the door gone through” in your code – most of the time this wouldn’t be safe, since the door gone through might be nothing and that would lead to run-time errors, but in your case there’s no way for the reason the action failed to be the can’t go through closed doors rule unless there actually is a door gone through, so you should be OK.

Another approach you could take is to replace the can’t go through closed doors rule with one that executes your code.

BTW it would be friendly to include a message telling the player that the robot broke the door, or it will be very confusing. Also you might want to elevate the condition to the rule header (“Unsuccessful attempt by the robot going when the reason the action failed is the can’t go through closed doors rule:”), because I believe as written your rule will preempt any other unsuccessful attempt rules from printing text when the robot is going even when the problem isn’t a closed door.

And you should know that unsuccessful attempt rules only fire when the robot tries the action in response to a request; if the instructions are getting stored in a table and then you’re having the robot try them, I think the unsuccessful attempt rules probably won’t wind up firing. (Well, if you’re using Editable Stored Actions you could convert the action back into a request just before you have the robot try it, but that would be a horrible hack!) EDIT: On further review, if you just read the current action into the table when the player commands it, when you read it back out it’ll still count as a request and so the unsuccessful attempt rules may fire, but writing the persuasion rules may be tricky. Anyway, it’s something to be aware of.

Indeed, that’s exactly what I was looking for, works like a charm. I figured there had to be a grammar that would give me what I needed but I couldn’t figure out where to look in the manual, and my Google-Fu failed me. Thanks!

I do actually have code in that block for printing text to describe the breaking of the wooden door, and the non-breaking of a steel door or a wall. But for the purposes of asking this question I figured I’d pare it back to the bare minimum code necessary to describe the problem. The “ran into wall” printing code is the catchall–should probably look for a list of reasons that trying going can fail to see if I need other ones, but I’m not overly concerned with that right now–trying to get the core puzzles into a functional state and expand all the text descriptions for there.

The instructions for the robot are stored as a punchcard of the format:
GoNorth GoEast GoSouth GoWest GoUp GoDown
false true false false false false

Every turn when the robot is not inactive, it will try to read the next line and try to move according to the instructions by lines like “try asking robot to try going north;” To make this work for the short term, I added the line “Persuasion rule for asking robot to try going: persuasion succeeds.” Before the final version I need to modify that–I don’t want the robot to respond in any way to spoken instructions from the player–only instructions on the punchcard are to be obeyed. So I’ll need to tweak the persuasion rules to make that possible. But as you said, the unsuccessful attempt rule won’t fire unless it’s an “asking” action so I had to involve the player in the action even though that doesn’t really make a lot of sense and often the player won’t be in the room at the time the action is carried out.

Anyway, thanks a lot guys!

Don’t use “try asking” for this, just “try the robot going north” if you don’t want persuasion to be involved.

If the player Isn’t in the room, try asking will fail.

You could circumvent this with a scope rule, but it’s probably better just to rewrite your try statements.

That was my first try, but I wanted to add specific “Unsuccessful attempt” response to make the door break, and that functionality didn’t fire. The manual says that the “Unsuccessful attempt” only fires if the player is doing the asking, so this is as designed, apparently. It makes no sense to me, but I’m assuming there was some specific reason for this, and I’m just interested in making something that does what I want–“try asking” does the trick but “try robot going” does not.

I found this information in section 12.5 of the manual:

And that matches the behavior I observed in practice so the manual appears to be accurate here.

Actually, the try asking does not fail when the player isn’t in the room. If I give the robot instructions to leave the room and come back, it does even if I don’t follow it. I haven’t modified the scope rules. Maybe it SHOULDN’T work, maybe it’s a bug in the language. I don’t know–I’m just starting with the language and am still feeling my way around the boundaries. But it DOES work.

Note that the “try asking” for the punchcard is only in the code, not coming from the command line. If I typed “robot, go north” to the command line when the robot is not in the room that would fail as expected.

The code from Faithful Companion that I linked above might actually be helpful here in some ways. [It contains a mechanical spoiler for the game so play it first! /huckster] I encountered the same issue with unsuccessful attempt rules only working on persuasion, so I set a flag just before the NPC was due to act, made success of persuasion contingent on that flag, and turned the flag off again immediately after.

From the other stuff I had to do in there, it looked to me like the way requests work internally is that the request itself isn’t treated as a stored action, rather the requested action is in the guts of the stored action and there’s a flag to show that it’s a request. That is, if you have “try asking the robot to try going north,” the stored action that gets executed is the robot going north, with a flag on it to show that it’s a request. (It’s just like “try the robot going north” except for that flag.) So you don’t have to worry about the robot being in scope.

“robot, go north” fails when the robot is out of scope because the parser doesn’t understand “robot.” It’s much like “take key” fails at the parsing stage when the key is not visible, but if the key is not visible or reachable a “try taking the key” executed from inside the code will fail at the basic accessibility stage instead.

You’re right, unsuccessful attempt is only run when persuasion is used. If you want it to fire whenever the robot tries to go through a door use a check rule instead, perhaps replacing the normal rule about going through closed doors.

That’s pretty much what I had in mind, good to know that that will work. Thanks for the example. :slight_smile:

Ah, interesting. That makes some sense to me from a programmer’s perspective (I’m new to Inform but not new to programming), but seems an unintuitive element in a language that strives for intuitiveness.

I am curious:
Does anyone know if there’s a reason why Unsuccessful Attempt code isn’t executed unless the attempt is the result of a request? That, too, seems unintuitive, as there might be very good reasons why you’d want to handle failed attempts at NPC’s spontaneous actions.

My interpretation is that unsuccessful attempt should be used for the NPC to explain why they can’t do something (which is why it lets you see why the action failed), whereas instead should be used to prevent an action from working and carry out/report should be used to change the standard effect.

If carry out/report were used, wouldn’t that mean I’d have to manually handle all the reasons why the robot couldn’t move? …I guess that wouldn’t be as onerous as it seemed at first thought–In this environment anyway, I think the only two reasons the robot can’t successfully move are that there is no exit in that direction, or there is a closed door in that direction. But it still seems like needing to reinvent the wheel (albeit a small easily understood wheel) to do that.

Not necessarily. Just write a “carry out the robot opening a wooden door” rule and a “report the robot opening a wooden door” rule and they’ll be run first because of their specificity.

Another thing you might do is rewrite the check rules that you’re invoking to take care of the cases you want. So if you only want your unsuccessful attempt rule to fire when the reason the action failed is the can’t go through closed doors rule, you could just rewrite the can’t go through closed doors to handle the case where the robot is trying to go through a closed wooden door. (You can use “check” rules if you want to stop the action from happening with special messages or other effects; “carry out” and “report” rules will only fire if the action has successfully passed the “check” stage. In this case it’d be a bit complicated – the can’t go through closed doors rule will have the robot try to open the door, and then if there’s a rule that prevents the robot from opening the door at the check stage I think it’d keep the carry out and report rules from running.)

Oh hey, do you want the robot to try opening closed doors? Because if you don’t you should definitely rewrite the can’t go through closed doors rule – that’s where implicit opens happen. You might also want to be aware of the bugs concerning NPCs and doors, though I’m not sure that would affect you in this case.

For the robot going a way that doesn’t exist, you could use an “Instead of the robot going nowhere” rule which could preempt the check rules and print a message. Or you could modify the rule that keeps the robot from going nowhere.

By the way, the reasons I used unsuccessful attempt rules in Faithful Companion were (a) I wanted to be able to write a generic catch-all message for the NPC failing to do anything, which would’ve made it very onerous to use check rules as I would’ve had to do one for each action, and (b) I had to code the original version in three hours and didn’t have time to think of a better way to do it.

Good point. I hadn’t run into a problem with the robot trying to open closed doors and I think that the reason for that is that the door in question is locked and has no key, so the robot would fail in any case.

Anyway, all very interesting stuff. I think I’ll leave it the way it is because it works as I intend it to. Seeing other ways of doing it are informative and useful for me trying to expand my knowledge of the language. Thanks!