-- Find ghosts to place. Then find buildings to destruct. function runOnce() global.runOnce = true if not global.blueBuildFirstTick then global.blueBuildFirstTick = {tick = 0, pass = false} end if not global.bluePositions then global.bluePosition = {} end if not global.blueBuildToggle then global.blueBuildToggle = {} end if not global.blueDemoToggle then global.blueDemoToggle = {} end -- if not global.blueLastDemo then -- global.blueLastDemo = {} -- end for n, p in pairs(game.players) do initPlayer(p) end end function initPlayer(player) player.print("Initializing Bluebuild.") global.blueBuildToggle[player.index] = true global.blueDemoToggle[player.index] = true global.bluePosition[player.index] = {x = 0, y = 0} -- global.blueBuildFirstTick[player.index] = game.tick -- global.blueLastDemo[player.index] = game.tick end function playerloop() for _, player in pairs(game.players) do if player.valid and player.connected then bluecheck(player) end end end function bluecheck(builder) local pos = builder.position --game.print("Checking player.") -- if global.bluePosition[builder.index] and global.bluePosition[builder.index] == pos then if distance(global.bluePosition[builder.index], pos) == 0 then global.blueBuildFirstTick.state = true global.blueBuildFirstTick.tick = game.tick --We haven't moved. Good, let's continue. --game.print("Player hasn't moved.") -- if global.blueBuildFirstTick[builder.index] and game.tick > global.blueBuildFirstTick[builder.index] + 5 then if global.blueBuildToggle[builder.index] == true then -- Make magic happen. bluebuild(builder) -- if bluebuild(builder) == true then -- global.blueBuildFirstTick[builder.index] = game.tick -- return -- end end if global.blueDemoToggle[builder.index] == true then --if global.blueLastDemo[builder.index] and game.tick > global.blueLastDemo[builder.index] + 5 then --global.blueLastDemo[builder.index] = game.tick -- Destructive magic happens here bluedemo(builder) -- if bluedemo(builder) == true then -- global.blueLastDemo[builder.index] = game.tick -- return --game.print("Last demo " .. global.blueLastDemo[builder.index] .. " current tick " .. game.tick) --global.blueBuildFirstTick[builder.index] = game.tick --global.blueLastDemo[builder.index] = game.tick -- end --end -- end --Still here? Sleep for 6 ticks anyway. -- global.blueBuildFirstTick[builder.index] = game.tick end else -- Player moved. Reset progress. global.bluePosition[builder.index] = pos global.blueBuildFirstTick.state = false -- global.blueBuildFirstTick[builder.index] = game.tick end end function bluebuild(builder) local pos = builder.position -- local reachDistance = data.raw.player.player.reach_distance local reachDistance = math.min(builder.build_distance + 1, 128) --local searchArea = {{pos.x - reachDistance, pos.y - reachDistance}, {pos.x + reachDistance, pos.y + reachDistance}} -- Bluebuild 1.1 - Switch to a maintained list of ghosts instead of constant searching. -- if (not global.ghosts) or (not global.ghosts[builder.surface.name]) then -- return -- end areaList = builder.surface.find_entities_filtered{area = {{pos.x - reachDistance, pos.y - reachDistance}, {pos.x + reachDistance, pos.y + reachDistance}}, type = "entity-ghost", force=builder.force } --local areaList = builder.surface.find_entities_filtered{area = searchArea, type = "entity-ghost", force=builder.force } --local tileList = builder.surface.find_entities_filtered{area = searchArea, type = "tile-ghost", force=builder.force } -- Merge the lists -- for key, value in pairs(tileList) do -- if not areaList then -- areaList = {} -- end -- table.insert(areaList, value) -- end -- game.print("Found " .. #areaList .. " ghosts in area.") for index, ghost in pairs(areaList) do if ghost == nil or not ghost.valid then -- table.remove(areaList, index) -- return false end --if builder.can_reach_entity(ghost) and builder.force == ghost.force then -- Need a fudge factor since my distance formula seems off. Game likely measures from nearest colliding point? -- if ghost.force == builder.force and distance(builder, ghost) < math.min(builder.build_distance + 1, 128) then -- game.print("Checking for items in inventory.") local materials = ghost.ghost_prototype.items_to_place_this local moduleList if ghost.type == "entity-ghost" then moduleList = ghost.item_requests --{"name"=..., "count"=...} end for __, item in pairs(materials) do if builder.get_item_count(__) > 0 then if ghost.type == "tile-ghost" then builder.remove_item({name=__}) ghost.revive() return true end local tmp, revive = ghost.revive() -- game.print("Placing item " .. revive.name .. ".") if revive and revive.valid then for module, modulecount in pairs(moduleList) do -- game.print("moduleList == " .. moduleItem.item ) if builder.get_item_count(module) > 0 then local modStack = {name=module, count=math.min(builder.get_item_count(module), modulecount)} revive.insert(modStack) builder.remove_item(modStack) end end -- game.print("Removing item from inventory.") --"revive" flag is just a way to signal to other mods that this was raised by script. script.raise_event(defines.events.on_put_item, {position=revive.position, player_index=builder.index, shift_build=false, built_by_moving=false, direction=revive.direction, revive=true}) script.raise_event(defines.events.on_built_entity, {created_entity=revive, player_index=builder.index, tick=game.tick, name="on_built_entity", revive=true}) -- table.remove(areaList, index) builder.remove_item({name=__}) return true end end end -- end -- end end -- Are we still here? return false end function bluedemo(builder) local pos = builder.position --local reachDistance = data.raw.player.player.reach_distance -- Reach distance must not be 0. Just for you, Choumiko. Now works with FAT Controller local reachDistance = math.max(math.min(builder.reach_distance+1, 128), 1) local searchArea = {{pos.x - reachDistance, pos.y - reachDistance}, {pos.x + reachDistance, pos.y + reachDistance}} local areaList = builder.surface.find_entities_filtered{area=searchArea, limit=200} --I may have greatly underestimated how many entities you can fit in a 14x14 block. local areaListCleaned = {} -- if not global.blueLastDemo[builder.index] then -- initPlayer(builder.index) -- end -- Clean areaList for index, ent in pairs(areaList) do if ent and ent.valid and ent.to_be_deconstructed(game.forces.player) and builder.can_reach_entity(ent) then table.insert(areaListCleaned, ent) end end --game.print("Found " .. #areaListCleaned .. " demo targets in area.") --Now calculate mining time and destroy for index, ent in pairs(areaListCleaned) do if ent.name == "deconstructible-tile-proxy" then --In case we're trying to demo floor tiles. tile = ent.surface.get_tile(ent.position) --game.print(ent.prototype.mineable_properties) builder.mine_tile(tile) return true end --Mining time is player... Nevermind, player.mining_power does not yet exist. We'll just assume mining power of 2.5 (iron pickaxe) -- TODO: This is busted. Everything is mining instantly! -- if ent.prototype.mineable_properties.mining_time * 60 + global.blueLastDemo[builder.index] < game.tick then -- This might all be obsolete now thanks to player.mine_entity(entity) --global.blueLastDemo[builder.index] = game.tick if builder.mine_entity(ent) then return true end --Could not mine target for whatever reason. Inventory probably full. --[[ -- Add inventory of the destroyed -- game.print("Destroyed inventory: " .. serpent.line(ent.get_inventory(defines.inventory.item_main))) for inv, def in pairs(defines.inventory) do --] local inventory = ent.get_inventory(def) if inventory and inventory.valid then contents = inventory.get_contents() if contents then --game.print("Inventory " .. serpent.line(def) .. " contents: " .. serpent.line(contents)) for key, value in pairs(contents) do local inserted = builder.insert({name=key, count=value}) if inserted > 0 then ent.remove_item({name=key, count=inserted}) end if inserted == 0 or not inserted == value then --Not enough inventory! builder.surface.create_entity({name="flying-text", position=builder.position, text="Inventory Full"}) return true end end end end end --Add mining products local products = ent.prototype.mineable_properties.products local inserted = 0 if products then -- game.print("Products: " .. serpent.line(products)) for key, value in pairs(products) do inserted = builder.insert({name=value.name, count=math.random(value.amount_min, value.amount_max)}) end end -- Is the destroyed item a item-entity? if not isTile and ent.type == "item-entity" then inserted = builder.insert({name=ent.stack.name, count=ent.stack.count}) end -- Was anything inserted? If not, end here so we don't destroy the entity if inserted == 0 then builder.surface.create_entity({name="flying-text", position=builder.position, text="Inventory Full"}) game.print(ent.name) -- Debug return true end script.raise_event(defines.events.on_preplayer_mined_item, {entity=ent, player_index=builder.index, name="on_preplayer_mined_item"}) ent.destroy() return true ]] -- end end return false end --Reinventing the wheel function distance(ent1, ent2) return math.floor( math.sqrt( (ent1.x - ent2.x)^2 + (ent1.y - ent2.y)^2 ) ) end -- function updateGhosts() -- if not global.ghosts then -- global.ghosts = {} -- end -- for __, surface in pairs(game.surfaces) do -- -- type(surface) is string -- if not global.ghosts[surface.name] then -- global.ghosts[surface.name] = {} -- end -- global.ghosts[surface.name] = game.surfaces[surface.name].find_entities_filtered{name="entity-ghost"} -- end -- end -- script.on_event(defines.events.on_built_entity, function(event) -- if not global.ghosts then -- global.ghosts = {} -- end -- if event.created_entity and event.created_entity.name == "entity-ghost" then -- if not global.ghosts[event.created_entity.surface.name] then -- global.ghosts[event.created_entity.surface.name] = {} -- end -- table.insert(global.ghosts[event.created_entity.surface.name], event.created_entity) -- end -- end) script.on_event(defines.events.on_player_joined_game, function(event) initPlayer(game.players[event.player_index]) end) script.on_event(defines.events.on_tick, function(event) local itemsPerSecond = 2 if game.tick % 60 * 5 == 0 or (global.blueBuildFirstTick.state and game.tick > global.blueBuildFirstTick.tick + 60 / itemsPerSecond) then playerloop() end -- Update ghost list every 5 minutes. -- if (game.tick + 500) % (60 * 60 * 5) == 0 then -- updateGhosts() -- end end) script.on_event('bluebuild-autobuild', function(event) global.blueBuildToggle[event.player_index] = not global.blueBuildToggle[event.player_index] if global.blueBuildToggle[event.player_index] then game.players[event.player_index].print("Bluebuild autobuild set to True.") else game.players[event.player_index].print("Bluebuild autobuild set to False.") end -- global.blueBuildFirstTick[event.player_index] = game.tick end) script.on_event('bluebuild-autodemo', function(event) global.blueDemoToggle[event.player_index] = not global.blueDemoToggle[event.player_index] if global.blueDemoToggle[event.player_index] then game.players[event.player_index].print("Bluebuild autodemo set to True.") else game.players[event.player_index].print("Bluebuild autodemo set to False.") end -- global.blueBuildFirstTick[event.player_index] = game.tick end) script.on_init(function() runOnce() end)