top of page
Writer's pictureNostalgiq

RPG Builder Mod: Modding the NPC Spawner to allow AI Overrides

Updated: Feb 7

Intro

Recently I asked Thomas whether it would be possible to put an Override on the NPC Spawner for default AI behavior a mob is initialized with, and he said it would be possible. For me, this was a great feature to work on because the alternative is to duplicate NPCs and set a different behavior for each one. While that's viable, it also adds a lot of mostly duplicated records to the database, which I want to avoid.


I wanted to work on this because in our game we need to be intentional about the initial behaviors NPCs are spawned with. If we want NPCs to spawn with random initial behaviors that works out of the box with RPGB, which is awesome and certainly has many use cases.


Below is a highlighted image of what you get after implementing this mod.


Note: You won't be able to follow along with this post unless you already own a copy of RPG Builder. Please check out our RPG Builder Resource post to learn more about the product.

As always, backup and version control your projects before modding them.


Disclaimer: There is no guarantee or future support offered regarding these changes. I tested them out at the time I wrote them, and they worked within the scope of my needs. However, I am not the author of RPGB and therefore am not the authoritative source on whether these mods are complete. Use at your own risk, and always backup your projects. about this mod.


Modded RPGB v2.0.6. New code additions are always highlighted in green, whilst RPGB code is always highlighted in blue.


Mod NPCSpawner.cs

For this mod we first need to modify the NPCSpawner.cs script. This script handles the in-game NPC initialization.

... (edits around line 52)
public RPGSpecies Species;
public bool OverrideDefaultAIState;
public AIStateIdle AIStateIdleDefault;
public AIStateIdleTemplate AIStateIdleTemplateDefault;
public bool OverrideRespawn;
...

We'll use OverrideDefaultAIState to capture whether the user intends to Override. AIStateIdleDefault and AIStateIdleTemplateDefault will be the user-specified Override defaults to the NPC AI template defined in the RPGB Editor.


Mod NPCSpawnerInspector.cs:

Next we simply add the fields in the Inspector so the user can alter the boolean and drag and drop their overrides.

... (edits around line 124, just below the Species Override section)
Spawner.OverrideDefaultAIState = EditorGUILayout.Toggle("Default AI State?", Spawner.OverrideDefaultAIState);
if (Spawner.OverrideDefaultAIState)
{
    Spawner.AIStateIdleDefault =
        (AIStateIdle)EditorGUILayout.ObjectField("AI State", Spawner.AIStateIdleDefault, typeof(AIState), false);
    Spawner.AIStateIdleTemplateDefault =
        (AIStateIdleTemplate)EditorGUILayout.ObjectField("AI State Template", Spawner.AIStateIdleTemplateDefault, typeof(AIStateTemplate), false);
    GUILayout.Space(5);
}
...

Mod AIState.cs

This script has a bit of code in the GetName() method which removes the text (Clone) from the Game Object name, namely:

string soName = name.Remove(name.Length - 7, 7);

Go ahead and replace that line with this line:

string soName = name.Replace("(Clone)", "");

In my build I ended up with some instances of (Clone)(Clone) which was causing issues, and the Length approach wasn't getting the name right as a result.


Mod AIEntity.cs

The last step is to figure out where the default states are loaded from. Thomas uses a really cryptic naming convention, and it took me a while to determine that the GetDefaultState() method was where I should look. Trololololol.


Anyway, we need that method to look like this now:

public AIStateIdle GetDefaultState()
{
    if (ThisCombatEntity.GetSpawner().OverrideDefaultAIState)
    {
        return ThisCombatEntity.IsPet() ? (AIStateIdle) ActiveStates[BehaviorTemplate.DefaultPetState.name].State : (AIStateIdle) ActiveStates[ThisCombatEntity.GetSpawner().AIStateIdleDefault.name].State;
    }
    return ThisCombatEntity.IsPet() ? (AIStateIdle) ActiveStates[BehaviorTemplate.DefaultPetState.name].State : (AIStateIdle) ActiveStates[BehaviorTemplate.DefaultState.name].State;
}

Simple. If the user specified an Override, use it by adding it as an eligible state to ActiveStates. Else, use the State that's specified in the RPGB database.

But there are two other places we need to fix as well. They are as follows:

  • The ResetKnockback() method.

  • The InitPhase() method.

What you do in both of these is replace the line that reads as this:

currentState = ThisCombatEntity.IsPet() ? ActiveStates[BehaviorTemplate.DefaultPetState.name].State : ActiveStates[BehaviorTemplate.DefaultState.name].State;

to this:

if (ThisCombatEntity.GetSpawner().OverrideDefaultAIState)
{
    currentState = ThisCombatEntity.IsPet() ? (AIStateIdle) ActiveStates[BehaviorTemplate.DefaultPetState.name].State : (AIStateIdle) ActiveStates[ThisCombatEntity.GetSpawner().AIStateIdleDefault.name].State;
}
else
{
    currentState = ThisCombatEntity.IsPet() ? ActiveStates[BehaviorTemplate.DefaultPetState.name].State : ActiveStates[BehaviorTemplate.DefaultState.name].State;   
}

What this does is sets the currentState to the one specified in the Spawner Override in a few places where the default behavior is used.

The End

Here's a video of it in action:


You can see that there are three NPC Spawners in the scene. Each one has a different behavior that the same NPC initializes with. One is Idle, the other two have different versions of a Roaming State/Template.


Since NPC Spawners can take multiple NPCs it's worth mentioning that the default behavior will override the behavior of all NPCs in that list.

Commentaires


Les commentaires ont été désactivés.
bottom of page