--- Creates a warp point system which makes moving around large maps easier. -- @module WarpPoints@4.0.0 -- @author Cooldude2606 -- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE -- @alais ThisModule -- Module Require local Gui = require('ExpGamingCore.Gui@^4.0.0') local Game = require('FactorioStdLib.Game@^0.8.0') local Role -- ExpGamingCore.Role@^4.0.0 -- Local Varibles local warp_tiles = require(module_path..'/src/warp_tiles') local warp_entities = require(module_path..'/src/warp_entities') local warp_radius = 4 local spawn_warp_scale = 5 local warp_tile = 'tutorial-grid' local warp_limit = 60 local warp_item = 'discharge-defense-equipment' local global_offset = {x=0,y=0} local warp_min_distance = 25 -- Module Define local _global = global local global local module_verbose = false local ThisModule = { on_init=function(self) if loaded_modules['ExpGamingCore.Role@^4.0.0'] then Role = require('ExpGamingCore.Role@^4.0.0') end if loaded_modules['ExpGamingCore.Command@^4.0.0'] then require(module_path..'/src/commands',{self=self,warps=global,warp_min_distance=warp_min_distance}) end end } -- Global Define global = _global{ warps={}, -- 0,0 is always a warp cooldowns={} } -- Function Define --- Removes a warp point from the list, and then updates the gui -- @usage ThisModule.remove_warp_point(name) -- name cant be spawn -- @tparam string name the name of the warp point function ThisModule.remove_warp_point(name) local warp = global.warps[name] if not warp then return end local surface = game.surfaces[warp.surface] local offset = warp.position local tiles = {} local tiles = {} -- clears the area where the warp was for x = -warp_radius, warp_radius do for y = -warp_radius, warp_radius do if x^2+y^2 < (warp_radius+1)^2 then table.insert(tiles,{name=warp.old_tile,position={x+offset.x,y+offset.y}}) local entities = surface.find_entities_filtered{area={{x+offset.x-1,y+offset.y-1},{x+offset.x,y+offset.y}}} for _,entity in pairs(entities) do if entity.name ~= 'player' then entity.destroy() end end end end end surface.set_tiles(tiles) if warp.tag.valid then warp.tag.destroy() end global.warps[name] = nil ThisModule.Gui() end --- Adds a warp point from the list, and then updates the gui -- @usage ThisModule.make_warp_point({x=10,y=10},surface,force,name) -- @tparam table position the position of the new warp point -- @tparam surface surface the surface that the warp point is on -- @tparam force force the force that the warp point will belong to -- @tparam string name the name of the warp point to be made function ThisModule.make_warp_point(position,surface,force,name) local warp = global.warps[name] if warp then return end; warp = nil local offset = {x=math.floor(position.x),y=math.floor(position.y)} local old_tile = surface.get_tile(offset).name local base_tiles = {} local tiles = {} -- this makes a base plate to make the warp point for x = -warp_radius, warp_radius do for y = -warp_radius, warp_radius do if x^2+y^2 < warp_radius^2 then table.insert(base_tiles,{name=warp_tile,position={x+offset.x,y+offset.y}}) end end end surface.set_tiles(base_tiles) -- this adds the patern and entities for _,position in pairs(warp_tiles) do table.insert(tiles,{name=warp_tile,position={position[1]+offset.x+global_offset.x,position[2]+offset.y+global_offset.y}}) end surface.set_tiles(tiles) for _,entity in pairs(warp_entities) do local entity = surface.create_entity{name=entity[1],position={entity[2]+offset.x+global_offset.x,entity[3]+offset.y+global_offset.y},force='neutral'} entity.destructible = false; entity.health = 0; entity.minable = false; entity.rotatable = false end -- creates a tag on the map for the wap point local tag = force.add_chart_tag(surface,{ position={offset.x+0.5,offset.y+0.5}, text='Warp: '..name, icon={type='item',name=warp_item} }) global.warps[name] = {tag=tag,surface=surface.index,position=tag.position,old_tile=old_tile} local _temp = {Spawn=global.warps.Spawn} global.warps.Spawn = nil for name,data in pairs(table.keysort(global.warps)) do _temp[name] = data end global.warps = _temp ThisModule.Gui() end local remove_warp = Gui.inputs{ type='button', name='remove-warp-point', caption='utility/remove', tooltip={'WarpPoints.remove-tooltip'} }:on_event('click',function(event) local name = event.element.parent.name ThisModule.remove_warp_point(name) end) local go_to_warp = Gui.inputs{ type='button', name='go-to-warp-point', caption='utility/export_slot', tooltip={'WarpPoints.go-to-tooltip'} }:on_event('click',function(event) local player = Game.get_player(event) local cooldown = global.cooldowns[event.player_index] or 0 local warp = global.warps[event.element.parent.name] if cooldown > 0 then player_return({'WarpPoints.cooldown',cooldown},nil,event) return end if player.vehicle then player.vehicle.set_driver(nil) end if player.vehicle then player.vehicle.set_passenger(nil) end if player.vehicle then return end player.teleport(game.surfaces[warp.surface].find_non_colliding_position('player',warp.position,32,1),game.surfaces[warp.surface]) if not Role and not player.admin or Role and not Role.allowed(player,'always-warp') then event.element.parent.parent.parent.parent.style.visible = false global.cooldowns[event.player_index] = warp_limit end end) ThisModule.Gui = Gui.left{ name='warp-list', caption='item/'..warp_item, tooltip={'WarpPoints.tooltip'}, draw=function(frame) local player = Game.get_player(frame.player_index) frame.caption={'WarpPoints.name'} local warp_list = frame.add{ type='scroll-pane', direction='vertical', vertical_scroll_policy='auto', horizontal_scroll_policy='never' } warp_list.vertical_scroll_policy = 'auto' warp_list.style.maximal_height = 150 local table = warp_list.add{ type='table', column_count=2 } for name,warp in pairs(global.warps) do if not warp.tag or not warp.tag.valid then player.force.add_chart_tag(game.surfaces[warp.surface],{ position=warp.position, text='Warp: '..name, icon={type='item',name=warp_item} }) end table.add{ type='label', caption=name, style='caption_label' } local _flow = table.add{ type='flow', name=name } local btn = go_to_warp(_flow) btn.style.height = 20 btn.style.width = 20 if not Role and player.admin and name ~= 'Spawn' or Role and Role.allowed(player,'make-warp') and name ~= 'Spawn' then local btn = remove_warp(_flow) btn.style.height = 20 btn.style.width = 20 end end local cooldown = global.cooldowns[player.index] or 0 if cooldown > 0 then frame.style.visible = false return elseif not Role and player.admin or Role and Role.allowed(player,'always-warp') then return elseif player.surface.get_tile(player.position).name == warp_tile and player.surface.name == 'nauvis' then return elseif player.position.x^2+player.position.y^2 < (warp_radius*spawn_warp_scale)^2 then return else frame.style.visible = false end end, can_open=function(player) local cooldown = global.cooldowns[player.index] or 0 if not Role and player.admin or Role and Role.allowed(player,'always-warp') then return true elseif player.surface.get_tile(player.position).name == warp_tile and player.surface.name == 'nauvis' then return true elseif player.position.x^2+player.position.y^2 < (warp_radius*spawn_warp_scale)^2 then return true elseif cooldown > 0 then return {'WarpPoints.cooldown',cooldown} else return {'WarpPoints.not-on-warp'} end end, open_on_join=true } -- Event Handlers Define script.on_event(defines.events.on_tick,function(event) if not (event.tick % 60 == 0) then return end for index,time in pairs(global.cooldowns) do if time > 0 then global.cooldowns[index] = time-1 if global.cooldowns[index] == 0 then player_return({'WarpPoints.cooldown-zero'},defines.textcolor.low,index) end end end end) script.on_event(defines.events.on_player_changed_position, function(event) local player = Game.get_player(event) local cooldown = global.cooldowns[player.index] or 0 local tile = player.surface.get_tile(player.position).name if not Role and player.admin or Role and not Role.allowed(player,'always-warp') and cooldown == 0 then if tile == warp_tile and player.surface.name == 'nauvis' then ThisModule.Gui:open(player) elseif player.position.x^2+player.position.y^2 < (warp_radius*spawn_warp_scale)^2 then ThisModule.Gui:open(player) else ThisModule.Gui:close(player) end end end) script.on_event(defines.events.on_player_created, function(event) if event.player_index == 1 then local player = Game.get_player(event) player.force.chart(player.surface, {{player.position.x - 20, player.position.y - 20}, {player.position.x + 20, player.position.y + 20}}) local tag = player.force.add_chart_tag(player.surface,{ position={0,0}, text='Warp: Spawn', icon={type='item',name=warp_item} }) global.warps['Spawn'] = {tag=tag,surface=player.surface.index,position={0,0}} end end) -- Module Return return ThisModule