Skip to content

Instantly share code, notes, and snippets.

@morsk
Created February 23, 2026 22:07
Show Gist options
  • Select an option

  • Save morsk/4cc47b8eaed43e50509d1f706c3d1cff to your computer and use it in GitHub Desktop.

Select an option

Save morsk/4cc47b8eaed43e50509d1f706c3d1cff to your computer and use it in GitHub Desktop.
Factorio: Restore Crash Site
/silent-command
--[[
This is Factorio code from data/core/lualib/crash-site.lua, with unnecessary parts removed,
especially the fires and explosions which were many lines of code.
It is Wube code and subject to their EULA, and they can DMCA it, but they generally don't care
about their script being reused in mods and player script.
If the crash site area is cluttered, it will displace the crash parts into places that fit, which may look weird.
So it's best to clear the area before using it.
It could of course be modified to clear things itself, but I didn't try.
]]
local crash_site_location = {-5, -6}
local default_ship_parts = {
{
name = "crash-site-spaceship-wreck-big-1",
angle_deviation = 0.1,
max_distance = 25,
min_separation = 2,
},
{
name = "crash-site-spaceship-wreck-big-2",
angle_deviation = 0.1,
max_distance = 25,
min_separation = 2,
},
{
name = "crash-site-spaceship-wreck-medium",
variations = 3,
angle_deviation = 0.05,
max_distance = 30,
min_separation = 1,
},
{
name = "crash-site-spaceship-wreck-small",
variations = 6,
angle_deviation = 0.05,
min_separation = 1,
}
}
local rotate = function(offset, angle)
local x = offset[1]
local y = offset[2]
local rotated_x = x * math.cos(angle) - y * math.sin(angle)
local rotated_y = x * math.sin(angle) + y * math.cos(angle)
return {rotated_x, rotated_y}
end
local entry_angle = 0.70
local random = math.random
local get_offset = function(part)
local angle = entry_angle + ((random() - 0.5) * part.angle_deviation)
angle = angle - 0.25
angle = angle * math.pi * 2
local distance = 8 + (random() * (part.max_distance or 40))
local offset = rotate({distance, 0}, angle)
return offset
end
local get_name = function(part, k)
if not part.variations then return part.name end
local variant = k or random(part.variations)
return part.name.."-"..variant
end
local function create_crash_site(surface, position)
local main_ship = surface.create_entity
{
name = "crash-site-spaceship",
position = position,
force = "player",
create_build_effect_smoke = false
}
local box = main_ship.bounding_box
for k, entity in pairs (surface.find_entities_filtered{area = box, force = "neutral", collision_mask = "player"}) do
if entity.valid then
if entity.type == "tree" then
entity.die()
else
entity.destroy()
end
end
end
for k, part in pairs(default_ship_parts) do
for k = 1, (part.variations or 1) do
local name = get_name(part, k)
for i = 1, part.repeat_count or 1 do
local part_position
local count = 0
local offset
while true do
offset = get_offset(part)
local x = (position[1] or position.x) + offset[1]
local y = (position[2] or position.y) + offset[2]
part_position = {x, y}
local can_place = surface.can_place_entity
{
name = name,
position = part_position,
force = "player",
build_check_type = defines.build_check_type.manual_ghost,
forced = true
}
if can_place then
if not part.min_separation or surface.count_entities_filtered{position = part_position, radius = part.min_separation, limit = 1, type = "tree", invert = true} == 0 then
break
end
end
count = count + 1
if count > 20 then
part_position = surface.find_non_colliding_position(name, part_position, 50, 4)
break
end
end
if part_position then
local entity = surface.create_entity
{
name = name,
position = part_position,
force = part.force or "neutral",
create_build_effect_smoke = false
}
for k, entity in pairs (surface.find_entities_filtered{type = {"tree", "simple-entity"}, position = part_position, radius = 1 + entity.get_radius()}) do
if entity.type == "tree" then
entity.die()
else
entity.destroy()
end
end
end
end
end
end
end
create_crash_site(game.get_surface("nauvis"), crash_site_location)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment