How to kill all biters, spawners, and worms?

Place to get help with not working mods / modding interface.
Post Reply
AngledLuffa
Fast Inserter
Fast Inserter
Posts: 187
Joined: Fri Jan 05, 2018 5:18 pm
Contact:

How to kill all biters, spawners, and worms?

Post by AngledLuffa »

I'm trying to update BitersBegone after the mod author said she doesn't have time to do so herself. The mod has two pieces: kill all biters on install, and prevent new biters from forming.

The old method of killing all biters works fine:

Code: Select all

  for _, surface in pairs(game.surfaces) do
    for _, entity in pairs(surface.find_entities_filtered({force="enemy"})) do
      if entity.destroy() then num = num + 1 end
    end
  end
(keeping track of how many entities are destroyed so it can print statistics)

This is slow, though, so it's suitable for running the first time a map is loaded after installing a mod, but not suitable for frequent use.

The old method of preventing new biters doesn't seem to work, though:

Code: Select all

for _, type in pairs(data.raw) do
  for _, prototype in pairs(type) do
    if prototype.autoplace and prototype.autoplace.force == "enemy" then
      prototype.autoplace.peaks = {}
    end
  end
end
Also, this method never worked when combined with RSO or another biter creation algorithm, so the original author of Biters Begone! added a method for deleting biters on a new chunk creation event. So for example if we do this:

Code: Select all

script.on_event(defines.events.on_chunk_generated, function(event)
  clear_biters()
end)
where clear_biters() is the first block of code, this stops any new biters from forming. However, this is slow. So instead you can pass in the area of the event and do this:

Code: Select all

clear_biters(area)...
  for _, surface in pairs(game.surfaces) do
    for _, entity in pairs(surface.find_entities_filtered({force="enemy", area=area})) do
      if entity.destroy() then num = num + 1 end
    end
  end
...

script.on_event(defines.events.on_chunk_generated, function(event)
  clear_biters(event.area)
end)
This is reasonably fast, but it has two problems. First, it doesn't kill worms and spawners at the edge of the area. This can be solved by expanding the bounding box:

Code: Select all

  if area then
    expanded_area = {}
    
    expanded_area["left_top"] = {}
    expanded_area["left_top"]["x"] = area.left_top.x - 16
    expanded_area["left_top"]["y"] = area.left_top.y - 16
    
    expanded_area["right_bottom"] = {}
    expanded_area["right_bottom"]["x"] = area.right_bottom.x + 16
    expanded_area["right_bottom"]["y"] = area.right_bottom.y + 16
  end
A second problem it is not quite fast enough, so you get stutters when exploring a lot of new area on a large map.

Looking for alternate ways to kill off all the biters, there is LuaForce::kill_all_units(), but this doesn't kill worms or spawners, just the biters themselves.

Is there any simple solution for quickly killing off all the worms and spawners?

1) a fast way to go from LuaForce to a list of all entities, not just the units
2) a fast way to go from an area to all of the entities in that area (my guess is filtering the entities by area is not optimized)
3) a reliable way to prevent the worms or spawners from ever being created
4) another method I haven't thought of?

Thanks!

AngledLuffa
Fast Inserter
Fast Inserter
Posts: 187
Joined: Fri Jan 05, 2018 5:18 pm
Contact:

Re: How to kill all biters, spawners, and worms?

Post by AngledLuffa »

Update: I tried setting max_probabilities=0.0 for the prototypes in data.raw, and that didn't seem to work either.

orzelek
Smart Inserter
Smart Inserter
Posts: 3911
Joined: Fri Apr 03, 2015 10:20 am
Contact:

Re: How to kill all biters, spawners, and worms?

Post by orzelek »

You can use this:

Code: Select all

local zeroExpression = {
    expression_id = "literal-number:1",
    literal_value = 0,
    type = "literal-number"
  }

function resetRichness(ent)
	if ent and ent.autoplace then
		ent.autoplace.richness_multiplier = null
		ent.autoplace.richness_expression = zeroExpression
		ent.autoplace.probability_expression = zeroExpression
	end
end

function removeProbability(ent)
	if ent and ent.autoplace then
		ent.autoplace.probability_expression = zeroExpression
	end
end
From what I recall from patch notes using nil instead of zeroExpression should also work in recent versions. Most likely you need only removeProbability - I'm using it for enemies in RSO.

And if RSO keeps creating enemies... just disable it in settings so it doesn't :D You won't need to scan the chunks then.

Currently RSO in itself can be used to disable enemies completely when it's present. It disables vanilla spawning automatically and has a setting to disable enemy spawning done in RSO.

AngledLuffa
Fast Inserter
Fast Inserter
Posts: 187
Joined: Fri Jan 05, 2018 5:18 pm
Contact:

Re: How to kill all biters, spawners, and worms?

Post by AngledLuffa »

Thanks, that's pretty thorough!

I further tested the scanning method with debug output on, and at most it was adding 1ms to the updates. Maybe that's not the worst. It does handle situations like RSO or other mods which change the biter spawning algorithm. Doesn't matter how the biters were spawned if you then clean them all up automatically, after all, and this way people won't have to fiddle with settings in order to have their biters be eradicated as expected.

quyxkh
Smart Inserter
Smart Inserter
Posts: 1028
Joined: Sun May 08, 2016 9:01 am
Contact:

Re: How to kill all biters, spawners, and worms?

Post by quyxkh »

For my lab-map scenario I just wipe everything on chunk generation, I've never seen it fail:

Code: Select all

script.on_event(de.on_chunk_generated, function(ev)
   -- [[ … ]]
    for _, entity in next,ev.surface.find_entities(ev.area) or empty do
	if entity.valid and not ( entity.type == 'player'
	   or keep_resources and entity.type == 'resource' ) then
	    entity.destroy()
	    end
        end
     -- [[ … ]]
    end)

Post Reply

Return to “Modding help”