Aggrevated-by-dialogue Enemy Respawn

OK so by creating the Aggro Group as a prefab, and linked that to my Respawn Manager parent, I managed to get the reference to the prefab of the Aggro Group to work, but… the guard doesn’t show up in the game world (at first it was because he was flying (ahh… games) in the game scene, but even after dragging him down, he’s still… invisible (and that only happens when he’s under the Aggro Group Respawn Manager parent empty gameObject)).

Edit: I split the Respawn Manager from the rest of the Aggro Guard Group, and the guard shows up, but he still doesn’t respawn after he’s killed…

Edit 2: placing a Respawn Manager on my dialogue guard just caused the entire engine to crash because of memory allocation issues…

Edit 3: My player respawner stopped working… This just keeps getting worse 🤦🏻 (fixed this one by deleting the aggro group respawn manager)

I don’t think you’re understanding this at all…
The Aggro Group is NOT a prefab, it should be in the scene.
The only prefab is the Guard or the Speaker, and those should be linked from the assets into a Respawn Manager (which is also… not a prefab, should be one in the scene per guard).

OK I do have a bit of a problem… the asset version of the guard just won’t accept the Aggro Group as an input to trigger him. Do I put an Aggro group under that asset to trigger him?

Edit: OK Believe it or not, I actually got this to work… Like you said, I created an Aggro Group within the Dialogue Guard Prefab itself, and assigned the values for his dialogue trigger (this was necessary so we can give him a dialogue to talk with everytime he respawns), based on the Aggro Group that exists under the enemy, so he can attack us again. Then, I created a Respawn Manager in the game scene itself, and the only variable I placed was the spawnable enemy PREFAB. Thanks again so much for tolerating me this long night Brian, this was a nightmare to get it to work, and I deeply appreciate your patience with me tonight!

The only drawback I have against this attempt of mine, is that I genuinely can’t pick which enemies exactly I want involved in a battle, which would not make it fun if, for example, I have a dungeon that has a large mix of creatures (I still want this fixed)

(I’m still thinking of how will I aggregate a group of enemies though, just through this dialogue… Probably just a regular shouting distance will do the trick, unless I want specific enemies to fight along (which I don’t see myself desperately needing). For now I’m just happy that I have a RESPAWNABLE guard I can interact with and trigger through dialogue!)

My follow up 4 questions would be (P.S: I apologize in advance if they’re a lot):

  1. [IGNORE, I SOLVED THIS ONE] How do we only aggregate the group of enemies (or make the Shouting distance effective in this case) only if he’s under attack, not through the dialogue? (Edit number idk: I fixed this, by creating a new void function in AIController.cs called ‘AggrevateOthers()’, that simply switches the boolean ‘aggrevateOthers’ to true (if it’s called… and it is, through the DialogueTrigger.Invoke() function), and increasing the ‘shoutDistance’ variable to a high enough value)

  2. How do we stop my Dialogue Guard (generally any NPC, not just this guard) from patrolling when we want to talk to him, and then wait for a few seconds before he goes back to patrolling duty when our conversation is over?

  3. Let’s examine a case where the player dies, and he didn’t kill the Dialogue Guard. When the player Respawns, in this case, the guards’ DialogueTrigger is still on ‘Attack’ mode (doesn’t matter if he’s aggressive or not, he’s still going to fight me if he sees me when I respawn (assuming I attacked him before my death, and I didn’t kill him)), caused by the dialogue triggered by the player before his death, but I want his dialogue reset so that the entire city (i.e: his allies) doesn’t start chasing me down as soon as I get close to him after my respawn. How do I fix that?

  4. Is there anyway we can change the input for ‘AggroGroup.cs’ from ‘Fighter’ to ‘RespawnManager’? This would make providing the inputs to my AggroGroup significantly easier (and since my entire fighter system swapped from ‘Fighter’ to ‘RespawnManager’, I think this makes perfect sense), because now I can select who is his ally, and who is not

  5. This block of code is causing my Main Menu → Resume Game some serious issues (I tried deleting it, and while it did get my fade to game effect to work semi-properly, it just kept my game in black screen when it exists). Any way to fix it?:


            if (spawnedEnemy.TryGetComponent(out DialogueAggro dialogueAggro) && aggroGroup != null)
            {

                dialogueAggro.SetAggroGroup(aggroGroup);

            }

            aggroGroup.AddFighter(spawnedEnemy.GetComponent<Fighter>());

Your RespawnManager now handles combat??? It shouldn’t. It’s job should be to spawn and respawn the enemy, and hooking up the Patrol path and if needed, the dialogue stuff discussed here. The enemy itself should have a Fighter component on it which manages combat.

I have no idea why it would do that, unless you’re not null checking aggrogroup (not every Respawner would have one, just the Respawners which respawn characters intended for the group).

You could have the AggroGroup subscribe to the Player’s Health’s OnDeath UnityEvent (remember, you use AddListener for that), and in that subscribed method, call Activate(false)

It does handle just the Patrol Path, Respawning, and Dialogue Stuff just as intended. However, after a bit of testing and playing around, I did notice that having an individual aggroGroup under every enemy prefab means that the prefab can immediately make respawnable enemies with dialogues that act exactly the way they should (I.e: talk first, and fight if we say the wrong thing), because the dialogueTrigger now has an AggroGroup it can talk to that’s under the same prefab rather than the scene (prefab <-> scene didn’t work), and because that Enemy Prefab also has a fighter component, it can then be injected in a RespawnManager in the game scene with no problems at all. The only problem is, because AggroGroups only accept fighters, and I respawn my enemies using RespawnManagers, I can’t group them up, hence why I’m asking if we can switch the input of the AggroGroup from just fighters to RespawnManagers, as nearly all my fighters now have a RespawnManager taking care of them, which should (theoretically) solve the problem, and we can be more selective about which enemies we want involved in a fight

Trust me, I’m not sure what’s going on either. I just know the stack trace complains pretty much about the fact that it can’t access the respawnables when this block is active

If it helps in anyway, here’s the Stack Trace, when I try resuming the game from the Main Menu with the code block mentioned above being active (for all of my enemies that have a RespawnManager handling them):

NullReferenceException: Object reference not set to an instance of an object
RPG.Respawnables.RespawnManager.Respawn () (at Assets/Project Backup/Scripts/Respawnables/RespawnManager.cs:95)
RPG.Respawnables.RespawnManager.Start () (at Assets/Project Backup/Scripts/Respawnables/RespawnManager.cs:47)

I’ll give this a go and keep you updated (and… my attempt didn’t work. I’m not very familiar with events if I’m being honest. This is what I tried doing):

In AggroGroup.Start(), I added these two lines:

Health health = GetComponent<Health>();
health.onDie.AddListener(DeactivateAggro);

and here is my ‘DeactivateAggro()’ function:

public void DeactivateAggro() {
            this.enabled = false;
        }

Finally, I went to Health.cs in the inspector, and added into onDie my aggroGroup and went to call the ‘DeactivateAggro()’ method from there. It didn’t work as expected (please guide me :slight_smile:)

OK so to retackle my issue of making my enemies non-aggressive after killing my player, I tried something a bit funky: I created a function called ‘DeactivateAggro()’ in ‘AIController.cs’, which checks for if the player is dead or not before setting a variable I have called ‘nonAggro’ (which is responsible for aggregating the enemies) to true (I’m trying to figure out how to make this function account for true or false). Whilst it works in deactivating the aggression of my enemies, it doesn’t account for the default settings of the aggression of my enemies, giving me one of two choices. Either:

  • Figure a way out to code the default setting of my ‘nonAggro’ variable, to be set to whatever the game engine has it set to by default (Please help)
    OR
  • Manually set the aggression for all my enemies (which won’t work, because again… the setting isn’t set to tackle whatever the default setting was set to at first)

The AIController doesn’t even factor in to this equation. You’re taking the simple solution and converting it into a needlessly complicated one.

In AggroGroup’s Awake() method:

        private void Awake()
        {
            Health playerHealth = GameObject.FindWithTag("Player").GetComponent<Health>();
            if (playerHealth)
            {
                playerHealth.onDie.AddListener(()=>Activate(activateOnStart));
            }
        }

That’s it. That’s the whole method. I used activateOnStart in case you have an aggroGroup that starts out hostile unitl you have a dialogue that makes it not hostile.

OK I’m not sure what’s with the ‘Awake()’ method, but after re-reading the entire conversation, the ‘AggroGroup.Awake()’ method specifically causes my player’s death to get a bit messy, where he would still keep beating my enemy that killed him… and the player is still alive, just without the controls enabled, which is basically a glitch (and somehow, the enemies in the Aggro group still won’t come attack my player if he attacks one of them)

Can we dive a little deeper into the ‘dialogue’ part of the Respawn Manager? Because right now my dialogue guard is aggrevated through an Aggro Group that’s placed within his prefab, and as much as it works perfectly fine, I’m not sure if that’s the ideal solution

There should be no aggrogroup in the enemy’s prefab.

For each group of enemies you want to control together, there should be an AggroGroup in the scene. The RespawnManger should have a link to that aggrogroup. When the character respawns, add it to the aggrogroup. If the character has a DialogueAggro, pass the Aggrogroup reference to the DialogueAggro on the player.

OK another ‘dumb’ question… how do we reference the aggroGroup to the player when his dialogueAggros’ aggroGroup is not serialized? The inspector isn’t showing it up (P.S: I placed that script on the player)

If you recall at first it was serialized, and then you mentioned that it shouldn’t be

Oh, and how do you connect an AggroGroup in the scene with the Dialogue Trigger that’s based on the enemy prefab? Now I can’t even aggrevate him (I am getting the ‘Attack’ signal, but it’s not leading anywhere), considering I deleted his private aggroGroup, which resulted in me not being able to call an ‘Aggrevate’ method (the game engine isn’t budgeting… it won’t detect an Aggro Group in the scene)

I feel a bit like we’re moving in circles here.

First, I did find a small flaw in my Aggrogroup code… I was disabling the CombatTarget, but not the Fighter…

        public void Activate(bool shouldActivate)
        {
            isActivated = shouldActivate;
            foreach (Fighter fighter in fighters)
            {
                fighter.enabled = shouldActivate;
                if (fighter.TryGetComponent(out CombatTarget target))
                {
                    target.enabled = shouldActivate;
                }
            }
        }

        public void AddFighterToGroup(Fighter fighter)
        {
            if (fighters.Contains(fighter)) return;
            fighters.Add(fighter);
            fighter.enabled = isActivated;
            if (fighter.TryGetComponent(out CombatTarget target))
            {
                target.enabled = isActivated;
            }
        }

This fixes that for the two functions…

Now a walkthrough on my respawnable AggroGroup:
We’ll start with an AggroGroup. This is a component in the scene
For convenience, I’m putting the RespawnManager that will use this AggroGroup under the AggroGroup in the scene
image
Each RespawnManager has a field for the prefab to respawn, an optional AggroGroup, and an optional PatrolPath
I’m using a RespawnManger with a few other features, as I pulled it in from Spellborn Hunter, but the prevailing fields are what’s at issue:
Here’s the HostileSpeaker:
image
In his case, I don’t want him to patrol, but I do want to set the aggrogroup. The Mob Prefab is the HostileSpeaker.
I have two enemies, one with the patrol path assigned, and the other without:
image
image

On my HostileSpeaker, I have an AIConversant, a DialogueTrigger and a DialogueAggro component
My dialogue is fairly straightforward…


image

When the game starts, the placeholder objects on the RespawnManagers are destroyed, and the prefabs are spawned in.
If the RespawnManager has an AggroGroup assigned to it, then when it spawns an enemy, it adds that enemy’s fighter to the AggroGroup. When the enemy dies, it removes that enemy from the AggroGroup.
If the RespawnManager has an AggroGroup assigned to it, and the enemy has a DialogueAggro component, then it calls SetAggroGroup() on it, passing the AggroGroup.
If the RespawnManager has a PatrolPath assigned, it assigns that Patrol Path to the enemy’s AIController.

In the DialogueTrigger on the HostileSpeaker, the event calls the DialogueAggro’s CallAggroGroup
image

That’s the whole thing in a nutshell. The only hitch in the giddyup was that I forgot to disable the Fighter in AddToFighterToGroup().

OK that did introduce a bit of a new bug… I can’t attack anyone in the aggroGroup. The game just returns the ‘x’ cursor which says ‘nope, can’t do that!’… If it helps in anyway, I did re-activate the ‘Awake()’ function I had in ‘aggroGroup.cs’ (the one which was causing me saving issues when I return from the games’ main menu to the playable state):

private void Awake() {

            Health playerHealth = GameObject.FindWithTag("Player").GetComponent<Health>();
            if (playerHealth) {

                playerHealth.onDie.AddListener(() => Activate(activateOnStart));

            }

        }

and the ‘if’ statement we coded together in ‘RespawnManager.cs’:

if (spawnedEnemy.TryGetComponent(out DialogueAggro dialogueAggro) && aggroGroup != null)
            {

                dialogueAggro.SetAggroGroup(aggroGroup);

            }

            aggroGroup.AddFighterToGroup(spawnedEnemy.GetComponent<Fighter>());

And when I trigger the ‘Attack’ for my dialogue trigger through conversation with the guard, well… it returns a null reference exception error:

NullReferenceException: Object reference not set to an instance of an object
RPG.Combat.AggroGroup.Activate (System.Boolean shouldActivate) (at Assets/Project Backup/Scripts/Combat/AggroGroup.cs:57)
RPG.Respawnables.DialogueAggro.CallAggroGroup () (at Assets/Project Backup/Scripts/Respawnables/DialogueAggro.cs:13)
UnityEngine.Events.InvokableCall.Invoke () (at <ba783288ca164d3099898a8819fcec1c>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <ba783288ca164d3099898a8819fcec1c>:0)
RPG.Dialogue.DialogueTrigger.Trigger (System.String actionToTrigger) (at Assets/Project Backup/Scripts/Dialogue/DialogueTrigger.cs:21)
RPG.Dialogue.PlayerConversant.TriggerAction (System.String action) (at Assets/Project Backup/Scripts/Dialogue/PlayerConversant.cs:180)
RPG.Dialogue.PlayerConversant.TriggerExitAction () (at Assets/Project Backup/Scripts/Dialogue/PlayerConversant.cs:168)
RPG.Dialogue.PlayerConversant.Quit () (at Assets/Project Backup/Scripts/Dialogue/PlayerConversant.cs:46)
RPG.UI.DialogueUI.<Start>b__8_1 () (at Assets/Project Backup/Scripts/UI/DialogueUI.cs:30)
UnityEngine.Events.InvokableCall.Invoke () (at <ba783288ca164d3099898a8819fcec1c>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <ba783288ca164d3099898a8819fcec1c>:0)
UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114)
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57)
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272)
UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:514)

I also reversed the changes I did to my dialogue guard to make sure we can safely interact with him

You can’t attack anybody in the AggroGroup until they are hostile (aggroed)

This is the same behavior as the original AggroGroup.
After they are hostile, you will be able to fight them.

how do we make them hostile again…? I thought the dialogue trigger did that?

Well, in this case, you have the NRE, that you mentioned at the same second I typed my reply…
Is Line 57

fighter.enabled = shouldActivate;

If it is, put this line right before it:

if(!fighter) continue;

Ahh, this got the fighter for my dialogue guard to work, and my fighters get activated right after that, but there’s a follow up issue… When the guy respawns, he remembers me as an enemy, and I can’t re-trigger the dialogue with him (for all my enemies, I have a boolean called ‘nonAggro’ that determines if they’re aggressive or not. For this guy’s specific case, I just want him aggressive right after dialogue, but if he respawns, or if I (the player) respawn (This one is important to me: the enemy doesn’t remember we were enemies when I respawn, even if he was aggrevated by me fighting one of his friends), I don’t want him to remember that we were enemies). Aside from that, the other enemies in the aggroGroup don’t even bother coming to attack me (like… I want them all to die before the dialogue cycle restarts), can we fix that?

Not tonight. That’s yet another added thing you’re adding to an already complex system, which is going to create several hours of bug testing…
We’re hip deep in advanced territory here.

ooh good lord haha, well at least we got something to work tonight (I’ll Edit the comment above just a tad bit). Thanks again Brian (by the way, I seriously appreciate how far you’re willing to go into helping students out with topics that aren’t even part of the course. Not everyday you bump into an amazing lecturer willing to go this far, so thank you so much for that!)

And one last fix that might be in dire need: my ‘Awake()’ function in ‘AggroGroup.cs’ still causes me issues when I return to my game from the main menu. When I hit ‘Resume’ on a save, it goes into ‘FadeIn’ mode (i.e: Black screen), and never comes back out of it. The game works, but the screen is black

Edit: OK to keep this short and sweet, here’s what I’ve wanted to do the entire time:

  • If I attack someone in the AggroGroup, and he has a dialogue that triggered that attack (the dialogue guard), the entire gang comes along and attacks me, regardless of their ‘nonAggro’ boolean selection.
  • If I die and respawn, reset everyones’ ‘nonAggro’ boolean to the default individual setting of each enemy. This includes the dialogue guard, where he becomes someone I can interact with before triggering him again (I don’t want them remembering me negatively and still trying to attack me again, because of what I did before dying)
  • If I attack someone who isn’t the dialogue guard, and they’re part of the dialogue guard’s AggroGroup, the dialogue guard now has his Combat Target activated, and he will come and attack my player for hurting his friends, and we can attack him now as well
  • if the dialogue guard dies and I stop fighting his friends before he respawns, his default dialogue guard settings are reset, and the same goes for everyone in the group. (The only way out of this fight, is to either kill everyone before anyone of the gang respawns (which means I’ll need a large respawn time), or to run out of their detection sphere)
  • Possibly deactivate the function of keeping his friends unavailable to be attacked unless the ‘Attack’ trigger is activated by the dialogue guard

If it’s too complex or will take a while, we can just settle for activating the other group members’ aggression when one of the group is attacked and call it a day for now (and returning their ‘nonAggro’ back to default if I get killed… and the Dialogue guard resets his settings to default (i.e: if he gets killed, on his respawn he returns to being a guy we can talk to, before triggering him to a fight)). I have a lot of other functionalities I want to integrate first before going too deep into combat. I apologize if this is too much to ask for :sweat_smile:

Edit 1: if it helps in anyway, I managed to make my Dialogue Guard return to default dialogue after he dies in Combat. I did that before by accident, figured I’d do it again… :stuck_out_tongue_winking_eye:

OK before we go too deep with my previous request, there’s a bug I just noticed in the system (well, it’s a player-based bug that’s been occuring for a while):

My player has that stupid tendency to attack anyone with a health component (or a CombatTarget component, not sure…) that is around him the moment he gets out of combat with his main target… As a result, he will occasionally attack my Quest Giver or Banker, and maybe even the shopkeeper if he gets too close, and all of these are actions he’s not supposed to do (I tried deleting the fighter components on them, but this system is some deep web I can’t easily get rid of…!), and he also has the ability to attack my Aggro Guard groups, which are… well… not activated for fighting yet (if they are close enough to him after he’s done with his previous fight, then it doesn’t matter if they’re active for him to attack or not… He will still attack them)

If I were to take a wild guess, I’d say it’s because of the auto attack system I implemented, but I can use some help

Privacy & Terms