Button Functionality and Frob Triggers

From The DarkMod Wiki
Revision as of 03:18, 3 March 2014 by RJFerret (talk | contribs) (→‎Assign targets to the button: +wikilink)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Originally written by Ishtvan on http://forums.thedarkmod.com/topic/4022

I added some global frob action scripts and button defs to make buttons more intuitive for the mapper.

Note: This doc relies on other information in the door tutorial.

A simple button that triggers one or more entities

Place a atdm:mover_button in your map

Assign a brush or model for it as you would for a func_darkmod_door. Modify the translation direction and speed so that the button moves in the direction you want. (Again see the documentation for translation in doors, or see the "entity usage" tab in the editor).

Levers

Levers are similar to buttons, but you need to use the atdm:mover_lever subclass (see also CFrobLever). Create exactly as for a button but assign a rotate property with X Y Z values for the direction and amount of rotation you want, eg, 45 0 0. Make sure the translate property is set to 0 0 0 (though they do work together if you want a lever that both rotates and translates as well.) Obviously also assign a lever shaped brush or model.

Assign targets to the button

(Add the property : 'target' to the button and the value will be the name of the entity to be functioned) They will now be triggered when the button is depressed. For example, if you assign a light, the light will be turned on and off by the button.

To add a custom script to the button

If you want your button to do more than just trigger something, you'll need to write a script. There's two ways to go about this:

Entity Scriptobject Method (7 steps)

  1. Create your button as described above.
  2. Place a new entity of class: target_callobjectfunction
  3. Set the target of the target_callobjectfunction to itself (alternatively you could set it to another entity and call the script on that entity, but that's not necessary)
  4. Set the key "call" to the name of the script you will write
  5. Set the key "scriptobject" to the name of the script object you will define
  6. Go into the map's script file and create a new object, using the following code:
  7. Define a member function of this object with the script that you want to run, and write the script.

The code below describes generally how to do steps 6 and 7:

Code in <your map name>.script

object <object name>
{
     // your script function declaration
} 

<object name>::<your script function name>
{
      // your script function implementation
}

Global scope method (4 steps - probably easier)

  • Create your button as described above.
  • Set the key "state_change_callback" to the name of a script you'll define globally in the script file for your map. (Must be named <map name>.script).
  • Unfortunately, due to how D3 scripting works, you'll have to copy the code to pop the button back up if you use the global scope method. Also, this script must have certain arguments because that's how it's called from the SDK. Copy and paste the following script for your button, replacing it with the name:
void <your function name>(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted)
{
   if(bOpen)
   {
       button.Close(1);
   }
}
  • Now, insert the script code that you want to run when the button is pressed here:
void state_change_button(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted)
{
   if(bOpen)
   {
       // YOUR CODE GOES HERE
       button.Close(1);
   }
}

Example

Optionally, you could add some interesting behavior here, like the button stays down for a while and then calls another script when it pops back up. To do that, you could do this:

void state_change_secret_door(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted)
{
   if(bOpen)
   {
       // open the secret door for 30 seconds
       $secret_door_1.Open();
       sys.wait( 30 );

       // close the secret door after 30 seconds
       $secret_door_1.Close();

       // pop the button back up
       button.Close(1);
   }
}

Comparison of Methods A and B

In Method A, you did not have to copy & paste the code to pop the button back up, because you were not creating a new state change function, the state change happens as usual and then triggers the target_callobjectfunction to call the script. This is probably the only advantage of Method A, other than being more OO to have local script functions instead of map-global ones.

In Method B you do have to copy the code to pop the button back up, but it's probably easier in terms of the number of steps required, since you can just change one key on the button and then put a global-scope script in the map.script file.

Also: Added generic response of triggering of targets into the global frob action scripts (/scripts/tdm_frobactions.script).

To create an entity that only triggers another entity when frobbed, either place a atdm:frobable_base, which works right out of the box or place any other item and set

"frobable" "1" 
"frob_action_script" "frob_trigger"

Inventory items trigger their targets when frobbed, doors trigger their targets when frobbed. Note that in these cases, the trigger is sent on every frob. That means if a player spasmadically presses frob 30 times in a second, the trigger will be sent 30 times, so you'd better make sure it is a target is a trigger_once or something like that if you don't want your trigger executing 30 times. Also if an item is trapped when you pick it up, make sure the trap can only get triggered once and then stops receiving triggers, otherwise it will keep going off if you drop the item and pick it up again and again.

If you want more complicated behavior for doors to trigger their targets only when completely open or closed, you'll have to either write your own state_change_callback script or use Sparhawk's setup for frobables triggering other frobables that should be covered in the door documentation.