Merge pull request #190 from bbassie/feature/warp-net-id

Feature: Warps need to be connected to the same electricity network
This commit is contained in:
Cooldude2606
2021-03-30 03:58:44 +01:00
committed by GitHub
4 changed files with 552 additions and 315 deletions

View File

@@ -29,13 +29,24 @@ return {
-- Warp area generation
entities = { --- @setting entities The entities which are created for warp areas
{'small-lamp',-3,-2},{'small-lamp',-3,2},{'small-lamp',3,-2},{'small-lamp',3,2},
{'small-lamp',-2,-3},{'small-lamp',2,-3},{'small-lamp',-2,3},{'small-lamp',2,3},
{'small-electric-pole',-3,-3},{'small-electric-pole',3,3},{'small-electric-pole',-3,3},{'small-electric-pole',3,-3}
{'small-lamp', -4, -2}, {'small-lamp', -2, -4}, {'small-electric-pole',-3,-3}, -- Top left corner
{'small-lamp', 3, -2}, {'small-lamp', 1, -4}, {'small-electric-pole',2,-3}, -- Top right corner
{'small-lamp', 3, 1}, {'small-lamp', 1, 3}, {'small-electric-pole',2,2}, -- Bottom right corner
{'small-lamp', -4, 1}, {'small-lamp', -2, 3}, {'small-electric-pole',-3,2}, -- Bottom left corner
},
base_tile = 'tutorial-grid', --- @setting base_tile The tile which is used for the warp areas
tiles = { --- @setting tiles The tiles which are created for warp areas
{-3,-2},{-3,-1},{-3,0},{-3,1},{-3,2},{3,-2},{3,-1},{3,0},{3,1},{3,2},
{-2,-3},{-1,-3},{0,-3},{1,-3},{2,-3},{-2,3},{-1,3},{0,3},{1,3},{2,3}
{"black-refined-concrete",-4,-2},{"black-refined-concrete",-4,-1},{"black-refined-concrete",-4,0},{"black-refined-concrete",-4,1},
{"black-refined-concrete",-3,-3},{"purple-refined-concrete",-3,-2},{"purple-refined-concrete",-3,-1},{"purple-refined-concrete",-3,0},
{"purple-refined-concrete",-3,1},{"black-refined-concrete",-3,2},{"black-refined-concrete",-2,-4},{"purple-refined-concrete",-2,-3},
{"purple-refined-concrete",-2,-2},{"purple-refined-concrete",-2,-1},{"purple-refined-concrete",-2,0},{"purple-refined-concrete",-2,1},
{"purple-refined-concrete",-2,2},{"black-refined-concrete",-2,3},{"black-refined-concrete",-1,-4},{"purple-refined-concrete",-1,-3},
{"purple-refined-concrete",-1,-2},{"purple-refined-concrete",-1,-1},{"purple-refined-concrete",-1,0},{"purple-refined-concrete",-1,1},
{"purple-refined-concrete",-1,2},{"black-refined-concrete",-1,3},{"black-refined-concrete",0,-4},{"purple-refined-concrete",0,-3},
{"purple-refined-concrete",0,-2},{"purple-refined-concrete",0,-1},{"purple-refined-concrete",0,0},{"purple-refined-concrete",0,1},
{"purple-refined-concrete",0,2},{"black-refined-concrete",0,3},{"black-refined-concrete",1,-4},{"purple-refined-concrete",1,-3},
{"purple-refined-concrete",1,-2},{"purple-refined-concrete",1,-1},{"purple-refined-concrete",1,0},{"purple-refined-concrete",1,1},
{"purple-refined-concrete",1,2},{"black-refined-concrete",1,3},{"black-refined-concrete",2,-3},{"purple-refined-concrete",2,-2},
{"purple-refined-concrete",2,-1},{"purple-refined-concrete",2,0},{"purple-refined-concrete",2,1},{"black-refined-concrete",2,2},
{"black-refined-concrete",3,-2},{"black-refined-concrete",3,-1},{"black-refined-concrete",3,0},{"black-refined-concrete",3,1}
}
}
}

View File

@@ -91,20 +91,34 @@ invalid=Autofill set to maximum amount: __1__ __2__ for __3__
inserted=Inserted __1__ __2__ into __3__
[warp-list]
main-caption=Warp List
main-caption=Warp List [img=info]
main-tooltip=Warp List; Must be within __1__ tiles to use
sub-tooltip=Warps can only be used every __1__ seconds and when within __2__ tiles
too-close=Can't make warp; too close to warp: __1__
sub-tooltip=Warps can only be used every __1__ seconds and when within __2__ tiles\n__3__\n__4__\n__5__\n__6__\n__7__\n__8__
sub-tooltip-current= - __1__ This is your current warp point;
sub-tooltip-connected= - __1__ You can travel to this warp point;
sub-tooltip-different= - __1__ This warp is on a different network;
sub-tooltip-cooldown= - __1__ You are currently on cooldown;
sub-tooltip-not_available= - __1__ You are not in range of a warp point;
sub-tooltip-bypass= - __1__ Your role allows you to travel here;
too-close=Cannot create warp; too close to existing warp point: __1__
too-close-to-water=Cannot create warp; too close to water, please move __1__ tiles away from the water body or landfill it
too-close-to-entities=Cannot create warp; too close to other entities, please move __1__ tiles away from the entities or remove them
last-edit=Last edited by __1__ at __2__\nClick to view on map
add-tooltip=Add new warp
confirm-tooltip=Save changes
cancel-tooltip=Discard changes
edit-tooltip=Currently being edited by: __1__
edit-tooltip-none=Currently being edited by: Nobody
discard-tooltip=Remove warp
timer-tooltip=Warp cooldown takes __1__ seconds
remove-tooltip=Remove warp
timer-tooltip=Please wait __1__ seconds before you can warp
timer-tooltip-zero=After each warp you will need to wait __1__ seconds before you can warp again
goto-tooltip=Go to x __1__ y __2__
goto-disabled=You must be on a warp point and have a full charge to warp
goto-bypass=Go to x __1__ y __2__, bypass mode
goto-bypass-different-network=Go to x __1__ y __2__, bypass mode different network
goto-same-warp=You are already on this warp
goto-different-network=This warp is on a different network, use power poles to connect it
goto-cooldown=You are on cooldown, wait for your cooldown to recharge
goto-disabled=You are not on a warp point, walk to a warp point
goto-edit=Edit warp icon
[readme]

View File

@@ -37,9 +37,16 @@ Global.register(force_warps, function(tbl)
force_warps = tbl
end)
-- When a warp is updated change its chat tag and resort the warp order
-- Create an array of entity names that will be added to the remove filter
local remove_warp_area_entity_names = {}
for _, entity in pairs(config.entities) do
table.insert(remove_warp_area_entity_names, entity[1])
end
-- When a warp is updated change its chat tag and restore the warp order
WrapData:on_update(function(warp_id, warp, old_warp)
if warp then
warp.updates = warp.updates + 1
-- Update the map chart tag if there is one
if warp.tag then
Warps.make_warp_tag(warp_id)
@@ -148,31 +155,15 @@ function Warps.make_warp_area(warp_id)
local position = warp.position
local posx = position.x
local posy = position.y
local radius = config.standard_proximity_radius
local radius2 = radius^2
-- Get the tile that is being replaced, store.update not needed as we dont want it to trigger
-- Get the tile that is being replaced, store.update not needed as we don't want it to trigger
local old_tile = surface.get_tile(position).name
warp.old_tile = old_tile
-- Make a circle that acts as a base for the warp structure
local base_tile = config.base_tile
local base_tiles = {}
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+posx, y+posy}})
end
end
end
surface.set_tiles(base_tiles)
-- Add a tile pattern on top of the base
local tiles = {}
for _, pos in pairs(config.tiles) do
table.insert(tiles, {name=base_tile, position={pos[1]+posx, pos[2]+posy}})
for _, tile in pairs(config.tiles) do
table.insert(tiles, {name=tile[1], position={tile[2]+posx, tile[3]+posy}})
end
surface.set_tiles(tiles)
@@ -187,6 +178,11 @@ function Warps.make_warp_area(warp_id)
entity.health = 0
entity.minable = false
entity.rotatable = false
-- Save reference of the last power pole
if entity.type == 'electric-pole' then
warp.electric_pole = entity
end
end
end
@@ -202,22 +198,15 @@ function Warps.remove_warp_area(warp_id)
local position = warp.position
local surface = warp.surface
local radius = config.standard_proximity_radius
local radius2 = radius^2
-- Check that a warp area was created previously
local base_tile = warp.old_tile
if not base_tile then return end
local old_tile = warp.old_tile
if not old_tile then return end
-- Reset all the tiles that were replaced
-- Restore the original tiles before the creation of the warp
local tiles = {}
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
for _, tile in pairs(config.tiles) do
table.insert(tiles, {name=old_tile, position={tile[2]+position.x, tile[3]+position.y}})
end
surface.set_tiles(tiles)
@@ -226,11 +215,17 @@ function Warps.remove_warp_area(warp_id)
{position.x+radius, position.y+radius}
}
-- Remove all the entities that are in the area
local entities = surface.find_entities_filtered{ force='neutral', area=area }
for _, entity in pairs(entities) do if entity and entity.valid and entity.name ~= 'player' then entity.destroy() end end
-- Remove warp structure entities
local entities = surface.find_entities_filtered{ force='neutral', area=area, name = remove_warp_area_entity_names }
for _, entity in pairs(entities) do
-- Destroy them, this will leave corpses of the entities that it destroyed.
if entity and entity.valid and entity.destructible == false then
entity.destructible = true
entity.die(entity.force)
end
end
-- Rechart map area, usefull if warp is not covered by a radar
-- Rechart map area, useful if warp is not covered by a radar
game.forces[warp.force_name].chart(surface, area)
end
@@ -351,7 +346,8 @@ function Warps.add_warp(force_name, surface, position, player_name, warp_name)
},
last_edit_name = player_name or '<server>',
last_edit_time = game.tick,
currently_editing = editing
currently_editing = editing,
updates = 0,
})
return warp_id
@@ -385,6 +381,11 @@ Warps.update_warp(warp_id, 'My Warp', 'iron-plate', game.player.name)
]]
function Warps.update_warp(warp_id, new_name, new_icon, player_name)
WrapData:update(warp_id, function(_, warp)
-- If the icon is not valid then replace with the old icon
if new_icon and not new_icon.name or not new_icon.type then
new_icon = warp.icon
end
warp.last_edit_name = player_name or '<server>'
warp.last_edit_time = game.tick
warp.name = new_name or warp.name
@@ -476,4 +477,4 @@ function Warps.get_editing(warp_id, player_name)
end
-- Module return
return Warps
return Warps

View File

@@ -12,7 +12,7 @@ local Roles = require 'expcore.roles' --- @dep expcore.roles
local Colors = require 'utils.color_presets' --- @dep utils.color_presets
local config = require 'config.gui.warps' --- @dep config.gui.warps
local Warps = require 'modules.control.warps' --- @dep modules.control.warps
local format_time = _C.format_time --- @dep expcore.common
local format_time, player_return = _C.format_time, _C.player_return --- @dep expcore.common
--- Stores all data for the warp gui
local WrapGuiData = Datastore.connect('WrapGuiData')
@@ -30,10 +30,18 @@ end)
--- Styles used for sprite buttons
local Styles = {
sprite20 = Gui.sprite_style(20),
sprite22 = Gui.sprite_style(20, nil, { right_margin = -3 }),
sprite22 = { height = 22, width = 22, padding = -2 },
sprite32 = { height = 32, width = 32, left_margin = 1 }
}
--- Status icon of a warp
local warp_status_icons = {
cooldown = '[img=utility/multiplayer_waiting_icon]',
not_available = '[img=utility/set_bar_slot]',
bypass = '[img=utility/side_menu_bonus_icon]',
current = '[img=utility/side_menu_map_icon]',
connected = '[img=utility/logistic_network_panel_white]',
different = '[img=utility/warning_white]',
}
--- Returns if a player is allowed to edit the given warp
--- If a player is allowed to use the edit buttons
@@ -73,180 +81,73 @@ Gui.element{
type = 'sprite-button',
sprite = 'utility/add',
tooltip = {'warp-list.add-tooltip'},
style = 'tool_button'
style = 'shortcut_bar_button'
}
:style(Styles.sprite20)
:style(Styles.sprite22)
:on_click(function(player, _)
-- Add the new warp
local force_name = player.force.name
local surface = player.surface
local position = player.position
-- Check if the warp is too close to water
local water_tiles = surface.find_tiles_filtered{ collision_mask = "water-tile", radius = config.standard_proximity_radius + 1, position = position }
if #water_tiles > 0 then
player_return({'expcore-commands.command-fail', {'warp-list.too-close-to-water', config.standard_proximity_radius + 1}}, 'orange_red', player)
if game.player then game.player.play_sound{ path = 'utility/wire_pickup' } end
for _, tile in pairs(water_tiles) do
rendering.draw_sprite{
sprite = 'utility/rail_path_not_possible',
x_scale = 0.5,
y_scale = 0.5,
target = tile.position,
surface = surface,
players = {player},
time_to_live = 60
}
end
return
end
-- Check if there are player entities in the way (has a bigger radius because the enities that can be placed by a player are larger)
local entities = surface.find_entities_filtered{
radius = config.standard_proximity_radius + 4.5,
position = position,
collision_mask = {
'item-layer', 'object-layer', 'player-layer', 'water-tile'
}
}
-- Remove 1 because that is the current player
if #entities > 1 then
player_return({'expcore-commands.command-fail', {'warp-list.too-close-to-entities', config.standard_proximity_radius + 4.5}}, 'orange_red', player)
if game.player then game.player.play_sound{path='utility/wire_pickup'} end
local character = player.character
for _, entity in pairs(entities) do
if entity ~= character then
rendering.draw_sprite{
sprite = 'utility/rail_path_not_possible',
x_scale = 0.5,
y_scale = 0.5,
target = entity,
surface = surface,
players = {player},
time_to_live = 60
}
end
end
return
end
-- Create the warp
local warp_id = Warps.add_warp(force_name, surface, position, player.name)
Warps.make_warp_tag(warp_id)
Warps.make_warp_area(warp_id)
end)
--- Removes a warp from the list, including the physical area and map tag
-- @element discard_warp
local discard_warp =
Gui.element{
type = 'sprite-button',
sprite = 'utility/trash',
tooltip = {'warp-list.discard-tooltip'},
style = 'tool_button'
}
:style(Styles.sprite20)
:on_click(function(_, element)
local warp_id = element.parent.name:sub(6)
Warps.remove_warp(warp_id)
end)
--- Opens edit mode for the warp
-- @element edit_warp
local edit_warp =
Gui.element{
type = 'sprite-button',
sprite = 'utility/rename_icon_normal',
tooltip = {'warp-list.edit-tooltip-none'},
style = 'tool_button'
}
:style(Styles.sprite20)
:on_click(function(player, element)
local warp_id = element.parent.name:sub(6)
Warps.set_editing(warp_id, player.name, true)
end)
--- Set of three elements which make up each row of the warp table
-- @element add_warp_base
local add_warp_base =
Gui.element(function(_, parent, warp_id)
-- Add the icon flow
local icon_flow =
parent.add{
name = 'icon-'..warp_id,
type = 'flow',
caption = warp_id
}
icon_flow.style.padding = 0
-- Add a flow which will contain the warp name and edit buttons
local warp_flow = parent.add{ type = 'flow', name = warp_id }
warp_flow.style.padding = 0
-- Add the two edit buttons outside the warp flow
local edit_flow = Gui.alignment(parent, 'edit-'..warp_id)
edit_warp(edit_flow)
discard_warp(edit_flow)
-- Return the warp flow as the main element
return warp_flow
end)
-- Removes the three elements that are added as part of the warp base
local function remove_warp_base(parent, warp_id)
Gui.destroy_if_valid(parent['icon-'..warp_id])
Gui.destroy_if_valid(parent['edit-'..warp_id])
Gui.destroy_if_valid(parent[warp_id])
end
--- Confirms the edit to name or icon of the warp
-- @element confirm_edit
local warp_editing
local warp_icon_button
local confirm_edit =
Gui.element{
type = 'sprite-button',
sprite = 'utility/confirm_slot',
tooltip = {'warp-list.confirm-tooltip'},
style = 'shortcut_bar_button_green'
}
:style(Styles.sprite22)
:on_click(function(player, element)
local warp_id = element.parent.name
local warp_name = element.parent[warp_editing.name].text
local warp_icon = element.parent.parent['icon-'..warp_id][warp_icon_button.name].elem_value
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
-- @element cancel_edit
local cancel_edit =
Gui.element{
type = 'sprite-button',
sprite = 'utility/close_black',
tooltip = {'warp-list.cancel-tooltip'},
style = 'shortcut_bar_button_red'
}
:style(Styles.sprite22)
:on_click(function(player, element)
local warp_id = element.parent.name
Warps.set_editing(warp_id, player.name)
end)
--- Editing state for a warp, contains a text field and the two edit buttons
-- @element warp_editing
warp_editing =
Gui.element(function(event_trigger, parent, warp)
local name = warp.name
-- Draw the element
local element =
parent.add{
name = event_trigger,
type = 'textfield',
text = name,
clear_and_focus_on_right_click = true
}
-- Add the edit buttons
cancel_edit(parent)
confirm_edit(parent)
-- Return the element
return element
end)
:style{
maximal_width = 110,
height = 20
}
:on_confirmed(function(player, element, _)
local warp_id = element.parent.name
local warp_name = element.text
local warp_icon = element.parent.parent['icon-'..warp_id][warp_icon_button.name].elem_value
Warps.set_editing(warp_id, player.name)
Warps.update_warp(warp_id, warp_name, warp_icon, player.name)
end)
--- Default state for a warp, contains only a label with the warp name
-- @element warp_label
local warp_label =
Gui.element(function(event_trigger, parent, warp)
local last_edit_name = warp.last_edit_name
local last_edit_time = warp.last_edit_time
-- Draw the element
return parent.add{
name = event_trigger,
type = 'label',
caption = warp.name,
tooltip = {'warp-list.last-edit', last_edit_name, format_time(last_edit_time)}
}
end)
:style{
single_line = false,
maximal_width = 150
}
:on_click(function(player, element, _)
local warp_id = element.parent.name
local warp = Warps.get_warp(warp_id)
local position = warp.position
player.zoom_to_world(position, 1.5)
end)
local update_wrap_buttons
--- Default state for the warp icon, when pressed teleports the player
--- Warp icon button, this will trigger a warp when the player is able to
-- @element warp_icon_button
warp_icon_button =
local warp_icon_button =
Gui.element(function(event_trigger, parent, warp)
local warp_position = warp.position
@@ -273,17 +174,18 @@ end)
-- Reset the warp cooldown if the player does not have unlimited warps
if not check_player_permissions(player, 'bypass_warp_cooldown') then
PlayerCooldown:set(player, config.cooldown_duration)
update_wrap_buttons(player)
PlayerCooldown:set(player, config.update_smoothing*config.cooldown_duration)
end
PlayerInRange:set(player, warp_id)
end)
--- Editing state for the warp icon, chose elem used to chosse icon
--- The button that is visible when the warp is in edit state
-- @element warp_icon_editing
local warp_icon_editing =
Gui.element(function(_, parent, warp)
Gui.element(function(event_trigger, parent, warp)
return parent.add{
name = warp_icon_button.name,
name = event_trigger,
type = 'choose-elem-button',
elem_type = 'signal',
signal = {type = warp.icon.type, name = warp.icon.name},
@@ -292,12 +194,215 @@ Gui.element(function(_, parent, warp)
end)
:style(Styles.sprite32)
--- Warp label, visible if the player is not in edit state
-- @element warp_label
local warp_label =
Gui.element(function(event_trigger, parent, warp)
local last_edit_name = warp.last_edit_name
local last_edit_time = warp.last_edit_time
-- Draw the element
return parent.add{
name = event_trigger,
type = 'label',
caption = warp.name,
tooltip = {'warp-list.last-edit', last_edit_name, format_time(last_edit_time)}
}
end)
:style{
single_line = true,
left_padding = 2,
right_padding = 2,
horizontally_stretchable = true
}
:on_click(function(player, element, _)
local warp_id = element.parent.caption
local warp = Warps.get_warp(warp_id)
local position = warp.position
player.zoom_to_world(position, 1.5)
end)
--- Warp status, visible if the player is not in edit state
--- This will show if the warp is connected or not
-- @element warp_status
local warp_status =
Gui.element(function(event_trigger, parent)
-- Draw the element
return parent.add{
name = event_trigger,
type = 'label',
caption = '[img=utility/electricity_icon_unplugged]', -- Temporary icon
}
end)
:style{
-- When editing mode because textbox is larger the icon would move up.
top_padding = 1,
single_line = false,
}
--- Warp textfield, visible if the player is in edit state
-- @element warp_textfield
local warp_textfield =
Gui.element(function(event_trigger, parent, warp)
-- Draw the element
return parent.add{
name = event_trigger,
type = 'textfield',
text = warp.name,
clear_and_focus_on_right_click = true
}
end)
:style{
-- Required fields to make it squashable and strechable.
minimal_width = 10,
maximal_width = 300,
horizontally_squashable = "on",
horizontally_stretchable = "on",
-- Other styling
height = 22,
padding = -2,
left_margin = 2,
right_margin = 2,
}
:on_confirmed(function(player, element, _)
local warp_id = element.parent.caption
local warp_name = element.text
local warp_icon = element.parent.parent['icon-'..warp_id][warp_icon_editing.name].elem_value
Warps.set_editing(warp_id, player.name)
Warps.update_warp(warp_id, warp_name, warp_icon, player.name)
end)
--- Confirms the edit to name or icon of the warp
-- @element confirm_edit_button
local confirm_edit_button =
Gui.element{
type = 'sprite-button',
sprite = 'utility/confirm_slot',
tooltip = {'warp-list.confirm-tooltip'},
style = 'shortcut_bar_button_green'
}
:style(Styles.sprite22)
:on_click(function(player, element)
local warp_id = element.parent.caption
local warp_name = element.parent.parent['name-'..warp_id][warp_textfield.name].text
local warp_icon = element.parent.parent['icon-'..warp_id][warp_icon_editing.name].elem_value
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
-- @element cancel_edit_button
local cancel_edit_button =
Gui.element{
type = 'sprite-button',
sprite = 'utility/close_black',
tooltip = {'warp-list.cancel-tooltip'},
style = 'shortcut_bar_button_red'
}
:style(Styles.sprite22)
:on_click(function(player, element)
local warp_id = element.parent.caption
-- Check if this is the first edit, if so remove the warp.
local warp = Warps.get_warp(warp_id)
if warp.updates == 1 then
Warps.remove_warp(warp_id)
return
end
Warps.set_editing(warp_id, player.name)
end)
--- Removes a warp from the list, including the physical area and map tag
-- @element remove_warp_button
local remove_warp_button =
Gui.element{
type = 'sprite-button',
sprite = 'utility/trash',
tooltip = {'warp-list.remove-tooltip'},
style = 'shortcut_bar_button_red'
}
:style(Styles.sprite22)
:on_click(function(_, element)
local warp_id = element.parent.caption
Warps.remove_warp(warp_id)
end)
--- Opens edit mode for the warp
-- @element edit_warp_button
local edit_warp_button =
Gui.element{
type = 'sprite-button',
sprite = 'utility/rename_icon_normal',
tooltip = {'warp-list.edit-tooltip-none'},
style = 'shortcut_bar_button'
}
:style(Styles.sprite22)
:on_click(function(player, element)
local warp_id = element.parent.caption
Warps.set_editing(warp_id, player.name, true)
end)
local update_all_warp_elements
--- Set of three elements which make up each row of the warp table
-- @element add_warp_elements
local add_warp_elements =
Gui.element(function(_, parent, warp)
-- Add icon flow, this will contain the warp button and warp icon edit button
local icon_flow = parent.add{
name = 'icon-'..warp.warp_id,
type = 'flow',
caption = warp.warp_id
}
icon_flow.style.padding = 0
-- Add the button and the icon edit button
warp_icon_button(icon_flow, warp)
warp_icon_editing(icon_flow, warp)
-- Add name flow, this will contain the warp label and textbox
local name_flow = parent.add{
type = 'flow',
name = 'name-'..warp.warp_id,
caption = warp.warp_id
}
name_flow.style.padding = 0
-- Add the label and textfield of the warp
warp_status(name_flow)
warp_label(name_flow, warp)
warp_textfield(name_flow, warp)
-- Add button flow, this will contain buttons to manage this specific warp
local button_flow = parent.add{
type = 'flow',
name = 'button-'..warp.warp_id,
caption = warp.warp_id
}
button_flow.style.padding = 0
-- Add both edit state buttons
confirm_edit_button(button_flow)
cancel_edit_button(button_flow)
edit_warp_button(button_flow)
remove_warp_button(button_flow)
-- Return the warp flow elements
return { icon_flow, name_flow, button_flow }
end)
-- Removes the three elements that are added as part of the warp base
local function remove_warp_elements(parent, warp_id)
Gui.destroy_if_valid(parent['icon-'..warp_id])
Gui.destroy_if_valid(parent['name-'..warp_id])
Gui.destroy_if_valid(parent['button-'..warp_id])
end
--- This timer controls when a player is able to warp, eg every 60 seconds
-- @element warp_timer
local warp_timer =
Gui.element{
type = 'progressbar',
tooltip = {'warp-list.timer-tooltip', config.cooldown_duration},
tooltip = {'warp-list.timer-tooltip-zero', config.cooldown_duration},
minimum_value = 0,
maximum_value = config.cooldown_duration*config.update_smoothing
}
@@ -307,30 +412,97 @@ Gui.element{
}
local warp_list_container
-- Helper function to style and enable or disable a button element
local function update_warp_elements(element, warp, warp_player_is_on, on_cooldown, bypass_warp_proximity)
-- Check if button element is valid
if not element or not element.valid then return end
local label_style = element.parent.parent['name-'..warp.warp_id][warp_label.name].style
local warp_status_element = element.parent.parent['name-'..warp.warp_id][warp_status.name]
-- If player is not on a warp
if not warp_player_is_on then
-- If player is allowed to warp without being on a warp. If not then disable the warp location
if bypass_warp_proximity then
local position = warp.position
element.tooltip = {'warp-list.goto-bypass', position.x, position.y}
element.enabled = true
warp_status_element.tooltip = {'warp-list.goto-bypass', position.x, position.y}
warp_status_element.caption = warp_status_icons.bypass
label_style.font = 'default-semibold'
else
element.tooltip = {'warp-list.goto-disabled'}
element.enabled = false
warp_status_element.tooltip = {'warp-list.goto-disabled'}
warp_status_element.caption = warp_status_icons.not_available
label_style.font = 'default'
end
-- If player is on the warp that is being updated
elseif warp_player_is_on.warp_id == warp.warp_id then
element.tooltip = {'warp-list.goto-same-warp'}
element.enabled = false
warp_status_element.tooltip = {'warp-list.goto-same-warp'}
warp_status_element.caption = warp_status_icons.current
label_style.font = 'default'
-- If player is on cooldown
elseif on_cooldown then
element.tooltip = {'warp-list.goto-cooldown'}
element.enabled = false
warp_status_element.tooltip = {'warp-list.goto-cooldown'}
warp_status_element.caption = warp_status_icons.cooldown
label_style.font = 'default'
else
-- If the warp the player is standing on is the same as the warp that is being updated
local warp_electric_network_id = warp.electric_pole and warp.electric_pole.electric_network_id or -1
local player_warp_electric_network_id = warp_player_is_on.electric_pole and warp_player_is_on.electric_pole.electric_network_id or -2
if warp_electric_network_id == player_warp_electric_network_id then
local position = warp.position
element.tooltip = {'warp-list.goto-tooltip', position.x, position.y}
element.enabled = true
warp_status_element.tooltip = {'warp-list.goto-tooltip', position.x, position.y}
warp_status_element.caption = warp_status_icons.connected
label_style.font = 'default-semibold'
-- If the warp is not on the same network but the player is allowed to warp without being on a warp
elseif bypass_warp_proximity then
local position = warp.position
element.tooltip = {'warp-list.goto-bypass-different-network', position.x, position.y}
element.enabled = true
warp_status_element.tooltip = {'warp-list.goto-bypass-different-network', position.x, position.y}
warp_status_element.caption = warp_status_icons.bypass
label_style.font = 'default-semibold'
-- If the warp is on a different network than the one the player is standing on
else
element.tooltip = {'warp-list.goto-different-network'}
element.enabled = false
warp_status_element.tooltip = {'warp-list.goto-different-network'}
warp_status_element.caption = warp_status_icons.different
label_style.font = 'default'
end
end
end
--- Update the warp buttons for a player
function update_wrap_buttons(player, timer, in_range)
function update_all_warp_elements(player, timer, warp_id)
-- Get the warp table
local frame = Gui.get_left_element(player, warp_list_container)
local scroll_table = frame.container.scroll.table
-- Check if the buttons should be active
-- Check if the player is currenty on cooldown
timer = timer or PlayerCooldown:get(player)
in_range = in_range or PlayerInRange:get(player)
local button_disabled = timer > 0 or not in_range
local on_cooldown = timer > 0
-- Get the warp the player is on
warp_id = warp_id or PlayerInRange:get(player)
local warp_player_is_on = warp_id and Warps.get_warp(warp_id) or nil
-- Check player permission
local bypass_warp_proximity = check_player_permissions(player, 'bypass_warp_proximity')
-- Change the enabled state of the warp buttons
local warp_ids = Warps.get_force_warp_ids(player.force.name)
for _, warp_id in pairs(warp_ids) do
local element = scroll_table['icon-'..warp_id][warp_icon_button.name]
if element and element.valid then
element.enabled = not button_disabled
if button_disabled then
element.tooltip = {'warp-list.goto-disabled'}
else
local position = Warps.get_warp(warp_id).position
element.tooltip = {'warp-list.goto-tooltip', position.x, position.y}
end
end
for _, next_warp_id in pairs(warp_ids) do
local element = scroll_table['icon-'..next_warp_id][warp_icon_button.name]
local next_warp = Warps.get_warp(next_warp_id)
update_warp_elements(element, next_warp, warp_player_is_on, on_cooldown, bypass_warp_proximity)
end
end
@@ -338,25 +510,39 @@ end
local function update_warp(player, warp_table, warp_id)
local warp = Warps.get_warp(warp_id)
-- Warp no longer exists so should be removed from the list
-- If the warp no longer exists then remove the warp elements from the warp table
if not warp then
remove_warp_base(warp_table, warp_id)
remove_warp_elements(warp_table, warp_id)
return
end
-- Get the warp flow for this warp
local warp_flow = warp_table[warp_id] or add_warp_base(warp_table, warp_id)
-- Create the warp elements if they do not already exist
if not warp_table['icon-'..warp_id] then
add_warp_elements(warp_table, warp)
end
local icon_flow = warp_table['icon-'..warp_id]
local name_flow = warp_table['name-'..warp_id]
local button_flow = warp_table['button-'..warp_id]
-- Update the edit flow
local edit_flow = warp_table['edit-'..warp_id]
-- Create local references to the elements for this warp
local warp_icon_element = icon_flow[warp_icon_button.name]
local warp_icon_edit_element = icon_flow[warp_icon_editing.name]
local label_element = name_flow[warp_label.name]
local textfield_element = name_flow[warp_textfield.name]
local cancel_edit_element = button_flow[cancel_edit_button.name]
local confirm_edit_element = button_flow[confirm_edit_button.name]
local edit_warp_element = button_flow[edit_warp_button.name]
local remove_warp_element = button_flow[remove_warp_button.name]
-- Hide the edit button if the player is not allowed to edit the warp
local player_allowed_edit = check_player_permissions(player, 'allow_edit_warp', warp)
local players_editing = table.get_keys(warp.currently_editing)
local edit_warp_element = edit_flow[edit_warp.name]
local discard_warp_element = edit_flow[discard_warp.name]
edit_warp_element.visible = player_allowed_edit
discard_warp_element.visible = player_allowed_edit
-- Set the tooltip of the edit button
if #players_editing > 0 then
edit_warp_element.hovered_sprite = 'utility/warning_icon'
edit_warp_element.tooltip = {'warp-list.edit-tooltip', table.concat(players_editing, ', ')}
@@ -365,54 +551,53 @@ local function update_warp(player, warp_table, warp_id)
edit_warp_element.tooltip = {'warp-list.edit-tooltip-none'}
end
-- Check if the player is was editing and/or currently editing
local warp_label_element = warp_flow[warp_label.name] or warp_label(warp_flow, warp)
local icon_entry = icon_flow[warp_icon_button.name] or warp_icon_button(icon_flow, warp)
local player_was_editing = icon_entry.type == 'choose-elem-button'
-- Set the visibility of the warp elements based on whether the user is editing or not
local player_is_editing = warp.currently_editing[player.name]
-- Update the warp and icon flow
if not player_was_editing and not player_is_editing then
-- Update the warp name label and icon
local warp_name = warp.name
local warp_icon = warp.icon
local last_edit_name = warp.last_edit_name
local last_edit_time = warp.last_edit_time
warp_label_element.caption = warp_name
warp_label_element.tooltip = {'warp-list.last-edit', last_edit_name, format_time(last_edit_time)}
if player_is_editing then
-- Set the icon elements visibility
warp_icon_element.visible = false
warp_icon_edit_element.visible = true
-- Set the name elements visibility
label_element.visible = false
textfield_element.visible = true
textfield_element.focus()
warp_table.parent.scroll_to_element(textfield_element, 'top-third')
-- Set the edit buttons
cancel_edit_element.visible = true
confirm_edit_element.visible = true
-- Set the warp buttons
edit_warp_element.visible = false
remove_warp_element.visible = false
else
-- Set the icon elements visibility
warp_icon_element.visible = true
-- The SpritePath type is not the same as the SignalID type
local sprite = warp_icon.type .. '/' ..warp_icon.name
if warp_icon.type == 'virtual' then
sprite = 'virtual-signal/' ..warp_icon.name
local sprite = warp.icon.type .. '/' ..warp.icon.name
if warp.icon.type == 'virtual' then
sprite = 'virtual-signal/' ..warp.icon.name
end
icon_entry.sprite = sprite
elseif player_was_editing and not player_is_editing then
-- Player was editing but is no longer, remove text field and add label
edit_warp_element.enabled = true
warp_flow.clear()
warp_label(warp_flow, warp)
icon_flow.clear()
local warp_icon_element = warp_icon_button(icon_flow, warp)
local timer = PlayerCooldown:get(player)
local in_range = PlayerInRange:get(player)
local apply_proximity = not check_player_permissions(player, 'bypass_warp_proximity')
if timer > 0 or (apply_proximity and not in_range) then
warp_icon_element.enabled = false
warp_icon_element.tooltip = {'warp-list.goto-disabled'}
end
elseif not player_was_editing and player_is_editing then
-- Player was not editing but now is, remove label and add text field
edit_warp_element.enabled = false
warp_flow.clear()
warp_editing(warp_flow, warp).focus()
warp_table.parent.scroll_to_element(warp_flow, 'top-third')
icon_flow.clear()
warp_icon_editing(icon_flow, warp)
warp_icon_element.sprite = sprite
-- Set icon edit to the warps icon
warp_icon_edit_element.elem_value = warp.icon
warp_icon_edit_element.visible = false
-- Set the name elements visibility
label_element.visible = true
label_element.caption = warp.name
textfield_element.visible = false
textfield_element.text = warp.name
-- Set the edit buttons
cancel_edit_element.visible = false
confirm_edit_element.visible = false
-- Set the warp buttons
edit_warp_element.visible = true and player_allowed_edit
remove_warp_element.visible = true and player_allowed_edit
end
local timer = PlayerCooldown:get(player)
local current_warp_id = PlayerInRange:get(player)
local to_warp = current_warp_id and Warps.get_warp(current_warp_id) or nil
local bypass_warp_proximity = check_player_permissions(player, 'bypass_warp_proximity')
update_warp_elements(warp_icon_element, warp, to_warp, timer > 0, bypass_warp_proximity)
end
-- Update all the warps for a player
@@ -425,13 +610,12 @@ local function update_all_warps(player, warp_table)
end
-- Update all warps for all players on a force
local function update_all_wrap_force(force)
local function update_all_warp_force(force)
local warp_ids = Warps.get_force_warp_ids(force.name)
for _, player in pairs(force.connected_players) do
local frame = Gui.get_left_element(player, warp_list_container)
local warp_table = frame.container.scroll.table
warp_table.clear()
for _, warp_id in ipairs(warp_ids) do
update_warp(player, warp_table, warp_id)
end
@@ -442,24 +626,39 @@ end
-- @element warp_list_container
warp_list_container =
Gui.element(function(event_trigger, parent)
local player = Gui.get_player_from_element(parent)
-- Check if user has permission to add warps
local allow_add_warp = check_player_permissions(player, 'allow_add_warp')
-- Draw the internal container
local container = Gui.container(parent, event_trigger, 200)
local container = Gui.container(parent, event_trigger, allow_add_warp and 268 or 220)
-- Draw the header
local header = Gui.header(
container,
{'warp-list.main-caption'},
{'warp-list.sub-tooltip', config.cooldown_duration, config.standard_proximity_radius},
{
'warp-list.sub-tooltip',
config.cooldown_duration,
config.standard_proximity_radius,
{'warp-list.sub-tooltip-current',warp_status_icons.current},
{'warp-list.sub-tooltip-connected',warp_status_icons.connected},
{'warp-list.sub-tooltip-different',warp_status_icons.different},
{'warp-list.sub-tooltip-cooldown',warp_status_icons.cooldown},
{'warp-list.sub-tooltip-not_available',warp_status_icons.not_available},
{'warp-list.sub-tooltip-bypass',warp_status_icons.bypass},
},
true
)
-- Draw the new warp button
local player = Gui.get_player_from_element(parent)
local add_new_warp_element = add_new_warp(header)
add_new_warp_element.visible = check_player_permissions(player, 'allow_add_warp')
add_new_warp_element.visible = allow_add_warp
-- Draw the scroll table for the warps
local scroll_table = Gui.scroll_table(container, 250, 3)
-- Set the scroll panel to always show the scrollbar (not doing this will result in a changing gui size)
scroll_table.parent.vertical_scroll_policy = 'always'
-- Change the style of the scroll table
local scroll_table_style = scroll_table.style
@@ -470,12 +669,14 @@ Gui.element(function(event_trigger, parent)
local warp_timer_element = warp_timer(container)
-- Change the progress of the warp timer
local progress = 1
local timer = PlayerCooldown:get(player)
if timer > 0 then
progress = 1 - (timer/config.cooldown_duration)
warp_timer_element.tooltip = {'warp-list.timer-tooltip', math.floor(timer/config.update_smoothing)}
warp_timer_element.value = 1 - (timer/config.update_smoothing/config.cooldown_duration)
else
warp_timer_element.tooltip = {'warp-list.timer-tooltip-zero', config.cooldown_duration}
warp_timer_element.value = 1
end
warp_timer_element.value = progress
-- Add any existing warps
update_all_warps(player, scroll_table)
@@ -499,25 +700,22 @@ end)
Warps.on_update(function(_, warp, old_warp)
-- Get the force to update, warp is nil when removed
if warp then
update_all_wrap_force(game.forces[warp.force_name])
update_all_warp_force(game.forces[warp.force_name])
else
update_all_wrap_force(game.forces[old_warp.force_name])
update_all_warp_force(game.forces[old_warp.force_name])
end
end)
--- When the player leaves or enters range of a warp this is triggered
PlayerInRange:on_update(function(player_name, player_in_range)
PlayerInRange:on_update(function(player_name, warp_id)
local player = game.players[player_name]
-- Change if the frame is visible based on if the player is in range
if not keep_gui_open[player.name] then
Gui.toggle_left_element(player, warp_list_container, player_in_range)
Gui.toggle_left_element(player, warp_list_container, warp_id ~= nil)
end
-- Check if the player requires proximity
if not check_player_permissions(player, 'bypass_warp_proximity') then
update_wrap_buttons(player, nil, player_in_range)
end
update_all_warp_elements(player, nil, warp_id)
end)
--- Update the warp cooldown progress bars to match the current cooldown
@@ -528,15 +726,17 @@ PlayerCooldown:on_update(function(player_name, player_cooldown)
local warp_timer_element = frame.container[warp_timer.name]
-- Set the progress
local progress = 1
if player_cooldown and player_cooldown > 0 then
progress = 1 - (player_cooldown/config.cooldown_duration)
warp_timer_element.tooltip = {'warp-list.timer-tooltip', math.floor(player_cooldown/config.update_smoothing)}
warp_timer_element.value = 1 - (player_cooldown/config.update_smoothing/config.cooldown_duration)
else
warp_timer_element.tooltip = {'warp-list.timer-tooltip-zero', config.cooldown_duration}
warp_timer_element.value = 1
end
warp_timer_element.value = progress
-- Trigger update of buttons if cooldown is now 0
if player_cooldown == 0 then
update_wrap_buttons(player, player_cooldown, nil)
update_all_warp_elements(player, player_cooldown, nil)
end
end)
@@ -595,9 +795,9 @@ Event.on_nth_tick(math.floor(60/config.update_smoothing), function()
-- Check the dist to the closest warp
local in_range = closest_warp.warp_id == warp_ids.spawn and closest_distance < rs2 or closest_distance < r2
if was_in_range and not in_range then
PlayerInRange:set(player, false)
PlayerInRange:set(player, nil)
elseif not was_in_range and in_range then
PlayerInRange:set(player, true)
PlayerInRange:set(player, closest_warp.warp_id)
end
-- Change the enabled state of the add warp button
@@ -631,6 +831,12 @@ Event.add(defines.events.on_player_created, function(event)
spawn_id = Warps.add_warp(force.name, player.surface, spawn_position, nil, 'Spawn')
Warps.set_spawn_warp(spawn_id, force)
Warps.make_warp_tag(spawn_id)
local entities = player.surface.find_entities_filtered{ type = 'electric-pole', position = spawn_position, radius = 20, limit = 1 }
if entities and entities[1] then
local warp = Warps.get_warp(spawn_id)
warp.electric_pole = entities[1]
end
end
end)
@@ -647,13 +853,18 @@ local function role_update_event(event)
local player = game.players[event.player_index]
local container = Gui.get_left_element(player, warp_list_container).container
-- Check if user has permission to add warps
local allow_add_warp = check_player_permissions(player, 'allow_add_warp')
-- Update container size depending on whether the player is allowed to add warps
container.parent.style.width = allow_add_warp and 268 or 220
-- Update the warps, incase the user can now edit them
local scroll_table = container.scroll.table
update_all_warps(player, scroll_table)
-- Update the new warp button incase the user can now add them
local add_new_warp_element = container.header.alignment[add_new_warp.name]
add_new_warp_element.visible = check_player_permissions(player, 'allow_add_warp')
add_new_warp_element.visible = allow_add_warp
end
Event.add(Roles.events.on_role_assigned, role_update_event)
@@ -678,4 +889,4 @@ local function maintain_tag(event)
end
Event.add(defines.events.on_chart_tag_modified, maintain_tag)
Event.add(defines.events.on_chart_tag_removed, maintain_tag)
Event.add(defines.events.on_chart_tag_removed, maintain_tag)