diff --git a/src/game_api/entities_activefloors.hpp b/src/game_api/entities_activefloors.hpp index 5d9cf3da4..7be149e3a 100644 --- a/src/game_api/entities_activefloors.hpp +++ b/src/game_api/entities_activefloors.hpp @@ -155,3 +155,12 @@ class TimedPowderkeg : public PushBlock /// timer till explosion, -1 = pause, counts down int32_t timer; }; + +class CrushElevator : public Movable +{ + public: + /// This is custom variable, you need [activate_crush_elevator_hack](#activate_crush_elevator_hack) to use it + float y_limit; + /// This is custom variable, you need [activate_crush_elevator_hack](#activate_crush_elevator_hack) to use it + float speed; +}; diff --git a/src/game_api/entities_items.hpp b/src/game_api/entities_items.hpp index b81a35dd3..a95b00a3c 100644 --- a/src/game_api/entities_items.hpp +++ b/src/game_api/entities_items.hpp @@ -303,9 +303,9 @@ class Spark : public Flame uint8_t size_change_timer; uint8_t extra_padding[3]; - /// This is cusome variable, you need [activate_sparktraps_hack](#activate_sparktraps_hack) to use it + /// This is custom variable, you need [activate_sparktraps_hack](#activate_sparktraps_hack) to use it float speed; - /// This is cusome variable, you need [activate_sparktraps_hack](#activate_sparktraps_hack) to use it + /// This is custom variable, you need [activate_sparktraps_hack](#activate_sparktraps_hack) to use it float distance; }; diff --git a/src/game_api/entities_monsters.hpp b/src/game_api/entities_monsters.hpp index e9aec55c6..653290d59 100644 --- a/src/game_api/entities_monsters.hpp +++ b/src/game_api/entities_monsters.hpp @@ -796,9 +796,9 @@ class Tiamat : public Monster float tail_radian; // Counts from 0 to 2*pi, Used to calculate tail angle float tail_move_speed; float right_arm_angle; - /// This is cusome variable, you need [activate_tiamat_position_hack](#activate_tiamat_position_hack) to use it + /// This is custom variable, you need [activate_tiamat_position_hack](#activate_tiamat_position_hack) to use it float attack_x; - /// This is cusome variable, you need [activate_tiamat_position_hack](#activate_tiamat_position_hack) to use it + /// This is custom variable, you need [activate_tiamat_position_hack](#activate_tiamat_position_hack) to use it float attack_y; }; diff --git a/src/game_api/rpc.cpp b/src/game_api/rpc.cpp index 976e7504f..ab8bf53ba 100644 --- a/src/game_api/rpc.cpp +++ b/src/game_api/rpc.cpp @@ -1904,3 +1904,38 @@ void activate_tiamat_position_hack(bool activate) else recover_mem("activate_tiamat_position_hack"); } + +void activate_crush_elevator_hack(bool activate) +{ + auto memory = Memory::get(); + static size_t offsets[3]; + if (offsets[0] == 0) + { + auto func_offset = get_virtual_function_address(VTABLE_OFFSET::ACTIVEFLOOR_CRUSHING_ELEVATOR, 78); + + offsets[0] = find_inst(memory.exe(), "\xF3\x0F\x58\xD0"sv, func_offset, func_offset + 0x80, "activate_crush_elevator_hack"); + if (offsets[0] == 0) + return; + + offsets[0] += 4; // pattern size + offsets[1] = find_inst(memory.exe(), "\xEB*\x0F\x57\xD2"sv, offsets[0], offsets[0] + 0xF0, "activate_crush_elevator_hack"); + if (offsets[1] == 0) + return; + + offsets[1] += 5; // pattern size + offsets[2] = find_inst(memory.exe(), "\xF3\x0F\x58\xC1"sv, offsets[1], offsets[1] + 0x40, "activate_crush_elevator_hack"); + if (offsets[2] == 0) + return; + + offsets[2] += 4; // pattern size + } + + if (activate) + { + write_mem_recoverable("activate_crush_elevator_hack", memory.at_exe(offsets[0]), "\x0f\x2e\x90\x30\x01\x00\x00"sv, true); // ucomiss xmm2,DWORD PTR [rax+0x130] // limit + write_mem_recoverable("activate_crush_elevator_hack", memory.at_exe(offsets[1]), "\xf3\x0f\x10\x9b\x30\x01\x00"sv, true); // movss xmm3,DWORD PTR [rbx+0x130] // limit + write_mem_recoverable("activate_crush_elevator_hack", memory.at_exe(offsets[2]), "\xf3\x0f\x58\x83\x34\x01\x00"sv, true); // addss xmm0,DWORD PTR [rbx+0x134] // speed + } + else + recover_mem("activate_crush_elevator_hack"); +} diff --git a/src/game_api/rpc.hpp b/src/game_api/rpc.hpp index 07c84cee8..b4805b71b 100644 --- a/src/game_api/rpc.hpp +++ b/src/game_api/rpc.hpp @@ -140,3 +140,4 @@ void set_ending_unlock(ENT_TYPE type); void set_olmec_cutscene_enabled(bool enable); void set_tiamat_cutscene_enabled(bool enable); void activate_tiamat_position_hack(bool activate); +void activate_crush_elevator_hack(bool activate); diff --git a/src/game_api/script/lua_console.cpp b/src/game_api/script/lua_console.cpp index 3c94bc7b3..af029d94c 100644 --- a/src/game_api/script/lua_console.cpp +++ b/src/game_api/script/lua_console.cpp @@ -52,6 +52,7 @@ LuaConsole::LuaConsole(SoundManager* soundmanager) {"RegenBlock", "as_movable"}, {"ThinIce", "as_movable"}, {"TimedPowderkeg", "as_pushblock"}, + {"CrushElevator", "as_movable"}, {"UnchainedSpikeBall", "as_movable"}, {"WoodenlogTrap", "as_movable"}, {"BGSurfaceStar", "as_entity"}, diff --git a/src/game_api/script/lua_vm.cpp b/src/game_api/script/lua_vm.cpp index 555119dfd..96916db53 100644 --- a/src/game_api/script/lua_vm.cpp +++ b/src/game_api/script/lua_vm.cpp @@ -2016,6 +2016,8 @@ end lua["set_olmec_cutscene_enabled"] = set_olmec_cutscene_enabled; + /// Tiamat cutscene is also responsible for locking the exit door + /// So you may need to close it yourself if you still want to be required to kill Tiamat lua["set_tiamat_cutscene_enabled"] = set_tiamat_cutscene_enabled; /// Activate custom variables for position used for detecting the player (normally hardcoded) @@ -2023,6 +2025,11 @@ end /// default game values are: attack_x = 17.5 attack_y = 62.5 lua["activate_tiamat_position_hack"] = activate_tiamat_position_hack; + /// Activate custom variables for speed and y coordinate limit for crushing elevator + /// note: because those variables are custom and game does not initiate them, you need to do it yourself for each CrushElevator entity, recommending `set_post_entity_spawn` + /// default game values are: speed = 0.0125, y_limit = 98.5 + lua["activate_crush_elevator_hack"] = activate_crush_elevator_hack; + lua.create_named_table("INPUTS", "NONE", 0, "JUMP", 1, "WHIP", 2, "BOMB", 4, "ROPE", 8, "RUN", 16, "DOOR", 32, "MENU", 64, "JOURNAL", 128, "LEFT", 256, "RIGHT", 512, "UP", 1024, "DOWN", 2048); lua.create_named_table( diff --git a/src/game_api/script/usertypes/entities_activefloors_lua.cpp b/src/game_api/script/usertypes/entities_activefloors_lua.cpp index 1a41d4530..66f24e2a4 100644 --- a/src/game_api/script/usertypes/entities_activefloors_lua.cpp +++ b/src/game_api/script/usertypes/entities_activefloors_lua.cpp @@ -36,6 +36,7 @@ void register_usertypes(sol::state& lua) lua["Entity"]["as_clambase"] = &Entity::as; lua["Entity"]["as_regenblock"] = &Entity::as; lua["Entity"]["as_timedpowderkeg"] = &Entity::as; + lua["Entity"]["as_crushelevator"] = &Entity::as; lua.new_usertype( "Crushtrap", @@ -200,5 +201,14 @@ void register_usertypes(sol::state& lua) &TimedPowderkeg::timer, sol::base_classes, sol::bases()); + + lua.new_usertype( + "CrushElevator", + "y_limit", + &CrushElevator::y_limit, + "speed", + &CrushElevator::speed, + sol::base_classes, + sol::bases()); } } // namespace NEntitiesActiveFloors diff --git a/src/game_api/script/usertypes/entity_casting_lua.cpp b/src/game_api/script/usertypes/entity_casting_lua.cpp index ed47d4fe7..60213c540 100644 --- a/src/game_api/script/usertypes/entity_casting_lua.cpp +++ b/src/game_api/script/usertypes/entity_casting_lua.cpp @@ -611,7 +611,7 @@ void register_usertypes(sol::state& lua) lua["TYPE_MAP"][620] = lua["Entity"]["as_movable"]; // ACTIVEFLOOR_TIAMAT_PLATFORM lua["TYPE_MAP"][621] = lua["Entity"]["as_movable"]; // ACTIVEFLOOR_TIAMAT_SHOULDERPLATFORM lua["TYPE_MAP"][622] = lua["Entity"]["as_movable"]; // ACTIVEFLOOR_BUBBLE_PLATFORM - lua["TYPE_MAP"][623] = lua["Entity"]["as_movable"]; // ACTIVEFLOOR_CRUSHING_ELEVATOR + lua["TYPE_MAP"][623] = lua["Entity"]["as_crushelevator"]; // ACTIVEFLOOR_CRUSHING_ELEVATOR lua["TYPE_MAP"][624] = lua["Entity"]["as_movable"]; // ACTIVEFLOOR_SHIELD lua["TYPE_MAP"][625] = lua["Entity"]["as_regenblock"]; // ACTIVEFLOOR_REGENERATINGBLOCK lua["TYPE_MAP"][628] = lua["Entity"]["as_movable"]; // FX_EGGSHIP_SHELL