Search Unity

[RELEASED] Emerald AI 2.3 - The Ultimate Universal AAA Quality AI Solution

Discussion in 'Assets and Asset Store' started by BHS, Jun 26, 2015.

  1. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    You're welcome! :)

    That's strange, it should be working. The avoidance option only works if they AI is not in combat. Also, try enabling all of the debug options to ensure nothing is obstructing the AI's raycast. These options should help pinpoint the issue.
     
  2. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    I can add an option to adjust this with the 2.2.2 update. The variable needed to detect the distance form an AI's target is with YourEmeraldAIComponent.DistanceFromTarget. I have not been able to recreate this issue so I'm curious as to why the AI is still able to attack your player even though it is out of range. You can also try enabling the Debug options, located under the Docs tab, to see if this helps pinpoint the cause of the issue.
     
  3. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Thanks, I will look into this before I submit version 2.2.2.


    I think this is just a limitation to the SetCombatTarget function as it only sets the chase distance to 2,000. If you have a much larger terrain, you will need to set it higher. I also noticed that the movement is never set to Run within this function so the AI only walks to its target. You can fix this by replacing what's in the SetCombatTarget with the following code. If 8,000 isn't enough, set the value higher. I tested this with a large terrain and everything worked correctly.

    Code (CSharp):
    1. EmeraldComponent.CurrentTarget = Target;
    2. EmeraldComponent.m_NavMeshAgent.stoppingDistance = EmeraldComponent.AttackDistance;
    3. EmeraldComponent.m_NavMeshAgent.destination = Target.position;
    4. EmeraldComponent.EmeraldDetectionComponent.PreviousTarget = Target;
    5. EmeraldComponent.CurrentMovementState = EmeraldAISystem.MovementState.Run;
    6. EmeraldComponent.CombatStateRef = EmeraldAISystem.CombatState.Active;
    7. EmeraldComponent.AIAnimator.SetBool("Idle Active", false);
    8. EmeraldComponent.AIAnimator.SetBool("Combat State Active", true);
    9. EmeraldComponent.MaxChaseDistance = 8000; //Can increase this value if you need to
     
    llJIMBOBll likes this.
  4. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Yes, all damage is sent to the EmeraldAIPlayerDamage script. Within this script, you call your own functions for custom player damage. Here's a simple example function that will take in account an AI's level and use it as a multiplier. Just use this instead of the DamagePlayerStandard function within the EmeraldAIPlayerDamage script.

    To use it, call the code below within the SendPlayerDamage function:
    Code (CSharp):
    1. DamagePlayerByLevel(DamageAmount, EmeraldComponent);
    Code (CSharp):
    1. void DamagePlayerByLevel(int DamageAmount, EmeraldAISystem EmeraldComponent)
    2.         {
    3.             if (GetComponent<EmeraldAIPlayerHealth>() != null)
    4.             {
    5.                 float LevelMultiplier = EmeraldComponent.AILevel * 0.25f;
    6.                 DamageAmount = (int)(DamageAmount * LevelMultiplier);
    7.                 DamageAmount = Mathf.Max(1, DamageAmount);
    8.                 GetComponent<EmeraldAIPlayerHealth>().DamagePlayer(DamageAmount);
    9.             }
    10.         }
     
  5. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    claudius_I likes this.
  6. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    I do plan on updating it and I will try to do this asap.

    You basically just need to update the script names to use the new namespaces and script names. So Emerald_AI is now EmeraldAI.EmeraldAISystem.
     
  7. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Emerald AI 2.0 was a new version release. So, Emerald AI 2.0 contains Emerald AI 2.2. You can see the most recent version on the Asset Store under the asset's version number.
     
  8. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Emerald AI uses NavMesh so AI are confined to the ground and their NavMesh's Base Offset. I may add an option to modify the NavMesh's Base Offset for simple AI such as fish with the 2.3 update.
     
  9. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Emerald AI uses an easy to use editor for creating AI. Most of the functionality is preset and done for you so you don't have to use nodes to create any AI mechanics. The API can be found within the EmeraldAIEventComponent on each AI. This allows users to add quite a bit of added functionality through custom scripts or simply creating an event. There are 8 events that can be used that are triggered when an AI does a certain action such as deal damage, arrive at a destination, die, etc. I plan on expanded the included API with the next couple of updates. All API should be accessible with PlayMaker.
     
  10. SickaGamer

    SickaGamer

    Joined:
    Jan 15, 2018
    Posts:
    691
    Advanced AI coming? Ie. phased boss fights, special attacks ect...
     
  11. wood333

    wood333

    Joined:
    May 9, 2015
    Posts:
    620
    Does Emerald have unity events? Edit : found the events.

    Is there a limit to the total number of factions?

    The OnDeath unity event is useful, but it would be even more useful it returned who killed it. Especially a OnDeath "by Player," would permit me to track the Player's performance.
     
    Last edited: May 16, 2019
  12. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Yes, with the 2.3 update. :)
     
  13. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Yes, it has 8 Unity Events (OnEnable, OnStart, OnDeath, OnAttack, OnStartCombat, OnDamge, ReachedDestination, and OnFlee). All can call outside functions or Emerald AI's built-in functions/API.

    The total faction amount is 5, but I will be redoing the way this is done to customize the amount with a future update.
     
    wood333 likes this.
  14. SickaGamer

    SickaGamer

    Joined:
    Jan 15, 2018
    Posts:
    691
    Alright! Time to get started!!! :p
     
  15. wood333

    wood333

    Joined:
    May 9, 2015
    Posts:
    620
    The OnDeath unity event is useful, but it would be even more useful if it returned who killed it. Especially a OnDeath "by Player," would permit me to track the Player's performance. This is necessary because AI can kill each other, which I like and is very good and realistic, but I don't track ai combat performance, just the Player's
     
    Last edited: May 16, 2019
  16. llJIMBOBll

    llJIMBOBll

    Joined:
    Aug 23, 2014
    Posts:
    553
    Thank you Sir!!!! :D
     
  17. MWray

    MWray

    Joined:
    Sep 27, 2018
    Posts:
    2
    Update to my previous post. I want to see if I can get some help figuring out why my animals no longer dynamicaly wander. I say no longer, because I had them wandering fine with Unity version 2018.2.17 and Emerald AI version 2.0, but now I've upgraded to Unity 2018.3.11 and Emerald AI 2.2 and none of the animals will dynamicaly wander. I have verified they are on the navmesh, so I don't believe that is the problem. Any suggestions for things to look at or try will be appreciated. I can send screen shots or setup details if necessary. Thanks. Since the first post, I have discovered that the animals will wander appropriately if a plane or terrain are in the scene and have a y component very near the value of the navmesh. Is there something different about navmeshes in unity 2018.11 or how emerald version 2.0 address the navmesh
     
  18. kylewetton

    kylewetton

    Joined:
    Sep 6, 2018
    Posts:
    24
    Hey mate, so here's a quick test. There is nothing strange going on with DistanceFromTarget and seems accurate? (See bottom left of screenshot). In this screenshot he is currently attacking me and I'm receiving hit damage.

    Importantly, as soon as my DistanceFromTarget reaches over 7f (one more jump in the screenshot), he stops, any lower than that and it's game on. I've confirmed his ray is hitting me at all times during this test, and is pointing accurately at my player.

    Screen Shot 2019-05-17 at 1.40.58 PM.png
     
    llJIMBOBll likes this.
  19. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    367
    Now, too many sales is not a bad problem to have. Continued success, BHS!

    Mark
     
    BHS likes this.
  20. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    367
    It may be possible to recreate this issue using water. I recently introduced water to my scene, and use NavMesh Obstacles to break the walkable paths. The water layer wasn't working as I expected it to. Anyway, if the player is just on the edge of the water marker and the AI is directly in front of the player but can't path to him, he looks for another path. If the player backs up below the water onto the navmesh underwater, the AI attacks, even though they are technically too far away. Their attacks will land and cause damage, as long as the player is on the navmesh and below the AI. I noted it as interesting, but something to solve later.

    Mark
     
  21. Room101_Studios

    Room101_Studios

    Joined:
    Apr 4, 2018
    Posts:
    5
    BHS,

    Any news on 2.2.2? ;)
     
  22. SickaGamer

    SickaGamer

    Joined:
    Jan 15, 2018
    Posts:
    691
    Yeah! @BHS Get 2.2.2 done so that you can get 2.3 done!!!!
     
  23. FractalCore

    FractalCore

    Joined:
    May 15, 2009
    Posts:
    139
    Have you made any progress on this? The issue of Playmaker not being able to send damage to the AI since the 2.2 upgrade.
     
  24. GWStudio

    GWStudio

    Joined:
    Sep 27, 2016
    Posts:
    97
    Hi... is there is any way to make the damage decrease based on distance from enemy i am using RFPS and i use projectile with this script attach to it :

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    namespace EmeraldAI.Example
    {
    [RequireComponent(typeof(Rigidbody))]
    [RequireComponent(typeof(AudioSource))]
    public class EmeraldAICollisionDamage : MonoBehaviour
    {
    public int DamageAmount = 100;
    public int PushAmount = 400;
    public AudioClip CollisionSound;
    public string EmeraldAITag = "Respawn";

    Rigidbody m_Rigidbody;
    AudioSource m_AudioSource;

    void Start()
    {
    m_Rigidbody = GetComponent<Rigidbody>();
    m_AudioSource = GetComponent<AudioSource>();
    }

    void OnCollisionEnter(Collision C)
    {
    if (C.gameObject.tag == EmeraldAITag && m_Rigidbody.velocity.magnitude > 0)
    {
    if (C.gameObject.GetComponent<EmeraldAISystem>() != null)
    {
    C.gameObject.GetComponent<EmeraldAISystem>().Damage(DamageAmount, EmeraldAISystem.TargetType.NonAITarget, transform, PushAmount);
    m_AudioSource.PlayOneShot(CollisionSound);
    }
    }
    }
    }
    }

    Thanks
     
  25. franky_li

    franky_li

    Joined:
    Aug 8, 2016
    Posts:
    130
    @BHS I have a problem with AI alignment. Even with Align AI switched on, AI will not be aligned. AI is an animal, so it must be aligned.
    Any suggestions?
     
  26. Tandinos

    Tandinos

    Joined:
    Jan 10, 2015
    Posts:
    6
    So how do I control the volume / turn off the default attacking sounds on AI ? its super loud and I can't seem to find it unless im blind, also how do we set up an fps controller to work deal damage ? can get it to lose health but yeah cant damage enemies
     
    Last edited: May 21, 2019
  27. Moe-Mogare

    Moe-Mogare

    Joined:
    Apr 16, 2015
    Posts:
    9
    I followed the tutorial to install it on invector & ran into this error I don't know whats going on

    Assets\Emerald AI\Scripts\Components\EmeraldAIPlayerDamage.cs(17,37): error CS1525: Invalid expression term '/'


    Assets\Emerald AI\Scripts\Components\EmeraldAIPlayerDamage.cs(89,10): error CS1513: } expected
     
  28. llJIMBOBll

    llJIMBOBll

    Joined:
    Aug 23, 2014
    Posts:
    553
    Hi for some reason the ai can detect player thru walls? and if the player is higher than the ai or on the level above the ai can attack the player.

    I've added some gifs to show, and also my detection setup settings. The building use building layer and my my building for maps use another layer but ai cant attack it.


    https://i.gyazo.com/be60054c41af3ee20fab9b925ab01682.gif


    https://i.gyazo.com/93bf8be86717356e0cf4367f22d31da1.gif


    https://i.gyazo.com/9dad3aded10f4dd1da53c0c20d7f5b1c.gif


    https://i.gyazo.com/ca8a2335c15c211d5ae3ce7fc2c59675.gif

    Cheers
     
  29. llJIMBOBll

    llJIMBOBll

    Joined:
    Aug 23, 2014
    Posts:
    553
    Yes this is happening to me too, If i about the height of the detection radius or anywhere below it the ai will attack, but once i go just 1 above the detection radius he no longer attacks. plus also the attack range is like 5 and some ai even 1
    Not sure how to fix it.

    Cheers
     
  30. songjiekun

    songjiekun

    Joined:
    Jan 21, 2017
    Posts:
    15
    hello:
    very interesting ai system
    does this work with generic/ non-humanoid characters and enemies?
     
  31. SickaGamer

    SickaGamer

    Joined:
    Jan 15, 2018
    Posts:
    691
    @BHS 2.2.2 here we come!
     
  32. JMyerscough

    JMyerscough

    Joined:
    Jul 12, 2012
    Posts:
    106
    Does this support the latest GKC?
     
    neodotca likes this.
  33. neodotca

    neodotca

    Joined:
    Feb 20, 2016
    Posts:
    120
    Please update the integration with GKC, thanks!
     
  34. Moe-Mogare

    Moe-Mogare

    Joined:
    Apr 16, 2015
    Posts:
    9
    As well as the invector I followed the integration only to have it fail
     
  35. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    I totally agree, I'll see if I can add it to the 2.2.2 update.
     
    wood333 likes this.
  36. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    When you updated Emerald AI to version 2.2, did you completely remove it from your project before importing the new version? If not, this could be what's causing your issue. The only addition with the dynamic wandering feature is that the slope angle is checked before generating the waypoint. So, if your AI is trying to generate waypoints on a hill or slope, you will need to increase your AI's Max Slope Limit. This is located under the Wander Type settings. What size is your AI's Dynamic Wander Radius?
     
  37. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Very strange. Are you using an Animation Event with the SendEmeraldDamage function to trigger damage? I'll continue to look into this to see if I can figure out what causing it. I haven't been able to recreate it yet.
     
  38. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Awesome, thanks for the additional information! I believe this may be what's causing the issues some users have been having.
     
  39. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    I just finished my UniStorm 4.0 update so I can start working on the 2.2.2 update. I can't give an ETA, but I'll get it released as soon as possible.
     
  40. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    I'm going to try and have this resolved with version 2.2.2.
     
  41. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    The RFPS integration tutorial covers explosive damage that is mitigated based on distance when using explosive weapons. It depends on how you want this handled because this script only deals damage once the AI have been hit.

    You can calculate distance based damage using the following:
    Code (CSharp):
    1. float DistanceDamage = Mathf.Clamp01(1 - YourDistance / DamageRadius);
     
  42. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    If your terrain is using anything other layer than the Default layer, you will need to add it to your Alignment Layers within the Alignment Settings.
     
  43. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    The attack sounds volume can be found in the Sound Settings in the Attack Sounds tab.

    AttackSoundsVolume.png

    The player does deal damage, but if you've switched the tags, you will need to add it to the player's Player Weapon script. By default, it can damage the Respawn tag.
     
  44. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    You've made a syntax mistakes somewhere with a } and/or a /. Double check that you've properly added the code to the script.
     
  45. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Thanks for the info. Another user suggested where the issue may be coming from. If I can recreate this, I'll get it fixed with the 2.2.2 update. Have you added any layers to the AI's Obstruction Ignore Layers? If your building layer is in this list, it would also allow the AI to attack through walls with that layer.
     
  46. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Hey there,

    Yes, it supports generic/non-humanoid characters.
     
  47. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    Not yet, I update the GKC tutorial first thing tomorrow.
     
  48. BHS

    BHS

    Joined:
    Dec 21, 2009
    Posts:
    3,841
    The Invector integration works just fine. You made a syntax error when following the tutorial. Please let me know if you need help with adding the code snippets to the EmeraldAIPlayerDamage script. :)
     
  49. raptorbastard

    raptorbastard

    Joined:
    Jan 31, 2019
    Posts:
    1
    Having an issue with getting the emerald AI to deal damage to me (Invector Player), I can kill him but he can't deal any damage for some reason. (Melee Attack.)

    He also freezes instead of ragdolls.

    **No Errors**

    EDIT: If I block or turn my back on him he is reacting to it but all of his attacks don't cause any affect not even a hurt/hit animation on the player.

    EDIT: FIXED IT, A note to anyone else having this problem it was because I didn't add the event to the animation. I think in the Invector tutorial you should leave a lil note or popup for people like me who are too eager to integrate invector xD. Found the solution through the AI setup tutorial.
     
    Last edited: May 23, 2019
  50. Zelre

    Zelre

    Joined:
    Dec 3, 2016
    Posts:
    52
    Hey guys, I've been working on a basic Level Up system for Emerald AI. It's not 100% complete and some features need improvement. As I'm also self taught when it comes to programming, some of my code may be messy or have room for improvement.

    I've written this without an Update function, and instead the GainExperience() function is called every time your AI lands an attack on it's target. I don't like Update functions unless needed.

    So, a quick overview.

    Every time your AI damages a target, it gains experience. When it levels up the following can be changed:

    Level;
    Health;
    Regen Rate; (Not yet added)
    Regen Amount; (Not yet added)
    AI's Damage;
    AI's physical size;

    Title System:
    I've also included a Title system. This allows you to change your AI's name and add a [TAG] in front of it when it reaches a certain level. I've included an event system with each title achievement to give you more control over what happens when these are reached, and I've added some basic Emerald things you can activate or change.




    Current Known Issues:
    1. If you set your AI's level higher than 1 before start, I've set it so the health, size and title change on start as well, but I've not gotten around to changing things like required experience, health, damage etc...
    2. Play emote in the title system seems to not activate the emote. I suspect it's because it can't use an emote while in combat? Might have to disable some things before this like stop attacking/stop movement etc... Haven't put much thought into it yet.
    3. Health bar does not scale to health changes when health is reset on level up.

    Later Plans:
    1. Improve the Title System, and maybe create a separate level system that relies more heavily on this system to change health, damage etc... Allowing you to create different variants of your AI based on level, while leaving your AI to reach these levels by itself... Why create an AI that's a BOSS monster, when you can leave your AI to fight its way there by itself? Obviously the need for all of this will depend on the game dynamics, but still. ;)
    2. Clean up code, improve things that don't function E.G. known issues.
    3. Persistence. I've added saving of the stats in a previous version of this level system I've created, but it's not as simple as just adding a JSON or .dat save system to the AI... This only works if your AI is placed before start and doesn't get instantiated at runtime. If it does, then a more complex save system will be required... One that saves runtime instantiated game objects and then applies their location and component settings to them. I can do this, but don't have the time or current need to do so.

    Conclusion:
    This is NOT complete. It's something I'm working on and wanted to post what I've done so far here with everyone.
    This does allow you to change practically ANYTHING on your AI. From movement speed, attack distance, Skinned Mesh etc... With a little tweaking.

    Code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.Events;
    6. using EmeraldAI;
    7. using EmeraldAI.Utility;
    8.  
    9. [System.Serializable]
    10. public class EmeraldLevelSystem : MonoBehaviour
    11. {
    12.     private EmeraldAISystem emeraldAI;
    13.     private EmeraldAIEventsManager emeraldEventManager;
    14.    
    15.     [Header("AI Details")]
    16.     [Tooltip("DO NOT EDIT. Displays the AI's name.")]
    17.     public string entityName;
    18.     [Tooltip("DO NOT EDIT. Change level in the Emerald AI Component.")]
    19.     public int level = 1;
    20.     [Tooltip("Set the AI's max level.")]
    21.     public int levelCap = 120;
    22.     [Tooltip("Shows the AI's current experience.")]
    23.     public int experience;
    24.     [Tooltip("Shows the required experience to level up. Change this to set the base experience.")]
    25.     public int requiredExperience = 84;
    26.    
    27.     [Header("AI Stats (DO NOT EDIT)")]
    28.     public int maxHealth;
    29.     private float walkSpeed;
    30.     private float runSpeed;
    31.     private float attackDistance;
    32.     public float regenRate;
    33.     public int regenAmount;
    34.    
    35.     [Header("AI Damage (DO NOT EDIT)")]
    36.     public int attack1Min;
    37.     public int attack1Max;
    38.     [Space]
    39.     public int attack2Min;
    40.     public int attack2Max;
    41.     [Space]
    42.     public int attack3Min;
    43.     public int attack3Max;
    44.        
    45.    
    46.     [Header("Level Up")]
    47.     [Tooltip("Enable health reset on Level Up.")]
    48.     public bool resetHealth = true;
    49.     [Tooltip("Add titles to AI's name when it reaches a certain level. Also allows more specific changes to be made when these specific levels are reached.")]
    50.     public Titles[] changeTitles;
    51.    
    52.     [Header("Settings")]
    53.     [Tooltip("Enable health change.")]
    54.     public bool _Health = true;
    55.     [Tooltip("Enable Aggro attacks change.")]
    56.     public bool _ComboAttacks = true;
    57.     [Tooltip("Enable Regen rate change.")]
    58.     public bool _RegenRate = true;
    59.     [Tooltip("Enable Regen Amount change.")]
    60.     public bool _RegenAmount = true;
    61.     [Tooltip("Enable Attack Damage change.")]
    62.     public bool _AttackDamage = true;
    63.     [Tooltip("Enable Size change.")]
    64.     public bool _ChangeSize = true;
    65.     private float sizeX;
    66.     private float sizeY;
    67.     private float sizeZ;
    68.    
    69.     [Header("Multipliers")]
    70.     [Tooltip("Every time the AI levels up, the following are multiplied by the Main Multiplier: Health.")]
    71.     public float mainMultiplier = 1.05f;
    72.     [Tooltip("Adds this amount to the multiplier every level up. This allows the multipler to increase and adds some complexity to the system.")]
    73.     public float mainAdditive = 0.001f;
    74.     [Space]
    75.     [Tooltip("Multiplies the experienced needed after each level by this amount.")]
    76.     public float experienceMultiplier = 1.05f;
    77.     [Tooltip("Adds this amount to the multiplier every level up. This allows the multipler to increase and adds some complexity to the system.")]
    78.     public float experienceAdditive = 0.001f;
    79.     [Space]
    80.     [Tooltip("Adds this amount to the AI's scale every time it levels up.")]
    81.     public float sizeAdditive = 0.02f;
    82.     [Space]
    83.     [Tooltip("Multiplies the Min and Max damage of all the AI's attacks (1-3) by this amount.")]
    84.     public float attackDamageMultiplier = 1.05f;
    85.     [Tooltip("Adds this amount to the multiplier every level up. This allows the multipler to increase and adds some complexity to the system.")]
    86.     public float attackDamageAdditive = 0.4f;
    87.    
    88.     [Header("Events")]
    89.     [Tooltip("Add events to be called when the AI levels up.")]
    90.     public UnityEvent OnLevelUp;
    91.    
    92.    
    93.    
    94.     // Start is called before the first frame update
    95.     void Awake()
    96.     {
    97.         ApplyComponents();
    98.         GetEmeraldStats();
    99.         SetOnStart();
    100.         SetTitle();
    101.     }
    102.    
    103.     //Applies the needed Emerald AI Components at Runtime
    104.     public void ApplyComponents()
    105.     {
    106.         //Apply Emerald AI System Component at Runtime
    107.         if(this.GetComponent<EmeraldAISystem>())
    108.         {
    109.             emeraldAI = this.GetComponent<EmeraldAISystem>();
    110.             maxHealth = emeraldAI.StartingHealth;
    111.         }
    112.         else
    113.         {
    114.             emeraldAI = null;
    115.             Debug.Log("No Emerald AI Component attached to this object. Please add one.");
    116.         }
    117.        
    118.         //Apply Emerald AI Events Manager Component at Runtime
    119.         if(this.GetComponent<EmeraldAIEventsManager>())
    120.         {
    121.             emeraldEventManager = this.GetComponent<EmeraldAIEventsManager>();
    122.         }
    123.         else
    124.         {
    125.             emeraldEventManager = null;
    126.             Debug.Log("No Emerald Event Manager Component attached to this object. Please add one.");
    127.         }
    128.        
    129.         emeraldAI.OnAttackEvent.AddListener(GainExperience);
    130.     }
    131.    
    132.     private void SetOnStart()
    133.     {
    134.         ChangeHealth();
    135.         ChangeDamage();
    136.         ChangeSize();
    137.     }
    138.    
    139.     //Pulls the needed variables from the Emerald AI at start.
    140.     public void GetEmeraldStats()
    141.     {
    142.         if(emeraldAI != null)
    143.         {
    144.             entityName = emeraldAI.AIName;
    145.             level = emeraldAI.AILevel;
    146.             maxHealth = emeraldAI.StartingHealth;
    147.             attack1Min = emeraldAI.MinimumDamageAmount1;
    148.             attack1Max = emeraldAI.MaximumDamageAmount1;
    149.             attack2Min = emeraldAI.MinimumDamageAmount2;
    150.             attack2Max = emeraldAI.MaximumDamageAmount2;
    151.             attack3Min = emeraldAI.MinimumDamageAmount3;
    152.             attack3Max = emeraldAI.MaximumDamageAmount3;
    153.             regenRate = emeraldAI.HealthRegRate;
    154.             regenAmount = emeraldAI.RegenerateAmount;
    155.             sizeX = transform.localScale.x;
    156.             sizeY = transform.localScale.y;
    157.             sizeZ = transform.localScale.z;
    158.         }
    159.         else
    160.         {
    161.             return;
    162.         }
    163.     }
    164.    
    165.     //Sets any changed variables to the Emerald AI System when called (On level up)
    166.     public void SetEmeraldStats()
    167.     {
    168.         if(emeraldAI != null)
    169.         {
    170.             emeraldAI.AILevel = level;
    171.             emeraldAI.StartingHealth = maxHealth;
    172.             emeraldAI.MinimumDamageAmount1 = attack1Min;
    173.             emeraldAI.MaximumDamageAmount1 = attack1Max;
    174.             emeraldAI.MinimumDamageAmount2 = attack2Min;
    175.             emeraldAI.MaximumDamageAmount2 = attack2Max;
    176.             emeraldAI.MinimumDamageAmount3 = attack3Min;
    177.             emeraldAI.MaximumDamageAmount3 = attack3Max;
    178.             emeraldAI.HealthRegRate = regenRate;
    179.             emeraldAI.RegenerateAmount = regenAmount;
    180.         }
    181.         else
    182.         {
    183.             return;
    184.         }
    185.     }
    186.    
    187.     //Handles experience gains. Calls for LevelUp when required experience is met.
    188.     public void GainExperience()
    189.     {
    190.         experience = experience + emeraldAI.CurrentDamageAmount;
    191.        
    192.         while(experience >= requiredExperience)
    193.         {
    194.             LevelUp();
    195.             experience = experience - requiredExperience;
    196.             requiredExperience = Mathf.RoundToInt(requiredExperience * (experienceMultiplier + (level * experienceAdditive)));
    197.         }
    198.     }
    199.    
    200.     //Handles all changes made on Level Up.
    201.     public void LevelUp()
    202.     {
    203.         //Level Increase
    204.         if(level < levelCap)
    205.         {
    206.             level++;
    207.             if(emeraldAI.TextLevel)
    208.             {
    209.                 emeraldAI.TextLevel.text = ("   " + level);
    210.             }      
    211.        
    212.             //Health Increase
    213.             if(_Health == true)
    214.             {
    215.                 ChangeHealth();
    216.             }
    217.        
    218.             //Attack Damage
    219.             if(_AttackDamage == true)
    220.             {
    221.                 ChangeDamage();
    222.             }
    223.        
    224.             //Size Increase
    225.             if(_ChangeSize == true)
    226.             {
    227.                 ChangeSize();
    228.             }
    229.        
    230.             SetEmeraldStats();
    231.             SetTitle();
    232.             OnLevelUp.Invoke();
    233.        
    234.         }
    235.         else
    236.         {
    237.             return;
    238.         }
    239.     }
    240.    
    241.     public void ChangeHealth()
    242.     {
    243.         maxHealth = Mathf.RoundToInt(maxHealth * (mainMultiplier + (level * mainAdditive)));
    244.         if(resetHealth == true)
    245.         {
    246.             emeraldEventManager.InstantlyRefillAIHeath();
    247.         }
    248.     }
    249.    
    250.     public void ChangeDamage()
    251.     {
    252.         attack1Min += Mathf.RoundToInt(level * attackDamageAdditive);
    253.         attack1Max += Mathf.RoundToInt(level * attackDamageAdditive);
    254.         attack2Min += Mathf.RoundToInt(level * attackDamageAdditive);
    255.         attack2Max += Mathf.RoundToInt(level * attackDamageAdditive);
    256.         attack3Min += Mathf.RoundToInt(level * attackDamageAdditive);
    257.         attack3Max += Mathf.RoundToInt(level * attackDamageAdditive);
    258.     }
    259.    
    260.     public void ChangeSize()
    261.     {
    262.         transform.localScale = new Vector3(sizeX + (level * sizeAdditive),sizeY + (level * sizeAdditive),sizeZ + (level * sizeAdditive));
    263.     }
    264.    
    265.     public void SetTitle()
    266.     {
    267.         for(int i = 0; i < changeTitles.Length; i++)
    268.         {
    269.             if(changeTitles[i].levelRequirement == level)
    270.             {
    271.                 if(emeraldAI.TextName)
    272.                 {
    273.                     emeraldAI.AIName = ("[" + changeTitles[i]._title + "]" + " " + entityName);
    274.                     emeraldAI.TextName.text = ("[" + changeTitles[i]._title + "]" + " " + entityName);
    275.                 }
    276.                
    277.                 emeraldEventManager.EnableItem(changeTitles[i].itemID);
    278.                
    279.                 if(changeTitles[i].spawnEffect != null)
    280.                 {
    281.                     emeraldEventManager.SpawnAdditionalEffect(changeTitles[i].spawnEffect);
    282.                 }
    283.                
    284.                 if(changeTitles[i].playAudioClip != null)
    285.                 {
    286.                     emeraldEventManager.PlaySoundClip(changeTitles[i].playAudioClip);
    287.                 }
    288.                 emeraldEventManager.StopFollowing();
    289.                 emeraldEventManager.PlayEmoteAnimation(changeTitles[i].playEmote);
    290.                
    291.                 if(changeTitles[i].OnTitleChange != null)
    292.                 {
    293.                     changeTitles[i].OnTitleChange.Invoke();
    294.                 }
    295.                
    296.                 if(changeTitles[i].aggroAttacks > 0)
    297.                 {
    298.                     emeraldAI.TotalAggroHits = changeTitles[i].aggroAttacks;
    299.                 }
    300.             }
    301.         }
    302.     }
    303. }
    304.  
    305. [System.Serializable]
    306. public class Titles
    307.     {  
    308.         [Header("Title")]
    309.         public string _title;
    310.        
    311.         [Header("Requirements")]
    312.         public int levelRequirement;
    313.        
    314.         [Header("Effects")]
    315.         public int itemID;
    316.         public int playEmote;
    317.         public AudioClip playAudioClip;
    318.         public GameObject spawnEffect;
    319.         [Range(3,50)]
    320.         public int aggroAttacks;
    321.        
    322.         [Header("Events")]
    323.         [Tooltip("Use this to make more specific changes when this title has been achieved.")]
    324.         public UnityEvent OnTitleChange;
    325.        
    326.     }
     
    Last edited: May 26, 2019
    julianr, wood333, Mad_Mark and 2 others like this.