commit
9b6429cef0
37 changed files with 1778 additions and 0 deletions
@ -0,0 +1,41 @@ |
|||
# Compiled Lua sources |
|||
luac.out |
|||
|
|||
# luarocks build files |
|||
*.src.rock |
|||
*.zip |
|||
*.tar.gz |
|||
|
|||
# Object files |
|||
*.o |
|||
*.os |
|||
*.ko |
|||
*.obj |
|||
*.elf |
|||
|
|||
# Precompiled Headers |
|||
*.gch |
|||
*.pch |
|||
|
|||
# Libraries |
|||
*.lib |
|||
*.a |
|||
*.la |
|||
*.lo |
|||
*.def |
|||
*.exp |
|||
|
|||
# Shared objects (inc. Windows DLLs) |
|||
*.dll |
|||
*.so |
|||
*.so.* |
|||
*.dylib |
|||
|
|||
# Executables |
|||
*.exe |
|||
*.out |
|||
*.app |
|||
*.i*86 |
|||
*.x86_64 |
|||
*.hex |
|||
|
@ -0,0 +1,5 @@ |
|||
# factoriomods |
|||
Mods I made changes on to adjust my playthrough |
|||
|
|||
## robot attrition |
|||
Mod is a requirement of Space Exploration. But I don't want it. So I disabled its functionality, it basically does no longer work. |
@ -0,0 +1,6 @@ |
|||
# robot-attrition |
|||
Robot Attrition |
|||
|
|||
This is **NOT** an open source project, please check the licence file. |
|||
|
|||
If you would like to contribute please contact Earendel on Discord first: https://discord.gg/ymjUVMv |
@ -0,0 +1,134 @@ |
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.10 |
|||
Date: 14. 05. 2021 |
|||
Locale: |
|||
- Added Russian translation thanks to Shadow_Man. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.9 |
|||
Date: 29. 01. 2021 |
|||
Bugfixes: |
|||
- Fix crash if a bot became invalid during the processing loop. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.8 |
|||
Date: 18. 01. 2021 |
|||
Bugfixes: |
|||
- Fix that crashed robots could be deployed as working robots. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.7 |
|||
Date: 13. 12. 2020 |
|||
Bugfixes: |
|||
- Fix for layered robot icons and the repair recipes. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.6 |
|||
Date: 13. 12. 2020 |
|||
Changes: |
|||
- Updated repair recipe to have % secondary products if not all of 1 ingredient is needed. |
|||
- Added 2nd restoration recipe for robot recombination. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.5 |
|||
Date: 07. 12. 2020 |
|||
Compatibility: |
|||
- Creative mod test bots don't cause a crash during loading. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.3 |
|||
Date: 07. 12. 2020 |
|||
Bugfixes: |
|||
- Fixed problem with robot repair activating. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.2 |
|||
Date: 04. 12. 2020 |
|||
Changes: |
|||
- Added option for robot repair. |
|||
|
|||
Bugfixes: |
|||
- Fixed swarm safety levels not being applied correctly. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.1 |
|||
Date: 24. 11. 2020 |
|||
Info: |
|||
- Updated for Factorio 1.1. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.5 |
|||
Date: 22. 11. 2020 |
|||
Changes: |
|||
- UPS improvement for games with lots of surfaces (400x faster in some cases). |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.4 |
|||
Date: 24. 07. 2020 |
|||
Changes: |
|||
- Added explosion reduction technology for increasing logistic swarm sizes (500 per level). |
|||
- Uses a faster method to drop items to the ground (thanks to Mylon). |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.3 |
|||
Date: 31. 05. 2020 |
|||
Locale: |
|||
- Added chinese translation thanks to Frost. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.2 |
|||
Date: 07. 02. 2020 |
|||
Info: |
|||
- Updated for Factorio 0.18.4. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.1 |
|||
Date: 27. 01. 2020 |
|||
Info: |
|||
- Updated for Factorio 0.18. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.8 |
|||
Changes: |
|||
- Code optimizations. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.7 |
|||
Changes: |
|||
- Fixed remote interface call. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.6 |
|||
Changes: |
|||
- Attrition can now be altered per-surface by mods, this can multiply or override the mod setting. |
|||
- Surfaces with attrition rates of 0.001 and below do not process attrition at all (saves UPS). |
|||
- Further UPS optimisations. |
|||
- Fixed bots dropping items on belts. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.5 |
|||
Changes: |
|||
- Code optimizations. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.4 |
|||
Changes: |
|||
- Updated description. |
|||
- Minimum attrition multiplier is now 0.001. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.3 |
|||
Changes: |
|||
- Re-worked the code for continuous processing instead of batches on longer interval. (Reduces UPS stutters). |
|||
- Default attrition factor is now 1 instead of 10 to match the new code structure (actual crash rate is slightly lower). |
|||
- Minimum attrition multiplier is now 0.01. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.2 |
|||
Changes: |
|||
- Changed robots creating fire on death to robots doing weak AOE explosion damage (fire did not make sense in space). |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.1 |
|||
Info: |
|||
- Updated for Factorio 0.17. |
@ -0,0 +1,271 @@ |
|||
Event = require('scripts/event') |
|||
|
|||
min_attrition_rate = 0.0011 |
|||
tickskip = 10 |
|||
|
|||
function is_system_force(force_name) |
|||
return force_name == "enemy" |
|||
or force_name == "neutral" |
|||
or force_name == "capture" |
|||
or force_name == "conquest" |
|||
or force_name == "ignore" |
|||
or force_name == "friendly" |
|||
end |
|||
|
|||
function get_attrition_rate_for_surface(surface_index) |
|||
-- use cache |
|||
if global.suface_attrition_rates[surface_index] then |
|||
return global.suface_attrition_rates[surface_index] |
|||
end |
|||
-- or load |
|||
local rate = nil |
|||
local default_rate = settings.global["robot-attrition-factor"].value |
|||
for interface, functions in pairs(remote.interfaces) do |
|||
if functions["robot_attrition_for_surface"] then |
|||
local returned_rate = remote.call(interface, "robot_attrition_for_surface", {default_rate = default_rate, surface_index = surface_index}) |
|||
if rate == nil or returned_rate > rate then |
|||
rate = returned_rate |
|||
end |
|||
end |
|||
end |
|||
if rate == nil then |
|||
rate = default_rate |
|||
end |
|||
global.suface_attrition_rates[surface_index] = rate |
|||
--game.print("Robot attrition rate for surface " .. surface_index .. " ("..game.surfaces[surface_index].name..") is " .. rate) |
|||
|
|||
return rate |
|||
end |
|||
|
|||
function get_crash_item(bot) |
|||
if global.crash_items[bot.name] then |
|||
if global.crash_items[bot.name] ~= "none" then |
|||
return global.crash_items[bot.name] |
|||
else |
|||
return nil |
|||
end |
|||
else |
|||
if bot.prototype.mineable_properties.products and bot.prototype.mineable_properties.products[1] then |
|||
local name = bot.prototype.mineable_properties.products[1].name.."-crashed" |
|||
if game.item_prototypes[name] then |
|||
global.crash_items[bot.name] = name |
|||
return name |
|||
end |
|||
end |
|||
end |
|||
global.crash_items[bot.name] = "none" |
|||
end |
|||
|
|||
function get_bot_speed(name) |
|||
if not global.bot_speed then global.bot_speed = {} end |
|||
if not global.bot_speed[name] then |
|||
global.bot_speed[name] = game.entity_prototypes[name].speed |
|||
end |
|||
return global.bot_speed[name] |
|||
end |
|||
|
|||
function get_bot_slow_speed_multiplier(name) |
|||
if not global.bot_slow_speed_multiplier then global.bot_slow_speed_multiplier = {} end |
|||
if not global.bot_slow_speed_multiplier[name] then |
|||
global.bot_slow_speed_multiplier[name] = game.entity_prototypes[name].speed_multiplier_when_out_of_energy |
|||
end |
|||
return global.bot_slow_speed_multiplier[name] |
|||
end |
|||
|
|||
function bot_crash(bot, n_bots) |
|||
|
|||
local inventory = bot.get_inventory(defines.inventory.robot_cargo) |
|||
local contents = inventory.get_contents() |
|||
if global.robot_repair_setting == "Repair75" then |
|||
local item = get_crash_item(bot) |
|||
if item then |
|||
bot.surface.spill_item_stack(bot.position, {name=item, count=1}, false, bot.force, false) --Spill, mark for decon, disallow belts |
|||
end |
|||
end |
|||
for name, count in pairs(contents) do |
|||
bot.surface.spill_item_stack(bot.position, {name=name, count=count}, false, bot.force, false) --Spill, mark for decon, disallow belts |
|||
end |
|||
bot.get_inventory(defines.inventory.robot_cargo).clear() |
|||
bot.force.kill_count_statistics.on_flow(bot.name, -1) --Track bot's death. |
|||
if global.forcedata and global.forcedata[bot.force.name] and global.forcedata[bot.force.name]["robot-attrition-explosion-safety"] |
|||
and n_bots <= 500 * global.forcedata[bot.force.name]["robot-attrition-explosion-safety"] then |
|||
--game.print("Skip explosion, n_bots "..n_bots.."<= ".. 500 * global.forcedata[bot.force.name]["robot-attrition-explosion-safety"]) |
|||
else |
|||
bot.surface.create_entity{name = "robot-explosion", position=bot.position} |
|||
end |
|||
if bot.valid then |
|||
bot.destroy() |
|||
end |
|||
global.bots_crashed = (global.bots_crashed or 0) + 1 -- used as an achievement metric |
|||
|
|||
end |
|||
|
|||
function process_bot(bot, n_bots) |
|||
local force_speed_multiplier = 1 + bot.force.worker_robots_speed_modifier |
|||
local speed = get_bot_speed(bot.name) * force_speed_multiplier |
|||
local held_item_count = 0 |
|||
if bot.energy > 0 then |
|||
local inventory = bot.get_inventory(defines.inventory.robot_cargo) |
|||
held_item_count = inventory.get_item_count() |
|||
else |
|||
speed = 0.5 * speed * get_bot_slow_speed_multiplier(bot.name) |
|||
end |
|||
local speed_items = speed * (held_item_count + 0.5) -- carrying itself counts as 0.5 items |
|||
local crash_score = speed_items |
|||
bot_crash(bot, n_bots) |
|||
return crash_score |
|||
end |
|||
|
|||
function on_tick(event) |
|||
--[[ |
|||
slowest funtions is by far: network.logistic_robots[i] |
|||
so only do that once per explosion. |
|||
which means that if a robot is selected it must die. |
|||
but risk factors should still be speed * items carried |
|||
so add these factors to the probability of the next selection round |
|||
factors apply multiplier to next selection phase |
|||
]]-- |
|||
--[[if not global.force_surfaces then return end |
|||
if game.tick % tickskip ~= 0 then return end |
|||
|
|||
--game.forces[force].logistic_networks[network].logistic_robots :: array of LuaEntity |
|||
--for _, force in pairs(game.forces) do |
|||
for force_name, force_surfaces in pairs(global.force_surfaces) do |
|||
local force = game.forces[force_name] |
|||
if not force then |
|||
global.force_surfaces[force_name] = nil |
|||
else |
|||
local i = randint |
|||
--for surface_name, networks in pairs(force.logistic_networks) do |
|||
local force_logistic_networks = force.logistic_networks -- array of surface_name, networks |
|||
for surface_name, _ in pairs(force_surfaces) do |
|||
local surface = game.surfaces[surface_name] |
|||
if not surface then |
|||
force_surfaces[surface_name] = nil |
|||
else |
|||
local networks = force_logistic_networks[surface_name] |
|||
if networks then |
|||
local surface_attrition_rate = get_attrition_rate_for_surface(game.surfaces[surface_name].index) |
|||
if surface_attrition_rate > min_attrition_rate then |
|||
for _, network in pairs(networks) do |
|||
local n_bots = network.all_logistic_robots - network.available_logistic_robots |
|||
if n_bots > 50 then -- ignore small networks |
|||
if not global.forces[force.name] then global.forces[force.name] = {} end |
|||
if not global.forces[force.name][surface_name] then global.forces[force.name][surface_name] = { crash = 0, crash_rate = 0.1 } end |
|||
local crash_rate = global.forces[force.name][surface_name].crash_rate * tickskip * surface_attrition_rate / 1000000 |
|||
local crash = global.forces[force.name][surface_name].crash + crash_rate * n_bots |
|||
if crash >= 1 then |
|||
local logistic_robots = network.logistic_robots |
|||
local to_crash = math.min(math.ceil(#logistic_robots/2), 1 + math.random(math.floor(crash))) -- don't crash all |
|||
local i = math.random(#logistic_robots) -- choose a starting bot |
|||
local crashed = 0 |
|||
while crashed < to_crash do |
|||
-- then step through bots |
|||
i = (i % #logistic_robots) + 1 |
|||
if logistic_robots[i] and logistic_robots[i].valid then |
|||
global.forces[force.name][surface_name].crash_rate = global.forces[force.name][surface_name].crash_rate * 0.9 + 0.1 * process_bot(logistic_robots[i], n_bots) |
|||
end -- if invalid bots were found just skip them anyway |
|||
crashed = crashed + 1 |
|||
end |
|||
crash = crash - crashed |
|||
end |
|||
global.forces[force.name][surface_name].crash = crash |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end ]]-- |
|||
end |
|||
|
|||
function on_init(event) |
|||
global.forces = {} |
|||
global.bot_speed = {} |
|||
global.bot_slow_speed_multiplier = {} |
|||
global.suface_attrition_rates = {} |
|||
|
|||
global.robot_repair_setting = settings.startup["robot-attrition-repair"].value |
|||
global.crash_items = {} |
|||
end |
|||
|
|||
function on_configuration_changed(event) |
|||
global.forces = {} |
|||
global.bot_speed = {} |
|||
global.bot_slow_speed_multiplier = {} |
|||
global.suface_attrition_rates = {} -- clear |
|||
if not global.force_surfaces then |
|||
for _, force in pairs(game.forces) do |
|||
if not is_system_force(force.name) then |
|||
for surface_name, networks in pairs(force.logistic_networks) do |
|||
for _, network in pairs(networks) do |
|||
if network.all_logistic_robots > 0 then |
|||
add_surface(force, game.surfaces[surface_name]) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
global.robot_repair_setting = settings.startup["robot-attrition-repair"].value |
|||
global.crash_items = {} |
|||
|
|||
end |
|||
function on_runtime_mod_setting_changed(event) |
|||
if event.setting == "robot-attrition-factor" then |
|||
global.suface_attrition_rates = {} -- clear |
|||
end |
|||
end |
|||
|
|||
|
|||
-- Surface Gathering |
|||
function add_surface(force, surface) |
|||
if not is_system_force(force.name) then |
|||
if #force.players > 0 then |
|||
global.force_surfaces = global.force_surfaces or {} |
|||
global.force_surfaces[force.name] = global.force_surfaces[force.name] or {} |
|||
if not global.force_surfaces[force.name][surface.name] then |
|||
global.force_surfaces[force.name][surface.name] = game.tick |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
function on_built_roboport(event) |
|||
if not(event.created_entity and event.created_entity.valid) then return end |
|||
add_surface(event.created_entity.force, event.created_entity.surface) |
|||
end |
|||
function on_cloned_roboport(event) |
|||
if not(event.destination and event.destination.valid) then return end |
|||
add_surface(event.destination.force, event.destination.surface) |
|||
end |
|||
function on_script_built_roboport(event) |
|||
if not(event.entity and event.entity.valid) then return end |
|||
add_surface(event.entity.force, event.entity.surface) |
|||
end |
|||
script.on_event(defines.events.on_built_entity, on_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.on_robot_built_entity, on_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.on_entity_cloned, on_cloned_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.script_raised_built, on_script_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.script_raised_revive, on_script_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
|
|||
-- Swarm safety |
|||
function on_research_finished(event) |
|||
local force = event.research.force |
|||
if event.research.name == "robot-attrition-explosion-safety" then |
|||
global.forcedata = global.forcedata or {} |
|||
global.forcedata[force.name] = global.forcedata[force.name] or {} |
|||
global.forcedata[force.name]["robot-attrition-explosion-safety"] = event.research.level - 1 |
|||
end |
|||
end |
|||
|
|||
Event.addListener(defines.events.on_research_finished, on_research_finished) |
|||
|
|||
-- standard events |
|||
Event.addListener(defines.events.on_tick, on_tick) |
|||
Event.addListener(defines.events.on_runtime_mod_setting_changed, on_runtime_mod_setting_changed) |
|||
|
|||
Event.addListener("on_init", on_init, true) |
|||
Event.addListener("on_configuration_changed", on_configuration_changed, true) |
@ -0,0 +1,6 @@ |
|||
local base_bot_speed = 0.06 |
|||
for _, bot in pairs(data.raw["logistic-robot"]) do |
|||
if bot.speed > base_bot_speed then |
|||
bot.speed = math.pow(bot.speed / base_bot_speed, 0.9) * base_bot_speed |
|||
end |
|||
end |
@ -0,0 +1,108 @@ |
|||
|
|||
if settings.startup["robot-attrition-repair"].value == "Repair75" then |
|||
local function repair_recipe_and_item(robot_prototype) |
|||
if not robot_prototype.minable and robot_prototype.minable.result then return end |
|||
|
|||
local o_item_name = robot_prototype.minable.result |
|||
local o_item = data.raw.item[o_item_name] |
|||
if not o_item then return end |
|||
|
|||
local o_recipe = data.raw.recipe[o_item_name] -- TODO: could do something smarter here |
|||
if not o_recipe then return end |
|||
|
|||
local item = table.deepcopy(o_item) |
|||
item.name = o_item.name.."-crashed" |
|||
item.place_result = nil |
|||
|
|||
item.localised_name = {"item-name.robot-attrition-crashed", {"entity-name."..robot_prototype.name}} |
|||
|
|||
local recipe_repair = table.deepcopy(o_recipe) |
|||
recipe_repair.name = o_item.name.."-repair" |
|||
recipe_repair.subgroup = o_item.subgroup or robot_prototype.subgroup |
|||
recipe_repair.order = (o_item.order or robot_prototype.order) .. "-b" |
|||
|
|||
local recipe_recombine = table.deepcopy(o_recipe) |
|||
recipe_recombine.name = o_item.name.."-recombine" |
|||
recipe_recombine.subgroup = o_item.subgroup or robot_prototype.subgroup |
|||
recipe_recombine.order = (o_item.order or robot_prototype.order) .. "-c" |
|||
|
|||
if o_item.icons then |
|||
recipe_repair.icons = table.deepcopy(o_item.icons) |
|||
recipe_recombine.icons = table.deepcopy(o_item.icons) |
|||
table.insert(item.icons, {icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25}) |
|||
table.insert(recipe_repair.icons, {icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25}) |
|||
table.insert(recipe_recombine.icons, {icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25}) |
|||
else |
|||
item.icons = { |
|||
{icon = o_item.icon, icon_size = o_item.icon_size}, |
|||
{icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25} |
|||
} |
|||
recipe_repair.icons = { |
|||
{icon = o_item.icon, icon_size = o_item.icon_size}, |
|||
{icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25} |
|||
} |
|||
recipe_recombine.icons = { |
|||
{icon = o_item.icon, icon_size = o_item.icon_size}, |
|||
{icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25} |
|||
} |
|||
end |
|||
|
|||
local function repair_recipe(set) |
|||
set.results = {{name = o_item.name, amount = 1}} |
|||
if set and set.ingredients then |
|||
local reduced = false |
|||
local last_k |
|||
for k, ingredient in pairs(set.ingredients) do |
|||
last_k = k |
|||
if ingredient[1] and ingredient[2] then |
|||
set.ingredients[k] = {name = ingredient[1], amount = ingredient[2]} |
|||
end |
|||
local original_amount = set.ingredients[k].amount or 1 |
|||
local reduce_amount = math.ceil(original_amount * 0.75) |
|||
if original_amount == reduce_amount and original_amount > 1 then |
|||
reduce_amount = original_amount - 1 |
|||
end |
|||
if reduce_amount == original_amount and original_amount == 1 then |
|||
table.insert(set.results, {name = set.ingredients[k].name, amount_min = 1, amount_max = 1, probability = 0.25}) |
|||
end |
|||
set.ingredients[k].amount = reduce_amount |
|||
end |
|||
table.insert(set.ingredients, {name = "repair-pack", amount = 1}) |
|||
table.insert(set.ingredients, {name = item.name, amount = 1}) |
|||
end |
|||
end |
|||
|
|||
for _, set in pairs({recipe_repair, recipe_repair.normal, recipe_repair.expensive}) do |
|||
repair_recipe(set) |
|||
end |
|||
|
|||
for _, set in pairs({recipe_recombine, recipe_recombine.normal, recipe_recombine.expensive}) do |
|||
set.ingredients = { |
|||
{name = "repair-pack", amount = 1}, |
|||
{name = item.name, amount = 4} |
|||
} |
|||
set.results = {{name = o_item.name, amount = 1}} |
|||
end |
|||
|
|||
recipe_repair.localised_name = {"recipe-name.robot-attrition-repair", {"entity-name."..robot_prototype.name}} |
|||
recipe_recombine.localised_name = {"recipe-name.robot-attrition-recombine", {"entity-name."..robot_prototype.name}} |
|||
|
|||
for _, technology in pairs(data.raw.technology) do |
|||
if technology.effects then |
|||
for _, effect in pairs(technology.effects) do |
|||
if effect.type == "unlock-recipe" and effect.recipe == o_recipe.name then |
|||
table.insert(technology.effects, { type = "unlock-recipe", recipe = recipe_repair.name}) |
|||
table.insert(technology.effects, { type = "unlock-recipe", recipe = recipe_recombine.name}) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
data:extend({item, recipe_repair, recipe_recombine}) |
|||
|
|||
end |
|||
|
|||
for _, prototype in pairs(data.raw["logistic-robot"]) do |
|||
repair_recipe_and_item(prototype) |
|||
end |
|||
end |
@ -0,0 +1,170 @@ |
|||
local robot_flame = table.deepcopy(data.raw.fire["fire-flame-on-tree"]) |
|||
robot_flame.name = "robot-crash-flame" |
|||
robot_flame.damage_per_tick = {amount = 10 / 60, type = "fire"} |
|||
robot_flame.fade_in_duration = 10 |
|||
robot_flame.fade_out_duration = 60 |
|||
data:extend({ |
|||
robot_flame |
|||
}) |
|||
|
|||
|
|||
|
|||
data:extend({ |
|||
{ |
|||
type = "explosion", |
|||
name = "robot-explosion", |
|||
animations = {{ |
|||
filename = "__base__/graphics/entity/medium-explosion/medium-explosion.png", |
|||
width = 112, |
|||
height = 94, |
|||
line_length = 6, |
|||
frame_count = 54, |
|||
animation_speed = 0.5, |
|||
priority = "high", |
|||
shift = { -0.56, -0.96 }, |
|||
scale = 0.75, |
|||
}}, |
|||
created_effect = { |
|||
type = "direct", |
|||
action_delivery = { |
|||
type = "instant", |
|||
target_effects = { |
|||
{ |
|||
type = "create-particle", |
|||
particle_name = "explosion-remnants-particle", |
|||
initial_height = 0.5, |
|||
initial_vertical_speed = 0.082, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { { -0.2, -0.2 }, { 0.2, 0.2 } }, |
|||
repeat_count = 3, |
|||
speed_from_center = 0.03, |
|||
speed_from_center_deviation = 0.05, |
|||
}, |
|||
{ |
|||
frame_speed = 1, |
|||
frame_speed_deviation = 0.361, |
|||
initial_height = 0.1, |
|||
initial_height_deviation = 0.5, |
|||
initial_vertical_speed = 0.04, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { |
|||
{ |
|||
-0.5, |
|||
-0.5 |
|||
}, |
|||
{ |
|||
0.5, |
|||
0.5 |
|||
} |
|||
}, |
|||
particle_name = "cable-and-electronics-particle-small-medium", |
|||
repeat_count = 13, |
|||
speed_from_center = 0.02, |
|||
speed_from_center_deviation = 0.05, |
|||
type = "create-particle" |
|||
}, |
|||
{ |
|||
frame_speed = 1, |
|||
frame_speed_deviation = 0.463, |
|||
initial_height = 1.2, |
|||
initial_height_deviation = 0.5, |
|||
initial_vertical_speed = 0.08, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { |
|||
{ |
|||
-0.6953, |
|||
-0.2969 |
|||
}, |
|||
{ |
|||
0.6953, |
|||
0.2969 |
|||
} |
|||
}, |
|||
particle_name = "logistic-robot-metal-particle-medium", |
|||
repeat_count = 10, |
|||
speed_from_center = 0.02, |
|||
speed_from_center_deviation = 0.05, |
|||
type = "create-particle" |
|||
}, |
|||
{ |
|||
initial_height = 1.4, |
|||
initial_height_deviation = 0.5, |
|||
initial_vertical_speed = 0.082, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { |
|||
{ |
|||
-0.5938, |
|||
-0.5977 |
|||
}, |
|||
{ |
|||
0.5938, |
|||
0.5977 |
|||
} |
|||
}, |
|||
particle_name = "logistic-robot-metal-particle-small", |
|||
repeat_count = 20, |
|||
speed_from_center = 0.03, |
|||
speed_from_center_deviation = 0.05, |
|||
type = "create-particle" |
|||
}, |
|||
{ type = "nested-result", action = { type = "area", radius = 0.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 40, type = "explosion" }}}}, |
|||
}}, |
|||
{ type = "nested-result", action = { type = "area", radius = 1.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 20, type = "explosion" }}}}, |
|||
}}, |
|||
{ type = "nested-result", action = { type = "area", radius = 2.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 10, type = "explosion" }}}}, |
|||
}}, |
|||
{ type = "nested-result", action = { type = "area", radius = 3.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 5, type = "explosion" }}}}, |
|||
}}, |
|||
}, |
|||
}, |
|||
}, |
|||
flags = { "not-on-map" }, |
|||
light = { color = { r = 1, g = 0.9, b = 0.8 }, intensity = 1, size = 15 }, |
|||
sound = { |
|||
aggregation = { max_count = 1, remove = true }, |
|||
variations = { |
|||
{ filename = "__base__/sound/small-explosion-1.ogg", volume = 0.4 }, |
|||
{ filename = "__base__/sound/small-explosion-2.ogg", volume = 0.4 }, |
|||
{ filename = "__base__/sound/fight/large-explosion-1.ogg", volume = 0.4 }, |
|||
{ filename = "__base__/sound/fight/large-explosion-2.ogg", volume = 0.4 } |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
type = "item-entity", |
|||
name = "robot-item-on-ground", |
|||
collision_box = { { -0.14, -0.14 }, { 0.14, 0.14 } }, |
|||
collision_mask = { "object-layer", "floor-layer", "item-layer", "water-tile" }, |
|||
flags = { "placeable-off-grid", "not-on-map" }, |
|||
minable = { mining_time = 0.025 }, |
|||
selection_box = { { -0.17, -0.17 }, { 0.17, 0.17 } }, |
|||
}, |
|||
{ |
|||
type = "technology", |
|||
name = "robot-attrition-explosion-safety", |
|||
effects = { }, |
|||
icon = "__robot_attrition__/graphics/technology/robot-safety.png", |
|||
icon_size = 128, |
|||
order = "e-g", |
|||
prerequisites = { |
|||
"logistic-system" |
|||
}, |
|||
max_level = "infinite", |
|||
unit = { |
|||
count_formula = "100*L^2", |
|||
time = 30, |
|||
ingredients = { |
|||
{ "logistic-science-pack", 1 }, |
|||
{ "utility-science-pack", 1 }, |
|||
} |
|||
}, |
|||
upgrade = true |
|||
}, |
|||
}) |
|||
|
|||
se_prodecural_tech_exclusions = se_prodecural_tech_exclusions or {} |
|||
table.insert(se_prodecural_tech_exclusions, "robot-attrition") |
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1,11 @@ |
|||
{ |
|||
"name": "robot_attrition", |
|||
"version": "0.5.10", |
|||
"title": "Robot Attrition", |
|||
"author": "Earendel", |
|||
"dependencies": [ |
|||
"base >= 1.1.0" |
|||
], |
|||
"description": "Very occasionally if you have heavy logistic bot congestion a logistic bot will crash. The crash rate is configurable (down to near-zero). A construction bot will automatically retrieve the dropped cargo, it is not lost. This means logistic bots are best used for higher value items like engines or power poles, using them for low value items like ore and copper wire is OK but less resource efficient. Bot-based item malls are totally fine. 100% bot-factories are still viable but need maybe 1% extra resources (if that). Bot-train ore unloading is viable but not ideal. Bots carrying ore from distant lands when you should be using trains is where things can become unsustainable unless you reduce the crash rate.", |
|||
"factorio_version": "1.1" |
|||
} |
@ -0,0 +1,21 @@ |
|||
FMLDOL |
|||
Factorio Mod Limited Distribution Only Licence |
|||
https://docs.google.com/document/d/1z-6hZQekEHOu1Pk4z-V5LuwlHnveFLJGTjVAtjYHwMU |
|||
This software is provided without warranty and the software author/license owner cannot be held liable for damages. |
|||
|
|||
Commercial Use: |
|||
No. |
|||
You are not allowed to make money off this mod or any of the contained assets. |
|||
You are allowed to feature the mods in other media, such as Twitch or YouTube. It would be nice if you mentioned Earendel's Patreon https://www.patreon.com/earendel when featuring the mod but this in not a requirement. |
|||
|
|||
Modification: |
|||
Restricted. |
|||
You may make alterations for your own private personal use only. |
|||
You are not allowed to distribute any content from the mod, or anything altered or derived from this mod with the following exception: |
|||
You may post partial modified sections of this mod in Earendel's discord https://discord.gg/ymjUVMv for the purpose of providing bug fixes or enhancements |
|||
|
|||
Distribution: |
|||
You cannot distribute any content of the mod separate from the complete mod package. |
|||
You can distribute the complete and unmodified mod package with the following conditions: |
|||
The mod must not be modified. (Packaging the mod into a larger zip file does not count as modification. It can be used in mod set packs.) |
|||
You must disclose the source by providing a link to the mod on the mod portal https://mods.factorio.com, a link to the Earendel's discord https://discord.gg/ymjUVMv for bug reporting and discussion, and a link to Earendel's Patreon https://www.patreon.com/earendel to support further development. |
@ -0,0 +1,11 @@ |
|||
[technology-name] |
|||
robot-attrition-explosion-safety=Bezpečnost roje |
|||
|
|||
[technology-description] |
|||
robot-attrition-explosion-safety=Logistické sítě s rozsahem menším než 500 aktivních logistických robotů na jednu vyzkoumanou úroveň nebudou při havárii robotů působit poškození jiným objektům. |
|||
|
|||
[mod-setting-name] |
|||
robot-attrition-factor=Faktor kolizí robotů |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=Násobič šance na havárii robotů. Poznámka: Jiné modifikace mohou měnit nebo přepisovat tuto hodnotu pro různé povrchy. |
@ -0,0 +1,24 @@ |
|||
[technology-name] |
|||
robot-attrition-explosion-safety=Swarm safety |
|||
|
|||
[technology-description] |
|||
robot-attrition-explosion-safety=Logistic bots won't damage things when they crash if they are in a logistic network with up to 500 active logistic bots per researched level. |
|||
|
|||
[item-name] |
|||
robot-attrition-crashed=Crashed __1__ |
|||
|
|||
[recipe-name] |
|||
robot-attrition-repair=Repair __1__ |
|||
robot-attrition-recombine=Recombine __1__ |
|||
|
|||
[mod-setting-name] |
|||
robot-attrition-factor=Robot Attrition Factor |
|||
robot-attrition-repair=Robot repair |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=A multiplier on the robot chance to crash. Note: Other mods can modify or override this value for specific surfaces. |
|||
robot-attrition-repair=Robot repair options. |
|||
|
|||
[string-mod-setting] |
|||
robot-attrition-repair-Disabed=Disabled |
|||
robot-attrition-repair-Repair75=Repair 75% cost (estimate) |
@ -0,0 +1,5 @@ |
|||
[mod-setting-name] |
|||
robot-attrition-factor=Współczynnik awaryjności robota |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=Mnożnik szansy na awarię robota. Uwaga: Inne mody mogą modyfikować lub zastępować tę wartość dla określonych powierzchni. |
@ -0,0 +1,24 @@ |
|||
[technology-name] |
|||
robot-attrition-explosion-safety=Безопасность роя |
|||
|
|||
[technology-description] |
|||
robot-attrition-explosion-safety=Логистические дроны не повреждают объекты при крушении, если они находятся в логистической сети с не более 500 дронов на 1 уровень исследования. |
|||
|
|||
[item-name] |
|||
robot-attrition-crashed=Упавший __1__ |
|||
|
|||
[recipe-name] |
|||
robot-attrition-repair=Ремонтировать __1__ |
|||
robot-attrition-recombine=Пересобрать __1__ |
|||
|
|||
[mod-setting-name] |
|||
robot-attrition-factor=Фактор износа дронов |
|||
robot-attrition-repair=Ремонт дронов |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=Множитель шанса крушения дрона. Примечание: другие моды могут изменять или переопределять это значение для нужных поверхностей. |
|||
robot-attrition-repair=Параметры ремонта дронов. |
|||
|
|||
[string-mod-setting] |
|||
robot-attrition-repair-Disabed=Отключено |
|||
robot-attrition-repair-Repair75=Затраты на ремонт 75% (примерно) |
@ -0,0 +1,5 @@ |
|||
[mod-setting-name] |
|||
robot-attrition-factor=机器人故障系数 |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=机器人产生故障的几率乘数。说明: 其他Mod可以修改这个值。 |
@ -0,0 +1,51 @@ |
|||
Event = { listeners = {} } |
|||
|
|||
-- can add multiple listeners to the same event. |
|||
-- event_key can be a uint of native events (defines.events) |
|||
-- event_key can be a string for custom input of virtual events |
|||
-- if a virtual event is added, set virtual = true |
|||
-- on_init, on_load, on_configuration_changed get triggered automatically as virtual events |
|||
Event.addListener = function(event_key, add_callback, virtual) |
|||
if not Event.listeners[event_key] then |
|||
Event.listeners[event_key] = {} |
|||
Event.listeners[event_key].callbacks = {} |
|||
Event.listeners[event_key].sequence = function (event) |
|||
for _, callback in pairs(Event.listeners[event_key].callbacks) do |
|||
callback(event) |
|||
end |
|||
end |
|||
if not virtual then -- custom input eventsm only works after on_init |
|||
script.on_event(event_key, Event.listeners[event_key].sequence) |
|||
end |
|||
table.insert(Event.listeners[event_key].callbacks, add_callback) |
|||
else |
|||
for _, callback in pairs(Event.listeners[event_key].callbacks) do |
|||
if callback == add_callback then return end |
|||
end |
|||
if not exists then |
|||
table.insert(Event.listeners[event_key].callbacks, add_callback) |
|||
end |
|||
end |
|||
end |
|||
|
|||
-- can add multiple listneers to the same event. |
|||
Event.removeListener = function(event_key, remove_callback) |
|||
if not Event.listeners[event_key] then return end |
|||
for _, callback in pairs(Event.listeners[event_key].callbacks) do |
|||
if callback == remove_callback then |
|||
Event.listeners[event_key].callbacks[_] = nil |
|||
end |
|||
end |
|||
end |
|||
|
|||
Event.trigger = function(event_key, event_data) |
|||
if Event.listeners[event_key] then |
|||
Event.listeners[event_key].sequence(event_data) |
|||
end |
|||
end |
|||
|
|||
script.on_init(function(event) Event.trigger("on_init", event) end) |
|||
script.on_load(function(event) Event.trigger("on_load", event) end) |
|||
script.on_configuration_changed(function(event) Event.trigger("on_configuration_changed", event) end) |
|||
|
|||
return Event |
@ -0,0 +1,19 @@ |
|||
data:extend{ |
|||
{ |
|||
type = "double-setting", |
|||
name = "robot-attrition-factor", |
|||
setting_type = "runtime-global", |
|||
default_value = 1, |
|||
minimum_value = 0.001, |
|||
maximum_value = 1000, |
|||
order = "a", |
|||
}, |
|||
{ |
|||
type = "string-setting", |
|||
name = "robot-attrition-repair", |
|||
setting_type = "startup", |
|||
default_value = "Disabled", |
|||
allowed_values = {"Disabled", "Repair75"}, |
|||
order = "b", |
|||
}, |
|||
} |
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,6 @@ |
|||
# robot-attrition |
|||
Robot Attrition |
|||
|
|||
This is **NOT** an open source project, please check the licence file. |
|||
|
|||
If you would like to contribute please contact Earendel on Discord first: https://discord.gg/ymjUVMv |
@ -0,0 +1,134 @@ |
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.10 |
|||
Date: 14. 05. 2021 |
|||
Locale: |
|||
- Added Russian translation thanks to Shadow_Man. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.9 |
|||
Date: 29. 01. 2021 |
|||
Bugfixes: |
|||
- Fix crash if a bot became invalid during the processing loop. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.8 |
|||
Date: 18. 01. 2021 |
|||
Bugfixes: |
|||
- Fix that crashed robots could be deployed as working robots. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.7 |
|||
Date: 13. 12. 2020 |
|||
Bugfixes: |
|||
- Fix for layered robot icons and the repair recipes. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.6 |
|||
Date: 13. 12. 2020 |
|||
Changes: |
|||
- Updated repair recipe to have % secondary products if not all of 1 ingredient is needed. |
|||
- Added 2nd restoration recipe for robot recombination. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.5 |
|||
Date: 07. 12. 2020 |
|||
Compatibility: |
|||
- Creative mod test bots don't cause a crash during loading. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.3 |
|||
Date: 07. 12. 2020 |
|||
Bugfixes: |
|||
- Fixed problem with robot repair activating. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.2 |
|||
Date: 04. 12. 2020 |
|||
Changes: |
|||
- Added option for robot repair. |
|||
|
|||
Bugfixes: |
|||
- Fixed swarm safety levels not being applied correctly. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.5.1 |
|||
Date: 24. 11. 2020 |
|||
Info: |
|||
- Updated for Factorio 1.1. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.5 |
|||
Date: 22. 11. 2020 |
|||
Changes: |
|||
- UPS improvement for games with lots of surfaces (400x faster in some cases). |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.4 |
|||
Date: 24. 07. 2020 |
|||
Changes: |
|||
- Added explosion reduction technology for increasing logistic swarm sizes (500 per level). |
|||
- Uses a faster method to drop items to the ground (thanks to Mylon). |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.3 |
|||
Date: 31. 05. 2020 |
|||
Locale: |
|||
- Added chinese translation thanks to Frost. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.2 |
|||
Date: 07. 02. 2020 |
|||
Info: |
|||
- Updated for Factorio 0.18.4. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.4.1 |
|||
Date: 27. 01. 2020 |
|||
Info: |
|||
- Updated for Factorio 0.18. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.8 |
|||
Changes: |
|||
- Code optimizations. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.7 |
|||
Changes: |
|||
- Fixed remote interface call. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.6 |
|||
Changes: |
|||
- Attrition can now be altered per-surface by mods, this can multiply or override the mod setting. |
|||
- Surfaces with attrition rates of 0.001 and below do not process attrition at all (saves UPS). |
|||
- Further UPS optimisations. |
|||
- Fixed bots dropping items on belts. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.5 |
|||
Changes: |
|||
- Code optimizations. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.4 |
|||
Changes: |
|||
- Updated description. |
|||
- Minimum attrition multiplier is now 0.001. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.3 |
|||
Changes: |
|||
- Re-worked the code for continuous processing instead of batches on longer interval. (Reduces UPS stutters). |
|||
- Default attrition factor is now 1 instead of 10 to match the new code structure (actual crash rate is slightly lower). |
|||
- Minimum attrition multiplier is now 0.01. |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.2 |
|||
Changes: |
|||
- Changed robots creating fire on death to robots doing weak AOE explosion damage (fire did not make sense in space). |
|||
|
|||
--------------------------------------------------------------------------------------------------- |
|||
Version: 0.3.1 |
|||
Info: |
|||
- Updated for Factorio 0.17. |
@ -0,0 +1,271 @@ |
|||
Event = require('scripts/event') |
|||
|
|||
min_attrition_rate = 0.0011 |
|||
tickskip = 10 |
|||
|
|||
function is_system_force(force_name) |
|||
return force_name == "enemy" |
|||
or force_name == "neutral" |
|||
or force_name == "capture" |
|||
or force_name == "conquest" |
|||
or force_name == "ignore" |
|||
or force_name == "friendly" |
|||
end |
|||
|
|||
function get_attrition_rate_for_surface(surface_index) |
|||
-- use cache |
|||
if global.suface_attrition_rates[surface_index] then |
|||
return global.suface_attrition_rates[surface_index] |
|||
end |
|||
-- or load |
|||
local rate = nil |
|||
local default_rate = settings.global["robot-attrition-factor"].value |
|||
for interface, functions in pairs(remote.interfaces) do |
|||
if functions["robot_attrition_for_surface"] then |
|||
local returned_rate = remote.call(interface, "robot_attrition_for_surface", {default_rate = default_rate, surface_index = surface_index}) |
|||
if rate == nil or returned_rate > rate then |
|||
rate = returned_rate |
|||
end |
|||
end |
|||
end |
|||
if rate == nil then |
|||
rate = default_rate |
|||
end |
|||
global.suface_attrition_rates[surface_index] = rate |
|||
--game.print("Robot attrition rate for surface " .. surface_index .. " ("..game.surfaces[surface_index].name..") is " .. rate) |
|||
|
|||
return rate |
|||
end |
|||
|
|||
function get_crash_item(bot) |
|||
if global.crash_items[bot.name] then |
|||
if global.crash_items[bot.name] ~= "none" then |
|||
return global.crash_items[bot.name] |
|||
else |
|||
return nil |
|||
end |
|||
else |
|||
if bot.prototype.mineable_properties.products and bot.prototype.mineable_properties.products[1] then |
|||
local name = bot.prototype.mineable_properties.products[1].name.."-crashed" |
|||
if game.item_prototypes[name] then |
|||
global.crash_items[bot.name] = name |
|||
return name |
|||
end |
|||
end |
|||
end |
|||
global.crash_items[bot.name] = "none" |
|||
end |
|||
|
|||
function get_bot_speed(name) |
|||
if not global.bot_speed then global.bot_speed = {} end |
|||
if not global.bot_speed[name] then |
|||
global.bot_speed[name] = game.entity_prototypes[name].speed |
|||
end |
|||
return global.bot_speed[name] |
|||
end |
|||
|
|||
function get_bot_slow_speed_multiplier(name) |
|||
if not global.bot_slow_speed_multiplier then global.bot_slow_speed_multiplier = {} end |
|||
if not global.bot_slow_speed_multiplier[name] then |
|||
global.bot_slow_speed_multiplier[name] = game.entity_prototypes[name].speed_multiplier_when_out_of_energy |
|||
end |
|||
return global.bot_slow_speed_multiplier[name] |
|||
end |
|||
|
|||
function bot_crash(bot, n_bots) |
|||
|
|||
local inventory = bot.get_inventory(defines.inventory.robot_cargo) |
|||
local contents = inventory.get_contents() |
|||
if global.robot_repair_setting == "Repair75" then |
|||
local item = get_crash_item(bot) |
|||
if item then |
|||
bot.surface.spill_item_stack(bot.position, {name=item, count=1}, false, bot.force, false) --Spill, mark for decon, disallow belts |
|||
end |
|||
end |
|||
for name, count in pairs(contents) do |
|||
bot.surface.spill_item_stack(bot.position, {name=name, count=count}, false, bot.force, false) --Spill, mark for decon, disallow belts |
|||
end |
|||
bot.get_inventory(defines.inventory.robot_cargo).clear() |
|||
bot.force.kill_count_statistics.on_flow(bot.name, -1) --Track bot's death. |
|||
if global.forcedata and global.forcedata[bot.force.name] and global.forcedata[bot.force.name]["robot-attrition-explosion-safety"] |
|||
and n_bots <= 500 * global.forcedata[bot.force.name]["robot-attrition-explosion-safety"] then |
|||
--game.print("Skip explosion, n_bots "..n_bots.."<= ".. 500 * global.forcedata[bot.force.name]["robot-attrition-explosion-safety"]) |
|||
else |
|||
bot.surface.create_entity{name = "robot-explosion", position=bot.position} |
|||
end |
|||
if bot.valid then |
|||
bot.destroy() |
|||
end |
|||
global.bots_crashed = (global.bots_crashed or 0) + 1 -- used as an achievement metric |
|||
|
|||
end |
|||
|
|||
function process_bot(bot, n_bots) |
|||
local force_speed_multiplier = 1 + bot.force.worker_robots_speed_modifier |
|||
local speed = get_bot_speed(bot.name) * force_speed_multiplier |
|||
local held_item_count = 0 |
|||
if bot.energy > 0 then |
|||
local inventory = bot.get_inventory(defines.inventory.robot_cargo) |
|||
held_item_count = inventory.get_item_count() |
|||
else |
|||
speed = 0.5 * speed * get_bot_slow_speed_multiplier(bot.name) |
|||
end |
|||
local speed_items = speed * (held_item_count + 0.5) -- carrying itself counts as 0.5 items |
|||
local crash_score = speed_items |
|||
bot_crash(bot, n_bots) |
|||
return crash_score |
|||
end |
|||
|
|||
function on_tick(event) |
|||
--[[ |
|||
slowest funtions is by far: network.logistic_robots[i] |
|||
so only do that once per explosion. |
|||
which means that if a robot is selected it must die. |
|||
but risk factors should still be speed * items carried |
|||
so add these factors to the probability of the next selection round |
|||
factors apply multiplier to next selection phase |
|||
]]-- |
|||
if not global.force_surfaces then return end |
|||
if game.tick % tickskip ~= 0 then return end |
|||
|
|||
--game.forces[force].logistic_networks[network].logistic_robots :: array of LuaEntity |
|||
--for _, force in pairs(game.forces) do |
|||
for force_name, force_surfaces in pairs(global.force_surfaces) do |
|||
local force = game.forces[force_name] |
|||
if not force then |
|||
global.force_surfaces[force_name] = nil |
|||
else |
|||
local i = randint |
|||
--for surface_name, networks in pairs(force.logistic_networks) do |
|||
local force_logistic_networks = force.logistic_networks -- array of surface_name, networks |
|||
for surface_name, _ in pairs(force_surfaces) do |
|||
local surface = game.surfaces[surface_name] |
|||
if not surface then |
|||
force_surfaces[surface_name] = nil |
|||
else |
|||
local networks = force_logistic_networks[surface_name] |
|||
if networks then |
|||
local surface_attrition_rate = get_attrition_rate_for_surface(game.surfaces[surface_name].index) |
|||
if surface_attrition_rate > min_attrition_rate then |
|||
for _, network in pairs(networks) do |
|||
local n_bots = network.all_logistic_robots - network.available_logistic_robots |
|||
if n_bots > 50 then -- ignore small networks |
|||
if not global.forces[force.name] then global.forces[force.name] = {} end |
|||
if not global.forces[force.name][surface_name] then global.forces[force.name][surface_name] = { crash = 0, crash_rate = 0.1 } end |
|||
local crash_rate = global.forces[force.name][surface_name].crash_rate * tickskip * surface_attrition_rate / 1000000 |
|||
local crash = global.forces[force.name][surface_name].crash + crash_rate * n_bots |
|||
if crash >= 1 then |
|||
local logistic_robots = network.logistic_robots |
|||
local to_crash = math.min(math.ceil(#logistic_robots/2), 1 + math.random(math.floor(crash))) -- don't crash all |
|||
local i = math.random(#logistic_robots) -- choose a starting bot |
|||
local crashed = 0 |
|||
while crashed < to_crash do |
|||
-- then step through bots |
|||
i = (i % #logistic_robots) + 1 |
|||
if logistic_robots[i] and logistic_robots[i].valid then |
|||
global.forces[force.name][surface_name].crash_rate = global.forces[force.name][surface_name].crash_rate * 0.9 + 0.1 * process_bot(logistic_robots[i], n_bots) |
|||
end -- if invalid bots were found just skip them anyway |
|||
crashed = crashed + 1 |
|||
end |
|||
crash = crash - crashed |
|||
end |
|||
global.forces[force.name][surface_name].crash = crash |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
function on_init(event) |
|||
global.forces = {} |
|||
global.bot_speed = {} |
|||
global.bot_slow_speed_multiplier = {} |
|||
global.suface_attrition_rates = {} |
|||
|
|||
global.robot_repair_setting = settings.startup["robot-attrition-repair"].value |
|||
global.crash_items = {} |
|||
end |
|||
|
|||
function on_configuration_changed(event) |
|||
global.forces = {} |
|||
global.bot_speed = {} |
|||
global.bot_slow_speed_multiplier = {} |
|||
global.suface_attrition_rates = {} -- clear |
|||
if not global.force_surfaces then |
|||
for _, force in pairs(game.forces) do |
|||
if not is_system_force(force.name) then |
|||
for surface_name, networks in pairs(force.logistic_networks) do |
|||
for _, network in pairs(networks) do |
|||
if network.all_logistic_robots > 0 then |
|||
add_surface(force, game.surfaces[surface_name]) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
global.robot_repair_setting = settings.startup["robot-attrition-repair"].value |
|||
global.crash_items = {} |
|||
|
|||
end |
|||
function on_runtime_mod_setting_changed(event) |
|||
if event.setting == "robot-attrition-factor" then |
|||
global.suface_attrition_rates = {} -- clear |
|||
end |
|||
end |
|||
|
|||
|
|||
-- Surface Gathering |
|||
function add_surface(force, surface) |
|||
if not is_system_force(force.name) then |
|||
if #force.players > 0 then |
|||
global.force_surfaces = global.force_surfaces or {} |
|||
global.force_surfaces[force.name] = global.force_surfaces[force.name] or {} |
|||
if not global.force_surfaces[force.name][surface.name] then |
|||
global.force_surfaces[force.name][surface.name] = game.tick |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
function on_built_roboport(event) |
|||
if not(event.created_entity and event.created_entity.valid) then return end |
|||
add_surface(event.created_entity.force, event.created_entity.surface) |
|||
end |
|||
function on_cloned_roboport(event) |
|||
if not(event.destination and event.destination.valid) then return end |
|||
add_surface(event.destination.force, event.destination.surface) |
|||
end |
|||
function on_script_built_roboport(event) |
|||
if not(event.entity and event.entity.valid) then return end |
|||
add_surface(event.entity.force, event.entity.surface) |
|||
end |
|||
script.on_event(defines.events.on_built_entity, on_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.on_robot_built_entity, on_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.on_entity_cloned, on_cloned_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.script_raised_built, on_script_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
script.on_event(defines.events.script_raised_revive, on_script_built_roboport, {{filter = "type", type = "roboport"}}) |
|||
|
|||
-- Swarm safety |
|||
function on_research_finished(event) |
|||
local force = event.research.force |
|||
if event.research.name == "robot-attrition-explosion-safety" then |
|||
global.forcedata = global.forcedata or {} |
|||
global.forcedata[force.name] = global.forcedata[force.name] or {} |
|||
global.forcedata[force.name]["robot-attrition-explosion-safety"] = event.research.level - 1 |
|||
end |
|||
end |
|||
|
|||
Event.addListener(defines.events.on_research_finished, on_research_finished) |
|||
|
|||
-- standard events |
|||
Event.addListener(defines.events.on_tick, on_tick) |
|||
Event.addListener(defines.events.on_runtime_mod_setting_changed, on_runtime_mod_setting_changed) |
|||
|
|||
Event.addListener("on_init", on_init, true) |
|||
Event.addListener("on_configuration_changed", on_configuration_changed, true) |
@ -0,0 +1,6 @@ |
|||
local base_bot_speed = 0.06 |
|||
for _, bot in pairs(data.raw["logistic-robot"]) do |
|||
if bot.speed > base_bot_speed then |
|||
bot.speed = math.pow(bot.speed / base_bot_speed, 0.9) * base_bot_speed |
|||
end |
|||
end |
@ -0,0 +1,108 @@ |
|||
|
|||
if settings.startup["robot-attrition-repair"].value == "Repair75" then |
|||
local function repair_recipe_and_item(robot_prototype) |
|||
if not robot_prototype.minable and robot_prototype.minable.result then return end |
|||
|
|||
local o_item_name = robot_prototype.minable.result |
|||
local o_item = data.raw.item[o_item_name] |
|||
if not o_item then return end |
|||
|
|||
local o_recipe = data.raw.recipe[o_item_name] -- TODO: could do something smarter here |
|||
if not o_recipe then return end |
|||
|
|||
local item = table.deepcopy(o_item) |
|||
item.name = o_item.name.."-crashed" |
|||
item.place_result = nil |
|||
|
|||
item.localised_name = {"item-name.robot-attrition-crashed", {"entity-name."..robot_prototype.name}} |
|||
|
|||
local recipe_repair = table.deepcopy(o_recipe) |
|||
recipe_repair.name = o_item.name.."-repair" |
|||
recipe_repair.subgroup = o_item.subgroup or robot_prototype.subgroup |
|||
recipe_repair.order = (o_item.order or robot_prototype.order) .. "-b" |
|||
|
|||
local recipe_recombine = table.deepcopy(o_recipe) |
|||
recipe_recombine.name = o_item.name.."-recombine" |
|||
recipe_recombine.subgroup = o_item.subgroup or robot_prototype.subgroup |
|||
recipe_recombine.order = (o_item.order or robot_prototype.order) .. "-c" |
|||
|
|||
if o_item.icons then |
|||
recipe_repair.icons = table.deepcopy(o_item.icons) |
|||
recipe_recombine.icons = table.deepcopy(o_item.icons) |
|||
table.insert(item.icons, {icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25}) |
|||
table.insert(recipe_repair.icons, {icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25}) |
|||
table.insert(recipe_recombine.icons, {icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25}) |
|||
else |
|||
item.icons = { |
|||
{icon = o_item.icon, icon_size = o_item.icon_size}, |
|||
{icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25} |
|||
} |
|||
recipe_repair.icons = { |
|||
{icon = o_item.icon, icon_size = o_item.icon_size}, |
|||
{icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25} |
|||
} |
|||
recipe_recombine.icons = { |
|||
{icon = o_item.icon, icon_size = o_item.icon_size}, |
|||
{icon="__core__/graphics/icons/alerts/destroyed-icon.png", icon_size = 64, scale = 0.25} |
|||
} |
|||
end |
|||
|
|||
local function repair_recipe(set) |
|||
set.results = {{name = o_item.name, amount = 1}} |
|||
if set and set.ingredients then |
|||
local reduced = false |
|||
local last_k |
|||
for k, ingredient in pairs(set.ingredients) do |
|||
last_k = k |
|||
if ingredient[1] and ingredient[2] then |
|||
set.ingredients[k] = {name = ingredient[1], amount = ingredient[2]} |
|||
end |
|||
local original_amount = set.ingredients[k].amount or 1 |
|||
local reduce_amount = math.ceil(original_amount * 0.75) |
|||
if original_amount == reduce_amount and original_amount > 1 then |
|||
reduce_amount = original_amount - 1 |
|||
end |
|||
if reduce_amount == original_amount and original_amount == 1 then |
|||
table.insert(set.results, {name = set.ingredients[k].name, amount_min = 1, amount_max = 1, probability = 0.25}) |
|||
end |
|||
set.ingredients[k].amount = reduce_amount |
|||
end |
|||
table.insert(set.ingredients, {name = "repair-pack", amount = 1}) |
|||
table.insert(set.ingredients, {name = item.name, amount = 1}) |
|||
end |
|||
end |
|||
|
|||
for _, set in pairs({recipe_repair, recipe_repair.normal, recipe_repair.expensive}) do |
|||
repair_recipe(set) |
|||
end |
|||
|
|||
for _, set in pairs({recipe_recombine, recipe_recombine.normal, recipe_recombine.expensive}) do |
|||
set.ingredients = { |
|||
{name = "repair-pack", amount = 1}, |
|||
{name = item.name, amount = 4} |
|||
} |
|||
set.results = {{name = o_item.name, amount = 1}} |
|||
end |
|||
|
|||
recipe_repair.localised_name = {"recipe-name.robot-attrition-repair", {"entity-name."..robot_prototype.name}} |
|||
recipe_recombine.localised_name = {"recipe-name.robot-attrition-recombine", {"entity-name."..robot_prototype.name}} |
|||
|
|||
for _, technology in pairs(data.raw.technology) do |
|||
if technology.effects then |
|||
for _, effect in pairs(technology.effects) do |
|||
if effect.type == "unlock-recipe" and effect.recipe == o_recipe.name then |
|||
table.insert(technology.effects, { type = "unlock-recipe", recipe = recipe_repair.name}) |
|||
table.insert(technology.effects, { type = "unlock-recipe", recipe = recipe_recombine.name}) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
|
|||
data:extend({item, recipe_repair, recipe_recombine}) |
|||
|
|||
end |
|||
|
|||
for _, prototype in pairs(data.raw["logistic-robot"]) do |
|||
repair_recipe_and_item(prototype) |
|||
end |
|||
end |
@ -0,0 +1,170 @@ |
|||
local robot_flame = table.deepcopy(data.raw.fire["fire-flame-on-tree"]) |
|||
robot_flame.name = "robot-crash-flame" |
|||
robot_flame.damage_per_tick = {amount = 10 / 60, type = "fire"} |
|||
robot_flame.fade_in_duration = 10 |
|||
robot_flame.fade_out_duration = 60 |
|||
data:extend({ |
|||
robot_flame |
|||
}) |
|||
|
|||
|
|||
|
|||
data:extend({ |
|||
{ |
|||
type = "explosion", |
|||
name = "robot-explosion", |
|||
animations = {{ |
|||
filename = "__base__/graphics/entity/medium-explosion/medium-explosion.png", |
|||
width = 112, |
|||
height = 94, |
|||
line_length = 6, |
|||
frame_count = 54, |
|||
animation_speed = 0.5, |
|||
priority = "high", |
|||
shift = { -0.56, -0.96 }, |
|||
scale = 0.75, |
|||
}}, |
|||
created_effect = { |
|||
type = "direct", |
|||
action_delivery = { |
|||
type = "instant", |
|||
target_effects = { |
|||
{ |
|||
type = "create-particle", |
|||
particle_name = "explosion-remnants-particle", |
|||
initial_height = 0.5, |
|||
initial_vertical_speed = 0.082, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { { -0.2, -0.2 }, { 0.2, 0.2 } }, |
|||
repeat_count = 3, |
|||
speed_from_center = 0.03, |
|||
speed_from_center_deviation = 0.05, |
|||
}, |
|||
{ |
|||
frame_speed = 1, |
|||
frame_speed_deviation = 0.361, |
|||
initial_height = 0.1, |
|||
initial_height_deviation = 0.5, |
|||
initial_vertical_speed = 0.04, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { |
|||
{ |
|||
-0.5, |
|||
-0.5 |
|||
}, |
|||
{ |
|||
0.5, |
|||
0.5 |
|||
} |
|||
}, |
|||
particle_name = "cable-and-electronics-particle-small-medium", |
|||
repeat_count = 13, |
|||
speed_from_center = 0.02, |
|||
speed_from_center_deviation = 0.05, |
|||
type = "create-particle" |
|||
}, |
|||
{ |
|||
frame_speed = 1, |
|||
frame_speed_deviation = 0.463, |
|||
initial_height = 1.2, |
|||
initial_height_deviation = 0.5, |
|||
initial_vertical_speed = 0.08, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { |
|||
{ |
|||
-0.6953, |
|||
-0.2969 |
|||
}, |
|||
{ |
|||
0.6953, |
|||
0.2969 |
|||
} |
|||
}, |
|||
particle_name = "logistic-robot-metal-particle-medium", |
|||
repeat_count = 10, |
|||
speed_from_center = 0.02, |
|||
speed_from_center_deviation = 0.05, |
|||
type = "create-particle" |
|||
}, |
|||
{ |
|||
initial_height = 1.4, |
|||
initial_height_deviation = 0.5, |
|||
initial_vertical_speed = 0.082, |
|||
initial_vertical_speed_deviation = 0.05, |
|||
offset_deviation = { |
|||
{ |
|||
-0.5938, |
|||
-0.5977 |
|||
}, |
|||
{ |
|||
0.5938, |
|||
0.5977 |
|||
} |
|||
}, |
|||
particle_name = "logistic-robot-metal-particle-small", |
|||
repeat_count = 20, |
|||
speed_from_center = 0.03, |
|||
speed_from_center_deviation = 0.05, |
|||
type = "create-particle" |
|||
}, |
|||
{ type = "nested-result", action = { type = "area", radius = 0.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 40, type = "explosion" }}}}, |
|||
}}, |
|||
{ type = "nested-result", action = { type = "area", radius = 1.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 20, type = "explosion" }}}}, |
|||
}}, |
|||
{ type = "nested-result", action = { type = "area", radius = 2.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 10, type = "explosion" }}}}, |
|||
}}, |
|||
{ type = "nested-result", action = { type = "area", radius = 3.5, |
|||
action_delivery = { type = "instant", target_effects = { { type = "damage", damage = { amount = 5, type = "explosion" }}}}, |
|||
}}, |
|||
}, |
|||
}, |
|||
}, |
|||
flags = { "not-on-map" }, |
|||
light = { color = { r = 1, g = 0.9, b = 0.8 }, intensity = 1, size = 15 }, |
|||
sound = { |
|||
aggregation = { max_count = 1, remove = true }, |
|||
variations = { |
|||
{ filename = "__base__/sound/small-explosion-1.ogg", volume = 0.4 }, |
|||
{ filename = "__base__/sound/small-explosion-2.ogg", volume = 0.4 }, |
|||
{ filename = "__base__/sound/fight/large-explosion-1.ogg", volume = 0.4 }, |
|||
{ filename = "__base__/sound/fight/large-explosion-2.ogg", volume = 0.4 } |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
type = "item-entity", |
|||
name = "robot-item-on-ground", |
|||
collision_box = { { -0.14, -0.14 }, { 0.14, 0.14 } }, |
|||
collision_mask = { "object-layer", "floor-layer", "item-layer", "water-tile" }, |
|||
flags = { "placeable-off-grid", "not-on-map" }, |
|||
minable = { mining_time = 0.025 }, |
|||
selection_box = { { -0.17, -0.17 }, { 0.17, 0.17 } }, |
|||
}, |
|||
{ |
|||
type = "technology", |
|||
name = "robot-attrition-explosion-safety", |
|||
effects = { }, |
|||
icon = "__robot_attrition__/graphics/technology/robot-safety.png", |
|||
icon_size = 128, |
|||
order = "e-g", |
|||
prerequisites = { |
|||
"logistic-system" |
|||
}, |
|||
max_level = "infinite", |
|||
unit = { |
|||
count_formula = "100*L^2", |
|||
time = 30, |
|||
ingredients = { |
|||
{ "logistic-science-pack", 1 }, |
|||
{ "utility-science-pack", 1 }, |
|||
} |
|||
}, |
|||
upgrade = true |
|||
}, |
|||
}) |
|||
|
|||
se_prodecural_tech_exclusions = se_prodecural_tech_exclusions or {} |
|||
table.insert(se_prodecural_tech_exclusions, "robot-attrition") |
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1,11 @@ |
|||
{ |
|||
"name": "robot_attrition", |
|||
"version": "0.5.10", |
|||
"title": "Robot Attrition", |
|||
"author": "Earendel", |
|||
"dependencies": [ |
|||
"base >= 1.1.0" |
|||
], |
|||
"description": "Very occasionally if you have heavy logistic bot congestion a logistic bot will crash. The crash rate is configurable (down to near-zero). A construction bot will automatically retrieve the dropped cargo, it is not lost. This means logistic bots are best used for higher value items like engines or power poles, using them for low value items like ore and copper wire is OK but less resource efficient. Bot-based item malls are totally fine. 100% bot-factories are still viable but need maybe 1% extra resources (if that). Bot-train ore unloading is viable but not ideal. Bots carrying ore from distant lands when you should be using trains is where things can become unsustainable unless you reduce the crash rate.", |
|||
"factorio_version": "1.1" |
|||
} |
@ -0,0 +1,21 @@ |
|||
FMLDOL |
|||
Factorio Mod Limited Distribution Only Licence |
|||
https://docs.google.com/document/d/1z-6hZQekEHOu1Pk4z-V5LuwlHnveFLJGTjVAtjYHwMU |
|||
This software is provided without warranty and the software author/license owner cannot be held liable for damages. |
|||
|
|||
Commercial Use: |
|||
No. |
|||
You are not allowed to make money off this mod or any of the contained assets. |
|||
You are allowed to feature the mods in other media, such as Twitch or YouTube. It would be nice if you mentioned Earendel's Patreon https://www.patreon.com/earendel when featuring the mod but this in not a requirement. |
|||
|
|||
Modification: |
|||
Restricted. |
|||
You may make alterations for your own private personal use only. |
|||
You are not allowed to distribute any content from the mod, or anything altered or derived from this mod with the following exception: |
|||
You may post partial modified sections of this mod in Earendel's discord https://discord.gg/ymjUVMv for the purpose of providing bug fixes or enhancements |
|||
|
|||
Distribution: |
|||
You cannot distribute any content of the mod separate from the complete mod package. |
|||
You can distribute the complete and unmodified mod package with the following conditions: |
|||
The mod must not be modified. (Packaging the mod into a larger zip file does not count as modification. It can be used in mod set packs.) |
|||
You must disclose the source by providing a link to the mod on the mod portal https://mods.factorio.com, a link to the Earendel's discord https://discord.gg/ymjUVMv for bug reporting and discussion, and a link to Earendel's Patreon https://www.patreon.com/earendel to support further development. |
@ -0,0 +1,11 @@ |
|||
[technology-name] |
|||
robot-attrition-explosion-safety=Bezpečnost roje |
|||
|
|||
[technology-description] |
|||
robot-attrition-explosion-safety=Logistické sítě s rozsahem menším než 500 aktivních logistických robotů na jednu vyzkoumanou úroveň nebudou při havárii robotů působit poškození jiným objektům. |
|||
|
|||
[mod-setting-name] |
|||
robot-attrition-factor=Faktor kolizí robotů |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=Násobič šance na havárii robotů. Poznámka: Jiné modifikace mohou měnit nebo přepisovat tuto hodnotu pro různé povrchy. |
@ -0,0 +1,24 @@ |
|||
[technology-name] |
|||
robot-attrition-explosion-safety=Swarm safety |
|||
|
|||
[technology-description] |
|||
robot-attrition-explosion-safety=Logistic bots won't damage things when they crash if they are in a logistic network with up to 500 active logistic bots per researched level. |
|||
|
|||
[item-name] |
|||
robot-attrition-crashed=Crashed __1__ |
|||
|
|||
[recipe-name] |
|||
robot-attrition-repair=Repair __1__ |
|||
robot-attrition-recombine=Recombine __1__ |
|||
|
|||
[mod-setting-name] |
|||
robot-attrition-factor=Robot Attrition Factor |
|||
robot-attrition-repair=Robot repair |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=A multiplier on the robot chance to crash. Note: Other mods can modify or override this value for specific surfaces. |
|||
robot-attrition-repair=Robot repair options. |
|||
|
|||
[string-mod-setting] |
|||
robot-attrition-repair-Disabed=Disabled |
|||
robot-attrition-repair-Repair75=Repair 75% cost (estimate) |
@ -0,0 +1,5 @@ |
|||
[mod-setting-name] |
|||
robot-attrition-factor=Współczynnik awaryjności robota |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=Mnożnik szansy na awarię robota. Uwaga: Inne mody mogą modyfikować lub zastępować tę wartość dla określonych powierzchni. |
@ -0,0 +1,24 @@ |
|||
[technology-name] |
|||
robot-attrition-explosion-safety=Безопасность роя |
|||
|
|||
[technology-description] |
|||
robot-attrition-explosion-safety=Логистические дроны не повреждают объекты при крушении, если они находятся в логистической сети с не более 500 дронов на 1 уровень исследования. |
|||
|
|||
[item-name] |
|||
robot-attrition-crashed=Упавший __1__ |
|||
|
|||
[recipe-name] |
|||
robot-attrition-repair=Ремонтировать __1__ |
|||
robot-attrition-recombine=Пересобрать __1__ |
|||
|
|||
[mod-setting-name] |
|||
robot-attrition-factor=Фактор износа дронов |
|||
robot-attrition-repair=Ремонт дронов |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=Множитель шанса крушения дрона. Примечание: другие моды могут изменять или переопределять это значение для нужных поверхностей. |
|||
robot-attrition-repair=Параметры ремонта дронов. |
|||
|
|||
[string-mod-setting] |
|||
robot-attrition-repair-Disabed=Отключено |
|||
robot-attrition-repair-Repair75=Затраты на ремонт 75% (примерно) |
@ -0,0 +1,5 @@ |
|||
[mod-setting-name] |
|||
robot-attrition-factor=机器人故障系数 |
|||
|
|||
[mod-setting-description] |
|||
robot-attrition-factor=机器人产生故障的几率乘数。说明: 其他Mod可以修改这个值。 |
@ -0,0 +1,51 @@ |
|||
Event = { listeners = {} } |
|||
|
|||
-- can add multiple listeners to the same event. |
|||
-- event_key can be a uint of native events (defines.events) |
|||
-- event_key can be a string for custom input of virtual events |
|||
-- if a virtual event is added, set virtual = true |
|||
-- on_init, on_load, on_configuration_changed get triggered automatically as virtual events |
|||
Event.addListener = function(event_key, add_callback, virtual) |
|||
if not Event.listeners[event_key] then |
|||
Event.listeners[event_key] = {} |
|||
Event.listeners[event_key].callbacks = {} |
|||
Event.listeners[event_key].sequence = function (event) |
|||
for _, callback in pairs(Event.listeners[event_key].callbacks) do |
|||
callback(event) |
|||
end |
|||
end |
|||
if not virtual then -- custom input eventsm only works after on_init |
|||
script.on_event(event_key, Event.listeners[event_key].sequence) |
|||
end |
|||
table.insert(Event.listeners[event_key].callbacks, add_callback) |
|||
else |
|||
for _, callback in pairs(Event.listeners[event_key].callbacks) do |
|||
if callback == add_callback then return end |
|||
end |
|||
if not exists then |
|||
table.insert(Event.listeners[event_key].callbacks, add_callback) |
|||
end |
|||
end |
|||
end |
|||
|
|||
-- can add multiple listneers to the same event. |
|||
Event.removeListener = function(event_key, remove_callback) |
|||
if not Event.listeners[event_key] then return end |
|||
for _, callback in pairs(Event.listeners[event_key].callbacks) do |
|||
if callback == remove_callback then |
|||
Event.listeners[event_key].callbacks[_] = nil |
|||
end |
|||
end |
|||
end |
|||
|
|||
Event.trigger = function(event_key, event_data) |
|||
if Event.listeners[event_key] then |
|||
Event.listeners[event_key].sequence(event_data) |
|||
end |
|||
end |
|||
|
|||
script.on_init(function(event) Event.trigger("on_init", event) end) |
|||
script.on_load(function(event) Event.trigger("on_load", event) end) |
|||
script.on_configuration_changed(function(event) Event.trigger("on_configuration_changed", event) end) |
|||
|
|||
return Event |
@ -0,0 +1,19 @@ |
|||
data:extend{ |
|||
{ |
|||
type = "double-setting", |
|||
name = "robot-attrition-factor", |
|||
setting_type = "runtime-global", |
|||
default_value = 1, |
|||
minimum_value = 0.001, |
|||
maximum_value = 1000, |
|||
order = "a", |
|||
}, |
|||
{ |
|||
type = "string-setting", |
|||
name = "robot-attrition-repair", |
|||
setting_type = "startup", |
|||
default_value = "Disabled", |
|||
allowed_values = {"Disabled", "Repair75"}, |
|||
order = "b", |
|||
}, |
|||
} |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 13 KiB |
Loading…
Reference in new issue