id Tech 4: scripts

Scripts are used for map events, weapons and artificial intelligence. This section mostly covers map scripts.

General notes

  • Entity scripts are not automatically updated with the map command. It is necessary to use the reloadScript command, then reload the map.
  • The scripting language strongly resembles C++; for example, single-line comments in scripts start with //; multiline comments start with /* and end with */.
  • It seems that doom_events.script contains the declarations of all script functions that link to C++ functions, as opposed to functions both declared and defined in a script file.
  • Function names are case-sensitive.
  • Some script functions have equivalent properties in DarkRadiant. For example, the bind() function, which makes one entity a child of another (making the child entity follow the displacements of the parent) can be used in DR by adding the bind property, whose value will be the parent entity's name.
  • The $world entity represents all brushes (walls and floors not created from a model file) in a level.
  • In A.I. scripts, there is an object created for every entity, which acts like a class in C++. The init() function of an entity (which acts like a C++ class constructor) is polymorphic: it can be overriden in sub-objects. For example, monster_zombie::Init() (in ai_monster_zombie.script) implicitly calls the method of the same name from the monster_base class (which it inherits from).
  • To access a member of a vector object (x, y or z), we must write the name of the vector, followed by an underscore and the appropriate letter:

    vector origin = $player1.getWorldOrigin();
    sys.print( "Origin : ("+ origin_x +", "+ origin_y +", "+ origin_z +")" );

  • When a new script function is declared, do not give it the same name as an already existing function that is available in the scope of the file. The new function will not be recognised by the game. For example, a local script function cannot have the name fadeOut():

    void myScript_fadeOut() // Functional, because the functions have different names
    {
        sys.fadeOut('0 0 0', 10);
    }

    The following code, however, will not work as expected:

    void fadeOut() // Not functional, because there is a naming conflict
    {
        sys.fadeOut('0 0 0', 10);
    }

  • The waitAction() function in character scripts

    The waitAction( string ) function pauses the execution of the current script until finishAction( string ) is called with the same string parameter.

    For example, in monster_base::sight_enemy():

    animState( ANIMCHANNEL_TORSO, "Torso_Sight", 4 );
    waitAction( "sight" );

    Here is an explanation of what the function triggers in the C++ code. The function calls are as follows:

    • animState() is linked to the C++ function idActor::Event_AnimState().
    • Event_AnimState() is just an event function, and simply calls idActor::SetAnimState().
    • SetAnimState() then calls idAnimState::SetState(). This function gets a pointer to the Torso_Sight() script function (represented by a function_t* object in the codebase) and executes the monster_base::Torso_Sight() script function. The appropriate animation is played, and when it finishes, the game is notified:
    • finishAction( "sight" );

Notable script files

  • ai_monster_base.script

    The base script file for monsters. Some of the monster_base object's methods are redefined in subcategories of monsters.

    The idle_sight_fov property (boolean) decides if the monster relies exclusively on its field of vision to find the player; if it's set to true, the player can be behind the monster without alerting it.

    idle_sight_fov is initialised to true, but becomes false in monster_base::checkForEnemy(). Consequently, the monster starts out unable to detect the player unless it directly sees him. But if the player gets close enough behind it, idle_sight_fov becomes false and the monster will be able to detect the player anywhere around it (except through walls).

  • ai_monster_zombie_base.script

    This file contains the monster_zombie_base object, which is the base object for all zombies. It is inherited by a few other object types.

  • ai_monster_zombie.script

    Contains the script used by most zombie enemies (monster_zombie), such as monster_zombie_fat, monster_zombie_civilian and monster_zombie_chainsaw.