Added Stat Change Predictors for Experimental Treatment and Dataminer by Pattieburger
This commit is contained in:
1 parent
d98397ec26
commit
0162ef2e35
4 files changed
+136
-6
No files matched your search
@@ -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
|
||||
- [CreepSore](https://github.com/CreepSore) for creating the bag of crafting search feature
|
||||
- [Poyo](https://x.com/Poyomama02) for the great thumbnail art
|
||||
- Pattieburger for Experimental Treatment and Dataminer Stat Change Predictors
|
||||
@@ -413,9 +413,8 @@ function EID:GlyphOfBalancePrediction(player)
|
||||
end
|
||||
|
||||
--- Crooked Penny ---
|
||||
function EID:CrookedPennyPrediction(rng, carBattery)
|
||||
local rng = EID:RNGNext(rng)
|
||||
local seed = rng
|
||||
function EID:CrookedPennyPrediction(seed, carBattery)
|
||||
seed = EID:RNGNext(seed)
|
||||
-- Repentance makes a new seed by XORing the room's decoration seed
|
||||
if EID.isRepentance then
|
||||
local roomSeed = game:GetLevel():GetCurrentRoom():GetDecorationSeed()
|
||||
@@ -430,13 +429,106 @@ function EID:CrookedPennyPrediction(rng, carBattery)
|
||||
else
|
||||
result = EID:getDescriptionEntry("CrookedPennyTails")
|
||||
-- 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
|
||||
|
||||
if carBattery then return result .. "#{{Collectible356}} " .. EID:CrookedPennyPrediction(rng)
|
||||
if carBattery then return result .. "#{{Collectible356}} " .. EID:CrookedPennyPrediction(seed)
|
||||
else return result 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) --
|
||||
local libertyItems = {[0] = 21, 71, 120, 121}
|
||||
if EID.isRepentance then libertyItems = {[0] = 12, 71, 120, 121, 342, 398} end
|
||||
|
||||
@@ -141,6 +141,29 @@ local function BlackRuneCallback(descObj)
|
||||
return VoidCallback(descObj, true)
|
||||
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
|
||||
local pandoraStages = {
|
||||
[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["5.300.41"] then table.insert(callbacks, BlackRuneCallback) 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
|
||||
if descObj.ObjSubType == 80 then table.insert(callbacks, BlackFeatherCallback) end
|
||||
|
||||
@@ -464,14 +464,24 @@ function EID:GenerateDescription(descriptionObj)
|
||||
if EID.descriptions[EID:getLanguage()].DisableModularDescriptions then return nil end
|
||||
|
||||
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
|
||||
if not itemDataTable then
|
||||
return ""
|
||||
end
|
||||
|
||||
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 = ""
|
||||
|
||||
|
||||
Reference in new issue
Block a user