Which parser?

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