EtG Modding Guide
  • ETG Modding Guide
  • Getting started
    • Modding EtG: Installing Mods
    • Modding EtG: Creating a Mod
    • Uploading a Mod
    • Useful Tools
      • Using IlSpy
  • Making An Item
    • Creating A Passive
    • Creating An Active
    • Creating An Ammolet
    • Creating A Guon
    • Synergies
  • Making a Gun
    • Creating A Gun
      • Setting Up Gun Sprite Folders
      • Creating Gun Jsons/Jtk2ds
        • Pixel Measurement Conversions
    • Setting Up Projectiles
      • Adding Components To A Projectile
      • Projectile HitEffects (Visual Effects)
      • Adding status effects to a projectile
    • Continuous Fire Animations
    • Gun Ammo Types
  • Custom Characters
    • Creating A Standalone Custom Character
  • Making a Floor
    • Introduction
    • Setup
    • Making The Dungeon
    • Tileset
    • Rooms
    • Making the flow
    • Making the Entrance
    • All Files
  • Text, Text Boxes, Etc
    • Textboxes
    • Text Formatting
  • Sounds
    • Using Custom Sounds
    • Customising Gun Sounds
    • Basegame Sound List
    • wwise Sound Dump
  • Misc
    • Making Asset bundles
    • Assetbundles: How-To
    • How to create a hook
    • Creating A Command
    • Subscribing Methods to Actions
    • Reversing Player Controls
    • Undodgeable Projectiles
    • Creating An Enemy
  • Shaders
    • Creating Shaders
  • All things Spriting
    • Important Sprite Creation Information.
    • Importing a Sprite To Visual Studios
  • Monobehaviour Documentation
    • BounceProjModifier
    • PierceProjModifier
    • KeyProjModifier
    • CompanionFollowPlayerBehaviour
  • Various Lists of IDs, Sounds, Etc.
    • List of Item and Gun IDs
    • Enemy Guids
    • List of Base Game Synergies
    • dfSpriteList
    • All Custom Ammo Types
    • Gun .Json Dump
  • OFF TOPIC MEMES
    • Modders Anthem
Powered by GitBook
On this page

Was this helpful?

  1. Making a Floor

Making the Entrance

PreviousMaking the flowNextAll Files

Last updated 3 years ago

Was this helpful?

We are now onto the last part of our floor tutorial! Congratulations. You've almost finished. now we just need to make the entrance.

For this example, I will make a pit to load the floor, but you can use other things as well.

Make the entrance of your floor in RAT. Do not add any pits.

Go back to ModRoomPrefabs and add a new PrototypeDungeonRoom

public static PrototypeDungeonRoom Keep_Entrance_Room;

Ideally, we want our room to have an icon, if we want this we go add new objects to our asset bundle, one empty gameobject, and one texture (the icon).

Go into ModPrefabs and add public static GameObject Entrance_Icon; in InitCustomPrefabs drop

Entrance_Icon = ModAssets.LoadAsset<GameObject>("Entrance_Icon");
ItemAPI.ItemBuilder.AddSpriteToObject(Entrance_Icon, ModAssets.LoadAsset<Texture2D>("Entrance_Icon"), false, false);

inside the InitCustomRoom add

Keep_Entrance_Room = RoomFactory.BuildFromResource("DPSMod/Resources/ModRooms/Keep_Entrance_Room.room");
Keep_Entrance_Room.associatedMinimapIcon = ModPrefabs.Entrance_Icon; //not required

(Tiny pumpkin is the room icon lol. its blurry here but i just forgot to change its filter mode to point)

now we head back towards FloorNameDungeonFlows inside InitDungeonFlows

This section has to do with our entrance

m_KeepEntranceRooms = ScriptableObject.CreateInstance<GenericRoomTable>();
            m_KeepEntranceRooms.includedRoomTables = new List<GenericRoomTable>(0);
            m_KeepEntranceRooms.includedRooms = new WeightedRoomCollection()
            {
                elements = new List<WeightedRoom>() {
                    //we will place the entrance to our floor here.
                }
            };


            SecretFloorNameEntranceInjector = new ProceduralFlowModifierData()
            {
                annotation = "Secret Floor Entrance Room",
                DEBUG_FORCE_SPAWN = false,
                OncePerRun = false,
                placementRules = new List<ProceduralFlowModifierData.FlowModifierPlacementType>() {
                    ProceduralFlowModifierData.FlowModifierPlacementType.RANDOM_NODE_CHILD
                },
                roomTable = m_KeepEntranceRooms,
                // exactRoom = SewersInjectionData.InjectionData[0].exactRoom,
                exactRoom = null,
                RequiresMasteryToken = false,
                chanceToLock = 0,
                selectionWeight = 1,
                chanceToSpawn = 1,
                RequiredValidPlaceable = null,
                prerequisites = new DungeonPrerequisite[0],
                CanBeForcedSecret = true,
                RandomNodeChildMinDistanceFromEntrance = 0,
                exactSecondaryRoom = null,
                framedCombatNodes = 0,
            };

            CastleInjectionData.InjectionData.Add(SecretFloorNameEntranceInjector); 

here we add our room

m_KeepEntranceRooms.includedRooms = new WeightedRoomCollection()
            {
                elements = new List<WeightedRoom>() {
                    //we will place the entrance to our floor here.
                }
            };
m_KeepEntranceRooms.includedRooms = new WeightedRoomCollection()
            {
                elements = new List<WeightedRoom>() {
                    ModRoomPrefabs.GenerateWeightedRoom(ModRoomPrefabs.Keep_Entrance_Room, Weight: 1f)
                }
            };

we can add more rooms if we want some variance and it will randomly select one of these rooms.

Add this to your toolbox:

public static SpeculativeRigidbody GenerateOrAddToRigidBody(GameObject targetObject, CollisionLayer collisionLayer, PixelCollider.PixelColliderGeneration colliderGenerationMode = PixelCollider.PixelColliderGeneration.Tk2dPolygon, bool collideWithTileMap = false, bool CollideWithOthers = true, bool CanBeCarried = true, bool CanBePushed = false, bool RecheckTriggers = false, bool IsTrigger = false, bool replaceExistingColliders = false, bool UsesPixelsAsUnitSize = false, IntVector2? dimensions = null, IntVector2? offset = null)
        {
            SpeculativeRigidbody m_CachedRigidBody = GameObjectExtensions.GetOrAddComponent<SpeculativeRigidbody>(targetObject);
            m_CachedRigidBody.CollideWithOthers = CollideWithOthers;
            m_CachedRigidBody.CollideWithTileMap = collideWithTileMap;
            m_CachedRigidBody.Velocity = Vector2.zero;
            m_CachedRigidBody.MaxVelocity = Vector2.zero;
            m_CachedRigidBody.ForceAlwaysUpdate = false;
            m_CachedRigidBody.CanPush = false;
            m_CachedRigidBody.CanBePushed = CanBePushed;
            m_CachedRigidBody.PushSpeedModifier = 1f;
            m_CachedRigidBody.CanCarry = false;
            m_CachedRigidBody.CanBeCarried = CanBeCarried;
            m_CachedRigidBody.PreventPiercing = false;
            m_CachedRigidBody.SkipEmptyColliders = false;
            m_CachedRigidBody.RecheckTriggers = RecheckTriggers;
            m_CachedRigidBody.UpdateCollidersOnRotation = false;
            m_CachedRigidBody.UpdateCollidersOnScale = false;

            IntVector2 Offset = IntVector2.Zero;
            IntVector2 Dimensions = IntVector2.Zero;
            if (colliderGenerationMode != PixelCollider.PixelColliderGeneration.Tk2dPolygon)
            {
                if (dimensions.HasValue)
                {
                    Dimensions = dimensions.Value;
                    if (!UsesPixelsAsUnitSize)
                    {
                        Dimensions = (new IntVector2(Dimensions.x * 16, Dimensions.y * 16));
                    }
                }
                if (offset.HasValue)
                {
                    Offset = offset.Value;
                    if (!UsesPixelsAsUnitSize)
                    {
                        Offset = (new IntVector2(Offset.x * 16, Offset.y * 16));
                    }
                }
            }
            PixelCollider m_CachedCollider = new PixelCollider()
            {
                ColliderGenerationMode = colliderGenerationMode,
                CollisionLayer = collisionLayer,
                IsTrigger = IsTrigger,
                BagleUseFirstFrameOnly = (colliderGenerationMode == PixelCollider.PixelColliderGeneration.Tk2dPolygon),
                SpecifyBagelFrame = string.Empty,
                BagelColliderNumber = 0,
                ManualOffsetX = Offset.x,
                ManualOffsetY = Offset.y,
                ManualWidth = Dimensions.x,
                ManualHeight = Dimensions.y,
                ManualDiameter = 0,
                ManualLeftX = 0,
                ManualLeftY = 0,
                ManualRightX = 0,
                ManualRightY = 0
            };

            if (replaceExistingColliders | m_CachedRigidBody.PixelColliders == null)
            {
                m_CachedRigidBody.PixelColliders = new List<PixelCollider> { m_CachedCollider };
            }
            else
            {
                m_CachedRigidBody.PixelColliders.Add(m_CachedCollider);
            }

            if (m_CachedRigidBody.sprite && colliderGenerationMode == PixelCollider.PixelColliderGeneration.Tk2dPolygon)
            {
                Bounds bounds = m_CachedRigidBody.sprite.GetBounds();
                m_CachedRigidBody.sprite.GetTrueCurrentSpriteDef().colliderVertices = new Vector3[] { bounds.center - bounds.extents, bounds.center + bounds.extents };
                // m_CachedRigidBody.ForceRegenerate();
                // m_CachedRigidBody.RegenerateCache();
            }

            return m_CachedRigidBody;
        }

now we need a new object in our assetbundle. we will place this in our entrance room. Go to ModPrefabs and add public static GameObject FloorNameEntrance;

Get it like so FloorNameEntrance = ModAssets.LoadAsset("FloorNameEntrance"); you can add a sprite to this object if you wish.

create a new file called KeepEntranceControllerthat inherits from BraveBehaviour, IPlaceConfigurable.

just copy AAAALLLLLLLL this in

public KeepEntranceController()
        {
            targetLevelName = "tt_floorname";
            PitOffset = new IntVector2(5, 2);
            m_Triggered = false;
            m_Destroyed = false;
        }

        public string targetLevelName;
        public IntVector2 PitOffset;

        private bool m_Triggered;
        private bool m_Destroyed;

        private RoomHandler m_ParentRoom;

        private IEnumerator Start()
        {
            yield return null;
            while (GameManager.Instance.IsLoadingLevel && Dungeon.IsGenerating) { yield return null; }
            yield return null;

            //IntVector2 baseCellPosition = (transform.position.IntXY(VectorConversions.Floor) + new IntVector2(4, 1.5));

            // specRigidbody.OnHitByBeam = (Action<BasicBeamController>)Delegate.Combine(specRigidbody.OnHitByBeam, new Action<BasicBeamController>(HandleBeamCollision));
            GameObject PitManager = new GameObject("Pit Manager") { layer = 0 };
            PitManager.transform.position = (transform.position + new Vector3(5, 1.5f));
            tk2dSprite PitDummySprite = PitManager.AddComponent<tk2dSprite>();
            //Toolbox.DuplicateSprite(PitDummySprite, null);
            tk2dSprite pitSprite = PitManager.GetComponent<tk2dSprite>();
            pitSprite.renderer.enabled = false;

            toolbox.GenerateOrAddToRigidBody(PitManager, CollisionLayer.Trap, PixelCollider.PixelColliderGeneration.Manual, IsTrigger: true, dimensions: new IntVector2(2, 2));

            KeepEntrancePitController HallPitManager = PitManager.AddComponent<KeepEntrancePitController>();
            HallPitManager.targetLevelName = targetLevelName;
            yield break;
        }

        


        /*private void HandleBeamCollision(BasicBeamController obj) {
            GoopModifier component = obj.GetComponent<GoopModifier>();
            if (component && component.goopDefinition != null && component.goopDefinition.CanBeIgnited && component.goopDefinition.fireEffect != null) { OnFireStarted(); }
        }*/

        public void ConfigureOnPlacement(RoomHandler room)
        {
            m_ParentRoom = room;

            

            IntVector2 basePosition = (transform.position.IntXY(VectorConversions.Floor) + PitOffset);
            IntVector2 cellPos = basePosition;
            IntVector2 cellPos2 = (basePosition + new IntVector2(1, 0));
            IntVector2 cellPos3 = (basePosition + new IntVector2(1, 1));
            IntVector2 cellPos4 = (basePosition + new IntVector2(0, 1));
            CellData cellData = GameManager.Instance.Dungeon.data[cellPos];
            CellData cellData2 = GameManager.Instance.Dungeon.data[cellPos2];
            CellData cellData3 = GameManager.Instance.Dungeon.data[cellPos3];
            CellData cellData4 = GameManager.Instance.Dungeon.data[cellPos4];

            cellData.type = CellType.PIT;
            cellData2.type = CellType.PIT;
            cellData3.type = CellType.PIT;
            cellData4.type = CellType.PIT;

            cellData.forceAllowGoop = false;
            cellData2.forceAllowGoop = false;
            cellData3.forceAllowGoop = false;
            cellData4.forceAllowGoop = false;

            cellData.fallingPrevented = false;
            cellData2.fallingPrevented = false;
            cellData3.fallingPrevented = false;
            cellData4.fallingPrevented = false;
        }

        private void Update() { }
        private void LateUpdate() { }

        protected override void OnDestroy()
        {
            m_Destroyed = true;
            base.OnDestroy();
        }
    }

    public class KeepEntrancePitController : DungeonPlaceableBehaviour, IPlaceConfigurable
    {

        public KeepEntrancePitController() { targetLevelName = "tt_floorname"; }

        public string targetLevelName;

        private void Start()
        {
            
            SpeculativeRigidbody Rigidbody = specRigidbody;
            Rigidbody.OnEnterTrigger = (SpeculativeRigidbody.OnTriggerDelegate)Delegate.Combine(Rigidbody.OnEnterTrigger, new SpeculativeRigidbody.OnTriggerDelegate(HandleTriggerEntered));
            SpeculativeRigidbody Rigidbody2 = specRigidbody;
            Rigidbody2.OnExitTrigger = (SpeculativeRigidbody.OnTriggerExitDelegate)Delegate.Combine(Rigidbody2.OnExitTrigger, new SpeculativeRigidbody.OnTriggerExitDelegate(HandleTriggerExited));
        }

        private void HandleTriggerEntered(SpeculativeRigidbody specRigidbody, SpeculativeRigidbody sourceSpecRigidbody, CollisionData collisionData)
        {
            PlayerController component = specRigidbody.GetComponent<PlayerController>();
            if (component) { component.LevelToLoadOnPitfall = targetLevelName; }
        }

        private void HandleTriggerExited(SpeculativeRigidbody specRigidbody, SpeculativeRigidbody sourceSpecRigidbody)
        {
            PlayerController component = specRigidbody.GetComponent<PlayerController>();
            if (component) { component.LevelToLoadOnPitfall = string.Empty; }
        }

        public void ConfigureOnPlacement(RoomHandler room) { }

        private void Update() {
            

        }

        protected override void OnDestroy() { base.OnDestroy(); }
    }

make sure to change values according to your needs.

now we head back to ModPrefabs and do

FloorNameEntrance.AddComponent<KeepEntranceController>();

And in ModRoomPrefabs do

RoomBuilder.AddObjectToRoom(Keep_Entrance_Room, new Vector2(3.5f, 12) /* needs tweaking */ , toolbox.GenerateDungeonPlacable(ModPrefabs.FloorNameEntrance, useExternalPrefab: true));

tada! congratulations, you have just done one of the hardest things in modding! nice work and i cant wait to see the results :).