Need Help With Attributes.

Hello,

Brand new to Quest. Can't quite figure out how to use Custom Attributes. I have the tutorial and have tried to follow it. I don't use the examples - I make my own to be sure I understand.

The tutorial gives the example of eggs. You create the object "Eggs," you give it an attribute of "weight," and then you type ""A box of eggs, weighing " + eggs.weight + " grams." OK. Except WHERE do I type that??

Instead of eggs, I created a Waste Basket. Gave it an attribute of "Full," and set it to "True." Went to "Setup" page and description changed "Text" to "Script." Below that, it says "Print" and next to that a little gray box says "Message" with a down arrow. So in the box I typed ""Waste Basket is " + Full + "."

As I understood the Eggs example, that should say "Waste Basket is full" when User looks at it. Instead I get this:

Error running script: Error compiling expression 'game.pov.parent = ': SyntaxError: Unexpected end of fileLine: 1, Column: 35```

Appreciate any help pointing me in right direction.

That error sounds like your game file is corrupted to me. The error doesn't seem to relate to the script you're talking about.

Could you try sharing the game so we can take a look and work out what's wrong?

Also, "Waste Basket is " + Full + "." probably won't work, unless Full is the name of an object.
I suspect you want either "Waste Basket is " + wastebasket.Full + "." (making sure you use the exact name of the object) or "Waste Basket is " + this.Full + "." (using this, which is an easier way of specifying "the object that has this script")

However, these options will display a message like "Waste basket is true." which probably isn't what you want.

If you leave the print type set to "Message" (or the look-at type set to "Text") you can use text processor directives, which might be easier in this case. You could put something like:

Waste basket is {either wastebasket.Full:full:empty}.

either is the quickest way to turn true/false into two pieces of text you specify. The syntax is

{either object name.attribute name:text if true:text if false}

That needs to go inside a text string; so you specify "message" within a print command, or "text" for an object/room description.


Thank you for responding. I would love to post my game here and have the experts steer me in the right direction. But I don't know how. Sent a message to the UpLoad feature asking if I could upload game there. Don't want to upload it if that is reserved for finished games. Is there a way to post game here, in a regular post?? I have no clue.


Plenty of stuff is uploaded here, just be sure to let everyone know it's a work in progress.


If you're using the desktop Quest editor, you could put the aslx file on dropbox or somewhere, and post a link here. (The downside of this method is that people who don't have the desktop editor won't be able to play it, only look at the code)

Or you could publish the game and choose to make it unlisted ("Only people I give the link to"), and post the link in the forum. (the downside of this method is that the published game includes a load of extra code, so it can be harder to find problems)


Make sure to use https in your link, not http. Only that works for some reason.


Thanks for your replies. I did upload my game. But now it doesn't seem to be there. I figure there are two possibilities.

  1. I'm too dumb to find it.

  2. It's such a pathetic little fragment that a Moderator (Or someone) deleted it.

Well, I will try again.


OK, I created a Drop Box account. Apparently it's free for thirty days. I have no idea how it works. I hope you guys are able to access my game from here and tell me what I need to do to create and use Attributes.

https://www.dropbox.com/s/i4xhz87k09e9kn2/Prac%20I.quest?dl=0

Thanks.


OK, your look script for the wast basket is:

        msg ("\"Waste Basket is \" + Full + \".\"")
        if (game.pov.parent = ) {
        }

Now, when you play the game, you get two messages. One for each of those lines.

When asking for help, you showed us only the first line of your script, and the second line of the game's output.

First line

   msg ("\"Waste Basket is \" + Full + \".\"")

This gives the output:

"Waste Basket is " + Full + "."

I suspect that in the GUI editor, you have selected "Message" (which prints exactly what you entered), rather than "Expression" (which lets you enter a Quest expression to determine what to print).

After changing the parameter type to "Expression", you will also need to refer to the variable by its correct name, as I explained in my previous post.

It also seems like your 'Full' attribute contains the string True.
So if you change the code to use an expression:

msg ("Waste Basket is " + Waste Basket.Full + ".")

it will give you the output:

Waste Basket is True.

Second line:

 if (game.pov.parent = ) {

This line doesn't mean anything. You seem to be comparing game.pov.parent (the current room) to nothing.
This explains the error message you quoted in your post.

I don't know what you intended to do with this line, but an unfinished line of code will only cause problems. You need to either fix it, or remove it, so you can get rid of the error message.

I hope that helps some.


But this line: "if (game.pov.parent = ) {"

I have no clue where that came from. I certainly didn't type it and I can't find it in the Quest game-create tool. All I can see is the first line. I can't delete that line if I don't know where it is.

Maybe I'm a lost cause.


Well, my post above left off the first part. I said I did change parameter to Expression, and it did change the output. Don't know why it got left off.


You'll need to look in code view to remove the extra lines. I'm assuming the GUI editor can't display it because it's not valid code.


OK, thanks. Actually, I didn't know Code View Existed. I erased that extra line. (Still no idea why it appeared.)

Now I will try again. I have a Waste Basket. I want to give it a "Full" attribute. When Players looks at it, I want game to say, "Waste Basket is full" if "Full" is set to True or "Waste Basket is empty" if "Full" is set to False.


Here is how you use attributes.
https://imgur.com/o9X6rbc
https://imgur.com/c27Gkvf

Here is the code.
First, you do this.

Wastebasket.full = false

Then, you do this when you want the waste basket to be full.

Wastebasket.full = true

The code to check it should look something like this.

if (Wastebasket.full = true) {
  msg ("The waste basket is full.")
}
else {
  msg ("The waste basket is not full yet.")
}

You can create a waste basket. You can then create a counter, and each time the basket is used, the counter can go up by one, until the basket is "full."


OK, thanks. I will check out your links.


Still can't get my "full" attribute to work. The error message is different. Maybe that's progress.

One problem is, I'm not sure WHERE to type the code you give. Went to SetUp tab for Waste Basket. Changed "Look at" description to Script. Changed "Print" to expression. In the box to the right of that, I typed, if (Waste Basket.Full = true) {msg ("It's full.") }

But when I run the program, I get

Error running script: Error compiling expression 'if (Waste Basket.Full = true) {msg ("It's full.") }': CompareElement: Operation 'Equal' is not defined for types 'String' and 'Boolean'

You guys have been patient with me. I'm sure I'll figure this out.


This code:

if (Waste Basket.full = true) {
  msg ("The waste basket is full.")
}

is a script, not an expression. You need to enter it in code view.
The equivalent in the GUI will look like this:
Screenshot 1

However, this is also bad practice.
More sensible code would be something like:

if (Waste Basket.full) {
  msg ("The waste basket is full.")
}

(which is slightly more efficient, but doesn't look so neat in GUI view)
Screenshot 2

OR the preferred way to check boolean attributes:

if (GetBoolean (Waste Basket, "full")) {
  msg ("The waste basket is full.")
}
Screenshot 3

However, in a case like this, it is so much easier to use the text processor. if statements are good for controlling the flow of text, but if you just want to change the text, you don't even need a script. You can just do:

msg ("The waste basket is {either Waste Basket.full:full:empty}.")
Screenshot 4 which is similar to what the tutorial advises. Or you could decide not to run a script at all: Screenshot 5

Since I'm obviously never going to figure out attributes, I decided to start at the beginning of the tutorial and go through it carefully. I learned things I had missed the first time around. Now I'm on the Custom Commands' page. Was doing fine till I got toAdditional Example (Advanced.)' Have tried to follow Tutorial exactly.

Command is `say.' In Command pattern box, I have say #text_talk# to #object_one#

Then I made a `switch' script. In the switch box, I put object_one.

In the `cases' box I have Bob under Key column and
Print "You say " + text_talk / Print "Bob pays no attention." in the column to the right. That is exactly the form used in the Tutorial. But now I get ...

You say "hi", but no answer.
Error running script: Error compiling expression '"You say " + text_talk / Print "Bob pays no attention"': Unknown object or variable 'Print'

Any ideas??


I think you've mixed two commands together.

The command "Print" in the GUI is actually called msg in code view. So your code should look like:

msg ("You say " + text_talk)
msg ("Bob pays no attention.")
Screenshot of GUI view

or if you want the responses to be a single line, it would be a single command:

msg ("You say " + text_talk + "Bob pays no attention.")
Screenshot of GUI view

https://docs.textadventures.co.uk/quest/tutorial/custom_commands.html#additional-example-advanced

image


I think this is the screenshot that caused the confusion.

In code view, that looks like this:

switch (object_one) {
  case (troll) {
    msg ("You say " + text_talk)
    msg ("The troll grunts, but otherwise ignores you.")
  }
  case (bob) {
    msg ("You say " + text_talk)
    msg ("Bob smiles back at you.")
  }
}

I can see how that screenshot could confuse a new Quest user.


Aw right! Mr. Angel's idea works.

msg ("You say " + text_talk + "Bob pays no attention.") Actually I omitted the word `msg' and the parentheses; simply added plus sign to what I had before. Works exactly as I wanted. Well ... Almost. There is one thing:

I say Hi to the couch, and I get `You say "hi", but no answer.' And that's perfect. Problem is, I also get that when I say Hi to Bob.

You say "hi", but no answer.
You say hi. Bob pays no attention

Shouldn't the game leave out the first line?? Is there a way to make program omit the generic response if Player is talking to a character/object who will give a specific response??


Actually I omitted the word `msg' and the parentheses

The "msg" appears as "Print" in the GUI. You entered it by choosing the command rather than typing it in.

I think this is the screenshot that caused the confusion.

Oh, I didn't know that… the 'switch' command looks completely different in the desktop and web editors. That's a bizarre design choice, and I have no idea why it's been done like that.


Shouldn't the game leave out the first line??

It would make sense. But where is the first line in your code?

Quest just does what you tell it. So, for example, if your code looks like:

msg ("You say \"" + text_talk + "\", but no answer.")
switch (object_one) {
  case (bob) {
    msg ("You say " + text_talk + ". Bob pays no attention.")
  }
}

It will do the things in order. First it prints the first message; then if the person is bob, it prints the second message.

If you want it to only do the first message as a default, if it doesn't do any of the others, it would be:

switch (object_one) {
  case (bob) {
    msg ("You say " + text_talk + ". Bob pays no attention.")
  }
  default {
    msg ("You say \"" + text_talk + "\", but no answer.")
  }
}

(There should be a 'code view' button that lets you view the code for the whole script. Even if you don't understand code yet, this lets you copy and paste the code so it's easier to show us what you're doing. It also means you can paste in the code that someone else has given you, and then switch back to the GUI view to see what it looks like there. Apparently I can't share helpful screenshots because I'm using the online version of Quest, and some stuff looks very different)


Have made progress! Ready to move on to next section of tutorial. There's just one little nagging item.

If I type Say Hello with no `To' clause; that is if I don't specify the person to whom I'm speaking, I get

"I don't understand your command."

On the page where we type the commands, there's a box that says, "Unresolved object text." And in the picture in the tutorial, that field is filled with `Say it to who?' But apparently this part of the command doesn't kick in.

Shouldn't there be some sort of mechanism so the Player can type "Hello" to the world in general?? Or maybe there should be two `Say' commands?? One that requires an object and one that doesn't??

Well, it's a small matter and I'm eager to move on.


On the page where we type the commands, there's a box that says, "Unresolved object text." And in the picture in the tutorial, that field is filled with `Say it to who?' But apparently this part of the command doesn't kick in.

When interpreting a command, Quest compares what the player entered to the pattern. So with a pattern like say #text# to #object#, the command will be selected every time the player enters something that starts with "say" and has a "to" in the middle.

Once it already knows what #text# is, and what part of the player's input matches #object# it will compare the #object# text to the aliases of all objects the player can see. If none of them matches, the "unresolved object" text appears.

Basically, this appears if the player types "say hello to john" when there isn't anybody called John in the room.

If you want to allow just "say hello", you would need to change the pattern.
You could make a second command, whose pattern is just say #text# - this one will only run if there is no "to" in what the player typed, so you can just make it print out "Who do you want to say it to?" or "Talking to yourself doesn't make you feel any better."

Alternatively, you could give your command a pattern like say #text_talk# to #object_one#;say #text_talk# (I think that works) and then make the script something like:

if (IsDefined(object_one)) {
  // put your existing code here
}
else {
  msg ("Who do you want to talk to?")
}

Thanks. I did make a second "say" command and it does what I want.


Have got to Section 8 of Tutorial, titled, "More things to do with objects." Flags seem like a really handy tool, and I think I've figured out how to use them. Um ... Somewhat.

It's not clear exactly how to change them. Tutorial gives the example of using a defibrillator on Bob, and I got that to work. Resurrect Bob from dead to alive. But then tutorial goes on to discuss Functions, and I'm kinda lost there. Will go over material again and maybe I'll figure it out.

But what I really wanna ask about is this quote from Tutorial: "It is good practice to give flags meaningful names, and to have them start off (or false)."

If I decide to rebel and have a flag start off True, how can I do that?? And can I arbitrarily change the flag at a later time??


In scripts, is there anything equivalent to "And??" Going through the Tutorial. Have got defibrillator to work on Bob by typing either "Use defibrillator" or "Use defibrillator on Bob." Tutorial suggests adding an "If" command to make sure Player is in same rom as Bob. But I just can't figure that out. Is there anyway to use two conditions in the same If clause?? "If Bob is in same room AND Bob is not moving ..."

Alternatively, is there something equivalent to "Exit Function??" So if first condition (Same room as Bob) is not met, program leaves and does not run following commands in that function??

Thank you.


OK, I think the problem I'm having with scripts is that the "If" command doesn't work. At least it doesn't work properly for me. I added a verb, "Break" to eggs. Want Player to be able to break eggs if he's in same room as eggs, but not if he's in a different location. Didn't use Code View, but this is what I see in Code view:

        if (game.pov.parent = eggs) {
          msg ("You scramble a few eggs.")
        }
        else {
          msg ("You must be in same room as eggs.")
        } 

My condition has changed from "Player In Room" to "game.pov.parent=eggs." Is it supposed to do that?? What does game.pov,parent mean?? Anyway, it says, "Must be in same room" even when I AM in same room.

Any ideas??
Thank you.


game.pov.parent is an expression that means "the room the player is in". game.pov means "the player", and .parent finds the room something is in.

So you're testing if the player is in a room named eggs.

If you want to check if the player is in the same room as an eggs object, you would want that line to be:

if (game.pov.parent = eggs.parent) {

or:

if (Contains (game.pov.parent, eggs)) {

(which will also be true if the eggs are inside something that's in the room; like the player's inventory)
or:

if (ListContains (ScopeReachable(), eggs)) {

(which tests if eggs are in ScopeReachable(), a list of objects the player can reach)

but you probanly don't need to do this. The player can only use verbs on objects they can see. So if this script is a verb on the eggs, it won't run at all when they're in a different room.


I created a Drop Box account. And I don't look in vain.
Compete with others, develop your strategy and become the top player – everything is possible in Eve online [url]https://iskmarket.com/[/url]


Thanks, Mr. Angel. I am making progress. The tutorial is unclear on "game.pov.parent." But thanks to you, I was able to get the defibrillator working correctly and not working when I'm not in the room with Bob.

Still have a ways to go though. Started this thread because I was frustrated I couldn't create a waste basket and make it behave the way I wanted. Still frustrated; maybe I'm biting off more than I can chew. Want to be able to do all these actions:

  1. Examine waste basket and tell if it's empty or full. This one can do.
  2. It's it's empty, put stuff in it, thus making it full.
  3. If it's full, get told I can't put any more into it.
  4. Empty it.
  5. Get told it's empty if I try to empty it while it's empty.

Will keep plugging away. Still think there must be a way to check for two conditions at once. "IF Bob is not moving AND Player is in same room THEN he can use defibrillator."


Still think there must be a way to check for two conditions at once. "IF Bob is not moving AND Player is in same room THEN he can use defibrillator."

There is an and operator (as well as or and not).

If you take any boolean expression (one that you could put between brackets of an if statement in code view), you can join 2 expressions together with and.

For example (I don't know what attributes you're using to indicate that Bob isn't moving; I'm sure you can replace my example with the check you want):

if (Contains (game.pov.parent, Bob) and GetBoolean (Bob, "stopped_moving")) {
  // Do something
}

However, in most cases you would want to break the conditions down to something like:

if (Contains (game.pov.parent, Bob)) {
  if (GetBoolean (Bob, "stopped_moving")) {
    // code to shock Bob goes here
  }
  else {
    msg ("Bob backs away. He probably doesn't need a shock right now.")
  }
}
else {
  msg ("Bob isn't here.")
}

Because in a lot of cases where you might use and, you'll want to display a different message depending which one isn't true.
An alternative way to arrange this (so that it's easier to see which if goes with which message) is to invert the conditions like this:

if (not Contains (game.pov.parent, Bob)) {
  msg ("Bob isn't here.")
}
else if (not GetBoolean (Bob, "stopped_moving")) {
  msg ("Bob backs away. He probably doesn't need a shock right now.")
}
else {
  // neither problem applies, so code to shock him goes here
}

Thanks, Mr. Angel. Appreciate your taking time to work with me.


Still plugging away on my attempt to create a waste basket. Learning a bit (A LITTLE bit) about Code View.

Can put stuff in the waste basket if it's empty, but not if it's full. That's what I want, but I end up with an extra word in the output. Here's the code:

        if (GetBoolean(waste basket, "full")) {
          msg ("The waste basket is full. You cannot possibly stuff anything else into it.")
        }
        else {
          msg ("OK, you put the " + object + " into the waste basket.")
          SetObjectFlagOn (waste basket, "full")
        }

When I play the game, I get:

OK, you put the Object: key into the waste basket.

How do I get that word, "Object" out of there??


The + operator can either be used to add two numbers together, or to join two strings together.

You're using it on "OK, you put the " (which is a string) and object (which is an object).

When you treat an object as a string, it might be automatically converted into a string. This turns it into a string that looks like "Object: key".

You probably want to convert the name to a string yourself, using a function like GetDisplayAlias.

For example:

        if (GetBoolean(waste basket, "full")) {
          msg ("The waste basket is full. You cannot possibly stuff anything else into it.")
        }
        else {
          msg ("OK, you put the " + GetDisplayAlias (object) + " into the waste basket.")
          SetObjectFlagOn (waste basket, "full")
        }

GetDisplayAlias (object) gives you a string which contains the object's alias attribute if it has one, and its name otherwise. This is how almost all of Quest's built-in functions display an object.

An alternative would be GetDisplayName, which will generate a link if the object is visible.


Your suggestion worked perfectly, Mr. Angel. Now, I hate to be a pest, but I CANNOT get waste basket to behave as it should. My immediate problem is that when I put something into the waste basket, it stays in my inventory. When I type `I' there it still is.

Well, I thought I could fix this by studying the refrigerator in Code View. You put stuff in refrigerator, you don't have it anymore and it stays in refrigerator. But I can't find the code for that in Code View. (Or maybe I can find it but don't recognize it.)

My next idea was to move the object to the waste basket. And that works IF you have only one object to move AND it happens to be the one you put in the waste basket. In the code below, I move the key to the waste basket. If I do indeed put the key into the waste basket, the code works perfectly. Unfortunately, if I put something else into the waste basket, the key goes into it.

I type "Put flour in waste basket," and then "Examine waste basket," and there's the key.

So how can I make the waste basket accept whatever object I put into it and simultaneously remove that object from my inventory??

      <inherit name="editor_object" />
      <inherit name="container_open" />
      <take />
      <alt type="stringlist">
        <value>wb</value>
      </alt>
      <feature_container />
      <close type="boolean">false</close>
      <listchildren />
      <open type="boolean">false</open>
      <transparent type="boolean">false</transparent>
      <look type="script">
        if (GetBoolean(waste basket, "full")) {
          msg ("The waste basket is overflowing with putrid offal and trash.")
        }
        else {
          msg ("A normal, plastic waste basket, eighteen (or so) inches tall. It is currently empty.")
        }
      </look>
      <ontake type="script">
        msg ("You are now holding the waste basket. Big whoop.")
      </ontake>
      <addscript type="script">
        if (GetBoolean(waste basket, "full")) {
          msg ("The waste basket is full. You cannot possibly stuff anything else into it.")
        }
        else {
          msg ("OK, you put the " + GetDisplayAlias (object) + " into the waste basket.")
          SetObjectFlagOn (waste basket, "full")
          MoveObject (key, waste basket)
        }
      </addscript>
    </object>
  </object>

You have the line:

          MoveObject (key, waste basket)

You have two expressions in there, technically. One is key, the other is waste basket.

When an expression is a bare word like that, Quest does 3 things:

  1. If the object is the name of a local variable, it uses that variable.
  2. If it's not a local variable, but is the name of an object, it uses that object.
  3. If it's neither of those, cause an error.

Obviously, putting the name of an object in your code will result in it always doing the thing to the same object, so '2' is no good for you, and you don't want an error. So part '1' of that process will help.

You need a local variable - which can hold any type of data, but right now you need one that's an object.

The local variables available within and addscript are (in addition to any you created):

  • object - the object that is being put in something
  • destination - the object it's being put into
  • this - the object that 'owns' the script. You can normally identify this in the editor by looking which object you are currently editing

Using these variables is usually a good idea.
So you would want something like:

          MoveObject (object, destination)

or

          MoveObject (object, this)

You can use whichever is easier for you to understand :)

Now, technically you could also do:

          MoveObject (object, waste basket)

but that's a bad habit to get into.

Maybe at some point in the future, another room will need a waste basket. So you might want to copy and paste the object, and put it in another room.
If you do that, you will need to go through all the copy's scripts, changing everywhere it says waste basket to waste basket2. This can be time consuming once you make more complex objects, and leaves little insidious bugs that are hard to track down if you miss one.

Using this instead of the object's name in your script means that a script will always refer to the right object; so you don't need to worry about it anymore. Stuff won't break if you clone the object, copy and paste it in the editor, or just change its name. So it's a good habit to get into.


Tangentially relevant: a common mistake people make is not using destination in drop scripts.
An object can have a script that runs when it is dropped. One common use for this is objects that are automatically switched off when they are dropped. Like a torch; someone might try:

msg ("The torch goes out as you drop it!")
SetObjectFlagOff (this, "lit")
MoveObject (this, game.pov.parent)

But you might not realise that commands like "put torch in cupboard" will also run the drop script (unless the cupboard has an addscript). So that script should be:

msg ("The torch goes out as you drop it!")
SetObjectFlagOff (this, "lit")
MoveObject (this, destination)

to ensure that putting the object into a container works properly. And also that rooms like the tightrope in my Circus game work properly. (objects dropped on the tightrope go to the ring below)

And on that subject, if you want your script to keep working as you do more complex things with it, it might be worth changing:

          MoveObject (object, destination)

to something like:

          if (HasScript (object, "drop")) {
            do  (object, "drop", QuickParams ("object", object, "destination", destination))
          }
          else {
            MoveObject (key, waste basket)
          }

so that if the object you're putting into the waste basket has a "when dropped" script, it will run that script rather than just moving it.


Thanks Mr. Angel. Now is there a way to use a local variable if you don't know to which object the variable will be referring?? I want to be able to empty the waste basket of whatever object happens to be in it.

Here is the code for waste basket. It's same as I posted in previous post except for a few lines at the end.

<object name="waste basket">
  <inherit name="editor_object" />
  <inherit name="container_open" />
  <take />
  <alt type="stringlist">
    <value>wb</value>
  </alt>
  <feature_container />
  <close type="boolean">false</close>
  <listchildren />
  <open type="boolean">false</open>
  <transparent type="boolean">false</transparent>
  <not_all />
  <look type="script">
    if (GetBoolean(waste basket, "full")) {
      msg ("The waste basket is overflowing with putrid offal and trash.")
    }
    else {
      msg ("A normal, plastic waste basket, eighteen (or so) inches tall. It is currently empty.")
    }
  </look>
  <ontake type="script">
    msg ("You are now holding the waste basket. Big whoop.")
  </ontake>
  <addscript type="script">
    if (GetBoolean(waste basket, "full")) {
      msg ("The waste basket is full. You cannot possibly stuff anything else into it.")
    }
    else {
      msg ("OK, you put the " + GetDisplayAlias (object) + " into the waste basket.")
      SetObjectFlagOn (waste basket, "full")
      MoveObject (object, this)
    }
  </addscript>
  <empty type="script">
    if (GetBoolean(waste basket, "full")) {
      msg ("You empty the waste basket")
      SetObjectFlagOff (waste basket, "full")
      RemoveObject (waste basket.child)
    }
    else {
      msg ("The waste basket is already empty.")
    }

As you see , I refer to contents of waste basket as "waste.basket child." From that fact that the code doesn't work and gives me and error message, I have deduced that's not the way to do it. If I just empty the waste basket, the item is still in it.

Here is the error I get:
"You empty the waste basket
Error running script: Error compiling expression 'object': RootExpressionElement: Cannot convert type 'Object' to expression result of 'Element'"

Sometimes, with your help, Mr. Angel, I think I'm just on the verge of understanding Quest. Of being able to do simple things, like emptying a waste basket. Then I get an error message like that.

RootExpressionElement: Cannot convert type 'Object' to expression result of 'Element'" <<

I mean, seriously, that makes absolutely no sense. Might as well be written in Martian. To me, it's pretty much what you'd expect if a cat walked on the keyboard.

Excuse me. I'm frustrated at my lack of progress and I'm sure you're frustrated at having to explain each tiny little step.


Hello.

MrAngel will probably post a better solution at some point, but, if you want something to work with:

    if (GetBoolean(waste basket, "full")) {
      msg ("You empty the waste basket")
      SetObjectFlagOff (waste basket, "full")
      // Make a list of all items in the waste basket
      items = GetDirectChildren (waste basket)
      // If the list has any items. . .
      if (list count (items) > 0){
        // Loop through each item
        foreach (o, items) {
          //NOTE: This next line moves the item(s) in the waste basket to the location of the waste basket; you might want to move the contents to game.pov.parent instead of waste basket.parent, or you might want to move it anywhere else you please
          MoveObject (o, waste basket.parent)
        }
      }
      else {
        // This means the waste basket had the "full" flag, but there was nothing in it.
        msg ("The waste basket is already empty.")
      }
    }
    else {
      //This means the waste basket had no "full" flag.
      msg ("The waste basket is already empty.")
    }

As you see , I refer to contents of waste basket as "waste.basket child." From that fact that the code doesn't work and gives me and error message,

That could work, but you would need to give waste basket.child a value. For example, in the add script you could add the line:

waste basket.child = object

local variables like object only exist until the end of the function that created them; so if you want to use them later, you save them by putting them into an attribute like this.

Alternatively, a more common approach would be to use GetDirectChildren to get the basket's children. Howver, this gives you an objectlist rather than an object, so you would change

RemoveObject (waste basket.child)

to

foreach (object, GetDirectChildren (waste basket)) {
  RemoveObject (object)
}

the foreach repeats the line inside it once for every object in the waste basket, setting object to a different thing each time. In your code this will usually be once, but foreach is often the simplest way to turn a list of a single item into an object variable


Well, I have accomplished my five goals with the waste basket. As stated in an earlier thread, I wanted to

Examine waste basket and tell if it's empty or full. This one I can do.
If it's empty, put stuff in it, thus making it full.
If it's full, get told I can't put any more into it.
Empty it.
Get told it's empty if I try to empty it while it's empty.

'Course, the first person singular pronoun is somewhat disingenuous. Basically, I had nothing to do with it. Mr. Angel, K V, and other posters, told me what to do at every step along the way. Question is, did I learn anything?? Hope so!

Ready to move on. Next chapter in Tutorial is "Status Attributes." I noticed this thread is the longest one on the Forum. Next time I have a question, I'll start a new thread.


I did my best to explain the logic and the thought process behind each step, so hopefully you could follow why I was doing things a certain way ^^

In reality, you don't really need scripts like this. Quest already has "limited containers", so you could just make the waste basket a container that can only hold 1 object. But it's a good problem to approach as a learning exercise.

One thing I would point out is that the full attribute can go out of sync with the state of the basket:

==> put key in basket
OK, you put the key into the waste basket.

==> remove key from waste basket
You pick it up.

==> put key in basket
The waste basket is full. You cannot possibly stuff anything else into it.

So in a real game, you would probably want to remove the full attribute, and stick to using:

if (ListCount (GetDirectChildren (waste basket)) > 0) {

to check if the basket is full.
This wouldn't have achieved the purpose of learning to use attributes, so I thought it would be a pointless distraction if I mentioned it earlier.


Thanks. I did notice that when I took something out of the waste basket, it was still full. Thought maybe it was something to do with "Take." Wondered if there was some embellishment to Take command I was supposed to use. Glad to get see it's easier than I thought.


Unfortunately there's no script that runs on a container when something is removed from it. You could do it by modifying the changedparent script of the defaultobject type; but that would be pretty complex.

Usually it's easier just to check the container's contents.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums