feature/control-separation

This commit is contained in:
Cooldude2606
2019-07-22 16:31:05 +01:00
435 changed files with 52086 additions and 22747 deletions

View File

@@ -3,36 +3,9 @@ local Gui = require 'expcore.gui'
local Roles = require 'expcore.roles'
local Event = require 'utils.event'
local config = require 'config.rockets'
local Global = require 'utils.global'
local format_time = ext_require('expcore.common','format_time')
local Colors = require 'resources.color_presets'
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 rocket_times = {}
local rocket_stats = {}
local rocket_silos = {}
Global.register({
rocket_times = rocket_times,
rocket_stats = rocket_stats,
rocket_silos = rocket_silos
},function(tbl)
rocket_times = tbl.rocket_times
rocket_stats = tbl.rocket_stats
rocket_silos = tbl.rocket_silos
end)
--- Gets the name used to reference the the rocket silo
local function get_silo_name(entity)
local position = entity.position
return math.floor(position.x)..':'..math.floor(position.y)
end
local Rockets = require 'modules.control.rockets'
--- Gets if a player is allowed to use the action buttons
local function player_allowed(player,action)
@@ -54,11 +27,9 @@ end
--- Used on the name label to allow zoom to map
local zoom_to_map_name = Gui.uid_name()
Gui.on_click(zoom_to_map_name,function(event)
local force = event.player.force
local rocket_silo_name = event.element.parent.caption
local rocket_silo_data = rocket_silos[force.name][rocket_silo_name]
local position = rocket_silo_data.entity.position
event.player.zoom_to_world(position,2)
local rocket_silo = Rockets.get_silo_entity(rocket_silo_name)
event.player.zoom_to_world(rocket_silo.position,2)
end)
--- Used to launch the rocket, when it is ready
@@ -75,11 +46,10 @@ end)
style.height = 16
end)
:on_click(function(player,element)
local force = player.force
local rocket_silo_name = element.parent.name:sub(8)
local rocket_silo_data = rocket_silos[force.name][rocket_silo_name]
if rocket_silo_data.entity.launch_rocket() then
rocket_silo_data.awaiting_reset = true
local silo_data = Rockets.get_silo_data_by_name(rocket_silo_name)
if silo_data.entity.launch_rocket() then
silo_data.awaiting_reset = true
element.enabled = false
local progress_label = element.parent.parent[rocket_silo_name].label
progress_label.caption = {'rocket-info.progress-launched'}
@@ -103,18 +73,16 @@ end)
style.height = 16
end)
:on_click(function(player,element)
local force = player.force
local rocket_silo_name = element.parent.name:sub(8)
local rocket_silo_data = rocket_silos[force.name][rocket_silo_name]
local active = rocket_silo_data.entity.auto_launch -- need to test for auto launch
if active then
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_data.entity.auto_launch = false
rocket_silo.auto_launch = false
else
element.sprite = 'utility/stop'
element.tooltip = {'rocket-info.toggle-rocket-tooltip-disabled'}
rocket_silo_data.entity.auto_launch = true
rocket_silo.auto_launch = true
end
end)
@@ -263,28 +231,25 @@ end
local function generate_stats(player,frame)
if not config.stats.show_stats then return end
local element = frame.container.stats.table
local force_rockets = player.force.rockets_launched
local force_name = player.force.name
local force_rockets = Rockets.get_rocket_count(force_name)
local stats = Rockets.get_stats(force_name)
if config.stats.show_first_rocket then
create_label_value_pair_time(element,'first-launch',rocket_stats.first_launch or 0)
create_label_value_pair_time(element,'first-launch',stats.first_launch or 0)
end
if config.stats.show_last_rocket then
create_label_value_pair_time(element,'last-launch',rocket_stats.last_launch or 0)
create_label_value_pair_time(element,'last-launch',stats.last_launch or 0)
end
if config.stats.show_fastest_rocket then
create_label_value_pair_time(element,'fastest-launch',rocket_stats.fastest_launch or 0,true)
create_label_value_pair_time(element,'fastest-launch',stats.fastest_launch or 0,true)
end
if config.stats.show_total_rockets then
local total_rockets = 1
if force_rockets > 0 then
total_rockets = 0
for _,force in pairs(game.forces) do
total_rockets = total_rockets + force.rockets_launched
end
end
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
create_label_value_pair(element,'total-rockets',force_rockets,{'rocket-info.value-tooltip-total-rockets',percentage})
end
@@ -295,14 +260,7 @@ local function generate_stats(player,frame)
end
for _,avg_over in pairs(config.stats.rolling_avg) do
local rocket_count = avg_over
local first_rocket = 0
if avg_over < force_rockets then
first_rocket = rocket_times[player.force.name][force_rockets-avg_over+1]
else
rocket_count = force_rockets
end
local avg = rocket_count > 0 and math.floor((game.tick-first_rocket)/rocket_count) or 0
local avg = Rockets.get_rolling_average(force_name,avg_over)
create_label_value_pair_time(element,'avg-launch-n',avg,true,avg_over)
end
@@ -312,11 +270,12 @@ end
local function generate_milestones(player,frame)
if not config.milestones.show_milestones then return end
local element = frame.container.milestones.table
local force_rockets = player.force.rockets_launched
local force_name = player.force.name
local force_rockets = Rockets.get_rocket_count(force_name)
for _,milestone in ipairs(config.milestones) do
if milestone <= force_rockets then
local time = rocket_times[player.force.name][milestone]
local time = Rockets.get_rocket_time(force_name,milestone)
create_label_value_pair_time(element,'milestone-n',time,false,milestone)
else
create_label_value_pair_time(element,'milestone-n',0,false,milestone)
@@ -325,11 +284,12 @@ local function generate_milestones(player,frame)
end
end
--- Creates the different buttons used with the rocket silos
local function generate_progress_buttons(player,element,rocket_silo_data)
local silo_name = rocket_silo_data.name
local status = rocket_silo_data.entity.status == defines.entity_status.waiting_to_launch_rocket
local active = rocket_silo_data.entity.auto_launch
--- Creats the different buttons used with the rocket silos
local function generate_progress_buttons(player,element,silo_data)
local silo_name = silo_data.name
local rocket_silo = silo_data.entity
local status = rocket_silo.status == defines.entity_status.waiting_to_launch_rocket
local active = rocket_silo.auto_launch
if player_allowed(player,'toggle_active') then
local button_element = element['toggle-'..silo_name]
@@ -358,7 +318,7 @@ local function generate_progress_buttons(player,element,rocket_silo_data)
button_element = launch_rocket(element,silo_name)
end
if rocket_silo_data.awaiting_reset then
if silo_data.awaiting_reset then
button_element.enabled = false
else
button_element.enabled = status
@@ -383,32 +343,33 @@ local function generate_progress(player,frame)
local element = frame.container.progress.table
local force = player.force
local force_name = force.name
local force_silo_data = rocket_silos[force_name]
local force_silos = Rockets.get_silos(force_name)
if not force_silo_data or table.size(force_silo_data) == 0 then
if not force_silos or table.size(force_silos) == 0 then
element.parent.no_silos.visible = true
else
element.parent.no_silos.visible = false
for silo_name,rocket_silo_data in pairs(force_silo_data) do
if not rocket_silo_data.entity or not rocket_silo_data.entity.valid then
force_silo_data[silo_name] = nil
Gui.destroy_if_valid(element['toggle-'..silo_name])
Gui.destroy_if_valid(element['launch-'..silo_name])
Gui.destroy_if_valid(element['label-x-'..silo_name])
Gui.destroy_if_valid(element['label-y-'..silo_name])
Gui.destroy_if_valid(element[silo_name])
for _,silo_data in pairs(force_silos) do
local silo_name = silo_data.name
if not silo_data.entity or not silo_data.entity.valid then
force_silos[silo_name] = nil
Gui.destory_if_valid(element['toggle-'..silo_name])
Gui.destory_if_valid(element['launch-'..silo_name])
Gui.destory_if_valid(element['label-x-'..silo_name])
Gui.destory_if_valid(element['label-y-'..silo_name])
Gui.destory_if_valid(element[silo_name])
elseif not element[silo_name] then
local entity = rocket_silo_data.entity
local entity = silo_data.entity
local progress = entity.rocket_parts
local pos = {
x=entity.position.x,
y=entity.position.y
}
generate_progress_buttons(player,element,rocket_silo_data)
generate_progress_buttons(player,element,silo_data)
--- Creates two flows and two labels for the X and Y position
local name = config.progress.allow_zoom_to_map and zoom_to_map_name or nil
@@ -445,30 +406,30 @@ local function generate_progress(player,frame)
type='label',
name='label',
caption={'rocket-info.progress-caption',progress},
tooltip={'rocket-info.progress-tooltip',rocket_silo_data.launched or 0}
tooltip={'rocket-info.progress-tooltip',silo_data.launched or 0}
}
else
local entity = rocket_silo_data.entity
local entity = silo_data.entity
local progress = entity.rocket_parts
local status = entity.status == 21
local label = element[silo_name].label
label.caption = {'rocket-info.progress-caption',progress}
label.tooltip = {'rocket-info.progress-tooltip',rocket_silo_data.launched or 0}
label.tooltip = {'rocket-info.progress-tooltip',silo_data.launched or 0}
if status and rocket_silo_data.awaiting_reset then
if status and silo_data.awaiting_reset then
label.caption = {'rocket-info.progress-launched'}
label.style.font_color = Colors.green
elseif status then
label.caption = {'rocket-info.progress-caption',100}
label.style.font_color = Colors.cyan
else
rocket_silo_data.awaiting_reset = false
silo_data.awaiting_reset = false
label.style.font_color = Colors.white
end
generate_progress_buttons(player,element,rocket_silo_data)
generate_progress_buttons(player,element,silo_data)
end
end
@@ -501,44 +462,11 @@ end)
--- Event used to update the stats and the hui when a rocket is launched
Event.add(defines.events.on_rocket_launched,function(event)
local entity = event.rocket_silo
local silo_name = get_silo_name(entity)
local force = event.rocket_silo.force
local force_name = force.name
local force_silo_data = rocket_silos[force_name]
local rockets_launched = force.rockets_launched
local first_rocket = rockets_launched == 1
--- Handles updates to the rocket stats
if not rocket_stats[force_name] then
rocket_stats[force_name] = {}
end
if first_rocket then
rocket_stats.first_launch = event.tick
rocket_stats.fastest_launch = event.tick
elseif event.tick-rocket_stats.last_launch < rocket_stats.fastest_launch then
rocket_stats.fastest_launch = event.tick-rocket_stats.last_launch
end
rocket_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
--- Adds this 1 to the launch count for this silo
force_silo_data[silo_name].launched = force_silo_data[silo_name].launched+1
--- Updates all the gui's (and toolbar since the button may now be visible)
--- Updates all the guis (and toolbar since the button may now be visible)
for _,player in pairs(force.players) do
rocket_info:update(player)
if first_rocket then
@@ -548,34 +476,11 @@ Event.add(defines.events.on_rocket_launched,function(event)
end
end)
--- When a launch is triggered it will await reset
Event.add(defines.events.on_rocket_launch_ordered,function(event)
local entity = event.rocket_silo
local silo_name = get_silo_name(entity)
local force = event.rocket_silo.force
local force_name = force.name
local force_silo_data = rocket_silos[force_name]
force_silo_data[silo_name].awaiting_reset = true
end)
--- Adds a silo to the list when it is built
local function on_built(event)
local entity = event.created_entity
if entity.valid and entity.name == 'rocket-silo' then
local force = entity.force
local force_name = force.name
local silo_name = get_silo_name(entity)
if not rocket_silos[force_name] then
rocket_silos[force_name] = {}
end
rocket_silos[force_name][silo_name] = {
name=silo_name,
entity=entity,
launched=0,
awaiting_reset=false
}
for _,player in pairs(force.players) do
local frame = rocket_info:get_frame(player)
@@ -590,8 +495,8 @@ Event.add(defines.events.on_robot_built_entity,on_built)
--- Optimised update for only the build progress
Event.on_nth_tick(150,function()
for _,force in pairs(game.forces) do
local silos = rocket_silos[force.name]
if silos then
local silos = Rockets.get_silos(force.name)
if #silos > 0 then
for _,player in pairs(force.connected_players) do
local frame = rocket_info:get_frame(player)
generate_progress(player,frame)

View File

@@ -1,53 +1,13 @@
--- Adds a science info gui that shows production usage and net for the different science packs as well as an eta
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 config = require 'config.science'
local Production = require 'modules.control.production'
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})
--- Gets the production stats for a certain science pack
local function get_production_stats(player,science_pack)
local force = player.force
local stats = force.item_production_statistics
local total_made = stats.get_input_count(science_pack)
local total_used = stats.get_output_count(science_pack)
local minute_made = stats.get_flow_count{
name=science_pack,
input=true,
precision_index=defines.flow_precision_index.one_minute,
}
local minute_used = stats.get_flow_count{
name=science_pack,
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
--- Gets the font colour for a certain level of production
local function get_font_colour(value,secondary)
if value > config.required_for_green then
return Colors.light_green
elseif value < config.required_for_red 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
--[[ Generates the main structure for the gui
element
> container
@@ -60,7 +20,7 @@ end
>>> eta
>>>> label
]]
local function generate_container(player,element)
local function generate_container(element)
Gui.set_padding(element,1,2,2,2)
element.style.minimal_width = 200
@@ -137,21 +97,8 @@ end
> spm-"name"
]]
local function add_data_label(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
local data_colour = Production.get_color(config.color_clamp, value, secondary)
local surfix,caption = Production.format_number(value)
if element[name] then
local data = element[name].label
@@ -197,16 +144,18 @@ end
> net-"science_pack" (add_data_label)
]]
local function generate_science_pack(player,element,science_pack)
local stats = get_production_stats(player,science_pack)
if stats.total_made > 0 then
local total = Production.get_production_total(player.force, science_pack)
local minute = Production.get_production(player.force, science_pack, defines.flow_precision_index.one_minute)
if total.made > 0 then
element.parent.non_made.visible = false
local icon_style = 'quick_bar_slot_button'
if stats.minute_net > config.required_for_green then
local flux = Production.get_fluctuations(player.force, science_pack, defines.flow_precision_index.one_minute)
if flux.net > -config.color_flux/2 then
icon_style = 'green_slot_button'
elseif stats.minute_net < config.required_for_red then
elseif flux.net < -config.color_flux then
icon_style = 'red_slot_button'
elseif stats.minute_made > 0 then
elseif minute.made > 0 then
icon_style = 'selected_slot_button'
end
@@ -257,9 +206,9 @@ local function generate_science_pack(player,element,science_pack)
Gui.set_padding(delta_table)
end
add_data_label(delta.table,'pos-'..science_pack,stats.minute_made,nil,{'science-info.pos-tooltip',stats.total_made})
add_data_label(delta.table,'neg-'..science_pack,-stats.minute_used,nil,{'science-info.neg-tooltip',stats.total_used})
add_data_label(element,'net-'..science_pack,stats.minute_net,stats.minute_made+stats.minute_used,{'science-info.net-tooltip',stats.total_net})
add_data_label(delta.table,'pos-'..science_pack,minute.made,nil,{'science-info.pos-tooltip',total.made})
add_data_label(delta.table,'neg-'..science_pack,-minute.used,nil,{'science-info.neg-tooltip',total.used})
add_data_label(element,'net-'..science_pack,minute.net,minute.made+minute.used,{'science-info.net-tooltip',total.net})
end
end
@@ -281,18 +230,9 @@ local function update_eta(player,element)
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
local time = Production.get_consumsion_eta(force, pack_name, defines.flow_precision_index.one_minute, required)
if not limit or limit < time then
limit = time
end
end
@@ -301,9 +241,8 @@ local function update_eta(player,element)
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})
element.caption = {'science-info.eta-time',format_time(limit,{hours=true,minutes=true,seconds=true,time=true})}
element.tooltip = format_time(limit,{hours=true,minutes=true,seconds=true,long=true})
end
end
@@ -316,7 +255,7 @@ Gui.new_left_frame('gui/science-info')
:set_direction('vertical')
:set_tooltip{'science-info.main-tooltip'}
:on_creation(function(player,element)
local table, eta = generate_container(player,element)
local table, eta = generate_container(element)
for _,science_pack in ipairs(config) do
generate_science_pack(player,table,science_pack)

View File

@@ -1,61 +1,15 @@
--- Adds a task list to the game which players can add remove and edit items on
local Gui = require 'expcore.gui'
local Store = require 'expcore.store'
local Global = require 'utils.global'
local Event = require 'utils.event'
local Roles = require 'expcore.roles'
local Token = require 'utils.token'
local config = require 'config.tasks'
local format_time,table_keys = ext_require('expcore.common','format_time','table_keys')
local task_store = 'gui.left.task-list.tasks'
local task_details = {}
local force_tasks = {}
Global.register({
task_details=task_details,
force_tasks=force_tasks
},function(tbl)
task_details = tbl.task_details
force_tasks = tbl.force_tasks
end)
--- Adds a new task for this force with this players name attached
local function add_task(player,task_number)
local task_id = tostring(Token.uid())
if not force_tasks[player.force.name] then
force_tasks[player.force.name] = {}
end
if task_number then
table.insert(force_tasks[player.force.name],task_number,task_id)
else
table.insert(force_tasks[player.force.name],task_id)
end
task_details[task_id] = {
task_id=task_id,
force=player.force.name,
last_edit_player=player.name,
last_edit_time=game.tick,
editing={[player.name]=true}
}
Store.set(task_store,task_id,'New task')
end
--- Removes all references to a task
local function remove_task(task_id)
local force_name = task_details[task_id].force
Store.clear(task_store,task_id)
task_details[task_id] = nil
table.remove_element(force_tasks[force_name],task_id)
end
local Tasks = require 'modules.control.tasks'
--- If a player is allowed to use the edit buttons
local function player_allowed_edit(player,task_id)
if task_id then
local details = task_details[task_id]
local details = Tasks.get_details(task_id)
if config.user_can_edit_own_tasks and details.last_edit_player == player.name then
return true
end
@@ -88,7 +42,7 @@ Gui.new_button()
style.width = 20
end)
:on_click(function(player,element)
add_task(player)
Tasks.new_task(player.force.name,nil,player.name)
end)
--- Used to save changes to a task
@@ -104,11 +58,8 @@ end)
:on_click(function(player,element)
local task_id = element.parent.name
local task = element.parent.task.text
local details = task_details[task_id]
details.editing[player.name] = nil
details.last_edit_player = player.name
details.last_edit_time = game.tick
Store.set(task_store,task_id,task)
Tasks.set_editing(task_id,player.name)
Tasks.update_task(task_id,task,player.name)
end)
--- Used to cancel any changes you made to a task
@@ -124,8 +75,7 @@ Gui.new_button()
end)
:on_click(function(player,element)
local task_id = element.parent.name
local details = task_details[task_id]
details.editing[player.name] = nil
Tasks.set_editing(task_id,player.name)
generate_task(player,element.parent.parent,task_id)
end)
@@ -141,7 +91,7 @@ Gui.new_button()
end)
:on_click(function(player,element)
local task_id = element.parent.name
remove_task(task_id)
Tasks.remove_task(task_id)
update_all()
end)
@@ -157,8 +107,7 @@ Gui.new_button()
end)
:on_click(function(player,element)
local task_id = element.parent.name
local details = task_details[task_id]
details.editing[player.name] = true
Tasks.set_editing(task_id,player.name,true)
generate_task(player,element.parent.parent.parent,task_id)
end)
@@ -175,12 +124,12 @@ end)
>> discard_task
]]
function generate_task(player,element,task_id)
local task = Store.get(task_store,task_id)
local details = task_details[task_id]
local editing = details.editing[player.name]
local task = Tasks.get_task(task_id)
local editing = Tasks.is_editing(task_id,player.name)
local details = Tasks.get_details(task_id)
local last_edit_player = details.last_edit_player
local last_edit_time = details.last_edit_time
local tasks = force_tasks[player.force.name]
local tasks = Tasks.get_force_tasks(player.force.name)
local task_number = table.index_of(tasks, task_id)
if not task then
@@ -351,18 +300,16 @@ Gui.new_left_frame('gui/task-list')
:set_open_by_default()
:on_creation(function(player,element)
local data_table = generate_container(player,element)
local force_name = player.force.name
local tasks = Tasks.get_force_tasks(player.force.name)
local tasks = force_tasks[force_name] or {}
for _,task_id in pairs(tasks) do
generate_task(player,data_table,task_id)
end
end)
:on_update(function(player,element)
local data_table = element.container.scroll.table
local force_name = player.force.name
local tasks = Tasks.get_force_tasks(player.force.name)
local tasks = force_tasks[force_name] or {}
for _,task_id in pairs(tasks) do
generate_task(player,data_table,task_id)
end
@@ -370,11 +317,8 @@ end)
update_all = task_list 'update_all'
--- When a new task is added it will update the task list for everyone on that force
Store.register(task_store,function(value,task_id)
local details = task_details[task_id]
local force = game.forces[details.force]
--- When a new task is added it will udpate the task list for everyone on that force
Tasks.add_handler(function(force,task_id)
for _,player in pairs(force.players) do
local frame = task_list:get_frame(player)
local element = frame.container.scroll.table

View File

@@ -4,34 +4,25 @@ local Global = require 'utils.global'
local Event = require 'utils.event'
local Game = require 'utils.game'
local Roles = require 'expcore.roles'
local Token = require 'utils.token'
local Colors = require 'resources.color_presets'
local config = require 'config.warps'
local format_time,table_keys,table_values,table_keysort = ext_require('expcore.common','format_time','table_keys','table_values','table_keysort')
local format_time,table_keys = ext_require('expcore.common','format_time','table_keys')
local Warps = require 'modules.control.warps'
local warp_list
local warp_name_store = 'gui.left.warps.names'
local warp_icon_store = 'gui.left.warps.tags'
local warp_player_in_range_store = 'gui.left.warps.in_range'
local warp_list
local warp_details = {}
local force_warps = {}
local keep_open = {}
Global.register({
warp_details=warp_details,
force_warps=force_warps,
keep_open=keep_open
},function(tbl)
force_warps = tbl.force_warps
warp_details = tbl.warp_details
keep_open = tbl.keep_open
Global.register(keep_open,function(tbl)
keep_open = tbl
end)
--- Returns if a player is allowed to edit the given warp
local function player_allowed_edit(player,warp_id)
if warp_id then
local details = warp_details[warp_id]
if not details.editing then
local details = Warps.get_details(warp_id)
local warps = Warps.get_warps(player.force.name)
if warps.spawn == warp_id then
return false
end
if config.user_can_edit_own_warps and details.last_edit_player == player.name then
@@ -54,196 +45,11 @@ local function player_allowed_edit(player,warp_id)
return true
end
--- Makes a map marker for this warp; updates it if already present
local function make_warp_tag(warp_id)
local warp = warp_details[warp_id]
if not warp then return end
local icon = Store.get(warp_icon_store,warp_id)
local name = Store.get(warp_name_store,warp_id)
if warp.tag and warp.tag.valid then
warp.tag.text = 'Warp: '..name
warp.tag.icon = {type='item',name=icon}
return
end
local force = game.forces[warp.force]
local surface = warp.surface
local position = warp.position
local tag = force.add_chart_tag(surface,{
position={position.x+0.5,position.y+0.5},
text='Warp: '..name,
icon={type='item',name=icon}
})
warp.tag = tag
end
-- This creates the area for the warp; this is not required but helps players know where the warps are
local function make_warp_area(warp_id)
local warp = warp_details[warp_id]
if not warp then return end
local position = warp.position
local px = position.x
local py = position.y
local surface = warp.surface
local radius = config.activation_range
local radius2 = radius^2
local old_tile = surface.get_tile(position).name
warp.old_tile = old_tile
local base_tile = config.base_tile
local base_tiles = {}
-- this makes a base plate to make the warp point
for x = -radius, radius do
local x2 = x^2
for y = -radius, radius do
local y2 = y^2
if x2+y2 < radius2 then
table.insert(base_tiles,{name=base_tile,position={x+px,y+py}})
end
end
end
surface.set_tiles(base_tiles)
-- this adds the tile pattern
local tiles = {}
for _,pos in pairs(config.tiles) do
table.insert(tiles,{name=base_tile,position={pos[1]+px,pos[2]+py}})
end
surface.set_tiles(tiles)
-- this adds the entities
for _,entity in pairs(config.entities) do
entity = surface.create_entity{
name=entity[1],
position={entity[2]+px,entity[3]+py},
force='neutral'
}
entity.destructible = false
entity.health = 0
entity.minable = false
entity.rotatable = false
end
end
--- This removes the warp area, also restores the old tile
local function clear_warp_area(warp_id)
local warp = warp_details[warp_id]
if not warp then return end
local position = warp.position
local surface = warp.surface
local radius = config.activation_range
local radius2 = radius^2
local base_tile = warp.old_tile
local tiles = {}
-- clears the area where the warp was
for x = -radius, radius do
local x2 = x^2
for y = -radius, radius do
local y2 = y^2
if x2+y2 < radius2 then
table.insert(tiles,{name=base_tile,position={x+position.x,y+position.y}})
end
end
end
surface.set_tiles(tiles)
-- removes all entities (in the area) on the neutral force
local entities = surface.find_entities_filtered{
force='neutral',
area={
{position.x-radius,position.y-radius},
{position.x+radius,position.y+radius}
}
}
for _,entity in pairs(entities) do if entity.name ~= 'player' then entity.destroy() end end
if warp.tag and warp.tag.valid then warp.tag.destroy() end
end
--- Special case for the warps; adds the spawn warp which cant be removed
local function add_spawn(player)
local warp_id = tostring(Token.uid())
local force = player.force
local force_name = force.name
local surface = player.surface
local spawn = force.get_spawn_position(surface)
if not force_warps[force_name] then
force_warps[force_name] = {}
end
table.insert(force_warps[force_name],warp_id)
warp_details[warp_id] = {
warp_id = warp_id,
force = force.name,
position = {
x=math.floor(spawn.x),
y=math.floor(spawn.y)
},
surface = surface,
last_edit_player='System',
last_edit_time=game.tick,
editing=false
}
Store.set(warp_name_store,warp_id,'Spawn')
Store.set(warp_icon_store,warp_id,config.default_icon)
end
--- General case for the warps; will make a new warp and set the player to be editing it
local function add_warp(player)
local warp_id = tostring(Token.uid())
local force_name = player.force.name
if not force_warps[force_name] then
add_spawn(player)
end
table.insert(force_warps[force_name],warp_id)
local position = player.position
warp_details[warp_id] = {
warp_id = warp_id,
force = force_name,
position = {
x=math.floor(position.x),
y=math.floor(position.y)
},
surface = player.surface,
last_edit_player=player.name,
last_edit_time=game.tick,
editing={[player.name]=true}
}
Store.set(warp_name_store,warp_id,'New warp')
Store.set(warp_icon_store,warp_id,config.default_icon)
make_warp_area(warp_id)
end
--- Removes all references to a warp
local function remove_warp(warp_id)
local force_name = warp_details[warp_id].force
local key = table.index_of(force_warps[force_name],warp_id)
force_warps[force_name][key] = nil
Store.clear(warp_name_store,warp_id)
Store.clear(warp_icon_store,warp_id)
warp_details[warp_id] = nil
end
--- Used on the name label to allow zoom to map
local zoom_to_map_name = Gui.uid_name()
Gui.on_click(zoom_to_map_name,function(event)
local warp_id = event.element.parent.name
local warp = warp_details[warp_id]
local warp = Warps.get_details(warp_id)
local position = warp.position
event.player.zoom_to_world(position,1.5)
end)
@@ -276,18 +82,9 @@ Gui.new_button()
end)
:on_click(function(player,element)
local warp_id = element.parent.caption
local warp = warp_details[warp_id]
local surface = warp.surface
local position = {
x=warp.position.x+0.5,
y=warp.position.y+0.5
}
Warps.teleport_player(warp_id,player)
local goto_position = surface.find_non_colliding_position('character',position,32,1)
if player.driving then player.driving = false end
player.teleport(goto_position,surface)
if config.bypass_warp_limits_permission and not Roles.player_allowed(player,config.bypass_warp_limits_permission) then
if config.bypass_warp_limits_permision and not Roles.player_allowed(player,config.bypass_warp_limits_permision) then
warp_timer:set_store(player.name,0)
-- this is to force an update of the buttons
local in_range = Store.get(warp_player_in_range_store,player.name)
@@ -311,18 +108,17 @@ end)
local py = position.y
local dist2 = config.minimum_distance^2
local warps = Store.get_children(warp_name_store)
for _,warp_id in pairs(warps) do
local warp = warp_details[warp_id]
local warps = Warps.get_all_warps()
for warp_id,warp in pairs(warps) do
local pos = warp.position
if (px-pos.x)^2+(py-pos.y)^2 < dist2 then
local warp_name = Store.get(warp_name_store,warp_id)
if (posx-pos.x)^2+(posy-pos.y)^2 < dist2 then
local warp_name = Warps.get_warp_name(warp_id)
player.print{'warp-list.too-close',warp_name}
return
end
end
add_warp(player)
Warps.new_warp(player.force.name,player.surface,position,player.name)
end)
--- Confirms the edit to name or icon of the warp
@@ -339,12 +135,8 @@ end)
local warp_id = element.parent.name
local warp_name = element.parent.warp.text
local warp_icon = element.parent.parent['icon-'..warp_id].icon.elem_value
local warp = warp_details[warp_id]
warp.editing[player.name] = nil
warp.last_edit_player = player.name
warp.last_edit_time = game.tick
Store.set(warp_name_store,warp_id,warp_name)
Store.set(warp_icon_store,warp_id,warp_icon)
Warps.set_editing(warp_id,player.name)
Warps.update_warp(warp_id,warp_name,warp_icon,player.name)
end)
--- Cancels the editing changes of the selected warp name or icon
@@ -360,8 +152,7 @@ Gui.new_button()
end)
:on_click(function(player,element)
local warp_id = element.parent.name
local details = warp_details[warp_id]
details.editing[player.name] = nil
Warps.set_editing(warp_id,player.name)
generate_warp(player,element.parent.parent,warp_id)
end)
@@ -377,7 +168,7 @@ Gui.new_button()
end)
:on_click(function(player,element)
local warp_id = element.parent.name
remove_warp(warp_id)
Warps.remove_warp(warp_id)
end)
--- Opens edit mode for the warp
@@ -392,8 +183,7 @@ Gui.new_button()
end)
:on_click(function(player,element)
local warp_id = element.parent.name
local details = warp_details[warp_id]
details.editing[player.name] = true
Warps.set_editing(warp_id,player.name,true)
generate_warp(player,element.parent.parent.parent,warp_id)
end)
@@ -411,11 +201,11 @@ end)
>>> discard_warp
]]
function generate_warp(player,element,warp_id)
local warp_name = Store.get(warp_name_store,warp_id)
local warp_icon = Store.get(warp_icon_store,warp_id) or config.default_icon
local warp = warp_details[warp_id]
local warp_name = Warps.get_warp_name(warp_id)
local warp_icon = Warps.get_warp_icon(warp_id)
local warp = Warps.get_details(warp_id)
local editing = warp.editing and warp.editing[player.name]
local editing = Warps.is_editing(warp_id,player.name)
local last_edit_player = warp.last_edit_player
local last_edit_time = warp.last_edit_time
local position = warp.position
@@ -608,22 +398,23 @@ Gui.new_left_frame('gui/warp-list')
:set_direction('vertical')
:on_creation(function(player,element)
local data_table = generate_container(player,element)
local force_name = player.force.name
local warps = Warps.get_warps(player.force.name)
local warps = force_warps[force_name] or {}
for _,warp_id in pairs(warps) do
generate_warp(player,data_table,warp_id)
for key,warp_id in pairs(warps) do
if key ~= 'spawn' then
generate_warp(player,data_table,warp_id)
end
end
end)
:on_update(function(player,element)
local data_table = element.container.scroll.table
local force_name = player.force.name
local warps = Warps.get_warps(player.force.name)
data_table.clear()
local warps = force_warps[force_name] or {}
for _,warp_id in pairs(warps) do
generate_warp(player,data_table,warp_id)
for key,warp_id in pairs(warps) do
if key ~= 'spawn' then
generate_warp(player,data_table,warp_id)
end
end
end)
:on_player_toggle(function(player,element,visible)
@@ -631,47 +422,12 @@ end)
end)
--- When the name of a warp is updated this is triggered
Store.register(warp_name_store,function(value,warp_id)
local warp = warp_details[warp_id]
local force = game.forces[warp.force]
local names = {}
local spawn_id
for _,_warp_id in pairs(force_warps[force.name]) do
local name = Store.get(warp_name_store,_warp_id)
if not warp_details[_warp_id].editing then
spawn_id = _warp_id
else
names[name.._warp_id] = _warp_id
end
end
force_warps[force.name] = table_values(table_keysort(names))
table.insert(force_warps[force.name],1,spawn_id)
Warps.add_handler(function(force,warp_id)
for _,player in pairs(force.players) do
warp_list:update(player)
end
end)
--- When the icon is updated this is called
Store.register(warp_icon_store,function(value,warp_id)
local warp = warp_details[warp_id]
local force = game.forces[warp.force]
for _,player in pairs(force.players) do
local frame = warp_list:get_frame(player)
local element = frame.container.scroll.table
generate_warp(player,element,warp_id)
end
if value then
make_warp_tag(warp_id)
else
clear_warp_area(warp_id)
end
end)
--- When the player leaves or enters range of a warp this is triggered
Store.register(warp_player_in_range_store,function(value,player_name)
local player = game.players[player_name]
@@ -689,17 +445,16 @@ Store.register(warp_player_in_range_store,function(value,player_name)
return
end
if force_warps[force.name] then
for _,warp_id in pairs(force_warps[force.name]) do
local element = table_area['icon-'..warp_id][goto_warp.name]
if element and element.valid then
element.enabled = state
if state then
local position = warp_details[warp_id].position
element.tooltip = {'warp-list.goto-tooltip',position.x,position.y}
else
element.tooltip = {'warp-list.goto-disabled'}
end
local warps = Warps.get_warps(force.name)
for _,warp_id in pairs(warps) do
local element = table_area['icon-'..warp_id][goto_warp.name]
if element and element.valid then
element.enabled = state
if state then
local position = Warps.get_details(warp_id).position
element.tooltip = {'warp-list.goto-tooltip',position.x,position.y}
else
element.tooltip = {'warp-list.goto-disabled'}
end
end
end
@@ -717,15 +472,15 @@ Event.on_nth_tick(math.floor(60/config.update_smoothing),function()
for _,player in pairs(game.connected_players) do
local was_in_range = Store.get(warp_player_in_range_store,player.name)
local force = player.force
local warps = force_warps[force.name]
local warps = Warps.get_warps(force.name)
if warps then
if #warps > 0 then
local surface = player.surface.index
local pos = player.position
local px,py = pos.x,pos.y
for _,warp_id in pairs(warps) do
local warp = warp_details[warp_id]
local warp_pos = warp.position
local warp = Warps.get_details(warp_id)
local wpos = warp.position
if warp.surface.index == surface then
local dx,dy = px-warp_pos.x,py-warp_pos.y
if not warp.editing and (dx*dx)+(dy*dy) < rs2 or (dx*dx)+(dy*dy) < r2 then
@@ -749,7 +504,6 @@ end)
--- When a player is created it will set them being in range to false to stop warping on join
Event.add(defines.events.on_player_created,function(event)
local player = Game.get_player_by_index(event.player_index)
local force_name = player.force.name
local allowed = config.bypass_warp_limits_permission and Roles.player_allowed(player,config.bypass_warp_limits_permission) or false
Store.set(warp_player_in_range_store,player.name,allowed)
@@ -757,24 +511,22 @@ Event.add(defines.events.on_player_created,function(event)
warp_timer:set_store(player.name,1)
end
if not force_warps[force_name] then
add_spawn(player)
end
local force = player.force
local spawn_position = force.get_spawn_position(player.surface)
Warps.new_warp(force.name,player.surface,spawn_position,nil,'Spawn',true,true)
end)
local function maintain_tag(event)
local tag = event.tag
local force = event.force
local warps = force_warps[force.name]
if warps then
for _,warp_id in pairs(warps) do
local warp = warp_details[warp_id]
if not warp.tag or not warp.tag.valid or warp.tag == tag then
if event.name == defines.events.on_chart_tag_removed then
warp.tag = nil
end
make_warp_tag(warp_id)
local warps = Warps.get_warps(force.name)
for _,warp_id in pairs(warps) do
local warp = Warps.get_warps(force.name)
if not warp.tag or not warp.tag.valid or warp.tag == tag then
if event.name == defines.events.on_chart_tag_removed then
warp.tag = nil
end
Warps.make_chart_tag(warp_id)
end
end
end