# Level Generation

**Level generation** is the process the game uses to create each floor. Each floor has its own requirements of size, special rooms, dead ends that must be met.

## Process[edit | edit source]

First, the game determines how many rooms will generate on the floor. Later floors have more rooms, and Curse of the Labyrinth makes the floor much larger.

- If the floor is not XL or The Void:
- NumberOfRooms = 3.33 × FloorDepth + 5-6
*(maximum of 20)*

- NumberOfRooms = 3.33 × FloorDepth + 5-6
- If the floor is an XL floor:
- NumberOfRooms = 1.8 × (3.33 × FloorDepth + 5-6)
*(maximum of 45)*

- NumberOfRooms = 1.8 × (3.33 × FloorDepth + 5-6)
- If the floor is The Void:
- NumberOfRooms = 50-59

- 2-3 more rooms are added if playing on Hard Mode
- 4 more rooms are added if the floor has Curse of the Lost.

Then the minimum number of dead ends the floor must generate is set.

- All floors have at least 5 dead ends
- 1 dead end is added to all floors except the first floor.
- 1 dead end is added to XL floors.
- 2 dead ends are added to The Void.

Next, special rooms are generated in dead ends.

- Special rooms are placed in order from the dead end farthest from the starting room to the closest.
- If all dead ends on a floor become occupied by special rooms, no more special rooms can generate.
- The Chest, Dark Room, and The Void only generate Boss Rooms and Secret/Super Secret Rooms (and a Grave Room on the Dark Room)).

Special rooms generate in the following order:

- Boss Room (always generates)
- If it is an XL floor, two boss rooms generate back to back.
- Multiple Boss Rooms are generated in The Void.

- Super Secret Room (always generates)
- Shop (always generates in the first 3 chapters, or 4 if Isaac has Silver Dollar)
- Will not generate on the third and subsequent victory laps.

- Treasure Room (always generates in the first 3 chapters, or 4 if Isaac has Bloody Crown)
- If it is an XL floor, two Treasure Rooms generate.

- Dice or Sacrifice Room (1/7 (~14%) base chance, plus an independent 1/4 chance for a total of 5/14 (~36%) if Isaac’s total health is equal to or greater than his total Heart Containers)
- Has a 1/50 base chance to be a Dice Room, plus an independent 1/5 chance for a total of 27/125 (~22%) if Isaac has 2 or more keys; otherwise a Sacrifice Room is chosen.

- Library (1/20 chance, plus an independent 1/4 chance for a total of 23/80 (~29%) if Isaac touched a book this run)
- Curse Room (1/2 chance, plus an independent 1/4 chance for a total of 5/8 (~63%) if Isaac has entered a Devil Room this run)
- Miniboss (1/4 chance, plus an independent 1/4 chance for a total of 7/16 (~44%) if it isn’t the first floor)
- Challenge Room (1/2 chance if Isaac’s total health is equal to or greater than his total heart containers, can't spawn otherwise)
- Cannot spawn on the first floor.
- Will always be a Boss Challenge Room on the second floor of a chapter, and a normal Challenge Room otherwise.

- Vault or Arcade (guaranteed if Isaac has 5 or more coins and it’s the second floor of a chapter, can’t spawn otherwise)
- Has a 1/10 chance to be a Vault, plus an independent 1/3 chance for a total of 2/5 (40%) if Isaac has 2 or more keys; otherwise an Arcade is chosen.

- Bedroom (1/50 chance, plus an independent 1/5 chance for a total of 27/125 (~22%) if Isaac has less than 2 Red/Bone Hearts and no Soul Hearts, or 2 or fewer Soul Hearts and no Red/Bone Hearts)
- Equal chance to be a clean or dirty bedroom.
- Can only spawn in the first 3 chapters

- Secret Room (guaranteed)
- Two secret rooms generate if the player has Fragmented Card)

- Finally, a Grave Room is placed if the floor is Dark Room.

## Pseudo-Code[edit | edit source]

Some parts of the level generation are based on the following pseudo-code:

--Pseudo lua code for getting the number of rooms for a floor. NumberOfRooms = Min(20, Rand(0, 1) + 5 + Floor(StageId * 10 / 3)) if CurseOfTheLabyrinth then NumberOfRooms = Min(45, Floor(NumberOfRooms * 1.8)) elseif CurseOfTheLost then NumberOfRooms += 4 end if StageId == 12 then --The Void NumberOfRooms = 50 + (Rand() % 10) end if IsHardDifficulty then NumberOfRooms += 2 + Rand(0, 1) end --Pseudo lua code for getting the number of deadends a floor must have. MinDeadEnds = 5 if StageId ~= 1 then MinDeadEnds += 1 end if CurseOfTheLabyrinth then MinDeadEnds += 1 end if StageId == 12 then MinDeadEnds += 2 end --Deadends are sorted by distance from the starting room descending. --e.g. Boss room is placed in the farthest deadend, super secret is placed in the next farthest deadend --DequeueDeadend also resizes the deadend. This is important to note because that means most deadends get changed to a 1x1 by the end of this. PlaceRoom(ROOM_BOSS, DequeueDeadend()) --Super Secret PlaceRoom(ROOM_SUPERSECRET, DequeueDeadend()) --Shop if StageId < 7 or (StageId < 9 and HasTrinket(SilverDollar)) and VictoryLap < 3 then PlaceRoom(ROOM_SHOP, DequeueDeadend()) end --Treasure if StageId < 7 or (StageId < 9 and HasTrinket(BloodyCrown)) then PlaceRoom(ROOM_TREASURE, DequeueDeadend()) end --Dice and Sacrifice if StageId < 12 then local deadend = DequeueDeadend() --resizes the room :( if deadend ~= nil then local roomType = nil if Rng() % 50 == 0 or (Rng() % 5 == 0 and GetNumKeys() > 1) then roomType = ROOM_DICE else roomType = ROOM_SACRIFICE end if Rng() % 7 == 0 or (Rng() & 3 == 0 and GetHearts() + GetSoulHearts() >= GetMaxHearts()) then PlaceRoom(roomType) else QueueDeadend(deadend) end end end --Library local deadend = DequeueDeadend() if deadend ~= nil then if Rng() % 20 == 0 or (Rng() & 3 == 0 and GetStateFlag(STATE_BOOK_PICKED_UP)) then PlaceRoom(ROOM_LIBRARY, deadend) else QueueDeadend(deadend) end end --Curse local deadend = DequeueDeadend() if deadend ~= nil then if Rng() & 1 == 0 or (Rng() & 3 == 0 and GetStateFlag(STATE_DEVILROOM_VISITED)) then PlaceRoom(ROOM_CURSE, deadend) else QueueDeadend(deadend) end end --MiniBoss local boss = GetMiniBossRoom() --mini boss is picked based on floor, STATE_ULTRAPRIDE_SPAWNED and rng local deadend = DequeueDeadend() if deadend ~= nil then if Rng() & 3 == 0 or (Rng() & 3 == 0 and StageId ~= 1) then PlaceRoom(boss, deadend) else QueueDeadend(deadend) end end --Challenge local deadend = DequeueDeadend() if deadend ~= nil then if (Rng() & 1 == 0 or StageId >= 2) and GetHearts() + GetSoulHearts() >= GetMaxHearts() and StageId > 1 then PlaceRoom(boss, deadend) else QueueDeadend(deadend) end end --Chest and Arcade local deadend = DequeueDeadend() if deadend ~= nil then local roomType = nil if Rng() % 10 == 0 or (Rng() % 3 == 0 and GetNumKeys() > 1) then roomType = ROOM_CHEST else roomType = ROOM_ARCADE end if GetNumCoins() >= 5 and (StageId == 2 or StageId == 4 or StageId == 6 or StageId == 8) then PlaceRoom(roomType) else QueueDeadend(deadend) end end --Bedroom if StageId < 7 then local deadend = DequeueDeadend() if deadend ~= nil then local roomType = nil if Rng() & 1 == 0 then roomType = ROOM_ISAACS else roomType = ROOM_BARREN end local maxHearts = nil if GetPlayerType() == PLAYER_THELOST or GetPlayerType() == PLAYER_XXX or GetPlayerType() == PLAYER_THESOUL then maxHearts = GetMaxHearts() else maxHearts = GetMaxHearts() + GetBoneHearts() * 2 end local second = false if (GetHearts() < 2 and GetSoulHearts() <= 0) or (maxHearts <= 0 and GetSoulHearts() <= 2) then second = true end if Rng() % 50 == 0 or (Rng() % 5 == 0 and second) then PlaceRoom(roomType) else QueueDeadend(deadend) end end end --Secret TryPlacingSecret() if HasTrinket(TRINKET_FRAGMENTED_CARD) then TryPlacingSecret() end -- Grave Room if StageId == 11 and StageType == 0 then --Dark Room PlaceGrave(DequeueDeadend()) end

## Notes[edit | edit source]

This is taken from Blade's GitHub Gist. (Blade is also known as blcd / Will.) He reverse engineered the game using a disassembler in order to create this pseudo-code.