175 lines
7.0 KiB
Lua

local add_vector = math2d.position.add
local subtract_vector = math2d.position.subtract
local rotate_vector = math2d.position.rotate_vector
local LINE_COLOR = { r = 0, g = 0.9, b = 0, a = 1 }
local LINE_WIDTH = 4
local HALF_WIDTH = (LINE_WIDTH / 2) / 32 -- 32 pixels per tile
local ARROW_TARGET_OFFSET = { 0, -0.75 }
local ARROW_ORIENTATED_OFFSET = { 0, -4 }
local ResultLocation = {}
function ResultLocation.clear_markers(player)
-- Clear all old markers belonging to player
if #game.players == 1 then
rendering.clear("FactorySearch")
else
local ids = rendering.get_all_ids("FactorySearch")
for _, id in pairs(ids) do
if rendering.get_players(id)[1].index == player.index then
rendering.destroy(id)
end
end
end
end
function ResultLocation.draw_markers(player, surface, selection_boxes)
local time_to_live = player.mod_settings["fs-highlight-duration"].value * 60
-- Draw new markers
for _, selection_box in pairs(selection_boxes) do
if selection_box.orientation then
local angle = selection_box.orientation * 360
-- Four corners
local left_top = selection_box.left_top
local right_bottom = selection_box.right_bottom
local right_top = {x = right_bottom.x, y = left_top.y}
local left_bottom = {x = left_top.x, y = right_bottom.y}
-- Extend the end of each line by HALF_WIDTH so that corners are still right angles despite `width`
local lines = {
{from = {x = left_top.x - HALF_WIDTH, y = left_top.y}, to = {x = right_top.x + HALF_WIDTH, y = right_top.y}}, -- Top
{from = {x = left_bottom.x - HALF_WIDTH, y = left_bottom.y}, to = {x = right_bottom.x + HALF_WIDTH, y = right_bottom.y}}, -- Bottom
{from = {x = left_top.x, y = left_top.y - HALF_WIDTH}, to = {x = left_bottom.x, y = left_bottom.y + HALF_WIDTH}}, -- Left
{from = {x = right_top.x, y = right_top.y - HALF_WIDTH}, to = {x = right_bottom.x, y = right_bottom.y + HALF_WIDTH}}, -- Right
}
local center = {x = (left_top.x + right_bottom.x) / 2, y = (left_top.y + right_bottom.y) / 2}
for _, line in pairs(lines) do
-- Translate each point to origin, rotate, then translate back
local rotated_from = add_vector(rotate_vector(subtract_vector(line.from, center), angle), center)
local rotated_to = add_vector(rotate_vector(subtract_vector(line.to, center), angle), center)
rendering.draw_line{
color = LINE_COLOR,
width = LINE_WIDTH,
from = rotated_from,
to = rotated_to,
surface = surface,
time_to_live = time_to_live,
players = {player},
}
end
else
rendering.draw_rectangle{
color = LINE_COLOR,
width = LINE_WIDTH,
filled = false,
left_top = selection_box.left_top,
right_bottom = selection_box.right_bottom,
surface = surface,
time_to_live = time_to_live,
players = {player},
}
end
--[[game.get_surface(surface).create_entity{
name = "highlight-box",
position = {0, 0}, -- Ignored by game
bounding_box = selection_box,
box_type = "copy", -- Green
render_player_index = player.index,
time_to_live = 600,
}]]
end
end
function ResultLocation.draw_arrows(player, surface, position)
local character = player.character
if (not character) and remote.interfaces["space-exploration"] then
character = remote.call("space-exploration", "get_player_character", { player = player })
end
if character and character.surface.name == surface and not (character.position.x == position.x and character.position.y == position.y) then
-- Skip arrow if positions are identical (i.e. target is character)
rendering.draw_sprite{
sprite = "fs_arrow",
x_scale = 1,
y_scale = 1,
target = character,
target_offset = ARROW_TARGET_OFFSET,
orientation_target = position,
oriented_offset = ARROW_ORIENTATED_OFFSET,
surface = surface,
time_to_live = player.mod_settings["fs-highlight-duration"].value * 60,
players = {player},
}
end
end
function ResultLocation.highlight(player, data)
local surface_name = data.surface
ResultLocation.clear_markers(player)
ResultLocation.draw_markers(player, surface_name, data.selection_boxes)
ResultLocation.draw_arrows(player, surface_name, data.position)
end
function ResultLocation.open(player, data)
local surface_name = data.surface
local position = data.position
local zoom_level = player.mod_settings["fs-initial-zoom"].value * player.display_resolution.width / 1920
-- If using factorissimo-2-notnotmelon, take the player to the outer position of the factory
if surface_name ~= player.surface.name and surface_name:sub(1, 14) == "factory-floor-" and remote.interfaces["factorissimo"] then
local factory
while surface_name:sub(1, 14) == "factory-floor-" do
factory = remote.call("factorissimo", "find_surrounding_factory", {name = surface_name}, position)
surface_name = factory.outside_surface.name
position = {x = factory.outside_x, y = factory.outside_y}
end
if factory.building then -- May not exist if building was mined or destroyed
data.surface = surface_name
data.position = position
data.selection_boxes = {[1] = factory.building.selection_box}
end
end
local remote_view_used = false
if remote.interfaces["space-exploration"] and remote.interfaces["space-exploration"]["remote_view_is_unlocked"] and
remote.call("space-exploration", "remote_view_is_unlocked", { player = player }) then
-- If Space Exploration's remote view is an option, then always use it
surface_name = surface_name:gsub("^%l", string.upper)
--if remote.call("space-exploration", "get_zone_from_name", {zone_name = surface_name}) then
remote.call("space-exploration", "remote_view_start", {player = player, zone_name = surface_name, position = position})
if remote.call("space-exploration", "remote_view_is_active", { player = player }) then
-- remote_view_start worked
remote_view_used = true
player.close_map()
player.zoom = zoom_level
end
end
if not remote_view_used then
if surface_name == player.surface.name then
player.zoom_to_world(position, zoom_level)
else
player.play_sound{path = "utility/cannot_build"}
player.create_local_flying_text{text = {"search-gui.wrong-surface"}, create_at_cursor = true}
end
end
ResultLocation.highlight(player, data)
end
-- Move arrow to new character when jetpack is activated
local function on_character_swapped_event(data)
local ids = rendering.get_all_ids("FactorySearch")
for _, id in pairs(ids) do
local target = rendering.get_target(id)
if target and target.entity and target.entity.unit_number == data.old_unit_number then
rendering.set_target(id, data.new_character, ARROW_TARGET_OFFSET)
end
end
end
remote.add_interface("FactorySearch", {on_character_swapped = on_character_swapped_event})
return ResultLocation