-- https://metin2.dev/topic/15905-syreldars-quest-functions/ ---@diagnostic disable: lowercase-global, undefined-field, deprecated, undefined-global --[[ Description: Checks if a `num` number is a valid number. Arguments: num (number): The number to be checked. allow_negative (boolean): Whether negative numbers are allowed. allow_decimals (boolean): Whether decimal numbers are allowed. allow_zero (boolean): Whether zero number is allowed. Example: local result1 = is_valid_number(42, true, true, false); -- Returns true local result2 = is_valid_number(-5, false, true, false); -- Returns false local result3 = is_valid_number(3.14, true, false, false); -- Returns false Returns: boolean: True if `num` is a valid number, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] is_valid_number = function(num, allow_negative, allow_decimals, allow_zero) allow_negative = allow_negative or true; allow_decimals = allow_decimals or false; allow_zero = allow_zero or true; if (type(num) ~= "number") then return false; elseif (not allow_zero and num == 0) then return false; elseif (not allow_negative and num < 0) then return false; elseif (not allow_decimals and num ~= math.floor(num)) then return false; elseif (({["nan"] = true, ["inf"] = true, ["-inf"] = true})[tostring(num)]) then return false; end -- if/elseif return true; end -- function --[[ Description: Checks if a `num` number is an integer. Arguments: num (number): The number to be checked. Example: local result1 = is_integer_number(42); -- Returns true local result2 = is_integer_number(3.14); -- Returns false Returns: boolean: True if `num` is an integer, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] is_integer_number = function(num) return is_valid_number(num, true, false); end -- function --[[ Description: Checks if a `num` number is even. Arguments: num (number): The number to be checked. Example: local result1 = is_number_even(42); -- Returns true local result2 = is_number_even(3); -- Returns false Returns: boolean: True if `num` is even, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] is_number_even = function(num) return is_integer_number(num) and math.mod(num, 2) == 0; end -- function --[[ Description: Checks if a `num` number is odd. Arguments: num (number): The number to be checked. Example: local result1 = is_number_odd(42); -- Returns false local result2 = is_number_odd(3); -- Returns true Returns: boolean: True if `num` is odd, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] is_number_odd = function(num) return is_integer_number(num) and math.mod(num, 2) ~= 0; end -- function --[[ Description: Outputs the factorial of a `num` number. Arguments: num (number): The number for which to calculate the factorial. Example: local result1 = factorial(5); -- Returns 120 local result2 = factorial(0); -- Returns 1 Returns: number: The factorial of `num`. Time complexity: O(n). Space complexity: O(1). ]] factorial = function(num) local result = 1; for i = 2, num do result = result * i; end -- for return result; end -- function --[[ Description: Checks if an `element` item is contained inside of a `table_ex` table. Arguments: table_ex (table): The table to search in. element (any): The element to search for in the table. Example: local table_ex = {1, 2, 3, 4, 5}; local result1 = table_is_in(table_ex, 3); -- Returns true local result2 = table_is_in(table_ex, 6); -- Returns false Returns: boolean: True if `element` is found in `table_ex`, false otherwise. Time complexity: O(n). Space complexity: O(1). ]] table_is_in = function(table_ex, element) for _, item in ipairs(table_ex) do if (item == element) then return true; end -- if end -- for return false; end -- function --[[ Description: Checks the number of elements contained inside an associative `table_ex` table, or dictionary. Arguments: table_ex (table): The table to count elements in. Example: local table_ex = {["a"] = 1, ["b"] = 2, ["c"] = 3} local result1 = table_get_count(table_ex) -- Returns 3 local result2 = table.getn(table_ex) -- Returns 0, see Note. Returns: number: The number of elements in `table_ex`. Time complexity: O(n). Space complexity: O(1). Note: This function is more versatile than `table.getn`. While `table.getn` only works for arrays (tables with consecutive integer keys starting at 1), `table_get_count` can count elements in both arrays and associative tables with any key types. It iterates through the table and counts each key-value pair, providing an accurate count regardless of the table's structure. ]] table_get_count = function(table_ex) local count = 0; for _, _ in pairs(table_ex) do count = count + 1; end -- for return count; end -- function --[[ Description: Checks if a `num` element is not nil and is a number. Arguments: num (any): The element to check. Example: local result1 = is_valid_num_field(42); -- Returns true local result2 = is_valid_num_field(nil); -- Returns false local result3 = is_valid_num_field("not_a_number"); -- Returns false Returns: boolean: True if `num` is not nil and is a number, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] is_valid_num_field = function(num) return num and num > 0; end -- function --[[ Description: Checks if a `table_ex` element is not nil, is a table, and has at least one element. Arguments: table_ex (any): The element to check. Example: local result1 = is_valid_table_field({1, 2, 3}); -- Returns true local result2 = is_valid_table_field(nil); -- Returns false local result3 = is_valid_table_field({}); -- Returns false Returns: boolean: True if `table_ex` is not nil, is a table, and has at least one element, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] is_valid_table_field = function(table_ex) return table_ex and table_get_count(table_ex) > 0; end -- function --[[ Description: Checks if a `func` element is not nil and is a function. Arguments: func (any): The element to check. Example: local result1 = is_valid_func_field(function() end); -- Returns true local result2 = is_valid_func_field(nil); -- Returns false local result3 = is_valid_func_field(42); -- Returns false Returns: boolean: True if `func` is not nil and is a function, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] is_valid_func_field = function(func) return func and type(func) == "function"; end -- function --[[ Description: Checks if a `keyword` is a key in a `table_ex` table. Arguments: table_ex (table): The table to search in. keyword (any): The key to search for in the table. Example: local table_ex = {["cat"] = 1, ["dog"] = 2, ["bird"] = 3}; local result1 = table_contains_keyword(table_ex, "dog"); -- Returns true local result2 = table_contains_keyword(table_ex, "monkey"); -- Returns false Returns: boolean: True if `keyword` is a key in `table_ex`, false otherwise. Time complexity: O(1). Space complexity: O(1). ]] table_contains_keyword = function(table_ex, keyword) return table_ex[keyword] ~= nil; end -- function --[[ Description: Returns a random element from a `table_ex` table. Arguments: table_ex (table): The table from which to select a random element. Example: local table_ex = {1, 2, 3, 4, 5}; local result1 = table_get_random_item(table_ex); -- Returns a random element, e.g., 2 Returns: any: A random element from `table_ex`. Time complexity: O(1). Space complexity: O(1). ]] table_get_random_item = function(table_ex) local table_ex_len = table_get_count(table_ex) local random_index = math.random(table_ex_len); return table_ex[random_index]; end -- function --[[ Description: Returns a random element from a `table_ex` table that is not in an `except_table`. Arguments: table_ex (table): The table from which to select a random element. except_table (table): The table containing elements to be excluded from selection. Example: local table_ex = {1, 2, 3, 4, 5}; local result1 = table_get_random_item_except(table_ex, {4, 1}); -- Returns a random element not in {4, 1} Returns: any: A random element from `table_ex` that is not in `except_table`. Time complexity: O(k + n), so O(n). -> k = number of excluded values. Space complexity: O(1). ]] table_get_random_item_except = function(table_ex, except_table) local excluded_values = {}; for _, value in pairs(except_table) do excluded_values[value] = true; end -- for local accepted_items = {}; for _, value in pairs(table_ex) do if (not excluded_values[value]) then table.insert(accepted_items, value); end -- if end -- for return table_get_random_item(accepted_items); end -- function --[[ Description: Returns a random number within a specified range that is not in an `except_table`. Arguments: range_min (number): The minimum value of the desired range (inclusive). range_max (number): The maximum value of the desired range (inclusive). except_table (table): A table containing values to be excluded from the random selection. Example: local result1 = get_random_number_within_except(1, 10, {4, 7}); -- Returns a random number between 1 and 10, excluding 4 and 7 Returns: number: A random number within the specified range that is not in `except_table`. Time complexity: O(k + n), so O(n). -> k = number of excluded values. Space complexity: O(1). ]] get_random_number_within_except = function(range_min, range_max, except_table) local excluded_values = {}; for _, value in pairs(except_table) do excluded_values[value] = true; end -- for local random_num = math.random(range_min, range_max); while excluded_values[random_num] do random_num = math.random(range_min, range_max); end -- while return random_num; end -- function --[[ Description: Returns the index of an `element` in a `table_ex` table, or nil if not found. Arguments: table_ex (table): The table to search in. element (any): The element to search for in the table. Example: local table_ex = {5, 7, 9}; local result1 = table_get_element_index(table_ex, 5); -- Returns 1 local result2 = table_get_element_index(table_ex, 11); -- Returns nil Returns: number: The index of `element` in `table_ex`, or nil if not found. Time complexity: O(n). Space complexity: O(1). ]] table_get_element_index = function(table_ex, element) for index, value in ipairs(table_ex) do if (value == element) then return index; end -- if end -- for return nil; end -- function --[[ Description: Checks if any subarray in a `array_of_arrays` table contains a `keyword`. Arguments: array_of_arrays (table): The table of subarrays to search in. keyword (any): The keyword to search for in the subarrays. Example: local array_of_arrays = { {["bird"] = "chirp"}, {["cat"] = "meow"}, {["dog"] = "whoof"} }; local result1 = table_is_any_subarray_containing_keyword(array_of_arrays, "cat"); -- Returns true local result2 = table_is_any_subarray_containing_keyword(array_of_arrays, "cow"); -- Returns false Returns: boolean: True if any subarray in `array_of_arrays` contains `keyword`, false otherwise. Time complexity: O(n). Space complexity: O(1). ]] table_is_any_subarray_containing_keyword = function(array_of_arrays, keyword) if (array_of_arrays == nil or keyword == nil) then return false; end -- if for _, subarray in ipairs(array_of_arrays) do if (subarray ~= nil and type(subarray) == "table") then for _, value in ipairs(subarray) do if (value == keyword) then return true end -- if end -- for end -- if end -- for return false; end -- function --[[ Description: Returns the index of the subarray containing a `keyword` in a `table_ex` table, or nil if not found. Arguments: table_ex (table): The table of subarrays to search in. keyword (any): The keyword to search for in the subarrays. Example: local table_ex = { {["bird"] = "chirp"}, {["cat"] = "meow"}, {["dog"] = "whoof"} }; local result1 = table_get_subarray_keyword_index(table_ex, "dog"); -- Returns 3 local result2 = table_get_subarray_keyword_index(table_ex, "worm"); -- Returns nil Returns: number: The index of the subarray containing `keyword`, or nil if not found. Time complexity: O(n). Space complexity: O(1). ]] table_get_subarray_keyword_index = function(table_ex, keyword) for index, subarray in ipairs(table_ex) do if (subarray[keyword]) then return index; end -- if end -- for return nil; end -- function --[[ Description: Shuffles the elements in a `table_ex` table and returns a shuffled version. Arguments: table_ex (table): The table to shuffle. Example: local table_ex = {1, 2, 3, 4, 5}; local result1 = table_shuffle(table_ex); -- Returns a shuffled table Returns: table: The shuffled version of `table_ex`. Time complexity: O(n). Space complexity: O(n). ]] table_shuffle = function(table_ex) local shuffled_table = {}; for i = 1, table_get_count(table_ex) do shuffled_table[i] = table_ex[i]; end -- for local rand = 0; for i = table_get_count(shuffled_table), 1, -1 do rand = math.random(i); shuffled_table[i], shuffled_table[rand] = shuffled_table[rand], shuffled_table[i]; end -- for return shuffled_table; end -- function --[[ Description: Reorders elements in `target_table` based on the shuffling of `original_table` reflected in `shuffled_table`. Arguments: original_table (table): The original unshuffled table. shuffled_table (table): The shuffled version of `original`. target_table (table): The table to reorder following the pattern of `shuffled`. Example: local original = {1, 2, 3, 4, 5}; local shuffled = {3, 1, 4, 5, 2}; local target = {'a', 'b', 'c', 'd', 'e'}; local result = mirror_shuffle(original, shuffled, target); -- result is {'c', 'a', 'd', 'e', 'b'} Returns: table: A new table with elements of `target` reordered to mirror the shuffle from `original` to `shuffled`. Time complexity: O(n). Space complexity: O(n). ]] mirror_shuffle = function(original_table, shuffled_table, target_table) local map_table = {}; for index, value in ipairs(original_table) do map_table[value] = index; end -- for local new_order_table = {}; for _, value in ipairs(shuffled_table) do new_order_table[table_get_count(new_order_table) + 1] = target_table[map_table[value]]; end -- for return new_order_table; end -- function --[[ Description: Counts the number of digits in a given integer using logarithmic calculation, compatible with Lua 5.0. Arguments: num (integer): The number whose digits are to be counted. Example: local digits = count_digits(1234); -- Returns 4, as there are 4 digits in 1234 Returns: integer: The number of digits in the given number. Time complexity: O(1), as logarithmic calculation is a constant time operation. Space complexity: O(1), as only a single calculation is performed. ]] count_digits = function(num) if (num == 0) then return 1; end -- if num = math.abs(num); return math.floor(math.log(num) / math.log(10) + 1); end -- function --[[ Description: Retrieves the nth digit of a given number. Arguments: num (integer): The number from which the digit is to be extracted. index (integer): The position of the digit to retrieve, where 1 is the first digit. Example: local digit = get_nth_digit(1234, 3); -- Returns 3, as the third digit of 1234 is 3 Returns: integer: The nth digit of the given number. Returns nil if `n` is outside the range of the number's length. Time complexity: O(1), as string conversion and digit retrieval are constant time operations. Space complexity: O(n), where n is the number of digits in the number, due to the string conversion. ]] get_nth_digit = function(num, index) local total_digits = count_digits(num); if (index < 1 or index > total_digits) then return -1; end -- if local str = tostring(num); return tonumber(string.sub(str, index, index)); end -- function --[[ Description: Generates an array containing numbers from 1 up to the specified numeric limit. Arguments: limit (integer): The upper bound of the number range to include in the array. Example: local result = generate_num_array(4); -- Returns {1, 2, 3, 4} Returns: table: An array containing numbers from 1 to `limit`. Time complexity: O(n), where n is the value of `limit`. Space complexity: O(n), where n is the value of `limit`. ]] generate_num_array = function(limit) local array = {}; for i = 1, limit do table.insert(array, i); end -- for return array; end -- function --[[ Description: Converts time values between units. Arguments: value (number): The numerical value to convert. unit (string): The unit of time ("min", "hour", "day", "week", "month_28_days", "month_30_days", "month_31_days"). Example: local result1 = time_to_sec(5, "min"); -- Returns the number of seconds contained in 5 minutes local result2 = time_hour_to_sec(2); -- Returns the number of seconds contained in 2 hours Returns: number: The number of seconds corresponding to 'value' in the given 'unit'. Time complexity: O(1). Space complexity: O(1). ]] time_to_sec = function(value, unit) local units = { min = 60, hour = 3600, day = 86400, week = 604800, month_28_days = 2419200, month_30_days = 2592000, month_31_days = 2678400 }; return units[unit] * value; end -- function --[[ Returns: The number of seconds contained in a number of minutes given by 'value'. ]] time_min_to_sec = function(value) return time_to_sec(value, "min") end -- function --[[ Returns: The number of seconds contained in a number of hours given by 'value'. ]] time_hour_to_sec = function(value) return time_to_sec(value, "hour") end -- function --[[ Returns: The number of seconds contained in a number of days given by 'value'. ]] time_day_to_sec = function(value) return time_to_sec(value, "day") end -- function --[[ Returns: The number of seconds contained in a number of weeks given by 'value'. ]] time_week_to_sec = function(value) return time_to_sec(value, "week") end -- function --[[ Returns: The number of seconds contained in a number of 28-day months given by 'value'. ]] time_month_to_sec_28_days = function(value) return time_to_sec(value, "month_28_days") end -- function --[[ Returns: The number of seconds contained in a number of 30-day months given by 'value'. ]] time_month_to_sec_30_days = function(value) return time_to_sec(value, "month_30_days") end -- function --[[ Returns: The number of seconds contained in a number of 31-day months given by 'value'. ]] time_month_to_sec_31_days = function(value) return time_to_sec(value, "month_31_days") end -- function --[[ Description: Formats a numerical `amount` with a dot as a thousands separator for better readability. Arguments: amount (number): The number to be formatted. Example: local result1 = get_gold_format(1000); -- Returns "1.000" local result2 = get_gold_format(-12345.67); -- Returns "-12.345.67" Returns: string: The formatted string version of `amount`. Time complexity: O(1). Space complexity: O(1). ]] get_gold_format = function(amount) if (not is_valid_number(amount, true, true)) then return amount; end -- if local _, _, minus, int, fraction = string.find(tostring(amount), '([-]?)(%d+)([.]?%d*)'); int = string.gsub(string.reverse(int), "(%d%d%d)", "%1."); return minus .. string.reverse(int) .. fraction; end -- function --[[ Description: Returns a string representing the total time in either the "Days, Hours, Minutes and Seconds" or "d:h:m:s" format. Arguments: sec (number): The total amount of seconds. format (string): Optional parameter, either "verbose" or "clock". simplify (boolean): Optional parameter, valid only if format is "clock". If true, the labels ("d", "h", "m", "s") will be omitted. Example: get_time_format(52165786, "verbose") -- Returns "603 days, 18 hours, 29 minutes and 46 seconds" get_time_format(52165786, "clock") -- Returns "603d:18h:29m:46s" get_time_format(52165786, "clock", true) -- Returns "603:18:29:46" Returns: string: A string representing the total time. Time complexity: O(1). Space complexity: O(1). ]] get_time_format = function(sec, format_type, simplify) format_type = format_type or "verbose"; simplify = simplify or false; local days = math.floor(sec / time_day_to_sec(1)); local hours = math.floor(math.mod(sec, time_day_to_sec(1)) / time_hour_to_sec(1)); local minutes = math.floor(math.mod(sec, time_hour_to_sec(1)) / time_min_to_sec(1)); local seconds = math.mod(sec, time_min_to_sec(1)); if (format_type == "verbose") then local parts = {}; local function add_part(quantity, unit) if (quantity > 0) then table.insert(parts, string.format("%d %s%s", quantity, unit, quantity > 1 and "s" or "")); end -- if end -- function add_part(days, "day"); add_part(hours, "hour"); add_part(minutes, "minute"); add_part(seconds, "second"); if (table_get_count(parts) > 1) then parts[table_get_count(parts) - 1] = string.format("%s and %s", parts[table_get_count(parts) - 1], parts[table_get_count(parts)]); table.remove(parts); end -- if return table.concat(parts, ", "); elseif (format_type == "clock") then if (simplify) then return string.format("%02d:%02d:%02d:%02d", days, hours, minutes, seconds); end -- if return string.format("%02dd:%02dh:%02dm:%02ds", days, hours, minutes, seconds); end -- if/elseif end -- function --[[ Description: Returns the number of seconds remaining until a specified time of day. Arguments: time_ex (string): The target time of day in "HH:MM" 24-hour format. Example: time_remaining_until("23:00") -- Returns the number of seconds remaining until 11 PM. Returns: number: The number of seconds remaining. Time complexity: O(1). Space complexity: O(1). ]] time_remaining_until = function(time_ex) local current_time = os.date("*t"); local current_time_secs = current_time.hour * time_hour_to_sec(1) + current_time.min * time_min_to_sec(1); local dot_pos = string.find(time_ex, ".", 1, true); local hours_ex = tonumber(string.sub(time_ex, 1, dot_pos - 1)); local minutes_ex = tonumber(string.sub(time_ex, dot_pos + 1)); local time_ex_secs = hours_ex * time_hour_to_sec(1) + minutes_ex * time_min_to_sec(1); local seconds_remaining = time_ex_secs - current_time_secs; if (seconds_remaining < 0) then seconds_remaining = seconds_remaining + time_day_to_sec(1); end -- if return seconds_remaining; end -- function --[[ Description: Calculates the future time based on the current system time and an additional number of seconds. The function retrieves the current hour and minute from the system, adds the specified seconds, and returns the resulting time in a 24-hour format. Arguments: sec (number): The number of seconds to add to the current system time. Example: get_time_after_seconds(600) -- If the current time is 18:00, this returns "18:10" Returns: string: A string representing the future time in "HH:MM" format, based on the current system time and the added seconds. Notes: The function handles the day transition, so if the time addition crosses midnight, the hour is adjusted accordingly. The function assumes that the system time is accurate and correctly set. Time complexity: O(1). Space complexity: O(1). ]] get_time_after_seconds = function(sec) local current_time = os.date("*t"); local total_minutes = current_time.min + sec / time_min_to_sec(1); local new_hour = current_time.hour + math.floor(total_minutes / time_min_to_sec(1)); local new_minute = math.floor(math.mod(total_minutes, time_min_to_sec(1))) if (new_hour >= 24) then new_hour = new_hour - 24; end -- if return string.format("%02d:%02d", new_hour, new_minute); end -- function --[[ Description: Returns a string representing the Roman numeral equivalent of a given integer. Arguments: int (number): The integer to be converted to a Roman numeral. Example: int_to_roman_str(23) -- Returns "XXIII" Returns: string: The Roman numeral representation. Time complexity: O(1). Space complexity: O(1). ]] int_to_roman_str = function(int) if (not is_valid_number(int, false, false)) then return "0"; end -- if local roman_numerals = { {1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"} }; local ret = ""; local temp_int = int; for i = 1, table_get_count(roman_numerals) do while (temp_int >= roman_numerals[i][1]) do ret = ret .. roman_numerals[i][2]; temp_int = temp_int - roman_numerals[i][1]; end -- while end -- for return ret; end -- function --[[ Description: Returns a boolean representing whether a given string is a valid Roman numeral. Arguments: str (string): The string to be checked. Example: is_valid_roman_str("XXIII") -- Returns true is_valid_roman_str("XXMIII") -- Returns false Returns: boolean: True if the string is a valid Roman numeral, false otherwise. Time complexity: O(n), where n is the length of the string. Space complexity: O(1). ]] is_valid_roman_str = function(str) if (not str or str == "") then return false; end -- if local valid_romans = {["I"] = 1, ["V"] = 5, ["X"] = 10, ["L"] = 50, ["C"] = 100, ["D"] = 500, ["M"] = 1000}; local cur_char = ""; for i = 1, string.len(str) do cur_char = string.sub(str, i, i); if (not valid_romans[cur_char]) then return false; end -- if end -- for return true; end -- function --[[ Description: Returns an integer equivalent of a given Roman numeral string. Arguments: str (string): The Roman numeral string to be converted. Example: roman_str_to_int("XXIII") -- Returns 23 roman_str_to_int("XXMIII") -- Returns 0, because "XXMIII" is not a valid Roman numeral Returns: number: The integer equivalent of the Roman numeral string. Time complexity: O(n), where n is the length of the string. Space complexity: O(1). ]] roman_str_to_int = function(str) if (not is_valid_roman_str(str)) then return 0; end -- if local valid_romans = {["I"] = 1, ["V"] = 5, ["X"] = 10, ["L"] = 50, ["C"] = 100, ["D"] = 500, ["M"] = 1000}; local ret = 0; local prev_val, cur_val = 0, 0; for i = string.len(str), 1, -1 do cur_val = valid_romans[string.sub(str, i, i)]; if (cur_val < prev_val) then ret = ret - cur_val; else ret = ret + cur_val; end -- if/else prev_val = cur_val; end -- for return ret; end -- function --[[ Description: Returns a decimal number converted from a binary number. Arguments: bin (number): The binary number to be converted. Example: bin_to_num(1011) -- Returns 11 Returns: number: The decimal number equivalent to the binary input. Time complexity: O(n), where n is the number of digits in the binary number. Space complexity: O(1). ]] bin_to_num = function(bin) local decimal = 0; local multiplier = 1; while (bin > 0) do local remainder = math.mod(bin, 10); bin = math.floor(bin / 10); decimal = decimal + remainder * multiplier; multiplier = multiplier * 2; end -- while return decimal; end -- function --[[ Description: Returns a binary string converted from a decimal number. Arguments: num (number): The decimal number to be converted. Example: num_to_bin(11) -- Returns "1011" Returns: string: The binary representation of the decimal input. Time complexity: O(log n), where n is the decimal number. Space complexity: O(log n), because the binary representation length is proportional to the logarithm of the number. ]] num_to_bin = function(num) local binary = ""; local temp_num = num; while (temp_num > 0) do binary = math.mod(temp_num, 2) .. binary; temp_num = math.floor(temp_num / 2); end -- while return binary; end -- function --[[ Description: Returns a number converted from a character based on ASCII values. Arguments: c (char): The character to be converted. Example: char_to_num("A") -- Returns 10 Returns: number: The numeric value of the character based on ASCII values. Time complexity: O(1). Space complexity: O(1). ]] char_to_num = function(c) local ascii = string.byte(c); if (ascii >= 48 and ascii <= 57) then -- 0-9 return ascii - 48; elseif (ascii >= 65 and ascii <= 90) then -- A-Z return ascii - 65 + 10; elseif (ascii >= 97 and ascii <= 122) then -- a-z return ascii - 97 + 36; end -- if/elseif return -1; end -- function --[[ Description: Returns a character converted from a number based on ASCII values. Arguments: n (number): The number to be converted. Example: num_to_char(10) -- Returns "A" Returns: char: The character corresponding to the numeric value based on ASCII values. Time complexity: O(1). Space complexity: O(1). ]] num_to_char = function(n) if (n >= 0 and n <= 9) then -- 0-9 return string.char(n + 48); elseif (n >= 10 and n <= 35) then -- A-Z return string.char(n - 10 + 65); elseif (n >= 36 and n <= 61) then -- a-z return string.char(n - 36 + 97); end -- if/elseif return ""; end -- function --[[ Description: Returns an array of ASCII values representing each character in the 'str' string. Arguments: str (string): The string to be converted into an array of ASCII values. Example: string_to_ascii_array("hello") -- Returns {104, 101, 108, 108, 111} Returns: table: An array of ASCII values. Time complexity: O(n), where n is the length of the string. Space complexity: O(n), where n is the length of the string. ]] string_to_ascii_array = function(str) local array = {}; local str_len = string.len(str); for i = 1, str_len do array[i] = string.byte(str, i); end -- for return array; end -- function --[[ Description: Returns a string converted from an array of ASCII values. Arguments: array (table): The array of ASCII values to be converted into a string. Example: ascii_array_to_string({104, 101, 108, 108, 111}) -- Returns "hello" Returns: string: The string representation of the ASCII values. Time complexity: O(n), where n is the length of the array. Space complexity: O(n), where n is the length of the array. ]] ascii_array_to_string = function(array) local str = ""; local array_len = table_get_count(array); for i = 1, array_len do str = str .. string.char(array[i]); end -- for return str; end -- function --[[ Description: Returns a string that represents the ID of the level. Arguments: level (number): The numeric level to be converted into an ID. Example: skill_level_to_id(35) -- Returns "G6" Returns: string: The level ID. Time complexity: O(1) Space complexity: O(1) Needs: https://metin2.dev/topic/29230-syreldars-useful-globals ]] skill_level_to_id = function(level) local map = { {["min"] = SKILL_LEVEL.PERFECT_MASTER, ["format"] = "P"}, {["min"] = SKILL_LEVEL.GRAND_MASTER, ["format"] = "G%d"}, {["min"] = SKILL_LEVEL.MASTER, ["format"] = "M%d"} }; for _, step in ipairs(map) do if (level >= step["min"]) then if (step["min"] == SKILL_LEVEL.PERFECT_MASTER) then return step["format"]; end -- if return string.format(step["format"], level - step["min"] - 1); end -- if end -- for return tostring(level); end -- function --[[ Description: Returns a number that represents the level of the given ID. Arguments: id (string): The ID to be converted into a numeric level. Example: skill_id_to_level("G6") -- Returns 35 Returns: number: The numeric level. Time complexity: O(1) Space complexity: O(1) Needs: https://metin2.dev/topic/29230-syreldars-useful-globals ]] skill_id_to_level = function(id) local prefix, num_str = string.match(id, "([GMP]?)(%d+)"); local num = tonumber(num_str); local prefix_map = { ["P"] = SKILL_LEVEL.PERFECT_MASTER, ["G"] = SKILL_LEVEL.GRAND_MASTER - 1, ["M"] = SKILL_LEVEL.MASTER - 1 }; return (prefix_map[prefix] or 0) + num; end -- function --[[ Executes: A clear of the currently active set regen, if present. Kills all currently alive dungeon monsters. Some monsters revive once, thus a second d.kill_all() call is needed. ]] clear_dungeon = function() d.clear_regen(); d.kill_all(); d.kill_all(); -- Needed for resurrecting monsters. end -- function --[[ Returns: The pids of all the online party members in the same instance (online and in the same channel, core and map). ]] party_get_member_pids = function() return {party.get_member_pids()}; end -- function --[[ Returns: The number of members in the party that are in the same instance (online and in the same channel, core and map). ]] party_get_member_count = function() return table_get_count(party_get_member_pids()); end -- function --[[ Returns: The index of the first dungeon instance of the map which index is 'map_index'. Needs: https://metin2.dev/topic/29230-syreldars-useful-globals ]] ToDungeonIndex = function(map_index) return map_index * DUNGEON_DATA.START_INDEX; end -- function --[[ Returns: The normalized index of the map which index is 'map_index'. Needs: https://metin2.dev/topic/29230-syreldars-useful-globals ]] ToNormalIndex = function(map_index) local start_index = DUNGEON_DATA.START_INDEX; return map_index >= start_index and math.floor(map_index / start_index) or map_index; end -- function --[[ Returns: true, if the player is in the dungeon instance of the map which index is 'map_index', else, false. ]] InDungeon = function(map_index) local pc_index = pc.get_map_index(); return pc.in_dungeon() and pc_index >= ToDungeonIndex(map_index) and pc_index < ToDungeonIndex(map_index+1); end -- function --[[ Returns: An array containing 2 subarrays: - The first subarray, vnum_list, contains the vnums of the skills; - The second subarray, name_list, contains the names of the skills; Needs: https://metin2.dev/topic/29230-syreldars-useful-globals ]] BuildSkillList2 = function(job, group, min_level, max_level) if (not job) then job = pc.get_job(); end -- if if (not group or pc.get_skill_group() == SKILL_GROUP.NONE) then group = SKILL_GROUP.FIRST_SPEC; end -- if if (not min_level) then min_level = SKILL_LEVEL.BASE; end -- if if (not max_level) then max_level = SKILL_LEVEL.PERFECT_MASTER-1; end -- if local skill_level = 0; local skill_list = ACTIVE_SKILL_LIST[job][group]; local vnum_list, name_list = {}, {}; for _, skill_vnum in ipairs(skill_list) do skill_level = pc.get_skill_level(skill_vnum); if (skill_level >= min_level and skill_level <= max_level) then table.insert(vnum_list, skill_vnum); table.insert(name_list, SKILL_NAME_TABLE[skill_vnum]); end -- if end -- for return {vnum_list, name_list}; end -- function --[[ A normal "say" with altered color, given by the 'color' arg. Warning: The color must be present in the COLORS array. Example: color_say("red", "The sun is burning my skin!"). Needs: https://metin2.dev/topic/29230-syreldars-useful-globals ]] color_say = function(color, text) local rgb = COLORS[color]; local r, g, b = rgb[1], rgb[2], rgb[3]; say(color256(r, g, b)..text..color256(200, 200, 200)) end -- function --[[ A normal string with altered color, given by the 'color' arg. Warning: The color must be present in the COLORS array. Example: say("I have red "..color_str("red", "eyes").." and brown "..color_str("brown", "hair").."!") will print a string where "eyes" is red-coloured and "hair" is brown-coloured. Needs: https://metin2.dev/topic/29230-syreldars-useful-globals ]] color_str = function(color, text) local rgb = COLORS[color]; local r, g, b = rgb[1], rgb[2], rgb[3]; return string.format("|cff%02x%02x%02x%s|r", r, g, b, text); end -- function