971 lines
37 KiB
Lua

-- luacheck: globals game global settings script defines, ignore 631
local noxy_trees = {}
local mathfloor = math.floor
local mathceil = math.ceil
local config = {}
noxy_trees.disabled = { -- Disables the spreading of these specific entities.
["dead-dry-hairy-tree"] = true,
["dead-grey-trunk"] = true,
["dead-tree"] = true,
["dead-tree-desert"] = true,
["dry-hairy-tree"] = true,
["dry-tree"] = true,
["green-coral"] = true,
-- Angels Bio Processings special trees.
["temperate-tree"] = true,
["swamp-tree"] = true,
["desert-tree"] = true,
["temperate-garden"] = true,
["swamp-garden"] = true,
["desert-garden"] = true,
["puffer-nest"] = true,
}
noxy_trees.disabled_match = {
["[-]planted"] = true,
["sapling[-]stage[-]"] = true,
}
noxy_trees.degradable = { -- The floor tiles that can be degraded and into what.
-- Vanilla tiles
["concrete"] = "stone-path",
["stone-path"] = true,
["hazard-concrete-left"] = "stone-path",
["hazard-concrete-right"] = "stone-path",
["lab-dark-1"] = "concrete",
["lab-dark-2"] = "concrete",
-- More Floors 0.15
["alien-metal"] = "circuit-floor",
["express-arrow-grate"] = "concrete",
["express-arrow-grate-right"] = "concrete",
["express-arrow-grate-down"] = "concrete",
["express-arrow-grate-left"] = "concrete",
["fast-arrow-grate"] = "concrete",
["fast-arrow-grate-right"] = "concrete",
["fast-arrow-grate-down"] = "concrete",
["fast-arrow-grate-left"] = "concrete",
["nitinol-arrow-grate"] = "concrete",
["nitinol-arrow-grate-right"] = "concrete",
["nitinol-arrow-grate-down"] = "concrete",
["nitinol-arrow-grate-left"] = "concrete",
["titanium-arrow-grate"] = "concrete",
["titanium-arrow-grate-right"] = "concrete",
["titanium-arrow-grate-down"] = "concrete",
["titanium-arrow-grate-left"] = "concrete",
["arrow-grate"] = "concrete",
["arrow-grate-right"] = "concrete",
["arrow-grate-down"] = "concrete",
["arrow-grate-left"] = "concrete",
["asphalt"] = "concrete",
["checkerboard"] = "stone-path",
["circuit-floor"] = "concrete",
["mf-concrete-blue"] = "concrete",
["mf-concrete-darkgrey"] = "concrete",
["mf-concrete-gold"] = "concrete",
["mf-concrete-green"] = "concrete",
["mf-concrete-limegreen"] = "concrete",
["mf-concrete-magenta"] = "concrete",
["mf-concrete-orange"] = "concrete",
["mf-concrete-pink"] = "concrete",
["mf-concrete-purple"] = "concrete",
["mf-concrete-red"] = "concrete",
["mf-concrete-skyblue"] = "concrete",
["mf-concrete-white"] = "concrete",
["mf-concrete-yellow"] = "concrete",
["mf-concrete-black"] = "concrete",
["cobblestone"] = true,
["decal1"] = "stone-path",
["decal2"] = "stone-path",
["decal3"] = "stone-path",
["decal4"] = "stone-path",
["diamond-plate"] = "concrete",
["mf_dirt_dark"] = true,
["mf_dirt"] = true,
["dirt_dark_blueprint"] = true,
["dirt_blueprint"] = true,
["experiment"] = "stone-path",
["mf_green_grass"] = true,
["mf_grass_dry"] = true,
["mf_grass_dry_blueprint"] = true,
["mf_green_grass_blueprint"] = true,
["gravel"] = true,
["hexagonb"] = "metal-scraps",
["lava"] = true,
["metal-scraps"] = true,
["redbrick"] = true,
["reinforced-concrete"] = "concrete",
["road-line"] = "asphalt",
["road-line-right"] = "asphalt",
["road-line-down"] = "asphalt",
["road-line-left"] = "asphalt",
["rusty-metal"] = "metal-scraps",
["rusty-grate"] = "metal-scraps",
["mf_sand_dark"] = true,
["mf_sand_light"] = true,
["sand_dark_blueprint"] = true,
["sand_light_blueprint"] = true,
["smooth-concrete"] = "stone-path",
["snow"] = true,
-- ["tar"] = true, -- Makes this stuff look weird (incorrect edges everywhere)
-- ["toxic"] = true, -- Makes this stuff look weird (incorrect edges everywhere)
["wood-floor"] = true,
["darkwood"] = true,
["herringbone"] = true,
["yellowbrick"] = true,
-- Asphalt Roads
["Arci-asphalt"] = true,
["Arci-asphalt-zebra-crossing-horizontal"] = "Arci-asphalt",
["Arci-asphalt-zebra-crossing-vertical"] = "Arci-asphalt",
["Arci-asphalt-triangle-white-up"] = "Arci-asphalt",
["Arci-asphalt-triangle-white-right"] = "Arci-asphalt",
["Arci-asphalt-triangle-white-down"] = "Arci-asphalt",
["Arci-asphalt-triangle-white-left"] = "Arci-asphalt",
["Arci-asphalt-hazard-white-right"] = "Arci-asphalt",
["Arci-asphalt-hazard-white-left"] = "Arci-asphalt",
["Arci-asphalt-hazard-yellow-right"] = "Arci-asphalt",
["Arci-asphalt-hazard-yellow-left"] = "Arci-asphalt",
["Arci-asphalt-hazard-red-right"] = "Arci-asphalt",
["Arci-asphalt-hazard-red-left"] = "Arci-asphalt",
["Arci-asphalt-hazard-blue-right"] = "Arci-asphalt",
["Arci-asphalt-hazard-blue-left"] = "Arci-asphalt",
["Arci-asphalt-hazard-green-right"] = "Arci-asphalt",
["Arci-asphalt-hazard-green-left"] = "Arci-asphalt",
["Arci-marking-white-straight-horizontal"] = "Arci-asphalt",
["Arci-marking-white-straight-vertical"] = "Arci-asphalt",
["Arci-marking-white-diagonal-left"] = "Arci-asphalt",
["Arci-marking-white-diagonal-right"] = "Arci-asphalt",
["Arci-marking-white-right-turn-up"] = "Arci-asphalt",
["Arci-marking-white-right-turn-right"] = "Arci-asphalt",
["Arci-marking-white-right-turn-down"] = "Arci-asphalt",
["Arci-marking-white-right-turn-left"] = "Arci-asphalt",
["Arci-marking-white-left-turn-up"] = "Arci-asphalt",
["Arci-marking-white-left-turn-right"] = "Arci-asphalt",
["Arci-marking-white-left-turn-down"] = "Arci-asphalt",
["Arci-marking-white-left-turn-left"] = "Arci-asphalt",
["Arci-marking-white-dl-straight-horizontal"] = "Arci-asphalt",
["Arci-marking-white-dl-straight-vertical"] = "Arci-asphalt",
["Arci-marking-white-dl-diagonal-left"] = "Arci-asphalt",
["Arci-marking-white-dl-diagonal-right"] = "Arci-asphalt",
["Arci-marking-white-dl-right-turn-up"] = "Arci-asphalt",
["Arci-marking-white-dl-right-turn-right"] = "Arci-asphalt",
["Arci-marking-white-dl-right-turn-down"] = "Arci-asphalt",
["Arci-marking-white-dl-right-turn-left"] = "Arci-asphalt",
["Arci-marking-white-dl-left-turn-up"] = "Arci-asphalt",
["Arci-marking-white-dl-left-turn-right"] = "Arci-asphalt",
["Arci-marking-white-dl-left-turn-down"] = "Arci-asphalt",
["Arci-marking-white-dl-left-turn-left"] = "Arci-asphalt",
["Arci-marking-yellow-straight-horizontal"] = "Arci-asphalt",
["Arci-marking-yellow-straight-vertical"] = "Arci-asphalt",
["Arci-marking-yellow-diagonal-left"] = "Arci-asphalt",
["Arci-marking-yellow-diagonal-right"] = "Arci-asphalt",
["Arci-marking-yellow-right-turn-up"] = "Arci-asphalt",
["Arci-marking-yellow-right-turn-right"] = "Arci-asphalt",
["Arci-marking-yellow-right-turn-down"] = "Arci-asphalt",
["Arci-marking-yellow-right-turn-left"] = "Arci-asphalt",
["Arci-marking-yellow-left-turn-up"] = "Arci-asphalt",
["Arci-marking-yellow-left-turn-right"] = "Arci-asphalt",
["Arci-marking-yellow-left-turn-down"] = "Arci-asphalt",
["Arci-marking-yellow-left-turn-left"] = "Arci-asphalt",
["Arci-marking-yellow-dl-straight-horizontal"] = "Arci-asphalt",
["Arci-marking-yellow-dl-straight-vertical"] = "Arci-asphalt",
["Arci-marking-yellow-dl-diagonal-left"] = "Arci-asphalt",
["Arci-marking-yellow-dl-diagonal-right"] = "Arci-asphalt",
["Arci-marking-yellow-dl-right-turn-up"] = "Arci-asphalt",
["Arci-marking-yellow-dl-right-turn-right"] = "Arci-asphalt",
["Arci-marking-yellow-dl-right-turn-down"] = "Arci-asphalt",
["Arci-marking-yellow-dl-right-turn-left"] = "Arci-asphalt",
["Arci-marking-yellow-dl-left-turn-up"] = "Arci-asphalt",
["Arci-marking-yellow-dl-left-turn-right"] = "Arci-asphalt",
["Arci-marking-yellow-dl-left-turn-down"] = "Arci-asphalt",
["Arci-marking-yellow-dl-left-turn-left"] = "Arci-asphalt",
-- Dectorio
["dect-wood-floor"] = true,
["dect-concrete-grid"] = true,
["dect-stone-gravel"] = true,
["dect-iron-ore-gravel"] = true,
["dect-copper-ore-gravel"] = true,
["dect-coal-gravel"] = true,
["dect-paint-danger-left"] = "stone-path",
["dect-paint-danger-right"] = "stone-path",
["dect-paint-emergency-left"] = "stone-path",
["dect-paint-emergency-right"] = "stone-path",
["dect-paint-caution-left"] = "stone-path",
["dect-paint-caution-right"] = "stone-path",
["dect-paint-radiation-left"] = "stone-path",
["dect-paint-radiation-right"] = "stone-path",
["dect-paint-defect-left"] = "stone-path",
["dect-paint-defect-right"] = "stone-path",
["dect-paint-operations-left"] = "stone-path",
["dect-paint-operations-right"] = "stone-path",
["dect-paint-safety-left"] = "stone-path",
["dect-paint-safety-right"] = "stone-path",
-- Other mods
["wood floors_brick speed"] = true,
}
noxy_trees.reinforced_degradable = {
-- Vanilla tiles 0.18
["refined-concrete"] = "concrete",
["refined-hazard-concrete-left"] = "refined-concrete",
["refined-hazard-concrete-right"] = "refined-concrete",
["red-refined-concrete"] = "refined-concrete",
["green-refined-concrete"] = "refined-concrete",
["blue-refined-concrete"] = "refined-concrete",
["orange-refined-concrete"] = "refined-concrete",
["yellow-refined-concrete"] = "refined-concrete",
["pink-refined-concrete"] = "refined-concrete",
["purple-refined-concrete"] = "refined-concrete",
["black-refined-concrete"] = "refined-concrete",
["brown-refined-concrete"] = "refined-concrete",
["cyan-refined-concrete"] = "refined-concrete",
["acid-refined-concrete"] = "refined-concrete",
}
-- Create a list for use in a filter function based of the degradable tiles.
noxy_trees.tilefilter = {}
for k,_ in pairs(noxy_trees.degradable) do
noxy_trees.tilefilter[#noxy_trees.tilefilter + 1] = k
end
for k,_ in pairs(noxy_trees.reinforced_degradable) do
noxy_trees.tilefilter[#noxy_trees.tilefilter + 1] = k
end
noxy_trees.fertility = { -- Tiles not listed here are considered non fertile (no spreading at all).
-- Vanilla 0.16
["dirt-1"] = 0.1,
["dirt-2"] = 0.15,
["dirt-3"] = 0.2,
["dirt-4"] = 0.3,
["dirt-5"] = 0.35,
["dirt-6"] = 0.4,
["dirt-7"] = 0.45,
["dry-dirt"] = 0.1,
["grass-1"] = 0.9,
["grass-2"] = 1,
["grass-3"] = 0.95,
["grass-4"] = 0.75,
["red-desert-0"] = 0.6,
["red-desert-1"] = 0.3,
["red-desert-2"] = 0.2,
["red-desert-3"] = 0.1,
["sand-1"] = 0.05,
["sand-2"] = 0.1,
["sand-3"] = 0.05,
["sand-4"] = 0.15, -- Seems to not be used / defined
-- Vanilla 0.15
["grass-medium"] = 1, -- The most fertile
["grass"] = 0.9,
["grass-dry"] = 0.75,
["dirt-dark"] = 0.45,
["dirt"] = 0.35,
["red-desert"] = 0.2,
["red-desert-dark"] = 0.15,
["sand-dark"] = 0.15,
["sand"] = 0.1,
["landfill"] = 0, -- Not fertile
-- Alien biomes 0.15
["grass-red"] = 1,
["grass-orange"] = 1,
["grass-yellow"] = 1,
["grass-yellow-fade"] = 0.9,
["grass-purple-fade"] = 0.9,
["grass-purple"] = 1,
["dirt-red-dark"] = 0.45,
["dirt-brown-dark"] = 0.45,
["grass-blue-fade"] = 0.9,
["grass-blue"] = 1,
["dirt-red"] = 0.35,
["dirt-brown"] = 0.35,
["dirt-tan-dark"] = 0.45,
["dirt-dull-dark"] = 0.45,
["dirt-grey-dark"] = 0.45,
["dirt-tan"] = 0.25,
["dirt-dull"] = 0.25,
["dirt-grey"] = 0.25,
["sand-red-dark"] = 0.15,
["sand-orange-dark"] = 0.15,
["sand-gold-dark"] = 0.15,
["sand-dull-dark"] = 0.1,
["sand-grey-dark"] = 0.1,
["sand-red"] = 0.1,
["sand-orange"] = 0.1,
["sand-gold"] = 0.1,
["sand-dull"] = 0.075,
["sand-grey"] = 0.075,
["snow"] = 0.25,
["volcanic-cool"] = 0.1,
-- Alien biomes 0.16
["mineral-purple-dirt-1"] = 0.45,
["mineral-purple-dirt-2"] = 0.45,
["mineral-purple-dirt-3"] = 0.45,
["mineral-purple-dirt-4"] = 0.45,
["mineral-purple-dirt-5"] = 0.45,
["mineral-purple-dirt-6"] = 0.45,
["mineral-purple-sand-1"] = 0.15,
["mineral-purple-sand-2"] = 0.15,
["mineral-purple-sand-3"] = 0.15,
["mineral-violet-dirt-1"] = 0.45,
["mineral-violet-dirt-2"] = 0.45,
["mineral-violet-dirt-3"] = 0.45,
["mineral-violet-dirt-4"] = 0.45,
["mineral-violet-dirt-5"] = 0.45,
["mineral-violet-dirt-6"] = 0.45,
["mineral-violet-sand-1"] = 0.15,
["mineral-violet-sand-2"] = 0.15,
["mineral-violet-sand-3"] = 0.15,
["mineral-red-dirt-1"] = 0.45,
["mineral-red-dirt-2"] = 0.45,
["mineral-red-dirt-3"] = 0.45,
["mineral-red-dirt-4"] = 0.45,
["mineral-red-dirt-5"] = 0.45,
["mineral-red-dirt-6"] = 0.45,
["mineral-red-sand-1"] = 0.15,
["mineral-red-sand-2"] = 0.15,
["mineral-red-sand-3"] = 0.15,
["mineral-brown-dirt-1"] = 0.45,
["mineral-brown-dirt-2"] = 0.45,
["mineral-brown-dirt-3"] = 0.45,
["mineral-brown-dirt-4"] = 0.45,
["mineral-brown-dirt-5"] = 0.45,
["mineral-brown-dirt-6"] = 0.45,
["mineral-brown-sand-1"] = 0.15,
["mineral-brown-sand-2"] = 0.15,
["mineral-brown-sand-3"] = 0.15,
["mineral-tan-dirt-1"] = 0.45,
["mineral-tan-dirt-2"] = 0.45,
["mineral-tan-dirt-3"] = 0.45,
["mineral-tan-dirt-4"] = 0.45,
["mineral-tan-dirt-5"] = 0.45,
["mineral-tan-dirt-6"] = 0.45,
["mineral-tan-sand-1"] = 0.15,
["mineral-tan-sand-2"] = 0.15,
["mineral-tan-sand-3"] = 0.15,
["mineral-aubergine-dirt-1"] = 0.45,
["mineral-aubergine-dirt-2"] = 0.45,
["mineral-aubergine-dirt-3"] = 0.45,
["mineral-aubergine-dirt-4"] = 0.45,
["mineral-aubergine-dirt-5"] = 0.45,
["mineral-aubergine-dirt-6"] = 0.45,
["mineral-aubergine-sand-1"] = 0.15,
["mineral-aubergine-sand-2"] = 0.15,
["mineral-aubergine-sand-3"] = 0.15,
["mineral-dustyrose-dirt-1"] = 0.45,
["mineral-dustyrose-dirt-2"] = 0.45,
["mineral-dustyrose-dirt-3"] = 0.45,
["mineral-dustyrose-dirt-4"] = 0.45,
["mineral-dustyrose-dirt-5"] = 0.45,
["mineral-dustyrose-dirt-6"] = 0.45,
["mineral-dustyrose-sand-1"] = 0.15,
["mineral-dustyrose-sand-2"] = 0.15,
["mineral-dustyrose-sand-3"] = 0.15,
["mineral-beige-dirt-1"] = 0.45,
["mineral-beige-dirt-2"] = 0.45,
["mineral-beige-dirt-3"] = 0.45,
["mineral-beige-dirt-4"] = 0.45,
["mineral-beige-dirt-5"] = 0.45,
["mineral-beige-dirt-6"] = 0.45,
["mineral-beige-sand-1"] = 0.15,
["mineral-beige-sand-2"] = 0.15,
["mineral-beige-sand-3"] = 0.15,
["mineral-cream-dirt-1"] = 0.45,
["mineral-cream-dirt-2"] = 0.45,
["mineral-cream-dirt-3"] = 0.45,
["mineral-cream-dirt-4"] = 0.45,
["mineral-cream-dirt-5"] = 0.45,
["mineral-cream-dirt-6"] = 0.45,
["mineral-cream-sand-1"] = 0.15,
["mineral-cream-sand-2"] = 0.15,
["mineral-cream-sand-3"] = 0.15,
["mineral-black-dirt-1"] = 0.45,
["mineral-black-dirt-2"] = 0.45,
["mineral-black-dirt-3"] = 0.45,
["mineral-black-dirt-4"] = 0.45,
["mineral-black-dirt-5"] = 0.45,
["mineral-black-dirt-6"] = 0.45,
["mineral-black-sand-1"] = 0.15,
["mineral-black-sand-2"] = 0.15,
["mineral-black-sand-3"] = 0.15,
["mineral-grey-dirt-1"] = 0.45,
["mineral-grey-dirt-2"] = 0.45,
["mineral-grey-dirt-3"] = 0.45,
["mineral-grey-dirt-4"] = 0.45,
["mineral-grey-dirt-5"] = 0.45,
["mineral-grey-dirt-6"] = 0.45,
["mineral-grey-sand-1"] = 0.15,
["mineral-grey-sand-2"] = 0.15,
["mineral-grey-sand-3"] = 0.15,
["mineral-white-dirt-1"] = 0.45,
["mineral-white-dirt-2"] = 0.45,
["mineral-white-dirt-3"] = 0.45,
["mineral-white-dirt-4"] = 0.45,
["mineral-white-dirt-5"] = 0.45,
["mineral-white-dirt-6"] = 0.45,
["mineral-white-sand-1"] = 0.15,
["mineral-white-sand-2"] = 0.15,
["mineral-white-sand-3"] = 0.15,
["vegetation-turquoise-grass-1"] = 0.95,
["vegetation-turquoise-grass-2"] = 0.95,
["vegetation-green-grass-1"] = 1,
["vegetation-green-grass-2"] = 1,
["vegetation-green-grass-3"] = 1,
["vegetation-green-grass-4"] = 1,
["vegetation-olive-grass-1"] = 1,
["vegetation-olive-grass-2"] = 1,
["vegetation-yellow-grass-1"] = 0.85,
["vegetation-yellow-grass-2"] = 0.85,
["vegetation-orange-grass-1"] = 0.85,
["vegetation-orange-grass-2"] = 0.85,
["vegetation-red-grass-1"] = 0.85,
["vegetation-red-grass-2"] = 0.85,
["vegetation-violet-grass-1"] = 0.95,
["vegetation-violet-grass-2"] = 0.95,
["vegetation-purple-grass-1"] = 0.95,
["vegetation-purple-grass-2"] = 0.95,
["vegetation-mauve-grass-1"] = 0.95,
["vegetation-mauve-grass-2"] = 0.95,
["vegetation-blue-grass-1"] = 0.95,
["vegetation-blue-grass-2"] = 0.95,
["volcanic-orange-heat-1"] = 0.05,
["volcanic-orange-heat-2"] = 0.05,
["volcanic-orange-heat-3"] = 0.05,
["volcanic-orange-heat-4"] = 0.05,
["volcanic-green-heat-1"] = 0.15,
["volcanic-green-heat-2"] = 0.15,
["volcanic-green-heat-3"] = 0.15,
["volcanic-green-heat-4"] = 0.15,
["volcanic-blue-heat-1"] = 0.05,
["volcanic-blue-heat-2"] = 0.05,
["volcanic-blue-heat-3"] = 0.05,
["volcanic-blue-heat-4"] = 0.05,
["volcanic-purple-heat-1"] = 0.05,
["volcanic-purple-heat-2"] = 0.05,
["volcanic-purple-heat-3"] = 0.05,
["volcanic-purple-heat-4"] = 0.05,
["frozen-snow-0"] = 0.5,
["frozen-snow-1"] = 0.5,
["frozen-snow-2"] = 0.5,
["frozen-snow-3"] = 0.5,
["frozen-snow-4"] = 0.5,
["frozen-snow-5"] = 0.5,
["frozen-snow-6"] = 0.5,
["frozen-snow-7"] = 0.5,
["frozen-snow-8"] = 0.5,
["frozen-snow-9"] = 0.5,
}
noxy_trees.deathselector = {
"dead-grey-trunk",
"dry-hairy-tree",
"dead-tree-desert"
}
noxy_trees.dead = {
["dry-tree"] = true,
["dry-hairy-tree"] = "dead-dry-hairy-tree",
["dead-grey-trunk"] = "dry-tree",
["dead-dry-hairy-tree"] = true,
["dead-tree-desert"] = "dry-tree",
}
noxy_trees.alive = {
"tree-01",
"tree-01",
"tree-02-red",
"tree-03",
"tree-04",
"tree-05",
"tree-06",
"tree-06-brown",
"tree-07",
"tree-08",
"tree-08-brown",
"tree-08-red",
"tree-09",
"tree-09-brown",
"tree-09-red",
-- Alien Biomes
"tree-wetland-a",
"tree-wetland-b",
"tree-wetland-c",
"tree-wetland-d",
"tree-wetland-e",
"tree-wetland-f",
"tree-wetland-g",
"tree-wetland-h",
"tree-wetland-i",
"tree-wetland-j",
"tree-wetland-k",
"tree-wetland-l",
"tree-wetland-m",
"tree-wetland-n",
"tree-wetland-o",
"tree-grassland-a",
"tree-grassland-b",
"tree-grassland-c",
"tree-grassland-d",
"tree-grassland-e",
"tree-grassland-f",
"tree-grassland-g",
"tree-grassland-h",
"tree-grassland-h2",
"tree-grassland-h3",
"tree-grassland-i",
"tree-grassland-k",
"tree-grassland-l",
"tree-grassland-m",
"tree-grassland-n",
"tree-grassland-0",
"tree-grassland-p",
"tree-grassland-q",
"tree-dryland-a",
"tree-dryland-b",
"tree-dryland-c",
"tree-dryland-d",
"tree-dryland-e",
"tree-dryland-f",
"tree-dryland-g",
"tree-dryland-h",
"tree-dryland-i",
"tree-dryland-j",
"tree-dryland-k",
"tree-dryland-l",
"tree-dryland-m",
"tree-dryland-n",
"tree-dryland-o",
"tree-desert-a",
"tree-desert-b",
"tree-desert-c",
"tree-desert-d",
"tree-desert-e",
"tree-desert-f",
"tree-desert-g",
"tree-desert-h",
"tree-desert-i",
"tree-desert-j",
"tree-desert-k",
"tree-desert-l",
"tree-desert-m",
"tree-desert-n",
"tree-snow-a",
"tree-volcanic-a"
}
local function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return mathfloor(num * mult + 0.5) / mult
end
local function cache_forces()
for _, force in pairs(game.forces) do
if #force.players > 0 then
global.forces[#global.forces + 1] = force.name
end
end
end
local function cache_surfaces()
if game then
global.surfaces = {}
for s in string.gmatch(config.surfaces, '([^,;]+)') do
local su = game.get_surface(s)
if not su then
if tonumber(s) then
su = game.get_surface(tonumber(s))
end
end
if su and su.valid then
table.insert(global.surfaces, su.index)
end
end
if (#global.surfaces < 1) then
global.surfaces = {1}
end
end
end
local function initialize()
global.chunks = {}
global.chunkindex = 0
global.surfaces = {}
global.last_surface = nil
global.forces = {}
global.tick = 0
global.rng = game.create_random_generator()
global.chunkcycles = 0
global.spawnedcount = 0
global.deadedcount = 0
global.killedcount = 0
global.degradedcount = 0
global.resurrected = 0
global.lastdebugmessage = 0
global.lasttotalchunks = 0
cache_surfaces()
cache_forces()
end
local function cache_settings()
config.enabled = settings.global["Noxys_Trees-enabled"].value
config.debug = settings.global["Noxys_Trees-debug"].value
config.debug_interval = settings.global["Noxys_Trees-debug-interval"].value
config.degrade_tiles = settings.global["Noxys_Trees-degrade-tiles"].value
config.do_not_degrade_reinforced_tiles = settings.global["Noxys_Trees-do-not-degrade-reinforced-tiles"].value
config.overpopulation_kills_trees = settings.global["Noxys_Trees-overpopulation-kills-trees"].value
config.kill_trees_near_unwanted = settings.global["Noxys_Trees-kill-trees-near-unwanted"].value
config.ticks_between_operations = settings.global["Noxys_Trees-ticks-between-operations"].value
config.chunks_per_operation = settings.global["Noxys_Trees-chunks-per-operation"].value
config.chunks_per_operation_enable_scaling = settings.global["Noxys_Trees-chunks-per-operation-enable-scaling"].value
config.chunks_per_operation_scaling_bias = settings.global["Noxys_Trees-chunks-per-operation-scaling-bias"].value
config.minimum_distance_between_tree = settings.global["Noxys_Trees-minimum-distance-between-tree"].value
config.minimum_distance_to_enemies = settings.global["Noxys_Trees-minimum-distance-to-enemies"].value
config.minimum_distance_to_uranium = settings.global["Noxys_Trees-minimum-distance-to-uranium"].value
config.minimum_distance_to_player_entities = settings.global["Noxys_Trees-minimum-distance-to-player-entities"].value
config.minimum_distance_to_degradetiles = settings.global["Noxys_Trees-minimum-distance-to-degradeable-tiles"].value
config.deaths_by_lack_of_fertility_minimum = settings.global["Noxys_Trees-deaths-by-lack-of-fertility-minimum"].value
config.deaths_by_pollution_bias = settings.global["Noxys_Trees-deaths-by-pollution-bias"].value
config.trees_to_grow_per_chunk_percentage = settings.global["Noxys_Trees-trees-to-grow-per-chunk-percentage"].value
config.maximum_trees_per_chunk = settings.global["Noxys_Trees-maximum-trees-per-chunk"].value
config.expansion_distance = settings.global["Noxys_Trees-expansion-distance"].value
config.surfaces = settings.global["Noxys_Trees-surfaces"].value
config.trees_grow_on_landfill = settings.global["Noxys_Trees-trees-grow-on-landfill"].value
if config.trees_grow_on_landfill then
noxy_trees.fertility["landfill"] = 0.5
end
cache_surfaces()
end
cache_settings()
local function nx_debug(message)
if config.debug then
game.print("NX Debug: " .. message)
end
end
local function get_trees_in_chunk(surface, chunk)
return surface.find_entities_filtered{area = {{ chunk.x * 32, chunk.y * 32}, {chunk.x * 32 + 32, chunk.y * 32 + 32}}, type = "tree"}
end
local function deadening_tree(surface, tree)
if noxy_trees.dead[tree.name] and noxy_trees.dead[tree.name] == true then
tree.die()
global.killedcount = global.killedcount + 1
return
end
-- Remove tree if a player entity is near it instead of spawning a dead tree.
local rp = config.minimum_distance_to_player_entities
if rp > 0 then
for _, force in pairs(game.forces) do
if #force.players > 0 then
if surface.count_entities_filtered{position = tree.position, radius = rp, force = force, limit = 1} > 0 then
tree.die()
global.deadedcount = global.deadedcount + 1
return
end
end
end
end
if noxy_trees.dead[tree.name] then
if noxy_trees.dead[tree.name] ~= true then
surface.create_entity{name = noxy_trees.dead[tree.name], position = tree.position}
tree.die()
global.deadedcount = global.deadedcount + 1
end
else
local deadtree = noxy_trees.deathselector[global.rng(1, #noxy_trees.deathselector)]
surface.create_entity{name = deadtree, position = tree.position}
tree.die()
global.deadedcount = global.deadedcount + 1
end
end
local function spawn_trees(surface, parent, tilestoupdate, newpos)
if noxy_trees.disabled[parent.name] then return end
if not newpos then
local distance = config.expansion_distance
newpos = {
parent.position.x + global.rng(distance * 2) - distance + (global.rng() - 0.5),
parent.position.y + global.rng(distance * 2) - distance + (global.rng() - 0.5),
}
end
local tile = surface.get_tile(newpos[1], newpos[2])
if tile and tile.valid == true then
-- Tile degradation
local degrade_to = nil
if config.degrade_tiles and noxy_trees.degradable[tile.name] then
degrade_to = noxy_trees.degradable[tile.name]
end
if not config.do_not_degrade_reinforced_tiles and noxy_trees.reinforced_degradable[tile.name] then
degrade_to = noxy_trees.reinforced_degradable[tile.name]
end
if degrade_to ~= nil then
if degrade_to == true then
if tile.hidden_tile then
tilestoupdate[#tilestoupdate + 1] = {["name"] = tile.hidden_tile, ["position"] = tile.position}
else
nx_debug("ERROR: Can't degrade tile because no hidden_tile: " .. tile.name)
end
else
if
game.tile_prototypes[degrade_to]
then
tilestoupdate[#tilestoupdate + 1] = {["name"] = degrade_to, ["position"] = tile.position}
else
nx_debug("ERROR: Invalid tile?: " .. degrade_to .. " Tried to convert from: " .. tile.name)
end
end
elseif -- Tree spreading
(noxy_trees.fertility[tile.name] or 0) > 0 and
not noxy_trees.dead[parent.name] and -- Stop dead trees from spreading.
noxy_trees.fertility[tile.name] > global.rng() and
surface.can_place_entity{name = parent.name, position = newpos}
then
local r = config.minimum_distance_between_tree / noxy_trees.fertility[tile.name]
if surface.count_entities_filtered{position = newpos, radius = r, type = "tree", limit = 1} > 0 then
return
end
local rp = config.minimum_distance_to_player_entities
if rp > 0 then
for _, force in pairs(game.forces) do
if #force.players > 0 then
if surface.count_entities_filtered{position = newpos, radius = rp, force = force, limit = 1} > 0 then
return
end
end
end
end
local er = config.minimum_distance_to_enemies
if surface.count_entities_filtered{position = newpos, radius = er, type = "unit-spawner", force = "enemy", limit = 1} > 0 or
surface.count_entities_filtered{position = newpos, radius = er, type = "turret", force = "enemy", limit = 1} > 0 then
return
end
local ur = config.minimum_distance_to_uranium
if surface.count_entities_filtered{position = newpos, radius = ur, type = "resource", name = "uranium-ore", limit = 1} > 0 then
return
end
local tr = config.minimum_distance_to_degradetiles
if tr > 0 then
if surface.count_tiles_filtered{position = newpos, radius = tr, name = noxy_trees.tilefilter, limit = 1, has_hidden_tile = true} > 0 then
return
end
end
surface.create_entity{name = parent.name, position = newpos}
global.spawnedcount = global.spawnedcount + 1
elseif -- Tree resurrections
(noxy_trees.fertility[tile.name] or 0) > 0 and
noxy_trees.dead[parent.name] and
noxy_trees.fertility[tile.name] > global.rng()
then
-- Only if polution is low enough we do a resurrect (which can also be seen as a mutation)
if surface.get_pollution{parent.position.x, parent.position.y} / config.deaths_by_pollution_bias < 1 + global.rng() then
-- We can skip the distance checks here since the parent tree already exists and we are just going to replace that one.
local newname = noxy_trees.combined[global.rng(#noxy_trees.combined)]
newpos = parent.position
parent.destroy()
surface.create_entity{name = newname, position = newpos}
global.resurrected = global.resurrected + 1
end
end
end
end
local function process_chunk(surface, chunk)
if not chunk then return end
local tilestoupdate = {}
local trees = get_trees_in_chunk(surface, chunk)
local trees_count = #trees
if trees_count >= config.maximum_trees_per_chunk then
if config.overpopulation_kills_trees then
local tokill = 1 + (trees_count / config.maximum_trees_per_chunk)
repeat
local tree = trees[global.rng(1, trees_count)]
if tree and tree.valid == true then
deadening_tree(surface, tree)
end
tokill = tokill - 1
until tokill < 1
end
elseif trees_count > 0 then
-- Grow new trees
local togen = 1 + mathceil(trees_count * config.trees_to_grow_per_chunk_percentage)
repeat
local parent = trees[global.rng(1, trees_count)]
if parent.valid then
spawn_trees(surface, parent, tilestoupdate)
end
togen = togen - 1
until togen <= 0
end
if trees_count < 1 then return end
-- Check random trees for things that would kill them nearby (enemies / uranium / players / fertility)
if config.kill_trees_near_unwanted then
local tokill = 1 + mathceil(trees_count * config.trees_to_grow_per_chunk_percentage)
if config.deaths_by_pollution_bias > 0 then
tokill = tokill + mathceil(surface.get_pollution{chunk.x * 32 + 16, chunk.y * 32 + 16} / config.deaths_by_pollution_bias)
end
repeat
local treetocheck = trees[global.rng(1, trees_count)]
if treetocheck and treetocheck.valid == true then
local er = config.minimum_distance_to_enemies
local ur = config.minimum_distance_to_uranium
if surface.count_entities_filtered{position = treetocheck.position, radius = er, type = "unit-spawner", force = "enemy", limit = 1} > 0 or
surface.count_entities_filtered{position = treetocheck.position, radius = er, type = "turret", force = "enemy", limit = 1} > 0 then
deadening_tree(surface, treetocheck)
elseif surface.count_entities_filtered{position = treetocheck.position, radius = ur, type = "resource", name = "uranium-ore", limit = 1} > 0 then
deadening_tree(surface, treetocheck)
else
local rp = config.minimum_distance_to_player_entities
if rp > 0 then
for _, force in pairs(game.forces) do
if #force.players > 0 then
if surface.count_entities_filtered{position = treetocheck.position, radius = rp, force = force, limit = 1} > 0 then
deadening_tree(surface, treetocheck)
break
end
end
end
end
end
end
if treetocheck and treetocheck.valid == true then
local tile = surface.get_tile(treetocheck.position.x, treetocheck.position.y)
if tile and tile.valid == true then
local fertility = 0
if noxy_trees.fertility[tile.name] then
fertility = noxy_trees.fertility[tile.name]
end
if fertility < config.deaths_by_lack_of_fertility_minimum and fertility < global.rng() then
if trees_count / config.maximum_trees_per_chunk > global.rng() then
deadening_tree(surface, treetocheck)
end
end
end
end
if config.deaths_by_pollution_bias > 0 then
if treetocheck and treetocheck.valid == true then
if surface.get_pollution{treetocheck.position.x, treetocheck.position.y} / config.deaths_by_pollution_bias > 1 + global.rng() then
deadening_tree(surface, treetocheck)
end
end
end
tokill = tokill - 1
until tokill <= 0
end
if #tilestoupdate > 0 then
surface.set_tiles(tilestoupdate)
global.degradedcount = global.degradedcount + #tilestoupdate
end
end
script.on_configuration_changed(function()
if global.noxy_trees then
for k,v in pairs(global.noxy_trees) do
global[k] = v
end
global.noxy_trees = nil
end
initialize()
end)
script.on_init(function ()
initialize()
end)
script.on_event({defines.events.on_runtime_mod_setting_changed}, cache_settings)
script.on_event({defines.events.on_forces_merging, defines.events.on_player_changed_force}, cache_forces)
script.on_event({defines.events.on_tick}, function(event)
local global = global
if config.enabled then
global.tick = global.tick - 1
-- Check alive trees this should only run once
if not noxy_trees.combined then
noxy_trees.combined = {}
for _, tree in pairs(noxy_trees.alive) do
if game.entity_prototypes[tree] then
noxy_trees.combined[#noxy_trees.combined + 1] = tree
end
end
end
-- Add disabled prototypes
if next(noxy_trees.disabled_match) then
for e,_ in pairs(game.entity_prototypes) do
for k,_ in pairs(noxy_trees.disabled_match) do
if e:find(k) then
noxy_trees.disabled[e] = true
end
end
end
-- Clear so we don't do this again.
noxy_trees.disabled_match = {}
end
-- Debug
if config.debug then
if global.lastdebugmessage + config.debug_interval < event.tick then
local timegap = (event.tick - global.lastdebugmessage) / 60
if not global.chunkcycles then global.chunkcycles = 0 end
nx_debug("Chunks: " .. global.chunkindex .. "/" .. #global.chunks .. "(" .. global.lasttotalchunks .. ")."
.. " Grown: " .. global.spawnedcount .. " (" .. round(global.spawnedcount / timegap, 2) .. "/s)."
.. " Deaded: " .. global.deadedcount .. " (" .. round(global.deadedcount / timegap, 2) .. "/s)."
.. " Killed: " .. global.killedcount .. " (" .. round(global.killedcount / timegap, 2) .. "/s)."
.. " Degrade: " .. global.degradedcount .. " (" .. round(global.degradedcount / timegap, 2) .. "/s)."
.. " Rezzed: " .. global.resurrected .. " (" .. round(global.resurrected / timegap, 2) .. "/s)."
.. " Chunk Cycle: " .. global.chunkcycles .. "."
)
global.lastdebugmessage = event.tick
global.spawnedcount = 0
global.deadedcount = 0
global.killedcount = 0
global.degradedcount = 0
global.resurrected = 0
end
end
if global.tick <= 0 or global.tick == nil then
global.tick = config.ticks_between_operations
-- Do the stuff
local last_surface, surface_index = next(global.surfaces, global.last_surface)
if surface_index then
local surface = game.get_surface(surface_index)
if surface and surface.valid then
local chunksdone = 0
local chunkstodo = config.chunks_per_operation
if config.chunks_per_operation_enable_scaling then --todo: Add cap on number of chunks per operation; maybe change the scaling so that it increases how often it runs instead of how many chunks
chunkstodo = mathfloor(chunkstodo * (global.lasttotalchunks / config.chunks_per_operation_scaling_bias))
end
if chunkstodo < 1 then chunkstodo = 1 end
repeat
if #global.chunks < 1 then
-- populate our chunk array
for chunk in surface.get_chunks() do
global.chunks[#global.chunks + 1] = chunk
end
global.chunkcycles = global.chunkcycles + 1
global.lasttotalchunks = #global.chunks
end
if #global.chunks < 1 then nx_debug("Bailing because no chunks!") break end
-- Select a chunk
global.chunkindex = global.chunkindex + 1
if global.chunkindex > #global.chunks then
global.chunkindex = 0
global.chunks = {}
break
end
process_chunk(surface, global.chunks[global.chunkindex])
-- Done
chunksdone = chunksdone + 1
until chunksdone >= chunkstodo
end
end
global.last_surface = last_surface
end
if global.tick > config.ticks_between_operations then
global.tick = config.ticks_between_operations
end
end
end)