Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add get_liquids_at function and small stuff #392

Merged
merged 6 commits into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/game_data/spel2.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/generate_emmylua.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"object": "any",
"ImVec2": "Vec2",
"BucketItem": "any",
"ENTITY_MASK": "MASK",
}

reFloat = re.compile(r"\bfloat\b")
Expand Down
1 change: 1 addition & 0 deletions docs/parse_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"SoundCallbackFunction": "function",
"object ": "any ",
"BucketItem": "any",
"ENTITY_MASK": "MASK",
}

header_files = [
Expand Down
12 changes: 12 additions & 0 deletions docs/src/includes/_globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,18 @@ Gets the value for the specified config

Get the current layer that the liquid is spawn in. Related function [set_liquid_layer](#set_liquid_layer)

### get_liquids_at


> Search script examples for [get_liquids_at](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=get_liquids_at)

#### tuple<int, int> get_liquids_at(float x, float y, [LAYER](#LAYER) layer)

Optimized function to check for the amount of liquids at a certain position, by accessing a 2d array of liquids by third of a tile. Try the `liquids.lua` example to know better how it works.
Returns a pair of water and lava, in that order.
Water blobs increase the number by 2 on the grid, while lava blobs increase it by 3. The maximum is usually 6.
Coarse water increase the number by 3, coarse and stagnant lava by 6. Combinations of both normal and coarse can make the number higher than 6.

### get_local_prng


Expand Down
123 changes: 123 additions & 0 deletions examples/liquids.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
meta.name = "Liquids by grid"
meta.version = "1.0"
meta.description = "Shows the amounts of liquids by grid, using the `get_liquids_at` function"

register_option_bool("only_draw_at_mouse", "Testing: Draw only liquid num at mouse position", "", false)
SereneRuby12 marked this conversation as resolved.
Show resolved Hide resolved
register_option_bool("draw_grid_lines", "Draw grid lines", "", true)
register_option_bool("draw_text_shadow", "Draw text shadow", "", true)

local function get_camera_bounds_grid()
local left, top = game_position(-1, 1)
local right, bottom = game_position(1, -1)
left, top, right, bottom = math.floor(left - 0.5), math.ceil(top + 0.5), math.ceil(right + 0.5), math.floor(bottom - 0.5)
return left, top, right, bottom
end

local water_color = Color:new(0, 0.1, 1.0, 1.0)
local lava_color = Color:new(1.0, 0.1, 0.0, 1.0)
local black = Color:black()

---@type table<integer, TextRenderingInfo>
local num_text_renders = {}
local last_zoom = get_zoom_level()

-- Generate a text for every possible number, to optimize when there's many numbers to render
local function reload_num_text_renders(zoom)
for i = 0, 12 do
num_text_renders[i] = TextRenderingInfo:new(tostring(i), 0.0081 / zoom, 0.0081 / zoom, VANILLA_TEXT_ALIGNMENT.CENTER, VANILLA_FONT_STYLE.NORMAL)
end
end
reload_num_text_renders(last_zoom)

---@param ctx VanillaRenderContext
---@param text_render TextRenderingInfo
local function draw_text_shadow(ctx, text_render)
local offset <const> = 0.027 / last_zoom
local saved_x, saved_y = text_render.x, text_render.y
text_render.x, text_render.y = text_render.x + offset, text_render.y - offset
ctx:draw_text(text_render, black)
text_render.x, text_render.y = saved_x, saved_y
end

---@param ctx VanillaRenderContext
---@param x number
---@param y number
local function draw_liquids_at(ctx, x, y)
local water, lava = get_liquids_at(x, y, LAYER.PLAYER)
if water == 0 and lava == 0 then return end

local spacing <const> = 0.0135 / last_zoom
local text_render = num_text_renders[water]
text_render.x, text_render.y = screen_position(x, y)
text_render.x = text_render.x - (text_render.width / 2.) - spacing
if options.draw_text_shadow then
draw_text_shadow(ctx, text_render)
end
ctx:draw_text(text_render, water_color)

text_render = num_text_renders[lava]
text_render.x, text_render.y = screen_position(x, y)
text_render.x = text_render.x + (text_render.width / 2.) + spacing
if options.draw_text_shadow then
draw_text_shadow(ctx, text_render)
end
ctx:draw_text(text_render, lava_color)
end

---@param ctx VanillaRenderContext
---@param x number
---@param y number
local function draw_grid_liquids(ctx, x, y)
local off <const> = 1./3.
for iy = -1, 1 do
for ix = -1, 1 do
local cx, cy = x + (ix * off), y + (iy * off)
draw_liquids_at(ctx, cx, cy)
end
end
end

local trans_white = Color:white()
trans_white.a = 0.25

---@param ctx VanillaRenderContext
set_callback(function(ctx)
local left, top, right, bottom = get_camera_bounds_grid()
local zoom = get_zoom_level()
if last_zoom ~= zoom then
reload_num_text_renders(zoom)
last_zoom = zoom
end

if not options.only_draw_at_mouse then
for y = bottom, top do
for x = left, right do
draw_grid_liquids(ctx, x, y)
end
end
else
local spacing <const> = 0.0135 / last_zoom
local x, y = game_position(mouse_position())
x = x + (1/6)
y = y + (1/6)
x = x - (x % (1/3))
y = y - (y % (1/3))
draw_liquids_at(ctx, x, y)
end

if not options.draw_grid_lines then return end
local off <const> = 1./3.
local line_width <const> = 3.5
for y = bottom, top do
for i = 0, 2 do
local line_y = y + (off * i) + 0.5
ctx:draw_screen_line(Vec2:new(screen_position(left, line_y)), Vec2:new(screen_position(right, line_y)), line_width, trans_white)
end
end
for x = left, right do
for i = 0, 2 do
local line_x = x + (off * i) + 0.5
ctx:draw_screen_line(Vec2:new(screen_position(line_x, top)), Vec2:new(screen_position(line_x, bottom)), line_width, trans_white)
end
end
end, ON.RENDER_PRE_HUD)
30 changes: 30 additions & 0 deletions src/game_api/aliases.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,33 @@ enum class PAUSE_SCREEN : int64_t
EXIT = 1 << 31,
};
ENUM_CLASS_FLAGS(PAUSE_SCREEN);

enum class ENTITY_MASK : uint32_t
{
PLAYER = 0x1,
MOUNT = 0x2,
MONSTER = 0x4,
ITEM = 0x8,
EXPLOSION = 0x10,
ROPE = 0x20,
FX = 0x40,
ACTIVEFLOOR = 0x80,
FLOOR = 0x100,
DECORATION = 0x200,
BG = 0x400,
SHADOW = 0x800,
LOGICAL = 0x1000,
WATER = 0x2000,
LAVA = 0x4000,
LIQUID = 0x6000,
ANY = 0x0,
};
ENUM_CLASS_FLAGS(ENTITY_MASK)

// Returns true if any of the set bits in `mask` are in `flags`
template <class T>
requires std::is_enum_v<T>
bool test_mask(T flags, T mask)
{
return static_cast<std::underlying_type_t<T>>(flags & mask) != 0;
}
19 changes: 19 additions & 0 deletions src/game_api/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <unordered_set> // for _Uset_traits<>::allocator_type, _Use...
#include <utility> // for min, max, pair, find

#include "aliases.hpp"
#include "bucket.hpp"
#include "containers/custom_vector.hpp" //
#include "custom_types.hpp" // for get_custom_entity_types, CUSTOM_TYPE
Expand Down Expand Up @@ -1354,6 +1355,24 @@ void add_entity_to_liquid_collision(uint32_t uid, bool add)
}
}

std::pair<uint8_t, uint8_t> get_liquids_at(float x, float y, LAYER layer)
{
uint8_t actual_layer = enum_to_layer(layer);
LiquidPhysics* liquid_physics = State::get().ptr()->liquid_physics;
// if (y > 125.5 || y < 0 || x > 85.5 || x < 0) // Original check by the game, can result is accesing the array out of bounds
// return 0;
if (actual_layer != get_liquid_layer() || y < 0 || x < 0)
return {0, 0};

uint32_t ix = static_cast<int>((x + 0.5) / 0.3333333);
uint32_t iy = static_cast<int>((y + 0.5) / 0.3333333);
if (iy >= (g_level_max_y * 3) || ix >= (g_level_max_x * 3))
return {0, 0};

auto& liquids_at = (*liquid_physics->liquids_by_third_of_tile)[iy][ix];
return {liquids_at.water, liquids_at.lava};
}

bool disable_floor_embeds(bool disable)
{
static const auto address = get_address("spawn_floor_embeds");
Expand Down
1 change: 1 addition & 0 deletions src/game_api/rpc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ void set_adventure_seed(int64_t first, int64_t second);
std::pair<int64_t, int64_t> get_adventure_seed(std::optional<bool> run_start);
void update_liquid_collision_at(float x, float y, bool add, std::optional<LAYER> layer = std::nullopt);
void add_entity_to_liquid_collision(uint32_t uid, bool add);
std::pair<uint8_t, uint8_t> get_liquids_at(float x, float y, LAYER layer);
bool disable_floor_embeds(bool disable);
void set_cursepot_ghost_enabled(bool enable);
void game_log(std::string message);
Expand Down
6 changes: 6 additions & 0 deletions src/game_api/script/lua_vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1927,6 +1927,12 @@ end
/// optional `layer` parameter to be used when liquid was moved to back layer using [set_liquid_layer](#set_liquid_layer)
lua["update_liquid_collision_at"] = update_liquid_collision_at;

/// Optimized function to check for the amount of liquids at a certain position, by accessing a 2d array of liquids by third of a tile. Try the `liquids.lua` example to know better how it works.
/// Returns a pair of water and lava, in that order.
/// Water blobs increase the number by 2 on the grid, while lava blobs increase it by 3. The maximum is usually 6.
/// Coarse water increase the number by 3, coarse and stagnant lava by 6. Combinations of both normal and coarse can make the number higher than 6.
lua["get_liquids_at"] = get_liquids_at;

/// Disable all crust item spawns, returns whether they were already disabled before the call
lua["disable_floor_embeds"] = disable_floor_embeds;

Expand Down
15 changes: 12 additions & 3 deletions src/game_api/state_structs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,14 @@ struct LiquidLake
Entity* impostor_lake;
};

// Water blobs increase the number by 2 on the grid, while lava blobs increase it by 3. The maximum is 6
// Coarse water increase the number by 3, coarse and stagnant lava by 6. Combinations of both normal and coarse can make the number higher than 6
struct LiquidAmounts
{
uint8_t lava;
uint8_t water;
};

struct LiquidPhysics
{
size_t unknown1; // MysteryLiquidPointer1 in plugin, collision with floors/activefloors related
Expand Down Expand Up @@ -872,11 +880,12 @@ struct LiquidPhysics
custom_vector<LiquidLake> 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

LiquidAmounts (*liquids_by_third_of_tile)[g_level_max_y * 3][g_level_max_x * 3]; // array byte* game allocates 0x2F9E8 bytes for it ((126 * 3) * (86 * 3) * 2 : y, x, liquid_type).
// always allocates after the LiquidPhysics

uint32_t total_liquid_spawned2; // Same as total_liquid_spawned?
bool unknown12;
bool unknown12; // if false, I think the game should check for liquids by looking for liquid entities rather than using the previous liquids array. Is set to true by the game actively
uint8_t padding12a;
uint8_t padding12b;
uint8_t padding12c;
Expand Down
Loading