Which parser?

If you’re willing to use I7 version 6M62 (which is probably still used by the majority of people), you can include Emily Short’s “Simple Graphical Window” extension to get scaled images.

2 Likes

It does make sense!

But now I’ve found a new problem. I’m finding the Inform documentation really hard to navigate, so I’m sure all the information is in there but I just can’t find it.

At the moment when I swallow something (i.e. ‘the art’) it returns:

(first taking the art)
You put the art into your mouth.

But I want it to say something else. I want to write something like:

When inserting the art into the mouth, say "Something new!" instead of "You put the art into your mouth."

But of course that’s not working. I’ve found how to completely change the behaviour of ‘insert into’, but I don’t want to do that, I just want to change the descriptor text for what happens when I do it with a particular noun.

(I’ve found how to add my “Something new!” description as well as “You put [the noun] into your mouth.” but I can’t find out to do it instead of it.)

I found you saying this on a thread I found yesterday :slight_smile: What would I be losing if I used v.6M62 instead? (I know I’m currently using v.10.something…)

After inserting a sweet thing into your mouth: say "Mm! Delicious!".
Report eating the gooey caramel: say "Now your hands are sticky.".

After overrides all report messages; Report will add that message to other standard reporting.

4 Likes

I’m also a fan of completely defining new behavior with:

Instead of inserting a sweet thing into your mouth:
    say "How delectable.";
    now the noun is nowhere;

(You have to include the second line because ‘instead’ completely gets rid of usual behavior’. Or you could do ‘now the noun is in your mouth’).

Sometimes Inform has weird rules printing things or blocking things, so you can ninja your way even earlier into the action with ‘before’:

Before inserting a sweet thing into your mouth:
   say "Hmmm, scrumptious.";
   now the noun is in your mouth instead;

If you don’t type ‘instead’, it just prints the hmm scrumptious line and keeps going. Adding ‘instead’ completely stops everything else.

In general, you use ‘Before, instead, after’ to change what happens before you do something, during it, or after; when making your own actions, you type Check, Carry out, and Report, which do the same things but are ‘weaker’, and can be overriden later in special cases by before, instead, and after.

3 Likes

Easiest way to do that is with a new report rule, and then telling Inform not to run any others by stopping the action:


report inserting something into your mouth:
	say "You lick [the noun] to give it a good coating of saliva, then wriggle it past your lips.";
	stop the action.

The docs are long and not really worth reading in full before diving in IMO, but the bits about rules and rule books are worth an early read through.

Another helpful tip is that you can type RULES when testing your game, which will show you which rules are firing and outputting text. Doing that, you’d see that it’s the “standard report inserting rule” that you don’t want, so you could knock it out like so if you didn’t want to use the “stop the action” approach:

the standard report inserting rule does nothing when the second noun is the mouth.

EDIT: lots of good ideas from others! On reflection I think the After approach is better than doing a report and stop the action; I’m just leery of after rules since I often forget they preempt the report rules so it’s easier for me to do things manually!

2 Likes

Maybe not “weaker” but “subject to standard parsing and being overridden and affected by other important rules as you’d expect” - if you’re using INSTEAD, parser goes hands-off and lets the author drive the world model for a moment.

INSTEAD is like an executive order from the author. You want to use it when you’re not interested in anything else that could possibly happen.

Instead of doing anything to the nuclear reactor: say "You know better. You've seen all those movies."

Most new authors try to use INSTEAD as a monkey-wrench for everything and get in trouble:

Instead of taking the shiny rock:
    say "Wow it's pretty!";
    increase the score by 1;
    now the player carries the rock.

Cool and works, but since you’ve veto’d all other rules in the game, the player can take the rock even if it starts inside a locked transparent container, and can take it multiple times because the parser isn’t allowed to run all the accessibility and “does the player already have this thing?” rules.

4 Likes

Oh god dammit, I tried ‘before’ and ‘while’ (is while even a rule? I don’t think it’s even a rule…) and a few things with insteads, but just assumed ‘after’ wouldn’t work (you know, because it comes after the other stuff). Thanks!

I think fiddling with TADS yesterday scared me a little because there was so much going on under the hood that the idea of completely rewriting a rule was very intimidating. I had assumed that there was more going on with ‘insert into’ than “now the noun is in your mouth” so I hadn’t wanted to touch it.

Oh that’s a very useful way of thinking about it. I hadn’t mentally connected before with check, instead with carry out and after with report. I guess it comes back to not reallising that I could change reports with ‘after’, because I hadn’t got that order of operations in my head (thought ‘after’ would be too late to change a ‘report’, but makes sense now that I think about the natural language meaning of the words).

Okay that’s incredibly useful, both the reading advice and the RULES tip.

Yeah, I’ve already found it’s power. A little too much power methinks…

It seems you are pre-empting me faster than I can write! I think this kind of thing is also why I’m afraid of defining new behaviour.

2 Likes

It’s better to learn and use CHECK/CARRY OUT/REPORT for new actions like all actions do, so they’ll play nicely with each other. It takes a bit to grok.

My initial stumbling block with Inform 7 was “how does it know what order to run all the rules in?” - me not understanding that the compile process sorts all your rules into rulebooks regardless of source-text order and the parser knows to run rulebooks in the correct order.

2 Likes

The new version was mainly about big internal changes, rewriting and restructuring lots of the code-base, but it did not lead to many changes for game authors, regarding new syntax or big new features or functionality. One could say the changes are laying the groundwork for new functionality in the future.

There have been quite a lot of bugfixes, but then again, many many games have been produced in 6M62 without running into those bugs.

So, if it’s for a short project now, and you’d like to have the scaled graphics, I think I’d recommend using the older version for the moment. When you switch to the new version later, you’ll be able to transfer practically all of your knowledge and code seamlessly. (Except for some extensions which might have stopped working and haven’t been updated.)

But other people might have other perspectives; I haven’t delved as deeply into the new version as @Zed has, for example.

1 Like

Oh, Lordy. Because I didn’t read and grok the rule books stuff until I was a reasonable way into building my first game, the only thing I really understood was that if there are multiples of the same kind of rule that apply, the one with more conditions wins - which makes sense, you’d want to go from the specific to the general. But then when I had a bunch of Every Turn rules where the order mattered, I started stacking nonsense conditions that would always be true (“if the player is in the location / the horse is in the stable”) just to manipulate the order!

This was, uh, not my finest hour.

2 Likes

I also ran into trouble with the fact that “Every Turn” rules kind of all need to be in one rule because they only have one chance to run, and if you write multiple “Every Turn” rules they’ll override each other since only the first one runs (or the most specific one runs,) first being the last one in source text order since the compiler reads your text and throws everything onto a stack of them and then it’ll still pick one that’s more specific to use as THE Every Turn rule.

(Don’t let this put you off Inform 7, it all does make sense in context!)

2 Likes

Er, I’m pretty sure by default all relevant every turn rules should fire, unless you’ve got a stop the action or instead buried in there (which one often does!)

(And yes, sorry, please don’t let us tangenting scare you off! Though deciding TADS doesn’t seem so bad is of course always a completely reasonable option :))

4 Likes

I talked about choosing v10 or 9.3/6M62 here:

One significant thing omitted there: installing extensions through the app apparently doesn’t work in the Linux or Mac IDEs in v10; one would have to do it manually.

There are a lot of extensions not yet ported to 10.1, especially those involving doing anything fancy with the UI like including hyperlinks.

But for a brand new user kicking the tires, I wouldn’t hesitate to say: go with the latest version.

Edited to add: oops, but now that I look at more of the thread and see that you’ve stressed the importance of handling images, maybe you should stick with 9.3/6M62.

3 Likes

For the record, here’s my 10-minute approach:

myMouth: Container, Fixture 'a mouth' @me
  "It's your mouth.  "

  checkInsert(obj) {
    if (obj != pebble)
      "You can't fit <<obj.theName>> into your mouth.  ";
  }
;

pebble: Thing 'a pebble' @livingRoom
  "It's a pebble.  "

  isSpittable = true
;

VerbRule(Spit) ('spit') singleDobj: VerbProduction
  action = Spit
  verbPhrase = 'spit/spitting (what)'
  missingQ = 'what do you want to spit'
;

DefineTAction(Spit)
;

modify Thing
  isSpittable = nil
  cannotSpitMsg = 'You cannot spit that.  '

  dobjFor(Spit) {
    preCond = [ touchObj ]
    verify() {
      if (!isSpittable)
        illogical(cannotSpitMsg);
    }
    check() {
      if (!gDobj.isIn(myMouth))
        "You have to put it in your mouth to spit it.  ";
    }
    action() {
      "You spit out <<gDobj.theName>>.  ";
      gDobj.moveInto(me.getOutermostRoom);
    }
  }
;

Transcript:

I can see a pebble here.

>spit pebble
You have to put it in your mouth to spit it. 

>put pebble in mouth
(first taking the pebble)
I put the pebble in the mouth. 

>spit pebble
You spit out the pebble. 

My advice: Don’t write your own preconditions (preCond). Use the existing ones and enforce specific behaviors via verify() and check(). Much easier. (Plus, existing preconditions will perform implicit actions for you, such as above where putting the pebble in my mouth implies picking it up.)

There’s also more fiddly work because the generic library isn’t used to carrying things around in a body part—when the player types INVENTORY, you probably don’t want to list “your mouth (empty)” (unlike, say, a basket), but only list your mouth when you do having something in it, e.g., “…and a pebble (in your mouth).” That could be done by modifying the inventory lister, among other ways.

Also, if you want to make this a generic module so others can add this to their games (or, say, make it possible for NPCs to do the spitting), it’s a bit more work. My advice there: Write custom code for your game first, and if you find it’s useful for others, then make it more generic.

EDIT: It occurred to me later that I coded that above in adv3Lite, an alternate to the standard adv3 library. If you’re using the latter, I believe the verb declarations need to be done slightly differently.

3 Likes

For the record, I just woke up.

Looking over Jim’s code, this was extremely close to what I would have done. The only deviation I’d make would be to add a canFitInMouth property, and reference that in the checkInsert(obj) method, so I wouldn’t need to update that method every time I added a new object to have in one’s mouth.

(Also implementing this with Adv3Lite, which may or may not be what Jim was using too)

I also added some string tokens (like “{the dobj}”) so that the written messages will format more flexibly for other cases, such as changing the perspective of the story. Also I changed the “spit” action to allow for “spit out pebble”.

There’s also a way to make it possible to command other NPCs to do this, but that’s a bit outside of the scope, I think.

myMouth: Container, Fixture { 'a mouth' @me
  "It's your mouth. "
  
  ownedBy = me
  ownerNamed = true

  checkInsert(obj) {
    if (!obj.canFitInMouth) {
      "<<obj.cannotFitInMouthMsg>>";
    }
  }
}

pebble: Thing { 'a pebble' @livingRoom
  "It's a pebble. "

  isSpittable = true
  canFitInMouth = true
}

VerbRule(Spit) 'spit' ('out'|) singleDobj: VerbProduction
  action = Spit
  verbPhrase = 'spit/spitting (what) '
  missingQ = 'what do you want to spit '
;

DefineTAction(Spit)
;

modify Thing {
  isSpittable = nil
  cannotSpitMsg = '{I} {cannot} spit {that dobj}. '

  canFitInMouth = nil
  cannotFitInMouthMsg = '{I} {cannot} fit {that dobj} in {my} mouth. '

  dobjFor(Spit) {
    preCond = [ touchObj ]
    verify() {
      if (!isSpittable) {
        illogical(cannotSpitMsg);
      }
    }
    check() {
      if (!gDobj.isIn(myMouth)) {
        "{I} {have} to put {that dobj} in {my} mouth first. ";
      }
    }
    action() {
      "{I} {spit} out {the dobj}. ";
      moveInto(me.getOutermostRoom());
    }
  }
}

I’m still writing this from my phone in bed, so I need to confirm that “{spit}” conjugates correctly. If not, I know exactly how to fix it; just need to get to my computer first.

Between Jim’s answer and my little edits, you have a sort of spectrum of solutions to choose from lol

2 Likes

Okay, I’ve edited my above variant code. There was a single formatting error, but also I added the following to myMouth:

ownedBy = me
ownerNamed = true

These two properties make it so placing something in your mouth will say:

You put the pebble in your mouth

instead of:

You put the pebble in the mouth

Also, can confirm that Adv3Lite correctly conjugates “{spit}”.

The TADS Action Squad is spread across a few time zones (shout out to @Piergiorgio_d_errico for the Italy time zone), and we sometimes gotta figure out if we’re solving the problem in Adv3 or Adv3Lite, but I like to think that we make up for our 24-hour help window by just being so gosh-darn endearing.

7 Likes

@jnelson and @inventor200 thanks so much! I’m going to be fully honest, I got very little sleep last night and I’m now seeing Inform code when I close my eyes, so I’ not 100% mentally prepared to grapple with that code right now, but reading it all through a couple of times, it does seem to make a lot more sense than what I was doing.

Although to return to the orignial debate: I will say that Inform has something over not just TADS, but every other programming langauge I’ve ever worked with. It’s a lot kinder to my dyslexia, which makes me just instantly forget syntax and name-y things that my mind deems arbitrary. I can write something 500 times, but if I haven’t done it for a couple of days I’ll still have to go and find an old example of it to refer to when I’m doing it again to make sure I have all the '.'s and ';'s and brackets in the right place. The natural language nature of inform is being very kind to me in that way.

@StJohnLimbo and @Zed, thanks for the advice about versions! I think for this little game I’ll stick with the latest version for the twin reasons of ‘I’ve started it here already’ and ‘I’m terrified of bugs that aren’t my fault’, but I have ideas for later projects that I think would need extensions for Inform that currently don’t work, so I might consider moving backwards for that if/when the time comes.

6 Likes

This is such good advice; however for some reason, I can’t bring myself to follow it.

3 Likes