mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-07-26 18:36:23 +09:00
Merge pull request #420 from bbassie/feature/rocket-info-gui
Migrate rocket info gui to scenario and fix for Space Age
This commit is contained in:
@@ -22,7 +22,6 @@ return {
|
|||||||
--"modules.data.toolbar",
|
--"modules.data.toolbar",
|
||||||
|
|
||||||
--- GUI
|
--- GUI
|
||||||
"modules.gui.rocket-info",
|
|
||||||
"modules.gui.warp-list",
|
"modules.gui.warp-list",
|
||||||
"modules.gui.player-list",
|
"modules.gui.player-list",
|
||||||
"modules.gui.vlayer",
|
"modules.gui.vlayer",
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ local default = Roles.new_role("Guest", "")
|
|||||||
"command/data-preference",
|
"command/data-preference",
|
||||||
"command/connect",
|
"command/connect",
|
||||||
"gui/player-list",
|
"gui/player-list",
|
||||||
--"gui/rocket-info",
|
"gui/rocket-info",
|
||||||
"gui/science-info",
|
"gui/science-info",
|
||||||
"gui/task-list",
|
"gui/task-list",
|
||||||
"gui/warp-list",
|
"gui/warp-list",
|
||||||
|
|||||||
@@ -14,46 +14,6 @@ ban-player=Ban player
|
|||||||
afk-time=__1__% of total map time\nLast moved __2__ ago
|
afk-time=__1__% of total map time\nLast moved __2__ ago
|
||||||
open-map=__1__ __2__\n__3__\nClick to open map
|
open-map=__1__ __2__\n__3__\nClick to open map
|
||||||
|
|
||||||
[rocket-info]
|
|
||||||
main-tooltip=Rocket Info
|
|
||||||
launch-tooltip=Launch rocket
|
|
||||||
launch-tooltip-disabled=Launch rocket (not ready)
|
|
||||||
toggle-rocket-tooltip=Disable auto launch
|
|
||||||
toggle-rocket-tooltip-disabled=Enable auto launch
|
|
||||||
toggle-section-tooltip=Expand Section
|
|
||||||
toggle-section-collapse-tooltip=Collapse Section
|
|
||||||
section-caption-stats=Statistics
|
|
||||||
section-tooltip-stats=Statistics about how rockets are launched
|
|
||||||
section-caption-milestones=Milestones
|
|
||||||
section-tooltip-milestones=The times when milestones were met
|
|
||||||
section-caption-progress=Build Progress
|
|
||||||
section-tooltip-progress=The progress for your rocket silos
|
|
||||||
progress-no-silos=You have no rocket silos
|
|
||||||
data-caption-first-launch=First Launch
|
|
||||||
data-tooltip-first-launch=The time of the first launch
|
|
||||||
data-caption-last-launch=Last Launch
|
|
||||||
data-tooltip-last-launch=The time of the last launch
|
|
||||||
data-caption-fastest-launch=Fastest Launch
|
|
||||||
data-tooltip-fastest-launch=The time taken for the fastest launch
|
|
||||||
data-caption-total-rockets=Total Launched
|
|
||||||
data-tooltip-total-rockets=Total number of rockets launched by your force
|
|
||||||
value-tooltip-total-rockets=__1__% of all rockets on this map
|
|
||||||
data-caption-avg-launch=Average Time
|
|
||||||
data-tooltip-avg-launch=The average amount of time taken to launch a rocket
|
|
||||||
data-caption-avg-launch-n=Average Time __1__
|
|
||||||
data-tooltip-avg-launch-n=The average amount of time taken to launch the last __1__ rockets
|
|
||||||
data-caption-milestone-n=Milestone __1__
|
|
||||||
data-tooltip-milestone-n=Time taken to each __1__ rockets
|
|
||||||
data-caption-milestone-next=N/A
|
|
||||||
data-tooltip-milestone-next=Not yet achieved
|
|
||||||
progress-x-pos=X __1__
|
|
||||||
progress-y-pos=Y __1__
|
|
||||||
progress-label-tooltip=View on map
|
|
||||||
progress-launched=Launched
|
|
||||||
progress-caption=__1__%
|
|
||||||
progress-tooltip=This silo has launched __1__ rockets
|
|
||||||
launch-failed=Failed to launch rocket, please wait a few seconds and try again.
|
|
||||||
|
|
||||||
[warp-list]
|
[warp-list]
|
||||||
main-caption=Warp List [img=info]
|
main-caption=Warp List [img=info]
|
||||||
main-tooltip=Warp List
|
main-tooltip=Warp List
|
||||||
|
|||||||
@@ -14,46 +14,6 @@ ban-player=封禁用戶
|
|||||||
afk-time=__1__% 地圖時間\n上次移動: __2__
|
afk-time=__1__% 地圖時間\n上次移動: __2__
|
||||||
open-map=__1__ __2__\n__3__\n按下打開地圖
|
open-map=__1__ __2__\n__3__\n按下打開地圖
|
||||||
|
|
||||||
[rocket-info]
|
|
||||||
main-tooltip=火箭資訊
|
|
||||||
launch-tooltip=發射火箭
|
|
||||||
launch-tooltip-disabled=發射火箭 (未準備)
|
|
||||||
toggle-rocket-tooltip=取消自動發射
|
|
||||||
toggle-rocket-tooltip-disabled=啟用自動發射
|
|
||||||
toggle-section-tooltip=擴張欄
|
|
||||||
toggle-section-collapse-tooltip=收縮欄
|
|
||||||
section-caption-stats=數據
|
|
||||||
section-tooltip-stats=火箭發射數據
|
|
||||||
section-caption-milestones=里程碑
|
|
||||||
section-tooltip-milestones=里程碑達成次數
|
|
||||||
section-caption-progress=建造程度
|
|
||||||
section-tooltip-progress=火箭建造程度
|
|
||||||
progress-no-silos=你沒有火箭發射井
|
|
||||||
data-caption-first-launch=首次發射
|
|
||||||
data-tooltip-first-launch=首次發射時間
|
|
||||||
data-caption-last-launch=最後發射
|
|
||||||
data-tooltip-last-launch=最後發射時間
|
|
||||||
data-caption-fastest-launch=最快發射
|
|
||||||
data-tooltip-fastest-launch=最快發射時間
|
|
||||||
data-caption-total-rockets=總發射次數
|
|
||||||
data-tooltip-total-rockets=我方總發射次數
|
|
||||||
value-tooltip-total-rockets=__1__% 的火箭發射都在本地圖上。
|
|
||||||
data-caption-avg-launch=平均時間
|
|
||||||
data-tooltip-avg-launch=火箭發射平均時間
|
|
||||||
data-caption-avg-launch-n=平均時間 __1__
|
|
||||||
data-tooltip-avg-launch-n=__1__ 次火箭發射的平均時間
|
|
||||||
data-caption-milestone-n=里程碑 __1__
|
|
||||||
data-tooltip-milestone-n=__1__ 次火箭發射的時間
|
|
||||||
data-caption-milestone-next=N/A
|
|
||||||
data-tooltip-milestone-next=未達成
|
|
||||||
progress-x-pos=X __1__
|
|
||||||
progress-y-pos=Y __1__
|
|
||||||
progress-label-tooltip=在地圖上看
|
|
||||||
progress-launched=已發射
|
|
||||||
progress-caption=__1__ %
|
|
||||||
progress-tooltip=該火箭發射井發射了 __1__ 次
|
|
||||||
launch-failed=火箭發射失敗, 請過一會再試。
|
|
||||||
|
|
||||||
[warp-list]
|
[warp-list]
|
||||||
main-caption=傳送陣清單 [img=info]
|
main-caption=傳送陣清單 [img=info]
|
||||||
main-tooltip=傳送陣清單
|
main-tooltip=傳送陣清單
|
||||||
|
|||||||
@@ -14,46 +14,6 @@ ban-player=封禁用戶
|
|||||||
afk-time=__1__% 地圖時間\n上次移動: __2__
|
afk-time=__1__% 地圖時間\n上次移動: __2__
|
||||||
open-map=__1__ __2__\n__3__\n按下打開地圖
|
open-map=__1__ __2__\n__3__\n按下打開地圖
|
||||||
|
|
||||||
[rocket-info]
|
|
||||||
main-tooltip=火箭資訊
|
|
||||||
launch-tooltip=發射火箭
|
|
||||||
launch-tooltip-disabled=發射火箭 (未準備)
|
|
||||||
toggle-rocket-tooltip=取消自動發射
|
|
||||||
toggle-rocket-tooltip-disabled=啟用自動發射
|
|
||||||
toggle-section-tooltip=擴張欄
|
|
||||||
toggle-section-collapse-tooltip=收縮欄
|
|
||||||
section-caption-stats=數據
|
|
||||||
section-tooltip-stats=火箭發射數據
|
|
||||||
section-caption-milestones=里程碑
|
|
||||||
section-tooltip-milestones=里程碑達成次數
|
|
||||||
section-caption-progress=建造程度
|
|
||||||
section-tooltip-progress=火箭建造程度
|
|
||||||
progress-no-silos=你沒有火箭發射井
|
|
||||||
data-caption-first-launch=首次發射
|
|
||||||
data-tooltip-first-launch=首次發射時間
|
|
||||||
data-caption-last-launch=最後發射
|
|
||||||
data-tooltip-last-launch=最後發射時間
|
|
||||||
data-caption-fastest-launch=最快發射
|
|
||||||
data-tooltip-fastest-launch=最快發射時間
|
|
||||||
data-caption-total-rockets=總發射次數
|
|
||||||
data-tooltip-total-rockets=我方總發射次數
|
|
||||||
value-tooltip-total-rockets=__1__% 的火箭發射都在本地圖上。
|
|
||||||
data-caption-avg-launch=平均時間
|
|
||||||
data-tooltip-avg-launch=火箭發射平均時間
|
|
||||||
data-caption-avg-launch-n=平均時間 __1__
|
|
||||||
data-tooltip-avg-launch-n=__1__ 次火箭發射的平均時間
|
|
||||||
data-caption-milestone-n=里程碑 __1__
|
|
||||||
data-tooltip-milestone-n=__1__ 次火箭發射的時間
|
|
||||||
data-caption-milestone-next=N/A
|
|
||||||
data-tooltip-milestone-next=未達成
|
|
||||||
progress-x-pos=X __1__
|
|
||||||
progress-y-pos=Y __1__
|
|
||||||
progress-label-tooltip=在地圖上看
|
|
||||||
progress-launched=已發射
|
|
||||||
progress-caption=__1__ %
|
|
||||||
progress-tooltip=該火箭發射井發射了 __1__ 次
|
|
||||||
launch-failed=火箭發射失敗, 請過一會再試。
|
|
||||||
|
|
||||||
[warp-list]
|
[warp-list]
|
||||||
main-caption=傳送陣清單 [img=info]
|
main-caption=傳送陣清單 [img=info]
|
||||||
main-tooltip=傳送陣清單
|
main-tooltip=傳送陣清單
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
--[[-- Control Module - Rockets
|
|
||||||
- Stores rocket stats for each force.
|
|
||||||
@control Rockets
|
|
||||||
@alias Rockets
|
|
||||||
|
|
||||||
@usage
|
|
||||||
-- import the module from the control modules
|
|
||||||
local Rockets = require("modules.exp_legacy.modules.control.rockets") --- @dep modules.control.rockets
|
|
||||||
|
|
||||||
-- Some basic information is stored for each silo that has been built
|
|
||||||
-- the data includes: the tick it was built, the rockets launched from it and more
|
|
||||||
Rockets.get_silo_data(rocket_silo_entity)
|
|
||||||
|
|
||||||
-- Some information is also stored for each force
|
|
||||||
Rockets.get_stats('player')
|
|
||||||
|
|
||||||
-- You can get the rocket data for all silos for a force by using get_silos
|
|
||||||
Rockets.get_silos('player')
|
|
||||||
|
|
||||||
-- You can get the launch time for a rocket, meaning what game tick the 50th rocket was launched
|
|
||||||
Rockets.get_rocket_time('player', 50)
|
|
||||||
|
|
||||||
-- The rolling average will work out the time to launch one rocket based on the last X rockets
|
|
||||||
Rockets.get_rolling_average('player', 10)
|
|
||||||
|
|
||||||
]]
|
|
||||||
|
|
||||||
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
|
||||||
local Storage = require("modules/exp_util/storage")
|
|
||||||
local config = require("modules.exp_legacy.config.gui.rockets") --- @dep config.rockets
|
|
||||||
|
|
||||||
local largest_rolling_avg = 0
|
|
||||||
for _, avg_over in pairs(config.stats.rolling_avg) do
|
|
||||||
if avg_over > largest_rolling_avg then
|
|
||||||
largest_rolling_avg = avg_over
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local Rockets = {
|
|
||||||
times = {},
|
|
||||||
stats = {},
|
|
||||||
silos = {},
|
|
||||||
}
|
|
||||||
|
|
||||||
local rocket_times = Rockets.times
|
|
||||||
local rocket_stats = Rockets.stats
|
|
||||||
local rocket_silos = Rockets.silos
|
|
||||||
Storage.register({
|
|
||||||
rocket_times = rocket_times,
|
|
||||||
rocket_stats = rocket_stats,
|
|
||||||
rocket_silos = rocket_silos,
|
|
||||||
}, function(tbl)
|
|
||||||
Rockets.times = tbl.rocket_times
|
|
||||||
Rockets.stats = tbl.rocket_stats
|
|
||||||
Rockets.silos = tbl.rocket_silos
|
|
||||||
rocket_times = Rockets.times
|
|
||||||
rocket_stats = Rockets.stats
|
|
||||||
rocket_silos = Rockets.silos
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Gets the silo data for a given silo entity
|
|
||||||
--- @param silo LuaEntity Rocket silo entity
|
|
||||||
--- @return table # Data table for this silo, contains rockets launch, silo status, and its force
|
|
||||||
function Rockets.get_silo_data(silo)
|
|
||||||
return rocket_silos[silo.unit_number]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the silo entity from its silo name, reverse to get_silo_data
|
|
||||||
--- @param silo_name string Silo name that is stored in its data
|
|
||||||
--- @return LuaEntity # Rocket silo entity
|
|
||||||
function Rockets.get_silo_entity(silo_name)
|
|
||||||
return rocket_silos[tonumber(silo_name)].entity
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the rocket stats for a force
|
|
||||||
--- @param force_name string Name of the force to get the stats for
|
|
||||||
--- @return table # Stats for the force
|
|
||||||
function Rockets.get_stats(force_name)
|
|
||||||
return rocket_stats[force_name] or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets all the rocket silos that belong to a force
|
|
||||||
--- @param force_name string Name of the force to get the silos for
|
|
||||||
--- @return table # Array of silo data that all belong to this force
|
|
||||||
function Rockets.get_silos(force_name)
|
|
||||||
local rtn = {}
|
|
||||||
for _, silo_data in pairs(rocket_silos) do
|
|
||||||
if silo_data.force == force_name then
|
|
||||||
table.insert(rtn, silo_data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return rtn
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the launch time of a given rocket, due to cleaning not all counts are valid
|
|
||||||
--- @param force_name string Name of the force to get the count for
|
|
||||||
--- @param rocket_number number Number of the rocket to get the launch time for
|
|
||||||
--- @return number? # Game tick that the rocket was launched on
|
|
||||||
function Rockets.get_rocket_time(force_name, rocket_number)
|
|
||||||
return rocket_times[force_name] and rocket_times[force_name][rocket_number] or nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the number of rockets that a force has launched
|
|
||||||
--- @param force_name string the name of the force to get the count for
|
|
||||||
--- @return number # Number of rockets that the force has launched
|
|
||||||
function Rockets.get_rocket_count(force_name)
|
|
||||||
local force = game.forces[force_name]
|
|
||||||
return force.rockets_launched
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the total number of rockets launched by all forces
|
|
||||||
--- @return number # Total number of rockets launched this game
|
|
||||||
function Rockets.get_game_rocket_count()
|
|
||||||
local rtn = 0
|
|
||||||
for _, force in pairs(game.forces) do
|
|
||||||
rtn = rtn + force.rockets_launched
|
|
||||||
end
|
|
||||||
|
|
||||||
return rtn
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the rolling average time to launch a rocket
|
|
||||||
--- @param force_name string Name of the force to get the average for
|
|
||||||
--- @param count number Distance to get the rolling average over
|
|
||||||
--- @return number # Number of ticks required to launch one rocket
|
|
||||||
function Rockets.get_rolling_average(force_name, count)
|
|
||||||
local force = game.forces[force_name]
|
|
||||||
local rocket_count = force.rockets_launched
|
|
||||||
if rocket_count == 0 then return 0 end
|
|
||||||
local last_launch_time = rocket_times[force_name][rocket_count]
|
|
||||||
local start_rocket_time = 0
|
|
||||||
if count < rocket_count then
|
|
||||||
start_rocket_time = rocket_times[force_name][rocket_count - count + 1]
|
|
||||||
rocket_count = count
|
|
||||||
end
|
|
||||||
return math.floor((last_launch_time - start_rocket_time) / rocket_count)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- When a launch is trigger it will wait for the silo to reset
|
|
||||||
--- @param event EventData.on_rocket_launch_ordered
|
|
||||||
Event.add(defines.events.on_rocket_launch_ordered, function(event)
|
|
||||||
local silo_data = Rockets.get_silo_data(event.rocket_silo)
|
|
||||||
assert(silo_data, "Rocket silo missing data: " .. tostring(event.rocket_silo))
|
|
||||||
silo_data.launched = silo_data.launched + 1
|
|
||||||
silo_data.awaiting_reset = true
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Event used to update the stats and the hui when a rocket is launched
|
|
||||||
--- @param event EventData.on_cargo_pod_finished_ascending
|
|
||||||
Event.add(defines.events.on_cargo_pod_finished_ascending, function(event)
|
|
||||||
local force = event.cargo_pod.force
|
|
||||||
local force_name = force.name
|
|
||||||
local rockets_launched = force.rockets_launched
|
|
||||||
|
|
||||||
--- Handles updates to the rocket stats
|
|
||||||
local stats = rocket_stats[force_name]
|
|
||||||
if not stats then
|
|
||||||
rocket_stats[force_name] = {}
|
|
||||||
stats = rocket_stats[force_name]
|
|
||||||
end
|
|
||||||
|
|
||||||
if rockets_launched == 1 then
|
|
||||||
stats.first_launch = event.tick
|
|
||||||
stats.fastest_launch = event.tick
|
|
||||||
elseif event.tick - stats.last_launch < stats.fastest_launch then
|
|
||||||
stats.fastest_launch = event.tick - stats.last_launch
|
|
||||||
end
|
|
||||||
|
|
||||||
stats.last_launch = event.tick
|
|
||||||
|
|
||||||
--- Appends the new rocket into the array
|
|
||||||
if not rocket_times[force_name] then
|
|
||||||
rocket_times[force_name] = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
rocket_times[force_name][rockets_launched] = event.tick
|
|
||||||
|
|
||||||
local remove_rocket = rockets_launched - largest_rolling_avg
|
|
||||||
if remove_rocket > 0 and not table.contains(config.milestones, remove_rocket) then
|
|
||||||
rocket_times[force_name][remove_rocket] = nil
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Adds a silo to the list when it is built
|
|
||||||
--- @param event EventData.on_built_entity | EventData.on_robot_built_entity
|
|
||||||
local function on_built(event)
|
|
||||||
local entity = event.entity
|
|
||||||
if entity.valid and entity.name == "rocket-silo" then
|
|
||||||
rocket_silos[entity.unit_number] = {
|
|
||||||
name = tostring(entity.unit_number),
|
|
||||||
force = entity.force.name,
|
|
||||||
entity = entity,
|
|
||||||
launched = 0,
|
|
||||||
awaiting_reset = false,
|
|
||||||
built = game.tick,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Event.add(defines.events.on_built_entity, on_built)
|
|
||||||
Event.add(defines.events.on_robot_built_entity, on_built)
|
|
||||||
|
|
||||||
return Rockets
|
|
||||||
@@ -1,587 +0,0 @@
|
|||||||
--[[-- Gui Module - Rocket Info
|
|
||||||
- Adds a rocket infomation gui which shows general stats, milestones and build progress of rockets
|
|
||||||
@gui Rocket-Info
|
|
||||||
@alias rocket_info
|
|
||||||
]]
|
|
||||||
|
|
||||||
local ExpUtil = require("modules/exp_util")
|
|
||||||
local Gui = require("modules/exp_gui")
|
|
||||||
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
|
|
||||||
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
|
||||||
local config = require("modules.exp_legacy.config.gui.rockets") --- @dep config.gui.rockets
|
|
||||||
local Colors = require("modules/exp_util/include/color")
|
|
||||||
local Rockets = require("modules.exp_legacy.modules.control.rockets") --- @dep modules.control.rockets
|
|
||||||
|
|
||||||
local time_formats = {
|
|
||||||
caption = ExpUtil.format_time_factory_locale{ format = "short", minutes = true, seconds = true },
|
|
||||||
caption_hours = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true },
|
|
||||||
tooltip = ExpUtil.format_time_factory_locale{ format = "long", minutes = true, seconds = true },
|
|
||||||
tooltip_hours = ExpUtil.format_time_factory_locale{ format = "long", hours = true, minutes = true, seconds = true },
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Check if a player is allowed to use certain interactions
|
|
||||||
local function check_player_permissions(player, action)
|
|
||||||
if not config.progress["allow_" .. action] then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if config.progress[action .. "_admins_only"] and not player.admin then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if config.progress[action .. "_role_permission"]
|
|
||||||
and not Roles.player_allowed(player, config.progress[action .. "_role_permission"]) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Button to toggle the auto launch on a rocket silo
|
|
||||||
-- @element toggle_launch
|
|
||||||
local toggle_launch = Gui.define("toggle_launch")
|
|
||||||
:draw{
|
|
||||||
type = "sprite-button",
|
|
||||||
sprite = "utility/play",
|
|
||||||
tooltip = { "rocket-info.toggle-rocket-tooltip" },
|
|
||||||
name = Gui.from_name,
|
|
||||||
}
|
|
||||||
:style(Gui.styles.sprite{
|
|
||||||
size = 16,
|
|
||||||
})
|
|
||||||
:on_click(function(def, player, element)
|
|
||||||
local rocket_silo_name = element.parent.name:sub(8)
|
|
||||||
local rocket_silo = Rockets.get_silo_entity(rocket_silo_name)
|
|
||||||
if rocket_silo.auto_launch then
|
|
||||||
element.sprite = "utility/play"
|
|
||||||
element.tooltip = { "rocket-info.toggle-rocket-tooltip" }
|
|
||||||
rocket_silo.auto_launch = false
|
|
||||||
else
|
|
||||||
element.sprite = "utility/stop"
|
|
||||||
element.tooltip = { "rocket-info.toggle-rocket-tooltip-disabled" }
|
|
||||||
rocket_silo.auto_launch = true
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- XY cords that allow zoom to map when pressed
|
|
||||||
-- @element silo_cords
|
|
||||||
local silo_cords = Gui.define("silo_cords")
|
|
||||||
:draw(function(definition, parent, silo_data)
|
|
||||||
local silo_name = silo_data.silo_name
|
|
||||||
local pos = silo_data.position
|
|
||||||
local tooltip = config.progress.allow_zoom_to_map and { "rocket-info.progress-label-tooltip" } or nil
|
|
||||||
|
|
||||||
-- Add the x cord flow
|
|
||||||
local flow_x = parent.add{
|
|
||||||
type = "flow",
|
|
||||||
name = "label-x-" .. silo_name,
|
|
||||||
caption = silo_name,
|
|
||||||
}
|
|
||||||
flow_x.style.padding = { 0, 2, 0, 1 }
|
|
||||||
|
|
||||||
-- Add the x cord label
|
|
||||||
local label_x = flow_x.add{
|
|
||||||
type = "label",
|
|
||||||
caption = { "rocket-info.progress-x-pos", pos.x },
|
|
||||||
tooltip = tooltip,
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Add the y cord flow
|
|
||||||
local flow_y = parent.add{
|
|
||||||
type = "flow",
|
|
||||||
name = "label-y-" .. silo_name,
|
|
||||||
caption = silo_name,
|
|
||||||
}
|
|
||||||
flow_y.style.padding = { 0, 2, 0, 1 }
|
|
||||||
|
|
||||||
-- Add the y cord label
|
|
||||||
local label_y = flow_y.add{
|
|
||||||
type = "label",
|
|
||||||
caption = { "rocket-info.progress-y-pos", pos.y },
|
|
||||||
tooltip = tooltip,
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.progress.allow_zoom_to_map then
|
|
||||||
definition:link_element(label_x)
|
|
||||||
definition:link_element(label_y)
|
|
||||||
end
|
|
||||||
|
|
||||||
return Gui.no_return()
|
|
||||||
end)
|
|
||||||
:on_click(function(def, player, element)
|
|
||||||
local rocket_silo_name = element.parent.caption
|
|
||||||
local rocket_silo = Rockets.get_silo_entity(rocket_silo_name)
|
|
||||||
player.set_controller{ type = defines.controllers.remote, position = rocket_silo.position, surface = rocket_silo.surface }
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Base element for each rocket in the progress list
|
|
||||||
-- @element rocket_entry
|
|
||||||
local rocket_entry = Gui.define("rocket_entry")
|
|
||||||
:draw(function(_, parent, silo_data)
|
|
||||||
local silo_name = silo_data.silo_name
|
|
||||||
local player = Gui.get_player(parent)
|
|
||||||
|
|
||||||
-- Add the toggle auto launch if the player is allowed it
|
|
||||||
-- Auto launch was removed from the api and no 2.0 equivalent was added
|
|
||||||
-- https://forums.factorio.com/viewtopic.php?f=28&t=118065&p=656502
|
|
||||||
if check_player_permissions(player, "toggle_active") then
|
|
||||||
parent.add{ type = "flow" }
|
|
||||||
--[[local flow = parent.add{ type = "flow", name = "toggle-" .. silo_name }
|
|
||||||
local button = toggle_launch(flow)
|
|
||||||
button.tooltip = silo_data.toggle_tooltip
|
|
||||||
button.sprite = silo_data.toggle_sprite]]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Draw the silo cords element
|
|
||||||
silo_cords(parent, silo_data)
|
|
||||||
|
|
||||||
-- Add a progress label
|
|
||||||
local alignment = Gui.elements.aligned_flow(parent, { name = silo_name })
|
|
||||||
local element =
|
|
||||||
alignment.add{
|
|
||||||
type = "label",
|
|
||||||
name = "label",
|
|
||||||
caption = silo_data.progress_caption,
|
|
||||||
tooltip = silo_data.progress_tooltip,
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Return the progress label
|
|
||||||
return element
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Data label which contains a name and a value label pair
|
|
||||||
-- @element data_label
|
|
||||||
local data_label = Gui.define("data_label")
|
|
||||||
:draw(function(_, parent, label_data)
|
|
||||||
local data_name = label_data.name
|
|
||||||
local data_subname = label_data.subname
|
|
||||||
local data_fullname = data_subname and data_name .. data_subname or data_name
|
|
||||||
|
|
||||||
-- Add the name label
|
|
||||||
local name_label = parent.add{
|
|
||||||
type = "label",
|
|
||||||
name = data_fullname .. "-label",
|
|
||||||
caption = { "rocket-info.data-caption-" .. data_name, data_subname },
|
|
||||||
tooltip = { "rocket-info.data-tooltip-" .. data_name, data_subname },
|
|
||||||
}
|
|
||||||
name_label.style.padding = { 0, 2 }
|
|
||||||
|
|
||||||
--- Right aligned label to store the data
|
|
||||||
local alignment = Gui.elements.aligned_flow(parent, { name = data_fullname })
|
|
||||||
local element =
|
|
||||||
alignment.add{
|
|
||||||
type = "label",
|
|
||||||
name = "label",
|
|
||||||
caption = label_data.value,
|
|
||||||
tooltip = label_data.tooltip,
|
|
||||||
}
|
|
||||||
element.style.padding = { 0, 2 }
|
|
||||||
|
|
||||||
return element
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Used to update the captions and tooltips on the data labels
|
|
||||||
local function update_data_labels(parent, data_label_data)
|
|
||||||
for _, label_data in ipairs(data_label_data) do
|
|
||||||
local data_name = label_data.subname and label_data.name .. label_data.subname or label_data.name
|
|
||||||
if not parent[data_name] then
|
|
||||||
data_label(parent, label_data)
|
|
||||||
else
|
|
||||||
local data_label_element = parent[data_name].label
|
|
||||||
data_label_element.tooltip = label_data.tooltip
|
|
||||||
data_label_element.caption = label_data.value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_progress_data(force_name)
|
|
||||||
local force_silos = Rockets.get_silos(force_name)
|
|
||||||
local progress_data = {}
|
|
||||||
|
|
||||||
for _, silo_data in pairs(force_silos) do
|
|
||||||
local rocket_silo = silo_data.entity
|
|
||||||
if not rocket_silo or not rocket_silo.valid then
|
|
||||||
-- Remove from list if not valid
|
|
||||||
force_silos[silo_data.name] = nil
|
|
||||||
table.insert(progress_data, {
|
|
||||||
silo_name = silo_data.name,
|
|
||||||
remove = true,
|
|
||||||
})
|
|
||||||
else
|
|
||||||
-- Get the progress caption and tooltip
|
|
||||||
local progress_color = Colors.white
|
|
||||||
local progress_caption = { "rocket-info.progress-caption", rocket_silo.rocket_parts }
|
|
||||||
local progress_tooltip = { "rocket-info.progress-tooltip", silo_data.launched or 0 }
|
|
||||||
local status = rocket_silo.status == defines.entity_status.waiting_to_launch_rocket
|
|
||||||
if status and silo_data.awaiting_reset then
|
|
||||||
progress_caption = { "rocket-info.progress-launched" }
|
|
||||||
progress_color = Colors.green
|
|
||||||
elseif status then
|
|
||||||
progress_caption = { "rocket-info.progress-caption", 100 }
|
|
||||||
progress_color = Colors.cyan
|
|
||||||
else
|
|
||||||
silo_data.awaiting_reset = false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get the toggle button data
|
|
||||||
local toggle_tooltip = { "rocket-info.toggle-rocket-tooltip-disabled" }
|
|
||||||
local toggle_sprite = "utility/play"
|
|
||||||
if false --[[rocket_silo.auto_launch]] then
|
|
||||||
toggle_tooltip = { "rocket-info.toggle-rocket-tooltip" }
|
|
||||||
toggle_sprite = "utility/stop"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Insert the gui data
|
|
||||||
table.insert(progress_data, {
|
|
||||||
silo_name = silo_data.name,
|
|
||||||
position = rocket_silo.position,
|
|
||||||
allow_launch = not silo_data.awaiting_reset and status or false,
|
|
||||||
progress_color = progress_color,
|
|
||||||
progress_caption = progress_caption,
|
|
||||||
progress_tooltip = progress_tooltip,
|
|
||||||
toggle_tooltip = toggle_tooltip,
|
|
||||||
toggle_sprite = toggle_sprite,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return progress_data
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Update the build progress section
|
|
||||||
local function update_build_progress(parent, progress_data)
|
|
||||||
local show_message = true
|
|
||||||
for _, silo_data in ipairs(progress_data) do
|
|
||||||
parent.parent.no_silos.visible = false
|
|
||||||
parent.visible = true
|
|
||||||
local silo_name = silo_data.silo_name
|
|
||||||
local progress_label = parent[silo_name]
|
|
||||||
if silo_data.remove then
|
|
||||||
-- Remove the rocket from the list
|
|
||||||
Gui.destroy_if_valid(parent["toggle-" .. silo_name])
|
|
||||||
Gui.destroy_if_valid(parent["launch-" .. silo_name])
|
|
||||||
Gui.destroy_if_valid(parent["label-x-" .. silo_name])
|
|
||||||
Gui.destroy_if_valid(parent["label-y-" .. silo_name])
|
|
||||||
Gui.destroy_if_valid(parent[silo_name])
|
|
||||||
elseif not progress_label then
|
|
||||||
-- Add the rocket to the list
|
|
||||||
show_message = false
|
|
||||||
rocket_entry(parent, silo_data)
|
|
||||||
else
|
|
||||||
show_message = false
|
|
||||||
-- Update the existing labels
|
|
||||||
progress_label = progress_label.label
|
|
||||||
progress_label.caption = silo_data.progress_caption
|
|
||||||
progress_label.tooltip = silo_data.progress_tooltip
|
|
||||||
progress_label.style.font_color = silo_data.progress_color
|
|
||||||
|
|
||||||
-- Update the toggle button
|
|
||||||
local toggle_button = parent["toggle-" .. silo_name]
|
|
||||||
if toggle_button then
|
|
||||||
toggle_button = toggle_button[toggle_launch.name]
|
|
||||||
toggle_button.tooltip = silo_data.toggle_tooltip
|
|
||||||
toggle_button.sprite = silo_data.toggle_sprite
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if show_message then
|
|
||||||
parent.parent.no_silos.visible = true
|
|
||||||
parent.visible = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the label data for all the different stats
|
|
||||||
local function get_stats_data(force_name)
|
|
||||||
local force_rockets = Rockets.get_rocket_count(force_name)
|
|
||||||
local stats = Rockets.get_stats(force_name)
|
|
||||||
local stats_data = {}
|
|
||||||
|
|
||||||
-- Format the first launch data
|
|
||||||
if config.stats.show_first_rocket then
|
|
||||||
local value = stats.first_launch or 0
|
|
||||||
table.insert(stats_data, {
|
|
||||||
name = "first-launch",
|
|
||||||
value = time_formats.caption_hours(value),
|
|
||||||
tooltip = time_formats.tooltip_hours(value),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Format the last launch data
|
|
||||||
if config.stats.show_last_rocket then
|
|
||||||
local value = stats.last_launch or 0
|
|
||||||
table.insert(stats_data, {
|
|
||||||
name = "last-launch",
|
|
||||||
value = time_formats.caption_hours(value),
|
|
||||||
tooltip = time_formats.tooltip_hours(value),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Format fastest launch data
|
|
||||||
if config.stats.show_fastest_rocket then
|
|
||||||
local value = stats.fastest_launch or 0
|
|
||||||
table.insert(stats_data, {
|
|
||||||
name = "fastest-launch",
|
|
||||||
value = time_formats.caption_hours(value),
|
|
||||||
tooltip = time_formats.tooltip_hours(value),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Format total rocket data
|
|
||||||
if config.stats.show_total_rockets then
|
|
||||||
local total_rockets = Rockets.get_game_rocket_count()
|
|
||||||
total_rockets = total_rockets == 0 and 1 or total_rockets
|
|
||||||
local percentage = math.round(force_rockets / total_rockets, 3) * 100
|
|
||||||
table.insert(stats_data, {
|
|
||||||
name = "total-rockets",
|
|
||||||
value = force_rockets,
|
|
||||||
tooltip = { "rocket-info.value-tooltip-total-rockets", percentage },
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Format game avg data
|
|
||||||
if config.stats.show_game_avg then
|
|
||||||
local avg = force_rockets > 0 and math.floor(game.tick / force_rockets) or 0
|
|
||||||
table.insert(stats_data, {
|
|
||||||
name = "avg-launch",
|
|
||||||
value = time_formats.caption(avg),
|
|
||||||
tooltip = time_formats.tooltip(avg),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Format rolling avg data
|
|
||||||
for _, avg_over in pairs(config.stats.rolling_avg) do
|
|
||||||
local avg = Rockets.get_rolling_average(force_name, avg_over)
|
|
||||||
table.insert(stats_data, {
|
|
||||||
name = "avg-launch-n",
|
|
||||||
subname = avg_over,
|
|
||||||
value = time_formats.caption(avg),
|
|
||||||
tooltip = time_formats.tooltip(avg),
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Return formated data
|
|
||||||
return stats_data
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the label data for the milestones
|
|
||||||
local function get_milestone_data(force_name)
|
|
||||||
local force_rockets = Rockets.get_rocket_count(force_name)
|
|
||||||
local milestone_data = {}
|
|
||||||
|
|
||||||
for _, milestone in ipairs(config.milestones) do
|
|
||||||
if milestone <= force_rockets then
|
|
||||||
local time = Rockets.get_rocket_time(force_name, milestone)
|
|
||||||
table.insert(milestone_data, {
|
|
||||||
name = "milestone-n",
|
|
||||||
subname = milestone,
|
|
||||||
value = time_formats.caption_hours(time),
|
|
||||||
tooltip = time_formats.tooltip_hours(time),
|
|
||||||
})
|
|
||||||
else
|
|
||||||
table.insert(milestone_data, {
|
|
||||||
name = "milestone-n",
|
|
||||||
subname = milestone,
|
|
||||||
value = { "rocket-info.data-caption-milestone-next" },
|
|
||||||
tooltip = { "rocket-info.data-tooltip-milestone-next" },
|
|
||||||
})
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return milestone_data
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Button to toggle a section dropdown
|
|
||||||
-- @element toggle_section
|
|
||||||
local toggle_section = Gui.define("rocket_info_toggle_section")
|
|
||||||
:draw{
|
|
||||||
type = "sprite-button",
|
|
||||||
sprite = "utility/expand",
|
|
||||||
hovered_sprite = "utility/expand",
|
|
||||||
tooltip = { "rocket-info.toggle-section-tooltip" },
|
|
||||||
style = "frame_action_button",
|
|
||||||
name = Gui.from_name,
|
|
||||||
}
|
|
||||||
:style(Gui.styles.sprite{
|
|
||||||
size = 20,
|
|
||||||
})
|
|
||||||
:on_click(function(def, player, element)
|
|
||||||
local header_flow = assert(element.parent)
|
|
||||||
local flow_name = header_flow.caption
|
|
||||||
local flow = header_flow.parent.parent[flow_name]
|
|
||||||
if Gui.toggle_visible_state(flow) then
|
|
||||||
element.sprite = "utility/collapse"
|
|
||||||
element.tooltip = { "rocket-info.toggle-section-collapse-tooltip" }
|
|
||||||
else
|
|
||||||
element.sprite = "utility/expand"
|
|
||||||
element.tooltip = { "rocket-info.toggle-section-tooltip" }
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Draw a section header and main scroll
|
|
||||||
-- @element rocket_list_container
|
|
||||||
local section = Gui.define("rocket_info_section")
|
|
||||||
:draw(function(definition, parent, section_name, table_size)
|
|
||||||
-- Draw the header for the section
|
|
||||||
local header = Gui.elements.header(parent, {
|
|
||||||
name = section_name .. "-header",
|
|
||||||
caption = { "rocket-info.section-caption-" .. section_name },
|
|
||||||
tooltip = { "rocket-info.section-tooltip-" .. section_name },
|
|
||||||
})
|
|
||||||
|
|
||||||
definition:link_element(header.label)
|
|
||||||
|
|
||||||
-- Right aligned button to toggle the section
|
|
||||||
header.caption = section_name
|
|
||||||
toggle_section(header)
|
|
||||||
|
|
||||||
-- Table used to store the data
|
|
||||||
local scroll_table = Gui.elements.scroll_table(parent, 215, table_size, section_name)
|
|
||||||
scroll_table.parent.visible = false
|
|
||||||
|
|
||||||
-- Return the flow table
|
|
||||||
return definition:unlink_element(scroll_table)
|
|
||||||
end)
|
|
||||||
:on_click(function(def, player, element, event)
|
|
||||||
event.element = element.parent.flow[toggle_section.name]
|
|
||||||
toggle_section:raise_event(event)
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Main gui container for the left flow
|
|
||||||
-- @element rocket_list_container
|
|
||||||
local rocket_list_container = Gui.define("rocket_list_container")
|
|
||||||
:draw(function(definition, parent)
|
|
||||||
-- Draw the internal container
|
|
||||||
local container = Gui.elements.container(parent, 200)
|
|
||||||
|
|
||||||
-- Set the container style
|
|
||||||
local style = container.style
|
|
||||||
style.padding = 0
|
|
||||||
|
|
||||||
local player = Gui.get_player(parent)
|
|
||||||
local force_name = player.force.name
|
|
||||||
-- Draw stats section
|
|
||||||
if config.stats.show_stats then
|
|
||||||
update_data_labels(section(container, "stats", 2), get_stats_data(force_name))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Draw milestones section
|
|
||||||
if config.milestones.show_milestones then
|
|
||||||
update_data_labels(section(container, "milestones", 2), get_milestone_data(force_name))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Draw build progress list
|
|
||||||
if config.progress.show_progress then
|
|
||||||
local col_count = 3
|
|
||||||
if check_player_permissions(player, "toggle_active") then col_count = col_count + 1 end
|
|
||||||
local progress = section(container, "progress", col_count)
|
|
||||||
-- Label used when there are no active silos
|
|
||||||
local no_silos = progress.parent.add{
|
|
||||||
type = "label",
|
|
||||||
name = "no_silos",
|
|
||||||
caption = { "rocket-info.progress-no-silos" },
|
|
||||||
}
|
|
||||||
no_silos.style.padding = { 1, 2 }
|
|
||||||
update_build_progress(progress, get_progress_data(force_name))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Return the external container
|
|
||||||
return container.parent
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Add the element to the left flow with a toolbar button
|
|
||||||
Gui.add_left_element(rocket_list_container, function(player, element)
|
|
||||||
return player.force.rockets_launched > 0 and Roles.player_allowed(player, "gui/rocket-info")
|
|
||||||
end)
|
|
||||||
Gui.toolbar.create_button{
|
|
||||||
name = "rocket_list_toggle",
|
|
||||||
left_element = rocket_list_container,
|
|
||||||
sprite = "item/rocket-silo",
|
|
||||||
tooltip = { "rocket-info.main-tooltip" },
|
|
||||||
visible = function(player, element)
|
|
||||||
return Roles.player_allowed(player, "gui/rocket-info")
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Update the gui for all players on a force
|
|
||||||
local function update_rocket_gui_all(force_name)
|
|
||||||
local stats = get_stats_data(force_name)
|
|
||||||
local milestones = get_milestone_data(force_name)
|
|
||||||
local progress = get_progress_data(force_name)
|
|
||||||
for _, player in pairs(game.forces[force_name].players) do
|
|
||||||
local container = Gui.get_left_element(rocket_list_container, player)
|
|
||||||
local frame = container.frame
|
|
||||||
update_data_labels(frame.stats.table, stats)
|
|
||||||
update_data_labels(frame.milestones.table, milestones)
|
|
||||||
update_build_progress(frame.progress.table, progress)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Event used to update the stats when a rocket is launched
|
|
||||||
--- @param event EventData.on_cargo_pod_finished_ascending
|
|
||||||
Event.add(defines.events.on_cargo_pod_finished_ascending, function(event)
|
|
||||||
update_rocket_gui_all(event.cargo_pod.force.name)
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Update only the progress gui for a force
|
|
||||||
local function update_rocket_gui_progress(force_name)
|
|
||||||
local progress = get_progress_data(force_name)
|
|
||||||
for _, player in pairs(game.forces[force_name].connected_players) do
|
|
||||||
local container = Gui.get_left_element(rocket_list_container, player)
|
|
||||||
local frame = container.frame
|
|
||||||
update_build_progress(frame.progress.table, progress)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Event used to set a rocket silo to be awaiting reset
|
|
||||||
--- @param event EventData.on_rocket_launch_ordered
|
|
||||||
Event.add(defines.events.on_rocket_launch_ordered, function(event)
|
|
||||||
update_rocket_gui_progress(event.rocket_silo.force.name)
|
|
||||||
end)
|
|
||||||
|
|
||||||
Event.on_nth_tick(150, function()
|
|
||||||
for _, force in pairs(game.forces) do
|
|
||||||
if #Rockets.get_silos(force.name) > 0 then
|
|
||||||
update_rocket_gui_progress(force.name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Adds a silo to the list when it is built
|
|
||||||
--- @param event EventData.on_built_entity | EventData.on_robot_built_entity | EventData.script_raised_built | EventData.script_raised_revive
|
|
||||||
local function on_built(event)
|
|
||||||
local entity = event.entity
|
|
||||||
if entity.valid and entity.name == "rocket-silo" then
|
|
||||||
update_rocket_gui_progress(entity.force.name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Event.add(defines.events.on_built_entity, on_built)
|
|
||||||
Event.add(defines.events.on_robot_built_entity, on_built)
|
|
||||||
Event.add(defines.events.script_raised_built, on_built)
|
|
||||||
Event.add(defines.events.script_raised_revive, on_built)
|
|
||||||
|
|
||||||
--- Redraw the progress section on role change
|
|
||||||
local function role_update_event(event)
|
|
||||||
if not config.progress.show_progress then return end
|
|
||||||
local player = game.players[event.player_index]
|
|
||||||
local container = Gui.get_left_element(rocket_list_container, player)
|
|
||||||
local progress_scroll = container.frame.progress
|
|
||||||
Gui.destroy_if_valid(progress_scroll.table)
|
|
||||||
|
|
||||||
local col_count = 3
|
|
||||||
if check_player_permissions(player, "toggle_active") then col_count = col_count + 1 end
|
|
||||||
local progress = progress_scroll.add{
|
|
||||||
type = "table",
|
|
||||||
name = "table",
|
|
||||||
column_count = col_count,
|
|
||||||
}
|
|
||||||
|
|
||||||
update_build_progress(progress, get_progress_data(player.force.name))
|
|
||||||
end
|
|
||||||
|
|
||||||
Event.add(Roles.events.on_role_assigned, role_update_event)
|
|
||||||
Event.add(Roles.events.on_role_unassigned, role_update_event)
|
|
||||||
|
|
||||||
return rocket_list_container
|
|
||||||
@@ -78,6 +78,7 @@ add(require("modules/exp_scenario/gui/production_stats"))
|
|||||||
add(require("modules/exp_scenario/gui/quick_actions"))
|
add(require("modules/exp_scenario/gui/quick_actions"))
|
||||||
add(require("modules/exp_scenario/gui/readme"))
|
add(require("modules/exp_scenario/gui/readme"))
|
||||||
add(require("modules/exp_scenario/gui/research_milestones"))
|
add(require("modules/exp_scenario/gui/research_milestones"))
|
||||||
|
add(require("modules/exp_scenario/gui/rocket_info"))
|
||||||
add(require("modules/exp_scenario/gui/science_production"))
|
add(require("modules/exp_scenario/gui/science_production"))
|
||||||
add(require("modules/exp_scenario/gui/surveillance"))
|
add(require("modules/exp_scenario/gui/surveillance"))
|
||||||
add(require("modules/exp_scenario/gui/task_list"))
|
add(require("modules/exp_scenario/gui/task_list"))
|
||||||
|
|||||||
@@ -0,0 +1,733 @@
|
|||||||
|
--[[-- Gui - Rocket Info
|
||||||
|
Adds a rocket information gui which shows general stats, milestones and build progress of rockets.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local ExpUtil = require("modules/exp_util")
|
||||||
|
local Gui = require("modules/exp_gui")
|
||||||
|
local Roles = require("modules/exp_legacy/expcore/roles")
|
||||||
|
local config = require("modules/exp_legacy/config/gui/rockets")
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements
|
||||||
|
local Elements = {}
|
||||||
|
|
||||||
|
local time_formats = {
|
||||||
|
caption = ExpUtil.format_time_factory_locale{ format = "short", minutes = true, seconds = true },
|
||||||
|
caption_hours = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true },
|
||||||
|
tooltip = ExpUtil.format_time_factory_locale{ format = "long", minutes = true, seconds = true },
|
||||||
|
tooltip_hours = ExpUtil.format_time_factory_locale{ format = "long", hours = true, minutes = true, seconds = true },
|
||||||
|
}
|
||||||
|
|
||||||
|
--- The font colours used for the build progress label
|
||||||
|
local font_color = {
|
||||||
|
neutral = { r = 1, g = 1, b = 1 },
|
||||||
|
waiting = { r = 0.3, g = 1, b = 1 },
|
||||||
|
launched = { r = 0.3, g = 1, b = 0.3 },
|
||||||
|
}
|
||||||
|
|
||||||
|
-- The largest rolling average is used to know when an old launch time can be discarded
|
||||||
|
local largest_rolling_avg = 0
|
||||||
|
for _, avg_over in pairs(config.stats.rolling_avg) do
|
||||||
|
if avg_over > largest_rolling_avg then
|
||||||
|
largest_rolling_avg = avg_over
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the total number of rockets launched by all forces
|
||||||
|
--- @return number
|
||||||
|
local function get_game_rocket_count()
|
||||||
|
local rtn = 0
|
||||||
|
for _, force in pairs(game.forces) do
|
||||||
|
rtn = rtn + force.rockets_launched
|
||||||
|
end
|
||||||
|
|
||||||
|
return rtn
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the rolling average time to launch a rocket based on the last count rockets
|
||||||
|
--- @param force LuaForce
|
||||||
|
--- @param count number Number of rockets to average over
|
||||||
|
--- @return number # Number of ticks required to launch one rocket
|
||||||
|
local function get_rolling_average(force, count)
|
||||||
|
local rocket_count = force.rockets_launched
|
||||||
|
if rocket_count == 0 then return 0 end
|
||||||
|
|
||||||
|
local times = Elements.container.get_launch_times(force)
|
||||||
|
local last_launch_time = times[rocket_count] or 0
|
||||||
|
local start_rocket_time = 0
|
||||||
|
if count < rocket_count then
|
||||||
|
start_rocket_time = times[rocket_count - count + 1] or 0
|
||||||
|
rocket_count = count
|
||||||
|
end
|
||||||
|
|
||||||
|
return math.floor((last_launch_time - start_rocket_time) / rocket_count)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle the visible state of a section, the section is stored in the element data
|
||||||
|
--- @class ExpGui_RocketInfo.elements.toggle_section_button: ExpElement
|
||||||
|
--- @field data table<LuaGuiElement, LuaGuiElement>
|
||||||
|
--- @overload fun(parent: LuaGuiElement, section: LuaGuiElement): LuaGuiElement
|
||||||
|
Elements.toggle_section_button = Gui.define("rocket_info/toggle_section_button")
|
||||||
|
:draw{
|
||||||
|
type = "sprite-button",
|
||||||
|
sprite = "utility/expand",
|
||||||
|
tooltip = { "exp-gui_rocket-info.tooltip-toggle-section-expand" },
|
||||||
|
style = "frame_action_button",
|
||||||
|
}
|
||||||
|
:style{
|
||||||
|
size = 20,
|
||||||
|
padding = -2,
|
||||||
|
}
|
||||||
|
:element_data(
|
||||||
|
Gui.from_argument(1)
|
||||||
|
)
|
||||||
|
:on_click(function(def, player, element)
|
||||||
|
--- @cast def ExpGui_RocketInfo.elements.toggle_section_button
|
||||||
|
local section = def.data[element]
|
||||||
|
if Gui.toggle_visible_state(section) then
|
||||||
|
element.sprite = "utility/collapse"
|
||||||
|
element.tooltip = { "exp-gui_rocket-info.tooltip-toggle-section-collapse" }
|
||||||
|
else
|
||||||
|
element.sprite = "utility/expand"
|
||||||
|
element.tooltip = { "exp-gui_rocket-info.tooltip-toggle-section-expand" }
|
||||||
|
end
|
||||||
|
end) --[[ @as any ]]
|
||||||
|
|
||||||
|
--- A clickable coordinate label which opens the silo location on the map when pressed
|
||||||
|
--- @class ExpGui_RocketInfo.elements.position_label: ExpElement
|
||||||
|
--- @field data table<LuaGuiElement, LuaEntity>
|
||||||
|
--- @overload fun(parent: LuaGuiElement, opts: { caption: LocalisedString, tooltip: LocalisedString?, entity: LuaEntity }): LuaGuiElement
|
||||||
|
Elements.position_label = Gui.define("rocket_info/position_label")
|
||||||
|
:draw{
|
||||||
|
type = "label",
|
||||||
|
caption = Gui.from_argument("caption"),
|
||||||
|
tooltip = Gui.from_argument("tooltip"),
|
||||||
|
}
|
||||||
|
:style{
|
||||||
|
padding = { 0, 2 },
|
||||||
|
}
|
||||||
|
:element_data(
|
||||||
|
Gui.from_argument("entity")
|
||||||
|
)
|
||||||
|
:on_click(function(def, player, element)
|
||||||
|
--- @cast def ExpGui_RocketInfo.elements.position_label
|
||||||
|
if not config.progress.allow_zoom_to_map then return end
|
||||||
|
local entity = def.data[element]
|
||||||
|
if not entity or not entity.valid then return end
|
||||||
|
player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface }
|
||||||
|
end) --[[ @as any ]]
|
||||||
|
|
||||||
|
--- Data table showing the launch statistics for a force
|
||||||
|
--- @class ExpGui_RocketInfo.elements.stats_table: ExpElement
|
||||||
|
--- @field data table<LuaGuiElement, table<string, LuaGuiElement>>
|
||||||
|
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
||||||
|
Elements.stats_table = Gui.define("rocket_info/stats_table")
|
||||||
|
:track_all_elements()
|
||||||
|
:element_data{}
|
||||||
|
:draw(function(def, parent)
|
||||||
|
return Gui.elements.scroll_table(parent, 215, 2)
|
||||||
|
end) --[[ @as any ]]
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.stats_table.row_data
|
||||||
|
--- @field key string Unique key used to look up the value label
|
||||||
|
--- @field name string Data name used to select the locale keys
|
||||||
|
--- @field subname number? Optional subname passed as a locale parameter
|
||||||
|
--- @field value LocalisedString
|
||||||
|
--- @field tooltip LocalisedString?
|
||||||
|
|
||||||
|
--- Compute the ordered stat rows for a force
|
||||||
|
--- @param force LuaForce
|
||||||
|
--- @return ExpGui_RocketInfo.elements.stats_table.row_data[]
|
||||||
|
function Elements.stats_table.calculate_row_data(force)
|
||||||
|
local stats = Elements.container.get_stats(force)
|
||||||
|
local force_rockets = force.rockets_launched
|
||||||
|
local rows = {}
|
||||||
|
|
||||||
|
if config.stats.show_first_rocket then
|
||||||
|
local value = stats.first_launch or 0
|
||||||
|
rows[#rows + 1] = { key = "first-launch", name = "first-launch", value = time_formats.caption_hours(value), tooltip = time_formats.tooltip_hours(value) }
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.stats.show_last_rocket then
|
||||||
|
local value = stats.last_launch or 0
|
||||||
|
rows[#rows + 1] = { key = "last-launch", name = "last-launch", value = time_formats.caption_hours(value), tooltip = time_formats.tooltip_hours(value) }
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.stats.show_fastest_rocket then
|
||||||
|
local value = stats.fastest_launch or 0
|
||||||
|
rows[#rows + 1] = { key = "fastest-launch", name = "fastest-launch", value = time_formats.caption_hours(value), tooltip = time_formats.tooltip_hours(value) }
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.stats.show_total_rockets then
|
||||||
|
local total_rockets = get_game_rocket_count()
|
||||||
|
if total_rockets == 0 then total_rockets = 1 end
|
||||||
|
local percentage = math.floor(force_rockets / total_rockets * 1000) / 10
|
||||||
|
rows[#rows + 1] = { key = "total-rockets", name = "total-rockets", value = tostring(force_rockets), tooltip = { "exp-gui_rocket-info.value-tooltip-total-rockets", percentage } }
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.stats.show_game_avg then
|
||||||
|
local avg = force_rockets > 0 and math.floor(game.tick / force_rockets) or 0
|
||||||
|
rows[#rows + 1] = { key = "avg-launch", name = "avg-launch", value = time_formats.caption(avg), tooltip = time_formats.tooltip(avg) }
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, avg_over in pairs(config.stats.rolling_avg) do
|
||||||
|
local avg = get_rolling_average(force, avg_over)
|
||||||
|
rows[#rows + 1] = { key = "avg-launch-n-" .. avg_over, name = "avg-launch-n", subname = avg_over, value = time_formats.caption(avg), tooltip = time_formats.tooltip(avg) }
|
||||||
|
end
|
||||||
|
|
||||||
|
return rows
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a stat row to the table and store its value label
|
||||||
|
--- @param stats_table LuaGuiElement
|
||||||
|
--- @param row_data ExpGui_RocketInfo.elements.stats_table.row_data
|
||||||
|
function Elements.stats_table.add_row(stats_table, row_data)
|
||||||
|
local labels = Elements.stats_table.data[stats_table]
|
||||||
|
local name_label = stats_table.add{
|
||||||
|
type = "label",
|
||||||
|
caption = { "exp-gui_rocket-info.data-caption-" .. row_data.name, row_data.subname },
|
||||||
|
tooltip = { "exp-gui_rocket-info.data-tooltip-" .. row_data.name, row_data.subname },
|
||||||
|
}
|
||||||
|
name_label.style.padding = { 0, 2 }
|
||||||
|
|
||||||
|
local value_label = stats_table.add{
|
||||||
|
type = "label",
|
||||||
|
caption = row_data.value,
|
||||||
|
tooltip = row_data.tooltip,
|
||||||
|
}
|
||||||
|
value_label.style.padding = { 0, 2 }
|
||||||
|
|
||||||
|
labels[row_data.key] = value_label
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the stats table, adding any rows that do not yet exist
|
||||||
|
--- @param stats_table LuaGuiElement
|
||||||
|
--- @param row_data ExpGui_RocketInfo.elements.stats_table.row_data[]
|
||||||
|
function Elements.stats_table.refresh(stats_table, row_data)
|
||||||
|
local labels = Elements.stats_table.data[stats_table]
|
||||||
|
for _, row in ipairs(row_data) do
|
||||||
|
local value_label = labels[row.key]
|
||||||
|
if value_label then
|
||||||
|
value_label.caption = row.value
|
||||||
|
value_label.tooltip = row.tooltip
|
||||||
|
else
|
||||||
|
Elements.stats_table.add_row(stats_table, row)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the stats table for a player, adding any rows that do not yet exist
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
function Elements.stats_table.refresh_player(player)
|
||||||
|
local force = player.force --[[ @as LuaForce ]]
|
||||||
|
local row_data = Elements.stats_table.calculate_row_data(force)
|
||||||
|
for _, stats_table in Elements.stats_table:online_elements(player) do
|
||||||
|
Elements.stats_table.refresh(stats_table, row_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the stats table for a force, adding any rows that do not yet exist
|
||||||
|
--- @param force LuaForce
|
||||||
|
function Elements.stats_table.refresh_force(force)
|
||||||
|
local row_data = Elements.stats_table.calculate_row_data(force)
|
||||||
|
for _, stats_table in Elements.stats_table:online_elements(force) do
|
||||||
|
Elements.stats_table.refresh(stats_table, row_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Data table showing the milestones for a force
|
||||||
|
--- @class ExpGui_RocketInfo.elements.milestones_table: ExpElement
|
||||||
|
--- @field data table<LuaGuiElement, table<number, LuaGuiElement>>
|
||||||
|
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
||||||
|
Elements.milestones_table = Gui.define("rocket_info/milestones_table")
|
||||||
|
:track_all_elements()
|
||||||
|
:element_data{}
|
||||||
|
:draw(function(def, parent)
|
||||||
|
return Gui.elements.scroll_table(parent, 215, 2)
|
||||||
|
end) --[[ @as any ]]
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.milestones_table.row_data
|
||||||
|
--- @field milestone number The milestone this row represents
|
||||||
|
--- @field value LocalisedString
|
||||||
|
--- @field tooltip LocalisedString
|
||||||
|
|
||||||
|
--- Compute the ordered milestone rows for a force, up to and including the next unachieved milestone
|
||||||
|
--- @param force LuaForce
|
||||||
|
--- @return ExpGui_RocketInfo.elements.milestones_table.row_data[]
|
||||||
|
function Elements.milestones_table.calculate_row_data(force)
|
||||||
|
local times = Elements.container.get_launch_times(force)
|
||||||
|
local force_rockets = force.rockets_launched
|
||||||
|
local rows = {}
|
||||||
|
|
||||||
|
for _, milestone in ipairs(config.milestones) do
|
||||||
|
-- The milestones config mixes the show_milestones flag with the milestone numbers
|
||||||
|
if type(milestone) == "number" then
|
||||||
|
if milestone <= force_rockets then
|
||||||
|
local time = times[milestone] or 0
|
||||||
|
rows[#rows + 1] = { milestone = milestone, value = time_formats.caption_hours(time), tooltip = time_formats.tooltip_hours(time) }
|
||||||
|
else
|
||||||
|
rows[#rows + 1] = { milestone = milestone, value = { "exp-gui_rocket-info.data-caption-milestone-next" }, tooltip = { "exp-gui_rocket-info.data-tooltip-milestone-next" } }
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return rows
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a milestone row to the table and store its value label
|
||||||
|
--- @param milestones_table LuaGuiElement
|
||||||
|
--- @param row_data ExpGui_RocketInfo.elements.milestones_table.row_data
|
||||||
|
function Elements.milestones_table.add_row(milestones_table, row_data)
|
||||||
|
local labels = Elements.milestones_table.data[milestones_table]
|
||||||
|
local name_label = milestones_table.add{
|
||||||
|
type = "label",
|
||||||
|
caption = { "exp-gui_rocket-info.data-caption-milestone-n", row_data.milestone },
|
||||||
|
tooltip = { "exp-gui_rocket-info.data-tooltip-milestone-n", row_data.milestone },
|
||||||
|
}
|
||||||
|
name_label.style.padding = { 0, 2 }
|
||||||
|
|
||||||
|
local value_label = milestones_table.add{
|
||||||
|
type = "label",
|
||||||
|
caption = row_data.value,
|
||||||
|
tooltip = row_data.tooltip,
|
||||||
|
}
|
||||||
|
value_label.style.padding = { 0, 2 }
|
||||||
|
|
||||||
|
labels[row_data.milestone] = value_label
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the milestones table, adding rows as new milestones become visible
|
||||||
|
--- @param milestones_table LuaGuiElement
|
||||||
|
--- @param row_data ExpGui_RocketInfo.elements.milestones_table.row_data[]
|
||||||
|
function Elements.milestones_table.refresh(milestones_table, row_data)
|
||||||
|
local labels = Elements.milestones_table.data[milestones_table]
|
||||||
|
for _, row in ipairs(row_data) do
|
||||||
|
local value_label = labels[row.milestone]
|
||||||
|
if value_label then
|
||||||
|
value_label.caption = row.value
|
||||||
|
value_label.tooltip = row.tooltip
|
||||||
|
else
|
||||||
|
Elements.milestones_table.add_row(milestones_table, row)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the milestones table for a player, adding rows as new milestones become visible
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
function Elements.milestones_table.refresh_player(player)
|
||||||
|
local force = player.force --[[ @as LuaForce ]]
|
||||||
|
local row_data = Elements.stats_table.calculate_row_data(force)
|
||||||
|
for _, stats_table in Elements.stats_table:online_elements(player) do
|
||||||
|
Elements.stats_table.refresh(stats_table, row_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the milestones table for a force, adding rows as new milestones become visible
|
||||||
|
--- @param force LuaForce
|
||||||
|
function Elements.milestones_table.refresh_force(force)
|
||||||
|
local row_data = Elements.stats_table.calculate_row_data(force)
|
||||||
|
for _, stats_table in Elements.stats_table:online_elements(force) do
|
||||||
|
Elements.stats_table.refresh(stats_table, row_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.progress_table.row
|
||||||
|
--- @field x LuaGuiElement
|
||||||
|
--- @field y LuaGuiElement
|
||||||
|
--- @field progress LuaGuiElement
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.progress_table.data
|
||||||
|
--- @field rows table<number, ExpGui_RocketInfo.elements.progress_table.row>
|
||||||
|
--- @field no_silos LuaGuiElement
|
||||||
|
|
||||||
|
--- Data table showing the build progress of each silo for a force
|
||||||
|
--- @class ExpGui_RocketInfo.elements.progress_table: ExpElement
|
||||||
|
--- @field data table<LuaGuiElement, ExpGui_RocketInfo.elements.progress_table.data>
|
||||||
|
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
||||||
|
Elements.progress_table = Gui.define("rocket_info/progress_table")
|
||||||
|
:track_all_elements()
|
||||||
|
:draw(function(def, parent)
|
||||||
|
--- @cast def ExpGui_RocketInfo.elements.progress_table
|
||||||
|
local progress_table = Gui.elements.scroll_table(parent, 215, 3)
|
||||||
|
|
||||||
|
-- The no silos label lives next to the table inside the same collapsible scroll pane
|
||||||
|
local no_silos = assert(progress_table.parent).add{
|
||||||
|
type = "label",
|
||||||
|
caption = { "exp-gui_rocket-info.progress-caption-no-silos" },
|
||||||
|
}
|
||||||
|
no_silos.style.padding = { 1, 2 }
|
||||||
|
|
||||||
|
def.data[progress_table] = { rows = {}, no_silos = no_silos }
|
||||||
|
return progress_table
|
||||||
|
end) --[[ @as any ]]
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.progress_table.row_data
|
||||||
|
--- @field entity LuaEntity
|
||||||
|
--- @field x LocalisedString
|
||||||
|
--- @field y LocalisedString
|
||||||
|
--- @field caption LocalisedString
|
||||||
|
--- @field tooltip LocalisedString
|
||||||
|
--- @field color Color
|
||||||
|
|
||||||
|
--- Compute the progress row data for a silo, clears awaiting_reset once the silo is no longer waiting
|
||||||
|
--- @param silo_data ExpGui_RocketInfo.elements.container.silo_data
|
||||||
|
--- @return ExpGui_RocketInfo.elements.progress_table.row_data
|
||||||
|
function Elements.progress_table.calculate_row_data(silo_data)
|
||||||
|
local entity = silo_data.entity
|
||||||
|
local position = entity.position
|
||||||
|
local waiting = entity.status == defines.entity_status.waiting_to_launch_rocket
|
||||||
|
|
||||||
|
local caption = { "exp-gui_rocket-info.progress-caption", entity.rocket_parts }
|
||||||
|
local color = font_color.neutral
|
||||||
|
if waiting and silo_data.awaiting_reset then
|
||||||
|
caption = { "exp-gui_rocket-info.progress-launched" }
|
||||||
|
color = font_color.launched
|
||||||
|
elseif waiting then
|
||||||
|
caption = { "exp-gui_rocket-info.progress-caption", 100 }
|
||||||
|
color = font_color.waiting
|
||||||
|
else
|
||||||
|
silo_data.awaiting_reset = false
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
entity = entity,
|
||||||
|
x = { "exp-gui_rocket-info.progress-x-pos", position.x },
|
||||||
|
y = { "exp-gui_rocket-info.progress-y-pos", position.y },
|
||||||
|
caption = caption,
|
||||||
|
tooltip = { "exp-gui_rocket-info.progress-tooltip", silo_data.launched },
|
||||||
|
color = color,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculate the row data for all rows, pruning the silo data as required
|
||||||
|
--- @param silo_data table<number, ExpGui_RocketInfo.elements.container.silo_data>
|
||||||
|
--- @return ExpGui_RocketInfo.elements.progress_table.row_data[]
|
||||||
|
function Elements.progress_table.calculate_row_data_all(silo_data)
|
||||||
|
local row_data = {}
|
||||||
|
for unit_number, silo_data in pairs(silo_data) do
|
||||||
|
if silo_data.entity.valid then
|
||||||
|
row_data[unit_number] = Elements.progress_table.calculate_row_data(silo_data)
|
||||||
|
else
|
||||||
|
-- Prune silos that are no longer valid
|
||||||
|
silo_data[unit_number] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return row_data
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a silo row to the progress table and store its labels
|
||||||
|
--- @param progress_table LuaGuiElement
|
||||||
|
--- @param row_data ExpGui_RocketInfo.elements.progress_table.row_data
|
||||||
|
function Elements.progress_table.add_row(progress_table, row_data)
|
||||||
|
local rows = Elements.progress_table.data[progress_table].rows
|
||||||
|
local zoom_tooltip = config.progress.allow_zoom_to_map and { "exp-gui_rocket-info.progress-label-tooltip" } or nil
|
||||||
|
|
||||||
|
local x = Elements.position_label(progress_table, { caption = row_data.x, tooltip = zoom_tooltip, entity = row_data.entity })
|
||||||
|
local y = Elements.position_label(progress_table, { caption = row_data.y, tooltip = zoom_tooltip, entity = row_data.entity })
|
||||||
|
local progress = progress_table.add{
|
||||||
|
type = "label",
|
||||||
|
caption = row_data.caption,
|
||||||
|
tooltip = row_data.tooltip,
|
||||||
|
}
|
||||||
|
progress.style.padding = { 0, 2 }
|
||||||
|
progress.style.font_color = row_data.color
|
||||||
|
|
||||||
|
rows[row_data.entity.unit_number] = { x = x, y = y, progress = progress }
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove a silo row from the progress table
|
||||||
|
--- @param progress_table LuaGuiElement
|
||||||
|
--- @param unit_number number
|
||||||
|
function Elements.progress_table.remove_row(progress_table, unit_number)
|
||||||
|
local element_data = Elements.progress_table.data[progress_table]
|
||||||
|
local row = element_data.rows[unit_number]
|
||||||
|
|
||||||
|
if not row then return end
|
||||||
|
element_data.rows[unit_number] = nil
|
||||||
|
Gui.destroy_if_valid(row.x)
|
||||||
|
Gui.destroy_if_valid(row.y)
|
||||||
|
Gui.destroy_if_valid(row.progress)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update an existing silo row to match the latest data
|
||||||
|
--- @param progress_table LuaGuiElement
|
||||||
|
--- @param row_data ExpGui_RocketInfo.elements.progress_table.row_data
|
||||||
|
function Elements.progress_table.refresh_row(progress_table, row_data)
|
||||||
|
local element_data = Elements.progress_table.data[progress_table]
|
||||||
|
local row = element_data.rows[row_data.entity.unit_number]
|
||||||
|
row.x.caption = row_data.x
|
||||||
|
row.y.caption = row_data.y
|
||||||
|
row.progress.caption = row_data.caption
|
||||||
|
row.progress.tooltip = row_data.tooltip
|
||||||
|
row.progress.style.font_color = row_data.color
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the progress table, reconciling rows with the current set of silos
|
||||||
|
--- @param progress_table LuaGuiElement
|
||||||
|
--- @param row_data ExpGui_RocketInfo.elements.progress_table.row_data[]
|
||||||
|
function Elements.progress_table.refresh(progress_table, row_data)
|
||||||
|
local element_data = Elements.progress_table.data[progress_table]
|
||||||
|
local rows = element_data.rows
|
||||||
|
local has_silos = false
|
||||||
|
local seen = {}
|
||||||
|
|
||||||
|
for _, row in pairs(row_data) do
|
||||||
|
has_silos = true
|
||||||
|
seen[row.entity.unit_number] = true
|
||||||
|
if rows[row.entity.unit_number] then
|
||||||
|
Elements.progress_table.refresh_row(progress_table, row)
|
||||||
|
else
|
||||||
|
Elements.progress_table.add_row(progress_table, row)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove rows for silos that are no longer present
|
||||||
|
for unit_number in pairs(rows) do
|
||||||
|
if not seen[unit_number] then
|
||||||
|
Elements.progress_table.remove_row(progress_table, unit_number)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
element_data.no_silos.visible = not has_silos
|
||||||
|
progress_table.visible = has_silos
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the progress table for a player, reconciling rows with the current set of silos
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
function Elements.progress_table.refresh_player(player)
|
||||||
|
local force = player.force --[[ @as LuaForce ]]
|
||||||
|
local silos = Elements.container.get_silos(force)
|
||||||
|
local row_data = Elements.progress_table.calculate_row_data_all(silos)
|
||||||
|
for _, progress_table in Elements.progress_table:online_elements(player) do
|
||||||
|
Elements.progress_table.refresh(progress_table, row_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the progress table for a force, reconciling rows with the current set of silos
|
||||||
|
--- @param force LuaForce
|
||||||
|
function Elements.progress_table.refresh_force(force)
|
||||||
|
local silos = Elements.container.get_silos(force)
|
||||||
|
local row_data = Elements.progress_table.calculate_row_data_all(silos)
|
||||||
|
for _, progress_table in Elements.progress_table:online_elements(force) do
|
||||||
|
Elements.progress_table.refresh(progress_table, row_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.container.silo_data
|
||||||
|
--- @field entity LuaEntity The rocket silo entity
|
||||||
|
--- @field launched number The number of rockets launched from this silo
|
||||||
|
--- @field awaiting_reset boolean True when a launch is ordered but the silo has not reset yet
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.container.force_stats
|
||||||
|
--- @field first_launch number? The tick the first rocket was launched
|
||||||
|
--- @field last_launch number? The tick the last rocket was launched
|
||||||
|
--- @field fastest_launch number? The tick duration between the two closest launches
|
||||||
|
|
||||||
|
--- @class ExpGui_RocketInfo.elements.container.force_data
|
||||||
|
--- @field stats ExpGui_RocketInfo.elements.container.force_stats Launch stats for the force
|
||||||
|
--- @field times table<number, number> Launch tick indexed by rocket number
|
||||||
|
--- @field silos table<number, ExpGui_RocketInfo.elements.container.silo_data> Silo data indexed by unit number
|
||||||
|
|
||||||
|
--- Container added to the left gui flow
|
||||||
|
--- @class ExpGui_RocketInfo.elements.container: ExpElement
|
||||||
|
--- @field data table<LuaForce, ExpGui_RocketInfo.elements.container.force_data>
|
||||||
|
Elements.container = Gui.define("rocket_info/container")
|
||||||
|
:draw(function(def, parent)
|
||||||
|
--- @cast def ExpGui_RocketInfo.elements.container
|
||||||
|
local container = Gui.elements.container(parent, 200)
|
||||||
|
container.style.padding = 0
|
||||||
|
|
||||||
|
local player = Gui.get_player(parent)
|
||||||
|
local force = player.force --[[ @as LuaForce ]]
|
||||||
|
local force_data = def._get_force_data(force)
|
||||||
|
|
||||||
|
if config.stats.show_stats then
|
||||||
|
local row_data = Elements.stats_table.calculate_row_data(force)
|
||||||
|
Elements.stats_table.refresh(def.add_section(container, "stats", Elements.stats_table), row_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.milestones.show_milestones then
|
||||||
|
local row_data = Elements.milestones_table.calculate_row_data(force)
|
||||||
|
Elements.milestones_table.refresh(def.add_section(container, "milestones", Elements.milestones_table), row_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.progress.show_progress then
|
||||||
|
local row_data = Elements.progress_table.calculate_row_data_all(force_data.silos)
|
||||||
|
Elements.progress_table.refresh(def.add_section(container, "progress", Elements.progress_table), row_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Gui.elements.container.get_root_element(container)
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Add a collapsible section to a container and return its data table
|
||||||
|
--- @param container LuaGuiElement The container frame to add the section to
|
||||||
|
--- @param section_name string Used to select the locale keys for the header
|
||||||
|
--- @param table_define any The data table element define to add
|
||||||
|
--- @return LuaGuiElement
|
||||||
|
function Elements.container.add_section(container, section_name, table_define)
|
||||||
|
local header = Gui.elements.header(container, {
|
||||||
|
caption = { "exp-gui_rocket-info.section-caption-" .. section_name },
|
||||||
|
tooltip = { "exp-gui_rocket-info.section-tooltip-" .. section_name },
|
||||||
|
})
|
||||||
|
|
||||||
|
local data_table = table_define(container)
|
||||||
|
|
||||||
|
-- The scroll pane is the parent of the table, it is what gets collapsed
|
||||||
|
local scroll_pane = assert(data_table.parent)
|
||||||
|
scroll_pane.visible = false
|
||||||
|
Elements.toggle_section_button(header, scroll_pane)
|
||||||
|
|
||||||
|
return data_table
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get or create the data for a force
|
||||||
|
--- @param force LuaForce
|
||||||
|
--- @return ExpGui_RocketInfo.elements.container.force_data
|
||||||
|
function Elements.container._get_force_data(force)
|
||||||
|
local force_data = Elements.container.data[force]
|
||||||
|
if not force_data then
|
||||||
|
force_data = { stats = {}, times = {}, silos = {} }
|
||||||
|
Elements.container.data[force] = force_data
|
||||||
|
end
|
||||||
|
|
||||||
|
return force_data
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the stats for a force
|
||||||
|
--- @param force LuaForce
|
||||||
|
--- @return { first_launch: number?, last_launch: number?, fastest_launch: number? }
|
||||||
|
function Elements.container.get_stats(force)
|
||||||
|
return Elements.container._get_force_data(force).stats
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the list of rocket launch times
|
||||||
|
--- @param force LuaForce
|
||||||
|
--- @return table<number, number>
|
||||||
|
function Elements.container.get_launch_times(force)
|
||||||
|
return Elements.container._get_force_data(force).times
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the list of current silos for a force
|
||||||
|
--- @param force LuaForce
|
||||||
|
--- @return table<number, ExpGui_RocketInfo.elements.container.silo_data>
|
||||||
|
function Elements.container.get_silos(force)
|
||||||
|
return Elements.container._get_force_data(force).silos
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a silo to the list of current silos for a force
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
function Elements.container.add_silo(entity)
|
||||||
|
local force = entity.force --[[ @as LuaForce ]]
|
||||||
|
local silos = Elements.container._get_force_data(force).silos
|
||||||
|
silos[entity.unit_number] = {
|
||||||
|
entity = entity,
|
||||||
|
launched = 0,
|
||||||
|
awaiting_reset = false,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Increment the launch count for a silo
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
function Elements.container.increment_silo(entity)
|
||||||
|
local force = entity.force --[[ @as LuaForce ]]
|
||||||
|
local silos = Elements.container._get_force_data(force).silos
|
||||||
|
local silo_data = silos[entity.unit_number]
|
||||||
|
if not silo_data then return end
|
||||||
|
silo_data.launched = silo_data.launched + 1
|
||||||
|
silo_data.awaiting_reset = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add the element to the left flow with a toolbar button
|
||||||
|
Gui.add_left_element(Elements.container, false)
|
||||||
|
Gui.toolbar.create_button{
|
||||||
|
name = "toggle_rocket_info",
|
||||||
|
left_element = Elements.container,
|
||||||
|
sprite = "item/rocket-silo",
|
||||||
|
tooltip = { "exp-gui_rocket-info.tooltip-main" },
|
||||||
|
visible = function(player, element)
|
||||||
|
return Roles.player_allowed(player, "gui/rocket-info")
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Record the launch and update the stats when a cargo pod finishes ascending
|
||||||
|
--- @param event EventData.on_cargo_pod_finished_ascending
|
||||||
|
local function on_cargo_pod_finished_ascending(event)
|
||||||
|
local force = event.cargo_pod.force --[[ @as LuaForce ]]
|
||||||
|
local rockets_launched = force.rockets_launched
|
||||||
|
|
||||||
|
-- Update the launch stats for the force
|
||||||
|
local stats = Elements.container.get_stats(force)
|
||||||
|
if rockets_launched == 1 then
|
||||||
|
stats.first_launch = event.tick
|
||||||
|
stats.fastest_launch = event.tick
|
||||||
|
elseif stats.last_launch and event.tick - stats.last_launch < (stats.fastest_launch or math.huge) then
|
||||||
|
stats.fastest_launch = event.tick - stats.last_launch
|
||||||
|
end
|
||||||
|
|
||||||
|
stats.last_launch = event.tick
|
||||||
|
|
||||||
|
-- Append the launch tick into the times array
|
||||||
|
local times = Elements.container.get_launch_times(force)
|
||||||
|
times[rockets_launched] = event.tick
|
||||||
|
|
||||||
|
-- Discard the launch time that is no longer needed by any rolling average unless it is a milestone
|
||||||
|
local remove_rocket = rockets_launched - largest_rolling_avg
|
||||||
|
if remove_rocket > 0 and not table.array_contains(config.milestones, remove_rocket) then
|
||||||
|
times[remove_rocket] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
Elements.stats_table.refresh_force(force)
|
||||||
|
Elements.milestones_table.refresh_force(force)
|
||||||
|
Elements.progress_table.refresh_force(force)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Mark a silo as awaiting reset when a launch is ordered
|
||||||
|
--- @param event EventData.on_rocket_launch_ordered
|
||||||
|
local function on_rocket_launch_ordered(event)
|
||||||
|
Elements.container.increment_silo(event.rocket_silo)
|
||||||
|
Elements.progress_table.refresh_force(event.rocket_silo.force --[[ @as LuaForce ]])
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the gui when a player joins the game as it may be outdated
|
||||||
|
--- @param event EventData.on_player_joined_game
|
||||||
|
local function on_player_joined_game(event)
|
||||||
|
local player = Gui.get_player(event)
|
||||||
|
Elements.stats_table.refresh_player(player)
|
||||||
|
Elements.milestones_table.refresh_player(player)
|
||||||
|
Elements.progress_table.refresh_player(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a silo to the force data when it is built
|
||||||
|
--- @param event EventData.on_built_entity | EventData.on_robot_built_entity | EventData.script_raised_built | EventData.script_raised_revive
|
||||||
|
local function on_built(event)
|
||||||
|
local entity = event.entity
|
||||||
|
if not entity.valid or entity.name ~= "rocket-silo" then return end
|
||||||
|
Elements.container.add_silo(entity)
|
||||||
|
Elements.progress_table.refresh_force(entity.force --[[ @as LuaForce ]])
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the progress for all forces that own at least one silo
|
||||||
|
local function refresh_all_progress()
|
||||||
|
for _, force in pairs(game.forces) do
|
||||||
|
Elements.progress_table.refresh_force(force)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local e = defines.events
|
||||||
|
|
||||||
|
return {
|
||||||
|
elements = Elements,
|
||||||
|
events = {
|
||||||
|
[e.on_cargo_pod_finished_ascending] = on_cargo_pod_finished_ascending,
|
||||||
|
[e.on_rocket_launch_ordered] = on_rocket_launch_ordered,
|
||||||
|
[e.on_player_joined_game] = on_player_joined_game,
|
||||||
|
[e.on_built_entity] = on_built,
|
||||||
|
[e.on_robot_built_entity] = on_built,
|
||||||
|
[e.script_raised_built] = on_built,
|
||||||
|
[e.script_raised_revive] = on_built,
|
||||||
|
},
|
||||||
|
on_nth_tick = {
|
||||||
|
[150] = refresh_all_progress,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -431,6 +431,42 @@ caption-research-name=[technology=__1__] __2__
|
|||||||
notice-inf=[color=255, 255, 255] Research completed at __1__ - [technology=__2__] - __3__[/color]
|
notice-inf=[color=255, 255, 255] Research completed at __1__ - [technology=__2__] - __3__[/color]
|
||||||
notice=[color=255, 255, 255] Research completed at __1__ - [technology=__2__][/color]
|
notice=[color=255, 255, 255] Research completed at __1__ - [technology=__2__][/color]
|
||||||
|
|
||||||
|
[exp-gui_rocket-info]
|
||||||
|
tooltip-main=Rocket Info
|
||||||
|
caption-main=Rocket Info
|
||||||
|
tooltip-toggle-section-expand=Expand Section
|
||||||
|
tooltip-toggle-section-collapse=Collapse Section
|
||||||
|
section-caption-stats=Statistics
|
||||||
|
section-tooltip-stats=Statistics about how rockets are launched
|
||||||
|
section-caption-milestones=Milestones
|
||||||
|
section-tooltip-milestones=The times when milestones were met
|
||||||
|
section-caption-progress=Build Progress
|
||||||
|
section-tooltip-progress=The progress for your rocket silos
|
||||||
|
data-caption-first-launch=First Launch
|
||||||
|
data-tooltip-first-launch=The time of the first launch
|
||||||
|
data-caption-last-launch=Last Launch
|
||||||
|
data-tooltip-last-launch=The time of the last launch
|
||||||
|
data-caption-fastest-launch=Fastest Launch
|
||||||
|
data-tooltip-fastest-launch=The time taken for the fastest launch
|
||||||
|
data-caption-total-rockets=Total Launched
|
||||||
|
data-tooltip-total-rockets=Total number of rockets launched by your force
|
||||||
|
value-tooltip-total-rockets=__1__% of all rockets on this map
|
||||||
|
data-caption-avg-launch=Average Time
|
||||||
|
data-tooltip-avg-launch=The average amount of time taken to launch a rocket
|
||||||
|
data-caption-avg-launch-n=Average Time __1__
|
||||||
|
data-tooltip-avg-launch-n=The average amount of time taken to launch the last __1__ rockets
|
||||||
|
data-caption-milestone-n=Milestone __1__
|
||||||
|
data-tooltip-milestone-n=Time taken to reach __1__ rockets
|
||||||
|
data-caption-milestone-next=N/A
|
||||||
|
data-tooltip-milestone-next=Not yet achieved
|
||||||
|
progress-x-pos=X __1__
|
||||||
|
progress-y-pos=Y __1__
|
||||||
|
progress-label-tooltip=View on map
|
||||||
|
progress-launched=Launched
|
||||||
|
progress-caption=__1__%
|
||||||
|
progress-tooltip=This silo has launched __1__ rockets
|
||||||
|
progress-caption-no-silos=You have no rocket silos
|
||||||
|
|
||||||
[exp-gui_science-production]
|
[exp-gui_science-production]
|
||||||
tooltip-main=Science Production
|
tooltip-main=Science Production
|
||||||
caption-main=Science
|
caption-main=Science
|
||||||
|
|||||||
@@ -430,6 +430,42 @@ caption-research-name=[technology=__1__] __2__
|
|||||||
notice-inf=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__] - __3__[/color]
|
notice-inf=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__] - __3__[/color]
|
||||||
notice=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__][/color]
|
notice=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__][/color]
|
||||||
|
|
||||||
|
[exp-gui_rocket-info]
|
||||||
|
tooltip-main=火箭資訊
|
||||||
|
caption-main=發射火箭
|
||||||
|
tooltip-toggle-section-expand=擴張欄
|
||||||
|
tooltip-toggle-section-collapse=收縮欄
|
||||||
|
section-caption-stats=數據
|
||||||
|
section-tooltip-stats=火箭發射數據
|
||||||
|
section-caption-milestones=里程碑
|
||||||
|
section-tooltip-milestones=里程碑達成次數
|
||||||
|
section-caption-progress=建造程度
|
||||||
|
section-tooltip-progress=火箭建造程度
|
||||||
|
data-caption-first-launch=首次發射
|
||||||
|
data-tooltip-first-launch=首次發射時間
|
||||||
|
data-caption-last-launch=最後發射
|
||||||
|
data-tooltip-last-launch=最後發射時間
|
||||||
|
data-caption-fastest-launch=最快發射
|
||||||
|
data-tooltip-fastest-launch=最快發射時間
|
||||||
|
data-caption-total-rockets=總發射次數
|
||||||
|
data-tooltip-total-rockets=我方總發射次數
|
||||||
|
value-tooltip-total-rockets=__1__% 的火箭發射都在本地圖上。
|
||||||
|
data-caption-avg-launch=平均時間
|
||||||
|
data-tooltip-avg-launch=火箭發射平均時間
|
||||||
|
data-caption-avg-launch-n=平均時間 __1__
|
||||||
|
data-tooltip-avg-launch-n=__1__ 次火箭發射的平均時間
|
||||||
|
data-caption-milestone-n=里程碑 __1__
|
||||||
|
data-tooltip-milestone-n=__1__ 次火箭發射的時間
|
||||||
|
data-caption-milestone-next=N/A
|
||||||
|
data-tooltip-milestone-next=未達成
|
||||||
|
progress-x-pos=X __1__
|
||||||
|
progress-y-pos=Y __1__
|
||||||
|
progress-label-tooltip=在地圖上看
|
||||||
|
progress-launched=已發射
|
||||||
|
progress-caption=__1__ %
|
||||||
|
progress-tooltip=該火箭發射井發射了 __1__ 次
|
||||||
|
progress-caption-no-silos=你沒有火箭發射井
|
||||||
|
|
||||||
[exp-gui_science-production]
|
[exp-gui_science-production]
|
||||||
tooltip-main=研究資訊
|
tooltip-main=研究資訊
|
||||||
caption-main=研究瓶
|
caption-main=研究瓶
|
||||||
|
|||||||
@@ -430,6 +430,42 @@ caption-research-name=[technology=__1__] __2__
|
|||||||
notice-inf=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__] - __3__[/color]
|
notice-inf=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__] - __3__[/color]
|
||||||
notice=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__][/color]
|
notice=[color=255, 255, 255] 研究完成在 __1__ - [technology=__2__][/color]
|
||||||
|
|
||||||
|
[exp-gui_rocket-info]
|
||||||
|
tooltip-main=火箭資訊
|
||||||
|
caption-main=發射火箭
|
||||||
|
tooltip-toggle-section-expand=擴張欄
|
||||||
|
tooltip-toggle-section-collapse=收縮欄
|
||||||
|
section-caption-stats=數據
|
||||||
|
section-tooltip-stats=火箭發射數據
|
||||||
|
section-caption-milestones=里程碑
|
||||||
|
section-tooltip-milestones=里程碑達成次數
|
||||||
|
section-caption-progress=建造程度
|
||||||
|
section-tooltip-progress=火箭建造程度
|
||||||
|
data-caption-first-launch=首次發射
|
||||||
|
data-tooltip-first-launch=首次發射時間
|
||||||
|
data-caption-last-launch=最後發射
|
||||||
|
data-tooltip-last-launch=最後發射時間
|
||||||
|
data-caption-fastest-launch=最快發射
|
||||||
|
data-tooltip-fastest-launch=最快發射時間
|
||||||
|
data-caption-total-rockets=總發射次數
|
||||||
|
data-tooltip-total-rockets=我方總發射次數
|
||||||
|
value-tooltip-total-rockets=__1__% 的火箭發射都在本地圖上。
|
||||||
|
data-caption-avg-launch=平均時間
|
||||||
|
data-tooltip-avg-launch=火箭發射平均時間
|
||||||
|
data-caption-avg-launch-n=平均時間 __1__
|
||||||
|
data-tooltip-avg-launch-n=__1__ 次火箭發射的平均時間
|
||||||
|
data-caption-milestone-n=里程碑 __1__
|
||||||
|
data-tooltip-milestone-n=__1__ 次火箭發射的時間
|
||||||
|
data-caption-milestone-next=N/A
|
||||||
|
data-tooltip-milestone-next=未達成
|
||||||
|
progress-x-pos=X __1__
|
||||||
|
progress-y-pos=Y __1__
|
||||||
|
progress-label-tooltip=在地圖上看
|
||||||
|
progress-launched=已發射
|
||||||
|
progress-caption=__1__ %
|
||||||
|
progress-tooltip=該火箭發射井發射了 __1__ 次
|
||||||
|
progress-caption-no-silos=你沒有火箭發射井
|
||||||
|
|
||||||
[exp-gui_science-production]
|
[exp-gui_science-production]
|
||||||
tooltip-main=研究資訊
|
tooltip-main=研究資訊
|
||||||
caption-main=研究瓶
|
caption-main=研究瓶
|
||||||
|
|||||||
Reference in New Issue
Block a user