Writing Script Objects: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
Tels (talk | contribs)
m even more info
Tels (talk | contribs)
 
(9 intermediate revisions by the same user not shown)
Line 56: Line 56:
void the_script_object_name_here::RestoreScriptObject()
void the_script_object_name_here::RestoreScriptObject()
{
{
     // print out that we are constructed for debuggin;
     // print out that we are constructed for debugging:
     sys.println ("the_script_object_name_here::init() called");
     sys.println ("the_script_object_name_here::RestoreScriptObject() called");


     // We have to do nothing by default, everything is already restored
     // We have to do nothing by default, everything is already restored
Line 64: Line 64:
}
}


void the_script_object_name_here::RestoreScriptObject()
void the_script_object_name_here::updateLoop()
{
{
     // endless loop
     // endless loop
Line 82: Line 82:
For a more complete example see '''script/tdm_location_settings.script'''.
For a more complete example see '''script/tdm_location_settings.script'''.


=== Notes ===
=== Constructor ===
 
The constructor <tt>init()</tt> is called by the engine for each script object during the first frame after spawning the entity. You <tt>main()</tt> routine should therefore do '''<tt>sys.waitFrame()</tt> before accessing any script objects.
 
Note that inherited script objects get <tt>init()</tt> called from all the classes they inherit from. So make sure that inherited classes do not do things twice in their constructors.
 
=== Self ===


Avoid method names that already exist in the C++ code. For instance "Restore()", "Save()", "Spawn()" etc. These all might cause unwanted side-effects or crashes. They also make it impossible to be called from the C++ code.
If you want to pass the script object to other functions, use '''<tt>self</tt>''':


== Pre-made Script Objects ==
sys.remove(self);


TDM already contains some useful script objects that you can attach to entities:
=== Inheritance ===


=== tdm_suicide ===
Script objects can inherit from other objects:


<pre>
<pre>
"script_object" "tdm_suicide"
object my_subclass : the_script_object_name_here
"remove_delay"  "100"              // remove this entity 100 seconds after spawning it
{
    /**
    * Define a new routine in addition to the inherited ones
    */
    void  newUpdateLoop();
}
void my_subclass::newUpdateLoop()
{
    sys.waitFrame();
    updateLoop();    // call the inherited method
}
</pre>
</pre>


=== tdm_light_holder ===
=== Accessing Methods ===
 
If your entity has a scriptobject, and you want to call a method on that script object from a variable, you need to use the right class name instead of plain '''entity''':


<pre>
<pre>
"script_object" "tdm_light_holder"
entity my_ent = $my_entity;
"extinguished"  "1"                // the light starts off, but can be lit by the player
my_ent.updateLoop();          // error, normal entities don't have the script event
 
the_script_object_name_here my_ent = $my_entity;
my_ent.updateLoop();          // works
 
$my_entity.updateLoop();      // also works
</pre>
</pre>


This is typical attached to either lights (an electrical lamp f.i.) or light holders (a candle holder with attached candle + flame, or a torch with attached flame). This script object has handy methods to toggle all lights that this holder has, regardless how many (multiple flames?) or where (flame on holder or flame on candle on holder?).
=== Notes ===
 
* Avoid method names that already exist in the C++ code. For instance "Restore()", "Save()", "Spawn()" etc. These all might cause unwanted side-effects or crashes. They also make it impossible to be called from the C++ code.
* It is sensible to put your script object in its own file.
 
 
{{infobox|Note: Make sure to include it from '''script/tdm_custom_scripts.script''', and '''not''' from your main map script. Otherwise savegames cannot be loaded!}}
 
== Pre-made Script Objects ==


This script object also makes the entity react to fire stims, an/or triggers like when you link a button/lever/trigger to this entity.
TDM already contains some useful script objects that you can attach to entities, see [[Script objects]] for a list.


{{scripting}}
{{scripting}}

Latest revision as of 11:19, 3 October 2014

Introduction

A script object is an object that is written in the idTech4 scripting language, and an be attached to arbitrary entities. Each entity can have only one script object.

Script objects can call script events, these provide access to functions provided by the C++ code. They also have access to the spawnargs of the entity they are attached to, other entities (and their spawnargs!), as well as global functions (like "sys.wait"), and CVARs.

An script object should have at least a definition, and one constructor. To prevent that inclusion of that script file defines the object twice, we also use "ifndef" and "define" to guard against this.

Writing your own Script Object

Here is an example:

#ifndef __NAME_HERE__
#define __NAME_HERE__

object the_script_object_name_here
{
    /**
    * Define a float variable that the script code can access. The "m_" prefix
    * will remind us that this is a member:
    **/
    float   m_updatePeriod;

    /**
    * Define the constructor, will be called automatically _once_:
    */
    void   init();

    /**
    * Optional: Define a routine that gets called when a savegame is loaded:
    */
    void   RestoreScriptObject();

    /**
    * Optional: Define a routine that can work periodically.
    */
    void   updateLoop();
};

// now define the routines and their code
void the_script_object_name_here::init()
{
    // print out that we are constructed for debugging:
    sys.println ("the_script_object_name_here::init() called");

    // initialize our member from a spanwarg from the entity this
    // script object is attached to:
    m_updatePeriod = getFloatKey( "update_period" );

    // Done now. If you want to do some work be done periodically,
    // call it here once, and let it loop.
    updateLoop();
};

void the_script_object_name_here::RestoreScriptObject()
{
    // print out that we are constructed for debugging:
    sys.println ("the_script_object_name_here::RestoreScriptObject() called");

    // We have to do nothing by default, everything is already restored
    // but if your script object plays some sounds, you might want to
    // restart them here.     
}

void the_script_object_name_here::updateLoop()
{
    // endless loop
    while (1)
    {

        // do something here

        // then wait the wanted time, and do it again:
        wait( m_updatePeriod );
    }
}

#endif // __NAME_HERE__

For a more complete example see script/tdm_location_settings.script.

Constructor

The constructor init() is called by the engine for each script object during the first frame after spawning the entity. You main() routine should therefore do sys.waitFrame() before accessing any script objects.

Note that inherited script objects get init() called from all the classes they inherit from. So make sure that inherited classes do not do things twice in their constructors.

Self

If you want to pass the script object to other functions, use self:

sys.remove(self);

Inheritance

Script objects can inherit from other objects:

object my_subclass : the_script_object_name_here
{
    /**
    * Define a new routine in addition to the inherited ones
    */
    void   newUpdateLoop();
}
void my_subclass::newUpdateLoop()
{
    sys.waitFrame();
    updateLoop();     // call the inherited method
}

Accessing Methods

If your entity has a scriptobject, and you want to call a method on that script object from a variable, you need to use the right class name instead of plain entity:

entity my_ent = $my_entity;
my_ent.updateLoop();           // error, normal entities don't have the script event

the_script_object_name_here my_ent = $my_entity;
my_ent.updateLoop();           // works

$my_entity.updateLoop();       // also works

Notes

  • Avoid method names that already exist in the C++ code. For instance "Restore()", "Save()", "Spawn()" etc. These all might cause unwanted side-effects or crashes. They also make it impossible to be called from the C++ code.
  • It is sensible to put your script object in its own file.


Note: Make sure to include it from script/tdm_custom_scripts.script, and not from your main map script. Otherwise savegames cannot be loaded!

Pre-made Script Objects

TDM already contains some useful script objects that you can attach to entities, see Script objects for a list.