From 3840ea92cc6419d53c3c0336525770315ba6963e Mon Sep 17 00:00:00 2001 From: npc-strider Date: Sat, 28 Nov 2020 01:37:34 +0800 Subject: [PATCH] First dev in 1.1: completely refactored control code, attempt spidertron waypoints compatibility (in progress). --- .gitignore | 1 + changelog.txt | 14 + control.lua | 463 ++-------------------- control/2dvec.lua | 88 ++++ control/debug.lua | 9 + control/entity_follow.lua | 11 + control/functions.lua | 218 ++++++++++ control/give_remote.lua | 51 +++ control/init.lua | 17 + control/player_follow.lua | 63 +++ control/player_man_designate.lua | 100 +++++ control/player_select.lua | 140 +++++++ control/remote.lua | 2 + data.lua | 2 +- graphics/icons/spidertron-link-tool.png | Bin 3065 -> 3492 bytes info.json | 4 +- make.sh | 13 +- shortcuts.lua => prototypes/shortcuts.lua | 20 +- 18 files changed, 781 insertions(+), 435 deletions(-) create mode 100644 .gitignore create mode 100644 control/2dvec.lua create mode 100644 control/debug.lua create mode 100644 control/entity_follow.lua create mode 100644 control/functions.lua create mode 100644 control/give_remote.lua create mode 100644 control/init.lua create mode 100644 control/player_follow.lua create mode 100644 control/player_man_designate.lua create mode 100644 control/player_select.lua create mode 100644 control/remote.lua rename shortcuts.lua => prototypes/shortcuts.lua (88%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d74e21 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/ diff --git a/changelog.txt b/changelog.txt index 878493d..029d7bd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -46,3 +46,17 @@ Version: 0.3.3 Date: 2020-08-23 Bugfixes: - Hotfix: fixed missing check for invalid entity + +--------------------------------------------------------------------------------------------------- +Version: 0.5.0 +Date: 2020-11-28 + Features: + - NOTE: BETA RELEASE - USE AT YOUR OWN RISK! + - Update mod to Factorio 1.1 + - Completely refactor code + - Attempt at Spidertron Waypoints compatibility + - 0NOTICE: THIS VERSION IS A WORK IN PROGRESS - CHANGELOG IS NOT FINAL + - 1NOTICE: THIS VERSION IS A WORK IN PROGRESS - CHANGELOG IS NOT FINAL + - 2NOTICE: THIS VERSION IS A WORK IN PROGRESS - CHANGELOG IS NOT FINAL + - 3NOTICE: THIS VERSION IS A WORK IN PROGRESS - CHANGELOG IS NOT FINAL + - 4NOTICE: THIS VERSION IS A WORK IN PROGRESS - CHANGELOG IS NOT FINAL diff --git a/control.lua b/control.lua index e538551..3ae8291 100644 --- a/control.lua +++ b/control.lua @@ -6,453 +6,62 @@ * Spiderbot. --]] --- /c for i=0,5 do game.player.insert("spidertron"); end; for i=0,2 do game.player.insert("spidertron-remote") end require("util") -local function give_tool(player, stack) - if player.clean_cursor() and player.cursor_stack and player.cursor_stack.can_set_stack(stack) then - if player.get_main_inventory() then - player.get_main_inventory().remove("squad-spidertron-remote-sel") - player.get_main_inventory().remove("squad-spidertron-remote") - end - player.cursor_stack.set_stack(stack) - return true - end -end +require("control.debug") +-- REMEMBER TO COMMENT DEBUG OUT IN RELEASE!! +-- REMEMBER TO COMMENT DEBUG OUT IN RELEASE!! +-- REMEMBER TO COMMENT DEBUG OUT IN RELEASE!! +-- REMEMBER TO COMMENT DEBUG OUT IN RELEASE!! +-- REMEMBER TO COMMENT DEBUG OUT IN RELEASE!! -local function give_link_tool(index) - local d = global.spidercontrol_spidersquad[index] - if d then - if #d.spiders > 0 and d.spiders[1].spider_entity.valid then --- NEED TO CHECK THIS!!!!!!!!!!!!!!!!! CAN WE REMOVE IT? - local player = game.players[index] - if give_tool(player, {name="squad-spidertron-link-tool",count=1}) then - player.cursor_stack.connected_entity=d.spiders[1].spider_entity - end - -- give_tool(player, {name="spidertron-link-tool",count=1}) - else - give_tool(game.players[index], {name="squad-spidertron-unlink-tool",count=1}) - end - end -end - -local function squad_center(spidersquad) - local xbar=0 - local ybar=0 - local c=0 - for i=1, #spidersquad do - c=c+1 - local pos = spidersquad[i].position - xbar=xbar+pos.x - ybar=ybar+pos.y - end - return {xbar/c,ybar/c} -end - -local function spiderbot_select(event) - local index = event.player_index - local spiders = event.entities - if event.item == "squad-spidertron-remote-sel" and #spiders > 0 then - local center = squad_center(spiders) - global.spidercontrol_spidersquad[index] = {spiders={}} -- some future proofing here - for i=1, #spiders do - local spider = spiders[i] - local pos = spider.position - table.insert(global.spidercontrol_spidersquad[index].spiders, { - spider_entity=spider, - d={pos.x-center[1],pos.y-center[2]} -- dx and dy - }) - end - local player = game.players[index] - if give_tool(player, {name="squad-spidertron-remote",count=1}) then - player.cursor_stack.connected_entity=spiders[1] - end - elseif event.item == "squad-spidertron-unlink-tool" and #spiders > 0 then - if #global.spidercontrol_linked_squads > 0 then - -- This is highly unoptimised, because we're searching through the list of all spidertrons and comparing it to the spidertrons in the selection box. Not quite the worst case, because everytime we get a match we remove it from the search list and we terminate the search when nothing is left in the search list. Can have a large UPS impact spike for bases with many squads that are very large, when a large selection of spidertrons are to be unlinked - -- Is there a way to attach an attribute directly to an entity, so that we don't need to search the whole global table?? That would improve speed by a lot - local ids = {} - local force = game.players[index].force.index - for i=1, #spiders do - ids[#ids+1] = spiders[i].unit_number - end - for i,t in pairs(global.spidercontrol_linked_squads) do - if #ids == 0 then break end - if force == t.force then - local pos = t.target.position - local c = 0 - for j, spider in pairs(t.spiders) do - if #ids == 0 then break end - - for k,id in pairs(ids) do - if spider.spider_entity.unit_number == id then - global.spidercontrol_linked_squads[i].spiders[j] = nil - table.remove(ids,k) - c = c + 1 - end - end - end - if c > 0 then - if t.target and t.target.valid then - game.forces[t.force].print({"", c.." spidertrons have been unlinked from a ", t.target.localised_name, " near [gps="..pos.x..","..pos.y.."]"}) - else - game.forces[t.force].print(c.." spidertrons have been unlinked from an entity near [gps="..pos.x..","..pos.y.."]") - end - end - end - end - end - end -end - -local function validate_spiders(t, msg) - local c=0 - if t then - --for i, spider_ in pairs(t.spiders) do - for i, spider in pairs(t.spiders) do - local spider_entity = spider.spider_entity - if not spider_entity or not spider_entity.valid then - t.spiders[i] = nil - c=c+1 - end - end - if c > 0 then - local str = c .. " units were destroyed or mined since the last position command was sent" - if type(msg) == "boolean" and msg == true then -- This is for messaging when a unit is destroyed - local pos = t.target.position - game.forces[t.force].print(str..". Position is near [gps="..pos.x..","..pos.y.."]") - else - game.players[msg].print(str) --this is causing crashes for one user. states that the player does not exist (why?) needs more research - end - end - return true - elseif type(msg) ~= "boolean" then - global.spidercontrol_spidersquad[msg] = {spiders={}} - end -end - -local function spiderbot_designate(index, position, force) - local d_ - local msg - if force then - d_ = global.spidercontrol_linked_squads[index] - msg = true - else - d_ = global.spidercontrol_spidersquad[index] - msg = index - end - - if validate_spiders(d_, msg) then - local spidersquad = d_.spiders - local leader - local follow - if not force then - leader = d_.spider_leader - follow = game.players[index].is_shortcut_toggled("squad-spidertron-follow") - end - local l_d = {0,0} - if leader then - if spidersquad[leader] and spidersquad[leader].spider_entity.valid then - -- game.players[index].print("Leader "..leader) - l_d = spidersquad[leader].d - else - game.players[index].print("Leader destroyed") -- In case destroyed by biters/nuke/whatever - global.spidercontrol_spidersquad[index].spider_leader = nil - leader = nil - end - end +require("control.init") +require("control.remote") +require("control.give_remote") +require("control.player_select") +require("control.player_man_designate") +require("control.player_follow") +require("control.entity_follow") +require("control.functions") +-- require("control.select") - for i, spider_ in pairs(spidersquad) do - if i ~= leader or not follow then - local spider = spider_.spider_entity - local d = spider_.d - spider.autopilot_destination = {position.x+d[1]-l_d[1], position.y+d[2]-l_d[2]} -- leader dy and dx offsets so that the leader itself becomes the new mean of the squad. - end - end - end -end +------------------------------------------------------------------------ +-- EVENTS +------------------------------------------------------------------------ -local function spiderbot_follow(player) - if player.character then - if player.is_shortcut_toggled("squad-spidertron-follow") then - player.set_shortcut_toggled("squad-spidertron-follow", false) - else - player.set_shortcut_toggled("squad-spidertron-follow", true) - end - else - player.print({"", {"error.error-message-box-title"}, ": ", {"player-doesnt-exist", {"gui.character"}}, " (", {"controller.god"}, "): ", {"gui-mod-info.status-disabled"}}) - end -end - -local function initialize() - if global.spidercontrol_spidersquad == nil then - game.print("Create tables for spidertron control mod") - global.spidercontrol_linked_squads = {} - global.spidercontrol_spidersquad = {} - for _, player in pairs(game.players) do - global.spidercontrol_spidersquad[player.index] = {spider_leader = nil, spiders={}} - end - end -end - -local function squad_leader_state(index) - local player = game.players[index] - if player.vehicle and player.vehicle.type == "spider-vehicle" then - local unit_no = player.vehicle.unit_number - if validate_spiders(global.spidercontrol_spidersquad[index], index) then - local d = global.spidercontrol_spidersquad[index].spiders - if d then - for i, spider in pairs(d) do - -- game.print(spider.spider_entity.unit_number) - if spider.spider_entity.unit_number == unit_no then - global.spidercontrol_spidersquad[index].spider_leader = i - break - end - end - end - end - elseif player.vehicle == nil and global.spidercontrol_spidersquad[index] ~= nil then -- Why is it possible for this to be nil? - global.spidercontrol_spidersquad[index].spider_leader = nil - end -end - -script.on_init(initialize) -script.on_configuration_changed(initialize) ---commands.add_command("spiderbot_initialize_variables", "debug: ensure that all global tables are not nil (should not happen in a normal game)", initialize) - -script.on_event(defines.events.on_player_alt_selected_area, spiderbot_select) -script.on_event(defines.events.on_player_selected_area, spiderbot_select) - -script.on_event(defines.events.on_player_used_spider_remote, function(event) - local index = event.player_index - local player = game.players[index] - local cursor_stack = player.cursor_stack - if cursor_stack then -- how can a player use a remote without a cursor_stack though??? - if cursor_stack.valid_for_read and event.success then - local cname = cursor_stack.name - if cname == "squad-spidertron-remote" then - player.set_shortcut_toggled("squad-spidertron-follow", false) - spiderbot_designate(index, event.position) - elseif cname == "spidertron-remote" then -- WARNING: We're only overriding for the player's spidertron if it's the vanilla spidertron remote. Does not cover modded remotes! - -- Alter dy and dx - local unit_no = event.vehicle.unit_number - local d_ = global.spidercontrol_spidersquad[index] -- Note : Decided against doing checks on a linked squad because it would involve checking that table which can be massively large (larger than player table) - if validate_spiders(d_, index) then - local spidersquad = d_.spiders - local leader = d_.spider_leader - - -- HELLO: if you are reading this and have an idea how to optimize it pls let me know (Not really critical as it's not in the tick loop, but could be problematic for very large squads ) - for i, spider in pairs(spidersquad) do --something something premature debugging evil, but seriously the amount of loops are worrying (for large squds). - if i ~= leader and spider.spider_entity.unit_number == unit_no then -- Don't alter dy and dx for the squad leader (leads to infinite walking) - local dest = event.position - local flat = {} -- repack the array (which is divided because of us storing dy and dx) into a flat one - for j, spider_ in pairs(spidersquad) do - if j == i then - flat[#flat+1] = {position = dest} -- need to predict where it will be and use that as a mean, not current location - else - flat[#flat+1] = spider_.spider_entity - end - end - local center = squad_center(flat) - -- tried to do something without calling this loop but it's the most reliable option - - --very interesting problem : because the mean of the squad is dependent on the positions of each squad member, varying the dy/dx parameters of only one spider (originally the one we're moving) results in this one being scaled off the 'actual' target location - at very far distances from the squad mean this becomes very noticeable. This means we need to calculate the mean of the entire squad if one has changed position. I noticed this error because of the fact that the offset was not constant but proportional to distance away from the mean - for k, spider_ in pairs(spidersquad) do - if k == i then - global.spidercontrol_spidersquad[index].spiders[k].d = { - dest.x - center[1], --dx - dest.y - center[2] --dy - } - else - local pos = spider_.spider_entity.position - global.spidercontrol_spidersquad[index].spiders[k].d = { - pos.x - center[1], --dx - pos.y - center[2] --dy - } - end - end - -- game.print("dx"..dest.x - center[1].."dy"..dest.y - center[2]) - break - end - end - end - elseif cname == "squad-spidertron-link-tool" then - if player.selected and player.selected.valid then - local selected = player.selected - local pos = selected.position - player.print({"", "Linked ".. #global.spidercontrol_spidersquad[index].spiders .. " spiders to ", selected.localised_name, " near [gps=" .. pos.x .. "," .. pos.y .. "]"}) - global.spidercontrol_linked_squads[#global.spidercontrol_linked_squads+1] = { - force=player.force.index, - target=selected, - spiders=util.table.deepcopy(global.spidercontrol_spidersquad[index].spiders) - } - global.spidercontrol_spidersquad[index] = {spider_leader = nil, spiders = {}} -- We're taking away player control of this squad! - -- Probably should print the squad ID, the target entity id and other information - else - local vehicle = event.vehicle - vehicle.autopilot_destination = vehicle.position - end - end - end - end +-- Follow +script.on_event("squad-spidertron-follow", function(event) + -- squad_leader_state(event.player_index) + SpiderbotFollow(game.players[event.player_index]) end) -script.on_event(defines.events.on_player_driving_changed_state, function (event) - squad_leader_state(event.player_index) -end) - -script.on_event(defines.events.on_player_died, function(event) - squad_leader_state(event.player_index) +-- link tool +script.on_event("squad-spidertron-link-tool", function(event) + GiveLinkTool(event.player_index) end) script.on_event(defines.events.on_lua_shortcut, function (event) local name = event.prototype_name if name == "squad-spidertron-follow" then local index = event.player_index - squad_leader_state(index) - spiderbot_follow(game.players[index]) + -- squad_leader_state(index) + SpiderbotFollow(game.players[index]) elseif name == "squad-spidertron-link-tool" then - give_link_tool(event.player_index) + GiveLinkTool(event.player_index) end end) -script.on_event(defines.events.on_player_created, function (event) - global.spidercontrol_spidersquad[event.player_index] = {spider_leader = nil, spiders = {}} -end) - -script.on_event("squad-spidertron-remote", function(event) - give_tool(game.players[event.player_index], {name="squad-spidertron-remote-sel",count=1}) -end) - -script.on_event("squad-spidertron-follow", function(event) - squad_leader_state(event.player_index) - spiderbot_follow(game.players[event.player_index]) -end) - -script.on_event("squad-spidertron-switch-modes", function(event) - local player = game.players[event.player_index] - local cursor_stack = player.cursor_stack - if cursor_stack and cursor_stack.valid_for_read then - local name = cursor_stack.name - if name == "squad-spidertron-remote" then - give_tool(player, {name="squad-spidertron-remote-sel",count=1}) - elseif name == "squad-spidertron-remote-sel" then - local e = global.spidercontrol_spidersquad[event.player_index] - if e.spiders[1] and e.spiders[1].spider_entity.valid and give_tool(player, {name="squad-spidertron-remote",count=1}) then - player.cursor_stack.connected_entity=e.spiders[1].spider_entity - end - -- -- Link pair - elseif name == "squad-spidertron-link-tool" then - give_tool(player, {name="squad-spidertron-unlink-tool",count=1}) - elseif name == "squad-spidertron-unlink-tool" then - give_link_tool(event.player_index) - end - end -end) - -script.on_event("squad-spidertron-link-tool", function(event) - give_link_tool(event.player_index) +script.on_nth_tick(settings.global["spidertron-follow-update-interval"].value, function(event) + UpdateFollow() + UpdateFollowEntity() end) - --- -- - This stuff handles the link tool --- script.on_event(defines.events.on_put_item, function(event) --- local player = game.players[event.player_index] --- local cursor_stack = player.cursor_stack --- if cursor_stack and cursor_stack.valid_for_read then --- if cursor_stack.name == "spidertron-link-tool" then - --- game.print("HELLO") --- end --- end +-- script.on_event(defines.events.on_spider_command_completed, function (event) +-- game.print(game.tick) -- end) --- script.on_event(defines.events.on_built_entity, function(event) --- if event.created_entity.name == "spidertron-link-tool" then --- event.created_entity.destroy() --- -- give_tool(player, {name="spidertron-link-tool",count=1}) -- Not using because this can cause UPS lag if someone click-drags it within placement range! --- game.print("HELLO") --- end --- end) - - -local mov_offset = settings.global["spidertron-follow-prediction-distance"].value --This is so the player stays within the spider squad when moving -local mov_offset_diagonal = math.sqrt(mov_offset^2/2) - -local function pos_offset(position,dir) - local def_dir = defines.direction - local pos_x = position.x - local pos_y = position.y - - if dir == def_dir.north then - pos_y = pos_y - mov_offset - elseif dir == def_dir.northeast then - -- game.print("ne") - pos_x = pos_x + mov_offset_diagonal - pos_y = pos_y - mov_offset_diagonal - elseif dir == def_dir.east then - -- game.print("e") - pos_x = pos_x + mov_offset - elseif dir == def_dir.southeast then - -- game.print("se") - pos_x = pos_x + mov_offset_diagonal - pos_y = pos_y + mov_offset_diagonal - elseif dir == def_dir.south then - -- game.print("s") - pos_y = pos_y + mov_offset - elseif dir == def_dir.southwest then - -- game.print("sw") - pos_x = pos_x - mov_offset_diagonal - pos_y = pos_y + mov_offset_diagonal - elseif dir == def_dir.west then - -- game.print("w") - pos_x = pos_x - mov_offset - else -- northwest - -- game.print("nw") - pos_x = pos_x - mov_offset_diagonal - pos_y = pos_y - mov_offset_diagonal - end - - return {x=pos_x, y=pos_y} -end - -local update_interval = settings.global["spidertron-follow-update-interval"].value - -script.on_nth_tick(update_interval, function(event) - for _, player in pairs(game.players) do - if player.is_shortcut_toggled("squad-spidertron-follow") and player.controller_type ~= 0 then -- 0 => defines.character.ghost (DEAD) - local index = player.index - local chk = global.spidercontrol_spidersquad[index] - if chk and chk.spiders and #chk.spiders > 0 then - local p_pos = player.position - local pos = p_pos - if player.walking_state.walking then - local dir = player.walking_state.direction - pos = pos_offset(p_pos,dir) - end - spiderbot_designate(index, pos) - end - end - end - if #global.spidercontrol_linked_squads > 0 then -- Might put this on another update_interval loop so the lag can be adjusted accordingly. Use the old modulo trick for that. - for i,t in pairs(global.spidercontrol_linked_squads) do - -- local t = global.spidercontrol_linked_squads[i] - if t.spiders then - if t.target.valid then - if #t.spiders > 0 then - spiderbot_designate(i, t.target.position, true) - else - local pos = t.target.position - game.forces[t.force].print({"", "Spidertron squad has been destroyed or unlinked from ", t.target.localised_name, " near [gps="..pos.x..","..pos.y.."]"}) -- using force comms because this could be the death of a spidertron, not only removal - table.remove(global.spidercontrol_linked_squads,i) - end - else - local pos = t.spiders[1].spider_entity.position - game.forces[t.force].print("Target entity of spidertron squad has been destroyed or removed near [gps="..pos.x..","..pos.y.."]") - table.remove(global.spidercontrol_linked_squads,i) - end - end - end - end -end) \ No newline at end of file +script.on_load(function() + SpidertronWaypointsCompatibility() +end) diff --git a/control/2dvec.lua b/control/2dvec.lua new file mode 100644 index 0000000..7afa2d2 --- /dev/null +++ b/control/2dvec.lua @@ -0,0 +1,88 @@ + + +function IJMean(vectors) + local sumx = 0 + local sumy = 0 + for i=1, #vectors do + local vec = vectors[i] + sumx = vec.x + sumx + sumy = vec.y + sumy + end + return { + x = sumx/#vectors, + y = sumy/#vectors + } +end + +function IJMeanEntity(entities) + local sumx = 0 + local sumy = 0 + for i=1, #entities do + local pos = entities[i].position + sumx = pos.x + sumx + sumy = pos.y + sumy + end + return { + x = sumx/#entities, + y = sumy/#entities + } +end + +function IJDelta(vec1, vec2) + local dx = vec2.x - vec1.x + local dy = vec2.y - vec1.y + return { x = dx, y = dy } +end + +function IJAdd(vec1, vec2) + return { + x = vec1.x + vec2.x, + y = vec1.y + vec2.y + } +end + +function IJSub(vec1, vec2) + return { + x = vec1.x - vec2.x, + y = vec1.y - vec2.y + } +end + + +function IJAhead(vec, dir, dd) + local dd_diagonal = math.sqrt(dd^2/2) + local d = defines.direction + local x = vec.x + local y = vec.y + + if dir == d.north then + y = y - dd + elseif dir == d.northeast then + -- game.print("ne") + x = x + dd_diagonal + y = y - dd_diagonal + elseif dir == d.east then + -- game.print("e") + x = x + dd + elseif dir == d.southeast then + -- game.print("se") + x = x + dd_diagonal + y = y + dd_diagonal + elseif dir == d.south then + -- game.print("s") + y = y + dd + elseif dir == d.southwest then + -- game.print("sw") + x = x - dd_diagonal + y = y + dd_diagonal + elseif dir == d.west then + -- game.print("w") + x = x - dd + else -- northwest + -- game.print("nw") + x = x - dd_diagonal + y = y - dd_diagonal + end + + return {x=x, y=y} +end \ No newline at end of file diff --git a/control/debug.lua b/control/debug.lua new file mode 100644 index 0000000..6fa6585 --- /dev/null +++ b/control/debug.lua @@ -0,0 +1,9 @@ + +commands.add_command( + "dvars", + "debug: dump spider control vars", + function (cmd) + -- game.print(serpent.block(global.spidercontrol_player_s[cmd.player_index])) + game.print(serpent.block(global.spidercontrol_linked_s)) + end +) diff --git a/control/entity_follow.lua b/control/entity_follow.lua new file mode 100644 index 0000000..f7f0c96 --- /dev/null +++ b/control/entity_follow.lua @@ -0,0 +1,11 @@ + +require("control.2dvec") + +function UpdateFollowEntity() + local links = global.spidercontrol_linked_s + for i = 1, #links do + if (#links[i].s > 0) then + GotoEntity(i) + end + end +end \ No newline at end of file diff --git a/control/functions.lua b/control/functions.lua new file mode 100644 index 0000000..9f5b5d1 --- /dev/null +++ b/control/functions.lua @@ -0,0 +1,218 @@ + +function SpidertronWaypointsCompatibility() + -- Compatability for Spidertron Waypoints + if remote.interfaces["SpidertronWaypoints"] then + SPIDERTRON_WAYPOINTS = true + -- local event_ids = remote.call("SpidertronWaypoints", "get_events") + -- local on_spidertron_given_new_destination = event_ids.on_spidertron_given_new_destination + -- script.on_event(on_spidertron_given_new_destination, function(event) + -- game.print("New destination") + -- Goto(global.spidercontrol_player_s[event.player_index].active, event.position) + -- end) + end +end + +function GiveStack(player, stack) + if player.clear_cursor() and player.cursor_stack and player.cursor_stack.can_set_stack(stack) then + if player.get_main_inventory() then + player.get_main_inventory().remove("squad-spidertron-remote-sel") + player.get_main_inventory().remove("squad-spidertron-remote") + end + player.cursor_stack.set_stack(stack) + return true + end +end + +function Remove(table, indices) + local n = #table + for i = 1, #indices do + table[indices[i]] = nil + end + + local tmp = {} + for i = 1, n do + if (table[i] ~= nil) then + tmp[#tmp+1] = table[i] + end + end + + return tmp +end + +function Goto(spiders, center) + local invalid = {} + for i = 1, #spiders do + local spider = spiders[i].spider + local d = spiders[i].delta + if spider.valid then + spider.autopilot_destination = IJAdd(center, d) + else + invalid[#invalid+1] = i + end + end + return Remove(spiders, invalid) -- We return an updated spider list (Remove any invalid spiders) +end + +local function drawSprite(surface, target, scale, force, tint) + return rendering.draw_sprite({ + sprite="item/squad-spidertron-link-tool", + target = target, + surface = (target.surface or surface), + x_scale = scale, + y_scale = scale, + only_in_alt_mode = true, + forces = {force}, + tint = (tint or {r=1,g=1,b=1}) + }) +end +-- rendering.draw_sprite({sprite="item/squad-spidertron-link-tool", target = game.player.selected, surface = game.player.surface, only_in_alt_mode = true, forces = {game.player.force}, tint = {r=1,g=1,b=1}}) +local function resetSprites(indices) + if indices then + for i = 1, #indices do + rendering.destroy(indices[i]) + end + end +end +-- Original GotoPlayer function before waypoints compat. +local function GotoPlayer_(index, position) + local active = global.spidercontrol_player_s[index].active + local active_n = #active + local active_updated = Goto(active, position) + global.spidercontrol_player_s[index].active = active_updated + + if (active_n > #active_updated) then + local str = (active_n - #active_updated) .. " units were destroyed or mined" + game.players[index].print(str) + end +end + +local function GotoPlayerSW(index, position) + local active = global.spidercontrol_player_s[index].active + local player = game.players[index] + local linear = player.is_shortcut_toggled("spidertron-remote-waypoint") + local cyclic = player.is_shortcut_toggled("spidertron-remote-patrol") + if (cyclic) then + active[1].spider.autopilot_destination = nil + local patrol = global.spidercontrol_spidertronwaypoints_patrol[index] + if (patrol) then + local start = rendering.get_target(patrol[1]).position + if (util.distance(position, start) < 5) then + for j = 1, #active do + local waypoints = {} + for i = 1, #patrol do + local position = IJAdd( + rendering.get_target(patrol[i]).position, + active[j].delta + ) + waypoints[#waypoints+1] = {position = position} + end + + remote.call("SpidertronWaypoints", "assign_patrol", active[j].spider, waypoints) + end + resetSprites(patrol) + global.spidercontrol_player_s[index].active = {} + GiveStack(player, {name="squad-spidertron-remote-sel",count=1}) + player.set_shortcut_toggled("spidertron-remote-patrol", false) + patrol = nil + else + patrol[#patrol+1] = drawSprite(player.surface, position, 1.5, player.force, {r=1.0,g=0.0,b=1.0}) + end + else + patrol = {drawSprite(player.surface, position, 1.5, player.force, {r=1.0,g=1.0,b=1.0})} + end + global.spidercontrol_spidertronwaypoints_patrol[index] = patrol + elseif (linear) then + local active_updated = Goto(active, position) + for i = 1, #active_updated do + local position = IJAdd(position, active_updated[i].delta) + local waypoint = {{position = position}} + remote.call("SpidertronWaypoints", "assign_waypoints", active_updated[i].spider, waypoint) + end + + resetSprites(global.spidercontrol_spidertronwaypoints_patrol[index]) + global.spidercontrol_spidertronwaypoints_patrol[index] = nil + else + GotoPlayer_(index, position) + + resetSprites(global.spidercontrol_spidertronwaypoints_patrol[index]) + global.spidercontrol_spidertronwaypoints_patrol[index] = nil + end +end + +function GotoPlayer(index, position) + if SPIDERTRON_WAYPOINTS then + GotoPlayerSW(index, position) + else + GotoPlayer_(index, position) + end + +end + +function GotoEntity(index) + local t = global.spidercontrol_linked_s[index] + local entity = t.target + local active = t.s + if entity.valid then + local active_n = #active + local pos = entity.position + + local active_updated = Goto(active, pos) + + global.spidercontrol_linked_s[index].s = active_updated + + if (active_n > #active_updated) then + local str = (active_n - #active_updated) .. " units were destroyed or mined near [gps="..pos.x..","..pos.y.."], linked to "..entity.localised_name + game.forces[t.force].print(str) + end + + if (#active_updated == 0) then + local str = {"", "Spidertron squad has been destroyed or unlinked from ", entity.localised_name, " near [gps="..pos.x..","..pos.y.."]"} + game.forces[t.force].print(str) -- using force comms because this could be the death of a spidertron, not only removal + end + else + local e = false + for i = 1, #active do + if (active[i].spider.valid) then + e = active[i].spider + end + end + if (e) then + local pos = e.position + game.forces[t.force].print("Target entity of spidertron squad has been destroyed or removed near [gps="..pos.x..","..pos.y.."]") + else + game.forces[t.force].print("Target entity of spidertron squad has been destroyed or removed") + end + + global.spidercontrol_linked_s = Remove(global.spidercontrol_linked_s, {index}) + end +end + +function FirstValid(entities) + for i = 1, #entities do + if entities[i] and entities[i].valid then + return entities[i] + end + end + return false +end + +-- local function squad_center(spidersquad) +-- local xbar=0 +-- local ybar=0 +-- local c=0 +-- for i=1, #spidersquad do +-- c=c+1 +-- local pos = spidersquad[i].position +-- xbar=xbar+pos.x +-- ybar=ybar+pos.y +-- end +-- return {xbar/c,ybar/c} +-- end + +function Mean(list) + local sum = 0 + for i=1, #list do + sum=sum+list[i] + end + return sum/#list +end \ No newline at end of file diff --git a/control/give_remote.lua b/control/give_remote.lua new file mode 100644 index 0000000..bd8e82d --- /dev/null +++ b/control/give_remote.lua @@ -0,0 +1,51 @@ +require("control.functions") + +function GiveLinkTool(index) + local d = global.spidercontrol_player_s[index].active + if (#d > 0 and d[1].spider.valid) then + local player = game.players[index] + if GiveStack(player, {name="squad-spidertron-link-tool",count=1}) then + player.cursor_stack.connected_entity = d[1].spider + end + else + GiveStack(game.players[index], {name="squad-spidertron-unlink-tool",count=1}) + end +end + +script.on_event("squad-spidertron-remote", function(event) + GiveStack(game.players[event.player_index], {name="squad-spidertron-remote-sel",count=1}) +end) + +script.on_event("squad-spidertron-switch-modes", function(event) + local player = game.players[event.player_index] + local cursor_stack = player.cursor_stack + if cursor_stack and cursor_stack.valid_for_read then + local name = cursor_stack.name + if name == "squad-spidertron-remote" then + GiveStack(player, {name="squad-spidertron-remote-sel",count=1}) + elseif name == "squad-spidertron-remote-sel" then + local e = global.spidercontrol_player_s[event.player_index].active + if e[1] and e[1].spider.valid and GiveStack(player, {name="squad-spidertron-remote",count=1}) then + player.cursor_stack.connected_entity = e[1].spider + end + -- -- Link pair + elseif name == "squad-spidertron-link-tool" then + GiveStack(player, {name="squad-spidertron-unlink-tool",count=1}) + elseif name == "squad-spidertron-unlink-tool" then + GiveLinkTool(event.player_index) + end + end +end) + + +-- script.on_event(defines.events.on_lua_shortcut, function (event) +-- local name = event.prototype_name +-- if name == "squad-spidertron-follow" then +-- local index = event.player_index +-- squad_leader_state(index) +-- spiderbot_follow(game.players[index]) +-- elseif name == "squad-spidertron-link-tool" then +-- GiveLinkTool(event.player_index) +-- end +-- end) + diff --git a/control/init.lua b/control/init.lua new file mode 100644 index 0000000..d15aee8 --- /dev/null +++ b/control/init.lua @@ -0,0 +1,17 @@ + +local function initialize() + if global.spidercontrol_spidersquad == nil then + game.print("Create tables for spidertron control mod") + global.spidercontrol_linked_s = {} + global.spidercontrol_player_s = {} + global.spidercontrol_spidertronwaypoints_patrol = {} + for _, player in pairs(game.players) do + global.spidercontrol_player_s[player.index] = {active = {}, inactive = {}} -- Some future-proofing here + end + end + SpidertronWaypointsCompatibility() +end + +script.on_init(initialize) +script.on_configuration_changed(initialize) +-- commands.add_command("spiderbot_initialize_variables", "debug: ensure that all global tables are not nil (should not happen in a normal game)", initialize) diff --git a/control/player_follow.lua b/control/player_follow.lua new file mode 100644 index 0000000..9a0056c --- /dev/null +++ b/control/player_follow.lua @@ -0,0 +1,63 @@ + +local function spidertronWaypointsOverride(s) + if SPIDERTRON_WAYPOINTS then + for i = 1, #s do + remote.call("SpidertronWaypoints", "clear_waypoints", s[i].spider.unit_number) + end + end +end + +function SpiderbotFollow(player) + if player.character then + if player.is_shortcut_toggled("squad-spidertron-follow") then + player.set_shortcut_toggled("squad-spidertron-follow", false) + local index = player.index + GotoPlayer(index, player.position) + spidertronWaypointsOverride(global.spidercontrol_player_s[index].active) + else + player.set_shortcut_toggled("squad-spidertron-follow", true) + global.spidercontrol_player_s[player.index].p_pos = nil + end + else + player.print({"", {"error.error-message-box-title"}, ": ", {"player-doesnt-exist", {"gui.character"}}, " (", {"controller.god"}, "): ", {"gui-mod-info.status-disabled"}}) + end +end + + + +local mov_offset = settings.global["spidertron-follow-prediction-distance"].value --This is so the player stays within the spider squad when moving + +function UpdateFollow() + for _, player in pairs(game.players) do + if (player.controller_type ~= 0 and player.is_shortcut_toggled("squad-spidertron-follow")) then -- 0 => defines.character.ghost (DEAD) + local index = player.index + local active = global.spidercontrol_player_s[index].active + if (active and #active > 0) then + local p_pos = global.spidercontrol_player_s[index].p_pos + local pos = player.position + if ( p_pos == nil or p_pos.x ~= pos.x or p_pos.y ~= pos.y ) then + + local vehicle = player.vehicle + if (vehicle and vehicle.type == "spider-vehicle") then + local un = vehicle.unit_number + for i = 1, #active do + if (active[i].spider.unit_number == un) then + pos = IJSub(vehicle.position, active[i].delta) + break + end + end + end + + -- player.print("running" .. game.tick) + if player.walking_state.walking then + local dir = player.walking_state.direction + pos = IJAhead(pos, dir, mov_offset) + end + GotoPlayer(index, pos) + spidertronWaypointsOverride(active) + global.spidercontrol_player_s[index].p_pos = player.position + end + end + end + end +end diff --git a/control/player_man_designate.lua b/control/player_man_designate.lua new file mode 100644 index 0000000..841a1ed --- /dev/null +++ b/control/player_man_designate.lua @@ -0,0 +1,100 @@ +require("control.functions") + +local function moveTo(player, index, position) + game.players[index].set_shortcut_toggled("squad-spidertron-follow", false) + GotoPlayer(index, position) +end + +local function realign(s, vehicle, position, target) + local unit_number = vehicle.unit_number + for i = 1, #s do + if (s[i].spider.unit_number == unit_number) then + -- This commented-out targeting works relative to the mean of the group, not the target entity. It has its benefits but ultimately I preferred the target-based modification, so i've left this uncommented. + -- if (s[i+1]) then -- Use another spidertron as a reference vector/position + -- local origin = IJSub(s[i+1].spider.position, s[i+1].delta) + -- s[i].delta = IJSub(position, origin) + -- elseif (s[i-1]) then + -- local origin = IJSub(s[i-1].spider.position, s[i-1].delta) + -- s[i].delta = IJSub(position, origin) + -- else + -- -- spider list should never be a sparse list, so if nothing's adjacent it's a single spidertron + -- s[i].delta = IJSub(position, vehicle.position) -- Not really good without a ref vector + -- end + s[i].delta = IJSub(position, target.position) + return s + end + end + return false +end + +local function drawSprite(target, scale, force, tint, target_offset) + return rendering.draw_sprite({ + sprite="item/squad-spidertron-link-tool", + target = target, + surface = target.surface, + x_scale = scale, + y_scale = scale, + only_in_alt_mode = true, + forces = {force}, + tint = (tint or {r=1,g=1,b=1}), + target_offset = (target_offset or {x=0,y=0}) + }) +end + +local function link(index, vehicle) + local player = game.players[index] + local n = #global.spidercontrol_player_s[index].active + if player.selected and player.selected.valid and n > 0 then + local selected = player.selected + local pos = selected.position + local scale = 1.5 + local force = player.force + player.print({"", "Linked ".. n .. " spiders to ", selected.localised_name, " near [gps=" .. pos.x .. "," .. pos.y .. "]"}) + local sprite = drawSprite(selected, scale, force) + local s = util.table.deepcopy(global.spidercontrol_player_s[index].active) + for i = 1, #s do + s[i].sprite = drawSprite(s[i].spider, scale, force, {r=1,g=0,b=0}, {x=0,y=-0.3}) + end + global.spidercontrol_linked_s[#global.spidercontrol_linked_s+1] = { + force=player.force.index, + target=selected, + sprite=sprite, + s=s + } + global.spidercontrol_player_s[index].active = {} -- We're taking away player control of this squad! + -- Probably should print the squad ID, the target entity id and other information + GiveStack(player, {name="squad-spidertron-unlink-tool",count=1}) + end + vehicle.autopilot_destination = vehicle.position -- Just to look better +end + + +script.on_event(defines.events.on_player_used_spider_remote, function(event) + local index = event.player_index + local player = game.players[index] + local cursor_stack = player.cursor_stack + if cursor_stack then -- how can a player use a remote without a cursor_stack though??? + if cursor_stack.valid_for_read and event.success then + local cname = cursor_stack.name + if cname == "squad-spidertron-remote" then + moveTo(player, index, event.position) + elseif cname == "spidertron-remote" then -- WARNING: We're only overriding for the player's spidertron if it's the vanilla spidertron remote. Does not cover modded remotes! + local vehicle = event.vehicle + local position = event.position + local s = realign(global.spidercontrol_player_s[index].active, vehicle, position, player) + if s then + global.spidercontrol_player_s[index].active = s + else + local t = global.spidercontrol_linked_s + for i = 1, #t do + if realign(t[i].s, vehicle, position, t[i].target) then + global.spidercontrol_linked_s[i].t = t + end + end + end + elseif cname == "squad-spidertron-link-tool" then + link(index, event.vehicle) + end + end + end +end) \ No newline at end of file diff --git a/control/player_select.lua b/control/player_select.lua new file mode 100644 index 0000000..6413187 --- /dev/null +++ b/control/player_select.lua @@ -0,0 +1,140 @@ + +require("control.functions") +require("control.2dvec") + +local function messageSpiders(target, s, force, n) + if target.valid then + local pos = target.position + game.forces[force].print({"", n.." spidertrons have been unlinked from a ", target.localised_name, " near [gps="..pos.x..","..pos.y.."]"}) + else + local e = FirstValid(s) + if e then + local pos = e.position + game.forces[force].print(n.." spidertrons have been unlinked from an entity near [gps="..pos.x..","..pos.y.."]") + else + game.forces[force].print(n.." spidertrons have been unlinked from an entity") + end + end +end +local function messageS(target, s, force) + if target.valid then + local pos = target.position + game.forces[force].print({"", "Spidertron squad has been unlinked from ", target.localised_name, " near [gps="..pos.x..","..pos.y.."]"}) -- using force comms because this could be the death of a spidertron, not only removal + else + local e = FirstValid(s) + if e then + local pos = e.position + game.forces[force].print({"", "Spidertron squad has been unlinked from a target near [gps="..pos.x..","..pos.y.."]"}) + else + game.forces[force].print({"", "Spidertron squad has been unlinked from a target"}) + end + end +end + + +local function unitNumbers(entities) + local ids = {} + for i = 1, #entities do + ids[#ids+1] = entities[i].unit_number + end + return ids +end + +local function spiderDeSelect(spiders, force) + local ids = unitNumbers(spiders) + local t = global.spidercontrol_linked_s + local rem_t = {} --This part is really bad - I think it's O(N^3) worst case? + for i = 1, #t do + if (t[i].force == force and #ids > 0) then + local s = t[i].s + local rem_s = {} + for j = 1, #s do + local rem_id = {} + for k = 1, #ids do + if (ids[k] == s[j].spider.unit_number) then + s[j].spider.autopilot_destination = nil + rem_id[#rem_id+1] = k + rem_s[#rem_s+1] = j + -- game.print("REMOVE["..i.."]["..j.."]") + end + end + if (#rem_id > 0) then + ids = Remove(ids, rem_id) + if (#ids == 0) then + break + end + end + end + if (#rem_s > 0) then + local force = t[i].force + local target = t[i].target + for x = 1, #rem_s do + rendering.destroy(s[rem_s[x]].sprite) + end + s = Remove(s, rem_s) + messageSpiders(target, s, force, #rem_s) + if (#s == 0) then + rem_t[#rem_t+1] = i + messageS(target, s, force) + else + global.spidercontrol_linked_s[i].s = s + end + end + if (#ids == 0) then + break + end + end + end + if (#rem_t > 0) then -- Need to remove sprite + for x = 1, #rem_t do + rendering.destroy(t[rem_t[x]].sprite) + end + global.spidercontrol_linked_s = Remove(global.spidercontrol_linked_s, rem_t) + end +end + + +local function spiderSelect(spiders, index) + + local player = game.players[index] + local force = player.force.index + local mean = IJMeanEntity(spiders) + global.spidercontrol_player_s[index].active = {} + + spiderDeSelect(spiders, force) -- TO prevent double-linking (linking the same spider to 2 or more entities) + if SPIDERTRON_WAYPOINTS then + for i = 1, #spiders do + remote.call("SpidertronWaypoints", "clear_waypoints", spiders[i].unit_number) + spiders[i].autopilot_destination = nil + end + end + -- spiderDeSelectPlayers(spiders, force) -- Y'know what, not sure if i can be arsed to deselect player squads... + + for i=1, #spiders do + table.insert(global.spidercontrol_player_s[index].active, { + spider = spiders[i], + delta = IJDelta(mean, spiders[i].position) + }) + end + + if GiveStack(player, {name="squad-spidertron-remote",count=1}) then + player.cursor_stack.connected_entity=spiders[1] + end +end + + +local function areaSelection(event) + local index = event.player_index + local spiders = event.entities -- We're only selecting spiders from our force (due to force filter) + local item = event.item + if #spiders > 0 then + if item == "squad-spidertron-remote-sel" then + spiderSelect(spiders, index) + elseif item == "squad-spidertron-unlink-tool" then + spiderDeSelect(spiders, spiders[1].force.index) + end + end +end + +script.on_event(defines.events.on_player_alt_selected_area, areaSelection) +script.on_event(defines.events.on_player_selected_area, areaSelection) \ No newline at end of file diff --git a/control/remote.lua b/control/remote.lua new file mode 100644 index 0000000..8d62e1c --- /dev/null +++ b/control/remote.lua @@ -0,0 +1,2 @@ +-- Just need to claim this interface name. +remote.add_interface("SpiderControl", {}) \ No newline at end of file diff --git a/data.lua b/data.lua index 68ce428..e695899 100644 --- a/data.lua +++ b/data.lua @@ -6,4 +6,4 @@ * Data --]] -require("shortcuts") +require("prototypes.shortcuts") diff --git a/graphics/icons/spidertron-link-tool.png b/graphics/icons/spidertron-link-tool.png index 7bb38381daff42a4cb75bbbd7f525d595c668aa4..3ed6319f6b727fda2978c5f616145a68e3ff9975 100644 GIT binary patch delta 3440 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 Eg1%z_nE(I) diff --git a/info.json b/info.json index dafde2a..fcb0316 100644 --- a/info.json +++ b/info.json @@ -1,7 +1,7 @@ { "name": "Spider_Control", - "version": "0.4.0", - "factorio_version": "1.0", + "version": "0.5.0", + "factorio_version": "1.1", "title": "Spidertron squad control", "author": "npc_strider(morley376)", "contact": "", diff --git a/make.sh b/make.sh index 6d22b1c..f80920c 100644 --- a/make.sh +++ b/make.sh @@ -1,6 +1,13 @@ +# v=$(grep "\"version\"" info.json | sed 's|.*:||;s|[",]||g;s| ||g') +# n=$(grep "\"name\"" info.json | sed 's|.*:||;s|[",]||g;s| ||g') +# #echo ${n}_${v}.zip + +# powershell -c "\$files = Get-ChildItem -Path . -Exclude .git,*.sh +# Compress-Archive -Path \$files -DestinationPath ../${n}_${v}.zip" + v=$(grep "\"version\"" info.json | sed 's|.*:||;s|[",]||g;s| ||g') n=$(grep "\"name\"" info.json | sed 's|.*:||;s|[",]||g;s| ||g') -#echo ${n}_${v}.zip +echo ${n}_${v}.zip +cd .. -powershell -c "\$files = Get-ChildItem -Path . -Exclude .git,*.sh -Compress-Archive -Path \$files -DestinationPath ../${n}_${v}.zip" \ No newline at end of file +7z a -tzip ${n}_${v}.zip ./${n} -xr'!.git' -xr'!.gitignore' -xr'!*.pdn' \ No newline at end of file diff --git a/shortcuts.lua b/prototypes/shortcuts.lua similarity index 88% rename from shortcuts.lua rename to prototypes/shortcuts.lua index 0ae4be5..b79dc88 100644 --- a/shortcuts.lua +++ b/prototypes/shortcuts.lua @@ -8,6 +8,10 @@ require('util') +------------------------------------------------------------------------ +-- ITEMS +------------------------------------------------------------------------ + local item_remote_sel = { type = "selection-tool", name = "squad-spidertron-remote-sel", @@ -59,15 +63,19 @@ item_link.localised_name = "Spidertron link tool" item_link.icon = "__Spider_Control__/graphics/icons/spidertron-link-tool.png" item_link.icon_color_indicator_mask = "__Spider_Control__/graphics/icons/spidertron-link-tool-mask.png" +------------------------------------------------------------------------ +-- SHORTCUTS +------------------------------------------------------------------------ + local shortcut_remote = { type = "shortcut", name = "squad-spidertron-remote", order = "a[squad-spidertron-remote]", - action = "create-blueprint-item", + action = "spawn-item", localised_name = "Spidertron squad remote", associated_control_input = "squad-spidertron-remote", technology_to_unlock = "spidertron", - item_to_create = "squad-spidertron-remote-sel", + item_to_spawn = "squad-spidertron-remote-sel", style = "red", icon = { @@ -110,6 +118,10 @@ shortcut_link.localised_name = "Link spidertrons to entity" shortcut_link.associated_control_input = "squad-spidertron-link-tool" shortcut_link.style = "green" +------------------------------------------------------------------------ +-- CUSTOM INPUT +------------------------------------------------------------------------ + local input_remote = { type = "custom-input", name = "squad-spidertron-remote", @@ -133,6 +145,10 @@ input_link.name = "squad-spidertron-link-tool" input_link.localised_name = "Link spidertron squad to entity" input_link.key_sequence = "ALT + Z" +------------------------------------------------------------------------ +-- EXTEND +------------------------------------------------------------------------ + data:extend( { shortcut_remote,