Implementing Invincible Script - KimonoBoy/SHVDNTutorial-NucleiLite GitHub Wiki

In this section we'll implement our Invincible script from earlier by creating a new type of NativeItem called a NativeCheckboxItem - this item can be checked or unchecked and dependening on its checked-state the Player becomes Invincible or not

Refactoring

Before we dive into the code and implement the Invincible-script, let's organize our class a bit, making it easier to read and update with new features

  1. Copy and Paste the below
using System;
using System.Windows.Forms;
using GTA;
using GTA.UI;
using LemonUI;
using LemonUI.Menus;

namespace NucleiLite
{
    public class Main : Script
    {
        ObjectPool menuPool = new ObjectPool();
        NativeMenu mainMenu = new NativeMenu("NucleiLite", "Main Menu");
        NativeMenu playerMenu = new NativeMenu("NucleiLite", "Player Menu");
        NativeMenu vehicleSpawnerMenu = new NativeMenu("NucleiLite", "Vehicle Spawner Menu");
        NativeMenu weaponsMenu = new NativeMenu("NucleiLite", "Weapons Menu");

        public Main()
        {
            CreateMainMenu();
            CreatePlayerMenu();
            CreateVehicleSpawnerMenu();
            CreateWeaponsMenu();

            AddMenusToPool();

            KeyDown += OnKeyDown;
            Tick += OnTick;
        }

        private void CreateMainMenu()
        {
            mainMenu.AddSubMenu(playerMenu);
            mainMenu.AddSubMenu(vehicleSpawnerMenu);
            mainMenu.AddSubMenu(weaponsMenu);
        }

        private void CreatePlayerMenu()
        {
            // Fix Player
            NativeItem itemFixPlayer = new NativeItem("Fix Player", "Restores Player's Health and Armor");
            itemFixPlayer.Activated += (sender, args) =>
            {
                Game.Player.Character.Health = Game.Player.Character.MaxHealth;
                Game.Player.Character.Armor = Game.Player.MaxArmor;
                Notification.Show("Health and Armor Restored!");
            };
            playerMenu.Add(itemFixPlayer);
        }

        private void CreateWeaponsMenu()
        {
        }

        private void CreateVehicleSpawnerMenu()
        {
        }

        private void AddMenusToPool()
        {
            menuPool.Add(mainMenu);
            menuPool.Add(playerMenu);
            menuPool.Add(vehicleSpawnerMenu);
            menuPool.Add(weaponsMenu);
        }

        private void OnTick(object sender, EventArgs e)
        {
            menuPool.Process();
        }

        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F5)
            {
                mainMenu.Visible = !mainMenu.Visible;                
            }
        }
    }
}
  1. Build, Reload() and Test that everything is still working.

Refactor Breakdown

What we did is split our code into smaller digestable pieces

            CreateMainMenu();
            CreatePlayerMenu();
            CreateVehicleSpawnerMenu();
            CreateWeaponsMenu();

Each method defined here is responsible for creating and adding items to that menu

Example - CreatePlayerMenu()

        private void CreatePlayerMenu()
        {
            // Fix Player
            NativeItem itemFixPlayer = new NativeItem("Fix Player", "Restores Player's Health and Armor");
            itemFixPlayer.Activated += (sender, args) =>
            {
                Game.Player.Character.Health = Game.Player.Character.MaxHealth;
                Game.Player.Character.Armor = Game.Player.MaxArmor;
                Notification.Show("Health and Armor Restored!");
            };
            playerMenu.Add(itemFixPlayer);
        }

Is responsible for creating all our items in our Player Menu, so we'll be adding the other scripts like invincible and wanted level

AddMenusToPool();

In this method we add all our menus to our menuPool as shown here

        private void AddMenusToPool()
        {
            menuPool.Add(mainMenu);
            menuPool.Add(playerMenu);
            menuPool.Add(vehicleSpawnerMenu);
            menuPool.Add(weaponsMenu);
        }

The Code

Let's implement our Invincible-script to our Menu

  1. Copy and Paste the following
using System;
using System.Windows.Forms;
using GTA;
using GTA.UI;
using LemonUI;
using LemonUI.Menus;

namespace NucleiLite
{
    public class Main : Script
    {
        ObjectPool menuPool = new ObjectPool();
        NativeMenu mainMenu = new NativeMenu("NucleiLite", "Main Menu");
        NativeMenu playerMenu = new NativeMenu("NucleiLite", "Player Menu");
        NativeMenu vehicleSpawnerMenu = new NativeMenu("NucleiLite", "Vehicle Spawner Menu");
        NativeMenu weaponsMenu = new NativeMenu("NucleiLite", "Weapons Menu");

        public Main()
        {
            CreateMainMenu();
            CreatePlayerMenu();
            CreateVehicleSpawnerMenu();
            CreateWeaponsMenu();

            AddMenusToPool();

            KeyDown += OnKeyDown;
            Tick += OnTick;
        }

        private void CreateMainMenu()
        {
            mainMenu.AddSubMenu(playerMenu);
            mainMenu.AddSubMenu(vehicleSpawnerMenu);
            mainMenu.AddSubMenu(weaponsMenu);
        }

        private void CreatePlayerMenu()
        {
            // Fix Player
            NativeItem itemFixPlayer = new NativeItem("Fix Player", "Restores Player's Health and Armor");
            itemFixPlayer.Activated += (sender, args) =>
            {
                Game.Player.Character.Health = Game.Player.Character.MaxHealth;
                Game.Player.Character.Armor = Game.Player.MaxArmor;
                Notification.Show("Health and Armor Restored!");
            };
            playerMenu.Add(itemFixPlayer);

            // Invincible
            NativeCheckboxItem checkBoxInvincible = new NativeCheckboxItem("Invincible", "Your character can no longer die.");
            checkBoxInvincible.CheckboxChanged += (sender, args) =>
            {
                Game.Player.Character.IsInvincible = checkBoxInvincible.Checked;
                Notification.Show($"Invincible: {Game.Player.Character.IsInvincible}");
            };
            playerMenu.Add(checkBoxInvincible);
        }

        private void CreateWeaponsMenu()
        {
        }

        private void CreateVehicleSpawnerMenu()
        {
        }

        private void AddMenusToPool()
        {
            menuPool.Add(mainMenu);
            menuPool.Add(playerMenu);
            menuPool.Add(vehicleSpawnerMenu);
            menuPool.Add(weaponsMenu);
        }

        private void OnTick(object sender, EventArgs e)
        {
            menuPool.Process();
        }

        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F5)
            {
                mainMenu.Visible = !mainMenu.Visible;                
            }
        }
    }
} 
  1. Build, Reload() and Test the script by checking the Invincible-item

image

image

Code Breakdown - Simplified

Let's break our implementation down

            // Invincible
            NativeCheckboxItem checkBoxInvincible = new NativeCheckboxItem("Invincible", "Your character can no longer die.");
            checkBoxInvincible.CheckboxChanged += (sender, args) =>
            {
                Game.Player.Character.IsInvincible = checkBoxInvincible.Checked;
                Notification.Show($"Invincible: {Game.Player.Character.IsInvincible}");
            };
            playerMenu.Add(checkBoxInvincible);
NativeCheckboxItem checkBoxInvincible = new NativeCheckboxItem("Invincible", "Your character can no longer die.");

We create a new NativeCheckboxItem which is part of the LemonUI-library. We give it a Title and a Description


checkBoxInvincible.CheckboxChanged += (sender, args) =>

Like we did with our itemFixPlayer-script we assign an anonymous method to our CheckboxChanged-event. This event is a part of the NativeCheckboxItem and is called everytime the checkBoxInvincible changes its checked-state

            {
                Game.Player.Character.IsInvincible = checkBoxInvincible.Checked;
                Notification.Show($"Invincible: {Game.Player.Character.IsInvincible}");
            };

We then set the Game.Player.Character.IsInvincible to the same value as the checkBoxInvincible.Checked state is. So if the checkbox is checked the IsInvincible becomes true and if its unchecked it becomes false, we also call the Notification.Show() method to display to the user the current state of the IsInvincible

There is also something new going on in our Notification.Show() method, that is this part

$"Invincible: {Game.Player.Character.IsInvincible}"

This is called string interpolation - look at the advanced section for a better understanding, for now just know that this is the equivalent of saying the following

Notification.Show("IsInvincible: " + Game.Player.Character.IsInvincible.ToString());

But it's much more easy to read. string-interpolation is defined by the $ sign infront of the string you want to interpolate - to give you a better idea of the power of this, consider the below code

string firstName = "Kimono";
string lastName = "Boy";
int age = 25;
bool hasPets = true;

Notification.Show("First Name: " + firstName + "\nLast Name: " + lastName + "\nAge: " + age.ToString() + "\nHas Pets?: " + hasPets.ToString());

image

With string-interpolation we can get the same result, but with a much simpler code

string firstName = "Kimono";
string lastName = "Boy";
int age = 25;
bool hasPets = true;

Notification.Show($"First Name: {firstName}\nLast Name: {lastName}\nAge: {age}\nHas Pets?: {hasPets}");

image

Note: "\n" is an escape character and is how we write new lines
You can learn more about escape characters at String Escape Characters

Also Note: This is with 4 variables only. Imagine larger messages or writing information to a file.

playerMenu.Add(checkBoxInvincible);

At last, we add the checkBoxInvincible item to our Player Menu

Code Breakdown - Advanced

There is not really much information to give about this code in the advanced section that we didn't cover in the simplified section - so we're just further going to understand the string interpolation part

Notification.Show($"Invincible: {Game.Player.Character.IsInvincible}");

String interpolation is easier to read and write than concatenating strings. In addition, it is less error-prone, since you don't have to worry about getting the order of the values correct or accidentally leaving out a space or other delimiter. It also helps prevent injection attacks by automatically escaping any special characters in the interpolated expressions.

String interpolation can even perform code-logic and evaluate the result of an expression, for instance

                int a = 5;
                int b = 2;

                Notification.Show($"The Value of {a} + {b} is {a + b}");

image

You can learn more about it here String Interpolation

To summarize: string interpolation is a more concise and readable way to construct dynamic strings in C# than concatenating strings. It also helps prevent errors and injection attacks, making it a safer option.

Conclusion

We've implemented our Invincible-script to our Menu - we can now set the Character Invincible or Not depending on the checked-state of our NativeCheckboxItem called checkBoxInvincible

Previous - Implementing Fix Player Script
Next - Implementing Wanted Level Script