Help with creating a container where you can add stuff in it

Hello everyone, I need some advice or guide in order to make this happen. I am creating an RPG about an apocalypse and I want to make a backpack that you can carry around so that you can add stuff that you find in the way on it.

And it would be much better if I could do so with first displaying a list that shows you your inventory and you choose from there what to add to it (I know there is a ScopeInventory thing but I am not familiar with it, I would be glad if you helped me with that as well). How can I make this happen?

So far I am only concerned about the adding stuff to it part, that's the most important thing I need.

Thanks for reading and I appreciate your help.


Not quite sure I understand the question right. Are you saying you want to make a point-and-click interface to the "Put #object1# in #object2#" command?

If you give the backpack a 'pack' verb, it'd probably look something like:

ShowMenu ("What do you want to put in your backpack?", ScopeReachableInventory(), true) {
  o = GetObject(result)
  if (o = Backpack) {
    msg ("You can't put the backpack in itself!")
  }
  else if (not o = null) {
    o.parent = Backpack
  }
}

In this case, I used ScopeReachableInventory() rather than ScopeInventory(); so that if you're carrying a locked box, it won't let the player put the box's contents in their backpack.

If the backpack has a capacity limit, or there are objects that you can't put down, you might want to call the default "put ___ in ___" command in place of o.parent = Backpack. That way, it'll check whether or not you're allowed to put that object in something else, and whether the pack is full, and give the standard messages back to the player.

If the backpack is in your inventory, you might want to prevent the list showing things that are already in it. In that case, you'd replace ScopeReachableInventory() with ListExclude(ScopeReachableInventory(), GetAllChildObjects(Backpack))

Sorry for any errors, I can't get at Quest from here, so am answering off the top of my head.


(filler for getting my edited post, updated/posted)


just to add some more info, as 'mrangel' has it covered:

the 'scope' Scripts/Functions, create and return an Object List Variable VARIABLE

A List VARIABLE is similar to a String/Object VARIABLE, except it can hold/store multiple values:

String Attribute VARIABLE, example: player.alias = "HK"
Object (reference/pointer) Attribute VARIABLE, example: player.weapon = katana // the 'katana' has to be an actual existing Object

as can be seen, these can only hold/store a single value at a time: "HK" and 'katana'

whereas, a List VARIABLE, can store/hold multiple values at a time:

player.alias_stringlist_attribute = split ("HK; Joe; Jim; Jeff", ";")
// or:
player.alias_stringlist_attribute = NewStringList ()
list add (player.alias_stringlist_attribute, "HK")
list add (player.alias_stringlist_attribute, "Joe")
list add (player.alias_stringlist_attribute, "Jim")
list add (player.alias_stringlist_attribute, "Jeff")

// the 'katana', 'claymore', 'battle_hammer', and 'battle_axe', all have to be actual existing Objects:
player.weapon_objectlist_attribute = NewObjectList ()
list add (player.weapon_objectlist_attribute, katana)
list add (player.weapon_objectlist_attribute, claymore)
list add (player.weapon_objectlist_attribute, battle_hammer)
list add (player.weapon_objectlist_attribute, battle_axe)


what makes Lists so useful, is that you can then iterate through their items:

foreach (item_variable, LIST) {
  // scripting using as for this example: 'item_variable'
}

for an example:

create ("joe")
joe.run_laps => msg ("Joe runs laps")

create ("jim")
jim.run_laps => msg ("Jim runs laps")

create ("jeff")
jeff.run_laps => msg ("Jeff runs laps")

create ("jack")
jack.run_laps => msg ("Jack runs laps")

create ("team_object")
team_object.team_list = NewObjectList ()
list add (team_object.team_list, joe)
list add (team_object.team_list, jim)
list add (team_object.team_list, jeff)
list add (team_object.team_list, jack)

foreach (team_member, team_object.team_list) {
  do (team_member, "run_laps")
}

// --------------------------

conceptually, how 'foreach' works:

// team_member = joe
do (team_member, "run_laps")
// do (joe, "run_laps")

// team_member = jim
do (team_member, "run_laps")
// do (jim, "run_laps")

// team_member = jeff
do (team_member, "run_laps")
// do (jeff, "run_laps")

// team_member = jack
do (team_member, "run_laps")
// do (jack, "run_laps")

and for selecting which/what range of items (what/which items) to iterate through, there's the: 'for' Script/Function, as well.

The 'foreach' does ALL ('each/every/all' --- 'for-EACH') items


here's more detailed guides:

http://textadventures.co.uk/forum/samples/topic/5559/attributes-and-if-script-guide-by-hk
http://textadventures.co.uk/forum/samples/topic/5137/list-and-dictionary-extensive-guide-by-hk

ask if you need help with anything


After testing out mrangel's code (which works out of the box), I added and changed a few things (just because he noted his lack of Quest access):


    <object name="Backpack">
      <inherit name="editor_object" />
      <inherit name="container_open" />
      <feature_container />
      <pack type="script"><![CDATA[
        objects = ListExclude(ScopeReachableInventory(), GetAllChildObjects(Backpack))
        objects = ListExclude(objects,Backpack)
        if (ListCount(objects)>=1) {
        }
        ShowMenu ("What do you want to put in your backpack?", objects, true) {
          o = GetObject(result)
          if (o = Backpack) {
            msg ("You can't put the backpack in itself!")
          }
          else if (not o = null) {
            PackBackpack (o)
          }
        }
      ]]></pack>
      <take />
      <alias>backpack</alias>
      <listchildren />
    </object>
  <function name="PackBackpack" parameters="object1">
    // put object1 in/on object 2
    object2 = Backpack
    canbedropped = true
    if (HasBoolean(object1, "drop")) {
      if (not object1.drop) {
        canbedropped = false
      }
    }
    if (object1.parent = object2) {
      msg (DynamicTemplate("AlreadyThere", object1))
    }
    else if (not ListContains(ScopeInventory(), object1)) {
      msg (DynamicTemplate("NotCarrying", object1))
    }
    else if (not canbedropped) {
      msg (DynamicTemplate("ObjectCannotBeStored", object1))
    }
    else if (not ListContains(ScopeReachable(), object1)) {
      msg (DynamicTemplate("ObjectNotOpen", GetBlockingObject(object1)))
    }
    else if (not ListContains(ScopeReachable(), object2)) {
      msg (DynamicTemplate("ObjectNotOpen", GetBlockingObject(object2)))
    }
    else if (not object2.container) {
      msg (Template("CannotDoThat"))
    }
    else if (not object2.isopen) {
      msg (DynamicTemplate("ObjectNotOpen", object2))
    }
    else {
      if (GetBoolean(object2, "hidechildren")) {
        object2.hidechildren = false
      }
      // if (HasDelegateImplementation(object2, "addscript")) {
        // rundelegate (object2, "addscript", object1)
        // }
      params = NewDictionary()
      dictionary add (params, "object", object1)
      dictionary add (params, "destination", object2)
      if (HasScript(object2, "addscript")) {
        do (object2, "addscript", params)
      }
      else if (HasScript(object1, "drop")) {
        do (object1, "drop", params)
      }
      else {
        object1.parent = object2
        msg (Template("Done"))
      }
    }
    // must be carrying object1
    // item cannot be dropped
    // object1 must not be inside a closed container
    // object2 must not be inside a closed container
    // object2 must be an open container or surface
  </function>

The function is the script from the "put ___ in ___" command, but I modified it just a little bit and made it a function, so there's no need to use HandleSingleCommand("put "+GetDisplayAlias(o)+" in backpack").



NOTE:

This is pending mrangel's approval.


The function is the script from the "put ___ in ___" command, but I modified it just a little bit and made it a function, so there's no need to use HandleSingleCommand("put "+GetDisplayAlias(o)+" in backpack").

I wouldn't have used that anyway; calling the parser is probably the slowest part of any script, and we already know which command's script we need to call. I'd likely have done something like:

params = NewDictionary()
dictionary add (params, "object1", o)
dictionary add (params, "object2", backpack)
invoke (put.script, params)

(assuming put is the name of the "put ___ in ___" command. But now I'm wondering, would it be better to use do(put, "script", params)?)

In the case of KV's code, there's a little redundancy. As you're removing the backpack from the list of objects before you show the menu, it can't be selected. So the if (o = Backpack) check will never be true. (The check for o being null is unlikely to be true; but could be if a timer script destroys the object while the player is looking at the menu)

PackBackpack also does some checks that initially seem redundant: That you're carrying object1, that it's not the backpack, and that it isn't already in the backpack. But I'd say it's better to have those, because it's possible for a timer event to move objects after the list has been displayed but before the player chose an option.


Aha!

Using invoke is very slick!

I'll be right back...


EDIT

I can't believe I've been using HandleSingleCommand() all this time instead of doing that! (KV trashes the room. ...then nonchalantly straightens everything back up and pretends it didn't just happen.)


How about this, mrangel?

It works well for me:

objects = ListExclude(ListExclude(ScopeReachableInventory(), GetAllChildObjects(backpack)),backpack)
if (ListCount(objects)>=1) {
  ShowMenu ("What do you want to put in your backpack?", objects, true) {
    o = GetObject(result)
    params = NewDictionary()
    dictionary add (params, "object1", o)
    dictionary add (params, "object2", backpack)
    invoke (put.script, params)
  }
}
else {
  msg ("You're not carrying anything you can pack at the moment.")
}

The backpack object:

<object name="backpack">
      <inherit name="editor_object" />
      <inherit name="container_open" />
      <feature_container />
      <take />
      <alias>backpack</alias>
      <listchildren />
      <pack type="script"><![CDATA[
        objects = ListExclude(ListExclude(ScopeReachableInventory(), GetAllChildObjects(backpack)),backpack)
        if (ListCount(objects)>=1) {
          ShowMenu ("What do you want to put in your backpack?", objects, true) {
            o = GetObject(result)
            params = NewDictionary()
            dictionary add (params, "object1", o)
            dictionary add (params, "object2", backpack)
            invoke (put.script, params)
          }
        }
        else {
          msg ("You're not carrying anything you can pack at the moment.")
        }
      ]]></pack>
      <alt type="stringlist">
        <value>back pack</value>
      </alt>
    </object>

Actually I have an idea.

You have a room where you store all the items in.
You have an object with a verb to move other objects to your inventory.

You'd just have to send the objects to the other room. Then with the object in your inventory, you use it to send other objects you want to your inventory.

I might actually use that.


KV: Yep, that's exactly what I was thinking :) I didn't post it myself because I wasn't sure the name of the command (like I think the look command is named "lookat" or something, so I wasn't sure if it was "put" or "putin")


Awesome!

You said you couldn't test it. So, I thought I'd be Pinky to your Brain.

So... what are we gonna do today, Brain?


We all like Pinky and the Brain from Animaniacs, right?


In the key of C:

mrangel is a genius.

KV's insane.


Log in to post a reply.

Support

Forums