315 lines
12 KiB
Lua
315 lines
12 KiB
Lua
--[[
|
|
This is intended for data stage.
|
|
Control stage collision masks have a different format, and there are already provided API functions for collision checking and things.
|
|
]]
|
|
|
|
local util = require("util")
|
|
local collision_mask_util = {}
|
|
|
|
local layer_names =
|
|
{
|
|
"ground-tile",
|
|
"water-tile",
|
|
"resource-layer",
|
|
"doodad-layer",
|
|
"floor-layer",
|
|
"item-layer",
|
|
"ghost-layer",
|
|
"object-layer",
|
|
"player-layer",
|
|
"train-layer",
|
|
"rail-layer",
|
|
"transport-belt-layer"
|
|
}
|
|
|
|
for k = 13, 55 do
|
|
table.insert(layer_names, "layer-"..k)
|
|
end
|
|
|
|
local collision_flags =
|
|
{
|
|
"consider-tile-transitions",
|
|
"not-colliding-with-itself",
|
|
"colliding-with-tiles-only"
|
|
}
|
|
|
|
local default_masks =
|
|
{
|
|
["accumulator"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["ammo-turret"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["arithmetic-combinator"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["arrow"] = {},
|
|
["artillery-flare"] = {},
|
|
["artillery-projectile"] = {},
|
|
["artillery-turret"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["artillery-wagon"] = {"train-layer"},
|
|
["assembling-machine"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["beacon"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["beam"] = {},
|
|
["boiler"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["burner-generator"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["car"] = {"player-layer", "train-layer", "consider-tile-transitions"},
|
|
["cargo-wagon"] = {"train-layer"},
|
|
["character-corpse"] = {},
|
|
["character"] = {"player-layer", "train-layer", "consider-tile-transitions"},
|
|
["cliff"] = {"item-layer", "object-layer", "player-layer", "water-tile", "not-colliding-with-itself"},
|
|
["combat-robot"] = {},
|
|
["constant-combinator"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["construction-robot"] = {},
|
|
["container"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["corpse"] = {},
|
|
["curved-rail"] = {"floor-layer", "item-layer", "object-layer", "rail-layer", "water-tile"},
|
|
["decider-combinator"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["deconstructible-tile-proxy"] = {"ground-tile"},
|
|
["electric-energy-interface"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["electric-pole"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["electric-turret"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["entity-ghost"] = {"ghost-layer"},
|
|
["explosion"] = {},
|
|
["fire"] = {},
|
|
["fish"] = {"ground-tile", "colliding-with-tiles-only"},
|
|
["flame-thrower-explosion"] = {},
|
|
["fluid-turret"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["fluid-wagon"] = {"train-layer"},
|
|
["flying-text"] = {},
|
|
["furnace"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["gate"] = {"item-layer", "object-layer", "player-layer", "train-layer", "water-tile"},
|
|
["generator"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["heat-interface"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["heat-pipe"] = {"floor-layer", "object-layer", "water-tile"},
|
|
["highlight-box"] = {},
|
|
["infinity-container"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["infinity-pipe"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["inserter"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["item-entity"] = {"item-layer"},
|
|
["item-request-proxy"] = {},
|
|
["lab"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["lamp"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["land-mine"] = {"object-layer", "water-tile"},
|
|
["leaf-particle"] = {},
|
|
["linked-container"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["loader-1x1"] = {"item-layer", "object-layer", "transport-belt-layer", "water-tile"},
|
|
["loader"] = {"item-layer", "object-layer", "transport-belt-layer", "water-tile"},
|
|
["locomotive"] = {"train-layer"},
|
|
["logistic-container"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["logistic-robot"] = {},
|
|
["market"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["mining-drill"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["offshore-pump"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["particle-source"] = {},
|
|
["particle"] = {},
|
|
["pipe-to-ground"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["pipe"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["player-port"] = {"floor-layer", "object-layer", "water-tile"},
|
|
["power-switch"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["programmable-speaker"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["projectile"] = {},
|
|
["pump"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["radar"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["rail-chain-signal"] = {"floor-layer", "item-layer", "rail-layer"},
|
|
["rail-remnants"] = {},
|
|
["rail-signal"] = {"floor-layer", "item-layer", "rail-layer"},
|
|
["reactor"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["resource"] = {"resource-layer"},
|
|
["roboport"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["rocket-silo-rocket-shadow"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["rocket-silo-rocket"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["rocket-silo"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["simple-entity-with-force"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["simple-entity-with-owner"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["simple-entity"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["smoke-with-trigger"] = {},
|
|
["smoke"] = {},
|
|
["solar-panel"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["speech-bubble"] = {},
|
|
["spider-leg"] = {"player-layer", "rail-layer"},
|
|
["spider-vehicle"] = {"player-layer", "train-layer"},
|
|
["splitter"] = {"item-layer", "object-layer", "transport-belt-layer", "water-tile"},
|
|
["sticker"] = {},
|
|
["storage-tank"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["straight-rail"] = {"floor-layer", "item-layer", "object-layer", "rail-layer", "water-tile"},
|
|
["stream"] = {},
|
|
["tile"] = {}, -- Tile prototypes are required to have a collision mask so have no default
|
|
["tile-ghost"] = {"ghost-layer"},
|
|
["train-stop"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["transport-belt"] = {"floor-layer", "object-layer", "transport-belt-layer", "water-tile"},
|
|
["tree"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["turret"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["underground-belt"] = {"item-layer", "object-layer", "transport-belt-layer", "water-tile"},
|
|
["unit-spawner"] = {"item-layer", "object-layer", "player-layer", "water-tile"},
|
|
["unit"] = {"player-layer", "train-layer", "not-colliding-with-itself"},
|
|
["wall"] = {"item-layer", "object-layer", "player-layer", "water-tile"}
|
|
}
|
|
|
|
local clear_flags = function(map)
|
|
for k, flag in pairs (collision_flags) do
|
|
map[flag] = nil
|
|
end
|
|
end
|
|
|
|
collision_mask_util.get_default_mask = function(type)
|
|
return util.copy(default_masks[type]) or error("Unknown entity type: "..type)
|
|
end
|
|
|
|
collision_mask_util.get_mask = function(entity_prototype)
|
|
return entity_prototype.collision_mask or collision_mask_util.get_default_mask(entity_prototype.type)
|
|
end
|
|
|
|
collision_mask_util.remove_layer = function(mask, layer)
|
|
return util.remove_from_list(mask, layer)
|
|
end
|
|
|
|
local insert = table.insert
|
|
|
|
collision_mask_util.add_layer = function(mask, layer)
|
|
collision_mask_util.remove_layer(mask, layer)
|
|
insert(mask, layer)
|
|
end
|
|
|
|
collision_mask_util.mask_contains_layer = function(mask, layer)
|
|
local map = util.list_to_map(mask)
|
|
return map[layer]
|
|
end
|
|
|
|
collision_mask_util.masks_collide = function(mask_1, mask_2)
|
|
|
|
local map_1 = util.list_to_map(mask_1)
|
|
local map_2 = util.list_to_map(mask_2)
|
|
if map_1["not-colliding-with-itself"] and map_2["not-colliding-with-itself"] and collision_mask_util.masks_are_same(mask_1, mask_2) then
|
|
return false
|
|
end
|
|
|
|
clear_flags(map_1)
|
|
clear_flags(map_2)
|
|
|
|
for layer, bool in pairs (map_2) do
|
|
if map_1[layer] then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
collision_mask_util.masks_are_same = function(mask_1, mask_2)
|
|
local map1 = util.list_to_map(mask_1)
|
|
local map2 = util.list_to_map(mask_2)
|
|
clear_flags(map1)
|
|
clear_flags(map2)
|
|
for layer, bool in pairs (map2) do
|
|
if not map2[layer] then return false end
|
|
map1[layer] = nil
|
|
end
|
|
return not next(map1)
|
|
end
|
|
|
|
collision_mask_util.collect_prototypes_with_mask = function(mask)
|
|
local prototype_list = {}
|
|
for type, default_mask in pairs (default_masks) do
|
|
for name, entity in pairs (data.raw[type]) do
|
|
local entity_mask = entity.collision_mask or default_mask
|
|
if collision_mask_util.masks_are_same(entity_mask, mask) then
|
|
table.insert(prototype_list, entity)
|
|
end
|
|
end
|
|
end
|
|
return prototype_list
|
|
end
|
|
|
|
collision_mask_util.collect_prototypes_with_layer = function(layer)
|
|
local prototype_list = {}
|
|
for type, default_mask in pairs (default_masks) do
|
|
for name, entity in pairs (data.raw[type]) do
|
|
local entity_mask = entity.collision_mask or default_mask
|
|
if collision_mask_util.mask_contains_layer(entity_mask, layer) then
|
|
table.insert(prototype_list, entity)
|
|
end
|
|
end
|
|
end
|
|
return prototype_list
|
|
end
|
|
|
|
collision_mask_util.collect_prototypes_colliding_with_mask = function(mask)
|
|
local prototype_list = {}
|
|
|
|
local check_list = default_masks
|
|
if collision_mask_util.mask_contains_layer(mask, "colliding-with-tiles-only") then
|
|
check_list = {tile = {}}
|
|
end
|
|
|
|
for type, default_mask in pairs (check_list) do
|
|
for name, entity in pairs (data.raw[type]) do
|
|
local entity_mask = entity.collision_mask or default_mask
|
|
if collision_mask_util.masks_collide(entity_mask, mask) then
|
|
table.insert(prototype_list, entity)
|
|
end
|
|
end
|
|
end
|
|
return prototype_list
|
|
end
|
|
|
|
collision_mask_util.replace_layer_in_all_prototypes = function(old_name, new_name)
|
|
for type, default_mask in pairs (default_masks) do
|
|
for name, entity in pairs (data.raw[type]) do
|
|
local entity_mask = entity.collision_mask or default_mask
|
|
if collision_mask_util.remove_layer(entity_mask, old_name) then
|
|
collision_mask_util.add_layer(entity_mask, new_name)
|
|
entity.collision_mask = entity_mask
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
collision_mask_util.is_layer_used = function(layer)
|
|
for type, default_mask in pairs (default_masks) do
|
|
for name, entity in pairs (data.raw[type]) do
|
|
local entity_mask = entity.collision_mask or default_mask
|
|
if collision_mask_util.mask_contains_layer(entity_mask, layer) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
collision_mask_util.get_first_unused_layer = function()
|
|
for k, layer in pairs (layer_names) do
|
|
if not collision_mask_util.is_layer_used(layer) then
|
|
return layer
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Script for exporting from the game.
|
|
|
|
local defaults = {}
|
|
for name, prototype in pairs (game.entity_prototypes) do
|
|
local type = prototype.type
|
|
if not defaults[type] then
|
|
defaults[type] = prototype.default_collision_mask_with_flags
|
|
end
|
|
end
|
|
|
|
local string = "local default_masks =\n{"
|
|
|
|
for type, mask in pairs (defaults) do
|
|
string = string.."\n[\""..type.."\"] = {"
|
|
local comma = false
|
|
for layer, bool in pairs (mask) do
|
|
if comma then
|
|
string = string..", "
|
|
end
|
|
string = string.."\""..layer.."\""
|
|
comma = true
|
|
end
|
|
string = string.."},"
|
|
end
|
|
|
|
string = string.."\n}"
|
|
|
|
game.write_file("collision_defaults.lua", string)
|
|
|
|
]]
|
|
|
|
return collision_mask_util
|