Dear forum users! In compliance with the new European GDPR regulations, we'd just like to inform you that if you have an account, your email address is stored in our database. We do not share your information with third parties, and your email address and password are encrypted for security reasons.

New to the forum? Say hello in this topic! Also make sure to read the rules.

Scripting 03 - Extension scripts ("CampingMines" script example)

A smaller forum with a few tutorials how to get started with the ScriptAPI.
Forum rules
By using the forum you agree to the following rules.
Post Reply
User avatar
Gurt
Lead Programmer
Lead Programmer
Posts: 1884
Joined: Sun Feb 28, 2016 3:22 pm
Title: Lead programmer
Started SFD: Made it!
Location: Sweden
Gender:
Age: 34

Scripting 03 - Extension scripts ("CampingMines" script example)

Post by Gurt » Thu Mar 17, 2016 9:15 pm

Scripting 03 - Extension scripts

Scripting in SFD assumes you have a fair knowledge of C#. You should be able to declare variables, write your own functions and classes, you should know about inheritance and derived classes and know how to cast objects.

In this part I will illustrate how to create an extension script and use it in your game.

Extension script is a new feature introduced in Pre-Alpha 1.6.4 which we currently experiment with.
It is a standalone script you load in parallel with the current existing map.


Try it yourself:
Let's create a simple time-limit extension script to show the principle and load in into an existing game.

1: The script itself:
We will create a script that will create a TimerTrigger, set it up to tick each 300 ms and call an update method which will check some player is standing still in the same place for too long. If so a mine will spawn at the feet of the player.
You can construct this script in an empty map to check that it compiles and runs as it should.
//
        // CampingMines by Gurt.
        // Create mines at the feet of any stale/non-moving player after a certain delay.

        // OnStartup is run when the script starts running.
        public void OnStartup()
        {

            // Update stale players and see what they are doing now-and-then
            IObjectTimerTrigger timer = (IObjectTimerTrigger)Game.CreateObject("TimerTrigger");
            timer.SetIntervalTime(300);
            timer.SetRepeatCount(0); // infinite times
            timer.SetScriptMethod("CheckStalePlayers");
            timer.Trigger();
        }

        public void CheckStalePlayers(TriggerArgs args)
        {
            // Don't spawn mines the first 7 seconds during startup
            if (Game.TotalElapsedGameTime < 7000)
            {
                return;
            }
            // for each ALIVE player
            IPlayer[] players = Game.GetPlayers();
            foreach (IPlayer player in players)
            {
                if (!player.IsDead && !player.IsRemoved) // failsafe
                {
                    PlayerMineTracker tracker = GetPlayerMineTracker(player);
                    tracker.Update();
                }
            }
        }

        private Dictionary<int, PlayerMineTracker> m_mineTrackers = new Dictionary<int, PlayerMineTracker>();

        private PlayerMineTracker GetPlayerMineTracker(IPlayer player)
        {
            PlayerMineTracker playerMineTracker = null;
            if (!m_mineTrackers.TryGetValue(player.UniqueID, out playerMineTracker))
            {
                playerMineTracker = new PlayerMineTracker(player);
                m_mineTrackers.Add(player.UniqueID, playerMineTracker);
            }
            return playerMineTracker;
        }

        private class PlayerMineTracker
        {
            private const float MOVE_DISTANCE_TRESHOLD = 10f;
            private const float SPAWN_MINE_TIME_MS = 3000f;

            private float m_lastMoveTime = 0f;
            private Vector2 m_lastPlayerMovePosition = Vector2.Zero;
            private IPlayer m_player;

            public PlayerMineTracker(IPlayer player)
            {
                m_player = player;
                m_lastMoveTime = Game.TotalElapsedGameTime;
                m_lastPlayerMovePosition = player.GetWorldPosition();
            }

            public void Update()
            {
                Vector2 currentWorldPosition = m_player.GetWorldPosition();
                if (InSamePosition(currentWorldPosition))
                {
                    if (Game.TotalElapsedGameTime - m_lastMoveTime > SPAWN_MINE_TIME_MS)
                    {
                        SpawnMine();
                        // reset variables to prepare for next mine to spawn
                        m_lastMoveTime = Game.TotalElapsedGameTime;
                        m_lastPlayerMovePosition = currentWorldPosition;
                    }
                }
                else
                {
                    m_lastMoveTime = Game.TotalElapsedGameTime;
                    m_lastPlayerMovePosition = currentWorldPosition;
                }
            }

            /// <summary>
            /// Checks if the player is within bounds of m_lastPlayerMovePosition
            /// </summary>
            private bool InSamePosition(Vector2 newPosition)
            {
                return (m_lastPlayerMovePosition - newPosition).Length() < MOVE_DISTANCE_TRESHOLD;
            }

            /// <summary>
            /// Spawns a new mine at the player's feet
            /// </summary>
            public void SpawnMine()
            {
                if (!m_player.IsDead && !m_player.IsRemoved) // failsafe
                {
                    Game.CreateObject("WPNMINETHROWN", m_player.GetWorldPosition());
                }
            }

        }

When we're happy with the script it's time to save it as an extension script.
Extension scripts are just plain text-files containing the script that the game can load during runtime.

Browse to your Superfighters Deluxe folder in your documents (where your profile and downloaded maps are stored). In this folder create a new folder (if not yet created) called "Scripts". In this folder create a new textfile and name it "CampingMines.txt". You should now have an empty file CampingMines.txt in your Document\Superfighters Deluxe\Scripts folder (C:\Users\[USER]\Documents\Superfighters Deluxe\Scripts in windows 7 by default). Open the CampingMines.txt file and paste the above code into it and save.

When you host a game in SFD you can now start the extension script at any time using the following command "/STARTSCRIPT [SCRIPTNAME]". Note that the name of the text-file containing the script must be the same that you type in the command.
To load the script we just created type "/StartScript CampingMines" and the script will start. Loaded extension scripts will automatically be started again the next round.
To stop an extension script type "/STOPSCRIPT [SCRIPTNAME]" and the extension script will stop the next round.

Additional notes
You can load as many extension scripts as you want. But as ALL activated scripts share the same game they also share the same objects. So creating, moving and removing objects can lead to unexpected behavior in other scripts if not care is taken. The example script above can stop working if another script is removing all TimerTriggers for example. The ShowPopupMessage() function can also be used in other scripts. But for standard maps the above script will spawn mines at the feet of camping players which is not yet available in any other way. The potential to create DeathMatch or SuddenDeath scripts now exist which can be applied to all maps.

The /startscript and /stopscript commands are not available in the /help section as this is still experimental.

Future plans include being able to listen to a "stop" function and apply required code for stopping a script and a function that returns a meta data object for the script itself - containing the name, description, author, etc... Maybe even the possibility to export the extension scripts to files similar to map files that can be installed by double-clicking on them.

For now each time a match is restarted everyone in the game will see the name of the extension script that is loaded as an indication that the server is running extension scripts.
1 x
Gurt

Post Reply