Created
February 23, 2026 22:07
-
-
Save morsk/4cc47b8eaed43e50509d1f706c3d1cff to your computer and use it in GitHub Desktop.
Factorio: Restore Crash Site
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /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