Dropping a bag.

Starve.
26 Oct 2020, 03:36

So, I'm making a thing for an English assignment in this, and I want there to be a small chance that if the player takes off a backpack while it's open, it can spill it's contents everywhere on the ground, being a reason why you should keep the bag closed.
How does this happen?


mrangel
26 Oct 2020, 13:43

When you say "takes off a bag", do you mean dropping the bag, or removing it (if it's wearable?)

In the case of dropping it, you can add a script to run when the bag is dropped. On the 'Inventory' tab, change its drop behaviour from 'Default behaviour' to 'Run script'.

The script will then be run instead of dropping the bag. So as well as spilling the contents, you need to remember to move the bag itself.

I'd suggest a script something like:

this.parent = destination
msg ("You put it down.")
if (this.isopen) { 
  foreach (object, GetDirectChildren (this)) {
    if (RandomChance (60)) {
      msg (CapFirst (GetDisplayName (object)) + " spills out onto the floor.")
      object.parent = destination
    }
  }
}

A quick explanation of how that works. If you'd rather work in the GUI script editor, just go into code view long enough to paste the code in. You can easily see how the code translates to the GUI.

I'll explain at a very basic level, as I don't know how much programming experience you have.

  • this.parent = destination
    This is the same as MoveObject (this, destination); more efficient but not quite as easy to read.
    • On any script, this is the object the script belongs to. So the bag in this case.
    • In the 'drop' script, the variable destination holds the place where the player is trying to drop the item. This is usually the current room, but doesn't have to be. For example, in my Circus game, dropping an object on the tightrope moves it to the ground below. And if the player types "put bag in locker", destination will be the locker.
  • if (this.isopen) {
    • The isopen property of a container determines if it's open.
  • foreach (object, GetDirectChildren (this)) {
    Loops over the objects inside the bag. GetDirectChildren finds all objects that are inside the bag.
  • if (RandomChance (60)) {
    Each object has a 60% chance of being dropped. So you'll find that a little over half the items in the bag will spill out. Change the number until you get the results you want.
  • msg (CapFirst (GetDisplayName (object)) + " spills out onto the floor.")
    Tells the player what they have dropped. We use GetDisplayName to get the alias of the object, and CapFirst to make the first letter of the sentence a capital.
  • object.parent = destination

If I was doing this, I might end up making the script a little more complex. Something like:

this.parent = destination
message = "You put " + this.article
dropped = NewObjectList()
if (GetBoolean (this, "isopen")) {
  // Get a list of objects in the bag which are visible
  droppable = FilterByAttribute (GetDirectChildren (this), "visible", true)
  // If it's possible for there to be items in the bag that the player isn't capable of dropping, uncomment this line:
  droppable = FilterByNotAttribute (droppable, "drop", false)
}
else {
  droppable = NewObjectList()
}
// Don't bother running all this script if the bag is closed or empty
if (LictCount (droppable) > 0) {
  if (destination = game.pov.parent or destination = game.pov.parent.dropdestinations) {
    message = message + " down"
    floorchance = 0
  }
  else {
    if (DoesInherit (destination, "surface")) {
      message = message + " on "
    }
    else {
      message = message + " in "
    }
    message = message + GetDefiniteName(destination)
    if (HasInt (destination, "maxobjects")) {
      floorchance = 15 + 85 * ListCount (GetDirectChildren (destination)) / destination.maxobjects
    }
    else {
      floorchance = ListCount (GetDirectChildren (destination)) * 15 + 10
    }
    if (HasObject (game.pov.parent, "dropdestination")) {
      floor = game.pov.parent.dropdestination
    }
    else {
      floor = game.pov.parent
    }
  }
  foreach (obj, droppable) {
    if (RandomChance (60)) {
      if (RandomChance (floorchance)) {
        floorchance = floorchance + 10
        if (HasScript (obj, "drop")) {
          do (obj, "drop", QuickParams ("destination", floor))
        }
        else {
          obj.parent = floor
        }
      }
      else {
        if (HasInt (destination, "maxobjects")) {
          floorchance = floorchance + 85 / destination.maxobjects
        }
        else {
            floorchance = floorchance * 1.2
        }
        if (HasScript (destination, "addscript")) {
          do (destination, "addscript", QuickParams ("destination", destination, "object", obj))
        }
        else if (HasScript (obj, "drop")) {
          do (obj, "drop", QuickParams ("destination", destination))
        }
        else {
          obj.parent = destination
        }
      }
      // an object with a dropscript might not have been moved
      // so check that it was moved before describing it
      if (not obj.parent = this) {
        list add (dropped, obj)
      }
    }
  }
  if (ListCount (dropped) = 1) {
    message = message + ", but it is open and " + GetDisplayName (ObjectListItem (dropped, 0)) + " falls out"
  }
  else if (ListCount (dropped) > 8) {
    message = message + ", but it is open and the contents spills out"
  }
  else if (ListCount (dropped) > 0) {
    message = message + ", but it is open and " + FormatList(dropped, ", ", ", and") + " fall out"
  }
}
msg (message + ".")

Changes made here:

  • The messages are a little more detailed ("You put it on the table." for example, or "You put it down, but it is open and a banana falls out.")
  • If you put the bag in a box, locker, etc, spilled objects will be divided between the locker and the floor. This seems more realistic to me.
  • Rather than listing all the objects that you dropped one per line, it uses FormatList to make a list of them.
  • Works correctly if the player's putting the bag in a container that has an addscript, or if the objects inside the bag have scripts to run when they are dropped.
  • Works with putting the bag into a limited container which allows a certain number of objects (if you put the bag in a locker that only allows 2 objeects, one object could fall out of the bag into the locker, and the rest would fall on the floor)
    • (we don't bother about maxvolume, because the player wouldn't be allowed to put the bag there so the script would never run)