--[[ This file is only loaded when the game is launched with the "--luadebug" launch option. This allows mods to have access to your computer's files, which is necessary to read glitched item info that's printed to the game's log file. Having --luadebug on would allow malicious mods to delete your files, execute command prompt commands, and probably much more. It also makes certain Lua functions behave differently, which breaks some other mods. USE AT YOUR OWN RISK. ]] local game = Game() -- glitched items start at 4294967295 local maxNumber = 4294967296 local spawnedItems = 0 local lastEffectTrigger = "chain" local descOne = "" local logLocation = os.getenv("USERPROFILE") .. "/Documents/My Games/Binding of Isaac Repentance/log.txt" local logFound = false local logCursor = 0 local triggerColors = { chain = "{{ColorSilver}}", active = "{{ColorLime}}", pickup_collected = "{{ColorYellow}}", enemy_kill = "{{ColorRed}}", damage_taken = "{{ColorRed}}", entity_spawned = "", tear_fire = "{{ColorCyan}}", enemy_hit = "{{ColorEIDError}}", room_clear = "{{ColorOrange}}", } local function entityToName(e, plural) local localizedNames = EID:getDescriptionEntry("GlitchedItemText") -- -1 is often used as an "any of this type", even if there's only one of that type, so converting it to 0 can help find names local eWithZero = string.gsub(e, "-1", "0") plural = plural or false local name = localizedNames[e] or EID:GetEntityXMLName(Type, Variant, SubType) or localizedNames[eWithZero] or e --print out entities with no name yet if name == e then Isaac.DebugString("No name found for " .. e .. " (could be modded)") elseif plural then name = name .. localizedNames["pluralize"] end return name end local function parseEffectLine(raw) local words = {} for w in string.gmatch(raw,"%S+") do table.insert(words, w) end local triggerReplacements = {} local replacements = {} local printEffect = true -- words[1] = "[INFO]", words[2] = "-" local effectTrigger = words[3] -- the effects list is rarely interrupted by music loading log entries, just ignore it and have a slightly inaccurate desc if effectTrigger == "Queued" then return "" end if (string.find(effectTrigger, "entity_spawned")) then effectTrigger = "entity_spawned" triggerReplacements[1] = "{{ColorEIDObjName}}" .. entityToName(string.sub(words[3], 16, -2)) .. "{{CR}}" end -- words[4] = "->" local effectType = words[5] local fullEffect = "" for i=5,#words do fullEffect = fullEffect .. words[i] .. " " end if effectType == "add_temporary_effect" or effectType == "use_active_item" then -- remainder of line = collectible name that's granted for the room local name = "" for i=6,#words do name = name .. words[i] if (i ~= #words) then name = name .. " " end end replacements[1] = name if (Isaac.GetItemIdByName(name) > 0) then replacements[1] = "{{Collectible" .. Isaac.GetItemIdByName(name) .. "}} " .. name end elseif effectType == "convert_entities" then replacements[1] = "{{ColorGray}}" .. entityToName(words[6], true) .. "{{CR}}" replacements[2] = "{{ColorGray}}" .. entityToName(words[8]) elseif effectType == "spawn_entity" then replacements[1] = "{{ColorGray}}" .. entityToName(words[6]) elseif effectType == "fart" then replacements[1] = words[6] elseif effectType == "area_damage" then replacements[1] = words[6] -- display area_damage 0's because they still need to be done to chain to the next thing --if words[6] == "0" then printEffect = false end end local localizedNames = EID:getDescriptionEntry("GlitchedItemText") local eidString = "" if effectTrigger ~= lastEffectTrigger then eidString = eidString .. triggerColors[effectTrigger] .. (localizedNames[effectTrigger] or (effectTrigger .. "#")) end if printEffect then eidString = eidString .. (localizedNames[effectType] or fullEffect) .. "#" end for k,v in ipairs(triggerReplacements) do eidString = string.gsub(eidString, "{T" .. k .. "}", v) end for k,v in ipairs(replacements) do eidString = string.gsub(eidString, "{" .. k .. "}", v) end if effectTrigger ~= "chain" then lastEffectTrigger = effectTrigger end return eidString end local function CheckLogForItems(_) -- Check log.txt every 5 frames if there's a collectible we haven't read the data for yet -- (Should work well for Corrupted Data) if game:GetFrameCount() % 5 ~= 0 or not EID.Config["DisplayGlitchedItemInfo"] or not logFound or EID.itemConfig:GetCollectible(maxNumber - spawnedItems - 1) == nil then return end local numEffects = 0 local eidDesc = "" local theLog = io.open(logLocation, "r") if theLog == nil then return end theLog:seek("set", logCursor) local line = theLog:read() while line ~= nil do if string.find(line, "initialized with") then spawnedItems = spawnedItems + 1 lastEffectTrigger = "chain" eidDesc = "" -- find the number of effects to watch for for s in string.gmatch(line, "%d*%.?%d+") do numEffects = tonumber(s) break end elseif numEffects > 0 then numEffects = numEffects - 1 eidDesc = eidDesc .. parseEffectLine(line) if numEffects == 0 then eidDesc = EID:CheckGlitchedItemConfig(maxNumber - spawnedItems) .. eidDesc -- Glowing Hour Glass type effects cause the game to reload all items, check if our desc is equal to the first one if (descOne == eidDesc) then spawnedItems = 1 end EID:addCollectible(maxNumber - spawnedItems, eidDesc) if spawnedItems == 1 then descOne = eidDesc end end elseif string.find(line, "Game ended;") then spawnedItems = 0 lastEffectTrigger = "chain" eidDesc = "" end line = theLog:read() end logCursor = theLog:seek() theLog:close() end EID:AddCallback(ModCallbacks.MC_POST_UPDATE, CheckLogForItems) local function GameStartTMTRAINER(_,isSave) local theLog = io.open(logLocation, "r") if (theLog == nil) then print("[EID] Could not find the log file at " .. logLocation .. "; glitched item descriptions won't work!") Isaac.DebugString("[EID] Could not find the log file at " .. logLocation .. "; glitched item descriptions won't work!") logFound = false return else logFound = true end -- luckily, when the game reloads, it also reloads all glitched items, so resuming works perfectly as long as we start at the beginning spawnedItems = 0 end EID:AddCallback(ModCallbacks.MC_POST_GAME_STARTED, GameStartTMTRAINER) local function GameEndTMTRAINER() -- Our cursor spot in the log gets wiped if mods are reloaded; can't think of a better way than this Isaac.DebugString("[EID] Game ended; ignore previous glitched items in the log!") end EID:AddCallback(ModCallbacks.MC_PRE_GAME_EXIT, GameEndTMTRAINER) -- shh. it's a non-obtrusive april fools joke for the 1% of people with luadebug -- https://www.youtube.com/watch?v=msDuNZyYAIQ if (os.date("%m/%d") == "04/01") then EID.descriptions["en_us"].sacrifice[1][3] = "{{Coin}} 50% chance of winning 1 coin at Sacrifice#75% chance if you're a genetic freak#!!! If you add Kurt Angle to the mix, your chances of winning drastically go down" end