1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2025-01-05 22:53:39 +02:00
RedMew/features/gui/camera.lua
Matthew edf50d24f7 Add camera (#493)
* Add camera

* Rewrite camera

* Use global register

* Add runtime killswitch.

* Change to every 120 ticks
2018-12-15 21:29:14 +01:00

189 lines
7.3 KiB
Lua

--[[
Camera, used under MIT license.
Copyright 2018 angelickite
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
local Event = require 'utils.event'
local mod_gui = require 'mod-gui'
local Command = require 'utils.command'
local Game = require 'utils.game'
local Gui = require 'utils.gui'
local Global = require 'utils.global'
local main_button_name = Gui.uid_name()
local camera_users = {}
Global.register(
{
camera_users = camera_users,
},
function(tbl)
camera_users = tbl.camera_users
end
)
local zoomlevels = {1.00, 0.75, 0.50, 0.40, 0.30, 0.25, 0.20, 0.15, 0.10, 0.05}
local zoomlevellabels = {'100%', '75%', '50%', '40%', '30%', '25%', '20%', '15%', '10%', '5%'}
local sizelevels = {0, 100, 200, 250, 300, 350, 400, 450, 500}
local sizelevellabels = {'hide', '100x100', '200x200', '250x250', '300x300', '350x350', '400x400', '450x450', '500x500'}
local function apply_button_style(button)
local button_style = button.style
button_style.font = 'default-bold'
button_style.height = 26
button_style.top_padding = 0
button_style.bottom_padding = 0
button_style.left_padding = 2
button_style.right_padding = 2
end
local function create_destroy_camera(destroy, player, args, table_index)
local player_index = player.index
local mainframeflow = mod_gui.get_frame_flow(player)
local mainframeid = 'mainframe_' .. player_index
local mainframe = mainframeflow[mainframeid]
if table_index or destroy then
if camera_users[player_index] then
camera_users[player_index] = nil
else
player.print('No current target. Correct usage is /watch <target> to watch a player.')
end
if mainframe then
mainframe.destroy()
if args then
player.print('Closing camera.')
end
end
end
if args and args.target then
local target = game.players[args.target]
if not target then
player.print('Not a valid target')
return
end
if not mainframe then
mainframe = mainframeflow.add {type = 'frame', name = mainframeid, direction = 'vertical', style = 'captionless_frame'}
mainframe.style.visible = true
end
local headerframe = mainframe.headerframe
if not headerframe then
mainframe.add {type = 'frame', name = 'headerframe', direction = 'horizontal', style = 'captionless_frame'}
end
local cameraframe = mainframe.cameraframe
if not cameraframe then
mainframe.add {type = 'frame', name = 'cameraframe', style = 'captionless_frame'}
end
mainframe.add {type = 'label', caption = 'Following: ' .. args.target}
local close_button = mainframe.add {type = 'button', name = main_button_name, caption = 'Close'}
apply_button_style(close_button)
local target_index = target.index
camera_users[player_index] = target_index
end
end
local function update_camera_render(target, targetframe, zoom, size, visible)
local position = {x = target.position.x, y = target.position.y - 0.5}
local surface_index = target.surface.index
local preview_size = size
local camera = targetframe.camera
if not camera then
camera = targetframe.add {type = 'camera', name = 'camera', position = position, surface_index = surface_index, zoom = zoom}
end
camera.position = position
camera.surface_index = surface_index
camera.zoom = zoom
camera.style.visible = visible
camera.style.minimal_width = preview_size
camera.style.minimal_height = preview_size
camera.style.maximal_width = preview_size
camera.style.maximal_height = preview_size
end
local function update_camera_zoom(targetframe)
local zoomselection = targetframe.zoomselection
local zoomlabels = {}
for i = 1, #zoomlevellabels do
zoomlabels[i] = {'', '' .. zoomlevellabels[i]}
end
if zoomselection then
zoomselection.items = zoomlabels
else
zoomselection = targetframe.add {type = 'drop-down', name = 'zoomselection', items = zoomlabels, selected_index = 3}
end
local zoom = zoomlevels[zoomselection.selected_index]
return zoom
end
local function update_camera_size(targetframe)
local sizeselection = targetframe.sizeselection
local sizelabels = {}
for i = 1, #sizelevellabels do
sizelabels[i] = {'', '' .. sizelevellabels[i]}
end
if sizeselection then
sizeselection.items = sizelabels
else
sizeselection = targetframe.add {type = 'drop-down', name = 'sizeselection', items = sizelabels, selected_index = 4}
end
local size = sizelevels[sizeselection.selected_index]
local visible = (size ~= 0)
return size, visible
end
local function on_tick()
if global.config.camera_disabled then
return
end
for table_key, camera_table in pairs(camera_users) do
local player = Game.get_player_by_index(table_key)
local target = Game.get_player_by_index(camera_table)
if not target.connected then
create_destroy_camera(true, player, nil, table_key)
player.print('Target has went offline, camera closed')
return
end
local mainframeflow = mod_gui.get_frame_flow(player)
local mainframeid = 'mainframe_' .. table_key
local mainframe = mainframeflow[mainframeid]
if mainframe then
local headerframe = mainframe.headerframe
local cameraframe = mainframe.cameraframe
local zoom = update_camera_zoom(headerframe)
local size, visible = update_camera_size(headerframe)
update_camera_render(target, cameraframe, zoom, size, visible)
end
end
end
local function watch_command(args, player)
if global.config.camera_disabled then
player.print('The watch/camera function has been disabled for performance reasons.')
return
end
if args.target then
create_destroy_camera(nil, player, args)
else
create_destroy_camera(true, player, args)
end
end
local function watch_close_button(event)
create_destroy_camera(true, event.player)
end
Command.add('watch', {description = 'Allows you to watch other players. Use /watch to close the camera.', arguments = {'target'}, default_values = {target = false}, admin_only = false}, watch_command)
Event.on_nth_tick(120, on_tick)
Gui.on_click(main_button_name, watch_close_button)