Command-Scripts (EM4)

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • Information about command scripts for EMERGENCY 4.

    Command-Scripts

    Command scripts are the scripts in which the interaction of the mouse pointer of the player is transformed into an action in the game. This is, for example, the case when the fireman is equipped with a firehose by the command "getFirehose".

    Structure of command scripts

    A command script always follows a certain structure:

    Source Code

    1. object ScriptName : CommandScript
    2. {
    3. ScriptName()
    4. {
    5. }
    6. bool CheckPossible(GameObject *Caller)
    7. {
    8. }
    9. bool CheckTarget(GameObject *Caller, Actor *Target, int childID)
    10. {
    11. }
    12. void PushActions(GameObject *Caller, Actor *Target, int childID)
    13. {
    14. }
    15. };
    Display All

    Source Code

    1. object ScriptName : CommandScript //Creates a command script with the name //ScriptName//


    Constructor

    Source Code

    1. ScriptName()
    2. {
    3. }


    This part of the script is the so-called constructor. The name of the constructor must always be identical to the name of the command script. Here, for example, the icon or the cursor can be defined.

    CheckPossible-method

    Source Code

    1. bool CheckPossible(GameObject *Caller)
    2. {
    3. }


    This part of the script determines when the script can be executed. Since the bool keyword is used here, the script must return a boolean value within this method. Here, for example, the command could only be executed by one person when the person's life display is completely full. The GameObject * Caller parameter is also passed to the method. The variable Caller can thus be used in this method.

    The caller is the GameObject that runs the command. In most cases the selected GameObject.



    CheckTarget-method

    Source Code

    1. bool CheckTarget(GameObject *Caller, Actor *Target, int childID)
    2. {
    3. }


    The CheckTarget method checks whether a target is appropriate for this command. For example, if a person is to be arrested with a policeman, it should be restricted that the script can only be applied to a person and not to vehicles. Again, parameters are passed: GameObject *Caller, Actor *Target and int childID.

    The variable target is the object that is the target of the command. For example, a person who wants to be arrested.



    The integer value childID is a number that will always pass a command. If no number is passed, the childID is 0.



    PushActions-method

    Source Code

    1. void PushActions(GameObject *Caller, Actor *Target, int childID)
    2. {
    3. }


    The PushActions method includes the actual script. Here is everything that should end up in the game. For example, a policeman is walking to and arresting a person. So if you read a script and want to know what the script does, you have to read in this part of the command script.

    Create a script

    Planning

    Before you start to script, you have to consider what the script should be. This happens in two steps:

    Planning InGame
    To begin with, you need to think about what to do when you run the script in the game. In this example, a simple scenario is chosen: The script should let run a person to a selected point. There the person should put a bottle on the ground and then go back to the starting point.

    Planning in the script
    At this point, the whole thing is a bit more complicated. Now you have to consider how the desired action in EMERGENCY can be realized in the form of the programming language. This is easier done by writing the script in a so-called Pseude code. A pseudocode is only a flowchart, not something that the game needs to process later. Thus, in this step, any script commands can be dispensed with.

    Source Code

    1. object ScriptName : CommandScript
    2. {
    3. ScriptName()
    4. {
    5. Only streets and other ground allowed as target position
    6. }
    7. bool CheckPossible(GameObject *Caller)
    8. {
    9. Nothing special here
    10. }
    11. bool CheckTarget(GameObject *Caller, Actor *Target, int childID)
    12. {
    13. Nothing special here
    14. }
    15. void PushActions(GameObject *Caller, Actor *Target, int childID)
    16. {
    17. Read position of person
    18. Read position of mouse
    19. Send person to the position of mouse
    20. Let the person kneel down (play animation)
    21. Create and place bottle on position
    22. Let the person stand up (play animation)
    23. Send person back to the original position
    24. }
    25. };
    Display All


    With this pseudocode we now have a construction guide for our script. If you have a lot of scripting experience, it is enough to have a flowchart in your head, but a pseudecode at the beginning of your scripter career can be a considerable relief.

    Search the SDK

    It is now known that the position of a person must be read out - but this does not get us in the script at first. The desired action must still be implemented in the script language of EMERGENCY. The SDK, a dictionary for scripting, can be used for this purpose. The SDK lists all commands that can be processed by EMERGENCY 4.

    The terms such as "ActionInsertMode" or "Actor" represent classes that contain the commands of this class. Thus, they are, so to speak, the upper bounds for certain functions. Our goal is to read out the position of the so-called "caller". The "caller" is our unit, which is executing the command. Our unit is a person, so we search the list of terms for appropriate classes:
    • ActionInsertModes: Does not seem to fit.
    • Actor: Probably not.

    • GameObject: This could fit, because this class affects almost all objects in the game.

    • Person: This could also fit.
    So we open the class "GameObject" and see all commands / functions that can be applied to a GameObject. With Ctrl + F we open the search window of the browser. The command to read a position might include something like "Pos" or "Position". Now look for "Pos" and take a look at the results - one of them looks promising:

    Source Code

    1. virtual Vector GetPosition() const;

    However, if you copy this command to the script, the compiler would issue an error. The compiler, for example, does not know at all which object to read the position from. If you are still at the beginning of your scripter career and do not know how to use the individual commands, the search function of the forum can be helpful. For example, the search for the term "GetPosition" shows this script snippet after a short time:

    Source Code

    1. Vehicle v(Target);
    2. Vector Vec = v.GetPostion();

    This example already shows how the command is used. If the system is transferred to the script, the first part of the PushActions method is as follows:

    Source Code

    1. void PushActions(GameObject *Caller, Actor *Target, int childID)
    2. {
    3. Person p(Caller); //Person = Data type, p = Name of variable, Caller = selected person)
    4. Vector Pos = p.GetPosition(); //Vector = Data type, Pos = Name of variable
    5. }


    Compose the script

    This approach applies to every single point of the "screenplay". When browsing the forum you will always find different ways to solve problems - in programming there are different ways which can lead to the desired goal. Some are simpler and shorter, some more cumbersome and detailed. But as long as the solution to the problem is achieved, it does not matter how to get to the goal.

    The script could look like this:

    Source Code

    1. void PushActions(GameObject *Caller, Actor *Target, int childID)
    2. {
    3. Person p(Caller);
    4. Vector PosAnfang = p.GetPosition();
    5. Vector Pos = Game::GetCommandPos();
    6. p.PushActionMove(ACTION_NEWLIST, Pos);
    7. p.PushActionSwitchAnim(ACTION_APPEND, "kneeldown");
    8. GameObject flasche = Game::CreatObject(PATH, "Falsche");
    9. p.PushActionSwitchAnim(ACTION_APPEND, "idle");
    10. p.PushActionMove(ACTION_APPEND, PosAnfang);
    11. }
    Display All

    However, the variable "PATH" must first be declared:

    Source Code

    1. const char PATH[] = "mod:Prototypes/Equipemnt/bottle.e4p;
    2. const char ICON[] = "FlascheHinlegen";
    3. object ScriptName : CommandScript
    4. {
    5. ScriptName()
    6. {
    7. SetIcon(ICON);
    8. SetCursor(ICON);
    9. SetValidTargets(ACTOR_FLOOR);
    10. }
    11. bool CheckTarget(GameObject *Caller, Actor *Target, int childID)
    12. {
    13. return true;
    14. }
    15. void PushActions(GameObject *Caller, Actor *Target, int childID)
    16. {
    17. Person p(Caller);
    18. Vector PosAnfang = p.GetPosition();
    19. Vector Pos = Game::GetCommandPos();
    20. p.PushActionMove(ACTION_NEWLIST, Pos);
    21. p.PushActionSwitchAnim(ACTION_APPEND, "kneeldown");
    22. GameObject flasche = Game::CreatObject(PATH, "Falsche");
    23. p.PushActionSwitchAnim(ACTION_APPEND, "idle");
    24. p.PushActionMove(ACTION_APPEND, PosAnfang);
    25. }
    26. };
    Display All

    On this occasion an image for the icon and cursor was defined in the constructor. Since the name of the images in the icon folder is not written directly in quotation marks, but a variable has been defined globally, this variable must be declared. The command "SetValidTargets(ACTOR_FLOOR);" restricts the possible targets so that the script can only be activated on the ground.

    If the script is now executed, it can be determined that the person is running but also a bottle is placed immediately on the ground. The compiler completes the entire script and executes the commands one at a time. In the present case, however, pushbutton commands were used. These are written in an ActionList, which is executed one after the other. The person runs first to the CommandPos, when this is done, she kneels, then she stands again, etc.

    "ACTION_NEWLIST" (an ActionInsertMode) creates a new ActionList. If there was an old list, all the commands contained therein are deleted and no longer executed. "ACTION_APPEND" simply attaches another method to the list. To make sure that the bottle is created when the person is also in place, we have to use a small trick as there is no way to add this spawn command directly to the ActionList. The trick is to simply run Script again and set another ChildID.

    Source Code

    1. void PushActions(GameObject *Caller, Actor *Target, int childID)
    2. {
    3. Person p(Caller);
    4. if(childID == 0)
    5. {
    6. Vector PosAnfang = p.GetPosition();
    7. Vector Pos = Game::GetCommandPos();
    8. p.PushActionMove(ACTION_NEWLIST, Pos);
    9. p.PushActionSwitchAnim(ACTION_APPEND, "kneeldown");
    10. p.PushActionExecuteCommand(ACTION_APPEND, "ScriptName");
    11. }
    12. else if(childID == 1)
    13. {
    14. GameObject flasche = Game::CreatObject(PATH, "Falsche");
    15. p.PushActionSwitchAnim(ACTION_APPEND, "idle");
    16. p.PushActionMove(ACTION_APPEND, PosAnfang);
    17. }
    18. }
    Display All


    Running the script would cause an error: The vector PosAnfang is not defined in the if loop with childID = 1, since it is defined on the same instance, ie in a clip in which the second if loop is not present and consequently has no access. The solution is simple: The vector must be globally defined as being outside the script, or it is defined by an instance by the if loop.

    Source Code

    1. void PushActions(GameObject *Caller, Actor *Target, int childID)
    2. {
    3. Person p(Caller);
    4. Vector PosAnfang;
    5. if(childID == 0)
    6. {
    7. Pos = p.GetPosition();
    8. Vector Pos = Game::GetCommandPos();
    9. p.PushActionMove(ACTION_NEWLIST, Pos);
    10. p.PushActionSwitchAnim(ACTION_APPEND, "kneeldown");
    11. p.PushActionExecuteCommand(ACTION_APPEND, "ScriptName");
    12. }
    13. else if(childID == 1)
    14. {
    15. GameObject flasche = Game::CreatObject(PATH, "Falsche");
    16. p.PushActionSwitchAnim(ACTION_APPEND, "idle");
    17. p.PushActionMove(ACTION_APPEND, PosAnfang);
    18. }
    19. }
    Display All

    Now the PushActions method and the constructor are finished. As a result, only the other two methods need to be created. Since it was initially decided not to restrict the command any further, you can simply omit the method CheckPossible (GameObject * Caller). The compiler does not need this method. But it's different with the CheckTarget method. This is required by the compiler. However, since no restrictions on the target are necessary, the method is simply filled with the return value true. Remember: methods with Bool must always return a truth value!

    Source Code

    1. bool CheckTarget(GameObject *Caller, Actor *Target, int childID)
    2. {
    3. return true;
    4. }

    2,707 times viewed