You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
7.6 KiB

local Beacon = {}
-- Note: supply_area_distance -- extends from edge of collision box
Beacon.affected_types = {"assembling-machine", "furnace", "lab", "mining-drill", "rocket-silo"}
function Beacon.get_beacon_prototypes()
if not Beacon.list_beacon_prototypes then
Beacon.list_beacon_prototypes = {}
for name, prototype in pairs(game.entity_prototypes) do
if prototype.type == "beacon" and prototype.supply_area_distance then
table.insert(Beacon.list_beacon_prototypes, prototype)
end
end
end
return Beacon.list_beacon_prototypes
end
function Beacon.get_max_beacon_range()
if not Beacon.max_beacon_range then
Beacon.max_beacon_range = 0
for _, prototype in pairs(Beacon.list_beacon_prototypes()) do
if prototype.supply_area_distance > Beacon.max_beacon_range then
Beacon.max_beacon_range = prototype.supply_area_distance
end
end
end
return Beacon.max_beacon_range
end
function Beacon.count_affecting_beacons(entity)
local count = 0
for _, prototype in pairs(Beacon.get_beacon_prototypes()) do
local area = util.area_extend(entity.bounding_box, prototype.supply_area_distance)
count = count + entity.surface.count_entities_filtered{type="beacon", name=prototype.name, area=area}
end
return count
end
function Beacon.set_overload_state(entity)
if entity.active == true then
entity.active = false
entity.surface.create_entity{
name = "flying-text",
position = entity.position,
text = {"space-exploration.beacon-overload"}
}
global.beacon_overloaded_entities = global.beacon_overloaded_entities or {}
global.beacon_overloaded_entities[entity.unit_number] = entity
global.beacon_overloaded_shapes = global.beacon_overloaded_shapes or {}
local shape_id = global.beacon_overloaded_shapes[entity.unit_number]
if shape_id and rendering.is_valid(shape_id) then rendering.destroy(shape_id) end -- shouldn't happen but best to check if other mods broke something
shape_id = rendering.draw_sprite{
sprite = "virtual-signal/"..mod_prefix.."beacon-overload",
surface = entity.surface,
target = entity,
x_scale = 1,
y_scale = 1,
target_offset = entity.prototype.alert_icon_shift
}
global.beacon_overloaded_shapes[entity.unit_number] = shape_id
end
-- Regardless of whether entity is active, issue a beacon overload alert to all
-- players on the entity's force. Alert is only issued if the reason for inactivation
-- was beacon overload
if global.beacon_overloaded_entities[entity.unit_number] then
for _, player in pairs(entity.force.players) do
player.add_custom_alert(entity,
{type="virtual", name=mod_prefix.."beacon-overload"},
{"space-exploration.beacon-overload-alert", "[img=virtual-signal/" .. mod_prefix .. "beacon-overload]", "[img=entity/" .. entity.name .. "]"},
true)
end
end
end
function Beacon.unset_overload_state(entity)
if not entity.active then
-- Before reactivating entity, make sure it is present in the overloaded entities list
-- Otherwise it was probably deactivated for a different reason altogether and should
-- not be reactivated by this function
global.beacon_overloaded_entities = global.beacon_overloaded_entities or {}
if global.beacon_overloaded_entities[entity.unit_number] then
entity.active = true
entity.surface.create_entity{
name = "flying-text",
position = entity.position,
text = {"space-exploration.beacon-overload-ended"}
}
global.beacon_overloaded_entities[entity.unit_number] = nil
for interface, functions in pairs(remote.interfaces) do -- allow other mods to deactivate after
if interface ~= "space-exploration" and functions["on_entity_activated"] then
remote.call(interface, "on_entity_activated", {entity=entity, mod="space-exploration"})
end
end
end
-- Remove associated overload shapes if they exist.
global.beacon_overloaded_shapes = global.beacon_overloaded_shapes or {}
if global.beacon_overloaded_shapes[entity.unit_number] then
local shape_id = global.beacon_overloaded_shapes[entity.unit_number]
if rendering.is_valid(shape_id) then rendering.destroy(shape_id) end
global.beacon_overloaded_shapes[entity.unit_number] = nil
end
end
end
function Beacon.validate_entity(entity, ignore_count)
-- make sure not affected by more than 1 beacon
if (not entity.prototype.allowed_effects) or table_size(entity.prototype.allowed_effects) == 0
or (not entity.prototype.module_inventory_size) or entity.prototype.module_inventory_size == 0 then return end
local ignore_count = ignore_count or 0
local beacons = Beacon.count_affecting_beacons(entity)
if beacons > 1 + ignore_count then
Beacon.set_overload_state(entity)
else
-- TODO: add hook here so other things can cancel
Beacon.unset_overload_state(entity)
end
end
function Beacon.validate_beacon(entity, is_deconstructing)
local prototype = entity.prototype
local area = util.area_extend(entity.bounding_box, prototype.supply_area_distance)
local structures = entity.surface.find_entities_filtered{type = Beacon.affected_types, area = area}
local ignore_count = is_deconstructing and 1 or 0
for _, structure in pairs(structures) do
Beacon.validate_entity(structure, ignore_count)
end
end
function Beacon.on_entity_created(event)
local entity
if event.entity and event.entity.valid then
entity = event.entity
end
if event.created_entity and event.created_entity.valid then
entity = event.created_entity
end
if not entity then return end
if entity.type == "beacon" then
Beacon.validate_beacon(entity)
elseif util.table_contains(Beacon.affected_types, entity.type) then
Beacon.validate_entity(entity)
end
end
Event.addListener(defines.events.on_built_entity, Beacon.on_entity_created)
Event.addListener(defines.events.on_robot_built_entity, Beacon.on_entity_created)
Event.addListener(defines.events.script_raised_built, Beacon.on_entity_created)
Event.addListener(defines.events.script_raised_revive, Beacon.on_entity_created)
function Beacon.on_entity_removed(event)
if event.entity and event.entity.valid then
if event.entity.type == "beacon" then
-- do validation but counting 1 beacon fewer
Beacon.validate_beacon(event.entity, true)
end
end
end
Event.addListener(defines.events.on_player_mined_entity, Beacon.on_entity_removed)
Event.addListener(defines.events.on_robot_mined_entity, Beacon.on_entity_removed)
Event.addListener(defines.events.on_entity_died, Beacon.on_entity_removed)
Event.addListener(defines.events.script_raised_destroy, Beacon.on_entity_removed)
function Beacon.validate_overloaded_entities()
-- Cleanup function to be run every 10 seconds, re-evaluating overload status
-- to determine if it's still appropriate, removing references to no-longer-valid
-- entities, and re-issuing alerts if necessary
global.beacon_overloaded_entities = global.beacon_overloaded_entities or {}
global.beacon_overloaded_shapes = global.beacon_overloaded_shapes or {}
for entity_number, entity in pairs(global.beacon_overloaded_entities) do
if entity.valid then
-- If entity is still valid, re-evaluate whether it is still correctly in overload
-- in case the causative beacon was removed without firing an event
Beacon.validate_entity(entity)
else
-- Remove references to these entities as they no longer exist
global.beacon_overloaded_entities[entity_number] = nil
global.beacon_overloaded_shapes[entity_number] = nil
end
end
end
Event.addListener("on_nth_tick_600", Beacon.validate_overloaded_entities)
return Beacon