diff --git a/docs/game_data/spel2.lua b/docs/game_data/spel2.lua index f9f06777c..9f0409a1e 100644 --- a/docs/game_data/spel2.lua +++ b/docs/game_data/spel2.lua @@ -464,6 +464,18 @@ function move_entity(uid, x, y, vx, vy, layer) end ---@param layer LAYER ---@return nil function move_grid_entity(uid, x, y, layer) end +---Destroy the grid entity (by uid or position), and its item entities, removing them from the grid without dropping particles or gold. +---Will also destroy monsters or items that are standing on a linked activefloor or chain, though excludes MASK.PLAYER to prevent crashes +---@param uid integer +---@return nil +function destroy_grid(uid) end +---Destroy the grid entity (by uid or position), and its item entities, removing them from the grid without dropping particles or gold. +---Will also destroy monsters or items that are standing on a linked activefloor or chain, though excludes MASK.PLAYER to prevent crashes +---@param x number +---@param y number +---@param layer LAYER +---@return nil +function destroy_grid(x, y, layer) end ---Make an ENT_TYPE.FLOOR_DOOR_EXIT go to world `w`, level `l`, theme `t` ---@param uid integer ---@param w integer diff --git a/docs/src/includes/_globals.md b/docs/src/includes/_globals.md index 01babc41e..fccf56f80 100644 --- a/docs/src/includes/_globals.md +++ b/docs/src/includes/_globals.md @@ -1204,6 +1204,18 @@ Depending on the image size, this can take a moment, preferably don't create the Create image from file, cropped to the geometry provided. Returns a tuple containing id, width and height. Depending on the image size, this can take a moment, preferably don't create them dynamically, rather create all you need in global scope so it will load them as soon as the game starts +### destroy_grid + + +> Search script examples for [destroy_grid](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=destroy_grid) + +#### nil destroy_grid(int uid) + +#### nil destroy_grid(float x, float y, [LAYER](#LAYER) layer) + +Destroy the grid entity (by uid or position), and its item entities, removing them from the grid without dropping particles or gold. +Will also destroy monsters or items that are standing on a linked activefloor or chain, though excludes [MASK](#MASK).PLAYER to prevent crashes + ### disable_floor_embeds diff --git a/src/game_api/layer.cpp b/src/game_api/layer.cpp index 68e52051d..39a0ca999 100644 --- a/src/game_api/layer.cpp +++ b/src/game_api/layer.cpp @@ -215,3 +215,35 @@ void Layer::move_grid_entity(Entity* ent, uint32_t x, uint32_t y, Layer* dest_la } } } + +void Layer::destroy_grid_entity(Entity* ent) +{ + if (ent) + { + auto items = ent->items.entities(); + for (auto ptr = items.cend(); ptr != items.cbegin();) + { + ptr--; + Entity* item_ent = *ptr; + if (!item_ent->is_player()) // if not player + { + destroy_grid_entity(item_ent); + } + } + + const auto pos = ent->position(); + const uint32_t current_grid_x = static_cast(std::round(pos.first)); + const uint32_t current_grid_y = static_cast(std::round(pos.second)); + if (current_grid_x < g_level_max_x && current_grid_y < g_level_max_y) + { + if (grid_entities[current_grid_y][current_grid_x] == ent) + { + grid_entities[current_grid_y][current_grid_x] = nullptr; + update_liquid_collision_at(pos.first, pos.second, false); + } + } + + ent->flags |= 1U << (29 - 1); // set DEAD flag to prevent certain stuff like gold nuggets drop or particles from entities such as spikes + ent->destroy(); + } +} diff --git a/src/game_api/layer.hpp b/src/game_api/layer.hpp index 8def12e0c..32dc5f40b 100644 --- a/src/game_api/layer.hpp +++ b/src/game_api/layer.hpp @@ -210,4 +210,6 @@ struct Layer void move_grid_entity(Entity* ent, float x, float y, Layer* dest_layer); void move_grid_entity(Entity* ent, uint32_t x, uint32_t y, Layer* dest_layer); + + void destroy_grid_entity(Entity* ent); }; diff --git a/src/game_api/rpc.cpp b/src/game_api/rpc.cpp index 0b53eda97..2442ce6b3 100644 --- a/src/game_api/rpc.cpp +++ b/src/game_api/rpc.cpp @@ -1673,6 +1673,26 @@ void move_grid_entity(int32_t uid, float x, float y, LAYER layer) } } +void destroy_grid(int32_t uid) +{ + if (auto entity = get_entity_ptr(uid)) + { + auto state = State::get(); + state.layer(entity->layer)->destroy_grid_entity(entity); + } +} + +void destroy_grid(float x, float y, LAYER layer) +{ + auto state = State::get(); + uint8_t actual_layer = enum_to_layer(layer); + + if (Entity* entity = state.layer(actual_layer)->get_grid_entity_at(x, y)) + { + state.layer(entity->layer)->destroy_grid_entity(entity); + } +} + void add_item_to_shop(int32_t item_uid, int32_t shop_owner_uid) { Movable* item = get_entity_ptr(item_uid)->as(); diff --git a/src/game_api/rpc.hpp b/src/game_api/rpc.hpp index 2b6c155fa..4c4c90d04 100644 --- a/src/game_api/rpc.hpp +++ b/src/game_api/rpc.hpp @@ -125,6 +125,8 @@ void change_waddler_drop(std::vector ent_types); void poison_entity(int32_t entity_uid); void modify_ankh_health_gain(uint8_t max_health, uint8_t beat_add_health); void move_grid_entity(int32_t uid, float x, float y, LAYER layer); +void destroy_grid(int32_t uid); +void destroy_grid(float x, float y, LAYER layer); void add_item_to_shop(int32_t item_uid, int32_t shop_owner_uid); void change_poison_timer(int16_t frames); void set_adventure_seed(int64_t first, int64_t second); diff --git a/src/game_api/script/lua_vm.cpp b/src/game_api/script/lua_vm.cpp index a9f789d9b..73d6725c5 100644 --- a/src/game_api/script/lua_vm.cpp +++ b/src/game_api/script/lua_vm.cpp @@ -966,6 +966,12 @@ end lua["move_entity"] = move_entity_abs; /// Teleport grid entity, the destination should be whole number, this ensures that the collisions will work properly lua["move_grid_entity"] = move_grid_entity; + auto destroy_grid = sol::overload( + static_cast(::destroy_grid), + static_cast(::destroy_grid)); + /// Destroy the grid entity (by uid or position), and its item entities, removing them from the grid without dropping particles or gold. + /// Will also destroy monsters or items that are standing on a linked activefloor or chain, though excludes MASK.PLAYER to prevent crashes + lua["destroy_grid"] = destroy_grid; /// Make an ENT_TYPE.FLOOR_DOOR_EXIT go to world `w`, level `l`, theme `t` lua["set_door_target"] = set_door_target; /// Short for [set_door_target](#set_door_target).