Choosing an object at random / dynamically changing properties of an object (Adv3Lite)

I wonder if some kindly person could help me out here? This whole TADS thing is proving to be a difficult nut to crack. In fact, I’m even scratching my head over the kind of nutcracker I should be using to try and make a dent in it. Having spent all evening following the avuncular Eric Eve through the many-mirrored maze of the Adv3Lite manuals, I still can’t quite find what I’m looking for, even though I’m sure it’s in there somewhere…

What I’m trying to do is something like this: I have some objects (they may as well be books). Say there are four of them (but they’re just called “some books”). When the player takes a book I want it to be one of the four, at random. The player can only have one book at a time (if they want another one, they have to put the first one back). So I want to either a) pre-define four distinct book objects with different names and descriptions and then bring one of them into play, at random, when the player takes a book, or b) define a single book object and dynamically change its name and description to a different name and description, at random, from my choice of four options, when the player takes it.

Now, I know exactly how I’d do this in Adventuron, but I’m beginning to realise (with mounting horror and panic) that TADS isn’t Adventuron at all! Should I be using an EventList for this? The addVocab(voc) method? Or some other flavour of witchcraft? Any pointers (even just to which bit of the manual(s) I should be looking at) would be a tremendous help!

I’d probably go the route of creating four book objects. Then you might need a staticBooks object to handle dobjFor Take when as yet no individuals are taken. The action in Take could be a simple rand([book1,book2,book3,book4]).moveInto(me); with an appropriate msg. There are pretty straightforward ways of forcing the book swap as well. I’ll wait to see if any of the Lite pros jump on this, else I can try to give you some more specific code…

1 Like

I feel you on what you’re saying, too, because I know exactly how I’d do this in adv3, but I wouldn’t be able to code in Lite with doing some research…

1 Like

Adv3 is really good too, just saying… but you’ve probably got time invested in learning Lite already…

1 Like

Here’s my quickie stab at this:

+ bookPile: Fixture, Surface 'a pile of books;;book'
  "You see a pile of <<spellNumber(books.length)>> books.  "

  // the books in the pile are stored in a private list, rather than the
  // 'contents' list every Thing has ... that's because we don't want to put the
  // individual books into scope for the player to see or choose from
  books = [ redBook, blueBook, greenBook, orangeBook ]

  dobjFor(Take) {
    verify() {
      logical;
    }
    check () {
      if (books.length < 4)
        "You can only take one book at a time.";
    }
    action() {
      // select one
      local book = rand(books);

      // remove it
      books -= book;

      "You take <<book.theName>> from the pile.  ";
      book.moveInto(gPlayerChar);
    }
  }

  // for PUT book ON pile
  checkInsert(obj) {
    if (!obj.ofKind(Book))
      "You can only put books on the pile.  ";
    else if (books.indexOf(obj) != nil)
      "That book is already on the pile.  ";
  }

  iobjFor(PutOn) {
    action() {
      // move the book out of the player's inventory
      gDobj.moveInto(nil);

      // put the book back on the pile
      books += gDobj;
    }
  }
;

class Book: Thing
;

redBook: Book 'a red book'
;

blueBook: Book 'a blue book'
;

greenBook: Book 'a green book'
;

orangeBook: Book 'an orange book'
;

If I understand what you’re saying, you want the collective books to appear as a single object until one is taken. The player is only allowed to take one. If they want more, they have to return the book to the pile and try again.

adv3Lite has a CollectiveGroup class, but I don’t think it does quite what you want here. If it was okay for the individual books to be visible in the group, and the player could pick which one they wanted, a far better choice would be to use a standard Container (PUT book IN bookcase) or a standard Surface (PUT book ON pile) and be done with it. It’s the way the individual books “disappear” into the pile that requires some custom code to make happen.

Like I said, I banged this out, so this might not work well in all contingencies, but it should give you a starting point to work from.

2 Likes

You could also consider making the book return an implicit action:

check { /* empty */ }
action {
  local b = me.allContents.valWhich({x:x.ofKind(OneAtATimeBook)});
  // or perhaps: local b = gAction.scopeList.valWhich({x:x.ofKind(OneAtATimeBook)});
  if(b) tryImplicitAction(PutOn,b,bookPile);
    // if there was any reason we couldn't get rid of our current book 
      // (it was in a locked box, etc.), we need to know
  if(me.allContents.valWhich({x:x.ofKind(OneAtATimeBook)})) {
    "You can't have more than one etc.";
    exit; }
  // Then the usual handling...
 }

If the player can take one of the “books” out of the book pile’s location, however, and drop it somewhere, then you have more work on your hands if you’re determined for there to be only one book in the game world at a time. Unless you’re simply preventing the player from leaving that room with a book…

1 Like

Yes, I’m sure it is - but I’ve now made my Adv3Lite bed of nails and am very much lying in it…

1 Like

Thanks John and Jim - this gives me a good foothold on the problem and a lot of material to tinker around with. I’m very grateful!

2 Likes

I’ve never looked at Adventuron, so I can’t comment on that. My experience (going back a few years) is that when I first started learning T3 I found it difficult and intimidating, but as I became more familiar with it, it got easier. There’s definitely a “TADS way of doing things.”

EventLists, for example, are almost entirely about creating variable text outputs, such as giving an NPC a ShuffledEventList output to replace “Bob does not respond.” What you’ve described is four distinct books, so trying to manipulate one book object by changing its vocabulary is not the TADS way. Your objects are distinguishable, so, as Jim Nelson suggested, create a Book class and make four distinct objects. That’s the TADS way.

I would suggest that you read the Learning document first. There are some advanced topics for which you’ll need the Library Manual. The Library Reference Manual is a different beast entirely; it’s not properly a manual at all, it’s a gigantic cross-linked database. When you’re first learning TADS, just ignore the LRM. Later on, it will become super-useful, but at the outset you won’t know what you’re looking for in it. That’s my experience, anyway.

Also, by the way, if you’re using Windows, a utility called Auto Hot Key will save you any amount of typing. For instance, you can set it up so that one simple macro key combination spews out:

dobjFor() {
    verify() {}
    check() {}
    action() {}
    }

…and then moves the cursor insertion point back up between the top row of parentheses so you can type the action name (Take or whatever).

2 Likes

There’s no standard library in Adventuron. Everything - doors, containers, actions, conversations, NPCs, the lot - has to be built from scratch. That makes it limited in some ways (it wasn’t designed to make the sort of very long, convoluted narrative games that I like to make) but gives it a certain appeal to the DIY enthusiast, and means that the author understands, more or less, how each of their wonky Heath Robinson contraptions works. In stark contrast, TADS is massively fully featured and seems to have a class for everything already built in - secret doors, bunches of grapes, the kitchen sink etc, etc. It also assumes a basic level of programming knowledge that I really don’t have (but aside from that, Eric Eve’s documentation is very good; I’ve read the Learning manual and have the others on hand). So yes, it’s hard and intimidating and feels, at the moment, a little like attempting to scale a diamond-coated cliff face, in carpet slippers. But I’m the stubborn and determined type (or an awkward sod, as you please), so will carry on chipping away and apologise in advance for the silly questions that are bound to crop up along the way.

1 Like

#TIL!

(I first thought “Heath Robinson” was a reference to Heathkit, a build-it-yourself company popular when I was a kid. Different Heath.)

1 Like

That’s him! Look at my source code sometime and you’ll see what I mean.

1 Like

I’m sorry to come back about this, Jim, as I really should be able to figure this out…but it’s giving me an ‘index out of range’ runtime error when I’m already holding one book and attempt to get another, and I can’t work out why. Any ideas?

Did you copy Jim’s code from the thread exactly or have you added more to it? What is the stack trace saying about where the RTE occurs?

1 Like

And did you try using the implicit action for the book returning part?

1 Like

As John asked, if you’ve made changes to the class, I’d need to see those to debug the problem. (You can DM them to me if you want.) Also, what commands are you entering to cause the issue? When I do this:

> TAKE BOOK
> TAKE BOOK

I get back “You can only take one book at a time.”

1 Like

Hmm - I hoped it would be a simple solution. I don’t think I did change anything. But I will fiddle around with it a bit more to try and work out what the problem is, as well as what on earth the stack trace means. I’ll come back after a bit more head scratching…

Thanks all!