Game Help

True. As I suggested earlier, however, there’s no need to create a list of strings. The IF way to do it is to create actual objects and put them in the room. That way, if you only want the player to be able to buy, say, the fish chowder once, you can whisk the object itself offstage (to nil) rather than having to edit the list. This is easier and less error-prone, and has the huge advantage that then you can let the parser handle commands like ‘buy fish chowder’. You don’t have to create your own manual pseudo-parser code.

If you make the chowder, etc., Fixtures, then they won’t be referred to in the room description. This is arguably good. What you do then is create a menuBoard object of some kind that lists what’s for sale. It’s easy-peasy.

Lol. I can’t believe it would have been that simple. I guess I’ll revert to menuitems. Thanks for the help on this :slight_smile:

I have an organization question. I’m not sure how to add files. Say I wanted to block off code in their own files. Is this done like C++? Do I just make a header file with the TADS script and include it with the preprocessor directive once it’s in my folder structure?

I’m reading the manual and can’t make anything of the menu.

In Room

[code] dobjFor(ExamineWares)
{

  action()
    {
        
        leakyTubMenu.display();
        
    }

}

east = mainRoad1StormPort
[/code]

Menu

leakyTubMenu : MenuItem 'Leaky Tub Menu';
+MenuItem 'fish soup';
++MenuItem 'fish soup';
+++MenuItem 'fish soup';

To add extra files to your game create a text file called (whatever).t inside that file paste in the code below and save it

#include <adv3.h> #include <en_us.h>
If you are using the Windows Workbench program click click on Source Files section of the project list and select add file. After that select your (whatever).t file and click open. Workbench will then add that file to the project for you. The process is described here.

As for the other question I wouldn’t recommend using menus here as any useful menus would start getting complex. You would need to dynamically add and remove items from the menu. You will probably want to have the shopkeeper NPC handle the sale. Check out the shopkeeper NPC from the tutorial game from Getting started in TADS3. You don’t necessarily need to do it exactly this way but it will give you an idea of how you might go about starting.

Thanks. What if you wanted infinite items. Consider a restaurant that isn’t running out. Is there a command for instantiation a new object and placing it in the room?

Are you using Workbench? If so, it’s a slam-dunk. Copy the top two lines of header from an existing file, start a new file, paste those two lines in at the top, and then click Save. You’ll be asked if you want to make the file part of your project.

If you say yes, it will be included in the Project pane. (Possibly you’ll have to drag it down below the library folders in the project pane. That is sometimes necessary.)

Yes, objects can be created dynamically at run-time. But think carefully about how you want the story to work. If the player buys an item, do you want it to show up in the player’s inventory? If so, and if you want a large number of identical items, you can just create a Fixture item that stays in the store, and then create a new object each time the player buys one.

Before you get into dynamic object creation, though, I’d suggest starting with the basics. Read the Getting Started Guide and create the mini-game that’s laid out there.

Hm, I’ve added this macros to my room, but it’s still just saying “listing wares” when I type wares in the room.

 dobjFor(ExamineWares)
    {
    
      action()
        {
            
            "ale.... 6";
            "strong spirits....8";
            "urchin wine....12";
            "red wine....12";
            "fish chowder....8";
            "lobster rolls....12";
            "lobster chowder....8";
            "lobster rolls....12";
            "lobster chowder....8";
            "baked urchin....12";
            "steamed clams....8";
            "steamed mussels....8"; 
            "clam platter....12";
            "seafood platter....18";
            
        }
    
    }

The problem you are having here is the way you defined your ExamineWares verb. It doesn’t have a direct object or an indirect object. Going through Learning TADS3 or Getting Started with TADS3 will help greatly. How you have your verb described currently, you will need to change the execAction function to display a text property on the shop room. You will probably want to either examine a display case item or just ask the NPC what is for sale. Since there is no direct object on an intransitive verb dobjFor(ExamineWares) will never be called.

TADS 3 is definitely confusing to the newcomer! The first time I tried to learn it, I gave up completely. But all this stuff really does make sense. I think you may be trying to apply concepts that you’ve learned in another programming language, which don’t necessarily apply in T3 (or in IF generally). The basic idea is to create a model world by declaring objects, and then to let the parser do the hard work. For example, I would not use an ExamineWares action. That’s an example of trying to accomplish something manually, bypassing the parser.

No, I want a wares command, as it’s part of that old school text rpg feel. Can you explain what I’m doing wrong and what I’m missing? Also the books are no good man. I’ve read through them, and that’s why I’m here, I can’t stand how broken up the information is in them. Also when I try to make the examples to fit my game they never work, haha. That’s the point of this thread, for tutoring. There are functions you guys have mentioned that aren’t even prioritized right in the books. The system docs have functions that simply say “No description available.” It’s not like we can guess the code, and figure out what they do. Sorry, that’s just my rant against poor documentation. There’s nothing worse.

What am I missing for knowledge on verbs? Do they have to inherit from another object type? How do I register this verb in such a way that dobjFor() will recognize it in my rooms?

//custom actions

 DefineIAction(ExamineWares)
     execAction() { 
  
           "listing wares...";
            
        }
   ;

   VerbRule(ExamineWares)
     'wares' | 'list' 'wares' | 'list' 'goods'| 'list' 'items'
     : ExamineWaresAction
     verbPhrase = 'list/listing'
   ;

Hey, sorry guys.

This method works. From out prior posts does dobjFor() only work ON objects that the TAction the verb applies to? Is there a similar method for controlling the flow of stuff inside rooms? Like capturing the commands typed in rooms, or is that not how this is supposed to work?

//custom actions
DefineIAction(ExamineWares)
     execAction() { 
  
          switch(me.getOutermostRoom())
            {
                case leakyTub:
                 case leakyTub:
                    "ale.... 6 \t \t \t     lobster....8 \n";
                    "strong spirits....8 \t lobster chowder....8 \n";
                    "urchin wine....12 \t   baked potatoes....6 \n";
                    "red wine....12  \t \t  seaweed dish....8 \n";
                    "fish chowder....8 \t   baked urchin....12 \n";
                    "steamed clams....8  \t steamed mussels....8 \n"; 
                    "clam platter....12 \t  seafood platter....18 \n";
                   
            }
            
        }
;

VerbRule(ExamineWares)
     'wares' | 'list' 'wares' | 'list' 'goods'| 'list' 'items'
     : ExamineWaresAction
     verbPhrase = 'list/listing'
;

A couple of points. First, “no description available” means you’re looking in the Library Reference Manual. The term “manual” is badly misleading here. It’s not a manual, it’s a reference. The Getting Started Guide and “Learning TADS 3” are in fact well organized. The Tour Guide is arguably not that useful.

Second, your ExamineWares action will certainly work. However, if the player types ‘examine wares’ or ‘look at wares’ or ‘x wares’, your action will never be reached, because in these cases ‘wares’ is a direct object. To examine a direct object, there must be an actual object in the room.

When you’ve created an actual object in the room – something called ‘wares’, let’s say – then you would simply put a dobjFor(Examine) in the Wares object (which would be an in-game object that inherits from Thing), and the parser would handle ‘x wares’ and so on.

If I have time, I’ll try to whip out a little code example this afternoon. No promises.

Okay, here’s a little test game (omitting the versionInfo and gameMain objects) that illustrates some of the basic techniques you’ve been working on implementing. If anything about it isn’t clear, feel free to ask more questions!

[code]// We’re only going to let the player buy one ale, so we don’t need to use
// dynamic object creation or make this a class. It starts out nowhere:

portableAle: Thing ‘foaming of ale/mug’ ‘mug of ale’
"A foaming mug of ale. "
vocabLikelihood { if (gActionIs(Buy)) return -2;
return 2;
}
;

class Shop: Room
;

leakyTub: Shop ‘Start Room’
"A small and not very attractive fish-and-chips shop. On the wall is a menu listing what’s on sale. "
south = beach
;

  • me: Actor
    ;

// For testing purposes, we’ll give the player a couple of inventory items:

++ banana: Thing ‘banana’ ‘banana’
"It looks yummy. "
;
++ galoshes: Thing ‘rubber galoshes shoes boots’ ‘galoshes’
"Your old rubber boots. "
isPlural = true
;

// And now the menu on the wall:

  • tubMenu: Fixture, Readable ‘menu list wares’ ‘menu’
    "The menu lists the following wares (food substances, one might guess):
    \n\tale 4p
    \n\tstrong spirits 6p
    \n\turchin wine 12p
    \n\tred wine 14p
    \n\tfish chowder 8p
    \n\tlobster rolls 12p
    \n\tlobster chowder 8p
    \n\tbaked urchin 8p
    \n\tsteamed clams 12p
    \n\tsteamed mussels 18p "
    readDesc = desc
    dobjFor(List) {
    verify() { logical; }
    action () {
    replaceAction (Examine, self);
    }
    }
    ;

// We’re not going to create a shopkeeper or the money, but we’ll provide something
// you can buy:

  • ale: Fixture ‘ale/mug’ ‘mug of ale’
    "Yes, indeed – there’s ale on the menu. "
    alreadyBoughtOne = nil
    dobjFor(Buy) {
    verify() {
    if (alreadyBoughtOne) illogical ('You wouldn’t want to get tipsy, would you? ');
    }
    action() {
    alreadyBoughtOne = true;
    portableAle.moveInto(me);
    "The shopkeeper hands you a foaming mug of ale. ";
    }
    }
    ;

// This action is for the bare ‘wares’ command:

DefineIAction(Wares)
execAction() {
if (me.location == leakyTub) tubMenu.desc;
else mainReport( 'There seems to be nothing on sale here. ');
}
;
VerbRule(Wares)
‘wares’ | ‘menu’
: WaresAction
verbPhrase = ‘check/checking the wares’
;

// And here’s a custom verb in case the user tries ‘list wares’:

DefineTAction(List)
;
VerbRule(List)
(‘list’ | ‘specify’ | ‘check’ ) singleDobj
: ListAction
verbPhrase = ‘list/listing (what)’
;
modify Thing
dobjFor(List) {
verify() { illogical (’{The dobj/he} {have} nothing to list. ');
}
}
;

// ‘buy’ is not an action that the library defines, and we’ll need it – I haven’t implemented
// the exchange of money, however:
DefineTAction(Buy);
VerbRule(Buy)
(‘buy’ | ‘purchase’) singleDobj
: BuyAction
verbPhrase = ‘buy/buying (what)’
;
modify Thing
dobjFor(Buy) {
verify() { illogical (’{The dobj/he} {is} not for sale. ');
}
}
;

// A second room, purely for testing purposes:

beach: Room ‘Beach’
"A sunny day on the beach. "
north = leakyTub
;
[/code]

I’m interested in this verify function. Will an action run until it hits and illogical call in verify? I’m guessing that’s the purpose of verity, kind of a routine to see if the action can even be carried out. LOL. I think you just unlocked something in my mind here.

verify() { if (alreadyBoughtOne) illogical ('You wouldn\'t want to get tipsy, would you? '); }

I’m currently working on people. I’ve got a pretty nice starting place. I’m just a little disappointed in conversation. Is there no Talk action? I see there’s say, tell, show and what not… but you can’t just set an initial one up for talk? Or do I just make my own action like ExamineWares and you Buy verb?

gert : Person 'Gert gert woman lady girl bar maid wench barmaid server servant owner keeper barkeep' '<<if gert.unknown>>an old-- rather plump-- looking woman<<else>>Gert (the bar keep)<<end>>' @leakyTub
    "<<if gert.unknown>>She<<else>>Gert<<end>>'s an old-- rather plump looking-- barkeep here at Leaky Tub. She's dressed in a plain black dress, with a dark sea 
    green apron tied around the waist. Her face is red with all the work she's been doing, either that or all the drinks
    she's been sneaking."
    isProperName = true
    isHer = true
    cannotKissActorMsg = 'She\'s not of a generation that welcomes outward shows of affection.'   
    cannotEatMsg = 'Whatever else <<if gert.unknown>>She<<else>>Gert<<end>> is, she is definitely not that tasty.'  
    uselessToAttackMsg = 'Beating up <<if gert.unknown>>the barkeep<<else>>Gert<<end>> will likely get you kicked out of the tavern.'
    globalParamName = 'Gert'
    properName = 'Gert'
    unknown = true
    dobjFor(Talk)
    {
        
        action()
        {
            "She says hello!";
        }
        
    }
;

ira : Person 'ira Ira IRA sailor man guy drunk alcoholic lightkeeper' '<<if ira.unknown>>an old drunken sailor<<else>>Ira (the old sailor)<<end>>' @leakyTub
    "<<if ira.unknown>>He<<else>>Ira<<end>>'s an old-- thin faced-- man with a lot of years on him. He looks as though he's
    spent a fiar bit of his life fairing the sea. The air around him smells of salt, fish, and cheap ale."
    isProperName = true
    isHer = true
    cannotKissActorMsg = '<<if ira.unknown>>He<<else>>Ira<<end>>\'s not of a generation that welcomes outward shows of affection.'   
    cannotEatMsg = 'Whatever else <<if ira.unknown>>He<<else>>Ira<<end>> is, he is definitely not that tasty.'  
    uselessToAttackMsg = 'Beating up <<if ira.unknown>>the drunken man<<else>>Ira<<end>> will likely get you kicked out of the tavern.'
    globalParamName = 'Ira'
    properName = 'Ira'
    unknown = true
;

morgan : Person 'morgan Morgan man guy librarian (book | guy)' '<<if morgan.unknown>>a young sober man<<else>>Morgan (the book lover)<<end>>' @leakyTub
    "<<if ira.unknown>>He<<else>>Moran<<end>>'s apparently drinking nothing hard tonight. Looks like a thin-- pale faced-- man
    that hasn't seen a stitch of physical labor in his life. His leather book satchel suggest that he prefers to read over 
    working up a sweat."
    isProperName = true
    isHer = true
    cannotKissActorMsg = '<<if morgan.unknown>>He<<else>>Morgan<<end>>\'s not of a generation that welcomes outward shows of affection.'   
    cannotEatMsg = 'Whatever else <<if morgan.unknown>>He<<else>>Morgan<<end>> is, he is definitely not that tasty.'  
    uselessToAttackMsg = 'Beating up <<if morgan.unknown>>the young man<<else>>Morgan<<end>> will likely get you kicked out of the tavern.'
    globalParamName = 'Ira'
    properName = 'Ira'
    unknown = true
;

Chapter 6 of “Learning TADS 3” discusses verify(), check(), preCond, and other aspects of action handling in detail. That’s the place to learn about verify() and such macros as logical, illogical, and illogicalAlready.

You’re correct that there’s no Talk action per se. The question is, how would you like it to work. You can very easily modify the grammar for the TalkTo action to allow player input such as ‘talk jerry’ (skipping the ‘to’). In order to implement a bare ‘talk’ command, you would have to figure out what you want it to do. It’s very possible in T3 to set up a conversation system in which the player will see a menu with numbered topics of conversation. The command ‘talk’ (when in the presence of another character) could bring up a suitable menu of conversation topics. But that’s only one of several possibilities, and it’s not the simplest type of thing to set up.

I would recommend against using <<>> logic in the name property. It may work, but if you want to do this, a better option would be something like this:

gert: Person 'plump old gert/woman/lady/girl/maid/wench/barmaid/server/owner/keeper/barkeep' name { if (unknown) return 'barkeep'; else return 'Gert'; } // etc.
In addition, you’ll need to write some code that switches unknown = nil after Gert introduces herself. Again, reading Eric’s discussion of NPCs will get you on the right track.

Hey,

Thanks for the help. My people are starting to shape up, but I’m getting a weird prompt error. When I type talk to man it outputs:

Which do you mean an drunken older sailorandrunkenoldsailorandrunkenoldsailor, or a sober guy a sober guy

[code]gert : Person ‘plump old gert/woman/lady/girl/maid/wench/barmaid/server/owner/keeper/barkeep’
name {

    if(gert.unknown)
        "an old-- rather plump-- looking woman";
        
        else "Gert (the bar keep)";

}
desc = "<<if gert.unknown>>She<<else>>Gert<<end>>'s an old-- rather plump looking-- barkeep here at Leaky Tub. She's dressed in a plain black dress, with a dark sea 
green apron tied around the waist. Her face is red with all the work she's been doing, either that or all the drinks
she's been sneaking."
location = leakyTub
isProperName = true
isHer = true
cannotKissActorMsg = 'She\'s not of a generation that welcomes outward shows of affection.'   
cannotEatMsg = 'Whatever else <<if gert.unknown>>She<<else>>Gert<<end>> is, she is definitely not that tasty.'  
uselessToAttackMsg = 'Beating up <<if gert.unknown>>the barkeep<<else>>Gert<<end>> will likely get you kicked out of the tavern.'
globalParamName = 'Gert'
properName = 'Gert'
unknown = true
dobjFor(TalkTo)
{
    
    action()
    {
        "She says hello!";
    }
    
}

;

ira : Person ‘ira the sailor/man/guy/drunk/alcoholic/lightkeeper’
name {

    if(ira.unknown)
        
        "an old drunken sailor";
        
    else "Ira (the light keeper)";

}

desc = “<>He<>Ira<>'s an old-- <>thin faced<>leathery faced<>-- man with a lot of years on him. He looks as though he’s
spent a fiar bit of his life fairing the sea. The air around him smells of salt, fish, and cheap ale.”
location = leakyTub
isProperName = true
isHer = true
cannotKissActorMsg = '<>He<>Ira<>‘s not of a generation that welcomes outward shows of affection.’
cannotEatMsg = ‘Whatever else <>He<>Ira<> is, he is definitely not that tasty.’
uselessToAttackMsg = ‘Beating up <>the drunken man<>Ira<> will likely get you kicked out of the tavern.’
globalParamName = ‘Ira’
properName = ‘Ira’
unknown = true
;

morgan : Person ‘morgan the librarian/man/guy/librarian’
name {

    if(morgan.unknown)
        "a young sober man";
        else "Morgan (the book lover)";

}
desc = "<<if ira.unknown>>He<<else>>Moran<<end>>'s apparently drinking nothing hard tonight. Looks like a thin-- pale faced-- man
that hasn't seen a stitch of physical labor in his life. His leather book satchel suggest that he prefers to read over 
working up a sweat."
location = leakyTub
isProperName = true
isHer = true
cannotKissActorMsg = '<<if morgan.unknown>>He<<else>>Morgan<<end>>\'s not of a generation that welcomes outward shows of affection.'   
cannotEatMsg = 'Whatever else <<if morgan.unknown>>He<<else>>Morgan<<end>> is, he is definitely not that tasty.'  
uselessToAttackMsg = 'Beating up <<if morgan.unknown>>the young man<<else>>Morgan<<end>> will likely get you kicked out of the tavern.'
globalParamName = 'Ira'
properName = 'Ira'
unknown = true

;[/code]

That error is because you’re using a double-quoted string in your name method. You need to return a single-quoted string from the method. The reason is because the name method (and also verify) may be consulted by the parser several times during the construction of an output message. A single-quoted string is data. A double-quoted string is not data – it’s displayed immediately.

The difference between single-quoted and double-quoted strings is just one of the things you have to come to terms with in T3.