From ec5dc174b1c9eae8e7a0d9252725c07bd30d174b Mon Sep 17 00:00:00 2001 From: hanakocz Date: Mon, 30 Sep 2024 23:05:53 +0200 Subject: [PATCH] Changes for utils. --- utils/functions/flying_texts.lua | 30 +++++ utils/functions/unearthing_biters.lua | 2 +- utils/functions/unearthing_worm.lua | 3 +- utils/table.lua | 184 ++++++++++++++++++-------- utils/utils.lua | 66 +++++---- 5 files changed, 202 insertions(+), 83 deletions(-) create mode 100644 utils/functions/flying_texts.lua diff --git a/utils/functions/flying_texts.lua b/utils/functions/flying_texts.lua new file mode 100644 index 00000000..d6c11c66 --- /dev/null +++ b/utils/functions/flying_texts.lua @@ -0,0 +1,30 @@ +local Public = {} + + +---Create Flying text for the player, or for all players on that surface if no player specified +---@param player LuaPlayer|nil +---@param surface LuaSurface +---@param position MapPosition +---@param text string|table +---@param color Color|table +function Public.flying_text(player, surface, position, text, color) + if not player then + for _, player in pairs(game.connected_players) do + if player.surface == surface then + player.create_local_flying_text({ + text = text, + position = position, + color = color + }) + end + end + else + player.create_local_flying_text({ + text = text, + position = position, + color = color + }) + end +end + +return Public diff --git a/utils/functions/unearthing_biters.lua b/utils/functions/unearthing_biters.lua index 5395c362..ec8ccff9 100644 --- a/utils/functions/unearthing_biters.lua +++ b/utils/functions/unearthing_biters.lua @@ -92,7 +92,7 @@ local function unearthing_biters(surface, position, amount, relative_evolution) return end - local evolution = game.forces.enemy.evolution_factor + local evolution = game.forces['enemy'].get_evolution_factor(surface) if relative_evolution then evolution = relative_evolution diff --git a/utils/functions/unearthing_worm.lua b/utils/functions/unearthing_worm.lua index f97ca4cc..8f05a5d3 100644 --- a/utils/functions/unearthing_worm.lua +++ b/utils/functions/unearthing_worm.lua @@ -142,8 +142,7 @@ local function unearthing_worm(surface, position, relative_evolution) if not position.y then return end - - local evolution_index = math.ceil(game.forces.enemy.evolution_factor * 10) + local evolution_index = math.ceil(game.forces['enemy'].get_evolution_factor(surface) * 10) if relative_evolution then evolution_index = math.ceil(relative_evolution * 10) diff --git a/utils/table.lua b/utils/table.lua index 70ce292b..60906d3c 100644 --- a/utils/table.lua +++ b/utils/table.lua @@ -1,6 +1,7 @@ ---@diagnostic disable: undefined-field --luacheck: globals table local Stats = require 'utils.stats' +local Utils = require 'utils.utils' local random = math.random local floor = math.floor local remove = table.remove @@ -8,9 +9,9 @@ local tonumber = tonumber local pairs = pairs local table_size = table_size ---- Searches a table to remove a specific element without an index --- @param t to search --- @param table element to search for +---Searches a table to remove a specific element without an index +---@param t table #table to search +---@param element any #table element to search for function table.remove_element(t, element) for k, v in pairs(t) do if v == element then @@ -20,10 +21,10 @@ function table.remove_element(t, element) end end ---- Removes an item from an array in O(1) time. --- The catch is that fast_remove doesn't guarantee to maintain the order of items in the array. --- @param tbl
arrayed table --- @param index Must be >= 0. The case where index > #tbl is handled. +---Removes an item from an array in O(1) time. +---The catch is that fast_remove doesn't guarantee to maintain the order of items in the array. +---@param tbl table #arrayed table +---@param index number #Must be >= 0. The case where index > #tbl is handled. function table.fast_remove(tbl, index) local count = #tbl if index > count then @@ -35,9 +36,9 @@ function table.fast_remove(tbl, index) tbl[count] = nil end ---- Adds the contents of table t2 to table t1 --- @param t1
to insert into --- @param t2
to insert from +---Adds the contents of table t2 to table t1 +---@param t1 table #table to insert into +---@param t2 table #table to insert from function table.add_all(t1, t2) for k, v in pairs(t2) do if tonumber(k) then @@ -48,10 +49,10 @@ function table.add_all(t1, t2) end end ---- Checks if a table contains an element --- @param t
--- @param e table element --- @returns the index of the element or nil +---Checks if a table contains an element +---@param t table +---@param e any #table element +---@return any #the index of the element or nil function table.index_of(t, e) for k, v in pairs(t) do if v == e then @@ -61,10 +62,10 @@ function table.index_of(t, e) return nil end ---- Checks if the arrayed portion of a table contains an element --- @param t
--- @param e table element --- @returns the index of the element or nil +---Checks if the arrayed portion of a table contains an element +---@param t table +---@param e any #table element +---@return number|nil #the index of the element or nil function table.index_of_in_array(t, e) for i = 1, #t do if t[i] == e then @@ -75,27 +76,27 @@ function table.index_of_in_array(t, e) end local index_of = table.index_of ---- Checks if a table contains an element --- @param t
--- @param e table element --- @returns indicating success +---Checks if a table contains an element +---@param t table +---@param e any #table element +---@return boolean #boolean indicating success function table.contains(t, e) return index_of(t, e) and true or false end local index_of_in_array = table.index_of_in_array ---- Checks if the arrayed portion of a table contains an element --- @param t
--- @param e table element --- @returns indicating success +---Checks if the arrayed portion of a table contains an element +---@param t table +---@param e any #table element +---@return boolean #boolean indicating success function table.array_contains(t, e) return index_of_in_array(t, e) and true or false end ---- Adds an element into a specific index position while shuffling the rest down --- @param t
to add into --- @param index the position in the table to add to --- @param element to add to the table +---Adds an element into a specific index position while shuffling the rest down +---@param t table #table to add into +---@param index number #index of the position in the table to add to +---@param element any #element to add to the table function table.set(t, index, element) local i = 1 for k in pairs(t) do @@ -108,8 +109,8 @@ function table.set(t, index, element) error('Index out of bounds', 2) end ---- Returns an array of keys for a table. ---@param tbl
+---Returns an array of keys for a table. +---@param tbl table function table.keys(tbl) local n = 1 local keys = {} @@ -122,11 +123,11 @@ function table.keys(tbl) return keys end ---- Chooses a random entry from a table --- because this uses math.random, it cannot be used outside of events --- @param t
--- @param key to indicate whether to return the key or value --- @return a random element of table t +---Chooses a random entry from a table. +---Because this uses math.random, it cannot be used outside of events +---@param t table +---@param key boolean #boolean to indicate whether to return the key or value +---@return any #a random element of table t function table.get_random_dictionary_entry(t, key) local target_index = random(1, table_size(t)) local count = 1 @@ -142,12 +143,12 @@ function table.get_random_dictionary_entry(t, key) end end ---- Chooses a random entry from a weighted table --- because this uses math.random, it cannot be used outside of events --- @param weighted_table
of tables with items and their weights --- @param item_index of the index of items, defaults to 1 --- @param weight_index of the index of the weights, defaults to 2 --- @return table element +---Chooses a random entry from a weighted table. +---Because this uses math.random, it cannot be used outside of events +---@param weighted_table table #table of tables with items and their weights +---@param item_index number|nil #number of the index of items, defaults to 1 +---@param weight_index number|nil #number of the index of the weights, defaults to 2 +---@return any # any table element -- @see features.chat_triggers::hodor function table.get_random_weighted(weighted_table, item_index, weight_index) local total_weight = 0 @@ -168,9 +169,39 @@ function table.get_random_weighted(weighted_table, item_index, weight_index) end end ---- Returns a table with % chance values for each item of a weighted_table --- @param weighted_table
of tables with items and their weights --- @param weight_index of the index of the weights, defaults to 2 + +---Returns one random value based on the supplied weights. Form {[a] = A, [b] = B, ...} and {[a] = a_weight, [b] = b_weight, ...} or just {a,b,c,...} and {1,2,1,...}. +---Both tables have to be the same size. +---@param values table +---@param weights table +---@return any +function table.get_random_weighted_t(values, weights) + local total_weight = 0 + for k, w in pairs(weights) do + assert(values[k], 'Weighted_raffle: A weight is missing value!') + if w > 0 then + -- negative weights treated as zero + total_weight = total_weight + w + end + end + assert(total_weight > 0, 'Total weight of weighted_raffle needs to be bigger than zero!') + + local cumulative_probability = 0 + local rng = random() + for k, v in pairs(values) do + assert(weights[k], 'Weighted_raffle: A value is missing weight!') + cumulative_probability = cumulative_probability + (weights[k] / total_weight) + if rng <= cumulative_probability then + return v + end + end +end + + +---Returns a table with % chance values for each item of a weighted_table +---@param weighted_table table of tables with items and their weights +---@param weight_index number of the index of the weights, defaults to 2 +---@return table function table.get_random_weighted_chances(weighted_table, weight_index) local total_weight = 0 weight_index = weight_index or 2 @@ -184,12 +215,13 @@ function table.get_random_weighted_chances(weighted_table, weight_index) return chance_table end ---- Creates a fisher-yates shuffle of a sequential number-indexed table --- because this uses math.random, it cannot be used outside of events if no rng is supplied --- from: http://www.sdknews.com/cross-platform/corona/tutorial-how-to-shuffle-table-items --- @param t
to shuffle +---Creates a fisher-yates shuffle of a sequential number-indexed table. +---Because this uses math.random, it cannot be used outside of events if no rng is supplied +---from: http://www.sdknews.com/cross-platform/corona/tutorial-how-to-shuffle-table-items +---@param t table #table to shuffle +---@param rng number|nil function table.shuffle_table(t, rng) - local rand = rng or math.random + local rand = rng or random local iterations = #t if iterations == 0 then error('Not a sequential table') @@ -203,9 +235,55 @@ function table.shuffle_table(t, rng) end end +---Shuffles a table of objects with a position, leaving objects closer to position to be earlier in the table (one time semi-sort) +---@param tbl table #table to shuffle, all elements in it have to be table objects that have position key +---@param position MapPosition|{x:double,y:double} +function table.shuffle_by_distance(tbl, position) + local function pos(obj) + if obj and obj.valid and obj.position then + return obj.position + end + error('entry was not valid or does not have position!', 2) + end + local size = #tbl + for i = size, 1, -1 do + local rand = random(size) + if Utils.is_closer(pos(tbl[i]), pos(tbl[rand]), position) and i > rand then + tbl[i], tbl[rand] = tbl[rand], tbl[i] + end + end +end + +--- pairs() iterator but sorted by specified function +---@param t table +---@param order function # example: function(t,a,b) return t[b] > t[a] end +---@return function # usage: for k, v in spairs(table, function()) do ... +function table.spairs(t, order) + -- collect the keys + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(t, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end + --- Clears all existing entries in a table --- @param t
to clear --- @param array to indicate whether the table is an array or not +---@param t table to clear +---@param array boolean to indicate whether the table is an array or not function table.clear_table(t, array) if array then for i = 1, #t do diff --git a/utils/utils.lua b/utils/utils.lua index a9a335cd..40e8426d 100644 --- a/utils/utils.lua +++ b/utils/utils.lua @@ -1,13 +1,40 @@ local Module = {} --- luacheck: ignore math -Module.distance = function (pos1, pos2) +---Returns cartesian distance between pos1 and pos2 +---@param pos1 MapPosition|{x:double,y:double} +---@param pos2 MapPosition|{x:double,y:double} +---@return number +function Module.distance(pos1, pos2) local dx = pos2.x - pos1.x local dy = pos2.y - pos1.y return math.sqrt(dx * dx + dy * dy) end --- rounds number (num) to certain number of decimal places (idp) +---Returns true if position is closer to pos1 than to pos2 +---@param pos1 MapPosition|{x:double,y:double} +---@param pos2 MapPosition|{x:double,y:double} +---@param position MapPosition|{x:double,y:double} +---@return boolean +function Module.is_closer(position, pos1, pos2) + return Module.distance(pos1, position) < Module.distance(pos2, position) +end + +---Returns true if the position is inside the area +---@param position MapPosition|{x:double,y:double}|nil +---@param area BoundingBox|{left_top:MapPosition, right_bottom:MapPosition} +---@return boolean +function Module.inside(position, area) + if not position then + return false + end + + local lt = area.left_top + local rb = area.right_bottom + + return position.x >= lt.x and position.y >= lt.y and position.x <= rb.x and position.y <= rb.y +end + +---rounds number (num) to certain number of decimal places (idp) function math.round(num, idp) local mult = 10 ^ (idp or 0) return math.floor(num * mult + 0.5) / mult @@ -23,7 +50,7 @@ function math.clamp(num, min, max) end end -Module.print_except = function (msg, player) +function Module.print_except(msg, player) for _, p in pairs(game.players) do if p.connected and p ~= player then p.print(msg) @@ -31,7 +58,7 @@ Module.print_except = function (msg, player) end end -Module.print_admins = function (msg) +function Module.print_admins(msg) for _, p in pairs(game.players) do if p.connected and p.admin then p.print(msg) @@ -39,14 +66,14 @@ Module.print_admins = function (msg) end end -Module.get_actor = function () +function Module.get_actor() if game.player then return game.player.name end return '' end -Module.cast_bool = function (var) +function Module.cast_bool(var) if var then return true else @@ -54,7 +81,7 @@ Module.cast_bool = function (var) end end -Module.get_formatted_playtime = function (x) +function Module.get_formatted_playtime(x) if x < 5184000 then local y = x / 216000 y = tostring(y) @@ -114,7 +141,7 @@ Module.get_formatted_playtime = function (x) end end -Module.find_entities_by_last_user = function (player, surface, filters) +function Module.find_entities_by_last_user(player, surface, filters) if type(player) == 'string' or not player then error("bad argument #1 to '" .. debug.getinfo(1, 'n').name .. "' (number or LuaPlayer expected, got " .. type(player) .. ')', 1) return @@ -140,7 +167,7 @@ Module.find_entities_by_last_user = function (player, surface, filters) return entities end -Module.ternary = function (c, t, f) +function Module.ternary(c, t, f) if c then return t else @@ -152,7 +179,7 @@ local minutes_to_ticks = 60 * 60 local hours_to_ticks = 60 * 60 * 60 local ticks_to_minutes = 1 / minutes_to_ticks local ticks_to_hours = 1 / hours_to_ticks -Module.format_time = function (ticks) +function Module.format_time(ticks) local result = {} local hours = math.floor(ticks * ticks_to_hours) @@ -178,7 +205,7 @@ Module.format_time = function (ticks) end -- Convert date from 1999/01/01 -Module.convert_date = function (year, month, day) +function Module.convert_date(year, month, day) year = tonumber(year) month = tonumber(month) day = tonumber(day) @@ -201,19 +228,4 @@ Module.convert_date = function (year, month, day) return (day - 32075 + sub(1461 * (year + 4800 + d), 4) + sub(367 * (month - 2 - d * 12), 12) - sub(3 * sub(year + 4900 + d, 100), 4)) - 2415021 end ---- Compares positions ----@param position table ----@param area table ----@return boolean -function Module.inside(position, area) - if not position then - return false - end - - local lt = area.left_top - local rb = area.right_bottom - - return position.x >= lt.x and position.y >= lt.y and position.x <= rb.x and position.y <= rb.y -end - return Module