private static void BuildWestBrosBossPrefab(AssetBundle assetBundle, out GameObject outObject, WestBros whichBro, bool isSmiley, tk2dSpriteCollectionData sourceSpriteCollection, tk2dSpriteAnimation sourceAnimations, bool keepIntroDoer = false) { GameObject prefab = ExpandCustomEnemyDatabase.GetOfficialEnemyByGuid(isSmiley ? "ea40fcc863d34b0088f490f4e57f8913" // Smiley : "c00390483f394a849c36143eb878998f").gameObject; // Shades outObject = UnityEngine.Object.Instantiate(prefab, Vector3.zero, Quaternion.identity); try { string name = $"West Bros {whichBro}"; outObject.SetActive(false); outObject.name = name; AIActor actor = outObject.GetComponent <AIActor>(); actor.healthHaver.overrideBossName = "Western Bros"; actor.EnemyId = UnityEngine.Random.Range(100000, 999999); actor.ActorName = name; EncounterTrackable Encounterable = outObject.GetComponent <EncounterTrackable>(); switch (whichBro) { case WestBros.Angel: actor.EnemyGuid = "275354563e244f558be87fcff4b07f9f"; Encounterable.EncounterGuid = "7d6e1faf682d4402b29535020313f383"; break; case WestBros.Nome: actor.EnemyGuid = "3a1a33a905bb4b669e7d798f20674c4c"; Encounterable.EncounterGuid = "78cb8889dc884dd9b3aafe64558d858e"; break; case WestBros.Tuc: actor.EnemyGuid = "d2e7ea9ea9a444cebadd3bafa0832cd1"; Encounterable.EncounterGuid = "1df53371ce084dafb46f6bcd5a6c1c5f"; break; } // TODO at some distant point in time Encounterable.journalData.PrimaryDisplayName = name; Encounterable.journalData.NotificationPanelDescription = name; Encounterable.journalData.AmmonomiconFullEntry = name; // x BroController // x BulletBroDeathController // x BulletBrosIntroDoer // x BulletBroSeekTargetBehavior // movement behaviour // BulletBroRepositionBehavior // completely unused var oldBroController = outObject.GetComponent <BroController>(); var newBroController = outObject.AddComponent <ExpandWesternBroController>(); newBroController.enrageAnim = oldBroController.enrageAnim; newBroController.enrageAnimTime = oldBroController.enrageAnimTime; newBroController.enrageHealToPercent = oldBroController.enrageHealToPercent; newBroController.overheadVfx = oldBroController.overheadVfx; newBroController.postEnrageMoveSpeed = oldBroController.postEnrageMoveSpeed; newBroController.whichBro = whichBro; newBroController.postSecondEnrageMoveSpeed = newBroController.postEnrageMoveSpeed; UnityEngine.Object.Destroy(oldBroController); UnityEngine.Object.Destroy(outObject.GetComponent <BulletBroDeathController>()); outObject.AddComponent <ExpandWesternBroDeathController>(); var newMovementBehavior = new ExpandWesternBroSeekTargetBehavior(); var oldMovementBehavior = actor.behaviorSpeculator.MovementBehaviors.First() as BulletBroSeekTargetBehavior; newMovementBehavior.CustomRange = oldMovementBehavior.CustomRange; newMovementBehavior.PathInterval = oldMovementBehavior.PathInterval; newMovementBehavior.StopWhenInRange = oldMovementBehavior.StopWhenInRange; actor.behaviorSpeculator.MovementBehaviors = new List <MovementBehaviorBase>() { newMovementBehavior }; // only smiley has a bossIntroDoer, so the stuff after this would null reference if done with shade if (isSmiley) { if (!keepIntroDoer) { UnityEngine.Object.Destroy(outObject.GetComponent <BulletBrosIntroDoer>()); UnityEngine.Object.Destroy(outObject.GetComponent <GenericIntroDoer>()); } else { // BulletBrosIntroDoer is a SpecificIntroDoer; it does not inherent from GenericIntroDoer, it requires it to be present BulletBrosIntroDoer bulletBrosIntroDoer = outObject.GetComponent <BulletBrosIntroDoer>(); // destroy it so we can add our own UnityEngine.Object.Destroy(bulletBrosIntroDoer); GenericIntroDoer genericIntroDoer = outObject.GetComponent <GenericIntroDoer>(); genericIntroDoer.portraitSlideSettings.bossNameString = "Western Bros"; genericIntroDoer.portraitSlideSettings.bossSubtitleString = "Triple Tap"; genericIntroDoer.portraitSlideSettings.bossQuoteString = string.Empty; genericIntroDoer.portraitSlideSettings.bossArtSprite = assetBundle.LoadAsset <Texture2D>("WesternBrosBossCard"); genericIntroDoer.triggerType = GenericIntroDoer.TriggerType.PlayerEnteredRoom; genericIntroDoer.OnIntroFinished = () => { }; ExpandWesternBroIntroDoer specificIntroDoer = outObject.AddComponent <ExpandWesternBroIntroDoer>(); } } var animationsAsset = assetBundle.LoadAsset <GameObject>($"WestBrosAnimations_{whichBro}"); List <tk2dSpriteAnimationClip> animationClips = new List <tk2dSpriteAnimationClip>(); foreach (tk2dSpriteAnimationClip clip in sourceAnimations.clips) { if (clip.name.StartsWith($"{whichBro.ToString().ToLower()}_")) { animationClips.Add(ExpandUtility.DuplicateAnimationClip(clip)); } } List <tk2dSpriteAnimationClip> clipsToAdd = new List <tk2dSpriteAnimationClip>(); foreach (tk2dSpriteAnimationClip clip in animationClips) { clip.name = clip.name.Replace($"{whichBro.ToString().ToLower()}_", string.Empty); clip.name = clip.name.Replace("dash_front", "dash_forward"); clip.name = clip.name.Replace("move_front", "move_forward"); if (clip.name.EndsWith("_prime")) { clip.frames[5].eventAudio = "Play_ENM_bullet_dash_01"; clip.frames[5].triggerEvent = true; } else if (clip.name.StartsWith("move_")) { clip.frames[2].eventAudio = "PLay_FS_ENM"; clip.frames[2].triggerEvent = true; } else if (clip.name == "anger") { // we change the west bros anger animation from a loop to a loop section so the anger SFX only plays once. // to do this we simply clone every frame once and make it loop at the first copied frame. var angerFrames = clip.frames.ToList(); foreach (var frame in clip.frames) { tk2dSpriteAnimationFrame clonedFrame = new tk2dSpriteAnimationFrame(); ExpandUtility.ReflectionShallowCopyFields(clonedFrame, frame, BindingFlags.Public | BindingFlags.Instance); angerFrames.Add(clonedFrame); } // it's important to do this before changing clip.frames clip.loopStart = clip.frames.Length; clip.frames = angerFrames.ToArray(); clip.wrapMode = tk2dSpriteAnimationClip.WrapMode.LoopSection; clip.frames[0].eventAudio = "Play_BOSS_bulletbros_anger_01"; clip.frames[0].triggerEvent = true; } else if (clip.name == "death_right") { clip.name = "die"; tk2dSpriteAnimationClip dieFrontRight = ExpandUtility.DuplicateAnimationClip(clip); dieFrontRight.name = "die_front_right"; clipsToAdd.Add(dieFrontRight); } else if (clip.name == "death_left") { clip.name = "die_left"; tk2dSpriteAnimationClip dieFrontLeft = ExpandUtility.DuplicateAnimationClip(clip); dieFrontLeft.name = "die_front_left"; clipsToAdd.Add(dieFrontLeft); } else if (clip.name == "idle_front") { clip.name = "idle"; tk2dSpriteAnimationClip bigShot = ExpandUtility.DuplicateAnimationClip(clip); bigShot.wrapMode = tk2dSpriteAnimationClip.WrapMode.Once; bigShot.name = "big_shot"; clipsToAdd.Add(bigShot); tk2dSpriteAnimationClip charge = ExpandUtility.DuplicateAnimationClip(clip); charge.wrapMode = tk2dSpriteAnimationClip.WrapMode.Loop; charge.name = "charge"; clipsToAdd.Add(charge); // not really necessary since it's nuked from the animator further down tk2dSpriteAnimationClip appear = ExpandUtility.DuplicateAnimationClip(clip); appear.wrapMode = tk2dSpriteAnimationClip.WrapMode.Once; appear.name = "appear"; clipsToAdd.Add(appear); tk2dSpriteAnimationClip introGunToggle = ExpandUtility.DuplicateAnimationClip(clip); introGunToggle.wrapMode = tk2dSpriteAnimationClip.WrapMode.Once; introGunToggle.name = "intro2"; clipsToAdd.Add(introGunToggle); introGunToggle.frames[0].eventInfo = "guntoggle"; introGunToggle.frames[0].triggerEvent = true; } else if (clip.name == "summon") { clip.name = "whistle"; clip.wrapMode = tk2dSpriteAnimationClip.WrapMode.Once; // the summon vfx don't look right // clip.frames[0].eventVfx = "summon_vfx"; // clip.frames[0].triggerEvent = true; } else if (clip.name == "pound") { clip.name = "jump_attack"; // Uses modified sound that plays faster on the first half to account for west bros having faster animation. clip.frames[0].eventAudio = "Play_EX_BOSS_westbros_slam_01"; clip.frames[0].triggerEvent = true; } else if (clip.name == "intro") { clip.wrapMode = tk2dSpriteAnimationClip.WrapMode.Once; // this is setup in case we want the intro to continue looping during the boss card instead of the idle animation // requires to change the intro doer so it sets finished to true once it reaches the first loop //if (whichBro == WestBros.Nome) //{ // // nome's intro animation wasn't looping at the end like the others // var list = clip.frames.ToList(); // list.RemoveAt(20); // list.RemoveAt(20); // clip.frames = list.ToArray(); // clip.loopStart = 23; // clip.frames[23] = clip.frames[0]; // clip.frames[24] = clip.frames[1]; // clip.frames[25] = clip.frames[2]; // clip.frames[26] = clip.frames[3]; //} //else if (whichBro == WestBros.Tuc) //{ // // tuc's intro animation was off by one frame compared to the others // var list = clip.frames.ToList(); // list.RemoveAt(15); // clip.frames = list.ToArray(); // clip.loopStart = 21; //} } } animationClips.AddRange(clipsToAdd); tk2dSpriteAnimation spriteAnimation = animationsAsset.AddComponent <tk2dSpriteAnimation>(); spriteAnimation.clips = animationClips.ToArray(); tk2dSpriteAnimator spriteAnimator = outObject.GetComponent <tk2dSpriteAnimator>(); spriteAnimator.Library = spriteAnimation; tk2dSprite sprite = outObject.GetComponent <tk2dSprite>(); sprite.SetSprite(sourceSpriteCollection, $"BB_{whichBro.ToString().ToLower()}_idle_front_001"); sprite.PlaceAtPositionByAnchor(new Vector3(0f, 0f), tk2dBaseSprite.Anchor.LowerCenter); AIAnimator animator = outObject.GetComponent <AIAnimator>(); // removes the 'appear' animation animator.OtherAnimations.RemoveAt(0); outObject.transform.Find("shadow").localPosition += new Vector3(1.52f, 0.02f, 0); var shooter = SetupAIShooter(outObject); shooter.handObject = WestBrosHandPrefab.GetComponent <PlayerHandController>(); DebrisObject hatPrefab = null; switch (whichBro) { case WestBros.Angel: shooter.gunAttachPoint.position = new Vector3(-1.05f, 0.5f); WestBrosAngelGUID = actor.EnemyGuid; hatPrefab = WestBrosAngelHatPrefab.GetComponent <DebrisObject>(); break; case WestBros.Nome: shooter.gunAttachPoint.position = new Vector3(-1.05f, 0.4f); WestBrosNomeGUID = actor.EnemyGuid; hatPrefab = WestBrosNomeHatPrefab.GetComponent <DebrisObject>(); break; case WestBros.Tuc: shooter.gunAttachPoint.position = new Vector3(-1.05f, 0.5f); WestBrosTucGUID = actor.EnemyGuid; hatPrefab = WestBrosTucHatPrefab.GetComponent <DebrisObject>(); break; } shooter.equippedGunId = WestBrosRevolverGenerator.GetWestBrosRevolverID(whichBro); if (shooter.equippedGunId == -1) { ETGModConsole.Log("The West Bros Gun ID should have been set at this point already, but it wasn't. Assigning fallback gun."); shooter.equippedGunId = isSmiley ? 35 : 22; } var hatLauncher = outObject.GetComponentInChildren <ExplosionDebrisLauncher>(); // basically changes smiley's debris launcher into shades' hatLauncher.specifyArcDegrees = false; hatLauncher.minShards = 1; hatLauncher.maxShards = 1; hatLauncher.debrisSources = new DebrisObject[] { hatPrefab }; // move the ring of bullets spawned by jumping var shootPoint = outObject.transform.Find("shoot point"); shootPoint.position += new Vector3(1.5f, 0); // move the actual pixel colliders var rigidbody = outObject.GetComponent <SpeculativeRigidbody>(); foreach (var item in rigidbody.PixelColliders) { item.ManualOffsetX = 32; item.Regenerate(outObject.transform); } // TODO balance actor.healthHaver.ForceSetCurrentHealth(600); actor.healthHaver.SetHealthMaximum(600); actor.RegenerateCache(); ExpandCustomEnemyDatabase.AddEnemyToDatabase(outObject, actor.EnemyGuid, true); FakePrefab.MarkAsFakePrefab(outObject); UnityEngine.Object.DontDestroyOnLoad(outObject); } catch (Exception e) { ETGModConsole.Log($"Error setting up the western bro {whichBro}: " + e.ToString()); } }
public static void GenerateGungeoneerMimicBoss(AssetBundle expandSharedAssets1, GameObject aiActorObject, PlayerController sourcePlayer = null) { if (sourcePlayer == null) { sourcePlayer = GameManager.Instance.PrimaryPlayer; } if (sourcePlayer == null) { return; } tk2dSprite playerSprite = aiActorObject.AddComponent <tk2dSprite>(); ExpandUtility.DuplicateSprite(playerSprite, (sourcePlayer.sprite as tk2dSprite)); // If Player sprite was flipped (aka, player aiming/facing towards the left), then this could cause sprite being shifted left on AIActor. // Always set false to ensure this doesn't happen. playerSprite.FlipX = false; ExpandUtility.GenerateAIActorTemplate(aiActorObject, out m_CorpseObject, aiActorObject.name, System.Guid.NewGuid().ToString(), GunAttachOffset: new Vector3(0.3f, 0.25f, 0), StartingGunID: 472); AIActor CachedEnemyActor = aiActorObject.GetComponent <AIActor>(); if (!aiActorObject | !CachedEnemyActor) { return; } if (ExpandStats.debugMode) { ETGModConsole.Log("Spawning '" + CachedEnemyActor.ActorName + "' with GUID: " + CachedEnemyActor.EnemyGuid + " .", false); } GameObject m_NewHandObject = new GameObject("PlayerMimicHand"); tk2dSprite m_HandSprite = m_NewHandObject.AddComponent <tk2dSprite>(); ExpandUtility.DuplicateSprite(m_HandSprite, sourcePlayer.primaryHand.gameObject.GetComponent <tk2dSprite>()); PlayerHandController m_HandController = m_NewHandObject.AddComponent <PlayerHandController>(); m_HandController.ForceRenderersOff = false; m_HandController.handHeightFromGun = 0.05f; CachedEnemyActor.aiShooter.handObject = m_HandController; // Generate BossCard based on current Player. Texture2D BossCardForeground = ExpandUtility.FlipTexture(Instantiate(sourcePlayer.BosscardSprites[0])); // Mirror thing will be used as static background. (will be the same for all possible boss cards) Texture2D BossCardBackground = expandSharedAssets1.LoadAsset <Texture2D>("MimicInMirror_BossCardBackground"); // Combine foreground boss card generated from PlayerController onto the static background image loased in earlier. Resolutions must match! Texture2D BossCardTexture = ExpandUtility.CombineTextures(BossCardBackground, BossCardForeground); GenericIntroDoer miniBossIntroDoer = aiActorObject.AddComponent <GenericIntroDoer>(); aiActorObject.AddComponent <ExpandGungeoneerMimicIntroDoer>(); miniBossIntroDoer.triggerType = GenericIntroDoer.TriggerType.PlayerEnteredRoom; miniBossIntroDoer.initialDelay = 0.15f; miniBossIntroDoer.cameraMoveSpeed = 14; miniBossIntroDoer.specifyIntroAiAnimator = null; miniBossIntroDoer.BossMusicEvent = "Play_MUS_Boss_Theme_Beholster"; miniBossIntroDoer.PreventBossMusic = false; miniBossIntroDoer.InvisibleBeforeIntroAnim = false; miniBossIntroDoer.preIntroAnim = string.Empty; miniBossIntroDoer.preIntroDirectionalAnim = string.Empty; miniBossIntroDoer.introAnim = "idle"; miniBossIntroDoer.introDirectionalAnim = string.Empty; miniBossIntroDoer.continueAnimDuringOutro = false; miniBossIntroDoer.cameraFocus = null; miniBossIntroDoer.roomPositionCameraFocus = Vector2.zero; miniBossIntroDoer.restrictPlayerMotionToRoom = false; miniBossIntroDoer.fusebombLock = false; miniBossIntroDoer.AdditionalHeightOffset = 0; miniBossIntroDoer.portraitSlideSettings = new PortraitSlideSettings() { bossNameString = "Dopplegunner", bossSubtitleString = "Imposter!", bossQuoteString = "Clone gone rogue...", bossSpritePxOffset = IntVector2.Zero, topLeftTextPxOffset = IntVector2.Zero, bottomRightTextPxOffset = IntVector2.Zero, bgColor = new Color(0, 0, 1, 1) }; if (BossCardTexture) { miniBossIntroDoer.portraitSlideSettings.bossArtSprite = BossCardTexture; miniBossIntroDoer.SkipBossCard = false; CachedEnemyActor.healthHaver.bossHealthBar = HealthHaver.BossBarType.MainBar; } else { miniBossIntroDoer.SkipBossCard = true; CachedEnemyActor.healthHaver.bossHealthBar = HealthHaver.BossBarType.SubbossBar; } miniBossIntroDoer.HideGunAndHand = true; miniBossIntroDoer.SkipFinalizeAnimation = true; miniBossIntroDoer.RegenerateCache(); CachedEnemyActor.BaseMovementSpeed = 8f; CachedEnemyActor.MovementSpeed = 8f; CachedEnemyActor.healthHaver.SetHealthMaximum(1000); CachedEnemyActor.healthHaver.ForceSetCurrentHealth(1000); CachedEnemyActor.healthHaver.overrideBossName = "Dopplegunner"; CachedEnemyActor.healthHaver.RegenerateCache(); CachedEnemyActor.EnemyId = Random.Range(2000, 9999); CachedEnemyActor.EnemyGuid = System.Guid.NewGuid().ToString(); CachedEnemyActor.OverrideDisplayName = ("Dopplegunner"); CachedEnemyActor.ActorName = ("Dopplegunner"); CachedEnemyActor.name = ("Dopplegunner"); CachedEnemyActor.CanTargetEnemies = false; CachedEnemyActor.CanTargetPlayers = true; if (sourcePlayer.characterIdentity == PlayableCharacters.Bullet) { CachedEnemyActor.EnemySwitchState = "Metal_Bullet_Man"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Convict) { CachedEnemyActor.EnemySwitchState = "Convict"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.CoopCultist) { CachedEnemyActor.EnemySwitchState = "Cultist"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Cosmonaut) { CachedEnemyActor.EnemySwitchState = "Cosmonaut"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Guide) { CachedEnemyActor.EnemySwitchState = "Guide"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Gunslinger) { CachedEnemyActor.EnemySwitchState = "Gunslinger"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Ninja) { CachedEnemyActor.EnemySwitchState = "Ninja"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Pilot) { CachedEnemyActor.EnemySwitchState = "Rogue"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Robot) { CachedEnemyActor.EnemySwitchState = "Robot"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Soldier) { CachedEnemyActor.EnemySwitchState = "Marine"; } else if (sourcePlayer.characterIdentity == PlayableCharacters.Eevee) { CachedEnemyActor.EnemySwitchState = "Convict"; ExpandShaders.ApplyParadoxPlayerShader(CachedEnemyActor.sprite); } else { CachedEnemyActor.EnemySwitchState = "Gun Cultist"; } ExpandGungeoneerMimicBossController playerMimicController = aiActorObject.AddComponent <ExpandGungeoneerMimicBossController>(); playerMimicController.m_Player = sourcePlayer; aiActorObject.AddComponent <ExpandGungeoneerMimicDeathController>(); if (CachedEnemyActor.GetComponent <ExpandGungeoneerMimicIntroDoer>()) { GenericIntroDoer genericIntroDoer = CachedEnemyActor.gameObject.GetComponent <GenericIntroDoer>(); FieldInfo field = typeof(GenericIntroDoer).GetField("m_specificIntroDoer", BindingFlags.Instance | BindingFlags.NonPublic); field.SetValue(genericIntroDoer, CachedEnemyActor.GetComponent <ExpandGungeoneerMimicIntroDoer>()); } CachedEnemyActor.aiAnimator.enabled = false; CachedEnemyActor.spriteAnimator.Stop(); CachedEnemyActor.spriteAnimator.DefaultClipId = 0; CachedEnemyActor.spriteAnimator.playAutomatically = false; List <tk2dSpriteAnimationClip> m_AnimationClips = new List <tk2dSpriteAnimationClip>(); foreach (tk2dSpriteAnimationClip clip in sourcePlayer.spriteAnimator.Library.clips) { if (!string.IsNullOrEmpty(clip.name)) { if (clip.name.ToLower() == "dodge") { m_AnimationClips.Add(clip); if (clip.frames != null && clip.frames.Length > 0) { if (!sourcePlayer.UseArmorlessAnim) { CachedEnemyActor.sprite.SetSprite(clip.frames[0].spriteId); } } } else if (clip.name.ToLower() == "dodge_armorless") { m_AnimationClips.Add(clip); if (clip.frames != null && clip.frames.Length > 0) { if (sourcePlayer.UseArmorlessAnim) { CachedEnemyActor.sprite.SetSprite(clip.frames[0].spriteId); } } } else if (clip.name.ToLower() == "run_down") { m_AnimationClips.Add(clip); } else if (clip.name.ToLower() == "run_down_armorless") { m_AnimationClips.Add(clip); } else if (clip.name.ToLower() == "death_shot") { m_AnimationClips.Add(clip); } else if (clip.name.ToLower() == "death_shot_armorless") { m_AnimationClips.Add(clip); } } } if (m_AnimationClips.Count > 0) { if (!CachedEnemyActor.spriteAnimator.Library) { CachedEnemyActor.spriteAnimator.Library = aiActorObject.AddComponent <tk2dSpriteAnimation>(); } CachedEnemyActor.spriteAnimator.Library.clips = m_AnimationClips.ToArray(); } CachedEnemyActor.healthHaver.RegenerateCache(); BehaviorSpeculator customBehaviorSpeculator = aiActorObject.AddComponent <BehaviorSpeculator>(); customBehaviorSpeculator.OverrideBehaviors = new List <OverrideBehaviorBase>(0); customBehaviorSpeculator.TargetBehaviors = new List <TargetBehaviorBase>(0); customBehaviorSpeculator.MovementBehaviors = new List <MovementBehaviorBase>(0); customBehaviorSpeculator.AttackBehaviors = new List <AttackBehaviorBase>(0); customBehaviorSpeculator.OtherBehaviors = new List <BehaviorBase>(0); customBehaviorSpeculator.InstantFirstTick = false; customBehaviorSpeculator.TickInterval = 0.1f; customBehaviorSpeculator.PostAwakenDelay = 0.5f; customBehaviorSpeculator.RemoveDelayOnReinforce = false; customBehaviorSpeculator.OverrideStartingFacingDirection = false; customBehaviorSpeculator.StartingFacingDirection = -90f; customBehaviorSpeculator.SkipTimingDifferentiator = false; customBehaviorSpeculator.RegenerateCache(); // BehaviorSpeculator is a serialized object. You must build these lists (or create new empty lists) and save them before the game can instantiate it correctly! ISerializedObject m_TargetBehaviorSpeculatorSeralized = customBehaviorSpeculator; m_TargetBehaviorSpeculatorSeralized.SerializedObjectReferences = new List <Object>(0); m_TargetBehaviorSpeculatorSeralized.SerializedStateKeys = new List <string>() { "OverrideBehaviors", "TargetBehaviors", "MovementBehaviors", "AttackBehaviors", "OtherBehaviors" }; m_TargetBehaviorSpeculatorSeralized.SerializedStateValues = new List <string>() { "[]", "[]", "[]", "[]", "[]" }; CachedEnemyActor.RegenerateCache(); return; }