Exemple #1
0
        public static void BuildWestBrosBossPrefabs(AssetBundle assetBundle)
        {
            // all 3 west bros animation sets are actually in their 3 cut guns (752,753,754), they all contain the same ones, so we just take the first one
            // 752 is nome
            // 753 is tuc
            // 754 is angel
            WestBrosGun = PickupObjectDatabase.GetById(752);

            Collection = WestBrosGun.gameObject.GetComponent <tk2dSprite>().Collection;
            Animation  = WestBrosGun.gameObject.GetComponent <tk2dSpriteAnimator>().Library;

            Shades       = ExpandCustomEnemyDatabase.GetOfficialEnemyByGuid("c00390483f394a849c36143eb878998f");
            ShadesDebris = Shades.GetComponentInChildren <ExplosionDebrisLauncher>().debrisSources[0];

            SetupHand(assetBundle, out WestBrosHandPrefab, ExpandCustomEnemyDatabase.WestBrosCollection.GetComponent <tk2dSpriteCollectionData>());

            BuildWestBrosHatPrefab(assetBundle, out WestBrosAngelHatPrefab, WestBros.Angel, Collection, ShadesDebris);
            BuildWestBrosHatPrefab(assetBundle, out WestBrosNomeHatPrefab, WestBros.Nome, Collection, ShadesDebris);
            BuildWestBrosHatPrefab(assetBundle, out WestBrosTucHatPrefab, WestBros.Tuc, Collection, ShadesDebris);

            BuildWestBrosBossPrefab(assetBundle, out WestBrosAngelPrefab, WestBros.Angel, false, Collection, Animation);
            BuildWestBrosBossPrefab(assetBundle, out WestBrosNomePrefab, WestBros.Nome, true, Collection, Animation, true);
            BuildWestBrosBossPrefab(assetBundle, out WestBrosTucPrefab, WestBros.Tuc, true, Collection, Animation);
        }
Exemple #2
0
        public override void Start()
        {
            if (!string.IsNullOrEmpty(ExceptionText) | !string.IsNullOrEmpty(ExceptionText2))
            {
                if (!string.IsNullOrEmpty(ExceptionText))
                {
                    ETGModConsole.Log(ExceptionText);
                }
                if (!string.IsNullOrEmpty(ExceptionText2))
                {
                    ETGModConsole.Log(ExceptionText2);
                }
                return;
            }

            ExpandSharedHooks.InstallRequiredHooks();

            AssetBundle expandSharedAssets1 = ResourceManager.LoadAssetBundle(ModAssetBundleName);
            AssetBundle sharedAssets        = ResourceManager.LoadAssetBundle("shared_auto_001");
            AssetBundle sharedAssets2       = ResourceManager.LoadAssetBundle("shared_auto_002");
            AssetBundle braveResources      = ResourceManager.LoadAssetBundle("brave_resources_001");
            AssetBundle enemiesBase         = ResourceManager.LoadAssetBundle("enemies_base_001");

            ExpandAssets.InitAudio(expandSharedAssets1, ModSoundBankName);

            ExpandObjectDatabase.BuildDatabase();


            // Init Custom GameLevelDefinitions
            ExpandCustomDungeonPrefabs.InitCustomGameLevelDefinitions(braveResources);

            // Init Custom Sprite Collections
            ExpandPrefabs.InitSpriteCollections(expandSharedAssets1);
            ExpandCustomEnemyDatabase.InitSpriteCollections(expandSharedAssets1);

            // Init ItemAPI
            SetupItemAPI(expandSharedAssets1);

            try
            {
                // Init Prefab Databases
                ExpandPrefabs.InitCustomPrefabs(expandSharedAssets1, sharedAssets, sharedAssets2, braveResources, enemiesBase);
                // Init Custom Enemy Prefabs
                ExpandCustomEnemyDatabase.InitPrefabs(expandSharedAssets1);
                // Init Custom Room Prefabs
                ExpandRoomPrefabs.InitCustomRooms(expandSharedAssets1, sharedAssets, sharedAssets2, braveResources, enemiesBase);
                // Init Custom DungeonFlow(s)
                ExpandDungeonFlow.InitDungeonFlows(sharedAssets2);
                // Post Init
                // Things that need existing stuff created first have code run here
                BootlegGuns.PostInit();
                // Dungeon Prefabs
                ExpandCustomDungeonPrefabs.InitDungoenPrefabs(expandSharedAssets1, sharedAssets, sharedAssets2, braveResources);

                ExpandLists.InvalidRatFloorRainRooms = new List <string>()
                {
                    ExpandRoomPrefabs.SecretBossRoom.name,
                    ExpandRoomPrefabs.ThwompCrossingVerticalNoRain.name,
                    ExpandRoomPrefabs.SecretRewardRoom.name,
                    ExpandPrefabs.DragunBossFoyerRoom.name,
                    ExpandPrefabs.DraGunExitRoom.name,
                    ExpandPrefabs.DraGunEndTimesRoom.name,
                    ExpandPrefabs.BlacksmithShop.name,
                    "Zelda Puzzle Room 1",
                    "Zelda Puzzle Room 2",
                    "Zelda Puzzle Room 3",
                    "Special Entrance"
                };
            } catch (Exception ex) {
                ETGModConsole.Log("[ExpandTheGungeon] ERROR: Exception occured while building prefabs!", true);
                Debug.LogException(ex);
                expandSharedAssets1 = null;
                sharedAssets        = null;
                sharedAssets2       = null;
                braveResources      = null;
                enemiesBase         = null;
                return;
            }

            // Modified version of Anywhere mod
            DungeonFlowModule.Install();

            InitConsoleCommands(ConsoleCommandName);

            GameManager.Instance.StartCoroutine(WaitForFoyerLoad());

            if (ExpandSettings.EnableLanguageFix)
            {
                GameManager.Options.CurrentLanguage = StringTableManager.GungeonSupportedLanguages.ENGLISH;
                StringTableManager.CurrentLanguage  = StringTableManager.GungeonSupportedLanguages.ENGLISH;
            }

            // Null bundles when done with them to avoid game crash issues
            expandSharedAssets1 = null;
            sharedAssets        = null;
            sharedAssets2       = null;
            braveResources      = null;
            enemiesBase         = null;
        }
Exemple #3
0
        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());
            }
        }
Exemple #4
0
        public override void Start()
        {
            if (!string.IsNullOrEmpty(ExceptionText))
            {
                ETGModConsole.Log(ExceptionText);
                return;
            }

            ExpandSharedHooks.InstallRequiredHooks();

            // Init ItemAPI
            SetupItemAPI();
            try {
                // Init Prefab Databases
                ExpandPrefabs.InitCustomPrefabs();
                // Init Custom Enemy Prefabs
                ExpandCustomEnemyDatabase.InitPrefabs();
                // Init Custom Room Prefabs
                ExpandRoomPrefabs.InitCustomRooms();
                // Init Custom DungeonFlow(s)
                ExpandDungeonFlow.InitDungeonFlows();
                // Init Custom Dungeons Prefabs
                ExpandCustomDungeonPrefabs.InitCustomDungeons();
                // Post Init
                // Things thta need existing stuff created first have code run here
                BootlegGuns.PostInit();

                ExpandLists.InvalidRatFloorRainRooms = new List <string>()
                {
                    ExpandRoomPrefabs.SecretBossRoom.name,
                    ExpandRoomPrefabs.ThwompCrossingVerticalNoRain.name,
                    ExpandRoomPrefabs.SecretRewardRoom.name,
                    ExpandPrefabs.DragunBossFoyerRoom.name,
                    ExpandPrefabs.DraGunExitRoom.name,
                    ExpandPrefabs.DraGunEndTimesRoom.name,
                    ExpandPrefabs.BlacksmithShop.name,
                    "Zelda Puzzle Room 1",
                    "Zelda Puzzle Room 2",
                    "Zelda Puzzle Room 3",
                    "Special Entrance"
                };
            } catch (Exception ex) {
                ETGModConsole.Log("[ExpandTheGungeon] ERROR: Exception occured while building prefabs!", true);
                Debug.LogException(ex);
                ExpandPrefabs.sharedAssets   = null;
                ExpandPrefabs.sharedAssets2  = null;
                ExpandPrefabs.braveResources = null;
                ExpandPrefabs.enemiesBase    = null;
                return;
            }
            // Modified version of Anywhere mod
            DungeonFlowModule.Install();

            InitConsoleCommands(ConsoleCommandName);

            // Null bundles when done with them to avoid game crash issues.
            ExpandPrefabs.sharedAssets   = null;
            ExpandPrefabs.sharedAssets2  = null;
            ExpandPrefabs.braveResources = null;
            ExpandPrefabs.enemiesBase    = null;
        }