Skip to content

Instantly share code, notes, and snippets.

@wende
Last active November 4, 2019 23:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wende/ba26e224d4fb65a9fcd53d4fd5aab327 to your computer and use it in GitHub Desktop.
Save wende/ba26e224d4fb65a9fcd53d4fd5aab327 to your computer and use it in GitHub Desktop.
BlueBuild - Fixed demo for longreach, optimized and fix for recent print bug
-- Find ghosts to place. Then find buildings to destruct.
function runOnce()
global.runOnce = true
if not global.blueBuildFirstTick then
global.blueBuildFirstTick = {}
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
if not global.ghostWannabes then
global.ghostWannabes = {}
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.blueBuildFirstTick[player.index] = game.tick
global.blueLastDemo[player.index] = game.tick
global.ghostWannabes[player.index] = {}
end
function playerloop()
for _, player in pairs(game.players) do
if player.connected then
if global.blueBuildFirstTick[player.index] and game.tick > global.blueBuildFirstTick[player.index] + 5 then
bluecheck(player)
end
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 global.bluePosition[builder.index] and global.bluePosition[builder.index].x == pos.x and global.bluePosition[builder.index].y == pos.y then
--We haven't moved. Good, let's continue.
--game.print("Player hasn't moved.")
if global.blueBuildToggle[builder.index] then
-- Make magic happen.
if bluebuild(builder) == true then
global.blueBuildFirstTick[builder.index] = game.tick
return
end
end
if global.blueBuildToggle[builder.index] then
if blueUpgrade(builder) == true then
global.blueBuildFirstTick[builder.index] = game.tick
return
end
end
--Still here? Sleep for 6 ticks anyway.
global.blueBuildFirstTick[builder.index] = game.tick
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
if bluedemo(builder) == true then
global.blueBuildFirstTick[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
else
-- Player moved. Reset progress.
global.bluePosition[builder.index] = pos
global.blueBuildFirstTick[builder.index] = game.tick
end
end
function bluebuild(builder)
local pos = builder.position
--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 = global.ghosts[builder.surface.name]
local areaList = builder.surface.find_entities_filtered{position = pos, radius = builder.reach_distance, type = {"entity-ghost", "tile-ghost"}, force=builder.force, limit=200 }
--local tileList = builder.surface.find_entities_filtered{position = pos, radius = builder.reach_distance, 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
if ghost.force == builder.force and builder.can_reach_entity(ghost) 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(item.name) >= item.count then
if ghost.type == "tile-ghost" then
builder.remove_item({name=item.name, count=item.count})
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=item.name, count=item.count})
return true
end
end
end
end
end
-- Are we still here?
return false
end
function bluedemo(builder)
local pos = builder.position
if not global.blueLastDemo[builder.index] then
initPlayer(builder.index)
end
--Now calculate mining time and destroy
for index, ent in pairs(global.ghostWannabes[builder.index]) do
if ent and distance(builder, ent) < builder.reach_distance then
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)
remove_wannabe(builder.index, ent)
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
remove_wannabe(builder.index, ent)
return true
end --Could not mine target for whatever reason. Inventory probably full.
end
end
end
return false
end
function blueUpgrade(builder)
local pos = builder.position
local reachDistance = math.max(math.min(builder.reach_distance, 128), 1)
local areaList = builder.surface.find_entities_filtered{position = pos, radius = reachDistance, to_be_upgraded=true, limit=150}
for _, target in pairs(areaList) do
local itemsNeeded = target and target.valid and target.get_upgrade_target() and target.get_upgrade_target().items_to_place_this[1]
local upgrade = target.get_upgrade_target()
if itemsNeeded and builder.get_item_count(itemsNeeded.name) >= itemsNeeded.count then
builder.remove_item{name=itemsNeeded.name, count=itemsNeeded.count}
builder.surface.play_sound{position=target.position, path="entity-build/" .. upgrade.name}
builder.surface.create_entity{position=target.position, name=upgrade.name, force=builder.force, direction=target.direction, fast_replace=true, player=builder, raise_built=true}
return true
end
end
end
--Reinventing the wheel
function distance(ent1, ent2)
return math.floor( math.sqrt( (ent1.position.x - ent2.position.x)^2 + (ent1.position.y - ent2.position.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
function remove_wannabe(player_index, entity)
for index, et in pairs(global.ghostWannabes[player_index]) do
if et and et == entity then
global.ghostWannabes[player_index][index] = nil
end
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" or event.created_entity.name == "tile-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)
playerloop()
-- Update ghost list every 5 minutes.
-- if (game.tick + 500) % (60 * 60 * 5) == 0 then
-- updateGhosts()
-- end
end)
script.on_event(defines.events.on_marked_for_deconstruction, function(event)
if not global.ghostWannabes[event.player_index] then
global.ghostWannabes[event.player_index] = {}
end
table.insert(global.ghostWannabes[event.player_index], event.entity)
end)
script.on_event(defines.events.on_cancelled_deconstruction, function(event)
remove_wannabe(event.player_index, event.entity)
end)
script.on_event('bluebuild-autobuild', function(event)
global.blueBuildToggle[event.player_index] = not global.blueBuildToggle[event.player_index]
game.players[event.player_index].print("Bluebuild autobuild set to " .. tostring(global.blueBuildToggle[event.player_index]) .. ".")
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]
game.players[event.player_index].print("Bluebuild autodemo set to " .. tostring(global.blueDemoToggle[event.player_index]) .. ".")
global.blueBuildFirstTick[event.player_index] = game.tick
end)
script.on_init(function()
runOnce()
end)
@wende
Copy link
Author

wende commented Nov 4, 2019

bec1f45ac439bb004e3e211d011be1872c0616eb Adds removing demolition when player cancelled it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment