Added Stat Change Predictors for Experimental Treatment and Dataminer by Pattieburger

This commit is contained in:
Wofsauge committed 2026-01-13 22:21:29 +01:00
1 parent d98397ec26
commit 0162ef2e35
4 files changed
+137 -7

No files matched your search

+1
View File
@@ -34,3 +34,4 @@ If you enjoy this mod and want to help on it, check it out on GitHub: https://gi
- [adc](https://steamcommunity.com/id/whytefang/) for creating an awesome new language pack and providing ideas for new functionalities - [adc](https://steamcommunity.com/id/whytefang/) for creating an awesome new language pack and providing ideas for new functionalities
- [CreepSore](https://github.com/CreepSore) for creating the bag of crafting search feature - [CreepSore](https://github.com/CreepSore) for creating the bag of crafting search feature
- [Poyo](https://x.com/Poyomama02) for the great thumbnail art - [Poyo](https://x.com/Poyomama02) for the great thumbnail art
- Pattieburger for Experimental Treatment and Dataminer Stat Change Predictors
+97 -5
View File
@@ -413,9 +413,8 @@ function EID:GlyphOfBalancePrediction(player)
end end
--- Crooked Penny --- --- Crooked Penny ---
function EID:CrookedPennyPrediction(rng, carBattery) function EID:CrookedPennyPrediction(seed, carBattery)
local rng = EID:RNGNext(rng) seed = EID:RNGNext(seed)
local seed = rng
-- Repentance makes a new seed by XORing the room's decoration seed -- Repentance makes a new seed by XORing the room's decoration seed
if EID.isRepentance then if EID.isRepentance then
local roomSeed = game:GetLevel():GetCurrentRoom():GetDecorationSeed() local roomSeed = game:GetLevel():GetCurrentRoom():GetDecorationSeed()
@@ -430,13 +429,106 @@ function EID:CrookedPennyPrediction(rng, carBattery)
else else
result = EID:getDescriptionEntry("CrookedPennyTails") result = EID:getDescriptionEntry("CrookedPennyTails")
-- failures advance crooked penny's RNG an additional time to give the pity penny a seed value -- failures advance crooked penny's RNG an additional time to give the pity penny a seed value
rng = EID:RNGNext(rng) seed = EID:RNGNext(seed)
end end
if carBattery then return result .. "#{{Collectible356}} " .. EID:CrookedPennyPrediction(rng) if carBattery then return result .. "#{{Collectible356}} " .. EID:CrookedPennyPrediction(seed)
else return result end else return result end
end end
-- Experimental Treatment Stat Changes (by Pattieburger)
-- Uses only s2,s3,s4 from the ET collectible RNG stream.
-- Outcome pattern: 4 stats UP, 2 stats DOWN, 1 stat unchanged.
-- Possible Stat change lookup table, for use with modular descriptions (7 stats total).
-- Used by Experimental Treatment and also Dataminer, without the first entry.
local statChangeLookup = {
[1] = {"RedHeart", 1.0 }, -- Health container
[2] = {"Speed", 0.2 },
[3] = REPENTANCE and {"FireRate", 0.5 } or {"Tears", 0.5 },
[4] = {"Damage", 1.0 },
[5] = {"Range", REPENTANCE and 2.5 or 0.5 },
[6] = {"ShotSpeed", 0.2 },
[7] = {"Luck", 1.0 },
}
function EID:ExperimentalTreatmentRNGCheck(player)
-- s1: current collectible RNG seed (pre-pickup)
local s1 = player:GetCollectibleRNG(CollectibleType.COLLECTIBLE_EXPERIMENTAL_TREATMENT):GetSeed()
-- simulate advances
local s2 = EID:RNGNext(s1, 5, 9, 7) -- used (NoChange)
local s3 = EID:RNGNext(s2, 5, 9, 7) -- used (Neg1)
local s4 = EID:RNGNext(s3, 5, 9, 7) -- used (Neg2)
-- NoChange: (s2 % 7) + 1
local noChange = (s2 % 7) + 1
-- Neg1: (s3 % 6) + 1, but if it collides with NoChange -> becomes Luck (7)
local neg1 = (s3 % 6) + 1
if neg1 == noChange then
neg1 = 7
end
-- Neg2: (s4 % 5) + 1, with collision rules:
-- - if collides with neg1 -> becomes Shot speed (6)
-- - if collides with noChange -> becomes Luck (7)
local neg2 = (s4 % 5) + 1
if neg2 == neg1 then
neg2 = 6
end
if neg2 == noChange then
neg2 = 7
end
local statChanges = {}
statChanges[statChangeLookup[neg1][1]] = -statChangeLookup[neg1][2]
statChanges[statChangeLookup[neg2][1]] = -statChangeLookup[neg2][2] + (statChanges[statChangeLookup[neg2][1]] or 0) -- optionally add existing value
-- Positives are the remaining 4 stats
for stat = 1, 7 do
if stat ~= noChange and stat ~= neg1 and stat ~= neg2 then
statChanges[statChangeLookup[stat][1]] = statChangeLookup[stat][2] + (statChanges[statChangeLookup[stat][1]] or 0) -- optionally add existing value
end
end
-- Return stat change table
return statChanges
end
-- Dataminer Stat Changes (by Pattieburger)
-- We "shuffle" the stat table using s1..s5 (mod6, mod5, mod4, mod3, mod2).
-- Result: position 1 = stat UP, position 2 = stat DOWN.
function EID:DataminerRNGCheck(player)
-- s0: current collectible RNG seed (pre-use)
local s0 = player:GetCollectibleRNG(CollectibleType.COLLECTIBLE_DATAMINER):GetSeed()
-- simulate s1..s5 (do NOT alter game RNG; just compute next seeds)
local s1 = EID:RNGNext(s0, 5, 9, 7)
local s2 = EID:RNGNext(s1, 5, 9, 7)
local s3 = EID:RNGNext(s2, 5, 9, 7)
local s4 = EID:RNGNext(s3, 5, 9, 7)
local s5 = EID:RNGNext(s4, 5, 9, 7)
-- stat indices:
-- 1=Speed, 2=Fire rate, 3=Damage, 4=Range, 5=Shotspeed, 6=Luck
local statTable = {1,2,3,4,5,6}
local seeds = { s1, s2, s3, s4, s5 }
for i = 6, 2, -1 do
local seed = seeds[7 - i] -- 6→1, 5→2, 4→3, 3→4, 2→5
local j = (seed % i) + 1
statTable[i], statTable[j] = statTable[j], statTable[i]
end
local upStat = statTable[1] + 1 -- +1 to skip Health container entry
local downStat = statTable[2] + 1 -- +1 to skip Health container entry
return {
[statChangeLookup[downStat][1]] = -statChangeLookup[downStat][2],
[statChangeLookup[upStat][1]] = statChangeLookup[upStat][2],
}
end
-- Liberty Cap, Broken Syringe, Mom's Lock (extremely similar, simple RNG modulos) -- -- Liberty Cap, Broken Syringe, Mom's Lock (extremely similar, simple RNG modulos) --
local libertyItems = {[0] = 21, 71, 120, 121} local libertyItems = {[0] = 21, 71, 120, 121}
if EID.isRepentance then libertyItems = {[0] = 12, 71, 120, 121, 342, 398} end if EID.isRepentance then libertyItems = {[0] = 12, 71, 120, 121, 342, 398} end
+27
View File
@@ -141,6 +141,29 @@ local function BlackRuneCallback(descObj)
return VoidCallback(descObj, true) return VoidCallback(descObj, true)
end end
local function RandomStatIncreaseCallback(descObj)
for i = 1, #EID.coopAllPlayers do
local player = EID.coopAllPlayers[i]
-- only add description for relevant players
if not EID.InsideItemReminder or (EID.InsideItemReminder and EID.ItemReminderPlayerEntity == player) then
local playerID = player:GetPlayerType()
EID:appendToDescription(descObj, "#"..EID:GetPlayerIcon(playerID) .. " {{ColorIsaac}}"..player:GetName().."{{CR}}#")
if descObj.ObjSubType == 240 then
-- Experimental Treatment
local itemDataTable = EID:ExperimentalTreatmentRNGCheck(player)
EID:appendToDescription(descObj, EID:GenerateDescriptionFromStatTable(itemDataTable))
else
-- Dataminer
local itemDataTable = EID:DataminerRNGCheck(player)
EID:appendToDescription(descObj, EID:GenerateDescriptionFromStatTable(itemDataTable))
end
end
end
return descObj
end
-- Map each text block of Pandora's Box to the AbsoluteStage number. Second entry is the block used for Alt-Stages -- Map each text block of Pandora's Box to the AbsoluteStage number. Second entry is the block used for Alt-Stages
local pandoraStages = { local pandoraStages = {
[1] = { 1, 1 }, -- B1 [1] = { 1, 1 }, -- B1
@@ -1302,6 +1325,10 @@ local function EIDConditionsAB(descObj)
if EID.collectiblesOwned[477] then table.insert(callbacks, VoidCallback) end if EID.collectiblesOwned[477] then table.insert(callbacks, VoidCallback) end
if EID.collectiblesOwned["5.300.41"] then table.insert(callbacks, BlackRuneCallback) end if EID.collectiblesOwned["5.300.41"] then table.insert(callbacks, BlackRuneCallback) end
end end
if EID.Config["ItemReminderShowRNGCheats"] then
if descObj.ObjSubType == 240 then table.insert(callbacks, RandomStatIncreaseCallback) end
if descObj.ObjSubType == 481 then table.insert(callbacks, RandomStatIncreaseCallback) end
end
elseif descObj.ObjVariant == PickupVariant.PICKUP_TRINKET then elseif descObj.ObjVariant == PickupVariant.PICKUP_TRINKET then
if descObj.ObjSubType == 80 then table.insert(callbacks, BlackFeatherCallback) end if descObj.ObjSubType == 80 then table.insert(callbacks, BlackFeatherCallback) end
+12 -2
View File
@@ -464,14 +464,24 @@ function EID:GenerateDescription(descriptionObj)
if EID.descriptions[EID:getLanguage()].DisableModularDescriptions then return nil end if EID.descriptions[EID:getLanguage()].DisableModularDescriptions then return nil end
local itemDataTable = EID.ItemData[itemID] local itemDataTable = EID.ItemData[itemID]
return EID:GenerateDescriptionFromStatTable(itemDataTable, descriptionObj, itemID)
end
-- Generates a description for an item based on its modules defined in EID.ItemData
-- Optional: A description object can be provided to apply modular data modifiers
-- Returns an empty string if no modules are defined for the item
function EID:GenerateDescriptionFromStatTable(itemDataTable, descriptionObj, itemID)
-- return empty string if no ItemData are defined -- return empty string if no ItemData are defined
if not itemDataTable then if not itemDataTable then
return "" return ""
end end
itemDataTable = EID:ApplyModularDataModifier(itemDataTable, descriptionObj) if descriptionObj then
itemDataTable = EID:ApplyModularDataModifier(itemDataTable, descriptionObj)
end
local sortedModulesPositivePrio, sortedModulesNegativePrio = EID:GetSortedModularDescriptionEntries(itemDataTable, false, true, itemID) local sortedModulesPositivePrio, sortedModulesNegativePrio = EID:GetSortedModularDescriptionEntries(itemDataTable, false, itemID ~= nil, itemID)
local description = "" local description = ""