Rule is compiling but is ignored (Solved)

EDIT 2:

I have fixed the issue in a way I thought I already had but clearly I hadn’t tried the correct combination.

Every turn:
if the the current hit points of the player > the maximum hit points of the player:
say “you’re now at full health”;
now the current hit points of the player are the maximum hit points of the player.

This works perfectly and makes me think that the after rule is not designed for what I was trying to achieve.


Continuing on from the battle system I’ve been working on I’ve hit another small snag thats bothering me immensley. My main goal is to have basic working versions of all the features I wish to include before redrafting the entire code from scratch. I have successfully got a working health potion model that I need tweaked so that it cannot increase the health of the player above their maximum hit points.

I was hoping ideally to set a limit to hit points so that the maximum hit points could simply never be exceeded but the only thing that would be affected by that rule would be health potions so I have decided to tackle this issue there instead (I may want a buff potion to increase beyond max health anyway). In a nutshell I simply want any HP added over 100/Maximum hit points to be overridden and simply make the player’s current hit points 100 or equal to their maximum hit points.

I’ve tried many, many variations but I have included what I think is the most straight forward version in bold. This is compiling with no errors but simply doesn’t do anything. Perhaps its an issues with some of the definitions I’ve included. I have tried to write a few definitions as to make writing rules a bit simplier but the defintion ‘overhealed’ may be redundant. Perhaps the definitions of current and maximum hit points need work instead? (I have based these initial basic mechanics from the lanista 2 example for reference).

CODE:

Section 1 - Hit Points

A person has a number called maximum hit points.
A person has a number called current hit points.

The maximum hit points of the player is 100.

When play begins:
repeat with victim running through people:
now the current hit points of the victim is the maximum hit points of the victim.

Definition: a person is dead if his current hit points are less than 0.
Definition: a person is alive if they are not dead.
Definition: a person is injured if his current hit points are less than his maximum hit points.
Definition: a person is uninjured if his current hit points are his maximum hit points.
Definition: a person is overhealed if his current hit points are at least his maximum hit points.

Section 4 - Health Potions

A potion is a kind of thing.

A Health Potion is a kind of potion.

Instead of drinking a Health Potion:
increase the current hit points of the player by 10;
Let RHP be a random Health Potion carried by the player;
Remove RHP from play;
say “You drink the potion increasing your health by 10!” instead.

Before drinking a Health Potion:
if the player is not injured:
say “you’re already at full health”;
stop the action.

After drinking a Health Potion:
if the player is not injured:
say “you’re now at full health”;
now the current hit points of the player are 100.

END CODE.

Again, any help is much appreciated and while this is a simple issue, it’s bothering me a lot as it seems like it should be very straightforward to solve.

Cheers!

EDIT:

I should note I also have tried:

After drinking a Health Potion:
if the player is overhealed:
say “you’re now at full health”;
now the current hit points of the player are 100.

Which also compiles but does nothing.
The majority of variations I tried simply didnt compile so I haven’t included them as examples but I tried countless versions of what I could imagine the above code to be in different words.

and lastly the most recent bit of code I wrote which compiled fine and is probably the most flexible within the gameworld:

After drinking a Health Potion:
if the the current hit points of the player > the maximum hit points of the player:
say “you’re now at full health”;
now the current hit points of the player are the maximum hit points of the player.

This also had no effect.

Perhaps I’m interpreting the after rule incorrectly but when reading the example 7.5 “If an action has survived all the rules in its way, and has actually succeeded, then we need to give the player a response which acknowledges this.”

My interpretation is that the action has survived the rule therefore the after rule can be used and should simply transform the hit points to that instructed.

What’s going on is that “instead of” rules preempt the regular action processing rules - they tell Inform that you want it to run that code instead of the regular code for how the action should be handled. Instead rules get checked after before rules do (see the chart in this bit of the docs), so that one works, but none of your after rules are actually firing.

This is why it’s generally a good idea not to use instead rules unless you’re really sure there’s a special-case reason to use one - most of the time you’ll want to use carry out rules instead.

This is an incredibly common mistake to make when learning inform, by the way - I way overused instead rules in my first game, since it was hard to wrap my head around the very complex way regular actions are processed, and instead rules seem like a handy shortcut. But they can really bite you in the butt, per this example and others in this thread: The perils of INSTEAD

BTW I’m not sure whether you’ve come across the RULES testing command yet? If you type that while playing (in the ide or in a game file that’s not compiled for release) you’ll get a printout of the name of every rule that’s running right before it fires. So that’s really helpful as a diagnostic tool, since in this case for example it would have shown you the after rules aren’t ever firing.

(I should say, your every turn hack will work, but it’s also not a best practice; every turn rules are more computationally expensive which usually isn’t a big deal but could matter in a mechanically complex game; more importantly, offloading ordinary parts of action processing to them risks confusing you later, and also runs the risk of weird timing bugs being introduced because it’s not guaranteed that this every turn rule would always fire right after the potion drinking is resolved).

Hope this helps!

3 Likes

Thanks again for your help, it’s very useful as usual.

This will be something I think I’ll redraft on the code I’ve already written to avoid edge cases. I had actually been reading about this very thing but some of the advice I had read online was to simply write whatever you were comfortable and seeing as though I had already been using instead I just rolled with it.

I will go though and try using carry out and then replace every turn with after and see if it works the way I hope.

It is a bit confusing when you start out and before, instead, check and carry out can all work interchangeablely for so many things but I think that now I’m trying to build a world model that had a lot of scope for customisation and relies on generalised rules, I really need to use the appropriate rules from now on to avoid further silly issues like this.

Cheers

2 Likes

It seems like it, and sometimes you can use the phases interchangeably without problems…you can print a message to the player if you really want to during CARRY OUT instead of REPORT, but each phase has unique reason to happen when it does.

It’s common for new authors to think INSTEAD is a one-size-fits-all solve for everything. Instead is usually for when you don’t want something to happen, or you want to blanket pass an action to a different action.

Instead of jumping when the location is Balancing on the Tightrope:
    say "That would be *really* unwise in your precarious situation."
Instead of dropping the feather:
    try casting featherdrop instead.

It’s common to end a check rule with an instead, and you can have multiple check rules that will all work together and run until at least one fails and stops the action:

Check casting a spell:
    if intelligence is less than 10:
        say "You haven't yet learned how to cast spells." instead.
Check casting a spell:
    if the player does not carry the magic wand:
        say "You will need a wand for that." instead.

CHECK is testing “can the player do this? If they can’t for this reason, do this…”
CARRY OUT is when you know the player can do something and the action will happen, and you’re changing world-state (usually) silently behind the scenes.
REPORT is the common description of an action’s outcome for the player.
AFTER will normally override a standard Report rule for a unique message, or so you can trigger something else to happen.

After jumping when the location is Bouncy Castle:
    say "Boing! Wow, the floor is springy!";
    reduce air pressure by 10;
    if air pressure is less than 5:
        say "Whoa, the castle deflated! There must be a leak.";
        now the player is in Bouncy Castle Ruins.

You can also end and After rule with “continue the action” to have it also run the normal report rule.

After taking the sticky beehive:
    say "Eew, it's sticky. You have honey on your hands.";
    continue the action.

This will run if the player takes the beehive saying “Eew it’s sticky…” and then report “Taken.” as normal.

4 Likes

These are really concise examples and well explained.

I think intuitively I have wanted to use check, before etc when they felt like the right time to use them (because it would make more sense), however due to simply habit I think I continued to use instead. I’m glad that I’ve been able to break this habit early on when it’s easy to change.

Thanks for the help. Tonight I will go through the source code that I’ve already written and begin changing and report back any issues I may face.

Cheers!

Update:

I was able to go through and adjust all my existing code to be in line with best practice and used carry out, check etc which then allowed before and after rules work as expected.

I feel a bit stupid as the majority of the reading I have done of the inform 7 documentation has been on my phone and unfortunately as a result I have missed some very obvious sub sections due to the fact that on my tiny phone screen they are extremely tiny and I have simply missed more than I should have.

Namely this very informative section:
http://inform7.com/book/WI_12_21.html

Since exploring more of these sub sections it has made problem solving much easier and over just a few evenings I have found my ability to imagine an outcome and then figure out how to write the code has exponentially improved. Much of this is a mindset and learning the way you need to think about problem solving but I must say it is very rewarding and satisfying to improve at such a rapid rate.

I have also begun retroactively rewriting code so that it can serve a general purpose and then creating more kinds of things, rooms, people etc as to allow for rules to be applied in a much more general and less specific way.

I just want to thank everyone who has been assisting me since I joined this forum, it’s been a very welcoming and encouraging experience and unlike most forums/discord servers which often treat newcomers with distain and assume that everyone understands the most basic and things when often the initial barrier to entry is the hardest part to overcome.

Cheers!

2 Likes