diff --git a/config/_file_loader.lua b/config/_file_loader.lua index 746bbcb7..38857d22 100644 --- a/config/_file_loader.lua +++ b/config/_file_loader.lua @@ -34,8 +34,9 @@ return { 'modules.addons.pollution-grading', 'modules.addons.random-player-colours', -- GUI - 'modules.gui.player-list', 'modules.gui.rocket-info', + 'modules.gui.science-info', + 'modules.gui.player-list', 'modules.commands.debug', -- Config Files 'config.expcore-commands.auth_admin', -- commands tagged with admin_only are blocked for non admins diff --git a/config/roles.lua b/config/roles.lua index 532b2db5..dab32e8f 100644 --- a/config/roles.lua +++ b/config/roles.lua @@ -190,6 +190,7 @@ local default = Roles.new_role('Guest','') 'command/report', 'gui/player-list', 'gui/rocket-info', + 'gui/science-info', } --- Jail role diff --git a/expcore/common.lua b/expcore/common.lua index 8e8c6e72..41adffd5 100644 --- a/expcore/common.lua +++ b/expcore/common.lua @@ -171,7 +171,8 @@ function Public.format_time(ticks,options) seconds=false, long=false, time=false, - string=false + string=false, + null=false } -- Basic numbers that are used in calculations local max_days, max_hours, max_minutes, max_seconds = ticks/5184000, ticks/216000, ticks/3600, ticks/60 @@ -188,6 +189,13 @@ function Public.format_time(ticks,options) if not options.minutes then rtn_seconds = rtn_seconds + rtn_minutes*60 end + -- Creates the null time format, does not work with long + if options.null and not options.long then + rtn_days='--' + rtn_hours='--' + rtn_minutes='--' + rtn_seconds='--' + end -- Format options local suffix = 'time-symbol-' local suffix_2 = '-short' @@ -215,7 +223,7 @@ function Public.format_time(ticks,options) rtn_minutes = {suffix..'minutes'..suffix_2,rtn_minutes} rtn_seconds = {suffix..'seconds'..suffix_2,rtn_seconds} end - else + elseif not options.null then -- weather string or not it has same format rtn_days = string.format('%02d',rtn_days) rtn_hours = string.format('%02d',rtn_hours) diff --git a/expcore/gui/left.lua b/expcore/gui/left.lua index aeb528d3..b96e587c 100644 --- a/expcore/gui/left.lua +++ b/expcore/gui/left.lua @@ -154,6 +154,8 @@ end function LeftFrames._prototype:set_open_by_default(state) if state == false then self.open_by_default = false + elseif state == nil then + self.open_by_default = true else self.open_by_default = state end @@ -282,7 +284,7 @@ Event.add(defines.events.on_player_created,function(event) define.events.on_draw(player,frame) end - if define.open_by_default == false then + if not define.open_by_default then frame.visible = false elseif type(define.open_by_default) == 'function' then if not define.open_by_default(player,define.name) then diff --git a/locale/en/gui.cfg b/locale/en/gui.cfg index e7e2aee4..32b8088a 100644 --- a/locale/en/gui.cfg +++ b/locale/en/gui.cfg @@ -51,4 +51,15 @@ 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 \ No newline at end of file +progress-tooltip=This silo has launched __1__ rockets + +[science-info] +main-caption=Science Packs +main-tooltip=Science Info +eta-caption=ETA: +eta-tooltip=The estimated time left for the current research +eta-time=T- __1__ +unit=__1__spm +pos-tooltip=Total made: __1__ +neg-tooltip=Total used: __1__ +net-tooltip=Total net: __1__ \ No newline at end of file diff --git a/modules/gui/science-info.lua b/modules/gui/science-info.lua new file mode 100644 index 00000000..2775a168 --- /dev/null +++ b/modules/gui/science-info.lua @@ -0,0 +1,329 @@ +local Gui = require 'expcore.gui' +local Event = require 'utils.event' +local Colors = require 'resources.color_presets' +local format_time = ext_require('expcore.common','format_time') +local format_number = ext_require('util','format_number') + +local null_time_short = {'science-info.eta-time',format_time(0,{hours=true,minutes=true,seconds=true,time=true,null=true})} +local null_time_long = format_time(0,{hours=true,minutes=true,seconds=true,long=true,null=true}) + +local science_packs ={ + red='automation-science-pack', + green='logistic-science-pack', + grey='military-science-pack', + blue='chemical-science-pack', + purple='production-science-pack', + yellow='utility-science-pack', + white='space-science-pack', +} + +local function get_production_stats(player,science_pack) + local item_name = science_packs[science_pack] + local force = player.force + local stats = force.item_production_statistics + local total_made = stats.get_input_count(item_name) + local total_used = stats.get_output_count(item_name) + local minute_made = stats.get_flow_count{ + name=item_name, + input=true, + precision_index=defines.flow_precision_index.one_minute, + } + local minute_used = stats.get_flow_count{ + name=item_name, + input=false, + precision_index=defines.flow_precision_index.one_minute, + } + return { + total_made=total_made, + total_used=total_used, + total_net=total_made-total_used, + minute_made=minute_made, + minute_used=minute_used, + minute_net=minute_made-minute_used + } +end + +local function get_font_colour(value,secondary) + if value > 1 then + return Colors.light_green + elseif value < -1 then + return Colors.indian_red + elseif secondary and secondary > 0 or not secondary and value ~= 0 then + return Colors.orange + else + return Colors.grey + end +end + +local function generate_container(player,element) + Gui.set_padding(element,1,2,2,2) + element.style.minimal_width = 200 + + -- main container which contains the other elements + local container = + element.add{ + name='container', + type='frame', + direction='vertical', + style='window_content_frame_packed' + } + Gui.set_padding(container) + + -- main header for the gui + local header = + container.add{ + name='header', + type='frame', + caption={'science-info.main-caption'}, + style='subheader_frame' + } + Gui.set_padding(header,2,2,4,4) + header.style.horizontally_stretchable = true + + -- main flow for the data + local flow = + container.add{ + name='scroll', + type='scroll-pane', + direction='vertical', + horizontal_scroll_policy='never', + vertical_scroll_policy='auto-and-reserve-space' + } + Gui.set_padding(flow,1,1,2,2) + flow.style.horizontally_stretchable = true + flow.style.maximal_height = 185 + + -- table that stores all the data + local flow_table = + flow.add{ + name='table', + type='table', + column_count=4 + } + Gui.set_padding(flow_table) + flow_table.style.horizontally_stretchable = true + flow_table.style.vertical_align = 'center' + + -- footer used to store the eta + local footer = + container.add{ + name='footer', + type='frame', + style='subheader_frame' + } + Gui.set_padding(footer,2,2,4,4) + footer.style.horizontally_stretchable = true + + -- label for the footer + footer.add{ + name='eta-label', + type='label', + caption={'science-info.eta-caption'}, + tooltip={'science-info.eta-tooltip'}, + style='heading_1_label' + } + + -- data for the footer + local right_align = Gui.create_right_align(footer,'eta') + local eta = + right_align.add{ + name='label', + type='label', + caption=null_time_short, + tooltip=null_time_long, + style='heading_1_label' + } + + return flow_table, eta +end + +local function add_data_pair(element,name,value,secondary,tooltip) + local data_colour = get_font_colour(value,secondary) + local caption = format_number(math.round(value,1),true) + + local surfix = caption:sub(-1) + if not tonumber(surfix) then + caption = caption:sub(1,-2) + else + surfix = '' + end + + if value > 0 then + caption = '+'..caption + elseif value == 0 and caption:sub(1,1) == '-' then + caption = caption:sub(2) + end + + if element[name] then + local data = element[name].label + data.caption = caption + data.tooltip = tooltip + data.style.font_color = data_colour + local label = element['spm-'..name] + label.caption = {'science-info.unit',surfix} + label.tooltip = tooltip + label.style.font_color = data_colour + + else + -- right aligned number + local right_align = Gui.create_right_align(element,name) + local data = + right_align.add{ + name='label', + type='label', + caption=caption, + tooltip=tooltip + } + data.style.font_color = data_colour + + -- adds the unit onto the end + local label = + element.add{ + name='spm-'..name, + type='label', + caption={'science-info.unit',surfix}, + tooltip=tooltip + } + label.style.font_color = data_colour + end +end + +local function generate_science_pack(player,element,pack_name) + local stats = get_production_stats(player,pack_name) + local item_name = science_packs[pack_name] + if stats.total_made > 0 then + local icon_style = 'quick_bar_slot_button' + if stats.minute_net > 1 then + icon_style = 'green_slot_button' + elseif stats.minute_net < -1 then + icon_style = 'red_slot_button' + elseif stats.minute_made > 0 then + icon_style = 'selected_slot_button' + end + + local icon = element['icon-'..pack_name] + + if icon then + icon.style = icon_style + icon.style.height = 55 + if icon_style == 'quick_bar_slot_button' then + icon.style.width = 36 + Gui.set_padding(icon,0,0,-2,-2) + end + + else + icon = + element.add{ + name='icon-'..pack_name, + type='sprite-button', + sprite='item/'..item_name, + tooltip={'item-name.'..item_name}, + style=icon_style + } + icon.style.height = 55 + if icon_style == 'quick_bar_slot_button' then + icon.style.width = 36 + Gui.set_padding(icon,0,0,-2,-2) + end + + end + + local delta = element['delta-'..pack_name] + + if not delta then + delta = + element.add{ + name='delta-'..pack_name, + type='frame', + style='bordered_frame' + } + Gui.set_padding(delta,0,0,3,3) + + local delta_table = + delta.add{ + name='table', + type='table', + column_count=2 + } + Gui.set_padding(delta_table) + end + + add_data_pair(delta.table,'pos-'..pack_name,stats.minute_made,nil,{'science-info.pos-tooltip',stats.total_made}) + add_data_pair(delta.table,'neg-'..pack_name,-stats.minute_used,nil,{'science-info.neg-tooltip',stats.total_used}) + add_data_pair(element,'net-'..pack_name,stats.minute_net,stats.minute_made,{'science-info.net-tooltip',stats.total_net}) + end +end + +local function generate_eta(player,element) + local force = player.force + local research = force.current_research + if not research then + element.caption = null_time_short + element.tooltip = null_time_long + + else + local progress = force.research_progress + local remaining = research.research_unit_count*(1-progress) + local limit + + local stats = player.force.item_production_statistics + for _,ingredient in pairs(research.research_unit_ingredients) do + local pack_name = ingredient.name + local required = ingredient.amount * remaining + local consumed = stats.get_flow_count{ + name=pack_name, + input=false, + precision_index=defines.flow_precision_index.one_minute, + } + if consumed == 0 then + limit = -1 + break + end + local minutes = required / consumed + if not limit or limit < minutes then + limit = minutes + end + end + + if not limit or limit == -1 then + element.caption = null_time_short + element.tooltip = null_time_long + + else + local ticks = limit*3600 + element.caption = {'science-info.eta-time',format_time(ticks,{hours=true,minutes=true,seconds=true,time=true})} + element.tooltip = format_time(ticks,{hours=true,minutes=true,seconds=true,long=true}) + + end + end +end + +local science_info = +Gui.new_left_frame('gui/science-info') +:set_sprites('entity/lab') +:set_direction('vertical') +:set_tooltip{'science-info.main-tooltip'} +:on_draw(function(player,element) + local table, eta = generate_container(player,element) + + for pack_name,item_name in pairs(science_packs) do + generate_science_pack(player,table,pack_name) + end + + generate_eta(player,eta) +end) +:on_update(function(player,element) + local container = element.container + local table = container.scroll.table + local eta = container.footer.eta.label + + for pack_name,item_name in pairs(science_packs) do + generate_science_pack(player,table,pack_name) + end + + generate_eta(player,eta) +end) + +Event.on_nth_tick(60,science_info 'update_all') + +return science_info \ No newline at end of file