🔫Create your first fight

Creating your gamemode base

First of all, create a new Package, specifically, a game-mode

Your package.toml should look like this:

[meta]
    # friendly name
    title =                 "Awesome Gamemode"
    # contributors
    author =                "You !"
    # version
    version =               "0.1.0"

# game-mode configurations
[game_mode]
    # whether to force the custom map package to do not load
    force_no_map_package =  false
    # auto destroy all entities spawned by this package when it unloads
    auto_cleanup =          true
    # whether to load all level entities on client - only enable it if your package needs to use level static meshes entities
    load_level_entities =   false
    # the game version (major.minor) at the time this package was created, for granting compatibility between breaking changes
    compatibility_version = "1.62"
    # packages requirements
    packages_requirements = [
                            "nact",
                            "default-weapons",
    ]
    # asset packs requirements
    assets_requirements = [
                            
    ]
    # compatible maps - maps to be highlighted when starting a new game through main menu
    compatible_maps = [
                            "nact-testmap",
    ]

As you can see, we added "nact" and "default-weapons" as packages_requirements of our newly created gamemode.

Also, we use the testMap from the NACT_TestMap package. While it is not mandatory, I suggest you to use it since a few areas were left for this tutorial :) Make sure to get the Asset Pack and the Map Package of the NACT_TestMap to quickly get up and running.

Area on the test map

Inside the test map, we prepared for you an area to create your first fight.

Zone for the tutorial fight

I strongly recommend that you use the nanos-getpos package for Voltaism to show your current positon on screen.

As you can see, it contains a few cover barriers and two guard houses. Now that we are familliar with the area, let's start adding some NACT action there !

Adding the territory

As you can see, the area contains a vending machine. This is a very precious thing to conquer. To create a encounter, first we need to create a Territory for the NPCs to defend and us to assault.

Go approximatly in the middle of the fight zone like in this screenshot

Center of the territory

Then in our Package we need to create a new file Server/Index.lua .

Use the NACT.RegisterTerritory command to create the territory:

local vendingMachineTerritory = NACT.RegisterTerritory("VendingMachine", {
    zoneBounds = {
        pos = Vector(1700, -408, 198),
        radius = 2000
    },
    team = 1
})

We pass a few parameters to the RegisterTerritory function:

  • "VendingMachine" wich is the name of our Territory

  • The zone bounds, wich is the sphere zone wich, when a enemy enters will "activate" the NPCs, and if the enemy leaves, the NPCs will return to idle

  • The team of the territory. NACT uses NanosWorld team system to differenciate allies and enemies

(Optional) See the Territory bounds with debug param

If you wish, you can view your territory bounds if you edit the Debug values in NACT (Packages/nact/Server/Debug.lua) and set the NACT_DEBUG_TRIGGERS to true

NACT_DEBUG_TRIGGERS = true
NACT_DEBUG_DETECTION = false
NACT_DEBUG_BEHAVIORS = false
NACT_DEBUG_COVERS = false
NACT_DEBUG_EDITOR_MODE = false
NACT_DEBUG_NPC_CHIT_CHAT = false

You should then see the territory bounds:

Territory bounds of VendingMachine

Adding the first NPC Fighter

(optional) Add something to spawn the player

Now that we are going to have some action, you should spawn the player. Here is some quick snippet if you want:

local function SpawnPlayer(player)
    local spawnedCharacter = Character(
        Vector(0,0, 200),
        Rotator(),
        "nanos-world::SK_ClassicMale"
    )

    local wAK47 = AK47(Vector(), Rotator())

    spawnedCharacter:PickUp(wAK47)

    player:Possess(spawnedCharacter)
end

Player.Subscribe("Ready", SpawnPlayer)

Package.Subscribe("Load", function()
    for k, v in pairs(Player.GetAll()) do
        SpawnPlayer(v)
    end
end)

The guard near the vending machine

Next to the vending machine we should add a guard next to it.

This seems like a great place to guard the vending machine

First create a Character like you would do in NanosWorld

local cNpcVendingMachine = Character(Vector(2065, 387, 200), Rotator(0, -170, 0), "nanos-world::SK_Mannequin")
cNpcVendingMachine:SetTeam(1)

Remember to set a team to the character or he will see you as an ally!

Next, we need to give a weapon to the character

local wAk47ForVendingMachineGuard = AK47(Vector(), Rotator())
wAk47ForVendingMachineGuard:SetAutoReload(false)

cNpcVendingMachine:PickUp(wAk47ForVendingMachineGuard)

We disable AutoReload on the weapon because we want the NPC to get in cover before reloading.

Then, we make the NPC pickup the weapon.

Now we have a NanosWorld Character with a weapon. Finally, to give it NPC AI we need to make it controllable by NACT

For this, we we will take a simple route and use a pré-configured NPC configuration for it We will use the NACT.RegisterNPC function:

NACT.RegisterNpc(cNpcVendingMachine, "VendingMachine", NACT.Defaults.Millitary.Soldier)

We pass as parameters:

  • The NanosWorldCharacter to control

  • The Territory where this NPC belongs

  • The configuration of the NPC. We use NACT.Defaults.Millitary.Soldier pré configuration.

Pré configuration are useful when you want simple NPCs without tinkering too much with it's parameters. Later in the tutorial, we will dive deeper in configuration options, but for guarding the vending machine, it's plenty enough !

NPC is ferociously guarding the Vending Machine

Adding an ally NPC

Not all NPCs have to be enemies, you can also add friendly NPCs that will help you get to the fight!

We will add a friendly NPC when the player spawn, modify the SpawnPlayer function. First create a Character and give him an AK47

    local cNpcFren = Character(Vector(200 ,0, 200), Rotator(), "nanos-world::SK_ClassicMale")
    local wAk47ForFren = AK47(Vector(), Rotator())
    wAk47ForFren:SetAutoReload(false)
    cNpcFren:PickUp(wAk47ForFren)

Notice that we did not set any Teams this time. That means the NPC is in the same team as the Player (team 0). In Nanos and in NACT, that makes them Allies.

Like in the previous section we will use a pré-configuration, we will use NACT.Defaults.Allies.FollowerSoldier

BE CAREFULL : FollowerSolider is a function ! You must pass the character to follow (the character of our player we spawned).


NACT.RegisterNpc(cNpcFren, "VendingMachine", NACT.Defaults.Allies.FollowerSoldier(spawnedCharacter))
Friend tried his best. But he got no KitKat :(

An ally have now joined you on the battle !

Adding a patrolling NPC

(optional) What is behind the pré-configurations

For now, we have used pre-configurations, but in order to get a bit deeper in the configurations of a NACT NPC, we will make our own configuration. First, let's see how the NACT.Defaults.Millitary.Soldier is defined (in NACT/Server/Defaults.lua)

NACT.Defaults.Millitary = {
    Soldier = {
        behaviors = {
            { class = NACT_Idle },
            { class = NACT_Detection},
            { class = NACT_Alert},
            { class = NACT_Combat},
            { class = NACT_Engage},
            { class = NACT_Seek},
            { class = NACT_Cover},
    }}
}

As we can see, the soldier is defined with a list of behaviors he can use. For now, we won't explore behaviors that much but we know one thing, this NPC default does not have the NACT_Patrol behavior, but we want to add that !

First, we want to get a good start location for the patrolling NPC. In order to make things easier, l'ets make the Vending Machine guard an ally so he won't shoot at us. For this, change his team to 0, like this:

local cNpcVendingMachine = Character(Vector(2065, 387, 200), Rotator(0, -170, 0), "nanos-world::SK_Mannequin")
cNpcVendingMachine:SetTeam(0)

As you can see, all our NPCs are now allies and our loyal ally from before follows us.

Everyone is friend now

Now that there is no action going on let's find a great spawn point for the patrolling NPC

The code for spawning the character is exactly the same as the previous enemy NPC. What differs here is the spawn location of the character

local cPatrollingNPC = Character(Vector(2420, 417, 200), Rotator(0, -170, 0), "nanos-world::SK_Mannequin")
local wAk47ForPatrollingNpc = AK47(Vector(), Rotator())
wAk47ForVendingMachineGuard:SetAutoReload(false)
cPatrollingNPC:PickUp(wAk47ForPatrollingNpc)

Now, we must create a new patrol route. Patrol route are set in a Territory, because multiple NPCs can share the same patrol Route. We will specify the patrol route called "VendingRoute" on the "VendingMachine" territory we created at the beginning of this tutorial

vendingMachineTerritory:AddPatrolRoute("VendingRoute", {
    points = {
        Vector(2108.63, 225.56, 200),
        Vector(2173.25, -8123, 200),
        Vector(1540.30, -339, 200)
    },
    walkMethod = "circle"
})

Next, we must create our config file for this NPC while registering it. We need to give it all the abilities of a "Soldier" default behavior, but instead of NACT_Detection we want the NPC to have NACT_Patrol behavior

NACT.RegisterNpc(cPatrollingNPC, "VendingMachine", {
    behaviors = {
        { class = NACT_Idle },
        { class = NACT_Patrol, config = {
            patrolPath = "VendingRoute"
        }},
        { class = NACT_Alert},
        { class = NACT_Combat},
        { class = NACT_Engage},
        { class = NACT_Seek},
        { class = NACT_Cover},
}})

Next, remove the code to spawn the ally NPC, our ally is of great help but he is not very stealthy. And set back the orther NPCs as enemies

cPatrollingNPC:SetTeam(1)
cNpcVendingMachine:SetTeam(1)
Patrolling NPCs add interesting stealth scenarios to the fight

Ending

Congratulations ! We hope this first fight helped you get a bit more familiar with NACT and hyped you to get more familiar with more complex concepts of the lib. Before going to the Deep Dive section, we recommend you to read the Essential Concepts part. See you soon and share with me your awesome creatioons !

Last updated