From 3e506387fb98d7a7dc485f04be0d15d569c0a1c1 Mon Sep 17 00:00:00 2001 From: PHIDIAS Date: Tue, 1 Sep 2026 23:00:43 +0900 Subject: [PATCH] . --- PHI-CL/changelog.txt | 7 + PHI-CL/control.lua | 13 ++ PHI-CL/control/calc.lua | 366 +++++++++++++++++++++++++++++++++ PHI-CL/data/b/ct.lua | 14 ++ PHI-CL/info.json | 4 +- PHI-CL/locale/en/locale.cfg | 17 ++ PHI-CL/locale/ja/locale.cfg | 17 ++ PHI-CL/locale/zh-CN/locale.cfg | 17 ++ PHI-CL/locale/zh-TW/locale.cfg | 17 ++ 9 files changed, 470 insertions(+), 2 deletions(-) create mode 100644 PHI-CL/control/calc.lua diff --git a/PHI-CL/changelog.txt b/PHI-CL/changelog.txt index 65b6e38..5d212e4 100644 --- a/PHI-CL/changelog.txt +++ b/PHI-CL/changelog.txt @@ -1,3 +1,10 @@ +--------------------------------------------------------------------------------------------------- +Version: 3.1.13 +Date: 2026-09-06 + + Changes: + - [CT] An experimental calculator. + --------------------------------------------------------------------------------------------------- Version: 3.1.12 Date: 2026-08-12 diff --git a/PHI-CL/control.lua b/PHI-CL/control.lua index b11948b..6595a9f 100644 --- a/PHI-CL/control.lua +++ b/PHI-CL/control.lua @@ -1,3 +1,4 @@ +local calc = require('control/calc') local cargo_landing = require('control/cargo-landing') local chest = require('control/chest') local editor = require('control/editor') @@ -31,6 +32,13 @@ local function gui_create(player) end inserter.create(player) + + if player.gui.screen['phi_cl_calc'] then + player.gui.screen['phi_cl_calc'].destroy() + end + + calc.create(player) + player.gui.screen['phi_cl_calc'].visible = false end local function gui_update(player, entity) @@ -111,6 +119,7 @@ end if settings.startup['PHI-CT'].value then script.on_event(defines.events.on_lua_shortcut, function(event) editor.toggle(event) + calc.toggle(event) end) script.on_event(defines.events.on_player_toggled_map_editor, editor.toggle_editor) @@ -137,4 +146,8 @@ if settings.startup['PHI-CT'].value then editor.available(p) end end) + + script.on_event(defines.events.on_gui_text_changed, function(event) + calc.change(event) + end) end diff --git a/PHI-CL/control/calc.lua b/PHI-CL/control/calc.lua new file mode 100644 index 0000000..3065bf3 --- /dev/null +++ b/PHI-CL/control/calc.lua @@ -0,0 +1,366 @@ +local main = {} + +function main.toggle(event) + if event.prototype_name ~= 'phi-cl-toggle-calc' then + return + end + + local player = game.players[event.player_index] + player.gui.screen['phi_cl_calc'].visible = not player.gui.screen['phi_cl_calc'].visible + player.set_shortcut_toggled('phi-cl-toggle-calc', player.gui.screen['phi_cl_calc'].visible) +end + +function main.create(player) + local frame = player.gui.screen.add({type = 'frame', name = 'phi_cl_calc', direction = 'vertical'}) + frame.auto_center = true + + local main_input = frame.add{type = 'textfield', name = 'phi_cl_calc_textfield', style = 'console_input_textfield'} + main_input.style.width = 360 + + local result_output = frame.add({type = 'label', name = 'phi_cl_calc_result', caption = '', style = 'heading_2_label'}) + result_output.style.horizontal_align = 'right' + + frame.add({type = 'label', name = 'phi_cl_calc_label_1', caption = '', style = 'heading_2_label'}) + + local scroll_pane = frame.add{type = 'scroll-pane', style = 'scroll_pane_under_subheader', name = 'phi_cl_calc_scroll_pane', direction = 'vertical', horizontal_scroll_policy = 'never', vertical_scroll_policy = 'auto'} + local table = scroll_pane.add{type = 'table', style = 'table', name = 'phi_cl_calc_table', column_count = 4} + + for _, v in ipairs({'A', 'B', 'C', 'D'}) do + table.add({type = 'label', name = 'phi_cl_calc_memory_name_' .. v, caption = v, style = 'heading_2_label'}) + local textfield = table.add{type = 'textfield', name = 'phi_cl_calc_memory_value_' .. v, style = 'console_input_textfield'} + textfield.style.width = 150 + textfield.style.horizontal_align = 'right' + end +end + +local calc_function = { + sqrt = math.sqrt, + abs = math.abs, + exp = math.exp, + ln = math.log, + log = function(x) return math.log(x, 10) end, + log2 = function(x) return math.log(x, 2) end, + sin = math.sin, + cos = math.cos, + tan = math.tan, + asin = math.asin, + acos = math.acos, + atan = math.atan, + floor = math.floor, + ceil = math.ceil, + round = function(x) return x >= 0 and math.floor(x + 0.5) or math.ceil(x - 0.5) end, + trunc = function(x) return (math.modf(x)) end, + sign = function(x) return x > 0 and 1 or (x < 0 and -1 or 0) end, + pi = function(_) return (math.pi) end, + rad = math.rad, + deg = math.deg, +} + +local calc_si_suffix = { + k = 1e3, + m = 1e6, + g = 1e9, + t = 1e12, + p = 1e15 +} + +local calc_number_base = { + x = {value = 16, digits = '%x'}, + b = {value = 2, digits = '[01]'}, + o = {value = 8, digits = '[0-7]'}, +} + +function main.parse(expression) + local cursor = 1 + + local function skip_space() + while expression:sub(cursor, cursor) == ' ' do + cursor = cursor + 1 + end + end + + local function factorial(n) + if n < 0 then + return error({'phi-cl.combine', {'calc.error'}, {'calc.factorial_neg', n}}, 0) + + elseif n > 170 then + return error({'phi-cl.combine', {'calc.error'}, {'calc.factorial_large', n}}, 0) + end + + if n ~= math.floor(n) then + return error({'phi-cl.combine', {'calc.error'}, {'calc.factorial_int', n}}, 0) + end + + local result = 1 + + for i = 2, n do + result = result * i + end + + return result + end + + local parse + + local function parse_atom() + skip_space() + local character = expression:sub(cursor, cursor) + + if character == '|' then + cursor = cursor + 1 + local value = parse() + skip_space() + + if expression:sub(cursor, cursor) ~= '|' then + return error({'phi-cl.combine', {'calc.error'}, {'calc.expected_bar'}}, 0) + end + + cursor = cursor + 1 + return math.abs(value) + + elseif character == '(' then + cursor = cursor + 1 + local value = parse() + skip_space() + + if expression:sub(cursor, cursor) ~= ')' then + return error({'phi-cl.combine', {'calc.error'}, {'calc.expected_paren'}}, 0) + end + + cursor = cursor + 1 + return value + + elseif character == '' then + return error({'phi-cl.combine', {'calc.error'}, {'calc.unexpected_end'}}, 0) + + elseif character:match('%a') then + skip_space() + local start = cursor + + while expression:sub(cursor, cursor):match('%w') do + cursor = cursor + 1 + end + + local name = expression:sub(start, cursor - 1) + local fn = calc_function[name] + skip_space() + + if expression:sub(cursor, cursor) == '(' then + if not fn then + return error({'phi-cl.combine', {'calc.error'}, {'calc.unknown_fn'}}, 0) + end + + cursor = cursor + 1 + local argument = parse() + skip_space() + + if expression:sub(cursor, cursor) ~= ')' then + return error({'phi-cl.combine', {'calc.error'}, {'calc.expected_paren'}}, 0) + end + + cursor = cursor + 1 + return fn(argument) + end + + if fn then + return error({'phi-cl.combine', {'calc.error'}, {'calc.expected_open', name}}, 0) + end + + return error({'phi-cl.combine', {'calc.error'}, {'calc.unknown_id', name}}, 0) + + else + skip_space() + + if expression:sub(cursor, cursor) == '0' then + local base = calc_number_base[expression:sub(cursor + 1, cursor + 1):lower()] + if base then + local literal_start = cursor + cursor = cursor + 2 + local digit_start = cursor + + while expression:sub(cursor, cursor):match(base.digits) do + cursor = cursor + 1 + end + + if cursor == digit_start or expression:sub(cursor, cursor):match('%w') then + while expression:sub(cursor, cursor):match('%w') do + cursor = cursor + 1 + end + + return error({'phi-cl.combine', {'calc.error'}, {'calc.invalid_num', expression:sub(literal_start, cursor - 1)}}, 0) + end + + return tonumber(expression:sub(digit_start, cursor - 1), base.value) + end + end + + local start = cursor + + while expression:sub(cursor, cursor):match('[%d%.eE]') do + cursor = cursor + 1 + end + + if cursor == start then + return error({'phi-cl.combine', {'calc.error'}, {'calc.expected_num'}}, 0) + end + + if expression:sub(cursor - 1, cursor - 1):lower() == 'e' then + skip_space() + + if expression:sub(cursor, cursor):match('[+-]') then + cursor = cursor + 1 + + while expression:sub(cursor, cursor):match('[%d%.]') do + cursor = cursor + 1 + end + end + end + + local num = tonumber(expression:sub(start, cursor - 1)) + + if not num then + return error({'phi-cl.combine', {'calc.error'}, {'calc.invalid_num', expression:sub(start, cursor - 1)}}, 0) + end + + return num + end + end + + local function parse_factor() + skip_space() + + if expression:sub(cursor, cursor) == '-' then + cursor = cursor + 1 + return -parse_factor() + + elseif expression:sub(cursor, cursor) == '+' then + cursor = cursor + 1 + return parse_factor() + end + + local base = parse_atom() + skip_space() + local suffix = calc_si_suffix[expression:sub(cursor, cursor)] + + if suffix then + cursor = cursor + 1 + base = base * suffix + end + + skip_space() + + if expression:sub(cursor, cursor) == '!' then + cursor = cursor + 1 + base = factorial(base) + end + + skip_space() + + if expression:sub(cursor, cursor + 1) == '**' then + cursor = cursor + 2 + return base ^ parse_factor() + + elseif expression:sub(cursor, cursor) == '^' then + cursor = cursor + 1 + return base ^ parse_factor() + end + + return base + end + + local function parse_term() + local value = parse_factor() + + while true do + skip_space() + local character = expression:sub(cursor, cursor) + + if character ~= '*' and character ~= '/' and character ~= '%' then + break + end + + if character == '*' then + value = value * parse_factor() + + elseif character == '/' then + local divisor = parse_factor() + + if divisor == 0 then + error({'phi-cl.combine', {'calc.error'}, {'calc.div_zero'}}, 0) + end + + value = value / divisor + + elseif character == '%' then + local divisor = parse_factor() + + if divisor == 0 then + error({'phi-cl.combine', {'calc.error'}, {'calc.mod_zero'}}, 0) + end + + value = value % divisor + end + end + + return value + end + + parse = function() + local value = parse_term() + + while true do + skip_space() + local character = expression:sub(cursor, cursor) + + if character ~= '+' and character ~= '-' then + break + end + + cursor = cursor + 1 + + if character == '+' then + value = value + parse_term() + + else + value = value - parse_term() + end + end + + return value + end + + local ok, result = pcall(function() + local value = parse() + skip_space() + + if cursor <= #expression then + error({'phi-cl.combine', {'calc.error'}, {'calc.trailing', expression:sub(cursor, expression:len())}}, 0) + end + + return value + end) + + if not ok then + return type(result) == 'table' and result or {'calc.error', tostring(result)} + end + + return result +end + +function main.change(event) + if event.element.name ~= 'phi_cl_calc_textfield' then + return + end + + local player = game.players[event.player_index] + local gui = player.gui.screen['phi_cl_calc'] + + if event.text:len() == 0 then + gui['phi_cl_calc_result'].caption = '' + return + end + + gui['phi_cl_calc_result'].caption = main.parse(event.text:lower()) +end + +return main diff --git a/PHI-CL/data/b/ct.lua b/PHI-CL/data/b/ct.lua index 2d3e4e8..48dc0a6 100644 --- a/PHI-CL/data/b/ct.lua +++ b/PHI-CL/data/b/ct.lua @@ -243,3 +243,17 @@ if data.raw['blueprint-book'] and data.raw['blueprint-book']['blueprint-book'] t localised_name = {'', {'gui-permissions-names.ToggleMapEditor'}} }}) end + +if data.raw['virtual-signal'] and data.raw['virtual-signal']['signal-equal'] then + data:extend({{ + type = 'shortcut', + name = 'phi-cl-toggle-calc', + action = 'lua', + toggleable = true, + icon = data.raw['virtual-signal']['signal-equal'].icon, + icon_size = data.raw['virtual-signal']['signal-equal'].icon_size, + small_icon = data.raw['virtual-signal']['signal-equal'].icon, + small_icon_size = data.raw['virtual-signal']['signal-equal'].icon_size, + localised_name = {'', {'virtual-signal-name.signal-equal'}} + }}) +end diff --git a/PHI-CL/info.json b/PHI-CL/info.json index 54e242c..805e5fb 100644 --- a/PHI-CL/info.json +++ b/PHI-CL/info.json @@ -1,8 +1,8 @@ { "name": "PHI-CL", - "version": "3.1.12", + "version": "3.1.13", "factorio_version": "2.1", - "date": "2026-08-12", + "date": "2026-09-06", "title": "Phidias Collection", "author": "PHIDIAS0303", "contributers": "", diff --git a/PHI-CL/locale/en/locale.cfg b/PHI-CL/locale/en/locale.cfg index 1887bd1..9b7fdfa 100644 --- a/PHI-CL/locale/en/locale.cfg +++ b/PHI-CL/locale/en/locale.cfg @@ -24,6 +24,23 @@ active-energy-void=Active energy void empty-train-battery=Empty train battery charged-train-battery=Charged train battery +[calc] +error=[ERROR] +factorial_neg=Factorial of a negative number __1__ +factorial_large=Factorial too large __1__ +factorial_int=Factorial must be an integer __1__ +expected_bar=Expected closing bar +expected_num=Expected number +expected_open=Expected opening parenthesis __1__ +expected_paren=Expected closing parenthesis +unexpected_end=Unexpected end of input +unknown_fn=Unknown function __1__ +unknown_id=Unknown identifier __1__ +invalid_num=Invalid number __1__ +div_zero=Division by zero +mod_zero=Modulo by zero +trailing=Unexpected trailing input __1__ + [technology-name] compound-energy=Compound energy diff --git a/PHI-CL/locale/ja/locale.cfg b/PHI-CL/locale/ja/locale.cfg index c6536b2..d301870 100644 --- a/PHI-CL/locale/ja/locale.cfg +++ b/PHI-CL/locale/ja/locale.cfg @@ -21,6 +21,23 @@ active-energy-void=アクティブエネルギーボイド empty-train-battery=空の列車バッテリー charged-train-battery=充電済み列車用バッテリー +[calc] +error=[エラー] +factorial_neg=負の数の階乗 __1__ +factorial_large=階乗が大きすぎます __1__ +factorial_int=階乗は整数でなければなりません __1__ +expected_bar=閉じる縦棒が必要です +expected_num=数字が必要です +expected_open=開き括弧が必要です __1__ +expected_paren=閉じる括弧が必要です +unexpected_end=予期しない入力の終端です +unknown_fn=不明な関数 __1__ +unknown_id=不明な識別子 __1__ +invalid_num=無効な数字 __1__ +div_zero=ゼロ除算はできません +mod_zero=ゼロで剰余はできません +trailing=予期しない余分な入力です __1__ + [technology-name] compound-energy=複合発電 diff --git a/PHI-CL/locale/zh-CN/locale.cfg b/PHI-CL/locale/zh-CN/locale.cfg index b22b3ba..c4fb8b7 100644 --- a/PHI-CL/locale/zh-CN/locale.cfg +++ b/PHI-CL/locale/zh-CN/locale.cfg @@ -21,6 +21,23 @@ active-energy-void=主動能量消除器 empty-train-battery=空火車電池 charged-train-battery=已充電火車電池 +[calc] +error=[錯誤] +factorial_neg=負數的階乘 __1__ +factorial_large=階乘太大 __1__ +factorial_int=階乘必須是整數 __1__ +expected_bar=缺少右側垂直線 +expected_num=缺少數字 +expected_open=缺少左括號 __1__ +expected_paren=缺少右括號 +unexpected_end=意外的輸入結尾 +unknown_fn=未知函數 __1__ +unknown_id=未知識別項 __1__ +invalid_num=無效的數字 __1__ +div_zero=除以零 +mod_zero=對零取餘數 +trailing=意外的尾隨輸入 __1__ + [technology-name] compound-energy=複合發電 diff --git a/PHI-CL/locale/zh-TW/locale.cfg b/PHI-CL/locale/zh-TW/locale.cfg index b22b3ba..c4fb8b7 100644 --- a/PHI-CL/locale/zh-TW/locale.cfg +++ b/PHI-CL/locale/zh-TW/locale.cfg @@ -21,6 +21,23 @@ active-energy-void=主動能量消除器 empty-train-battery=空火車電池 charged-train-battery=已充電火車電池 +[calc] +error=[錯誤] +factorial_neg=負數的階乘 __1__ +factorial_large=階乘太大 __1__ +factorial_int=階乘必須是整數 __1__ +expected_bar=缺少右側垂直線 +expected_num=缺少數字 +expected_open=缺少左括號 __1__ +expected_paren=缺少右括號 +unexpected_end=意外的輸入結尾 +unknown_fn=未知函數 __1__ +unknown_id=未知識別項 __1__ +invalid_num=無效的數字 __1__ +div_zero=除以零 +mod_zero=對零取餘數 +trailing=意外的尾隨輸入 __1__ + [technology-name] compound-energy=複合發電