Modding Guide: Adding a New Room
Relevant source files
The following files were used as context for generating this wiki page:
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/Room.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/StandardRoom.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/RegularLevel.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/BlacksmithRoom.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/builders/RegularBuilder.java
- core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/RitualSiteRoom.java
This guide provides a technical walkthrough for creating and integrating new room types into Shattered Pixel Dungeon's level generation system. Rooms are the fundamental building blocks of every dungeon floor, and understanding their structure and lifecycle is key to creating custom level content.
The process involves defining a new room class, implementing its layout and content through a paint method, and registering it with the level generation system to appear in the dungeon.
Room Class Hierarchy
All rooms in the game extend the abstract Room class. This base class defines the core properties and behaviors, such as size, position, and connections to other rooms. For modding, you will typically extend one of its main subclasses: StandardRoom, SpecialRoom, or ConnectionRoom.
The diagram below shows the basic inheritance structure for rooms.
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/Room.java, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/StandardRoom.java, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/SpecialRoom.java, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/connection/ConnectionRoom.java
Creating a New Room Class
Creating a new room involves extending an appropriate base class and overriding key methods to define its structure, appearance, and content.
Step 1: Extend a Base Room Class
Create a new Java class that inherits from StandardRoom, SpecialRoom, or another existing room type. StandardRoom is the most common choice for general-purpose rooms.
// Example: A simple chasm room
public class ChasmRoom extends StandardRoom {
// ... implementation ...
}
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/ChasmRoom.java:24
Step 2: Define Room Dimensions
The level builder uses dimension methods to determine the size of the room. You can override these to enforce specific size constraints.
| Method | Description |
|---|---|
minWidth() / maxWidth() | Defines the minimum/maximum width of the room in tiles. |
minHeight() / maxHeight() | Defines the minimum/maximum height of the room in tiles. |
sizeCatProbs() | A StandardRoom method that returns probabilities for size categories (normal, large, giant), influencing how the level builder picks its size. |
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/Room.java:60-75, core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/StandardRoom.java:23-26
For example, BlacksmithRoom sets a minimum width and height of 6.
// core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/BlacksmithRoom.java
@Override
public int minWidth() {
return Math.max(super.minWidth(), 6);
}
@Override
public int minHeight() {
return Math.max(super.minHeight(), 6);
}
Step 3: Paint the Room's Layout
The paint(Level level) method is where you define the room's visual layout by setting terrain tiles. The Painter class provides static methods for drawing shapes and filling areas.
Painter Method | Description |
|---|---|
fill(level, room, terrain) | Fills the entire room with a specified terrain. |
fill(level, room, inset, terrain) | Fills the room with an inset (border). |
drawInside(level, room, door, length, terrain) | Draws a line of terrain inward from a door. |
drawLine(level, start, end, terrain) | Draws a line between two points. |
set(level, pos, terrain) | Sets a single tile to a specified terrain. |
Sources: core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/painters/Painter.java
A simple paint implementation first fills the room with walls, then carves out an empty floor, and finally sets the doors.
// core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/special/WeakFloorRoom.java
public void paint( Level level ) {
Painter.fill( level, this, Terrain.WALL );
Painter.fill( level, this, 1, Terrain.CHASM );
Door door = entrance();
door.set( Door.Type.REGULAR );
// ... additional painting logic ...
}
Step 4: Add Content (Items, Mobs, Features)
Inside the paint method, you can also programmatically add content to the level that will spawn within your room.
- Items: Use
level.addItemToSpawn(Item item)to add an item to the level's spawn list. The item will be placed in a valid drop cell later. - Mobs/NPCs: Instantiate a mob and add it to
level.mobs. You must manually set itspos. - Custom Visuals: For special floor or wall graphics, create an instance of a
CustomTilemapand add it tolevel.customTiles. - Level Transitions: To add a quest entrance or other portal, create a
LevelTransitionand add it tolevel.transitions.
The BlacksmithRoom provides a good example of adding an NPC, a quest entrance, and setting specific terrain features.
// core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/BlacksmithRoom.java
public void paint(Level level ) {
// ... terrain painting ...
// Add NPC
Blacksmith npc = new Blacksmith();
do {
npc.pos = level.pointToCell(random( 2 ));
} while (level.heaps.get( npc.pos ) != null);
level.mobs.add( npc );
// Add quest entrance
int entrancePos;
do {
entrancePos = level.pointToCell(random( 2 ));
} while (level.heaps.get( npc.pos ) != null || entrancePos == npc.pos);
QuestEntrance vis = new QuestEntrance();
vis.pos(entrancePos, level);
level.customTiles.add(vis);
level.transitions.add(new LevelTransition(level,
entrancePos,
LevelTransition.Type.BRANCH_EXIT,
Dungeon.depth,
Dungeon.branch + 1,
LevelTransition.Type.BRANCH_ENTRANCE));
Painter.set(level, entrancePos, Terrain.EXIT);
// ... more logic ...
}
Step 5: Define Room-Specific Rules
You can override methods to control how your room interacts with other game systems.
canConnect(Room other): Determines if this room can connect to another. For example, to prevent a quest room from connecting directly to the level exit.canPlaceItem(Point p, Level l): Determines if an item can be randomly placed at a specific point in the room.canPlaceCharacter(Point p, Level l): Determines if a mob can be randomly placed at a specific point.
The RitualSiteRoom prevents items and characters from spawning too close to its central ritual marker.
// core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/quest/RitualSiteRoom.java
@Override
public boolean canPlaceItem(Point p, Level l) {
return super.canPlaceItem(p, l) && l.distance(CeremonialCandle.ritualPos, l.pointToCell(p)) >= 2;
}
@Override
public boolean canPlaceCharacter(Point p, Level l) {
return super.canPlaceCharacter(p, l) && l.distance(CeremonialCandle.ritualPos, l.pointToCell(p)) >= 2;
}
Integrating the Room into Level Generation
After creating your room class, you must add it to the level generation process so it can be selected and placed.
The overall flow involves initializing a list of rooms, using a Builder to arrange them, and a Painter to draw them.
This diagram shows the simplified level generation flow.
To add your room, you need to modify the factory method that creates rooms of its type. For a new StandardRoom, you would modify StandardRoom.createRoom(). For a new SpecialRoom, you would modify SpecialRoom.createRoom().
For example, EntranceRoom.createEntrance() uses a weighted list to select a specific type of entrance room based on the current dungeon depth. You would add your new room class to the rooms list and its corresponding weight to the chances array.
// core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/rooms/standard/entrance/EntranceRoom.java
private static ArrayList<Class<?extends StandardRoom>> rooms = new ArrayList<>();
static {
// Add your new room class here
rooms.add(WaterBridgeEntranceRoom.class);
// ... other rooms
}
private static float[][] chances = new float[27][];
static {
// Add a weight for your room in the appropriate depth-based array
chances[1] = new float[]{4,3,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
// ... other chances
}
public static StandardRoom createEntrance(){
return Reflection.newInstance(rooms.get(Random.chances(chances[Dungeon.depth])));
}
Conclusion
Adding a new room to Shattered Pixel Dungeon is a multi-step but logical process. It begins with creating a new class that inherits from an existing room type, where you define its size and layout via the paint() method. You can populate the room with items, mobs, and other features directly within this method. Finally, to make the room appear in the game, you must integrate it into the level generation logic, typically by adding it to a factory method like StandardRoom.createRoom() or SpecialRoom.createRoom(). By following these steps, you can create a wide variety of custom spaces to enhance the dungeon.