Shelf too high

Hi all,
So in my game, I have a shelf that is too high, so you have to stand on a chair to get the item.

if (not player.posture = "stand" and not player.posture_object = "chair") {
  msg ("You cannot reach it. The shelf is too high.")
}

So, the problem I've got now, is if the player wants to put something onto the shelf. Obviously with the shelf being too high, they'll need to be standing on the chair to do it, but how can I code the object that you're putting onto the shelf to restrict the take command.
In order to take the 'object' you're putting onto the shelf, you've got to be standing on the chair.

Hope you can help, thankyou.


Hmm… my first thought would be to do something when the player stands on the chair.

If the player stands on the chair:

shelf.isopen = true

and when they get off it:

shelf.isopen = false
shelf.transparent = true
shelf.blockingmessage = "You can't reach it."

That way, objects on the shelf aren't reachable and you don't need to mess around with individual take scripts.

Edit: Hmm… that works for taking object off the shelf, but results in getting a default "not open" message when trying to put something on it.

I can see one way to deal with the take script, but it's a bit awkward.


Normally it would be pretty simple to add a take script to an object; the shelf's addobject script would look like:

if (player.posture = "stand" and player.posture_object = "chair") {
  object.parent = this
  msg ("You put it on the shelf.")
  object.take => {
    if (player.posture = "stand" and player.posture_object = "chair") {
      AddToInventory (this)
      this.take = true
    }
    else {
      msg ("You cannot reach it. The shelf is too high.")
    }
  }
}
else {
  msg ("You cannot reach it. The shelf is too high.")
}

But that only works with objects that can be taken normally. If an object already has a take script, this would overwrite it.

If you need to deal with that situation, my solution would be to have a list of take scripts, which are processed one by one. So you'd give an object an attribute which is a list of take scripts, and then make its actual take script one which loops through that list running the functions one by one until it's taken. This gets to be a huge knot of code pretty fast, but there's nothing particularly difficult about it; just time-consuming to write.


I'm not trying to help, but this is what I have been doing with limitations. I add an if script, so that if player tries to take (or any other verb) without meeting requirements, then, move object to shelf or here (not inventory) or with exits, move player to room one, because the game runs through the scripts so quickly that no one actually sees the transition. Then I add the msg that explains why nothing happened.


Here's a thought (although it would need a small modification of some of the core functions).

If we make these modifications:

  <function name="ContainsReachable" type="boolean" parameters="parentObj, searchObj">
    return (ContainsAccessible(parentObj, searchObj, true) and not HasString (searchObj, "unreachablereason"))
  </function>

  <function name="CanReachThrough" type="boolean" parameters="obj">
    return (GetBoolean(obj, "isopen") and not GetBoolean(obj, "hidechildren") and not HasString (obj, "unreachablereason"))
  </function>

  <function name="BlockingMessage" parameters="blocked, prefix" type="string">
    if (HasString (blocked, "unreachablereason")) {
        obj = blocked
    }
    else {
      obj = GetBlockingObject(blocked)
    }
    if (HasString(obj, "blockingmessage")) {
      return (obj.blockingmessage)
    }
    else if (HasString(obj, "unreachablereason")) {
      return (obj.unreachablereason)
    }
    else {
      return (prefix + DynamicTemplate("ObjectNotOpen", obj))
    }
  </function>

Off the top of my head… I may have made an error there. But I think that then you could just do one extra line when the player gets on or off the chair:

  • shelf.unreachablereason = "It's too high to reach!"
  • shelf.unreachablereason = null

Giving the shelf an unreachablereason string attribute would then give that string as an error when the player tries to use most of the built-in commands on the shelf or on anything inside it. That will stop them taking objects off the shelf, putting objects on it, attempting to unlock it, or lick it, or anything else they might think of. (They will still be able to look at the shelf and any items on it, but anything else will tell them that they can't reach it).

I quite like that code (assuming that it works as I planned), because you could do other things with it as well. For example:

  • mosquito.unreachablereason = "It flies away whenever you try to grasp it."
  • lava.unreachablereason = "It's too hot to touch."

Perhaps the restriction should be on the shelf (defined as a surface) rather than the object? If so, the solution seems simple?


@DavyB:

Perhaps the restriction should be on the shelf (defined as a surface) rather than the object?

That's what I was thinking. Making it not open and changing the blockingmessage to "It's too high to reach." should work; except that when the player tries to put something on the shelf, it would say "It is not open." instead of a sensible message.
So I suggested a modification which would allow the reachable/visible distinction to apply for reasons other than being inside a closed container.

If my mental model of the scope system is correct, the modifications I just suggested should also give a sensible "It's too high to reach" message in response to a host of other commands, such as "put shelf in backpack", "use shelf", "take shelf", "eat shelf", "open shelf", and so on.


Thanks for all the help guys.

I did find a workable solution

So in the box, script to run when trying to add an object, i put this

if (not player.posture = "stand" and not player.posture_object = "chair") {
  msg ("You cannot reach " + object.article + ". The shelf is too high.")
}
else {
  MoveObject (object, shelf)
  SetObjectFlagOn (object, "TooHigh")
  msg ("Ok. You put " + object.article + " on the shelf.")
}

then I created a local command for the room called 'Take'
giving it the same command pattern as normal take #object#; get #object#; pick up #object#

Then giving it a script as follows

if (GetBoolean(object, "TooHigh")) {
  if (not player.posture = "stand" and not player.posture_object = "chair") {
    msg ("You cannot reach " + object.article + ". The shelf is too high.")
  }
  else {
    DoTake (object, multiple)
    SetObjectFlagOff (object, "TooHigh")
  }
}
else {
  DoTake (object, multiple)
}

Not sure if its the best solution, but it seems to work


This conversation was helpful for me in a few ways.

I also want to say that I LOVE Mr. Angel's suggestion for core modifications. I think I'm not only going to add it to my "Core3" that I've been building (probably mostly for myself). But I'll add an "object unreachable" checkbox to the inventory tab with a place to add the attribute if checked. I'll definitely credit Mr. Angel in the Core3 Integration for all his angelic work!


Nice way to do it :)

However, I have a few comments.

Firstly, the expression not player.posture = "stand" and not player.posture_object = "chair" looks wrong.

This means that they will get the too high message if they aren't standing and they're not on the chair. So if they're sitting on the chair, or their posture is standing but they're not on the chair, they will still be able to reach it.

What you probably want there is not (player.posture = "stand" and player.posture_object = "chair") or not player.posture = "stand" or not player.posture_object = "chair".

Secondly, if you're using a local command like that, you don't really need the TooHigh boolean. You could do something like making the shelf's addscript look like:

if (player.posture = "stand" and player.posture_object = "chair") {
  MoveObject (object, shelf)
  msg ("Ok. You put " + object.article + " on the shelf.")
}
else {
  msg ("You cannot reach the shelf. It is too high.")
}

and the room's take command:

if (Contains (shelf, object))) {
  if (not player.posture = "stand" or not player.posture_object = "chair") {
    msg ("You cannot reach " + object.article + ". The shelf is too high.")
  }
  else {
    DoTake (object, multiple)
  }
}
else {
  DoTake (object, multiple)
}

And thirdly, your local command might break "take all", because it doesn't seem to allow multiples. You should give the command an allow_all boolean, and update it so that:

took_something = false
shelfobjects = NewObjectList()
foreach (obj, object) {
  if (not multiple or (not Contains(game.pov, obj.parent) and not DoesInherit(obj.parent, "npc_type"))) {
    if (Contains (shelf, obj) and not (player.posture = "stand" and player.posture_object = "chair")) {
      list add (shelfobjects, obj)
    }
    else {
      DoTake (obj, multiple)
      took_something = true
    }
  }
}
if (ListCount (shelfobjects) > 0) {
  msg ("You couldn't reach " + FormatList (shelfobjects, ", ", " or ", "") + ". The shelf is too high.")
}
else if (multiple and not took_something) {
  msg (Template("NothingToTake"))
}

Hi guys, thanks for the help so far.

[This means that they will get the too high message if they aren't standing and they're not on the chair. So if they're sitting on the chair, or their posture is standing but they're not on the chair, they will still be able to reach it.]
I've tried both sitting on the chair and standing in the room, and both instances told that the shelf is too high.
Also tried the other suggestion of MrAngel

if (not (player.posture = "stand" and player.posture_object = "chair")) {
  msg ("You cannot reach it. The shelf is too high.")
}

but even if you're standing on the chair or not, the shelf is still too high.
Thanks though for the tip about 'Take All'. Yes it has stopped working in that room.


Hi guys,

Thankyou for all your help.
Finally figured out why this was not working properly

if (player.posture = "stand" and player.posture_object = chair) {
  this.take = true
  msg ("You pick " + this.article + " up.")
  AddToInventory (this)
}
else {
  msg ("The shelf is too high. You cannot reach.")
}

The posture_object that you are sitting on, standing on or reclining on does not need quotes ""


I would have suggested that… but I assumed that the example code you gave in your first post was correct. Without seeing the code that sets those attributes, I have to guess what you're setting them to.


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

Support

Forums