TADS 2 coding tips

From IFWiki

Here are some TADS 2 coding examples which might be useful in your game:

Locations with unimportant objects

modify room
  unimportantthings = []
;
parseErrorParam: function(num, str, ...) {
  if(num=2 || num=9 || num=20) {
    if(find(Me.location.unimportantthings,getarg(3))) {
      return 'The %s isn\'t something you need to refer to in this game.';
    }
  }
  return nil;
}

This works for verbs as well as nouns. In each room you can make a list of unimportantthings with the words which are unimportant in that location. It only displays the message if the word is useless for other things (such as objects you are carrying), so if the book in the library isn't important but the one you are carrying is important, it will assume you mean the book that you are carrying.

Disallowing the parser to select arbitrary objects

modify deepverb
  disambig1(actor, prep, obj, verprop, wordlist, objlist, flaglist, numberWanted, isAmbiguous, silent) = {
    local i;
    i:=1;
    while(i<=length(flaglist)) {
      if((flaglist[i] & PRSFLG_COUNT)<>0 || (flaglist[i] & PRSFLG_ANY)<>0) {
        if(!silent) "Sorry, we don't allow the parser to select arbitrary objects in this game.";
        return DISAMBIG_ERROR;
      }
      i++;
    }
    return DISAMBIG_CONTINUE;
  }
  disambigDobj(actor, prep, iobj, verprop, wordlist, objlist, flaglist, numberWanted, isAmbiguous, silent) = {
    return self.disambig1(actor,prep,iobj,verprop,wordlist,objlist,flaglist,numberWanted,isAmbiguous,silent);
  }
  disambigIobj(actor, prep, dobj, verprop, wordlist, objlist, flaglist, numberWanted, isAmbiguous, silent) = {
    return self.disambig1(actor,prep,dobj,verprop,wordlist,objlist,flaglist,numberWanted,isAmbiguous,silent);
  }

String reversing function

strrev: function(s) {
  local o,i;
  i:=length(s);
  o:='';
  while(i>0) {
    o:=o+substr(s,i,1);
    i--;
  }
  return o;
}

String rotate 13 function

strrot13: function(s) {
  local o,i,l,f,x;
  l:='abcdefghijklmABCDEFGHIJKLMnopqrstuvwxyzNOPQRSTUVWXYZ';
  i:=1;
  o:='';
  while(i<=length(s)) {
    x:=substr(s,i,1);
    f:=find(l,x);
    if(f<>nil) {
      if(f>26) {
        f:=f-26;
      } else {
        f:=f+26;
      }
      x:=substr(l,f,1);
    }
    o:=o+x;
    i++;
  }
  return o;
}

Make the room title bold

modify room
  dispBeginSdesc = "\H+<b>\H-"
  dispEndSdesc = "\H+</b>\H-"
;

Using tab characters in command lines

Tabs are treated as spaces by the parser, but if you push TAB key in the game, it does nothing, and if you paste text with tab character in it, it changes it to a space. But still with parserReplaceCommand and similar stuff, you can use the tabs. So, you can use it internally in your game for indicating commands entered by the game program itself, or by manually entered. There is other uses for this also.

You can use tabs internally like this:

parserReplaceCommand('	'+x); /* Note the TAB */

In preparse function, you might do:

if(substr(p1,1,1)='	')

Large number supporting

parseNounPhrase: function(wordlist, typelist, current_index, complain_on_no_match, is_actor_check) {
  local s;
  s:=wordlist[current_index];
  if(reSearch('^[0-9]+$',s)<>nil) {
    numObj.too_large:=(s<>cvtstr(cvtnum(s)));
    numObj.text_value:=s;
  }
  return 2;
}
modify numObj
  text_value = nil
  too_large = nil
  thedesc = {
    if(self.too_large) "the number <<text_value>>";
    else "the number <<value>>";
  }
;
modify strObj
  text_value = {
    return self.value;
  }
;