Jump to content
The Dark Mod Forums
Sign in to follow this  
kingsal

Help with a Thief-style chest. (Solved)

Recommended Posts

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
  • Like 1

Share this post


Link to post
Share on other sites

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.

  • Like 1

My FMs: The King of Diamonds (2016) | Visit my Mapbook thread sometimes! | Read my tutorial on Image-Based Lighting Workflows for TDM!

 

 

Share this post


Link to post
Share on other sites

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

Texture Blending in DR: DR ASE Blend Exporter

Share this post


Link to post
Share on other sites

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!

  • Like 1

Share this post


Link to post
Share on other sites

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.

  • Like 1

Share this post


Link to post
Share on other sites

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.

  • Like 1

Share this post


Link to post
Share on other sites

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).

  • Like 1

My FMs: The King of Diamonds (2016) | Visit my Mapbook thread sometimes! | Read my tutorial on Image-Based Lighting Workflows for TDM!

 

 

Share this post


Link to post
Share on other sites

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

Texture Blending in DR: DR ASE Blend Exporter

Share this post


Link to post
Share on other sites

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! | Read my tutorial on Image-Based Lighting Workflows for TDM!

 

 

Share this post


Link to post
Share on other sites

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();
}
}

  • Like 1

Share this post


Link to post
Share on other sites

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
  • Like 1

Share this post


Link to post
Share on other sites

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.

  • Like 1

Share this post


Link to post
Share on other sites

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.

  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...