Compare commits

...

29 Commits

Author SHA1 Message Date
Joey De Pauw c359a92d45 changelog 3.3 2021-03-09 16:46:10 +01:00
JoeyDP 986997ece2
Merge pull request #2 from AngledLuffa/fewer_tables
Fewer tables
2021-03-09 16:42:29 +01:00
Joey De Pauw 226be2bbef changelog 3.2 2021-03-09 16:30:35 +01:00
John Bauer 35e1c523af Optimize a division 2021-03-08 13:41:18 -08:00
John Bauer 798ed388cf Slightly optimize the tables in the absorb and suction functions 2021-03-08 11:56:17 -08:00
John Bauer 422e24bf32 Create fewer tables when spreading pollution 2021-03-08 10:51:09 -08:00
John Bauer 680e2c09e0 Bump version number 2021-03-07 08:16:06 -08:00
John Bauer 181b9a71cd Rearrange a couple functions for readability 2021-02-27 09:12:54 -08:00
John Bauer a3394b3759 Add some comments 2021-02-27 08:02:50 -08:00
Joey De Pauw 76dbc156c7 Merge branch 'master' of github.com:JoeyDP/Factorio-Better-Air-Filtering 2021-02-05 18:57:54 +01:00
Joey De Pauw e7f576a1b3 apply fix by boskid 2021-02-05 18:57:31 +01:00
JoeyDP 1d42185a7d
Merge pull request #1 from EldrinnElantey/master
Localization into Russian
2021-02-05 18:45:23 +01:00
Eldrinn Elantey 6e9e8087dc Update air-filtering.cfg 2021-02-01 23:35:36 +04:00
Eldrinn Elantey f487bdbc1d Localization into Russian 2021-02-01 23:24:17 +04:00
Joey De Pauw d92ed1e91e Factorio 1.1 2020-12-05 14:38:48 +01:00
Joey De Pauw 29614e6d26 v2.3 2020-01-04 13:36:59 +01:00
Joey De Pauw ff0d0c0d8d v2.2 2020-01-03 16:17:35 +01:00
Joey De Pauw 3de4a98b64 v2.1 2019-12-14 18:03:46 +01:00
Joey De Pauw 7f08bc633b update readme 2019-12-06 20:22:23 +01:00
Joey De Pauw ad176591a1 changelog - update date 2019-12-06 20:14:12 +01:00
Joey De Pauw 86afc16a04 v 0.2.0 2019-12-06 20:11:47 +01:00
Joey De Pauw 33dd2b9bfd update interval setting and optimization (> 0.1) 2019-12-06 19:40:51 +01:00
Joey De Pauw a3afe85909 update README 2019-10-12 17:55:50 +02:00
Joey De Pauw 0e18a7f6b8 gif of setup 2019-10-12 17:52:49 +02:00
Joey De Pauw 4ee328a3f4 reduce fluid capacity of air filters 2019-10-12 11:53:07 +02:00
Joey De Pauw 2509004f80 update README 2019-10-11 19:36:30 +02:00
Joey De Pauw debc17df30 start v0.1.2: fixed tech name, tier 2 is furnace and accepts expendable filters still 2019-10-11 15:48:24 +02:00
Joey De Pauw 8da5bd0d1b updated changelog 2019-10-09 12:48:02 +02:00
Joey De Pauw c00df91c1c v 0.1.1 2019-10-09 12:45:02 +02:00
23 changed files with 490 additions and 254 deletions

View File

@ -1,32 +1,37 @@
# Better Air Filtering
#### A mod for Factorio that provides complex air filtering steps to remove pollution.
Based on the [air filtering mod](https://mods.factorio.com/mod/air-filtering) by [Schorty](https://mods.factorio.com/user/Schorty).
## Overview
![overview](https://github.com/JoeyDP/Factorio-Better-Air-Filtering/blob/master/res/overview.png?raw=true)
![overview](https://github.com/JoeyDP/Factorio-Better-Air-Filtering/blob/master/res/setup.gif?raw=true)
This mod features three tiers of air filtering machines. These machines remove pollution from the air in their region by using air filters. Each consecutive tier has a larger radius and stronger filtering effect. Keep in mind that you will still need filters spread around your base at strategic locations to effectively counteract the spread of pollution.
#### Air filter machine 1
### Air filter machine 1
You start with a basic passive air filter machine that cleans the air in its own [chunk](https://wiki.factorio.com/Map_structure#Chunk). It should help keep biter attacks at bay through the early game.
#### Air filter machine 2
### Air filter machine 2
The upgraded version has a stronger filtering effect. In addition, by using a moderate amount of electricity this machine is able to pull in pollution from neighboring chunks in the shape of a diamond. This version has a radius of two chunks (in [manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry)). Note that a continuous amount of energy is consumed for this suction effect in addition to the cost of filtering the air.
![range_mark_2](https://github.com/JoeyDP/Factorio-Better-Air-Filtering/blob/master/res/radius_mk2.png?raw=true)
#### Air filter machine 3
### Air filter machine 3
The third and final upgrade of the air filtering machine features a larger radius of three chunks along with more air filtering per second.
#### Filter Types
There are currently two types of filters: __expendable filters__ and __recyclable filters__. The first ones are easier to craft, but filter out less pollution and are destroyed upon use. Recyclable filters are more expensive but can be refreshed with a bit of coal to be used again.
### Filter Types
There are currently two types of filters: __expendable filters__ and __recyclable filters__. The first ones are easier to craft, but filter out less pollution and are destroyed upon use. Recyclable filters are more expensive but can be refreshed with a bit of coal to be used again. However, beware that there is a slight chance the filter breaks in the recycling process.
> Known issue: used air filters cannot be extracted from the first tier of air filter machines by inserters. Factorio does not feature inserters that can extract from burnt_result_inventory.
## Technical Details
Some things to keep in mind when using this mod:
- Pollution updates are very UPS efficient. The suction of pollution is implemented per chunk, rather than per machine and updates are spread evenly over an interval of 20 ticks (default). The interval can be changed in the settings.
- The [evolution](https://wiki.factorio.com/Enemies#Evolution) factor of enemies is based on the total amount of produced pollution. Cleaning it back up does not reverse this effect. This means that biters will still get stronger, no matter how proficient you are at cleaning pollution. You can prevent attacks caused by pollution reaching the biter nests however.
- Pollution from other chunks is sucked toward air filters at an exponentially decreasing rate depending on the distance. The formula is `suction = base_suction * (1/4)^distance`. This means that filters only pull in approximately as much pollution as they can filter.
- When an air filter machine or any other entity containing pollution is destroyed or mined, the pollution inside is dispersed back into the atmosphere.
## Changes
Refer to the Factorio mod page for the complete [changelog](https://mods.factorio.com/mod/better-air-filtering/changelog).
@ -34,9 +39,13 @@ Refer to the Factorio mod page for the complete [changelog](https://mods.factori
## Future Features
- A third and more efficient air filtering production chain based on first "dissolving" pollution in water and then treating it in chemical plants.
- Support for signals, and a potential integration with https://mods.factorio.com/mod/pollution-detector.
## Bugs / Crashes / Suggestions
> Important! This mod is in it's early stages of development and has not yet been extensively tested and balanced.
If you experience issues, please notify me on the [forum](https://mods.factorio.com/mod/better-air-filtering/discussion). Suggestions for future releases are also welcome.
## Contribute
First and foremost, suggestions for balancing changes or new features are greatly appreciated. If you create a nice setup with this mod, feel free to share some screenshots or gifs as well. This can be done on the [forum](https://mods.factorio.com/mod/better-air-filtering/discussion) or via [PM](https://forums.factorio.com/ucp.php?i=pm&mode=compose&u=75847).
Changes in the code can be suggested through a pull request on [github](https://github.com/JoeyDP/Factorio-Better-Air-Filtering).

View File

@ -1,9 +1,76 @@
---------------------------------------------------------------------------------------------------
Version: 0.3.3
Date: 2021.03.09
Performance:
- Merge pull request by AngledLuffa to optimize code for pollution suction (https://github.com/JoeyDP/Factorio-Better-Air-Filtering/pull/2).
---------------------------------------------------------------------------------------------------
Version: 0.3.2
Date: 2021.02.05
Fixes:
- Apply fix by boskid: https://forums.factorio.com/95616
---------------------------------------------------------------------------------------------------
Version: 0.3.1
Date: 2020.12.05
Updates:
- Updated to Factorio 1.1.
---------------------------------------------------------------------------------------------------
Version: 0.3.0
Date: 2020.01.24
Updates:
- Updated to Factorio 0.18.
---------------------------------------------------------------------------------------------------
Version: 0.2.3
Date: 2020.01.04
Fixes:
- Register on_tick event on a different callback.
---------------------------------------------------------------------------------------------------
Version: 0.2.2
Date: 2020.01.03
Fixes:
- Air filter machine mk1 changed to type furnace.
- Air filter machine mk1 removed from fast replace group.
---------------------------------------------------------------------------------------------------
Version: 0.2.1
Date: 2019.12.14
Fixes:
- Desync when upgrading from 0.1.3 should be fixed.
---------------------------------------------------------------------------------------------------
Version: 0.2.0
Date: 2019.12.06
Performance:
- Improved performance thanks to Elrood (https://mods.factorio.com/mod/better-air-filtering/discussion/5de458a8b40f56000b3ca43c)
Features:
- Recycling now has a slight chance of breaking the filter.
- Increased power consumption of mk2 and mk3 machines.
- Setting for update interval (can be changed for better UPS).
---------------------------------------------------------------------------------------------------
Version: 0.1.3
Date: 2019.11.16
Locale:
- EN for pollution filter fuel category.
---------------------------------------------------------------------------------------------------
Version: 0.1.2
Date: 2019.10.12
Features:
- Air filters tier 2 and 3 now behave like furnaces. They accept expendable air filters as well as reusable ones.
- Fluid capacity of air filter machines reduced to more reasonable amounts.
Locale:
- EN for reusable air filter tech.
---------------------------------------------------------------------------------------------------
Version: 0.1.1
Date: 2019.10.09
Features:
- Pollution is now registered in the pollution statistics rather than the fluid statistics.
- Air filter machines now accept speed and efficiency modules or beacon effects.
Fixes:
- Invalid entity issue when removing air filter machine during update resolved.
---------------------------------------------------------------------------------------------------
Version: 0.1.0
Date: 2019.10.08
Info:
- Initial release
- Initial release.
Locale:
- Only English
- English.
License:
- Using MIT License.
- MIT License.

View File

@ -2,7 +2,7 @@
-- # Constants #
-- #################
local INTERVAL = 20
local INTERVAL
@ -38,13 +38,6 @@ function positionToChunk(position)
return { x = math.floor(position.x / 32), y = math.floor(position.y / 32) }
end
function movePollution(surface, chunkFrom, chunkTo, amount)
amount = math.min(amount, surface.get_pollution(chunkToPosition(chunkFrom)))
surface.pollute(chunkToPosition(chunkFrom), -amount)
surface.pollute(chunkToPosition(chunkTo), amount)
return amount
end
function getBasePurificationRate(entity)
-- Depends mostly on recipe (optimal recipe used per machine). Should be multiplied by crafting speed to achieve actual max purification rate
if entity.name == "air-filter-machine-1" then
@ -65,18 +58,6 @@ function energyCraftingModifier(entity)
end
end
function getSuctionRate(entity)
if not entity.is_crafting() and getSpaceForPollution(entity) == 0 then
return 0
else
return getBasePurificationRate(entity) * entity.crafting_speed * energyCraftingModifier(entity)
end
end
function getAbsorptionRate(entity)
return math.min(getSpaceForPollution(entity), getSuctionRate(entity))
end
function pollutionInPollutedWater(amount)
return amount * 6 / 10
end
@ -94,6 +75,26 @@ function getSpaceForPollution(entity)
return capacity - pollution
end
function getSuctionRate(entity)
if not entity.is_crafting() and getSpaceForPollution(entity) == 0 then
return 0
else
return getBasePurificationRate(entity) * entity.crafting_speed * energyCraftingModifier(entity)
end
end
function getAbsorptionRate(entity)
return math.min(getSpaceForPollution(entity), getSuctionRate(entity))
end
function getTotalAbsorptionRate(filters)
local totalAbsorptionRate = 0.0
for _, filter in pairs(filters) do
totalAbsorptionRate = totalAbsorptionRate + getAbsorptionRate(filter)
end
return totalAbsorptionRate
end
function inRadius(filter, radius)
if filter.name == "air-filter-machine-1" then
return radius <= 0
@ -106,50 +107,10 @@ function inRadius(filter, radius)
end
end
-- #####################
-- # Update script #
-- #####################
--function updateInserters(event)
--for _, surface in pairs(game.surfaces) do
-- local inserters = surface.find_entities_filtered({type="inserter"})
-- for _, inserter in pairs(inserters) do
-- updateInserter(inserter)
-- end
--end
--end
--function updateInserter(inserter)
--game.print(serpent.line(inserter.position))
--local drop_target = inserter.drop_target
--if drop_target == nil then return end
--local pickup_target = inserter.pickup_target
--if pickup_target == nil then return end
--local burnt_result_inventory = pickup_target.get_burnt_result_inventory()
--if burnt_result_inventory == nil then return end
--if burnt_result_inventory.is_empty() then return end
--if inserter.get_item_count() > 0 then return end
--
--
--local contents = burnt_result_inventory.get_contents()
--
--
--for item_name, count in pairs (contents) do
-- fuel_item_name = item_name
--end
--
--if inserter.get_item_count() < 1 then
-- if inserter.held_stack.valid_for_read == false then
-- if pickup_target.get_item_count(fuel_item_name) > 0 then
-- inserter.held_stack.set_stack({name = fuel_item_name, count = 1})
-- pickup_target.remove_item({name = fuel_item_name, count = 1})
-- return
-- end
-- end
--end
--end
function absorbPollution(event)
-- game.print("insertPollution")
@ -159,27 +120,32 @@ function absorbPollution(event)
end
function absorbChunk(chunk)
if chunk:get_pollution() == 0 then
local chunk_pollution = chunk:get_pollution()
if chunk_pollution == 0 then
return
end
local totalAbsorptionRate = chunk:getTotalAbsorptionRate()
local filters = chunk:getFilters()
local totalAbsorptionRate = getTotalAbsorptionRate(filters)
-- game.print("totalAbsorptionRate: " .. totalAbsorptionRate)
-- game.print("filter count: " .. #chunk.filters)
--game.print("totalAbsorptionRate: " .. totalAbsorptionRate)
--game.print("filter count: " .. #filters)
if totalAbsorptionRate == 0 then
return
end
local toAbsorb = math.min(chunk:get_pollution(), totalAbsorptionRate)
local toAbsorb = math.min(chunk_pollution, totalAbsorptionRate)
-- game.print("To absorb: " .. toAbsorb)
local totalInsertedAmount = 0.0
for _, filter in pairs(chunk.filters) do
local fluid = { name = "pollution", amount = 0.0 }
for _, filter in pairs(filters) do
local toInsert = (getAbsorptionRate(filter) / totalAbsorptionRate) * toAbsorb
if toInsert > 0 then
local insertedAmount = filter.insert_fluid({ name = "pollution", amount = toInsert })
fluid.amount = toInsert
local insertedAmount = filter.insert_fluid(fluid)
game.pollution_statistics.on_flow(filter.name, -insertedAmount)
totalInsertedAmount = totalInsertedAmount + insertedAmount
end
end
@ -194,10 +160,10 @@ function stepsToOrigin(x, y)
-- Provide coordinates of possible 1-steps toward (0, 0)
local steps = {}
if x ~= 0 then
table.insert(steps, { x = x - sign(x), y = y })
table.insert(steps, { x - sign(x), y })
end
if y ~= 0 then
table.insert(steps, { x = x, y = y - sign(y) })
table.insert(steps, { x, y - sign(y) })
end
return steps
end
@ -212,24 +178,26 @@ function suctionUpdateChunk(chunkTo, dx, dy)
-- game.print("From " .. dx .. ", " .. dy)
-- game.print("suction: " .. totalSuction)
local chunkFrom = getFilteredChunk(chunkTo.surface, chunkTo.x + dx, chunkTo.y + dy)
local test = chunkFrom:getTotalSuctionRate(0)
local pollution = chunkFrom:get_pollution()
if pollution > 0 then
local toPollute = math.min(pollution, totalSuction)
local chunksVia = {}
for _, step in pairs(stepsToOrigin(dx, dy)) do
local chunk = getFilteredChunk(chunkTo.surface, chunkTo.x + step.x, chunkTo.y + step.y)
table.insert(chunksVia, chunk)
end
local surface = chunkTo.surface
-- get_pollution can handle indexed x, y as well as named x, y
local position = { (chunkTo.x + dx) * 32, (chunkTo.y + dy) * 32 }
-- game.print("Moving " .. toPollute .. " pollution")
-- game.print("From: " .. chunkFrom.x .. ", " .. chunkFrom.y)
for _, chunkVia in pairs(chunksVia) do
-- game.print("To: " .. chunkVia.x .. ", " .. chunkVia.y)
chunkVia:pollute(toPollute / #chunksVia)
local pollution = surface.get_pollution(position)
if pollution > 0.1 then
local toPollute = math.min(pollution, totalSuction)
-- first, unpollute the chunkFrom
surface.pollute(position, -toPollute)
--game.print("Moving " .. toPollute .. " pollution")
--game.print("From: " .. position[1] .. ", " .. position[2] .. " (" .. toPollute .. ")")
local steps = stepsToOrigin(dx, dy)
toPollute = toPollute / #steps
for _, step in pairs(steps) do
position[1] = (chunkTo.x + step[1]) * 32
position[2] = (chunkTo.y + step[2]) * 32
surface.pollute(position, toPollute)
--game.print("To: " .. position[1] .. ", " .. position[2] .. " (" .. toPollute .. ")")
end
chunkFrom:pollute(-toPollute)
end
end
@ -332,13 +300,14 @@ local FilteredChunk = {
surface = nil,
x = 0,
y = 0,
filters = {},
--filters = {}
}
function FilteredChunk:new (o)
o = o or {}
setmetatable(o, self)
self.__index = self
o.filters = o.filters or {}
return o
end
@ -347,7 +316,6 @@ function createFilteredChunk(surface, x, y)
chunk.surface = surface
chunk.x = x
chunk.y = y
chunk.filters = {} -- this statement, though it appears to have no effect, has a large impact on the saving of global state.
return chunk
end
@ -355,7 +323,25 @@ function FilteredChunk:equal(other)
return self.surface.name == other.surface.name and self.x == other.x and self.y == other.y
end
function FilteredChunk:getFilters()
local filters = {}
for _, filter in pairs(self.filters) do
if filter.valid then
table.insert(filters, filter)
end
end
self.filters = filters
return filters
end
function FilteredChunk:addToMap()
--game.print("Active chunks before: ")
--for i, c in pairs(air_filtered_chunks) do
-- game.print(serpent.line(c))
--end
--game.print(serpent.block(global.air_filtered_chunks_map))
--game.print("Adding chunk to map")
local chunkListX = global.air_filtered_chunks_map[self.surface.name] or {}
local chunkListY = chunkListX[self.x] or {}
@ -364,32 +350,47 @@ function FilteredChunk:addToMap()
chunkListX[self.x] = chunkListY
global.air_filtered_chunks_map[self.surface.name] = chunkListX
table.insert(air_filtered_chunks, self)
--game.print("Active chunks after: ")
--for i, c in pairs(air_filtered_chunks) do
-- game.print(serpent.line(c))
--end
--game.print(serpent.block(global.air_filtered_chunks_map))
end
function FilteredChunk:removeFromMap()
--game.print("Removing chunk from map")
table.remove(global.air_filtered_chunks_map[self.surface.name][self.x], self.y)
global.air_filtered_chunks_map[self.surface.name][self.x][self.y] = nil
for i, c in pairs(air_filtered_chunks) do
if self:equal(c) then
table.remove(air_filtered_chunks, i)
--game.print("Removing chunk from list")
table.remove(air_filtered_chunks, i)
break
end
end
end
function FilteredChunk:getTotalAbsorptionRate()
local totalAbsorptionRate = 0.0
for _, filter in pairs(self.filters) do
local absorptionRate = getAbsorptionRate(filter)
totalAbsorptionRate = totalAbsorptionRate + absorptionRate
end
return totalAbsorptionRate
--local i = 1
--while i <= #air_filtered_chunks do
-- local c = air_filtered_chunks[i]
-- if self:equal(c) then
-- --game.print("Removing chunk from list")
-- table.remove(air_filtered_chunks, i)
-- else
-- i = i + 1
-- end
--end
--game.print("Remaining chunks: ")
--for _, c in pairs(air_filtered_chunks) do
-- game.print(serpent.line(c))
--end
end
function FilteredChunk:getTotalSuctionRate(distance)
local totalSuctionRate = 0.0
for _, filter in pairs(self.filters) do
for _, filter in pairs(self:getFilters()) do
if inRadius(filter, distance) then
local suctionRate = getSuctionRate(filter)
totalSuctionRate = totalSuctionRate + suctionRate
@ -417,6 +418,9 @@ function FilteredChunk:addFilter(filter)
end
end
-- Remove a filter machine from its chunk
-- If this is removing the last filter, the record
-- for this chunk is dropped.
function FilteredChunk:removeFilter(filter)
for i, f in pairs(self.filters) do
if f.unit_number == filter.unit_number then
@ -429,6 +433,9 @@ function FilteredChunk:removeFilter(filter)
end
end
-- either return an existing FilteredChunk for the given coordinates,
-- or create a new one at the corresponding coordinates if there are
-- no existing filters on this chunk
function getFilteredChunk(surface, x, y)
local chunkListX = global.air_filtered_chunks_map[surface.name]
if chunkListX ~= nil then
@ -453,6 +460,8 @@ function isAirFilterMachine(entity)
return starts_with(entity.name, "air-filter-machine-")
end
-- when a new machine is created, add it to the list of filters
-- on whichever chunk it is on
function onEntityCreated(event)
if isAirFilterMachine(event.created_entity) then
local chunkPos = positionToChunk(event.created_entity.position)
@ -498,6 +507,7 @@ function onEntityRemoved(event)
if pollution > 0 then
--game.print("Dispersing " .. pollution .. " pollution back")
event.entity.surface.pollute(event.entity.position, pollution)
game.pollution_statistics.on_flow(event.entity.name, pollution)
end
end
@ -522,6 +532,7 @@ function preEntityRemoved(event)
if pollution > 0 then
--game.print("Dispersing " .. pollution .. " pollution back")
event.entity.surface.pollute(event.entity.position, pollution)
game.pollution_statistics.on_flow(event.entity.name, pollution)
end
end
@ -531,6 +542,21 @@ function preEntityRemoved(event)
end
end
-- Set up callbacks
script.on_event({ defines.events.on_built_entity, defines.events.on_robot_built_entity }, onEntityCreated)
-- on_entity_died should trigger both functions -> called manually
script.on_event({ defines.events.on_player_mined_entity, defines.events.on_robot_mined_entity, defines.events.on_entity_died }, onEntityRemoved)
script.on_event({ defines.events.on_pre_player_mined_item, defines.events.on_pre_robot_mined_item, defines.events.on_entity_died }, preEntityRemoved)
local functions = generateFunctions()
function refreshMetatables()
for _, chunkListX in pairs(global.air_filtered_chunks_map) do
for x, chunkListY in pairs(chunkListX) do
@ -542,8 +568,18 @@ function refreshMetatables()
end
end
function load()
refreshMetatables()
if INTERVAL ~= settings.global["baf-update-interval"].value then
setup()
end
end
script.on_load(load)
function init()
-- gather all filters on every surface
air_filtered_chunks = {}
global.air_filtered_chunks_map = {}
for _, surface in pairs(game.surfaces) do
local filters = surface.find_entities_filtered {
@ -557,27 +593,23 @@ function init()
end
end
function load()
refreshMetatables()
end
-- Set up callbacks
script.on_event({ defines.events.on_built_entity, defines.events.on_robot_built_entity }, onEntityCreated)
-- on_entity_died should trigger both functions -> called manually
script.on_event({ defines.events.on_player_mined_entity, defines.events.on_robot_mined_entity, defines.events.on_entity_died }, onEntityRemoved)
script.on_event({ defines.events.on_pre_player_mined_item, defines.events.on_pre_robot_mined_item, defines.events.on_entity_died }, preEntityRemoved)
local functions = generateFunctions()
local onTick = spreadOverTicks(functions, INTERVAL)
script.on_event(defines.events.on_tick, onTick)
script.on_load(load)
script.on_init(init)
script.on_configuration_changed(init)
function onSettingsChanged(event)
if event.setting == "baf-update-interval" then
setup()
end
end
script.on_event(defines.events.on_runtime_mod_setting_changed, onSettingsChanged)
function setup()
INTERVAL = settings.global["baf-update-interval"].value
onTick = spreadOverTicks(functions, INTERVAL)
script.on_event(defines.events.on_tick, onTick)
end
setup()

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,14 +1,16 @@
{
"name": "better-air-filtering",
"version": "0.1.0",
"version": "0.3.3",
"title": "Better Air Filtering",
"author": "Joey De Pauw",
"contact": "joeydepauw@gmail.com",
"homepage": "",
"factorio_version": "0.17",
"factorio_version": "1.1",
"dependencies": [
"base >= 0.17",
"!air-filtering"
"base >= 1.1",
"!air-filtering",
"!NauvisDay",
"!CW-carbon-capture"
],
"description": "An overhaul of the air filtering mod by Schorty."
"description": "An overhaul of the air filtering mod by Schorty. Includes complex air filtering steps to remove pollution."
}

View File

@ -5,8 +5,8 @@ air-filter-machine-3=Air filter machine 3
[entity-description]
air-filter-machine-1=Passive air filter that reduces pollution in the current chunk using air filters.
air-filter-machine-2=A stronger air filter that uses electricity to pull pollution towards it from a 2 chunk radius.
air-filter-machine-3=An even stronger air filter, capable of cleaning pollution in a 3 chunk radius.
air-filter-machine-2=An air filter machine that uses electricity to pull pollution towards it from a 2 chunk radius.
air-filter-machine-3=Powerful air filter, capable of cleaning pollution in a 3 chunk radius.
[item-name]
@ -17,6 +17,10 @@ liquid-filter=Liquid filter
used-liquid-filter=Used liquid filter
[fuel-category-name]
pollution-filter=Air filter
[fluid-name]
pollution=Pollution
polluted-water=Polluted Water
@ -25,6 +29,7 @@ polluted-water=Polluted Water
[recipe-name]
filter-air=Filter air
filter-air2=Filter air
filter-air-expendable=Filter air
liquid-pollution=Condense pollution
air-filter-recycling=Recycle used air filter
@ -32,9 +37,20 @@ air-filter-recycling=Recycle used air filter
[technology-name]
air-filtering=Air filtering
air-filter-recycling=Recycle used air filters
reusable-air-filters=Reusable air filters
[technology-description]
air-filtering-1=Enables the crafting of passive Air Filter Machines to improve air quality by reducing pollution.
air-filtering-2=A stronger air filter that uses electricity to pull pollution towards it from a 2 chunk radius.
air-filtering-3=An even stronger air filter, capable of cleaning pollution in a 3 chunk radius.
air-filter-recycling=Used air filters can be reused after being recycled by using a bit of coal to refill them.
reusable-air-filters=More strudy air filters that can be recycled with future technology.
air-filter-recycling=Used air filters can be reused after being recycled by using a bit of coal to refill them. Beware that there is a slight chance the filter breaks in the recycling process.
[mod-setting-name]
baf-update-interval=Update interval
[mod-setting-description]
baf-update-interval=Updates are implemented efficiently and are spread over an UPDATE INTERVAL amount of ticks. The default of 20 gives three updates per second. 30 would result in 2 updates per second for example.

View File

@ -0,0 +1,56 @@
[entity-name]
air-filter-machine-1=Машина для фильтрации воздуха 1
air-filter-machine-2=Машина для фильтрации воздуха 2
air-filter-machine-3=Машина для фильтрации воздуха 3
[entity-description]
air-filter-machine-1=Пассивная установка для фильтрации воздуха, действует в радиусе 1 чанка. Для работы требуются воздушные фильтры.
air-filter-machine-2=Активная установка для фильтрации воздуха, которая использует электричество, чтобы притягивать к себе загрязнения из области радиусом в 2 чанка.
air-filter-machine-3=Мощная установка для фильтрации воздуха, способный очищать от загрязнений область радиусом 3 чанка.
[item-name]
expendable-air-filter=Одноразовый воздушный фильтр
air-filter=Воздушный фильтр
used-air-filter=Использованный воздушный фильтр
liquid-filter=Жидкостный фильтр
used-liquid-filter=Использованный жидкостный фильтр
[fuel-category-name]
pollution-filter=Воздушный фильтр
[fluid-name]
pollution=Загрязнение
polluted-water=Загрязненная вода
[recipe-name]
filter-air=Фильтрация воздуха
filter-air2=Фильтрация воздуха
filter-air-expendable=Фильтрация воздуха
liquid-pollution=Конденсировать загрязнения
air-filter-recycling=Переработка использованных воздушных фильтров
[technology-name]
air-filtering=Фильтрация воздуха
air-filter-recycling=Переработка использованных воздушных фильтров
reusable-air-filters=Многоразовые воздушные фильтры
[technology-description]
air-filtering-1=Позволяет создавать пассивные установки для фильтрации воздуха которые улучшают качества воздуха за счет уменьшения загрязнения.
air-filtering-2=Позволяет создавать активные установки для фильтрации воздуха, который использует электричество, чтобы притягивать к себе загрязнения из области радиусом в 2 чанка.
air-filtering-3=Позволяет создавать мощные установки для фильтрации воздуха, способный очищать от загрязнений область радиусом в 3 чанка.
reusable-air-filters=Более прочные воздушные фильтры, которые можно переработать с помощью технологий будущего.
air-filter-recycling=Отработанные воздушные фильтры можно повторно использовать после переработки, заправив их небольшим количеством угля. Помните, что существует небольшая вероятность того, что фильтр сломается в процессе переработки.
[mod-setting-name]
baf-update-interval=Интервал обновления
[mod-setting-description]
baf-update-interval=Обновления выполняются эффективно и распределяются по интервалу ОБНОВЛЕНИЯ в тиках. По умолчанию 20 дает три обновления в секунду. Например, 30 приведет к 2 обновлениям в секунду.

View File

@ -0,0 +1,9 @@
for surfaceName, chunkListX in pairs(global.air_filtered_chunks_map) do
for x, chunkListY in pairs(chunkListX) do
for y, chunk in pairs(chunkListY) do
if chunk.filters == nil or #chunk.filters == 0 then
global.air_filtered_chunks_map[surfaceName][x][y] = nil
end
end
end
end

View File

@ -0,0 +1,40 @@
-- Unlock new recipe
for _, force in pairs(game.forces) do
local technologies = force.technologies
local recipes = force.recipes
recipes["filter-air-expendable"].enabled = technologies["air-filtering-2"].researched
end
-- Doesn't work because migration script is loaded too late
--local function capAtCapacity(entity, capacity)
-- local pollutionFluid = entity.fluidbox[1]
-- local pollution = 0
-- if pollutionFluid then
-- pollution = pollutionFluid.amount
-- end
-- if pollution > capacity then
-- local toRemove = pollution - capacity
-- entity.surface.pollute(entity.position, toRemove)
-- entity.insert_fluid({ name = "pollution", amount = -toRemove })
-- game.print("Removing " .. toRemove .. " pollution")
-- end
--end
--
---- Disperse pollution (fluidbox made smaller)
--for _, surface in pairs(game.surfaces) do
-- local filters1 = surface.find_entities_filtered {
-- name = { "air-filter-machine-1" }
-- }
-- for _, filter in pairs(filters1) do
-- capAtCapacity(filter, 4)
-- end
-- local filters23 = surface.find_entities_filtered {
-- name = { "air-filter-machine-2", "air-filter-machine-3" }
-- }
-- for _, filter in pairs(filters23) do
-- capAtCapacity(filter, 40)
-- end
--end

View File

@ -1,37 +1,36 @@
data:extend({
{
type = "assembling-machine",
type = "furnace",
name = "air-filter-machine-1",
icon = "__better-air-filtering__/graphics/icons/air-filter-machine-1.png",
icon_size = 32,
flags = { "placeable-neutral", "placeable-player", "player-creation" },
minable = { hardness = 0.2, mining_time = 0.5, result = "air-filter-machine-1" },
fast_replaceable_group = "air-filter-machine",
--fast_replaceable_group = "air-filter-machine",
max_health = 150,
corpse = "medium-remnants",
alert_icon_shift = util.by_pixel(-3, -12),
collision_box = { { -1.2, -1.2 }, { 1.2, 1.2 } },
selection_box = { { -1.5, -1.5 }, { 1.5, 1.5 } },
animation =
{
layers =
{
animation = {
layers = {
{
filename = "__better-air-filtering__/graphics/entity/air-filter-machine-1.png",
priority="medium",
priority = "medium",
width = 108,
height = 114,
frame_count = 32,
animation_speed=0.8,
animation_speed = 0.8,
line_length = 8,
shift = util.by_pixel(0, 2)
},
{
filename = "__better-air-filtering__/graphics/entity/air-filter-machine-shadow.png",
priority="medium",
priority = "medium",
width = 95,
height = 83,
frame_count = 1,
animation_speed = 0.8,
line_length = 1,
repeat_count = 32,
draw_as_shadow = true,
@ -42,17 +41,15 @@ data:extend({
match_animation_speed_to_activity = true,
open_sound = { filename = "__base__/sound/machine-open.ogg", volume = 0.85 },
close_sound = { filename = "__base__/sound/machine-close.ogg", volume = 0.75 },
working_sound =
{
working_sound = {
sound = { { filename = "__base__/sound/electric-furnace.ogg", volume = 0.7 } },
idle_sound = { filename = "__base__/sound/idle1.ogg", volume = 0.6 },
apparent_volume = 1.5,
},
fluid_boxes =
{
fluid_boxes = {
{
production_type = "input",
base_area = 10,
base_area = 0.2,
base_level = -1,
pipe_connections = {},
},
@ -60,8 +57,7 @@ data:extend({
},
crafting_categories = { "air-filtering-basic" },
crafting_speed = 0.5,
energy_source =
{
energy_source = {
type = "burner",
fuel_category = "pollution-filter",
usage_priority = "secondary-input",
@ -69,14 +65,17 @@ data:extend({
burnt_inventory_size = 1,
},
energy_usage = "50kW",
fixed_recipe = "filter-air",
ingredient_count = 1,
result_inventory_size = 0,
source_inventory_size = 0,
--ingredient_count = 1,
return_ingredients_on_change = true,
module_slots = 0,
allowed_effects=nil
module_specification = {
module_slots = 0
},
allowed_effects = nil
},
{
type = "assembling-machine",
type = "furnace",
name = "air-filter-machine-2",
icon = "__better-air-filtering__/graphics/icons/air-filter-machine-2.png",
icon_size = 32,
@ -89,10 +88,8 @@ data:extend({
alert_icon_shift = util.by_pixel(-3, -12),
collision_box = { { -1.2, -1.2 }, { 1.2, 1.2 } },
selection_box = { { -1.5, -1.5 }, { 1.5, 1.5 } },
animation =
{
layers =
{
animation = {
layers = {
{
filename = "__better-air-filtering__/graphics/entity/air-filter-machine-2.png",
priority = "medium",
@ -104,7 +101,7 @@ data:extend({
},
{
filename = "__better-air-filtering__/graphics/entity/air-filter-machine-shadow.png",
priority="medium",
priority = "medium",
width = 95,
height = 83,
frame_count = 1,
@ -116,58 +113,42 @@ data:extend({
}
},
match_animation_speed_to_activity = true,
entity_info_icon_shift={0, -0.3},
scale_entity_info_icon = true,
open_sound = { filename = "__base__/sound/machine-open.ogg", volume = 0.85 },
close_sound = { filename = "__base__/sound/machine-close.ogg", volume = 0.75 },
working_sound =
{
working_sound = {
sound = { { filename = "__base__/sound/electric-furnace.ogg", volume = 0.7 } },
idle_sound = { filename = "__base__/sound/idle1.ogg", volume = 0.6 },
apparent_volume = 1.5,
},
fluid_boxes =
{
fluid_boxes = {
{
production_type = "input",
base_area = 10,
base_area = 0.4,
base_level = -1,
pipe_connections= {}
},
{
production_type = "input",
pipe_picture = assembler2pipepictures(),
pipe_covers = pipecoverspictures(),
base_area = 10,
base_level = -1,
pipe_connections = {{ type="input", position = {0, -2} }}
},
{
production_type = "output",
pipe_picture = assembler2pipepictures(),
pipe_covers = pipecoverspictures(),
base_area = 10,
base_level = 1,
pipe_connections = { { type = "output", position = { 0, 2 } } },
secondary_draw_orders = { north = -1 }
pipe_connections = {}
},
off_when_no_fluid_recipe = true
},
crafting_categories = { "air-filtering-advanced" },
crafting_speed = 1.0,
energy_source =
{
energy_source = {
type = "electric",
usage_priority = "secondary-input",
drain="100kW",
drain = "200kW",
},
energy_usage = "50kW",
fixed_recipe = "filter-air2",
ingredient_count = 2,
energy_usage = "100kW",
result_inventory_size = 1,
source_inventory_size = 1,
module_specification = {
module_slots = 2
},
allowed_effects = { "consumption", "speed" },
return_ingredients_on_change = true,
module_slots = 0,
allowed_effects=nil
},
{
type = "assembling-machine",
type = "furnace",
name = "air-filter-machine-3",
icon = "__better-air-filtering__/graphics/icons/air-filter-machine-3.png",
icon_size = 32,
@ -178,10 +159,8 @@ data:extend({
corpse = "medium-remnants",
collision_box = { { -1.2, -1.2 }, { 1.2, 1.2 } },
selection_box = { { -1.5, -1.5 }, { 1.5, 1.5 } },
animation =
{
layers =
{
animation = {
layers = {
{
filename = "__better-air-filtering__/graphics/entity/air-filter-machine-3.png",
priority = "medium",
@ -193,7 +172,7 @@ data:extend({
},
{
filename = "__better-air-filtering__/graphics/entity/air-filter-machine-shadow.png",
priority="medium",
priority = "medium",
width = 95,
height = 83,
frame_count = 1,
@ -207,52 +186,35 @@ data:extend({
match_animation_speed_to_activity = true,
open_sound = { filename = "__base__/sound/machine-open.ogg", volume = 0.85 },
close_sound = { filename = "__base__/sound/machine-close.ogg", volume = 0.75 },
working_sound =
{
working_sound = {
sound = { { filename = "__base__/sound/electric-furnace.ogg", volume = 0.7 } },
idle_sound = { filename = "__base__/sound/idle1.ogg", volume = 0.6 },
apparent_volume = 1.5,
},
fluid_boxes =
{
fluid_boxes = {
{
production_type = "input",
base_area = 10,
base_area = 0.4,
base_level = -1,
pipe_connections= {}
},
{
production_type = "input",
pipe_picture = assembler3pipepictures(),
pipe_covers = pipecoverspictures(),
base_area = 10,
base_level = -1,
pipe_connections = {{ type="input", position = {0, -2} }}
},
{
production_type = "output",
pipe_picture = assembler3pipepictures(),
pipe_covers = pipecoverspictures(),
base_area = 10,
base_level = 1,
pipe_connections = { { type = "output", position = { 0, 2 } } },
secondary_draw_orders = { north = -1 }
pipe_connections = {}
},
off_when_no_fluid_recipe = true
},
crafting_categories = { "air-filtering-advanced" },
crafting_speed = 1.25,
energy_source =
{
energy_source = {
type = "electric",
usage_priority = "secondary-input",
drain="200kW",
drain = "300kW",
},
energy_usage = "100kW",
energy_usage = "200kW",
fixed_recipe = "filter-air2",
ingredient_count = 2,
result_inventory_size = 1,
source_inventory_size = 1,
module_specification = {
module_slots = 3
},
allowed_effects = { "consumption", "speed" },
return_ingredients_on_change = true,
module_slots = 0,
allowed_effects=nil
}
})

View File

@ -7,7 +7,7 @@ data:extend({
gas_temperature = 0,
base_color = { r = 0.95, g = 0.9, b = 0.9 },
flow_color = { r = 0.95, g = 0.9, b = 0.9 },
icon = "__base__/graphics/icons/fluid/pollution.png",
icon = "__better-air-filtering__/graphics/icons/fluid/pollution.png",
icon_size = 32,
order = "a[fluid]-z[water]",
auto_barrel = false
@ -19,7 +19,7 @@ data:extend({
max_temperature = 100,
base_color = { r = 0.27, g = 0.30, b = 0.34 },
flow_color = { r = 0.27, g = 0.30, b = 0.34 },
icon = "__better-air-filtering__/graphics/icons/fluid/pollution.png",
icon = "__better-air-filtering__/graphics/icons/fluid/polluted-water.png",
icon_size = 32,
order = "a[fluid]-z[pollution]",
auto_barrel = false

View File

@ -12,8 +12,7 @@ data:extend({
name = "air-filter-machine-1",
energy_required = 10.0,
enabled = false,
ingredients =
{
ingredients = {
{ "assembling-machine-1", 1 },
{ "electronic-circuit", 5 }
},
@ -24,8 +23,7 @@ data:extend({
name = "air-filter-machine-2",
energy_required = 10.0,
enabled = false,
ingredients =
{
ingredients = {
{ "air-filter-machine-1", 2 },
{ "steel-plate", 10 },
{ "advanced-circuit", 10 }
@ -37,8 +35,7 @@ data:extend({
name = "air-filter-machine-3",
energy_required = 10.0,
enabled = false,
ingredients =
{
ingredients = {
{ "air-filter-machine-2", 2 },
{ "processing-unit", 10 }
},
@ -52,8 +49,7 @@ data:extend({
order = "f[plastic-bar]-a[expendable-air-filter]",
energy_required = 2,
enabled = false,
ingredients =
{
ingredients = {
{ "coal", 5 },
{ "iron-plate", 2 },
},
@ -67,8 +63,7 @@ data:extend({
order = "f[plastic-bar]-b[air-filter]",
energy_required = 5,
enabled = false,
ingredients =
{
ingredients = {
{ "coal", 10 },
{ "plastic-bar", 4 },
{ "steel-plate", 2 }
@ -97,21 +92,29 @@ data:extend({
order = "f[plastic-bar]-c[air-filter-recycling]",
energy_required = 2,
enabled = false,
ingredients =
{
ingredients = {
{ "used-air-filter", 1 },
{ "coal", 5 }
},
result = "air-filter",
results = {
{ type = "item",
name = "air-filter",
amount = 1,
probability = 0.95,
catalyst_amount = 1
}
},
main_product = ""
},
{
type = "recipe",
name = "filter-air",
hide_from_player_crafting = true,
hide_from_stats = true,
icons = {
{
icon = "__base__/graphics/icons/fluid/pollution.png"
icon = "__better-air-filtering__/graphics/icons/fluid/pollution.png"
},
{
icon = "__better-air-filtering__/graphics/icons/recipe/filter-air.png",
@ -125,8 +128,7 @@ data:extend({
order = "a[filter-air]",
energy_required = 1,
enabled = false,
ingredients =
{
ingredients = {
{ type = "fluid", name = "pollution", amount = 2, fluidbox_index = 1 }
},
results = {}
@ -135,9 +137,10 @@ data:extend({
type = "recipe",
name = "filter-air2",
hide_from_player_crafting = true,
hide_from_stats = true,
icons = {
{
icon = "__base__/graphics/icons/fluid/pollution.png"
icon = "__better-air-filtering__/graphics/icons/fluid/pollution.png"
},
{
icon = "__better-air-filtering__/graphics/icons/recipe/filter-air.png",
@ -151,25 +154,52 @@ data:extend({
order = "b[filter-air]",
energy_required = 5,
enabled = false,
ingredients =
{
ingredients = {
{ type = "fluid", name = "pollution", amount = 20, fluidbox_index = 1 },
{ type = "item", name = "air-filter", amount = 1 },
},
results = { { type = "item", name = "used-air-filter", amount = 1 } },
main_product = ""
},
{
type = "recipe",
name = "filter-air-expendable",
hide_from_player_crafting = true,
hide_from_stats = true,
icons = {
{
icon = "__better-air-filtering__/graphics/icons/fluid/pollution.png"
},
{
icon = "__better-air-filtering__/graphics/icons/recipe/filter-air.png",
scale = 0.6,
shift = { 6, 6 }
},
},
icon_size = 32,
category = "air-filtering-advanced",
subgroup = "raw-material",
order = "b[filter-air]",
energy_required = 3,
enabled = false,
ingredients = {
{ type = "fluid", name = "pollution", amount = 10, fluidbox_index = 1 },
{ type = "item", name = "expendable-air-filter", amount = 1 },
},
results = {},
main_product = ""
},
{
type = "recipe",
name = "liquid-pollution",
hide_from_player_crafting = true,
hide_from_stats = true,
category = "air-filtering-advanced",
subgroup = "raw-material",
order = "c[filter-air]",
energy_required = 1,
enabled = false,
ingredients =
{
ingredients = {
{ type = "fluid", name = "pollution", amount = 6, fluidbox_index = 1 },
{ type = "fluid", name = "water", amount = 10, fluidbox_index = 2 }
},

View File

@ -2,7 +2,7 @@ data:extend({
{
type = "technology",
name = "air-filtering-1",
localised_description = {"technology-description.air-filtering-1"},
localised_description = { "technology-description.air-filtering-1" },
icon = "__better-air-filtering__/graphics/technology/air-filtering-1.png",
icon_size = "64",
prerequisites = { "automation", "electronics" },
@ -78,7 +78,7 @@ data:extend({
{
type = "technology",
name = "air-filtering-2",
localised_description = {"technology-description.air-filtering-2"},
localised_description = { "technology-description.air-filtering-2" },
icon = "__better-air-filtering__/graphics/technology/air-filtering-2.png",
icon_size = "64",
prerequisites = { "air-filtering-1", "reusable-air-filters", "advanced-electronics" },
@ -87,10 +87,13 @@ data:extend({
type = "unlock-recipe",
recipe = "air-filter-machine-2"
},
{
type = "unlock-recipe",
recipe = "filter-air2"
},
{
type = "unlock-recipe",
recipe = "filter-air-expendable"
}
},
unit = {
@ -107,7 +110,7 @@ data:extend({
{
type = "technology",
name = "air-filtering-3",
localised_description = {"technology-description.air-filtering-3"},
localised_description = { "technology-description.air-filtering-3" },
icon = "__better-air-filtering__/graphics/technology/air-filtering-3.png",
icon_size = "64",
prerequisites = { "air-filtering-2" },

View File

@ -0,0 +1,10 @@
data:extend({
{
type = "int-setting",
name = "baf-update-interval",
setting_type = "runtime-global",
minimum_value = 5,
maximum_value = 120,
default_value = 20
}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
res/setup.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 MiB

BIN
res/setup_original.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 MiB