Teleportation - TADS3.1

I have enclosed a piece of code that I have a slight problem with. If I enter the command code ‘goto’ and press enter before I enter a vocabword destination then I get a run-time
error. Is there a way to prevent the run-time error by making sure the destination word is enclosed in the command when I use the enter key. I would also like a text error message to point out my mistake. Would appreciate some help on this.

RonG


/*  Teleportation code.  ******************************************************/

    DefineTAction(Goto)
       objInScope(obj){if(obj.ofKind(Room))return true;
          return nil;
   }
;
    VerbRule(Goto)
       'goto'singleDobj
       :GotoAction
       verbPhrase='go/going to a room'
;
    modify Room
       dobjFor(Goto){
       action(){
          me.moveIntoForTravel(self);
          me.lookAround(true);
   }
  } 
;

This is untested, but the first thing I would try would be:

objInScope(obj) {if (obj && obj.ofKind(Room)) return true;

I changed the code as shown but it didn’t help. It seems to me that we should be able to kill the command if no object is present at all in the command. Such as ‘!objInScope’. But I didn’t have any luck trying to do that. Perhaps it needs some type of if-else statement. I’m learning but still haven’t quite figured this one out.

RonG

/*  Teleportation code.  ******************************************************/

   VerbRule(Goto)
      'goto'singleDobj
      :GotoAction
      verbPhrase='go/going to a room'
;    

   DefineTAction(Goto)
      objInScope(obj){if(obj&&obj.ofKind(Room))return true;
      //objInScope(obj){if(obj.ofKind(Room))return true;
         return nil;
   }
;
    
   modify Room
      dobjFor(Goto){
      action(){
         me.moveIntoForTravel(self);
         me.lookAround(true);
   }
  } 
;

It’s not enough for objInScope(obj) to return true; you also need to make sure the room is in the list returned by getScopeList().

DefineTAction(Goto)
    objInScope(obj) { return getScopeList.indexOf(obj) != nil; }
    getScopeList()  { return allRooms; }
;

allRooms: ClassList
    type_ = Room
;

One of my hobbies is reimplementing the “list of all objects of a particular class” object in every project I touch. The latest addition to that proud line is my ClassList extension, which you’ll need to add to your project to use the above code as-is.

And you should also backstop the new verb by adding a default response to Thing:

modify Thing
    dobjFor(Goto) {
        verify() { illogical('You can\'t go to that. '); }
    }
;

This shouldn’t matter after the above change, but it prevents a runtime error when the parser tries to visit the verify method for each object in the scope list.

I’ll give all of this a shot and see what happens. I also downloaded the project you had marked. Thanks much.

RonG

I’ve added/modified the source for the ‘goto’ command. No problem compiling this but I have two problems when testing.

If I enter the goto command then press the enter key without including a target of any type, I get an ‘Invalid Index’ error along with ‘cannot be indexed’. I know this is an entry error but it still makes a mess of things.

If I enable the ‘modify thing’ section, then I cannot go to any target room. I get a ‘not necessary message’. I tried moving that section of code around but it made no difference. Perhaps that section of code is still not sequenced properly?


#charset "utf-8"
//#charset "us-ascii"

/*******************************************************************************
*  TADS Copyright (c) 1999, 2002 by Michael J. Roberts. Permission is granted  *
*  to anyone to copy and use this file for any purpose.                        *
*******************************************************************************/

/*  Includes and Source file extensions.  *************************************/

#include <adv3.h>
#include <en_us.h>
#include <tads.h>
#include <vector.h>

/*  List wrapper for all objects of a perticular class.  **********************/

property propNotDefined;
export propNotDefined;

class ClassList: object
   init() {
      local lst = new Vector(50);
      forEachInstance(type_, {obj: lst.append(obj)}); 
      lst_ = lst.toList();
   }

   propNotDefined(prop, [args]) {
      lst_?? init;           
      return lst_.(prop)(args...);
   }

   operator[](x) {
      lst_ ?? init;
   return lst_[x];
   }

   lst_=nil
   type_ = self
;

/*  Sample template for ClassList objects.  */

ClassList template &type_;

/*  Clock time at start of story.  ********************************************/

ClockEvent eventTime=[1,06,00];

/*  Teleportation code.  ******************************************************/

   VerbRule(Goto)
      'goto'singleDobj
      :GotoAction
      verbPhrase='go/going to a room'
;    

   DefineTAction(Goto)
      objInScope(obj){ return getScopeList.indexOf(obj) !=nil;}
      getScopeList() {return allRooms;}
;
    
allRooms: ClassList
   type_=Room
;

//modify Thing
  // dobjFor(Goto){
    //  verify() {illogical('You can\'t go to that.');}
   //}
//;

modify Room
      dobjFor(Goto){
      action(){
         me.moveIntoForTravel(self);
         me.lookAround(true);
   }
  } 
;

This happens because of the way you’ve defined the Goto verb phrase. You wrote this:

VerbRule(Goto)
    'goto' singleDobj
    :GotoAction
    verbPhrase='go/going to a room'
;

When doing disambiguation, the parser checks the verb phrase for some text in parentheses, which it will parrot back at the player in the event he doesn’t supply an object. So you should always have some parenthesized text, ideally written in a way that the parser’s prompt makes sense.

VerbRule(Goto)
    'goto' singleDobj
    : GotoAction
    verbPhrase = 'go/going (where)'
;

Produces this output:

Room inherits from Thing, so if you don’t override the verify method, Room will also block the goto command.

This should fix it - note the empty verify() method has been added to Room.

modify Room
	dobjFor(Goto) {
		verify() {}
		action() {
			me.moveIntoForTravel(self);
			me.lookAround(true);
		}
	}
;

A general note on this command - the way you’ve implemented it, the player only needs to know the name of the room in order to travel there. You may wish to restrict travel to rooms that the player has visited, which you can do by testing the room’s “seen” property.

modify Room
	dobjFor(Goto) {
		verify() {}
		check() {
			if (!seen)
				failCheck('You don\'t know where that is. ');
		}
		action() {
			me.moveIntoForTravel(self);
			me.lookAround(true);
		}
	}
;

Here’s the latest version of my ‘Goto’ code. Everything works except for using the comand Goto followed directly by the enter key (no object). In that case, I get the following error:
Invalid index operation - this type of value cannot be indexed.
Go Figure!!!


/*  Teleportation code.  ******************************************************/

   VerbRule(Goto)
      'goto'singleDobj
      :GotoAction
      verbPhrase='go/going(where)'
;    

   DefineTAction(Goto)
      objInScope(obj){ return getScopeList.indexOf(obj) !=nil;}
      getScopeList() {return allRooms;}
;
    
allRooms: ClassList
   type_=Room
;

modify Thing
   dobjFor(Goto){
      verify(){illogical('You can\'t go to that.');}
  }
;

modify Room
   dobjFor(Goto){
      verify(){}   
      check(){
         if(!seen)
            failCheck('You don\'t know where that is.');
   }

action(){
   me.moveIntoForTravel(self);
   me.lookAround(true);

  }
 } 
;

Is there a reason you are deleting the spaces in the VerbRule strings? It should be written like this:

VerbRule(Goto)
    'goto' singleDobj
    : GotoAction
    verbPhrase = 'go/going (where)'
;

If there’s no space in ‘go/going(where)’, the regex fails to find the match and you’re back to the index error.

I am woefully to blame for my lack of spaces. With my crappy vision and my monitor size, I sometimes can’t determine whether I should have spaces or not. Thanks for bearing with me. I am thankfully amazed at how quickly all of you answer my posts.

RonG

btw: Now, it all works great!

I can’t help with the small monitor, but if you go to the Tools menu in Workbench, select Options, and then choose Fonts in the left pane of the dialog box, you’ll find a field (on the right) in which you can increase the font size. Maybe you can find a compromise size that works okay on your monitor.

Duh! After fifty years of marriage, my wife doesn’t hesitate to tell me that I always find the
most difficult or impossible solutions to the simplest problems. I can now see the spaces, or the lack of spaces, in my code. I got rid of the TADS file listings on the left of the monitor and increased the font size. What a help!!

RonG