Jump to content


Photo

Help with a Thief-style chest. (Solved)

chest

13 replies to this topic

#1 kingsal

kingsal

    Member

  • Member
  • PipPip
  • 260 posts

Posted 18 May 2016 - 07:24 PM

Hey Guys,

 

I apologize ahead of time, I am a novice at scripting.

 

I am trying to create a thief-style chest; one that when opened, the items are automatically dumped into the player's inventory. 

I have pretty hacky prototype. Once the player frobs open the lid (atdm:mover_binarymover_base),  it targets  a func_callscriptfunction. I have a hacky Stim/response that removes the lid's targets when frobbed. This prevents the player from getting items every time they open the chest. The problem is when I try to lock the lid or attach a froblock, it breaks and nothing happens. The lid doesn't seem to like having other entities bound to it or target it.

 

Any suggestions or help would be awesome?

Thanks a bunch guys.

 

 

EDIT (Solved). Thanks for everyone's help with this.

Here is the .script and .def for anyone who is interested in using this in their FM.

 

Here is the script by SteveL: 

#ifndef AUTOLOOT_CHEST
#define AUTOLOOT_CHEST

//Script for autoloot chest by SteveL
// Spawnargs: "random_spawn", "random_chance"
//"random_spawn" = name of inventory item. (example "atdm:ammo_gasarrow")
//"random_chance" = Probability of spawn. (0 to 1)

void autoloot_chest(entity chest, boolean bOpen, boolean bLocked, boolean bInterrupted)
{
    // Fire only if map has been open 3 seconds (avoiding map initialisation) and 
    // only the first time the door/lid is fully opened.
    if ( sys.getTime() > 3 && bOpen && !chest.getBoolKey("already_opened") )
    {
        chest.setKey("already_opened", "1");
        // Search through "random_spawn" spawnargs, and find a matching "random_chance" spawnarg
        string key = chest.getNextKey("random_spawn", "");
        while ( key != "" )
        { 
            float chance = chest.getFloatKey(sys.strReplace(key, "_spawn", "_chance"));
            float r = sys.random(1.0);
            if ( chance > r )
            {
                entity newItem1 = sys.spawn(chest.getKey(key));
                newItem1.addItemToInv($player1);
                sys.wait(1.0);
            }
            key = chest.getNextKey("random_spawn", key);
        }
    }
}	
#endif

And the def file:

Be sure to replace the YOUR FM with your fm's directory. 

//++++++++++++++++++++++++Frob Chest++++++++++++++++++++++++++++++
//Auto Loot Chest
//Uses script "autoloot_chest" by SteveL
//Spawnargs: "random_spawn", "random_chance"
//"random_spawn" = Name of inventory item. (example "atdm:ammo_gasarrow")
//"random_chance" = Probability of spawn. (0 to 1)

entityDef frob_chest_lid
{
	//editor stuff
		"inherit"		"atdm:mover_binarymover_base"
		"editor_displayFolder"	"YOUR FM/autoloot_chest/"
		"editor_usage"	        "Auto loot chest. Random_spawn = name of inventory item. (example: atdm:ammo_gasarrow). Random_chance = Probability of spawn. (0 to 1)." 
		"editor_color"		"1.00 0.82 0.29"
		"spawnclass"            "CFrobDoor"
		
	//model
		"model"			"models/darkmod/containers/openable/footlocker_wood_lid.ase"	
		
	//sound
		"snd_open"		"chest_wood_open"
		"snd_close"		"chest_wood_close"
		
	//movement
		"rotate"		"0 0 -80"
		"move_time"             "0.4"
	
	//interaction
		"frobable"              "1"
		"locked"                "0"
		"state_change_callback" "autoloot_chest"
		
}

//Chest Body
entityDef frob_chest
{
	//editor stuff
		"inherit"		"atdm:entity_base"
		"spawnclass"            "idStaticEntity"
		"editor_displayFolder"	"YOUR FM/autoloot_chest/"
		"editor_usage"          "Auto loot chest."
		"editor_color"		"1.00 0.82 0.29"
		
	//model
		"model"                 "models/darkmod/containers/openable/footlocker_wood.ase"
	
	//other stuff
		"solid"                  "1"
}

Edited by kingsal, 24 June 2016 - 02:30 AM.

  • Anderson likes this

#2 Spooks

Spooks

    Member

  • Member
  • PipPip
  • 448 posts

Posted 19 May 2016 - 01:30 AM

Hello. Your script looks okay, not sure if there's any better arguments to use than just addItemToInv. If you want the items to be added just once, it's as simple as an if loop that closes after 1 frob.

float chestFrobbed = 0;

void function() {

	if (chestFrobbed == 0) {
        entity newItem1 = sys.spawn("atdm:weapon_shortsword");
        newItem1.addItemToInv($player1);
        chestFrobbed = 1;
	sys.waitFrame();
	}
}

It's probably tidier to do it with a boolean, but boolean and entitity data types can't be immediately declared it seems, don't know why.


  • Anderson likes this

My FMs: The King of Diamonds (2016)

 

Visit my Mapbook thread sometimes!


#3 Obsttorte

Obsttorte

    Scripting guru, Mapper

  • Active Developer
  • PipPipPipPipPip
  • 5524 posts

Posted 19 May 2016 - 02:48 AM

There are no booleans in the scripting language, so you have to use float. Wouldn't it make more sense to use a script object instead a global script to do this? Otherwise you will have to write a separate script function for every chest.


FM's: Builder Roads, Old Habits, Old Habits Rebuild
WIP's: Several. Although after playing Thief 4 I really wanna make a city mission.
Mapping and Scripting: Apples and Peaches
Sculptris Models and Tutorials: Obsttortes Models
My wiki articles: Obstipedia
Let's Map TDM YouTube playlist: ObstlerTube
Texture Blending in DR: DR ASE Blend Exporter

End of shameless self promotion.

#4 kingsal

kingsal

    Member

  • Member
  • PipPip
  • 260 posts

Posted 19 May 2016 - 01:13 PM

Spooks- I tried your script out and it works really well and is much cleaner. It also works with being locked and having a froblock attached to it. Thanks so much!  :D

 

Obs- That would definitely be a more solid solution and friendlier to the mission designer. It would be nice to be able to select the items as spawnargs inside darkradiant.

There is one small advantage to each chest having its own script, you can make edits to its contents without digging around for it in the editor.  If for instance, you wanted to quickly balance the items across the entire map.  

 

Thanks guys for the help! 


  • Anderson likes this

#5 SteveL

SteveL

    Hero Coder

  • Active Developer
  • PipPipPipPip
  • 3669 posts

Posted 19 May 2016 - 01:26 PM

There is one small advantage to each chest having its own script, you can make edits to its contents without digging around for it in the editor.  If for instance, you wanted to quickly balance the items across the entire map.  

 

You could probably use the menu function that selects all entities that have the same model as the one you have selected. That'd let you skip between chests in the map easily.

 

The script object version would also let you balance the loot distribution by setting a probability against each item so you could have the same spawnargs on every chest and still keep the loot balanced. 

 

e.g.

"random_spawn1" "atdm:weapon_shortsword"

"random_chance1" "20"

 

I don't mind providing the starter script object if you want to try it out. The documentation is a bit brief, both ours and ID's.


  • Anderson likes this

#6 kingsal

kingsal

    Member

  • Member
  • PipPip
  • 260 posts

Posted 19 May 2016 - 01:50 PM

Steve- If its something you're interested in, that would be awesome. I'd definitely like to try it out! It sounds like a much better long term solution.

 

I do like the TDM style chests with the items being optional to pick up, it feels immersive. However, there are some nice advantages to an item dump chest, you don't have to worry about bsp recompiling if you move it and you can easily balance item distribution. 


  • Anderson likes this

#7 Spooks

Spooks

    Member

  • Member
  • PipPip
  • 448 posts

Posted 19 May 2016 - 03:42 PM

There are no booleans in the scripting language, so you have to use float. Wouldn't it make more sense to use a script object instead a global script to do this? Otherwise you will have to write a separate script function for every chest.

 

Somebody needs to update the Scripting Basics page on the wiki then, the Boolean data type is stated to exist there. At the very least it should be noted booleans and entities can't have their values set outside of a function (i.e. at declaration time when they're global variables).


  • Anderson likes this

My FMs: The King of Diamonds (2016)

 

Visit my Mapbook thread sometimes!


#8 Obsttorte

Obsttorte

    Scripting guru, Mapper

  • Active Developer
  • PipPipPipPipPip
  • 5524 posts

Posted 19 May 2016 - 03:55 PM

The wiki actually states that it is a float.


FM's: Builder Roads, Old Habits, Old Habits Rebuild
WIP's: Several. Although after playing Thief 4 I really wanna make a city mission.
Mapping and Scripting: Apples and Peaches
Sculptris Models and Tutorials: Obsttortes Models
My wiki articles: Obstipedia
Let's Map TDM YouTube playlist: ObstlerTube
Texture Blending in DR: DR ASE Blend Exporter

End of shameless self promotion.

#9 Spooks

Spooks

    Member

  • Member
  • PipPip
  • 448 posts

Posted 19 May 2016 - 04:10 PM

Yes, but unlike floats it throws up errors to the likes of "wrong immediate type of boolean data type" when you try to set a value, unlike float. I'm just wondering why it's even a data type, for some sort of parity? We already don't have int.


My FMs: The King of Diamonds (2016)

 

Visit my Mapbook thread sometimes!


#10 stumpy

stumpy

    Advanced Member

  • Member
  • PipPipPip
  • 1749 posts

Posted 19 May 2016 - 08:11 PM

its used to see if a door is open or closed as in (boolean bOpen) it checks that bOpen is true or false if you remove it then doors controlled by scripts will fail to function, and you'll break many maps that use that function.

eg

void sewerhatch1_state(entity mover_lever, boolean bOpen, boolean bLocked, boolean bInterrupted)
{
      if (bOpen)
      {
            $manhole_cover_1a.Open();
      }
      else
      {
            $manhole_cover_1a.Close();
      }
}


  • Spooks likes this

#11 SteveL

SteveL

    Hero Coder

  • Active Developer
  • PipPipPipPip
  • 3669 posts

Posted 21 May 2016 - 01:18 AM

void sewerhatch1_state(entity mover_lever, boolean bOpen, boolean bLocked, boolean bInterrupted)

Ah, that's a "state_change_callback" script.

@kingsal You could use one of those more simply than a script object to get the job done with the chest. state_change_callback is a way to call a script when a door is moved or a button is pressed. Unlike most ways to call a script, the script gets told which entity fired it. 
 
Chest lids are doors, so you could put your spawnargs on the lid along with "state_change_callback" "autoloot_chest"
 
Then in your map script:
void autoloot_chest(entity chest, boolean bOpen, boolean bLocked, boolean bInterrupted)
{
    // Fire only if map has been open 3 seconds (avoiding map initialisation) and 
    // only the first time the door/lid is fully opened.
    if ( sys.getTime() > 3 && bOpen && !chest.getBoolKey("already_opened") )
    {
        chest.setKey("already_opened", "1");
        // Search through "random_spawn" spawnargs, and find a matching "random_chance" spawnarg
        string key = chest.getNextKey("random_spawn", "");
        while ( key != "" )
        { 
            float chance = chest.getFloatKey(sys.strReplace(key, "_spawn", "_chance"));
            float r = sys.random(1.0);
            if ( chance > r )
            {
                entity newItem1 = sys.spawn(chest.getKey(key));
                newItem1.addItemToInv($player1);
                sys.wait(1.0);
            }
            key = chest.getNextKey("random_spawn", key);
        }
    }
}
The script disables a chest by adding a spawnarg to it in real time. You can use any random_spawnXYZ spawnarg naming scheme as long as there's a matching random_chanceXYZ sparnarg for each. Without the matching spawnarg, the chance will come out at 0 so the item won't ever be added.

I tested it with these s/args on a chest lid:
"random_spawn1" "atdm:ammo_firearrow"
"random_spawn2" "atdm:ammo_mossarrow"
"random_spawnA" "atdm:ammo_broadhead"
"random_chanceA" "0.5"
"random_chance1" "0.8"
"random_chance2" "0.5"
"state_change_callback" "autoloot_chest"

You can make a new entity def with your preferred settings. Then changing the def will change all matching chest lids that haven't overridden the spawnargs.

If you want to stick to your original plan of a separate script for each chest then Spooks' global variable is the quick way as you found, but that method only works with a separate script for each chest, because a script shared between chests wouldn't know which chest had triggered it (and so couldn't disable the right chest).

Edited by SteveL, 22 May 2016 - 05:29 AM.

  • Anderson likes this

#12 kingsal

kingsal

    Member

  • Member
  • PipPip
  • 260 posts

Posted 21 May 2016 - 05:12 PM

Oh awesome Steve.

 

I am a novice when it comes to scripting, but this is really helpful.  If I get a chance today or tomorrow I will plug in your script and give it a shot. 

This is fantastic.

 

I can see getting a lot of use out of both scripts for different purposes. 


  • Anderson likes this

#13 SteveL

SteveL

    Hero Coder

  • Active Developer
  • PipPipPipPip
  • 3669 posts

Posted 22 May 2016 - 05:36 AM

Cool. I added a fix to the script above by the way by moving
chest.setKey("already_opened", "1");
to the top of the block, so the player can't trigger the script a second time during the sys.wait()s between multiple items being spawned.


  • Anderson likes this

#14 kingsal

kingsal

    Member

  • Member
  • PipPip
  • 260 posts

Posted 24 June 2016 - 12:05 AM

Sorry for the delayed response on this.

I've tested out Steve's script and wrote a .def if anyone wants to use it in their FM. Edited in the first post

 

Thanks for the help everyone!





Reply to this topic



  



Also tagged with one or more of these keywords: chest

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users