When clearing a room, the game has a chance of rewarding a pickup or trinket. This based on many things, including your current luck and whether you have some particular items. The full logic is contained within the following pseudo-code:
local room = Game():GetLevel():GetCurrentRoom() local awardSeed = room.AwardSeed local player = Game():GetPlayer(0) local difficulty = Game().Difficulty local rng = RNG() rng:SetSeed(awardSeed, 35) --5, 9, 7 local pickupPercent = rng:RandomFloat() if (player:HasCollectible(COLLECTIBLE_LUCKYFOOT)) then pickupPercent = (pickupPercent * 0.9) + 0.1 end local luck = math.max(math.min(player.Luck, 10), 0) --Clamp to 0-10 --Max luck increases the pickupPercent range from 0-1 to 0-2 --That means the more luck you have, the more likely you are to get chests. pickupPercent = rng:RandomFloat() * luck * 0.1 + pickupPercent if (player:HasTrinket(TRINKET_LUCKY_TOE)) then if (player:HasCollectible(COLLECTIBLE_LUCKYFOOT) and luck > 0) then pickupPercent = (pickupPercent * 0.98) + 0.02 else pickupPercent = (pickupPercent * 0.9) + 0.1 end end local pickupAward = COLLECTIBLE_NULL local pickupCount = 1 if (pickupPercent > 0.22) then if (pickupPercent < 0.3) then if (rng:RandomInt(3) == 0) then pickupAward = PICKUP_TAROTCARD elseif (rng:RandomInt(2) == 0) then pickupAward = PICKUP_TRINKET else pickupAward = PICKUP_PILL end elseif (pickupPercent < 0.45) then pickupAward = PICKUP_COIN elseif (pickupPercent < 0.5 and player:HasTrinket(TRINKET_RIB_OF_GREED)) then pickupAward = PICKUP_COIN elseif (pickupPercent < 0.6 and (not player:HasTrinket(TRINKET_DAEMONS_TAIL) or rng:RandomInt(5) == 0)) then pickupAward = PICKUP_HEART elseif (pickupPercent < 0.8) then pickupAward = PICKUP_KEY elseif (pickupPercent < 0.95) then pickupAward = PICKUP_BOMB else pickupAward = PICKUP_CHEST end if (rng:RandomInt(20) == 0 or (rng:RandomInt(15) == 0 and player:HasTrinket(TRINKET_WATCH_BATTERY))) then pickupAward = PICKUP_LIL_BATTERY end if (rng:RandomInt(50) == 0) then pickupAward = PICKUP_GRAB_BAG end if (player:HasTrinket(TRINKET_ACE_SPADES) and rng:RandomInt(10) == 0) then pickupAward = PICKUP_TAROTCARD elseif (player:HasTrinket(TRINKET_SAFETY_CAP) and rng:RandomInt(10) == 0) then pickupAward = PICKUP_PILL elseif (player:HasTrinket(TRINKET_MATCH_STICK) and rng:RandomInt(10) == 0) then pickupAward = PICKUP_BOMB elseif (player:HasTrinket(TRINKET_CHILDS_HEART) and rng:RandomInt(10) == 0 and (not player:HasTrinket(TRINKET_DAEMONS_TAIL) or rng:RandomInt(5) == 0)) then pickupAward = PICKUP_HEART elseif (player:HasTrinket(TRINKET_RUSTED_KEY) and rng:RandomInt(10) == 0) then pickupAward = PICKUP_KEY end if (player:HasCollectible(COLLECTIBLE_SMELTER) and rng:RandomInt(50) == 0) then pickupAward = PICKUP_TRINKET end end if (player:HasCollectible(COLLECTIBLE_GUPPYS_TAIL)) then if (rng:RandomInt(3) != 0) then if (rng:RandomInt(3) == 0) then pickupAward = PICKUP_NULL end else if (rng:RandomInt(2) != 0) then pickupAward = PICKUP_LOCKEDCHEST else pickupAward = PICKUP_CHEST end end end if (player:HasCollectible(COLLECTIBLE_CONTRACT_FROM_BELOW) and pickupAward != PICKUP_TRINKET) then pickupCount = player:GetCollectibleNum(COLLECTIBLE_CONTRACT_FROM_BELOW) + 1 --The chance of getting nothing goes down with each contract exponentially local nothingChance = math.pow(0.666, pickupCount - 1) if (nothingChance * 0.5 > rng:NextFloat()) then pickupCount = 0 end end if (difficulty == 1 and pickupAward == PICKUP_HEART) then if rng:RandomInt(100) >= 35 then pickupAward = PICKUP_NULL end end if (player:HasCollectible(COLLECTIBLE_BROKEN_MODEM) and rng:RandomInt(4) == 0 and pickupCount >= 1 and (pickupAward == PICKUP_COIN or pickupAward == PICKUP_HEART or pickupAward == PICKUP_KEY or pickupAward == PICKUP_GRAB_BAG or pickupAward == PICKUP_BOMB) then pickupCount = pickupCount + 1 end if (pickupCount > 0 and pickupAward != PICKUP_NULL) then local subType = 0 for i=1, pickupCount do local ent = Game():Spawn(ENTITY_PICKUP, pickupAward, nearCenter, Vector(0, 0), 0, subtype, rng:Next()) subType = ent.SubType end end
Translation
First, the game generates a random number using this formula:
(RandomFloat * Luck * 0.1) + pickupPercent
- RandomFloat and pickupPercent are random numbers between 0 and 1
- Luck is clamped to 0 if Isaac’s luck is less than 0 and 10 if Isaac’s luck is greater than 10
- This chance is modified by the following items/trinkets:
- Lucky Foot multiplies RandomFloat and pickupPercent by 0.9, then adds 0.1.
- Lucky Toe multiplies pickupPercent by 0.98, then adds 0.02.
That number is then used to determine the reward given after clearing the room. At zero luck and with no other modifiers, the chances are as follows:
- Nothing (22%)
- A tarot card (2.66%)
- A pill (2.66%)
- A trinket (2.66%)
- A coin (15%, or 20% if Isaac has Rib of Greed)
- A heart (15%, or 10% if Isaac has Rib of Greed)
- If Isaac has Daemon's Tail, the heart has an 80% chance of being replaced by a key.
- A key (20%)
- A bomb (15%)
- A chest (5%)
- If Isaac has positive luck, the chance for a chest increases and all other chances decrease.
- Lucky Foot/Toe decrease the chance of getting nothing, but do not themselves increase the chance for chests to spawn.
- If Isaac has positive luck, the chance for a chest increases and all other chances decrease.
The reward then has a chance to be modified/replaced by the following, in order:
- Watch Battery (3.33% chance to replace with a lil’ battery)
- A sack (2% chance, always in effect)
- Ace of Spades (10% chance to replace with a tarot card)
- Safety Cap (10% chance to replace with a pill)
- Match Stick (10% chance to replace with a bomb)
- Child's Heart (10% chance to replace with a heart)
- Rusted Key (10% chance to replace with a key)
- Smelter (2% chance to replace with a trinket)
- If Isaac has multiple of these, the first one to activate is the one that replaces the room reward
- Guppy's Tail has a 33% chance to replace the reward with a (locked) chest and a 33% chance to prevent it from spawning.
- Contract From Below gives an extra copy of the reward, but has a 33% chance to prevent it from spawning.
- Each extra contract Isaac has causes another copy of the reward to spawn and halves the chance the reward doesn’t spawn.
- If playing on Hard Mode, heart rewards have a 66% chance to not spawn.
- Broken Modem has a 25% chance to create an additional copy of the reward if it’s a key, coin, heart, bomb, or sack.
Notes
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.