diff --git a/changelog.txt b/changelog.txt index f63f9af86..b960c45fd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -25,10 +25,22 @@ Additions: Called after a player drops a card/pill onto the ground from their inventory. - MC_PRE_PLAYER_GIVE_BIRTH_CAMBION/IMMACULATE (EntityPlayer, CambionFamiliarFlag) Return false to cancel the familiar being added. + - MC_POST_CYCLE_RATE_CALCULATE (EntityPickup, int CycleNum, int OriginalRate) + Called after the rate at which a collectible is supposed to cycle is calculated (Glitched Crown effect) + Return integer to overwrite cycle rate. * EntityLaser: - GetDamageMultiplier() - SetDamageMultiplier(float Mult) +* ItemPool: + - GetRandomPool(RNG, bool AdvancedSearch, table BlackList) + - PickCollectible(ItemPoolType, bool Decrease, RNG, GetCollectibleFlag) +* RNG: + - GetShiftIdx() + - PhantomNext() + - Previous() + - PhantomPrevious() * Enums: + - GetCollectibleFlag - CambionFamiliarFlag * Added a new option "Extra debug render for FindInRadius". While the DebugFlag.HITSPHERES flag is enabled, debug spheres will be rendered for FindInRadius/QueryRadius calls. /newline/ @@ -37,6 +49,8 @@ Modified: PlayCutscene(CutsceneID, ClearGameState = false) * Game: SetDizzyAmount(TargetIntensity, CurrentIntensity) - Providing CurrentIntensity is now optional +* ItemPool: + GetCollectible(ItemPoolType, Decrease, Seed, DefaultItem, Flags) - Now gives access to the hidden flags * The game no longer prematurely ends the daily run if there was console input, instead blocking it /newline/ Fixes: diff --git a/repentogon/Patches/ASMPatches.cpp b/repentogon/Patches/ASMPatches.cpp index 5f5b68d63..f229c33bc 100644 --- a/repentogon/Patches/ASMPatches.cpp +++ b/repentogon/Patches/ASMPatches.cpp @@ -95,6 +95,7 @@ void PerformASMPatches() { ASMPatchProjectileDeath(); ASMPatchTearDeath(); ASMPatchPrePlayerGiveBirth(); + ASMPatchPostCycleRateCalculate(); // Delirium delirium::AddTransformationCallback(); diff --git a/repentogon/Patches/ASMPatches/ASMCallbacks.cpp b/repentogon/Patches/ASMPatches/ASMCallbacks.cpp index d292ea7fa..b5627bdc4 100644 --- a/repentogon/Patches/ASMPatches/ASMCallbacks.cpp +++ b/repentogon/Patches/ASMPatches/ASMCallbacks.cpp @@ -1084,3 +1084,57 @@ void ASMPatchPrePlayerGiveBirth() { printf("[REPENTOGON] Patching Entity_Player::TriggerHeartPickedUp at %p for MC_PRE_PLAYER_GIVE_BIRTH_IMMACULATE\n", immaculateAddr); PreBirthPatch(immaculateAddr, false); // Immaculate } + +// MC_POST_CYCLE_RATE_CALCULATE(1211) +uint32_t __stdcall RunPostCycleRateCalculate(Entity_Pickup* collectible, uint32_t originalCycleRate) { + uint32_t cycleRate = originalCycleRate; + + const int callbackid = 1211; + if (!CallbackState.test(callbackid - 1000)) { + return originalCycleRate; + } + + lua_State* L = g_LuaEngine->_state; + lua::LuaStackProtector protector(L); + lua::LuaCaller caller(L); + + lua_rawgeti(L, LUA_REGISTRYINDEX, g_LuaEngine->runCallbackRegistry->key); + + lua::LuaResults failure = lua::LuaCaller(L).push(callbackid) + .push(collectible->_cycleCollectibleCount) + .push(collectible, lua::Metatables::ENTITY_PICKUP) + .push(collectible->_cycleCollectibleCount) + .push(originalCycleRate) + .call(1); + + if (failure || !lua_isinteger(L, -1)) { + return originalCycleRate; + } + + cycleRate = (uint32_t)lua_tointeger(L, -1); + if (cycleRate == 0) { // Since the game uses this number as a divisor a value of 0 would cause a Crash + cycleRate = 1; + } + return cycleRate; +} + +void ASMPatchPostCycleRateCalculate() { + SigScan scanner("837f??0075??c787????????00000000"); + scanner.Scan(); + void* cycleSig = scanner.GetAddress(); + + printf("[REPENTOGON] Patching Entity_Pickup::Update at %p for MC_POST_COLLECTIBLE_CYCLE_RATE_CALCULATE\n", cycleSig); + + ASMPatch::SavedRegisters reg(ASMPatch::SavedRegisters::GP_REGISTERS_STACKLESS & ~ASMPatch::SavedRegisters::ECX, true); + ASMPatch patch; + patch.AddBytes(ByteBuffer().AddAny((char*)cycleSig, 0x4)) // check if subtype is 0 + .AddConditionalRelativeJump(ASMPatcher::CondJumps::JE, (char*)cycleSig + 0x6) // return if subtype is 0 + .PreserveRegisters(reg) + .Push(ASMPatch::Registers::ECX) // cycleRate + .Push(ASMPatch::Registers::EDI) // Entity_Pickup* + .AddInternalCall(RunPostCycleRateCalculate) // call RunPostCycleRateCalculate + .CopyRegister(ASMPatch::Registers::ECX, ASMPatch::Registers::EAX) // cycleRate = result + .RestoreRegisters(reg) + .AddRelativeJump((char*)cycleSig + 0x15); + sASMPatcher.PatchAt(cycleSig, &patch); +} diff --git a/repentogon/Patches/ASMPatches/ASMCallbacks.h b/repentogon/Patches/ASMPatches/ASMCallbacks.h index 2637c2538..752c759d3 100644 --- a/repentogon/Patches/ASMPatches/ASMCallbacks.h +++ b/repentogon/Patches/ASMPatches/ASMCallbacks.h @@ -21,3 +21,4 @@ void ASMPatchPickupUpdatePickupGhosts(); void ASMPatchProjectileDeath(); void ASMPatchTearDeath(); void ASMPatchPrePlayerGiveBirth(); +void ASMPatchPostCycleRateCalculate(); diff --git a/repentogon/resources/scripts/enums_ex.lua b/repentogon/resources/scripts/enums_ex.lua index 2db80983f..5c4c55b49 100644 --- a/repentogon/resources/scripts/enums_ex.lua +++ b/repentogon/resources/scripts/enums_ex.lua @@ -173,6 +173,7 @@ ModCallbacks.MC_PLAYER_INIT_PRE_LEVEL_INIT_STATS = 1127 ModCallbacks.MC_PRE_NEW_ROOM = 1200 ModCallbacks.MC_PRE_MEGA_SATAN_ENDING = 1201 ModCallbacks.MC_POST_MODS_LOADED = 1210 +ModCallbacks.MC_POST_CYCLE_RATE_CALCULATE = 1211 ModCallbacks.MC_POST_ITEM_OVERLAY_SHOW = 1134 ModCallbacks.MC_PRE_RENDER = 1135 ModCallbacks.MC_PRE_OPENGL_RENDER = 1136