diff --git a/docs/game_data/spel2.lua b/docs/game_data/spel2.lua index 0c13e7ec5..6e826d4d8 100644 --- a/docs/game_data/spel2.lua +++ b/docs/game_data/spel2.lua @@ -1969,6 +1969,7 @@ do ---@field logic LogicList @Level logic like dice game and cutscenes ---@field liquid LiquidPhysics ---@field next_entity_uid integer @Next entity spawned will have this uid + ---@field room_owners RoomOwnersInfo @Holds info about owned rooms and items (shops, challenge rooms, vault etc.) ---@class LightParams ---@field red number @@ -2069,6 +2070,19 @@ do ---@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[] + +---@class ItemOwnerDetails + ---@field owner_type ENT_TYPE + ---@field owner_uid integer + +---@class RoomOwnerDetails + ---@field layer integer + ---@field room_index integer + ---@field owner_uid integer + ---@class BackgroundMusic ---@field game_startup BackgroundSound ---@field main_backgroundtrack BackgroundSound @@ -4461,7 +4475,7 @@ function MovableBehavior:get_state_id() end ---@field spawn_y number ---@field spawn_room_x integer ---@field spawn_room_y integer - ---@field exit_doors Vec2[] + ---@field exit_doors custom_Array ---@field themes ThemeInfo[] @size: 18 ---@class PostRoomGenerationContext diff --git a/docs/index.html b/docs/index.html index fb35de00f..07ac14da2 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1663,6 +1663,9 @@
  • HudPlayer
  • +
  • + ItemOwnerDetails +
  • Letter
  • @@ -1678,6 +1681,12 @@
  • RenderInfo
  • +
  • + RoomOwnerDetails +
  • +
  • + RoomOwnersInfo +
  • ShortTileCodeDef
  • @@ -8732,6 +8741,27 @@

    HudPlayer

    +

    ItemOwnerDetails

    +

    Used in RoomOwnersInfo

    + + + + + + + + + + + + + + + + + + +
    TypeNameDescription
    ENT_TYPEowner_type
    intowner_uid

    Letter

    @@ -9109,6 +9139,53 @@

    RenderInfo

    Hooks after the virtual function.
    The callback signature is nil render(RenderInfo self, float float, VanillaRenderContext vanilla_render_context)
    +

    RoomOwnerDetails

    +

    Used in RoomOwnersInfo

    + + + + + + + + + + + + + + + + + + + + + + + +
    TypeNameDescription
    intlayer
    introom_index
    intowner_uid
    +

    RoomOwnersInfo

    +

    Used in StateMemory

    + + + + + + + + + + + + + + + + + + +
    TypeNameDescription
    custom_map<int, ItemOwnerDetails>owned_itemskey/index is the uid of an item
    array<RoomOwnerDetails>owned_rooms

    ShortTileCodeDef

    Used in get_short_tile_code, get_short_tile_code_definition and PostRoomGenerationContext

    @@ -10188,7 +10265,7 @@

    LevelGenSystem

    -array<Vec2> +custom_array<Vec2> exit_doors @@ -15475,6 +15552,11 @@

    StateMemory

    next_entity_uid Next entity spawned will have this uid + +RoomOwnersInfo +room_owners +Holds info about owned rooms and items (shops, challenge rooms, vault etc.) +

    Texture types

    TextRenderingInfo

    diff --git a/docs/light.html b/docs/light.html index 8b57b29c3..051158250 100644 --- a/docs/light.html +++ b/docs/light.html @@ -1663,6 +1663,9 @@
  • HudPlayer
  • +
  • + ItemOwnerDetails +
  • Letter
  • @@ -1678,6 +1681,12 @@
  • RenderInfo
  • +
  • + RoomOwnerDetails +
  • +
  • + RoomOwnersInfo +
  • ShortTileCodeDef
  • @@ -8732,6 +8741,27 @@

    HudPlayer

    +

    ItemOwnerDetails

    +

    Used in RoomOwnersInfo

    + + + + + + + + + + + + + + + + + + +
    TypeNameDescription
    ENT_TYPEowner_type
    intowner_uid

    Letter

    @@ -9109,6 +9139,53 @@

    RenderInfo

    Hooks after the virtual function.
    The callback signature is nil render(RenderInfo self, float float, VanillaRenderContext vanilla_render_context)
    +

    RoomOwnerDetails

    +

    Used in RoomOwnersInfo

    + + + + + + + + + + + + + + + + + + + + + + + +
    TypeNameDescription
    intlayer
    introom_index
    intowner_uid
    +

    RoomOwnersInfo

    +

    Used in StateMemory

    + + + + + + + + + + + + + + + + + + +
    TypeNameDescription
    custom_map<int, ItemOwnerDetails>owned_itemskey/index is the uid of an item
    array<RoomOwnerDetails>owned_rooms

    ShortTileCodeDef

    Used in get_short_tile_code, get_short_tile_code_definition and PostRoomGenerationContext

    @@ -10188,7 +10265,7 @@

    LevelGenSystem

    -array<Vec2> +custom_array<Vec2> exit_doors @@ -15475,6 +15552,11 @@

    StateMemory

    next_entity_uid Next entity spawned will have this uid + +RoomOwnersInfo +room_owners +Holds info about owned rooms and items (shops, challenge rooms, vault etc.) +

    Texture types

    TextRenderingInfo

    diff --git a/docs/src/includes/_types.md b/docs/src/includes/_types.md index 5f7880ca5..5d400f670 100644 --- a/docs/src/includes/_types.md +++ b/docs/src/includes/_types.md @@ -687,6 +687,15 @@ int | [health](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=health) int | [bombs](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=bombs) | int | [ropes](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ropes) | +### ItemOwnerDetails + +Used in [RoomOwnersInfo](#RoomOwnersInfo) + +Type | Name | Description +---- | ---- | ----------- +[ENT_TYPE](#ENT_TYPE) | [owner_type](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=owner_type) | +int | [owner_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=owner_uid) | + ### Letter @@ -799,6 +808,25 @@ nil | [clear_virtual(CallbackId callback_id)](https://github.com/spelunky-fyi/ov [CallbackId](#Aliases) | [set_pre_render(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_render) | Hooks before the virtual function.
    The callback signature is `bool render(RenderInfo self, float float, VanillaRenderContext vanilla_render_context)` [CallbackId](#Aliases) | [set_post_render(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_render) | Hooks after the virtual function.
    The callback signature is `nil render(RenderInfo self, float float, VanillaRenderContext vanilla_render_context)` +### RoomOwnerDetails + +Used in [RoomOwnersInfo](#RoomOwnersInfo) + +Type | Name | Description +---- | ---- | ----------- +int | [layer](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=layer) | +int | [room_index](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=room_index) | +int | [owner_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=owner_uid) | + +### RoomOwnersInfo + +Used in [StateMemory](#StateMemory) + +Type | Name | Description +---- | ---- | ----------- +custom_map<int, [ItemOwnerDetails](#ItemOwnerDetails)> | [owned_items](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=owned_items) | key/index is the uid of an item +array<[RoomOwnerDetails](#RoomOwnerDetails)> | [owned_rooms](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=owned_rooms) | + ### ShortTileCodeDef Used in [get_short_tile_code](#get_short_tile_code), [get_short_tile_code_definition](#get_short_tile_code_definition) and [PostRoomGenerationContext](#PostRoomGenerationContext) @@ -1158,7 +1186,7 @@ float | [spawn_x](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=spawn float | [spawn_y](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=spawn_y) | int | [spawn_room_x](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=spawn_room_x) | int | [spawn_room_y](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=spawn_room_y) | -array<[Vec2](#Vec2)> | [exit_doors](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=exit_doors) | +custom_array<[Vec2](#Vec2)> | [exit_doors](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=exit_doors) | [ThemeInfo](#ThemeInfo) | [themes[18]](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=themes) | ## Lighting types @@ -2630,6 +2658,7 @@ array<int, 9> | [journal_progress_theme_slots](https://github.com/spelunky [LogicList](#LogicList) | [logic](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=logic) | Level logic like dice game and cutscenes [LiquidPhysics](#LiquidPhysics) | [liquid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=liquid) | int | [next_entity_uid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=next_entity_uid) | Next entity spawned will have this uid +[RoomOwnersInfo](#RoomOwnersInfo) | [room_owners](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=room_owners) | Holds info about owned rooms and items (shops, challenge rooms, vault etc.) ## Texture types diff --git a/examples/randomizer2.lua b/examples/randomizer2.lua index 59ad6218c..2de78b799 100644 --- a/examples/randomizer2.lua +++ b/examples/randomizer2.lua @@ -427,8 +427,8 @@ local function spawn_boss(boss) duat_spawn_x = state.level_gen.spawn_x duat_spawn_y = state.level_gen.spawn_y - state.level_gen.spawn_x = 17 - state.level_gen.spawn_y = 106 + --state.level_gen.spawn_x = 17 + --state.level_gen.spawn_y = 106 if state.level_gen.spawn_y < 47 then return end local box = AABB:new() box.top = duat_spawn_y - 2 @@ -782,9 +782,16 @@ local function random_bosses(enable) boss_cbs[#boss_cbs + 1] = set_post_entity_spawn(function(e) e:set_post_update_state_machine(function(e) local box = get_hitbox(e.uid) - for _,v in pairs(get_entities_overlapping_hitbox({ENT_TYPE.ACTIVEFLOOR_BONEBLOCK, ENT_TYPE.ACTIVEFLOOR_REGENERATINGBLOCK}, MASK.ACTIVEFLOOR, box, e.layer)) do + for _, v in pairs(get_entities_overlapping_hitbox({ ENT_TYPE.ACTIVEFLOOR_BONEBLOCK, ENT_TYPE + .ACTIVEFLOOR_REGENERATINGBLOCK, ENT_TYPE.ACTIVEFLOOR_SLIDINGWALL }, MASK.ACTIVEFLOOR, box, e.layer)) do kill_entity(v, true) end + if #state.level_gen.exit_doors > 0 then + for _,_ in pairs(get_entities_overlapping_hitbox(ENT_TYPE.FLOOR_DOOR_ENTRANCE, MASK.FLOOR, box, e.layer)) do + state.level_gen.spawn_x = state.level_gen.exit_doors[1].x + state.level_gen.spawn_y = state.level_gen.exit_doors[1].y + end + end end) end, SPAWN_TYPE.ANY, MASK.ACTIVEFLOOR, ENT_TYPE.ACTIVEFLOOR_CRUSHING_ELEVATOR) @@ -2605,7 +2612,8 @@ end local function duat_door() if not options.door then return end -- spawn duat skip door - spawn_door(17, 106, 0, level_order[state.level_count+1].w, level_order[state.level_count+1].l, level_order[state.level_count+1].t) + spawn_door(17, 106, 0, level_order[state.level_count + 1].w, level_order[state.level_count + 1].l, level_order[state.level_count + 1].t) + state.level_gen.exit_doors[1] = Vec2:new(17, 106) spawn_entity(ENT_TYPE.BG_DOOR_BACK_LAYER, 17, 106, 0, 0, 0) end diff --git a/src/game_api/entities_fx.hpp b/src/game_api/entities_fx.hpp index 5c9db1258..8f629b1f0 100644 --- a/src/game_api/entities_fx.hpp +++ b/src/game_api/entities_fx.hpp @@ -216,7 +216,9 @@ class FxSpringtrapRing : public Movable class FxWitchdoctorHint : public Movable { public: - std::set unknown; // uid of the witchdoctor, why the map/set? + /// There can be only one Hint above the player, so it has list of witchdoctors + /// in case there are more then one attacking you the same time + std::set witchdoctor; }; class FxNecromancerANKH : public Movable diff --git a/src/game_api/entities_monsters.hpp b/src/game_api/entities_monsters.hpp index 595930cad..0b5653f7a 100644 --- a/src/game_api/entities_monsters.hpp +++ b/src/game_api/entities_monsters.hpp @@ -243,7 +243,7 @@ class Yang : public RoomOwner { public: /// Table of uid's of the turkeys, goes only up to 3, is nil when yang is angry - std::set turkeys_in_den; // probably a Map, but the second value is just 1 or 0, not really useful + std::set turkeys_in_den; uint8_t unknown4; uint8_t unknown5; /// I'm looking for turkeys, wanna help? diff --git a/src/game_api/layer.hpp b/src/game_api/layer.hpp index ddd0aee0f..8def12e0c 100644 --- a/src/game_api/layer.hpp +++ b/src/game_api/layer.hpp @@ -5,6 +5,7 @@ #include // for less #include // for map #include // for operator new +#include // #include // for find, pair #include // for allocator, vector @@ -117,6 +118,15 @@ struct EntityList } }; +struct EntityRegions +{ + EntityList** entity_lists; + // pointers to entities from entities_by_region array + + uint8_t size; + uint8_t cap; +}; + struct Layer { bool is_back_layer; @@ -125,14 +135,17 @@ struct Layer EntityList all_entities; // char + fx + mons + item + logical + mount + activefloor + BG (excluding BG_SHOP, BG_LEVEL_*) EntityList unknown_entities1; - size_t unknown1; - // key is the mask - std::map entities_by_mask; + EntityRegions* unknown1; // players in motion? + + std::map entities_by_mask; // key is the mask - EntityList entities_by_unknown[647]; // could be more, not sure what for, each holds like 1 entity for split second - char stuff0[0xB778]; // unknown, maybe more of the array above? + // 4x4 block areas (the edge ones extend to infinity?), each probably contains diffrent mask entities + EntityList entities_by_region1[31][21]; + EntityList entities_by_region2[31][21]; // Active floors ? + EntityList entities_by_region3[31][21]; + EntityList entities_by_region4[31][21]; - std::map unknown_map; // some movable and liquids and something else maybe?, key is uid + std::map entity_regions; // key is uid, all entities except FX, FLOOR, DECORATION, BG, SHADOW and LOGICAL Entity* grid_entities[g_level_max_y][g_level_max_x]; EntityList entities_overlaping_grid[g_level_max_y][g_level_max_x]; // static entities (like midbg, decorations) that overlap this grid position @@ -142,7 +155,7 @@ struct Layer EntityList unknown_entities3; // debris, explosions, laserbeams etc. ? EntityList unknown_entities4; // explosions, laserbeams, BG_LEVEL_*_SOOT ? only for short time while there are spawned? std::vector unknown_vector; // add_to_layer uses this - size_t unknown6; // MysteryLayerPointer1 in plugin + std::set* unknown6; // triggered by floor entity destruction? needs more testing // List of items that were destroyed and are waiting to have the dtor called // and then be returned to the entity pool EntityList expired_entities; diff --git a/src/game_api/level_api.hpp b/src/game_api/level_api.hpp index 8573182b1..cd6d900b3 100644 --- a/src/game_api/level_api.hpp +++ b/src/game_api/level_api.hpp @@ -13,6 +13,7 @@ #include // for vector #include "aliases.hpp" // for LAYER +#include "containers/custom_vector.hpp" // for custom_vector #include "containers/game_string.hpp" // for game_string #include "containers/game_unordered_map.hpp" // for game_unordered_map #include "containers/game_vector.hpp" // for game_vector @@ -485,7 +486,7 @@ struct LevelGenSystem float spawn_y; union { - std::vector exit_doors; + custom_vector exit_doors; struct { /// NoDoc diff --git a/src/game_api/rpc.cpp b/src/game_api/rpc.cpp index 56d6c6f09..0b53eda97 100644 --- a/src/game_api/rpc.cpp +++ b/src/game_api/rpc.cpp @@ -1675,13 +1675,6 @@ void move_grid_entity(int32_t uid, float x, float y, LAYER layer) void add_item_to_shop(int32_t item_uid, int32_t shop_owner_uid) { - struct dummy // dummy struct - { - std::set::iterator __omg; - int __wow; - }; - using AddRestrictedItemFun = size_t(std::set*, dummy, ShopRestrictedItem); - Movable* item = get_entity_ptr(item_uid)->as(); Entity* owner = get_entity_ptr(shop_owner_uid); if (item && owner && item->is_movable()) @@ -1699,21 +1692,14 @@ void add_item_to_shop(int32_t item_uid, int32_t shop_owner_uid) { if (owner->type->id == it) // TODO: check what happens if it's not room owner/shopkeeper { - static auto add_to_items_set = (AddRestrictedItemFun*)get_address("add_shopitem"); auto state = State::get(); item->flags = setflag(item->flags, 23); // shop item item->flags = setflag(item->flags, 20); // Enable button prompt (flag is problably: show dialogs and other fx) state.layer_local(item->layer)->spawn_entity_over(to_id("ENT_TYPE_FX_SALEICON"), item, 0, 0); state.layer_local(item->layer)->spawn_entity_over(to_id("ENT_TYPE_FX_SALEDIALOG_CONTAINER"), item, 0, 0.5); - // This function actually only takes iterator and value as argument, but for some reason they need to be passed thru stack - // This is probably some standard `insert` function, but the items is a strange one, i would guess it's a map (item uid as a key and array/struct as a value) - // but standard function, no matter if i set it to map or set, also adds something at the end of a bucket (key hash?), so it's either very similar container or some special setup for set/map - const auto bucket = add_to_items_set(&state.ptr()->shops.items, {state.ptr()->shops.items.end(), 0}, {item_uid, 0, 0}); - - auto the_struct = (ShopRestrictedItem*)(bucket + 0x1C); // 0x1C - is just the internal map/set stuff - the_struct->owner_uid = shop_owner_uid; - the_struct->owner_type = owner->type->id; + ItemOwnerDetails iod{shop_owner_uid, owner->type->id}; + state.ptr()->room_owners.owned_items.insert({item->uid, iod}); return; } } diff --git a/src/game_api/script/usertypes/state_lua.cpp b/src/game_api/script/usertypes/state_lua.cpp index b2cc8de25..eec0989a4 100644 --- a/src/game_api/script/usertypes/state_lua.cpp +++ b/src/game_api/script/usertypes/state_lua.cpp @@ -401,6 +401,7 @@ void register_usertypes(sol::state& lua) statememory_type["logic"] = &StateMemory::logic; statememory_type["liquid"] = &StateMemory::liquid_physics; statememory_type["next_entity_uid"] = &StateMemory::next_entity_uid; + statememory_type["room_owners"] = &StateMemory::room_owners; lua.create_named_table("QUEST_FLAG", "RESET", 1, "DARK_LEVEL_SPAWNED", 2, "VAULT_SPAWNED", 3, "SPAWN_OUTPOST", 4, "SHOP_SPAWNED", 5, "SHORTCUT_USED", 6, "SEEDED", 7, "DAILY", 8, "CAVEMAN_SHOPPIE_AGGROED", 9, "WADDLER_AGGROED", 10, "SHOP_BOUGHT_OUT", 11, "EGGPLANT_CROWN_PICKED_UP", 12, "UDJAT_EYE_SPAWNED", 17, "BLACK_MARKET_SPAWNED", 18, "DRILL_SPAWNED", 19, "MOON_CHALLENGE_SPAWNED", 25, "STAR_CHALLENGE_SPAWNED", 26, "SUN_CHALLENGE_SPAWNED", 27); @@ -554,6 +555,15 @@ void register_usertypes(sol::state& lua) 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); + + /// Used in RoomOwnersInfo + lua.new_usertype("ItemOwnerDetails", "owner_type", &ItemOwnerDetails::owner_type, "owner_uid", &ItemOwnerDetails::owner_uid); + + /// Used in RoomOwnersInfo + lua.new_usertype("RoomOwnerDetails", "layer", &RoomOwnerDetails::layer, "room_index", &RoomOwnerDetails::room_index, "owner_uid", &RoomOwnerDetails::owner_uid); + lua.create_named_table("CAUSE_OF_DEATH", "DEATH", 0, "ENTITY", 1, "LONG_FALL", 2, "STILL_FALLING", 3, "MISSED", 4, "POISONED", 5); lua["toast_visible"] = []() -> bool diff --git a/src/game_api/search.cpp b/src/game_api/search.cpp index cee662741..67b6a89c0 100644 --- a/src/game_api/search.cpp +++ b/src/game_api/search.cpp @@ -1727,15 +1727,6 @@ std::unordered_map g_address_rules{ .find_after_inst("\x41\x0F\xB6\x87\x17\x01\x00\x00\x83\xF8"sv) .at_exe(), }, - { - // Set write bp on State->shops->restricted_item_count, this structure is quite common so i chosen pattern before the call - "add_shopitem"sv, - PatternCommandBuffer{} - .find_after_inst("\x4C\x8D\x84\x24\xD0\x00\x00\x00\xE8"sv) - .offset(-0x1) - .decode_call() - .at_exe(), - }, { // Find a string "Basic systems initialized", right after it's usage (found via XREFS) // stuff gets emplaced to a map, it is this map diff --git a/src/game_api/state.hpp b/src/game_api/state.hpp index 9dddb4bef..aa5c4d2d6 100644 --- a/src/game_api/state.hpp +++ b/src/game_api/state.hpp @@ -265,7 +265,8 @@ struct StateMemory uint8_t unknown31a; // padding probably uint8_t unknown31b; uint8_t unknown31c; - ShopsInfo shops; + /// Holds info about owned rooms and items (shops, challenge rooms, vault etc.) + RoomOwnersInfo room_owners; /// Number of frames since the game was launched uint32_t time_startup; uint32_t special_visibility_flags; diff --git a/src/game_api/state_structs.hpp b/src/game_api/state_structs.hpp index f353dd99e..559448b64 100644 --- a/src/game_api/state_structs.hpp +++ b/src/game_api/state_structs.hpp @@ -1,12 +1,13 @@ #pragma once #include "aliases.hpp" +#include "containers/custom_map.hpp" #include "containers/custom_vector.hpp" #include "layer.hpp" #include "render_api.hpp" #include #include -#include +#include class Entity; @@ -841,13 +842,13 @@ struct LiquidPhysics LiquidTileSpawnData stagnant_lava_tile_spawn_data; }; }; - std::list* floors; // pointer to map/list that contains all floor uids that the liquid interact with - std::list* push_blocks; // pointer to map/list that contains all activefloor uids that the liquid interact with - custom_vector impostor_lakes; // - uint32_t total_liquid_spawned; // Total number of spawned liquid entities, all types. - uint32_t unknown8; // padding probably - uint8_t* unknown9; // array byte* ? game allocates 0x2F9E8 bytes for it, (0x2F9E8 / g_level_max_x * g_level_max_y = 18) which is weird, but i still think it's position based index, maybe it's 16 and accounts for more rows (grater level height) - // always allocates after the LiquidPhysics + std::map, size_t*>* floors; // key is a grid position, the struct seams to be the same as in push_blocks + std::map* push_blocks; // key is uid, not sure about the struct it points to (it's also possible that the value is 2 pointers) + custom_vector impostor_lakes; // + uint32_t total_liquid_spawned; // Total number of spawned liquid entities, all types. + uint32_t unknown8; // padding probably + uint8_t* unknown9; // array byte* ? game allocates 0x2F9E8 bytes for it, (0x2F9E8 / g_level_max_x * g_level_max_y = 18) which is weird, but i still think it's position based index, maybe it's 16 and accounts for more rows (grater level height) + // always allocates after the LiquidPhysics uint32_t total_liquid_spawned2; // Same as total_liquid_spawned? bool unknown12; @@ -972,27 +973,27 @@ struct Dialogue uint32_t unknown18; }; -struct ShopRestrictedItem +struct ItemOwnerDetails { - int32_t item_uid; int32_t owner_uid; ENT_TYPE owner_type; }; -struct ShopOwnerDetails +struct RoomOwnerDetails { uint8_t layer; uint8_t padding1; uint8_t padding2; uint8_t padding3; uint32_t room_index; - uint32_t shop_owner_uid; + int32_t owner_uid; }; -struct ShopsInfo +struct RoomOwnersInfo { - std::set items; // could also be a map - std::vector shop_owners; + /// key/index is the uid of an item + custom_map owned_items; + std::vector owned_rooms; }; struct MultiLineTextRendering diff --git a/src/injected/ui.cpp b/src/injected/ui.cpp index 1527b33e3..18c1f8599 100644 --- a/src/injected/ui.cpp +++ b/src/injected/ui.cpp @@ -605,6 +605,7 @@ void load_cursor() void render_cursor() { ImGuiContext& g = *GImGui; + g.Style.MouseCursorScale = 1.5f; if (g_cursor.texture == nullptr || !g.IO.MouseDrawCursor || g.MouseCursor != ImGuiMouseCursor_Arrow) return; g.MouseCursor = ImGuiMouseCursor_None; @@ -1523,6 +1524,19 @@ void spawn_entity_over() auto who = overlay->as(); who->give_powerup(item.id); } + else if (item.name.find("ENT_TYPE_ITEM") != std::string::npos && overlay->type->search_flags & 0x100) + { + int spawned = UI::spawn_entity_over(item.id, g_over_id, g_dx, g_dy); + auto ent = get_entity_ptr(spawned); + ent->set_draw_depth(9); + ent->flags = set_flag(ent->flags, 4); // pass thru objects + ent->flags = set_flag(ent->flags, 10); // no gravity + ent->flags = clr_flag(ent->flags, 13); // collides walls + if (!test_flag(g_state->special_visibility_flags, 1)) + ent->flags = set_flag(ent->flags, 1); // invisible + if (!lock_entity) + g_last_id = spawned; + } else if (item.name.find("ENT_TYPE_MONS") != std::string::npos && overlay->type->id >= turkey && overlay->type->id <= couch) { auto mount = overlay->as(); @@ -3239,11 +3253,9 @@ void tooltip(const char* tip, bool force = false) return; if (ImGui::IsItemHovered() || force) { - ImGuiContext& g = *GImGui; - if (options["hd_cursor"]) - g.Style.MouseCursorScale = 1.5f; + auto base = ImGui::GetMainViewport(); + ImGui::SetNextWindowViewport(base->ID); ImGui::SetTooltip("%s", tip); - g.Style.MouseCursorScale = 1.0f; } } @@ -3253,9 +3265,8 @@ void tooltip(const char* tip, const char* key) return; if (ImGui::IsItemHovered()) { - ImGuiContext& g = *GImGui; - if (options["hd_cursor"]) - g.Style.MouseCursorScale = 1.5f; + auto base = ImGui::GetMainViewport(); + ImGui::SetNextWindowViewport(base->ID); if (key && keys[key]) { ImGui::SetTooltip("(%s) %s", key_string(keys[key]).c_str(), tip); @@ -3264,7 +3275,6 @@ void tooltip(const char* tip, const char* key) { ImGui::SetTooltip("%s", tip); } - g.Style.MouseCursorScale = 1.0f; } } @@ -8720,6 +8730,8 @@ void imgui_draw() if (options["hd_cursor"]) render_cursor(); + else + g.Style.MouseCursorScale = 1.0f; } void check_focus() diff --git a/src/injected/ui_util.cpp b/src/injected/ui_util.cpp index ae3f0a884..4d71f4c0b 100644 --- a/src/injected/ui_util.cpp +++ b/src/injected/ui_util.cpp @@ -604,14 +604,18 @@ void UI::safe_destroy(Entity* ent, bool unsafe, bool recurse) auto check = ent; do { - // TODO: weird hack, but destroying the olmec in 3-1 crashes. some logic is still using it - // destroying olmec anywhere else would be fine I think if (check && in_array(check->type->id, olmecs)) { - auto olmec = check->as(); - olmec->attack_phase = 3; - olmec->flags = 0x50001231; - move_entity_abs(olmec->uid, 10.0f, 1000.0f, 0.0f, 0.0f); + auto state = State::get().ptr(); + if (state->logic->olmec_cutscene) + { + // 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 = nullptr; + } + destroy_entity_items(check); + check->destroy(); return; } else if (in_array(check->type->id, jellys))