diff --git a/docs/game_data/spel2.lua b/docs/game_data/spel2.lua index f9f06777c..56fa8e5a1 100644 --- a/docs/game_data/spel2.lua +++ b/docs/game_data/spel2.lua @@ -2034,51 +2034,6 @@ do ---@field local_player_slot integer ---@field get_code fun(self): string @Gets the string equivalent of the code ----@class LogicList - ---@field olmec_cutscene LogicOlmecCutscene - ---@field tiamat_cutscene LogicTiamatCutscene - ---@field magmaman_spawn LogicMagmamanSpawn - ---@field diceshop LogicDiceShop - ----@class Logic - ---@field logic_index integer - ----@class LogicOlmecCutscene : Logic - ---@field olmec Entity - ---@field player Entity - ---@field cinematic_anchor Entity - ---@field timer integer - ----@class LogicTiamatCutscene : Logic - ---@field tiamat Entity - ---@field player Entity - ---@field cinematic_anchor Entity - ---@field timer integer - ----@class MagmamanSpawnPosition - ---@field x integer - ---@field y integer - ---@field timer integer - ----@class LogicVolcana : Logic - ---@field magmaman_positions custom_Array - ----@class LogicDiceShop : Logic - ---@field bet_machine integer - ---@field die1 integer - ---@field die2 integer - ---@field die_1_value integer - ---@field die_2_value integer - ---@field prize_dispenser integer - ---@field prize integer - ---@field forcefield integer - ---@field bet_active boolean - ---@field forcefield_deactivated boolean - ---@field boss_angry boolean - ---@field result_announcement_timer integer - ---@field won_prizes_count integer - ---@field balance integer - ---@class RoomOwnersInfo ---@field owned_items custom_map @key/index is the uid of an item ---@field owned_rooms RoomOwnerDetails[] @@ -5922,6 +5877,159 @@ function Quad:is_point_inside(x, y, epsilon) end ---@field player_create_giblets boolean[] @size: MAX_PLAYERS ---@field next_sidepanel_slidein_timer number +---@class LogicList + ---@field tutorial LogicTutorial @Handles dropping of the torch and rope in intro routine (first time play) + ---@field ouroboros LogicOuroboros + ---@field basecamp_speedrun LogicBasecampSpeedrun @Keep track of time, player position passing official + ---@field ghost_trigger Logic @It's absence is the only reason why ghost doesn't spawn at boss levels or CO + ---@field ghost_toast_trigger LogicGhostToast + ---@field tun_aggro Logic @Spawns tun at the door at 30s mark + ---@field diceshop LogicDiceShop + ---@field tun_pre_challenge LogicTunPreChallenge + ---@field tun_moon_challenge LogicMoonChallenge + ---@field tun_star_challenge LogicStarChallenge + ---@field tun_sun_challenge LogicSunChallenge + ---@field magmaman_spawn LogicMagmamanSpawn + ---@field water_bubbles LogicUnderwaterBubbles @Only the bubbles that spawn from the floor
Even without it, entities moving in water still spawn bubbles + ---@field olmec_cutscene LogicOlmecCutscene + ---@field tiamat_cutscene LogicTiamatCutscene + ---@field apep_spawner LogicApepTrigger @Triggers and spawns Apep only in rooms set as ROOM_TEMPLATE.APEP + ---@field city_of_gold_ankh_sacrifice LogicCOGAnkhSacrifice @All it does is it runs transition to Duat after time delay (sets the state next theme etc. and state.items for proper player respawn) + ---@field duat_bosses_spawner Logic + ---@field bubbler LogicTiamatBubbles @Spawn rising bubbles at Tiamat (position hardcoded) + ---@field tusk_pleasure_palace LogicTuskPleasurePalace @Triggers aggro on everyone when non-high roller enters door + ---@field discovery_info Logic @black market, vlad, wet fur discovery, logic shows the toast + ---@field black_market Logic @Changes the camera bounds when you reach black market + ---@field jellyfish_trigger Logic + ---@field arena_1 LogicArena1 @Handles create spawns and more, is cleared as soon as the winner is decided (on last player alive) + ---@field arena_2 Logic + ---@field arena_3 Logic @Handles time end death + ---@field arena_alien_blast LogicArenaAlienBlast + ---@field arena_loose_bombs LogicArenaLooseBombs + ---@field start_logic fun(self, idx: LOGIC): Logic @This only properly constructs the base class
you may still need to initialise the parameters correctly +local LogicList = nil +---@param idx LOGIC +---@return nil +function LogicList:stop_logic(idx) end +---@param log Logic +---@return nil +function LogicList:stop_logic(log) end + +---@class Logic + ---@field logic_index LOGIC + +---@class LogicTutorial : Logic + ---@field pet_tutorial Entity + ---@field timer integer + +---@class LogicOuroboros : Logic + ---@field sound SoundMeta + ---@field timer integer + +---@class LogicBasecampSpeedrun : Logic + ---@field administrator integer @entity uid of the character that keeps the time + ---@field crate integer @entity uid. you must break this crate for the run to be valid, otherwise you're cheating + +---@class LogicGhostToast : Logic + ---@field toast_timer integer @ default 90 + +---@class LogicDiceShop : Logic + ---@field boss_uid integer + ---@field boss_type ENT_TYPE + ---@field bet_machine integer @entity uid + ---@field die1 integer @entity uid + ---@field die2 integer @entity uid + ---@field die_1_value integer + ---@field die_2_value integer + ---@field prize_dispenser integer @entity uid + ---@field prize integer @entity uid + ---@field forcefield integer @entity uid + ---@field bet_active boolean + ---@field forcefield_deactivated boolean + ---@field result_announcement_timer integer @the time the boss waits after your second die throw to announce the results + ---@field won_prizes_count integer + ---@field balance integer @cash balance of all the games + +---@class LogicTunPreChallenge : Logic + ---@field tun_uid integer + +---@class LogicChallenge : Logic + ---@field floor_challenge_entrance_uid integer + ---@field floor_challenge_waitroom_uid integer + ---@field challenge_active boolean + ---@field forcefield_countdown integer + +---@class LogicMoonChallenge : LogicChallenge + ---@field mattock_uid integer @entity uid + +---@class LogicStarChallenge : LogicChallenge + ---@field torches Entity[] + ---@field start_countdown integer + +---@class LogicSunChallenge : LogicChallenge + ---@field start_countdown integer + +---@class LogicMagmamanSpawn : Logic + ---@field magmaman_positions custom_Array +local LogicMagmamanSpawn = nil +---@param x integer +---@param y integer +---@return nil +function LogicMagmamanSpawn:add_spawn(x, y) end +---@param ms MagmamanSpawnPosition +---@return nil +function LogicMagmamanSpawn:add_spawn(ms) end +---@param x integer +---@param y integer +---@return nil +function LogicMagmamanSpawn:remove_spawn(x, y) end +---@param ms MagmamanSpawnPosition +---@return nil +function LogicMagmamanSpawn:remove_spawn(ms) end + +---@class LogicUnderwaterBubbles : Logic + +---@class LogicOlmecCutscene : Logic + ---@field fx_olmecpart_large Entity + ---@field olmec Entity + ---@field player Entity + ---@field cinematic_anchor Entity + ---@field timer integer + +---@class LogicTiamatCutscene : Logic + ---@field tiamat Entity + ---@field player Entity + ---@field cinematic_anchor Entity + ---@field timer integer + +---@class LogicApepTrigger : Logic + ---@field spawn_cooldown integer + ---@field cooling_down boolean + ---@field apep_journal_entry_logged boolean + +---@class LogicCOGAnkhSacrifice : Logic + ---@field timer integer + +---@class LogicTiamatBubbles : Logic + ---@field bubble_spawn_timer integer + +---@class LogicTuskPleasurePalace : Logic + ---@field locked_door integer + +---@class LogicArena1 : Logic + ---@field crate_spawn_timer integer + +---@class LogicArenaAlienBlast : Logic + ---@field timer integer + +---@class LogicArenaLooseBombs : Logic + ---@field timer integer + +---@class MagmamanSpawnPosition + ---@field x integer + ---@field y integer + ---@field timer integer + end --## Static class functions @@ -5960,12 +6068,6 @@ function Color:fuchsia() end function Color:purple() end --## Constructors - -MagmamanSpawnPosition = nil ----@param x_ integer ----@param y_ integer ----@return MagmamanSpawnPosition -function MagmamanSpawnPosition:new(x_, y_) end ---Create a new color - defaults to black ---@return Color function Color:new() end @@ -6084,6 +6186,12 @@ function Quad:new(_bottom_left_x, _bottom_left_y, _bottom_right_x, _bottom_right ---@return Quad function Quad:new(aabb) end +MagmamanSpawnPosition = nil +---@param x_ integer +---@param y_ integer +---@return MagmamanSpawnPosition +function MagmamanSpawnPosition:new(x_, y_) end + --## Enums diff --git a/docs/parse_source.py b/docs/parse_source.py index 8f00d989e..dbd0cec7c 100644 --- a/docs/parse_source.py +++ b/docs/parse_source.py @@ -104,6 +104,7 @@ "../src/game_api/script/usertypes/screen_arena_lua.cpp", "../src/game_api/script/usertypes/socket_lua.cpp", "../src/game_api/script/usertypes/steam_lua.cpp", + "../src/game_api/script/usertypes/logic_lua.cpp", ] vtable_api_files = [ "../src/game_api/script/usertypes/vtables_lua.cpp", @@ -891,7 +892,8 @@ def run_parse(): if not var: continue var = var.split(",") - vars.append({"name": var[0], "type": var[1]}) + if(len(var) > 1): + vars.append({"name": var[0], "type": var[1]}) enums.append({"name": name, "vars": vars}) data = open(file, "r").read() data = data.replace("\n", " ") diff --git a/docs/src/includes/_enums.md b/docs/src/includes/_enums.md index 0853597b3..5d0f07cf3 100644 --- a/docs/src/includes/_enums.md +++ b/docs/src/includes/_enums.md @@ -642,6 +642,44 @@ Name | Data | Description [COARSE_LAVA](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LIQUID_POOL.COARSE_LAVA) | 4 | [STAGNANT_LAVA](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LIQUID_POOL.STAGNANT_LAVA) | 5 | +## LOGIC + + +> Search script examples for [LOGIC](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC) + + + +Name | Data | Description +---- | ---- | ----------- +[TUTORIAL](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.TUTORIAL) | LOGIC::TUTORIAL | +[OUROBOROS](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.OUROBOROS) | LOGIC::OUROBOROS | +[SPEEDRUN](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.SPEEDRUN) | LOGIC::SPEEDRUN | +[GHOST](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.GHOST) | LOGIC::GHOST | +[GHOST_TOAST](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.GHOST_TOAST) | LOGIC::GHOST_TOAST | +[TUN_AGGRO](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.TUN_AGGRO) | LOGIC::TUN_AGGRO | +[DICESHOP](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.DICESHOP) | LOGIC::DICESHOP | +[PRE_CHALLENGE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.PRE_CHALLENGE) | LOGIC::PRE_CHALLENGE | +[MOON_CHALLENGE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.MOON_CHALLENGE) | LOGIC::MOON_CHALLENGE | +[STAR_CHALLENGE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.STAR_CHALLENGE) | LOGIC::STAR_CHALLENGE | +[SUN_CHALLENGE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.SUN_CHALLENGE) | LOGIC::SUN_CHALLENGE | +[MAGMAMAN_SPAWN](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.MAGMAMAN_SPAWN) | LOGIC::MAGMAMAN_SPAWN | +[WATER_BUBBLES](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.WATER_BUBBLES) | LOGIC::WATER_BUBBLES | +[OLMEC_CUTSCENE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.OLMEC_CUTSCENE) | LOGIC::OLMEC_CUTSCENE | +[TIAMAT_CUTSCENE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.TIAMAT_CUTSCENE) | LOGIC::TIAMAT_CUTSCENE | +[APEP](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.APEP) | LOGIC::APEP | +[COG_SACRIFICE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.COG_SACRIFICE) | LOGIC::COG_SACRIFICE | +[DUAT_BOSSES](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.DUAT_BOSSES) | LOGIC::DUAT_BOSSES | +[BUBBLER](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.BUBBLER) | LOGIC::BUBBLER | +[PLEASURE_PALACE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.PLEASURE_PALACE) | LOGIC::PLEASURE_PALACE | +[DISCOVERY_INFO](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.DISCOVERY_INFO) | LOGIC::DISCOVERY_INFO | +[BLACK_MARKET](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.BLACK_MARKET) | LOGIC::BLACK_MARKET | +[JELLYFISH](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.JELLYFISH) | LOGIC::JELLYFISH | +[ARENA_1](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.ARENA_1) | LOGIC::ARENA_1 | +[ARENA_2](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.ARENA_2) | LOGIC::ARENA_2 | +[ARENA_3](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.ARENA_3) | LOGIC::ARENA_3 | +[ARENA_ALIEN_BLAST](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.ARENA_ALIEN_BLAST) | LOGIC::ARENA_ALIEN_BLAST | +[ARENA_LOOSE_BOMBS](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=LOGIC.ARENA_LOOSE_BOMBS) | LOGIC::ARENA_LOOSE_BOMBS | + ## MASK diff --git a/docs/src/includes/_types.md b/docs/src/includes/_types.md index e62cc7f36..044efcb96 100644 --- a/docs/src/includes/_types.md +++ b/docs/src/includes/_types.md @@ -152,6 +152,36 @@ bool | [final_ghost](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=fi int | [breath_cooldown](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=breath_cooldown) | bool | [punish_ball](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=punish_ball) | +### LogicArena1 + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [crate_spawn_timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=crate_spawn_timer) | + +### LogicArenaAlienBlast + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=timer) | + +### LogicArenaLooseBombs + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=timer) | + ## Callback context types @@ -709,7 +739,7 @@ nil | [set_quad(Quad quad)](https://github.com/spelunky-fyi/overlunky/search?l=L ### MagmamanSpawnPosition -Used in [LogicList](#LogicList) +Used in [LogicMagmamanSpawn](#LogicMagmamanSpawn) Type | Name | Description ---- | ---- | ----------- @@ -1293,7 +1323,53 @@ Used in [LogicList](#LogicList) Type | Name | Description ---- | ---- | ----------- -int | [logic_index](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=logic_index) | +[LOGIC](#LOGIC) | [logic_index](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=logic_index) | + +### LogicApepTrigger + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [spawn_cooldown](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=spawn_cooldown) | +bool | [cooling_down](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=cooling_down) | +bool | [apep_journal_entry_logged](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=apep_journal_entry_logged) | + +### LogicBasecampSpeedrun + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [administrator](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=administrator) | entity uid of the character that keeps the time +int | [crate](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=crate) | entity uid. you must break this crate for the run to be valid, otherwise you're cheating + +### LogicCOGAnkhSacrifice + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=timer) | + +### LogicChallenge + +Used in [LogicMoonChallenge](#LogicMoonChallenge), [LogicStarChallenge](#LogicStarChallenge), [LogicSunChallenge](#LogicSunChallenge) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [floor_challenge_entrance_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=floor_challenge_entrance_uid) | +int | [floor_challenge_waitroom_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=floor_challenge_waitroom_uid) | +bool | [challenge_active](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=challenge_active) | +int | [forcefield_countdown](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=forcefield_countdown) | ### LogicDiceShop @@ -1303,20 +1379,31 @@ Derived from [Logic](#Logic) Type | Name | Description ---- | ---- | ----------- -int | [bet_machine](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=bet_machine) | -int | [die1](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=die1) | -int | [die2](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=die2) | +int | [boss_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=boss_uid) | +[ENT_TYPE](#ENT_TYPE) | [boss_type](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=boss_type) | +int | [bet_machine](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=bet_machine) | entity uid +int | [die1](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=die1) | entity uid +int | [die2](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=die2) | entity uid int | [die_1_value](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=die_1_value) | int | [die_2_value](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=die_2_value) | -int | [prize_dispenser](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=prize_dispenser) | -int | [prize](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=prize) | -int | [forcefield](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=forcefield) | +int | [prize_dispenser](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=prize_dispenser) | entity uid +int | [prize](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=prize) | entity uid +int | [forcefield](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=forcefield) | entity uid bool | [bet_active](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=bet_active) | bool | [forcefield_deactivated](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=forcefield_deactivated) | -bool | [boss_angry](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=boss_angry) | -int | [result_announcement_timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=result_announcement_timer) | +int | [result_announcement_timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=result_announcement_timer) | the time the boss waits after your second die throw to announce the results int | [won_prizes_count](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=won_prizes_count) | -int | [balance](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=balance) | +int | [balance](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=balance) | cash balance of all the games + +### LogicGhostToast + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [toast_timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=toast_timer) | default 90 ### LogicList @@ -1324,10 +1411,61 @@ Used in [StateMemory](#StateMemory) Type | Name | Description ---- | ---- | ----------- +[LogicTutorial](#LogicTutorial) | [tutorial](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tutorial) | Handles dropping of the torch and rope in intro routine (first time play) +[LogicOuroboros](#LogicOuroboros) | [ouroboros](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ouroboros) | +[LogicBasecampSpeedrun](#LogicBasecampSpeedrun) | [basecamp_speedrun](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=basecamp_speedrun) | Keep track of time, player position passing official +[Logic](#Logic) | [ghost_trigger](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ghost_trigger) | It's absence is the only reason why ghost doesn't spawn at boss levels or CO +[LogicGhostToast](#LogicGhostToast) | [ghost_toast_trigger](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ghost_toast_trigger) | +[Logic](#Logic) | [tun_aggro](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tun_aggro) | Spawns tun at the door at 30s mark +[LogicDiceShop](#LogicDiceShop) | [diceshop](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=diceshop) | +[LogicTunPreChallenge](#LogicTunPreChallenge) | [tun_pre_challenge](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tun_pre_challenge) | +[LogicMoonChallenge](#LogicMoonChallenge) | [tun_moon_challenge](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tun_moon_challenge) | +[LogicStarChallenge](#LogicStarChallenge) | [tun_star_challenge](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tun_star_challenge) | +[LogicSunChallenge](#LogicSunChallenge) | [tun_sun_challenge](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tun_sun_challenge) | +[LogicMagmamanSpawn](#LogicMagmamanSpawn) | [magmaman_spawn](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=magmaman_spawn) | +[LogicUnderwaterBubbles](#LogicUnderwaterBubbles) | [water_bubbles](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=water_bubbles) | Only the bubbles that spawn from the floor
Even without it, entities moving in water still spawn bubbles [LogicOlmecCutscene](#LogicOlmecCutscene) | [olmec_cutscene](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=olmec_cutscene) | [LogicTiamatCutscene](#LogicTiamatCutscene) | [tiamat_cutscene](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tiamat_cutscene) | -LogicMagmamanSpawn | [magmaman_spawn](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=magmaman_spawn) | -[LogicDiceShop](#LogicDiceShop) | [diceshop](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=diceshop) | +[LogicApepTrigger](#LogicApepTrigger) | [apep_spawner](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=apep_spawner) | Triggers and spawns Apep only in rooms set as [ROOM_TEMPLATE](#ROOM_TEMPLATE).APEP +[LogicCOGAnkhSacrifice](#LogicCOGAnkhSacrifice) | [city_of_gold_ankh_sacrifice](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=city_of_gold_ankh_sacrifice) | All it does is it runs transition to Duat after time delay (sets the state next theme etc. and state.items for proper player respawn) +[Logic](#Logic) | [duat_bosses_spawner](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=duat_bosses_spawner) | +[LogicTiamatBubbles](#LogicTiamatBubbles) | [bubbler](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=bubbler) | Spawn rising bubbles at [Tiamat](#Tiamat) (position hardcoded) +[LogicTuskPleasurePalace](#LogicTuskPleasurePalace) | [tusk_pleasure_palace](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=tusk_pleasure_palace) | Triggers aggro on everyone when non-high roller enters door +[Logic](#Logic) | [discovery_info](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=discovery_info) | black market, vlad, wet fur discovery, logic shows the toast +[Logic](#Logic) | [black_market](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=black_market) | Changes the camera bounds when you reach black market +[Logic](#Logic) | [jellyfish_trigger](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=jellyfish_trigger) | +[LogicArena1](#LogicArena1) | [arena_1](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=arena_1) | Handles create spawns and more, is cleared as soon as the winner is decided (on last player alive) +[Logic](#Logic) | [arena_2](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=arena_2) | +[Logic](#Logic) | [arena_3](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=arena_3) | Handles time end death +[LogicArenaAlienBlast](#LogicArenaAlienBlast) | [arena_alien_blast](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=arena_alien_blast) | +[LogicArenaLooseBombs](#LogicArenaLooseBombs) | [arena_loose_bombs](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=arena_loose_bombs) | +[Logic](#Logic) | [start_logic(LOGIC idx)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=start_logic) | This only properly constructs the base class
you may still need to initialise the parameters correctly +nil | [stop_logic(LOGIC idx)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=stop_logic) | +nil | [stop_logic(Logic log)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=stop_logic) | + +### LogicMagmamanSpawn + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +custom_array<[MagmamanSpawnPosition](#MagmamanSpawnPosition)> | [magmaman_positions](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=magmaman_positions) | +nil | [add_spawn(int x, int y)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=add_spawn) | +nil | [add_spawn(MagmamanSpawnPosition ms)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=add_spawn) | +nil | [remove_spawn(int x, int y)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=remove_spawn) | +nil | [remove_spawn(MagmamanSpawnPosition ms)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=remove_spawn) | + +### LogicMoonChallenge + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) [LogicChallenge](#LogicChallenge) + + +Type | Name | Description +---- | ---- | ----------- +int | [mattock_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=mattock_uid) | entity uid ### LogicOlmecCutscene @@ -1337,11 +1475,54 @@ Derived from [Logic](#Logic) Type | Name | Description ---- | ---- | ----------- +[Entity](#Entity) | [fx_olmecpart_large](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=fx_olmecpart_large) | [Entity](#Entity) | [olmec](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=olmec) | [Entity](#Entity) | [player](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=player) | [Entity](#Entity) | [cinematic_anchor](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=cinematic_anchor) | int | [timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=timer) | +### LogicOuroboros + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +[SoundMeta](#SoundMeta) | [sound](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=sound) | +int | [timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=timer) | + +### LogicStarChallenge + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) [LogicChallenge](#LogicChallenge) + + +Type | Name | Description +---- | ---- | ----------- +array<[Entity](#Entity)> | [torches](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=torches) | +int | [start_countdown](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=start_countdown) | + +### LogicSunChallenge + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) [LogicChallenge](#LogicChallenge) + + +Type | Name | Description +---- | ---- | ----------- +int | [start_countdown](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=start_countdown) | + +### LogicTiamatBubbles + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [bubble_spawn_timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=bubble_spawn_timer) | + ### LogicTiamatCutscene Used in [LogicList](#LogicList) @@ -1355,14 +1536,35 @@ Type | Name | Description [Entity](#Entity) | [cinematic_anchor](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=cinematic_anchor) | int | [timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=timer) | -### LogicVolcana +### LogicTuskPleasurePalace +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +int | [locked_door](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=locked_door) | + +### LogicTutorial + +Used in [LogicList](#LogicList) +Derived from [Logic](#Logic) + + +Type | Name | Description +---- | ---- | ----------- +[Entity](#Entity) | [pet_tutorial](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=pet_tutorial) | +int | [timer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=timer) | + +### LogicUnderwaterBubbles + +Used in [LogicList](#LogicList) Derived from [Logic](#Logic) Type | Name | Description ---- | ---- | ----------- -custom_array<[MagmamanSpawnPosition](#MagmamanSpawnPosition)> | [magmaman_positions](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=magmaman_positions) | ## Online types diff --git a/src/game_api/entities_activefloors.cpp b/src/game_api/entities_activefloors.cpp index 145540261..d0db120c7 100644 --- a/src/game_api/entities_activefloors.cpp +++ b/src/game_api/entities_activefloors.cpp @@ -38,8 +38,6 @@ void Drill::trigger() move_state = 6; flags = flags & ~(1U << (10 - 1)); - using construct_soundposition_ptr_fun_t = SoundMeta*(uint32_t id, bool background_sound); - static const auto construct_soundposition_ptr_call = (construct_soundposition_ptr_fun_t*)get_address("construct_soundmeta"); - sound1 = construct_soundposition_ptr_call(0x159, 0); - sound2 = construct_soundposition_ptr_call(0x153, 0); + sound1 = construct_soundmeta(0x159, false); + sound2 = construct_soundmeta(0x153, false); } diff --git a/src/game_api/render_api.cpp b/src/game_api/render_api.cpp index 8ea4ed966..95b7aefd8 100644 --- a/src/game_api/render_api.cpp +++ b/src/game_api/render_api.cpp @@ -378,7 +378,7 @@ void on_open_journal_chapter(JournalUI* journal_ui, uint8_t chapter, bool instan { if (p.second) { - p.first->~JournalPage(); + delete p.first; } } } diff --git a/src/game_api/script/lua_vm.cpp b/src/game_api/script/lua_vm.cpp index a9f789d9b..7d53814cd 100644 --- a/src/game_api/script/lua_vm.cpp +++ b/src/game_api/script/lua_vm.cpp @@ -81,6 +81,7 @@ #include "usertypes/gui_lua.hpp" // for register_usertypes #include "usertypes/hitbox_lua.hpp" // for register_usertypes #include "usertypes/level_lua.hpp" // for register_usertypes +#include "usertypes/logic_lua.hpp" // for register_usertypes #include "usertypes/particles_lua.hpp" // for register_usertypes #include "usertypes/player_lua.hpp" // for register_usertypes #include "usertypes/prng_lua.hpp" // for register_usertypes @@ -291,6 +292,7 @@ end NBehavior::register_usertypes(lua); NSteam::register_usertypes(lua); NVTables::register_usertypes(lua); + NLogic::register_usertypes(lua); StateMemory* main_state = State::get().ptr_main(); diff --git a/src/game_api/script/usertypes/logic_lua.cpp b/src/game_api/script/usertypes/logic_lua.cpp new file mode 100644 index 000000000..d5fd293ef --- /dev/null +++ b/src/game_api/script/usertypes/logic_lua.cpp @@ -0,0 +1,410 @@ +#include "logic_lua.hpp" + +#include +#include // for data_t, global_table, state, proxy... +#include // for basic_usertype + +#include "entity.hpp" +#include "sound_manager.hpp" +#include "state.hpp" +#include "state_structs.hpp" + +namespace NLogic +{ +void register_usertypes(sol::state& lua) +{ + + auto stop_logic = sol::overload( + static_cast(&LogicList::stop_logic), + static_cast(&LogicList::stop_logic)); + + lua.create_named_table("LOGIC", // + "TUTORIAL", + LOGIC::TUTORIAL, + "OUROBOROS", + LOGIC::OUROBOROS, + "SPEEDRUN", + LOGIC::SPEEDRUN, + "GHOST", + LOGIC::GHOST, + "GHOST_TOAST", + LOGIC::GHOST_TOAST, + "TUN_AGGRO", + LOGIC::TUN_AGGRO, + "DICESHOP", + LOGIC::DICESHOP, + "PRE_CHALLENGE", + LOGIC::PRE_CHALLENGE, + "MOON_CHALLENGE", + LOGIC::MOON_CHALLENGE, + "STAR_CHALLENGE", + LOGIC::STAR_CHALLENGE, + "SUN_CHALLENGE", + LOGIC::SUN_CHALLENGE, + "MAGMAMAN_SPAWN", + LOGIC::MAGMAMAN_SPAWN, + "WATER_BUBBLES", + LOGIC::WATER_BUBBLES, + "OLMEC_CUTSCENE", + LOGIC::OLMEC_CUTSCENE, + "TIAMAT_CUTSCENE", + LOGIC::TIAMAT_CUTSCENE, + "APEP", + LOGIC::APEP, + "COG_SACRIFICE", + LOGIC::COG_SACRIFICE, + "DUAT_BOSSES", + LOGIC::DUAT_BOSSES, + "BUBBLER", + LOGIC::BUBBLER, + "PLEASURE_PALACE", + LOGIC::PLEASURE_PALACE, + "DISCOVERY_INFO", + LOGIC::DISCOVERY_INFO, + "BLACK_MARKET", + LOGIC::BLACK_MARKET, + "JELLYFISH", + LOGIC::JELLYFISH, + "ARENA_1", + LOGIC::ARENA_1, + "ARENA_2", + LOGIC::ARENA_2, + "ARENA_3", + LOGIC::ARENA_3, + "ARENA_ALIEN_BLAST", + LOGIC::ARENA_ALIEN_BLAST, + "ARENA_LOOSE_BOMBS", + LOGIC::ARENA_LOOSE_BOMBS); + + auto start_logic = [&lua](LogicList& l, LOGIC idx) -> sol::object + { + auto return_logic = l.start_logic(idx); + switch (idx) + { + case LOGIC::TUTORIAL: + return sol::make_object(lua, (LogicTutorial*)return_logic); + case LOGIC::OUROBOROS: + return sol::make_object(lua, (LogicOuroboros*)return_logic); + case LOGIC::SPEEDRUN: + return sol::make_object(lua, (LogicBasecampSpeedrun*)return_logic); + case LOGIC::GHOST_TOAST: + return sol::make_object(lua, (LogicGhostToast*)return_logic); + case LOGIC::DICESHOP: + return sol::make_object(lua, (LogicDiceShop*)return_logic); + case LOGIC::PRE_CHALLENGE: + return sol::make_object(lua, (LogicTunPreChallenge*)return_logic); + case LOGIC::MOON_CHALLENGE: + return sol::make_object(lua, (LogicMoonChallenge*)return_logic); + case LOGIC::STAR_CHALLENGE: + return sol::make_object(lua, (LogicStarChallenge*)return_logic); + case LOGIC::SUN_CHALLENGE: + return sol::make_object(lua, (LogicSunChallenge*)return_logic); + case LOGIC::MAGMAMAN_SPAWN: + return sol::make_object(lua, (LogicMagmamanSpawn*)return_logic); + case LOGIC::WATER_BUBBLES: + return sol::make_object(lua, (LogicUnderwaterBubbles*)return_logic); + case LOGIC::OLMEC_CUTSCENE: + return sol::make_object(lua, (LogicOlmecCutscene*)return_logic); + case LOGIC::TIAMAT_CUTSCENE: + return sol::make_object(lua, (LogicTiamatCutscene*)return_logic); + case LOGIC::APEP: + return sol::make_object(lua, (LogicApepTrigger*)return_logic); + case LOGIC::COG_SACRIFICE: + return sol::make_object(lua, (LogicCOGAnkhSacrifice*)return_logic); + case LOGIC::BUBBLER: + return sol::make_object(lua, (LogicTiamatBubbles*)return_logic); + case LOGIC::PLEASURE_PALACE: + return sol::make_object(lua, (LogicTuskPleasurePalace*)return_logic); + case LOGIC::ARENA_1: + return sol::make_object(lua, (LogicArena1*)return_logic); + // case LOGIC::ARENA_2: + // return sol::make_object(lua, () return_logic); + case LOGIC::ARENA_ALIEN_BLAST: + return sol::make_object(lua, (LogicArenaAlienBlast*)return_logic); + case LOGIC::ARENA_LOOSE_BOMBS: + return sol::make_object(lua, (LogicArenaLooseBombs*)return_logic); + default: + return sol::make_object(lua, return_logic); + } + }; + + /// Used in StateMemory + lua.new_usertype( + "LogicList", + "tutorial", + &LogicList::tutorial, + "ouroboros", + &LogicList::ouroboros, + "basecamp_speedrun", + &LogicList::basecamp_speedrun, + "ghost_trigger", + &LogicList::ghost_trigger, + "ghost_toast_trigger", + &LogicList::ghost_toast_trigger, + "tun_aggro", + &LogicList::tun_aggro, + "diceshop", + &LogicList::diceshop, + "tun_pre_challenge", + &LogicList::tun_pre_challenge, + "tun_moon_challenge", + &LogicList::tun_moon_challenge, + "tun_star_challenge", + &LogicList::tun_star_challenge, + "tun_sun_challenge", + &LogicList::tun_sun_challenge, + "magmaman_spawn", + &LogicList::magmaman_spawn, + "water_bubbles", + &LogicList::water_bubbles, + "olmec_cutscene", + &LogicList::olmec_cutscene, + "tiamat_cutscene", + &LogicList::tiamat_cutscene, + "apep_spawner", + &LogicList::apep_spawner, + "city_of_gold_ankh_sacrifice", + &LogicList::city_of_gold_ankh_sacrifice, + "duat_bosses_spawner", + &LogicList::duat_bosses_spawner, + "bubbler", + &LogicList::bubbler, + "tusk_pleasure_palace", + &LogicList::tusk_pleasure_palace, + "discovery_info", + &LogicList::discovery_info, + "black_market", + &LogicList::black_market, + "jellyfish_trigger", + &LogicList::jellyfish_trigger, + "arena_1", + &LogicList::arena_1, + "arena_2", + &LogicList::arena_2, + "arena_3", + &LogicList::arena_3, + "arena_alien_blast", + &LogicList::arena_alien_blast, + "arena_loose_bombs", + &LogicList::arena_loose_bombs, + "start_logic", + start_logic, + "stop_logic", + stop_logic); + /// Used in LogicList + lua.new_usertype( + "Logic", + "logic_index", + sol::readonly(&Logic::logic_index)); + /// Used in LogicList + lua.new_usertype( + "LogicTutorial", + "pet_tutorial", + &LogicTutorial::pet_tutorial, + "timer", + &LogicTutorial::timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicOuroboros", + "sound", + &LogicOuroboros::sound, + "timer", + &LogicOuroboros::timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicBasecampSpeedrun", + "administrator", + &LogicBasecampSpeedrun::administrator, + "crate", + &LogicBasecampSpeedrun::crate, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicGhostToast", + "toast_timer", + &LogicGhostToast::toast_timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + auto logicdiceshop_type = lua.new_usertype("LogicDiceShop", sol::base_classes, sol::bases()); + logicdiceshop_type["boss_uid"] = &LogicDiceShop::boss_uid; + logicdiceshop_type["boss_type"] = &LogicDiceShop::boss_type; + logicdiceshop_type["bet_machine"] = &LogicDiceShop::bet_machine; + logicdiceshop_type["die1"] = &LogicDiceShop::die1; + logicdiceshop_type["die2"] = &LogicDiceShop::die2; + logicdiceshop_type["die_1_value"] = &LogicDiceShop::die_1_value; + logicdiceshop_type["die_2_value"] = &LogicDiceShop::die_2_value; + logicdiceshop_type["prize_dispenser"] = &LogicDiceShop::prize_dispenser; + logicdiceshop_type["prize"] = &LogicDiceShop::prize; + logicdiceshop_type["forcefield"] = &LogicDiceShop::forcefield; + logicdiceshop_type["bet_active"] = &LogicDiceShop::bet_active; + logicdiceshop_type["forcefield_deactivated"] = &LogicDiceShop::forcefield_deactivated; + /// NoDoc + logicdiceshop_type["boss_angry"] = &LogicDiceShop::unknown; + logicdiceshop_type["result_announcement_timer"] = &LogicDiceShop::result_announcement_timer; + logicdiceshop_type["won_prizes_count"] = &LogicDiceShop::won_prizes_count; + logicdiceshop_type["balance"] = &LogicDiceShop::balance; + /// Used in LogicList + lua.new_usertype( + "LogicTunPreChallenge", + "tun_uid", + &LogicTunPreChallenge::tun_uid, + sol::base_classes, + sol::bases()); + /// Used in LogicMoonChallenge, LogicStarChallenge, LogicSunChallenge + lua.new_usertype( + "LogicChallenge", + "floor_challenge_entrance_uid", + &LogicChallenge::floor_challenge_entrance_uid, + "floor_challenge_waitroom_uid", + &LogicChallenge::floor_challenge_waitroom_uid, + "challenge_active", + &LogicChallenge::challenge_active, + "forcefield_countdown", + &LogicChallenge::forcefield_countdown, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicMoonChallenge", + "mattock_uid", + &LogicMoonChallenge::mattock_uid, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicStarChallenge", + "torches", + &LogicStarChallenge::torches, + "start_countdown", + &LogicStarChallenge::start_countdown, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicSunChallenge", + "start_countdown", + &LogicSunChallenge::start_countdown, + sol::base_classes, + sol::bases()); + auto add_spawn = sol::overload( + static_cast(&LogicMagmamanSpawn::add_spawn), + static_cast(&LogicMagmamanSpawn::add_spawn)); + auto remove_spawn = sol::overload( + static_cast(&LogicMagmamanSpawn::remove_spawn), + static_cast(&LogicMagmamanSpawn::remove_spawn)); + /// Used in LogicList + lua.new_usertype( + "LogicMagmamanSpawn", + "magmaman_positions", + &LogicMagmamanSpawn::magmaman_positions, + "add_spawn", + add_spawn, + "remove_spawn", + remove_spawn, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicUnderwaterBubbles", + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicOlmecCutscene", + "fx_olmecpart_large", + &LogicOlmecCutscene::fx_olmecpart_large, + "olmec", + &LogicOlmecCutscene::olmec, + "player", + &LogicOlmecCutscene::player, + "cinematic_anchor", + &LogicOlmecCutscene::cinematic_anchor, + "timer", + &LogicOlmecCutscene::timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicTiamatCutscene", + "tiamat", + &LogicTiamatCutscene::tiamat, + "player", + &LogicTiamatCutscene::player, + "cinematic_anchor", + &LogicTiamatCutscene::cinematic_anchor, + "timer", + &LogicTiamatCutscene::timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicApepTrigger", + "spawn_cooldown", + &LogicApepTrigger::spawn_cooldown, + "cooling_down", + &LogicApepTrigger::cooling_down, + "apep_journal_entry_logged", + &LogicApepTrigger::apep_journal_entry_logged, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicCOGAnkhSacrifice", + "timer", + &LogicCOGAnkhSacrifice::timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicTiamatBubbles", + "bubble_spawn_timer", + &LogicTiamatBubbles::bubble_spawn_timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicTuskPleasurePalace", + "locked_door", + &LogicTuskPleasurePalace::locked_door, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicArena1", + "crate_spawn_timer", + &LogicArena1::crate_spawn_timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicArenaAlienBlast", + "timer", + &LogicArenaAlienBlast::timer, + sol::base_classes, + sol::bases()); + /// Used in LogicList + lua.new_usertype( + "LogicArenaLooseBombs", + "timer", + &LogicArenaLooseBombs::timer, + sol::base_classes, + sol::bases()); + + /// Used in LogicMagmamanSpawn + lua.new_usertype( + "MagmamanSpawnPosition", + sol::constructors{}, + "x", + &MagmamanSpawnPosition::x, + "y", + &MagmamanSpawnPosition::y, + "timer", + &MagmamanSpawnPosition::timer); +} +} // namespace NLogic diff --git a/src/game_api/script/usertypes/logic_lua.hpp b/src/game_api/script/usertypes/logic_lua.hpp new file mode 100644 index 000000000..ea4308ac2 --- /dev/null +++ b/src/game_api/script/usertypes/logic_lua.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace sol +{ +class state; +} // namespace sol + +namespace NLogic +{ +void register_usertypes(sol::state& lua); +}; diff --git a/src/game_api/script/usertypes/state_lua.cpp b/src/game_api/script/usertypes/state_lua.cpp index e4f65b7b9..0e770ea02 100644 --- a/src/game_api/script/usertypes/state_lua.cpp +++ b/src/game_api/script/usertypes/state_lua.cpp @@ -497,81 +497,6 @@ void register_usertypes(sol::state& lua) }), "get_code", &OnlineLobby::get_code); - /// Used in StateMemory - lua.new_usertype( - "LogicList", - "olmec_cutscene", - &LogicList::olmec_cutscene, - "tiamat_cutscene", - &LogicList::tiamat_cutscene, - "magmaman_spawn", - &LogicList::magmaman_spawn, - "diceshop", - &LogicList::diceshop); - /// Used in LogicList - lua.new_usertype( - "Logic", - "logic_index", - &Logic::logic_index); - /// Used in LogicList - lua.new_usertype( - "LogicOlmecCutscene", - "olmec", - &LogicOlmecCutscene::olmec, - "player", - &LogicOlmecCutscene::player, - "cinematic_anchor", - &LogicOlmecCutscene::cinematic_anchor, - "timer", - &LogicOlmecCutscene::timer, - sol::base_classes, - sol::bases()); - /// Used in LogicList - lua.new_usertype( - "LogicTiamatCutscene", - "tiamat", - &LogicTiamatCutscene::tiamat, - "player", - &LogicTiamatCutscene::player, - "cinematic_anchor", - &LogicTiamatCutscene::cinematic_anchor, - "timer", - &LogicTiamatCutscene::timer, - sol::base_classes, - sol::bases()); - /// Used in LogicList - lua.new_usertype( - "MagmamanSpawnPosition", - sol::constructors{}, - "x", - &MagmamanSpawnPosition::x, - "y", - &MagmamanSpawnPosition::y, - "timer", - &MagmamanSpawnPosition::timer); - lua.new_usertype( - "LogicVolcana", - "magmaman_positions", - &LogicMagmamanSpawn::magmaman_positions, - sol::base_classes, - sol::bases()); - - /// Used in LogicList - auto logicdiceshop_type = lua.new_usertype("LogicDiceShop", sol::base_classes, sol::bases()); - logicdiceshop_type["bet_machine"] = &LogicDiceShop::bet_machine; - logicdiceshop_type["die1"] = &LogicDiceShop::die1; - logicdiceshop_type["die2"] = &LogicDiceShop::die2; - logicdiceshop_type["die_1_value"] = &LogicDiceShop::die_1_value; - logicdiceshop_type["die_2_value"] = &LogicDiceShop::die_2_value; - logicdiceshop_type["prize_dispenser"] = &LogicDiceShop::prize_dispenser; - logicdiceshop_type["prize"] = &LogicDiceShop::prize; - logicdiceshop_type["forcefield"] = &LogicDiceShop::forcefield; - logicdiceshop_type["bet_active"] = &LogicDiceShop::bet_active; - logicdiceshop_type["forcefield_deactivated"] = &LogicDiceShop::forcefield_deactivated; - logicdiceshop_type["boss_angry"] = &LogicDiceShop::boss_angry; - logicdiceshop_type["result_announcement_timer"] = &LogicDiceShop::result_announcement_timer; - logicdiceshop_type["won_prizes_count"] = &LogicDiceShop::won_prizes_count; - logicdiceshop_type["balance"] = &LogicDiceShop::balance; /// Used in StateMemory lua.new_usertype("RoomOwnersInfo", "owned_items", &RoomOwnersInfo::owned_items, "owned_rooms", &RoomOwnersInfo::owned_rooms); diff --git a/src/game_api/sound_manager.cpp b/src/game_api/sound_manager.cpp index 75bfd3991..33c23252b 100644 --- a/src/game_api/sound_manager.cpp +++ b/src/game_api/sound_manager.cpp @@ -914,3 +914,15 @@ SoundMeta* play_sound(VANILLA_SOUND sound, uint32_t source_uid) } return sound_info; } + +SoundMeta* construct_soundmeta(VANILLA_SOUND sound, bool background_sound) +{ + return construct_soundmeta(sound_name_to_id(sound), background_sound); +} + +SoundMeta* construct_soundmeta(uint32_t sound_id, bool background_sound) +{ + using construct_soundposition_ptr_fun_t = SoundMeta*(uint32_t id, bool background_sound); + static const auto construct_soundposition_ptr_call = (construct_soundposition_ptr_fun_t*)get_address("construct_soundmeta"); + return construct_soundposition_ptr_call(sound_id, background_sound); +} diff --git a/src/game_api/sound_manager.hpp b/src/game_api/sound_manager.hpp index e1e41d137..14e5de664 100644 --- a/src/game_api/sound_manager.hpp +++ b/src/game_api/sound_manager.hpp @@ -294,3 +294,8 @@ struct BackgroundSound : public SoundMeta /// Use source_uid to make the sound be played at the location of that entity, set it -1 to just play it "everywhere" /// Returns SoundMeta (read only), beware that after the sound starts, that memory is no longer valid SoundMeta* play_sound(VANILLA_SOUND sound, uint32_t source_uid); + +// could probably be exposed if someone can actually figure out how to properly "register it"? +// it also needs to make sure the lua owns the returned object and it will properly delete it +SoundMeta* construct_soundmeta(VANILLA_SOUND sound, bool background_sound); +SoundMeta* construct_soundmeta(uint32_t sound_id, bool background_sound); diff --git a/src/game_api/state.cpp b/src/game_api/state.cpp index 7a4dd4dc6..466730bde 100644 --- a/src/game_api/state.cpp +++ b/src/game_api/state.cpp @@ -9,6 +9,7 @@ #include // for allocator, operator""sv, operator""s #include // for move +#include "containers/custom_allocator.hpp" // #include "entities_chars.hpp" // for Player #include "entity.hpp" // for to_id, Entity, HookWithId, EntityDB #include "entity_hooks_info.hpp" // for Player @@ -26,6 +27,7 @@ #include "script/lua_vm.hpp" // for get_lua_vm #include "script/usertypes/theme_vtable_lua.hpp" // for NThemeVTables #include "search.hpp" // for get_address +#include "sound_manager.hpp" // #include "spawn_api.hpp" // for init_spawn_hooks #include "steam_api.hpp" // for init_achievement_hooks #include "strings.hpp" // for strings_init @@ -725,3 +727,249 @@ uint8_t enum_to_layer(const LAYER layer) } return 0; } + +Logic* LogicList::start_logic(LOGIC idx) +{ + if ((uint32_t)idx > 27 || logic_indexed[(uint32_t)idx] != nullptr) + return nullptr; + + int size = 0; + VTABLE_OFFSET offset = VTABLE_OFFSET::NONE; + switch (idx) + { + case LOGIC::GHOST: + { + offset = VTABLE_OFFSET::LOGIC_GHOST_TRIGGER; + size = sizeof(Logic); + break; + } + case LOGIC::TUN_AGGRO: + { + offset = VTABLE_OFFSET::LOGIC_TUN_AGGRO; + size = sizeof(Logic); + break; + } + case LOGIC::DUAT_BOSSES: + { + offset = VTABLE_OFFSET::LOGIC_DUAT_BOSSES_TRIGGER; + size = sizeof(Logic); + break; + } + case LOGIC::DISCOVERY_INFO: + { + offset = VTABLE_OFFSET::LOGIC_DISCOVERY_INFO; + size = sizeof(Logic); + break; + } + case LOGIC::BLACK_MARKET: + { + offset = VTABLE_OFFSET::LOGIC_BLACK_MARKET; + size = sizeof(Logic); + break; + } + case LOGIC::JELLYFISH: + { + offset = VTABLE_OFFSET::LOGIC_COSMIC_OCEAN; + size = sizeof(Logic); + break; + } + case LOGIC::ARENA_3: + { + offset = VTABLE_OFFSET::LOGIC_ARENA_3; + size = sizeof(Logic); + break; + } + case LOGIC::SPEEDRUN: + { + offset = VTABLE_OFFSET::LOGIC_BASECAMP_SPEEDRUN; + size = sizeof(LogicBasecampSpeedrun); + break; + } + case LOGIC::GHOST_TOAST: + { + offset = VTABLE_OFFSET::LOGIC_GHOST_TOAST_TRIGGER; + size = sizeof(LogicGhostToast); + break; + } + case LOGIC::WATER_BUBBLES: + { + offset = VTABLE_OFFSET::LOGIC_WATER_RELATED; + size = sizeof(LogicUnderwaterBubbles); + break; + } + case LOGIC::APEP: + { + offset = VTABLE_OFFSET::LOGIC_APEP_TRIGGER; + size = sizeof(LogicApepTrigger); + break; + } + case LOGIC::COG_SACRIFICE: + { + offset = VTABLE_OFFSET::LOGIC_CITY_OF_GOLD_ANKH_SACRIFICE; + size = sizeof(LogicCOGAnkhSacrifice); + break; + } + case LOGIC::BUBBLER: + { + offset = VTABLE_OFFSET::LOGIC_TIAMAT; + size = sizeof(LogicTiamatBubbles); + break; + } + case LOGIC::ARENA_1: + { + offset = VTABLE_OFFSET::LOGIC_ARENA_1; + size = sizeof(LogicArena1); + break; + } + case LOGIC::ARENA_ALIEN_BLAST: + { + offset = VTABLE_OFFSET::LOGIC_ARENA_ALIEN_BLAST; + size = sizeof(LogicArenaAlienBlast); + break; + } + case LOGIC::ARENA_LOOSE_BOMBS: + { + offset = VTABLE_OFFSET::LOGIC_ARENA_LOOSE_BOMBS; + size = sizeof(LogicArenaLooseBombs); + break; + } + case LOGIC::TUTORIAL: + { + offset = VTABLE_OFFSET::LOGIC_TUTORIAL; + size = sizeof(LogicTutorial); + break; + } + case LOGIC::OUROBOROS: + { + offset = VTABLE_OFFSET::LOGIC_OUROBOROS; + size = sizeof(LogicOuroboros); + break; + } + case LOGIC::PLEASURE_PALACE: + { + offset = VTABLE_OFFSET::LOGIC_TUSK_PLEASURE_PALACE; + size = sizeof(LogicTuskPleasurePalace); + break; + } + case LOGIC::MAGMAMAN_SPAWN: + { + offset = VTABLE_OFFSET::LOGIC_VOLCANA_RELATED; + size = sizeof(LogicMagmamanSpawn); + break; + } + case LOGIC::PRE_CHALLENGE: + { + offset = VTABLE_OFFSET::LOGIC_TUN_PRE_CHALLENGE; + size = sizeof(LogicTunPreChallenge); + break; + } + case LOGIC::MOON_CHALLENGE: + { + offset = VTABLE_OFFSET::LOGIC_TUN_MOON_CHALLENGE; + size = sizeof(LogicMoonChallenge); + break; + } + case LOGIC::SUN_CHALLENGE: + { + offset = VTABLE_OFFSET::LOGIC_TUN_SUN_CHALLENGE; + size = sizeof(LogicSunChallenge); + break; + } + case LOGIC::TIAMAT_CUTSCENE: + { + offset = VTABLE_OFFSET::LOGIC_TIAMAT_CUTSCENE; + size = sizeof(LogicTiamatCutscene); + break; + } + case LOGIC::DICESHOP: + { + offset = VTABLE_OFFSET::LOGIC_DICESHOP; + size = sizeof(LogicDiceShop); + break; + } + case LOGIC::OLMEC_CUTSCENE: + { + offset = VTABLE_OFFSET::LOGIC_OLMEC_CUTSCENE; + size = sizeof(LogicOlmecCutscene); + break; + } + case LOGIC::STAR_CHALLENGE: + { + offset = VTABLE_OFFSET::LOGIC_TUN_STAR_CHALLENGE; + size = sizeof(LogicStarChallenge); + break; + } + case LOGIC::ARENA_2: + // offset = VTABLE_OFFSET::LOGIC_ARENA_2; + // size = ?; + default: + return nullptr; + } + static auto first_table_entry = get_address("virtual_functions_table"); + + auto addr = (size_t*)custom_malloc(size); + std::memset(addr, 0, size); // just in case + + *addr = first_table_entry + (size_t)offset * 8; // set up vtable + Logic* new_logic = (Logic*)addr; + new_logic->logic_index = idx; + + // set up logic that is not possible to initialize thru the API + if (idx == LOGIC::WATER_BUBBLES) + { + auto proper_type = (LogicUnderwaterBubbles*)new_logic; + proper_type->unknown1 = 1.0f; + proper_type->unknown2 = 1000; + proper_type->unknown3 = true; + } + else if (idx == LOGIC::OUROBOROS) + { + auto proper_type = (LogicOuroboros*)new_logic; + proper_type->sound = construct_soundmeta(0x51, false); + // proper_type->sound->start(); // it needs something more + // game stores the pointer in a special temp memory or something + } + else if (idx == LOGIC::PLEASURE_PALACE) + { + auto proper_type = (LogicTuskPleasurePalace*)new_logic; + proper_type->unknown4 = 1552; // magic? + } + + logic_indexed[(uint32_t)idx] = new_logic; + return new_logic; +} + +void LogicList::stop_logic(LOGIC idx) +{ + if ((uint32_t)idx > 27 || logic_indexed[(uint32_t)idx] == nullptr) + return; + + delete logic_indexed[(uint32_t)idx]; + logic_indexed[(uint32_t)idx] = nullptr; +} + +void LogicList::stop_logic(Logic* log) +{ + if (log == nullptr) + return; + + auto idx = log->logic_index; + delete log; + logic_indexed[(uint32_t)idx] = nullptr; +} + +void LogicMagmamanSpawn::add_spawn(uint32_t x, uint32_t y) +{ + magmaman_positions.emplace_back(x, y); +} + +void LogicMagmamanSpawn::remove_spawn(uint32_t x, uint32_t y) +{ + for (auto it = magmaman_positions.begin(); it < magmaman_positions.end(); ++it) + { + if (it->x == x && it->y == y) + { + magmaman_positions.erase(it); + } + } +} diff --git a/src/game_api/state_structs.hpp b/src/game_api/state_structs.hpp index ab315298b..e913ddb32 100644 --- a/src/game_api/state_structs.hpp +++ b/src/game_api/state_structs.hpp @@ -10,6 +10,7 @@ #include class Entity; +struct SoundMeta; struct RobinHoodTableEntry { @@ -388,99 +389,106 @@ struct ArenaState bool punish_ball; }; +enum class LOGIC : uint32_t +{ + TUTORIAL = 0, + OUROBOROS, + SPEEDRUN, + GHOST, + GHOST_TOAST, + TUN_AGGRO, + DICESHOP, + PRE_CHALLENGE, + MOON_CHALLENGE, + STAR_CHALLENGE, + SUN_CHALLENGE, + MAGMAMAN_SPAWN, + WATER_BUBBLES, + OLMEC_CUTSCENE, + TIAMAT_CUTSCENE, + APEP, + COG_SACRIFICE, + DUAT_BOSSES, + BUBBLER, + PLEASURE_PALACE, + DISCOVERY_INFO, + BLACK_MARKET, + JELLYFISH, + ARENA_1, + ARENA_2, + ARENA_3, + ARENA_ALIEN_BLAST, + ARENA_LOOSE_BOMBS, +}; + class Logic { public: - uint32_t logic_index; // array index into state.logic, where this instance resides - uint32_t padding; + LOGIC logic_index; + uint32_t unused_padding; virtual ~Logic() = 0; // Continuously performs the main functionality of the logic instance - // Tutorial: handles dropping of the torch and rope in intro routine - // Ouroboros: transitions to level when music finished - // Basecamp speedrun: keep track of time, player position passing official - // Ghost trigger: spawns ghost when time is up (checks cursed for earlier ghost) - // Ghost toast trigger: shows the 'A terrible chill...' toast after 90 frames - // Tun aggro: spawns Tun after 30 seconds - // Dice shop: runs the logic of the dice shop - // Tun pre challenge: unknown - // Moon challenge: handles waitroom forcefields + tracks mattock breakage - // Star challenge: handles waitroom forcefields + tracks torches/timer - // Sun challenge: handles waitroom forcefields + tracks timer - // Volcana/Lava: spawns magmamen at random (and does other things) - // Water: unknown - // Olmec cutscene: runs the cutscene - // Tiamat cutscene: runs the cutscene - // Apep trigger: tracks player position, spawns APEP_HEAD - // COG Ankh sacrifice: countdown timer (100 frames) from the moment you die, triggers transitioning to duat - // Duat bosses trigger: tracks player position, spawns ANUBIS2 and OSIRIS_HEAD - // Tiamat: spawns bubbles - // Tusk pleasure palace: triggers aggro on everyone when non-high roller enters door - // Discovery: shows the toast - // Black market: lifts camera bounds restrictions - // Cosmic ocean: spawns jelly when time is up - // Arena 1: handles crate spawning - // Arena 3: handles death mist - virtual void perform() = 0; + // If it returns false, game will call deconstructor next in most cases + virtual bool perform() = 0; }; class LogicOuroboros : public Logic { public: - size_t unknown3; // sound related? - uint16_t timer; - - virtual ~LogicOuroboros() = 0; + SoundMeta* sound; + uint32_t timer; }; class LogicBasecampSpeedrun : public Logic { public: - uint32_t official; // entity uid of the character that keeps the time - uint32_t crate; // entity uid; you must break this crate for the run to be valid, otherwise you're cheating - uint32_t unknown3; - uint32_t unknown4; - - virtual ~LogicBasecampSpeedrun() = 0; + /// entity uid of the character that keeps the time + uint32_t administrator; + /// entity uid. you must break this crate for the run to be valid, otherwise you're cheating + uint32_t crate; }; class LogicGhostToast : public Logic { public: + /// default 90 uint32_t toast_timer; - - virtual ~LogicGhostToast() = 0; }; class LogicDiceShop : public Logic { public: - uint32_t boss; // entity uid; either tusk or the shopkeeper - uint32_t unknown4; - uint32_t bet_machine; // entity uid - uint32_t die1; // entity uid - uint32_t die2; // entity uid + uint32_t boss_uid; + ENT_TYPE boss_type; + /// entity uid + uint32_t bet_machine; + /// entity uid + uint32_t die1; + /// entity uid + uint32_t die2; int8_t die_1_value; int8_t die_2_value; uint16_t unknown8; - uint32_t prize_dispenser; // entity uid - uint32_t prize; // entity uid - uint32_t forcefield; // entity uid + /// entity uid + uint32_t prize_dispenser; + /// entity uid + uint32_t prize; + /// entity uid + uint32_t forcefield; bool bet_active; bool forcefield_deactivated; - bool boss_angry; - uint8_t result_announcement_timer; // the time the boss waits after your second die throw to announce the results - uint8_t won_prizes_count; // to see whether you achieved high roller status - uint8_t unknown14; - uint8_t unknown15; - uint8_t unknown16; - int32_t balance; // cash balance of all the games - - virtual ~LogicDiceShop() = 0; + bool unknown; + /// the time the boss waits after your second die throw to announce the results + uint8_t result_announcement_timer; + uint8_t won_prizes_count; + uint8_t padding[3]; + /// cash balance of all the games + int32_t balance; }; -class LogicMoonChallenge : public Logic +class LogicChallenge : public Logic { public: uint32_t unknown3; @@ -489,45 +497,36 @@ class LogicMoonChallenge : public Logic uint32_t floor_challenge_waitroom_uid; bool challenge_active; uint8_t forcefield_countdown; // waiting area forcefield activation timer (the one that locks you in) - uint16_t unknown7; - uint16_t unknown8a; - uint16_t unknown8b; - uint32_t mattock; // entity uid - - virtual ~LogicMoonChallenge() = 0; + uint16_t padding1; + uint32_t padding2; }; -class LogicStarChallenge : public Logic +class LogicMoonChallenge : public LogicChallenge { public: - uint32_t unknown3; - uint32_t unknown4; - uint32_t floor_challenge_entrance_uid; - uint32_t floor_challenge_waitroom_uid; - bool challenge_active; - uint8_t forcefield_countdown; // waiting area forcefield activation timer (the one that locks you in) - uint16_t unknown7; - uint32_t unknown8; - std::vector torches; - uint32_t start_countdown; - - virtual ~LogicStarChallenge() = 0; + /// entity uid + int32_t mattock_uid; }; -class LogicSunChallenge : public Logic +class LogicStarChallenge : public LogicChallenge { public: - uint32_t unknown3; - uint32_t unknown4; - uint32_t floor_challenge_entrance_uid; - uint32_t floor_challenge_waitroom_uid; - bool challenge_active; - uint8_t forcefield_countdown; // waiting area forcefield activation timer (the one that locks you in) - uint16_t unknown7; - uint32_t unknown8; + std::vector torches; // TODO: check if custom vector (probably yes) uint8_t start_countdown; + uint8_t padding[3]; + uint32_t unknown9; + float unknown10; // position in front of tun and one tile higher, dunno what for? + float unknown11; // kind of would make sense for the wanted poster, but you get this struct after you buy the challenge, not possible when tun is angry? +}; - virtual ~LogicSunChallenge() = 0; +class LogicSunChallenge : public LogicChallenge +{ + public: + uint8_t start_countdown; + uint8_t padding[3]; + uint32_t unknown9; + float unknown10; // same as for LogicStarChallenge + float unknown11; }; class MagmamanSpawnPosition @@ -544,42 +543,44 @@ class LogicMagmamanSpawn : public Logic { public: custom_vector magmaman_positions; + + void add_spawn(uint32_t x, uint32_t y); + void add_spawn(MagmamanSpawnPosition ms) + { + add_spawn(ms.x, ms.y); + }; + void remove_spawn(uint32_t x, uint32_t y); + void remove_spawn(MagmamanSpawnPosition ms) + { + remove_spawn(ms.x, ms.y); + }; }; class LogicOlmecCutscene : public Logic { public: - uint8_t unknown6a; - uint8_t unknown6b; - uint8_t unknown6c; - uint8_t unknown6d; - uint8_t unknown7a; - uint8_t unknown7b; - uint8_t unknown7c; - uint8_t unknown7d; + /// Copied over [buttons_gameplay](#PlayerSlot) from the leader, used to skip the cutscene + /// You can skip the cutscene if you set it to 1 or 4 + uint8_t leader_inputs; + uint8_t padding[7]; Entity* fx_olmecpart_large; Entity* olmec; Entity* player; Entity* cinematic_anchor; uint32_t timer; - - virtual ~LogicOlmecCutscene() = 0; }; class LogicTiamatCutscene : public Logic { public: - uint32_t unknown3; - uint32_t unknown4; + /// Copied over [buttons_gameplay](#PlayerSlot) from the leader, used to skip the cutscene + /// You can skip the cutscene if you set it to 1 or 4 + uint8_t leader_inputs; + uint8_t padding[7]; Entity* tiamat; Entity* player; Entity* cinematic_anchor; uint32_t timer; - int32_t unknown5; - uint32_t unknown6; - uint32_t unknown7; - - virtual ~LogicTiamatCutscene() = 0; }; class LogicApepTrigger : public Logic @@ -588,102 +589,135 @@ class LogicApepTrigger : public Logic uint32_t spawn_cooldown; bool cooling_down; bool apep_journal_entry_logged; - uint32_t unknown4c; - uint32_t unknown4d; - uint32_t unknown5; - uint32_t unknown6; - - virtual ~LogicApepTrigger() = 0; }; class LogicCOGAnkhSacrifice : public Logic { + public: uint8_t unknown3; uint8_t timer; - - virtual ~LogicCOGAnkhSacrifice() = 0; -}; - -class LogicDuatBossesTrigger : public Logic -{ - public: - virtual ~LogicDuatBossesTrigger() = 0; }; class LogicTiamatBubbles : public Logic { public: uint8_t bubble_spawn_timer; - - virtual ~LogicTiamatBubbles() = 0; }; class LogicTuskPleasurePalace : public Logic { public: - uint32_t locked_door; // entity uid - uint32_t unknown4; - - virtual ~LogicTuskPleasurePalace() = 0; + int32_t locked_door; // entity uid + uint32_t unknown4; // default 1552 + uint32_t unknown5; // dunno + uint32_t unknown6; // padding probably }; class LogicArena1 : public Logic { public: uint32_t crate_spawn_timer; - uint32_t unknown4; - uint32_t unknown5; - uint32_t unknown6; - - virtual ~LogicArena1() = 0; }; class LogicArenaAlienBlast : public Logic { public: uint32_t timer; - - virtual ~LogicArenaAlienBlast() = 0; }; class LogicArenaLooseBombs : public Logic { public: uint32_t timer; +}; + +class LogicUnderwaterBubbles : public Logic +{ + public: + // no idea what does are, messing with them can crash + float unknown1; // default: 1.0, excludes liquid from spawning the bubbles by y level from the top to bottom + // is treated like number (calculations to get the right grid entity level) + // it's more like a value in rooms than y coordinates + + int16_t unknown2; // default: 1000 + bool unknown3; // default: 1 or 0 +}; + +class LogicTunPreChallenge : public Logic +{ + public: + // except for Tun the rest of the values do not make any sense (garbage) + // the logic.perform does only ever touches the tun as well, first one always 0? + size_t unknown1; + size_t unknown2; + size_t unknown3; + int32_t tun_uid; +}; - virtual ~LogicArenaLooseBombs() = 0; +class LogicTutorial : public Logic +{ + public: + Entity* pet_tutorial; + uint32_t timer; }; struct LogicList { - Logic* tutorial; - LogicOuroboros* ouroboros; - LogicBasecampSpeedrun* basecamp_speedrun; - Logic* ghost_trigger; - LogicGhostToast* ghost_toast_trigger; - Logic* tun_aggro; - LogicDiceShop* diceshop; - Logic* tun_pre_challenge; - LogicMoonChallenge* tun_moon_challenge; - LogicStarChallenge* tun_star_challenge; - LogicSunChallenge* tun_sun_challenge; - LogicMagmamanSpawn* magmaman_spawn; - Logic* water_related; - LogicOlmecCutscene* olmec_cutscene; - LogicTiamatCutscene* tiamat_cutscene; - LogicApepTrigger* apep_trigger; - LogicCOGAnkhSacrifice* city_of_gold_ankh_sacrifice; - LogicDuatBossesTrigger* duat_bosses_trigger; - LogicTiamatBubbles* bubbler; - LogicTuskPleasurePalace* tusk_pleasure_palace; - Logic* discovery_info; // black market, vlad, wet fur discovery; shows the toast - Logic* black_market; - Logic* cosmic_ocean; - LogicArena1* arena_1; - Logic* arena_2; - Logic* arena_3; - LogicArenaAlienBlast* arena_alien_blast; - LogicArenaLooseBombs* arena_loose_bombs; + /// This only properly constructs the base class + /// you may still need to initialise the parameters correctly + Logic* start_logic(LOGIC idx); + void stop_logic(LOGIC idx); + void stop_logic(Logic* log); + + union + { + std::array logic_indexed; + struct + { + /// Handles dropping of the torch and rope in intro routine (first time play) + LogicTutorial* tutorial; + LogicOuroboros* ouroboros; + /// Keep track of time, player position passing official + LogicBasecampSpeedrun* basecamp_speedrun; + /// It's absence is the only reason why ghost doesn't spawn at boss levels or CO + Logic* ghost_trigger; // virtual does nothing, all the code elsewhere, the only purpose is to mark if ghost should spawn this level or not + LogicGhostToast* ghost_toast_trigger; + /// Spawns tun at the door at 30s mark + Logic* tun_aggro; + LogicDiceShop* diceshop; + LogicTunPreChallenge* tun_pre_challenge; + LogicMoonChallenge* tun_moon_challenge; + LogicStarChallenge* tun_star_challenge; + LogicSunChallenge* tun_sun_challenge; + LogicMagmamanSpawn* magmaman_spawn; + /// Only the bubbles that spawn from the floor + /// Even without it, entities moving in water still spawn bubbles + LogicUnderwaterBubbles* water_bubbles; + LogicOlmecCutscene* olmec_cutscene; + LogicTiamatCutscene* tiamat_cutscene; + /// Triggers and spawns Apep only in rooms set as ROOM_TEMPLATE.APEP + LogicApepTrigger* apep_spawner; + /// All it does is it runs transition to Duat after time delay (sets the state next theme etc. and state.items for proper player respawn) + LogicCOGAnkhSacrifice* city_of_gold_ankh_sacrifice; + Logic* duat_bosses_spawner; + /// Spawn rising bubbles at Tiamat (position hardcoded) + LogicTiamatBubbles* bubbler; + /// Triggers aggro on everyone when non-high roller enters door + LogicTuskPleasurePalace* tusk_pleasure_palace; // TODO: van helsing? + /// black market, vlad, wet fur discovery, logic shows the toast + Logic* discovery_info; + /// Changes the camera bounds when you reach black market + Logic* black_market; + Logic* jellyfish_trigger; // same as ghost_trigger + /// Handles create spawns and more, is cleared as soon as the winner is decided (on last player alive) + LogicArena1* arena_1; + Logic* arena_2; // can't trigger + /// Handles time end death + Logic* arena_3; + LogicArenaAlienBlast* arena_alien_blast; + LogicArenaLooseBombs* arena_loose_bombs; + }; + }; }; struct LiquidPhysicsEngine diff --git a/src/game_api/strings.cpp b/src/game_api/strings.cpp index 6e226c1fc..b2fd9e8e5 100644 --- a/src/game_api/strings.cpp +++ b/src/game_api/strings.cpp @@ -12,6 +12,7 @@ #include // for unordered_map, _Umap_traits... #include // for max, min, pair +#include "constants.hpp" // #include "containers/game_allocator.hpp" // for game_free, game_malloc #include "detours.h" // for DetourAttach, DetourTransac... #include "entity.hpp" // for get_type, Entity, EntityDB @@ -54,7 +55,7 @@ void OnNPCDialogue(size_t func, Entity* NPC, char16_t* buffer, int shoppie_sound { std::u16string str = pre_speach_bubble(NPC, buffer); char16_t* new_string = NULL; - if (str != u"~[:NO_RETURN:]#") + if (str != no_return_str) { if (str.empty()) { @@ -78,7 +79,7 @@ void OnToast(char16_t* buffer) { std::u16string str = pre_toast(buffer); char16_t* new_string = NULL; - if (str != u"~[:NO_RETURN:]#") + if (str != no_return_str) { if (str.empty()) { diff --git a/src/game_api/virtual_table.hpp b/src/game_api/virtual_table.hpp index 2739eaab3..6d611fae1 100644 --- a/src/game_api/virtual_table.hpp +++ b/src/game_api/virtual_table.hpp @@ -924,7 +924,7 @@ enum class VTABLE_OFFSET THEME_HUNDUN = 51582, THEME_BASECAMP = 51634, THEME_ARENA = 51686, - // LOGIC_TUTORIAL = UNKNOWN + LOGIC_TUTORIAL = 52047, LOGIC_OUROBOROS = 52035, LOGIC_BASECAMP_SPEEDRUN = 52039, LOGIC_GHOST_TRIGGER = 52013, diff --git a/src/injected/ui_util.cpp b/src/injected/ui_util.cpp index d74586c2f..3fcc543c7 100644 --- a/src/injected/ui_util.cpp +++ b/src/injected/ui_util.cpp @@ -612,7 +612,7 @@ void UI::safe_destroy(Entity* ent, bool unsafe, bool recurse) // if cutscene is still running, perform the last frame of cutscene before killing olmec state->logic->olmec_cutscene->timer = 809; state->logic->olmec_cutscene->perform(); - state->logic->olmec_cutscene->~LogicOlmecCutscene(); + delete state->logic->olmec_cutscene; state->logic->olmec_cutscene = nullptr; } destroy_entity_items(check);