Browse Source

initial

master
Florin Tobler 4 years ago
commit
9b6429cef0
  1. 41
      .gitignore
  2. 5
      README.md
  3. 6
      robot_attrition_0.5.10/robot_attrition/README.md
  4. 134
      robot_attrition_0.5.10/robot_attrition/changelog.txt
  5. 271
      robot_attrition_0.5.10/robot_attrition/control.lua
  6. 6
      robot_attrition_0.5.10/robot_attrition/data-final-fixes.lua
  7. 108
      robot_attrition_0.5.10/robot_attrition/data-updates.lua
  8. 170
      robot_attrition_0.5.10/robot_attrition/data.lua
  9. BIN
      robot_attrition_0.5.10/robot_attrition/graphics/technology/robot-safety.png
  10. 11
      robot_attrition_0.5.10/robot_attrition/info.json
  11. 21
      robot_attrition_0.5.10/robot_attrition/licence.txt
  12. 11
      robot_attrition_0.5.10/robot_attrition/locale/cs/strings.cfg
  13. 24
      robot_attrition_0.5.10/robot_attrition/locale/en/strings.cfg
  14. 5
      robot_attrition_0.5.10/robot_attrition/locale/pl/strings.cfg
  15. 24
      robot_attrition_0.5.10/robot_attrition/locale/ru/strings.cfg
  16. 5
      robot_attrition_0.5.10/robot_attrition/locale/zh-CN/strings.cfg
  17. 51
      robot_attrition_0.5.10/robot_attrition/scripts/event.lua
  18. 19
      robot_attrition_0.5.10/robot_attrition/settings.lua
  19. BIN
      robot_attrition_0.5.10/robot_attrition/thumbnail.png
  20. 6
      robot_attrition_0.5.10_original/robot_attrition/README.md
  21. 134
      robot_attrition_0.5.10_original/robot_attrition/changelog.txt
  22. 271
      robot_attrition_0.5.10_original/robot_attrition/control.lua
  23. 6
      robot_attrition_0.5.10_original/robot_attrition/data-final-fixes.lua
  24. 108
      robot_attrition_0.5.10_original/robot_attrition/data-updates.lua
  25. 170
      robot_attrition_0.5.10_original/robot_attrition/data.lua
  26. BIN
      robot_attrition_0.5.10_original/robot_attrition/graphics/technology/robot-safety.png
  27. 11
      robot_attrition_0.5.10_original/robot_attrition/info.json
  28. 21
      robot_attrition_0.5.10_original/robot_attrition/licence.txt
  29. 11
      robot_attrition_0.5.10_original/robot_attrition/locale/cs/strings.cfg
  30. 24
      robot_attrition_0.5.10_original/robot_attrition/locale/en/strings.cfg
  31. 5
      robot_attrition_0.5.10_original/robot_attrition/locale/pl/strings.cfg
  32. 24
      robot_attrition_0.5.10_original/robot_attrition/locale/ru/strings.cfg
  33. 5
      robot_attrition_0.5.10_original/robot_attrition/locale/zh-CN/strings.cfg
  34. 51
      robot_attrition_0.5.10_original/robot_attrition/scripts/event.lua
  35. 19
      robot_attrition_0.5.10_original/robot_attrition/settings.lua
  36. BIN
      robot_attrition_0.5.10_original/robot_attrition/thumbnail.png
  37. BIN
      space-exploration-extension/thumbnail.png

41
.gitignore

@ -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

5
README.md

@ -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.

6
robot_attrition_0.5.10/robot_attrition/README.md

@ -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

134
robot_attrition_0.5.10/robot_attrition/changelog.txt

@ -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.

271
robot_attrition_0.5.10/robot_attrition/control.lua

@ -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)

6
robot_attrition_0.5.10/robot_attrition/data-final-fixes.lua

@ -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

108
robot_attrition_0.5.10/robot_attrition/data-updates.lua

@ -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

170
robot_attrition_0.5.10/robot_attrition/data.lua

@ -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")

BIN
robot_attrition_0.5.10/robot_attrition/graphics/technology/robot-safety.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

11
robot_attrition_0.5.10/robot_attrition/info.json

@ -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"
}

21
robot_attrition_0.5.10/robot_attrition/licence.txt

@ -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.

11
robot_attrition_0.5.10/robot_attrition/locale/cs/strings.cfg

@ -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.

24
robot_attrition_0.5.10/robot_attrition/locale/en/strings.cfg

@ -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)

5
robot_attrition_0.5.10/robot_attrition/locale/pl/strings.cfg

@ -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.

24
robot_attrition_0.5.10/robot_attrition/locale/ru/strings.cfg

@ -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% (примерно)

5
robot_attrition_0.5.10/robot_attrition/locale/zh-CN/strings.cfg

@ -0,0 +1,5 @@
[mod-setting-name]
robot-attrition-factor=机器人故障系数
[mod-setting-description]
robot-attrition-factor=机器人产生故障的几率乘数。说明: 其他Mod可以修改这个值。

51
robot_attrition_0.5.10/robot_attrition/scripts/event.lua

@ -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

19
robot_attrition_0.5.10/robot_attrition/settings.lua

@ -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",
},
}

BIN
robot_attrition_0.5.10/robot_attrition/thumbnail.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

6
robot_attrition_0.5.10_original/robot_attrition/README.md

@ -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

134
robot_attrition_0.5.10_original/robot_attrition/changelog.txt

@ -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.

271
robot_attrition_0.5.10_original/robot_attrition/control.lua

@ -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)

6
robot_attrition_0.5.10_original/robot_attrition/data-final-fixes.lua

@ -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

108
robot_attrition_0.5.10_original/robot_attrition/data-updates.lua

@ -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

170
robot_attrition_0.5.10_original/robot_attrition/data.lua

@ -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")

BIN
robot_attrition_0.5.10_original/robot_attrition/graphics/technology/robot-safety.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

11
robot_attrition_0.5.10_original/robot_attrition/info.json

@ -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"
}

21
robot_attrition_0.5.10_original/robot_attrition/licence.txt

@ -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.

11
robot_attrition_0.5.10_original/robot_attrition/locale/cs/strings.cfg

@ -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.

24
robot_attrition_0.5.10_original/robot_attrition/locale/en/strings.cfg

@ -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)

5
robot_attrition_0.5.10_original/robot_attrition/locale/pl/strings.cfg

@ -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.

24
robot_attrition_0.5.10_original/robot_attrition/locale/ru/strings.cfg

@ -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% (примерно)

5
robot_attrition_0.5.10_original/robot_attrition/locale/zh-CN/strings.cfg

@ -0,0 +1,5 @@
[mod-setting-name]
robot-attrition-factor=机器人故障系数
[mod-setting-description]
robot-attrition-factor=机器人产生故障的几率乘数。说明: 其他Mod可以修改这个值。

51
robot_attrition_0.5.10_original/robot_attrition/scripts/event.lua

@ -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

19
robot_attrition_0.5.10_original/robot_attrition/settings.lua

@ -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",
},
}

BIN
robot_attrition_0.5.10_original/robot_attrition/thumbnail.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
space-exploration-extension/thumbnail.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Loading…
Cancel
Save