Getting ALL from a container in Adventuron

In this bit of experimental code for a container, provided by Chris A, PUT ALL IN POCKET works, but GET ALL FROM POCKET or GET ALL IN POCKET doesn’t (“You can’t get anything”). Not having much experience with coding, I can’t figure out what is wrong here…any ideas?

start_at                 = my_location
locations {
   my_location      : location "You are in a room." ;
}

objects {
   coin  : object "a coin"     at = "container_pocket" msg = "A gold coin." ;
   spoon : object "a spoon"    at = "inventory"   ;
   sword : object "a sword"    at = "my_location" { traits = [notpockatable_t] }

   // Not strictly necessary, but the player should know to check their pockets.
   jeans : object "some jeans" at = "inventory" {
      traits          = [notpockatable_t]
      initially_worn  = true
      wearable        = true
      msg             = Regular jeans with all the standard features.
   }

   container_pocket : object "a pocket" conspicuous="false" container_type="bag" at = "jeans" {
      experimental_container_accessibility_expression -> (has_looked_in_pocket)
   }
   
}

collections {
   list_object_buffer : list;
}

booleans {
   is_subject1_in_pocket    : dynamic_boolean {(s1_location{} == "container_pocket")}
   is_subject1_in_inventory : dynamic_boolean {(s1_location{} == "inventory")}
   has_looked_in_pocket     : boolean;
}

integers {
   pocket_item_limit : integer "2";
   pocket_item_count : dynamic_integer {( child_count "container_pocket" )}
}

on_command {
   : gosub "subroutine_pocket_management" ;
}

traits {
   notpockatable_t : trait;
}

subroutines {
   subroutine_pocket_management : subroutine {
      : if (is_carried "jeans") {
         : match "examine _;get _;wear _"  {
            // TODO :: Need to make the system examine function aware of container accessibility
            : if (has_looked_in_pocket == false && parent_of (s1()) == "container_pocket") {
               : nope;
            }
         }
         // Take the item from pocket if pocket is noun2 or nothing valid provided for noun2
         : if (verb_is "get" && (noun2_is ("pocket") || noun2_is ("")) && has_looked_in_pocket && is_subject1_in_pocket ) {
            : remove_from_container "container_pocket";
            : done;
         }
         : match "get all"  {
            : if (noun2_is "pocket" && has_looked_in_pocket) {
               : do_all "container_pocket";
               : done ;
            }
         }
         : match "look pocket" {
            : set_true "has_looked_in_pocket" ;
            : append   "Inside the pockets of your jeans you notice\s" ;
            : look_inside
               of               = "container_pocket"
               extract_the      = "description"
               store_results_in = "list_object_buffer"
               make_known       = "true"
            ;
            : print_list_verbose  "list_object_buffer" lead_in="" when_empty = "nothing."  ;
            : return ;
         }   
         : match "put _"  {
            : match "put all"  {
               : if (noun2_is "pocket" && has_looked_in_pocket) {
                  : do_all "inventory_notworn";
                  : done ;
               }
            }
             : if (noun2_is ("pocket")  && s1_has_trait "notpockatable_t" == false) {
               : if ( is_subject1_in_inventory && has_looked_in_pocket) {
                  : if (pocket_item_count == pocket_item_limit) {
                     : print "You can't put any more items in your pocket!." ;
                  }
                  : else {
                     : insert_in_container "container_pocket";
                  }
                  : done;
               }
            }
         }
      }
   }
   
   
}

Hello Chris,

Adventuron currently lets its get all commands take priority, which can cause a problem if you are trying to do something specific. The reason for this is that a lot of authors seem to match “get _” and “drop _” which would then stop Adventuron’s get all commands executing (if a user command executes, it overrides the system command).

So, Adventuron essentially pastes the following code (secretly) at the top of on_command:

   : match "get all"    { : do_all "current_location_objects"; }
   : match "drop all"   { : do_all "inventory_notworn"; }
   : match "wear all"   { : do_all "inventory_notworn"; }
   : match "remove all" { : do_all "inventory_worn"; }

The good news is that you can override this behaviour using the following setting (treat this as experimental for now as I think I want to change the configuration name and values).

game_settings {
   enable_standard_all_behaviour = false
}

You’ll need to add the default handlers in yourself, but place then at the bottom of your on_command block, being careful not to match get _, drop _, wear _, and remove _ yourself.

The adapted code is as follows:

start_at                 = my_location

locations {
   my_location      : location "You are in a room." ;
}

objects {
   coin  : object "a coin"     at = "container_pocket" msg = "A gold coin." ;
   spoon : object "a spoon"    at = "inventory"   ;
   sword : object "a sword"    at = "my_location" { traits = [notpockatable_t] }

   // Not strictly necessary, but the player should know to check their pockets.
   jeans : object "some jeans" at = "inventory" {
      traits          = [notpockatable_t]
      initially_worn  = true
      wearable        = true
      msg             = Regular jeans with all the standard features.
   }

   container_pocket : object "a pocket" conspicuous="false" container_type="bag" at = "jeans" {
      experimental_container_accessibility_expression -> (has_looked_in_pocket)
   }
   
}



collections {
   list_object_buffer : list;
}

booleans {
   is_subject1_in_pocket    : dynamic_boolean {(s1_location{} == "container_pocket")}
   is_subject1_in_inventory : dynamic_boolean {(s1_location{} == "inventory")}
   has_looked_in_pocket     : boolean;
}

integers {
   pocket_item_limit : integer "2";
   pocket_item_count : dynamic_integer {( child_count "container_pocket" )}
}

// Start of change 1
game_settings {
   enable_standard_all_behaviour = false
}
// End of change 1

on_command {
   : gosub "subroutine_pocket_management" ;
   // Start of change 2
   : match "get all"    { : do_all "current_location_objects"; }
   : match "drop all"   { : do_all "inventory_notworn"; }
   : match "wear all"   { : do_all "inventory_notworn"; }
   : match "remove all" { : do_all "inventory_worn"; }
   // End of change 2
}

traits {
   notpockatable_t : trait;
}

subroutines {
   
   subroutine_pocket_management : subroutine {

      : if (is_carried "jeans") {
      
         : match "examine _;get _;wear _"  {
            // TODO :: Need to make the system examine function aware of container accessibility
            : if (has_looked_in_pocket == false && parent_of (s1()) == "container_pocket") {
               : nope;
            }
         }
         
         // Take the item from pocket if pocket is noun2 or nothing valid provided for noun2
         : if (verb_is "get" && (noun2_is ("pocket") || noun2_is ("")) && has_looked_in_pocket && is_subject1_in_pocket ) {
            : remove_from_container "container_pocket";
            : done;
         }

         : match "get all"  {
            : if (noun2_is "pocket") {
               : if (has_looked_in_pocket) {
                  : do_all "container_pocket";
                  : done ;
               }
            }
         }

         : match "look pocket" {
            : set_true "has_looked_in_pocket" ;
            : append   "Inside the pockets of your jeans you notice\s" ;
            : look_inside
               of               = "container_pocket"
               extract_the      = "description"
               store_results_in = "list_object_buffer"
               make_known       = "true"
            ;
            : print_list_verbose  "list_object_buffer" lead_in="" when_empty = "nothing."  ;
            : return ;
         }   
         
         : match "put _"  {
            : match "put all"  {
               : if (noun2_is "pocket" && has_looked_in_pocket) {
                  : do_all "inventory_notworn";
                  : done ;
               }
            }
             : if (noun2_is ("pocket")  && s1_has_trait "notpockatable_t" == false) {
               : if ( is_subject1_in_inventory && has_looked_in_pocket) {
                  : if (pocket_item_count == pocket_item_limit) {
                     : print "You can't put any more items in your pocket!." ;
                  }
                  : else {
                     : insert_in_container "container_pocket";
                  }
                  : done;
               }
            }
         }
         
      }
   }
   
   
}

Chris

1 Like

That works - thanks Chris.

Inline content lists is currently not supported in the engine (but will come eventually).

You can code something like this however. The code is not too fancy, and would need to be replicated for each container in your game currently. A general solution to all of this is forthcoming that would involve close to zero custom code. Treat this as a workaround, and not anything that I’m overly proud of.

on_describe {
   
   : if (is_present "cupboard" && child_count "cupboard" > 0) {
      : append   {("Inside the cupboard is\s" )}
      : look_inside
         of               = "cupboard"
         extract_the      = "description"
         store_results_in = "list_object_buffer"
         make_known       = "true"
      ;
      : print_list_verbose  "list_object_buffer" lead_in="" when_empty = "nothing."  ;
      : return ;
   }
   
}

Ok, I get it, thanks. Will see what I can cobble together with this. If only the world was not so full of containers!

Aha! That explains something. I had reported this issue some time back. As you discovered, PUT ALL IN CONTAINER works, but GET ALL FROM CONTAINER doesn’t. Now we know why. More importantly, there is a workaround. I must try that.

Yes, I know I’m not the only one wrestling with the great Adventuron container conundrum(s).

Given that you can append the contents of a dynamic string to the object description (as I’ve discovered whilst fooling around with this), is there a way to get the contents of the look_inside list into a dynamic string? Ok, probably not - but worth asking just in case!

Otherwise, I can live with the workaround that you have gracefully (if shamefully) provided.

Adventuron will support this kind of layout natively, but until then, you could set up a string variable in on_pre_describe {}. You can’t use dynamic strings to call commands by design so there is not really a way to make this any simpler until Adventuron comes with this kind of object list layout setting.

Make sure you are running the latest beta.

start_at                 = my_location

locations {
   my_location      : location "You are in a room." ;
}

objects {
   cupboard : scenery "{cupboard_description}" at = "my_location" container_type="bag";
   book : object "a book" at = "cupboard" ;
   bowl : object "a bowl" at = "cupboard" ;
}

collections {
   list_object_buffer : list;
}

strings {
   cupboard_description : string;
}

on_pre_describe {
   : if (is_present "cupboard") {
      : set_string var = "cupboard_description"  text = "a cupboard" ;
      : if (child_count "cupboard" > 0) {
         : look_inside
            of               = "cupboard"
            extract_the      = "description"
            store_results_in = "list_object_buffer"
            make_known       = "true"
         ;
         : print_list_verbose  "list_object_buffer"
            lead_in       = " (containing "
            final_part    = ")"
            append_to_var = "cupboard_description"
         ;
      }
   }
}

Thanks Chris. This does work to an extent, although there are then oddities with the ‘put’ system message (eg ‘you put the book in the cupboard (containing a bowl)’) that I can’t figure out how to resolve other than just changing the message to not reference the container (eg ‘you put it in there’).

Also, is it possible to check if something is contained? Is_within only seems to work for an object in a location, not an object inside an object. The reason for this is to see if an object is in a container and then get it if the container is present and accessible. Otherwise I put the book in the cupboard, but then I have to ‘get book out of cupboard’ to get it, rather than just getting the book (currently = ‘the book is not here’)

If all of this is too complicated and too much like asking for a full implementation of containers then don’t worry: I’ll just stick with my old method of only allowing the relevant things to go into the relevant containers and tracking it with booleans.

Oh dear! That’s the problem with workarounds.

Of course, you could set the message for the container back to normal at the top of on_pre_command {}. The message only has to be changed until the layout of a screen has completed.

on_pre_command {
   : if (true) {
      : mask {
         : set_string var = "cupboard_description" text = "a cupboard" ;
      }
   }
}

On a separate note, please update to 55q, and is_within should work properly.

Proper container support won’t require any of this code. I’m so sorry for all these workarounds.

No need to apologise: I’m just checking that you’re paying attention.

The above works, and also ‘is_within’ works (I’m using the beta version for the actual game that I’m wrestling with, but the version with this test code was in a different browser running the current stable version; hence it didn’t work).

As an aside, it possible to give more of a prompt in the autocomplete for is_within? I find the syntax hard to remember and I have to look in the manual every time for the outer ="" and inner ="" bit.

I don’t think I can add is_within “” to the classroom version, it’s just too complication a concept I think.

I was going to release an “advanced” version of adventuron with the autocomplete not hiding anything, but I am tempted to add a hidden advanced mode to classroom until that version is ready to launch.

Please give me a bit of time with that, in the meantime, use the great power of CONTROL + F to copy and paste is_within {} in the knowledge that I’m definitely going to sort this out - later.

I’ll give you 5 mins to sort it out.

Actually, what I meant was (in the beta version), giving more than: ‘is_within {}’ for the autocomplete. Like 'is_within { outer = “” inner = “” } ’ which tells you that the outer and inner thing is required. Not a big deal, but would avoid precious seconds lost trying to remember the syntax and then scurrying off to the cook book.

Doh.

I’ll try to sort it out.

In the meantime, after autocompleting, go to a blank line between the two {} characters of the is_within, and press control + space. All will be revealed.

I’ve stuck all these bits of code together and it does make a working container configuration that does what I want it to do (lists the objects in the container when the container is open). Here’s the final code for the benefit of anyone else who want to do this. Thanks Chris!

start_at                 = my_location

locations {
   my_location      : location "You are in a room." ;
}

objects {
   coin  : object "a coin"     at = "my_location" msg = "A gold coin." ;
   spoon : object "a spoon"    at = "my_location"   ;
   
   apple : object "an apple" at = "my_location" ;
   
   sword : object "a sword"    at = "my_location" { traits = [notpockatable_t] }


   box : object "{box_description}" container_type="bag" at = "my_location" {
   }
   
}


collections {
   list_object_buffer : list;
}

booleans {

   boxopen     : boolean ;
}

integers {
   box_item_limit : integer "2";
}

strings {
   
   box_description : string;
   
}

game_settings {
   enable_standard_all_behaviour = false
}

on_pre_describe {
   : if (is_present "box") {
      : set_string var = "box_description"  text = "a box" ;
      : if (child_count "box" > 0) {
      : if (boxopen) {
         
      
      
         : look_inside
            of               = "box"
            extract_the      = "description"
            store_results_in = "list_object_buffer"
            make_known       = "true"
         ;
         : print_list_verbose  "list_object_buffer"
            lead_in       = " (containing "
            final_part    = ")"
            append_to_var = "box_description"
         ;
         }
      }
   }
}



on_pre_command {
   : if (true) {
      : mask {
         : set_string var = "box_description" text = "a box" ;
      }
   }
}

on_command {
   : gosub "subroutine_box_management" ;
   
: match "open box"  {
: if (!boxopen) {
   : print "you open the box." ;
   : set_true "boxopen" ;
   
}
}
: match "close box"  {
   : if (boxopen) {
      : print "you close the box." ;
      : set_false "boxopen" ;
      
   }
   
}

: match "inventory-"  {
     : if (is_present "box") {
      : set_string var = "box_description"  text = "a box" ;
      : if (child_count "box" > 0) {
      : if (boxopen) {
         
      
      
         : look_inside
            of               = "box"
            extract_the      = "description"
            store_results_in = "list_object_buffer"
            make_known       = "true"
         ;
         : print_list_verbose  "list_object_buffer"
            lead_in       = " (containing "
            final_part    = ")"
            append_to_var = "box_description"
         ;
         }
      }
   }
   : inventory;
   
}

   : match "get all"    { : do_all "current_location_objects"; }
   : match "drop all"   { : do_all "inventory_notworn"; }
   : match "wear all"   { : do_all "inventory_notworn"; }
   : match "remove all" { : do_all "inventory_worn"; }
 
}

traits {
   notpockatable_t : trait;
}

subroutines {
   
   subroutine_box_management : subroutine {

      : if (is_present "box") {
         : match "examine _;get _;wear _"  {
            : if (boxopen == false && parent_of (s1()) == "box") {
               : nope;
            }
         }
    
         : if (verb_is "get" && (noun2_is ("box") || noun2_is ("")) && boxopen && s1_location{} == "box" ) {
            : remove_from_container "box";
            : done;
         }

         : match "get all"  {
            : if (noun2_is "box") {
               : if (boxopen) {
                  : do_all "box";
                  : done ;
               }
            }
         }

         : match "look box" {
            : set_true "boxopen" ;
            : append   "Inside the box you see \s" ;
            : look_inside
               of               = "box"
               extract_the      = "description"
               store_results_in = "list_object_buffer"
               make_known       = "true"
            ;
            : print_list_verbose  "list_object_buffer" lead_in="" when_empty = "nothing."  ;
            : return ;
         }   
         
         : match "put all"  {
               : if (noun2_is "box") {
               : if (boxopen) {
                  : do_all "inventory_notworn";
                  : done ;
               }
           : else {
              : print "But the box is not open!" ;
              : done ;
              
           }
           
            }
            }
            
         
        : match "put _"  {
        : if (noun2_is "box") {
        : if (s1_location{} == "inventory") {
        : if (boxopen) {
           : if (s1_has_trait "notpockatable_t"==true) {
              : print {("You can't fit the "+s1()+" in the box!")} ;
              
           }
           : else {
                 : if (child_count "box"==box_item_limit) {
                    : print "You can't fit any more items in the box." ;
                 }
                 : else {
                    : insert_in_container "box";
                 }
  
           }
           
        }
    : else {
       : print "But the box is not open." ;
       
    }
        }
        : else {
           : print "You're not carrying it!" ;
           
        }
        
        }
      
        
        }

            }
         }
      }
         

Sorry it’s so long winded. It’ll be trivial to do all this before the next (Adventuron) jam starts.

Anyway, I tried the solution and I think you need to let the player be aware of the box state of closed somewhere. When I examine the closed box it just tells me the contents of the box, which makes me feel like the box is not closed.

I see you are auto opening the box upon examination. If you want to retain that behaviour, then try something like this (in the EXAMINE BOX match handler):

            : if (boxopen == false) {
               : print "(Opening the box)." ;
               : set_true "boxopen" ;
            }

I also cleaned up some of the code, and I include it here

start_at                 = my_location

game_settings {
   enable_standard_all_behaviour = false
}

locations {
   my_location : location "You are in a room." ;
}

objects {
   spoon : object "a spoon"           at = "my_location" ;
   apple : object "an apple"          at = "my_location" ;
   coin  : object "a coin"            at = "my_location" msg = "A gold coin." ;
   sword : object "a sword"           at = "my_location" { traits = [notpockatable_t] }
   box   : object "{box_description}" at = "my_location" container_type="bag"  ;
}

collections {
   list_object_buffer : list;
}

booleans {
   boxopen : boolean ;
}

integers {
   box_item_limit : integer "2";
}

traits {
   notpockatable_t : trait;
}

strings {
   box_description : string;
}

on_pre_describe {
   : if (is_present "box") {
      : gosub "update_box_description" ;
   }
}

on_pre_command {
   : if (true) {
      : mask {
         : set_string var = "box_description" text = "a box" ;
      }
   }
}

on_command {
   : if (is_present "box") {
      : gosub "subroutine_box_management" ;
   }
   
   
   : match "get all"    { : do_all "current_location_objects"; }
   : match "drop all"   { : do_all "inventory_notworn"; }
   : match "wear all"   { : do_all "inventory_notworn"; }
   : match "remove all" { : do_all "inventory_worn"; }
 
}

subroutines {
   
   subroutine_box_management : subroutine {

      : match "open box"  {
         : if (!boxopen) {
            : print "You open the box." ;
            : set_true "boxopen" ;
            : gosub "update_box_description" ;
            : gosub "print_box_contents" ;
         }
      }
      
      : match "close box"  {
         : if (boxopen) {
            : print "you close the box." ;
            : set_false "boxopen" ;
            
         }
      }
   
      : match "inventory -"  {
         : gosub "update_box_description" ;
         : inventory;
      }

      : match "examine _;get _;wear _"  {
         : if (boxopen == false && parent_of (s1()) == "box") {
            : nope;
         }
      }
 
      : if (verb_is "get" && (noun2_is ("box") || noun2_is ("")) && boxopen && s1_location{} == "box" ) {
         : remove_from_container "box";
         : done;
      }

      : match "get all"  {
         : if (noun2_is "box") {
            : if (boxopen) {
               : do_all "box";
               : done ;
            }
         }
      }

      : match "look box" {
         : if (boxopen == false) {
            : append "You open the box. " ;
            : set_true "boxopen" ;
         }
         : gosub "print_box_contents" ;
      }
      
      : match "put all"  {
         : if (noun2_is "box") {
            : if (boxopen) {
               : do_all "inventory_notworn";
               : done ;
            }
            : else {
               : print "But the box is not open!" ;
               : done ;
            }
         }
      }
      
      : match "put _"  {
        : if (noun2_is "box") {
           : if (s1_location() == "inventory") {
               : if (boxopen) {
                  : if (s1_has_trait "notpockatable_t"==true) {
                     : print {("You can't fit the "+s1()+" in the box!")} ;
                  }
                  : else {
                     : if (child_count "box"==box_item_limit) {
                        : print "You can't fit any more items in the box." ;
                     }
                     : else {
                       : insert_in_container "box";
                     }
                  }
               }
               : else {
                  : print "But the box is not open." ;
               }
            }
            : else {
              : print "You're not carrying it!" ;
            }
         }
      }
   }

   update_box_description : subroutine {
      : set_string var = "box_description"  {((boxopen ? "a box" : "a closed box"))}
      
      : if (boxopen) {
         : if (child_count "box" > 0) {

            : look_inside
               of               = "box"
               extract_the      = "description"
               store_results_in = "list_object_buffer"
               make_known       = "true"
            ;
            : print_list_verbose  "list_object_buffer"
               lead_in       = " (containing "
               final_part    = ")"
               append_to_var = "box_description"
            ;
         }
      }
   }
   
   print_box_contents : subroutine {
      : if (child_count "box" > 0) {
         : append   "Inside the box you see \s" ;
         : look_inside
            of               = "box"
            extract_the      = "description"
            store_results_in = "list_object_buffer"
            make_known       = "true"
         ;
         : print_list_verbose  "list_object_buffer" lead_in="" when_empty = "nothing."  ;
         : return ;
      }
      : else {
         : print "The box is empty." ;
      }
   }

}

Thanks Chris. It’s really just a rough template. The container opening and closing, and object listing depending on the state , I’ve got finished code for from the last game - but in that one you could only put and get limited and specific objects in the container. So this really is a massive leap forward.

Well done on your tenaciousness.

I think these “workarounds” are about as good as it can get without me completing the native container implementation, adding in system level traits such as:

  • open
  • openable
  • locked
  • lockable

All this needs to go along with a “proper” door implementation:

Just for your amusement, this is how I think it will look once containers are natively supported.

start_at                 = my_location

locations {
   my_location : location "You are in a room." ;
}

objects {
   spoon : object "a spoon"           at = "my_location" ;
   apple : object "an apple"          at = "my_location" ;
   coin  : object "a coin"            at = "my_location" msg = "A gold coin." ;
   sword : object "a sword"           at = "my_location" size="10";
   box   : object "a box"             at = "my_location" container_type="bag" ;
}

Lockable containers not demonstrated above.

Simple as that eh? I guess the effect will be the same for the player, just without all this painful Heath Robinson stuff having to happen behind the scenes (or it will be happening, but the author won’t have to worry about it).