|
local util = require("util") |
|
|
|
local main_ship_name = "crash-site-spaceship" |
|
|
|
local default_ship_parts = function() |
|
return |
|
{ |
|
{ |
|
name = "crash-site-spaceship-wreck-big-1", |
|
angle_deviation = 0.1, |
|
max_distance = 25, |
|
min_separation = 2, |
|
fire_count = 1 |
|
}, |
|
{ |
|
name = "crash-site-spaceship-wreck-big-2", |
|
angle_deviation = 0.1, |
|
max_distance = 25, |
|
min_separation = 2, |
|
explosion_count = 3, |
|
fire_count = 1 |
|
}, |
|
{ |
|
name = "crash-site-spaceship-wreck-medium", |
|
variations = 3, |
|
angle_deviation = 0.05, |
|
max_distance = 30, |
|
min_separation = 1, |
|
explosion_count = 1, |
|
fire_count = 1 |
|
}, |
|
{ |
|
name = "crash-site-spaceship-wreck-small", |
|
variations = 6, |
|
angle_deviation = 0.05, |
|
min_separation = 1, |
|
fire_count = 1 |
|
}, |
|
{ |
|
name = "crash-site-fire-smoke", |
|
angle_deviation = 0.08, |
|
repeat_count = 0, |
|
scale_lifetime = true |
|
} |
|
} |
|
end |
|
|
|
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 get_lifetime = function(offset) |
|
|
|
local distance = ((offset[1] * offset[1]) + (offset[2] * offset[2])) ^ 0.5 |
|
|
|
local time = random(60 * 20, 60 * 30) - math.min(distance * 100, 15 * 60) |
|
|
|
return time |
|
|
|
end |
|
|
|
local get_random_position = function(box, x_scale, y_scale) |
|
local x_scale = x_scale or 1 |
|
local y_scale = y_scale or 1 |
|
local x1 = box.left_top.x |
|
local y1 = box.left_top.y |
|
local x2 = box.right_bottom.x |
|
local y2 = box.right_bottom.y |
|
local x = ((x2 - x1) * x_scale * (random() - 0.5)) + ((x1 + x2) / 2) |
|
local y = ((y2 - y1) * y_scale * (random() - 0.5)) + ((y1 + y2) / 2) |
|
return {x, y} |
|
end |
|
|
|
local random_from_map = function(map) |
|
local array = {} |
|
local i = 1 |
|
for k, v in pairs (map) do |
|
array[i] = k |
|
i = i + 1 |
|
end |
|
local key = array[random(#array)] |
|
local value = map[key] |
|
return key, value |
|
end |
|
|
|
local insert_items_randomly = function(entities, items) |
|
|
|
local item_prototypes = game.item_prototypes |
|
for name, count in pairs (items) do |
|
if not item_prototypes[name] then |
|
items[name] = nil |
|
end |
|
end |
|
if not next(items) then return end |
|
|
|
for unit_number, entity in pairs (entities) do |
|
if not entity.valid then |
|
entities[unit_number] = nil |
|
end |
|
end |
|
if not next(entities) then return end |
|
|
|
local stupid = 1000 |
|
while true do |
|
local item_name, count = random_from_map(items) |
|
local unit_number, entity = random_from_map(entities) |
|
local inserted = entity.insert{name = item_name, count = 1} |
|
if inserted == count then |
|
items[item_name] = nil |
|
else |
|
items[item_name] = count - inserted |
|
end |
|
|
|
if not next(items) then break end |
|
|
|
stupid = stupid - 1 |
|
if stupid <= 0 then break end |
|
end |
|
end |
|
|
|
local main_ship_flame_count = 4 |
|
local main_ship_explosion_count = 10 |
|
|
|
local lib = {} |
|
|
|
lib.create_crash_site = function(surface, position, ship_items, part_items, ship_parts) |
|
local main_ship = surface.create_entity |
|
{ |
|
name = main_ship_name, |
|
position = position, |
|
force = "player", |
|
create_build_effect_smoke = false |
|
} |
|
util.insert_safe(main_ship, ship_items) |
|
local box = main_ship.bounding_box |
|
for k, entity in pairs (surface.find_entities_filtered{area = box, force = "neutral", collision_mask = "player-layer"}) do |
|
if entity.valid then |
|
if entity.type == "tree" then |
|
entity.die() |
|
else |
|
entity.destroy() |
|
end |
|
end |
|
end |
|
|
|
for k = 1, main_ship_flame_count do |
|
local position = get_random_position(box, 0.8, 0.5) |
|
surface.create_entity |
|
{ |
|
name = "crash-site-fire-flame", |
|
position = position |
|
} |
|
local fire = surface.create_entity |
|
{ |
|
name = "crash-site-fire-smoke", |
|
position = position |
|
} |
|
fire.time_to_live = random(60 * 15, 60 * 30) |
|
fire.time_to_next_effect = random(60 * 3) |
|
end |
|
|
|
for k = 1, main_ship_explosion_count do |
|
local explosions = surface.create_entity |
|
{ |
|
name = "crash-site-explosion-smoke", |
|
position = get_random_position(box, 0.8, 0.5) |
|
} |
|
explosions.time_to_live = random(60 * 15, 60 * 30) |
|
explosions.time_to_next_effect = random(60) |
|
end |
|
|
|
local wreck_parts = {} |
|
|
|
for k, part in pairs(ship_parts or 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 |
|
} |
|
|
|
if entity.get_output_inventory() and #entity.get_output_inventory() > 0 then |
|
wreck_parts[entity.unit_number] = entity |
|
end |
|
|
|
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 |
|
|
|
if part.explosion_count then |
|
for k = 1, part.explosion_count do |
|
local explosions = surface.create_entity |
|
{ |
|
name = "crash-site-explosion-smoke", |
|
position = get_random_position(entity.bounding_box) |
|
} |
|
explosions.time_to_live = get_lifetime(offset) |
|
explosions.time_to_next_effect = random(30) |
|
end |
|
end |
|
|
|
if part.fire_count then |
|
for k = 1, part.fire_count do |
|
surface.create_entity |
|
{ |
|
name = "crash-site-fire-flame", |
|
position = get_random_position(entity.bounding_box) |
|
} |
|
local explosions = surface.create_entity |
|
{ |
|
name = "crash-site-fire-smoke", |
|
position = get_random_position(entity.bounding_box) |
|
} |
|
explosions.time_to_live = get_lifetime(offset) |
|
explosions.time_to_next_effect = random(30) |
|
end |
|
end |
|
|
|
if part.scale_lifetime then |
|
entity.time_to_live = get_lifetime(offset) |
|
entity.time_to_next_effect = random(60) |
|
end |
|
end |
|
end |
|
end |
|
end |
|
|
|
insert_items_randomly(wreck_parts, part_items) |
|
|
|
end |
|
|
|
local set_label_size = function(player) |
|
|
|
local label = player.gui.screen.skip_cutscene_label |
|
if not label then return end |
|
|
|
label.style.horizontal_align = "center" |
|
local resolution = player.display_resolution |
|
label.style.width = resolution.width / player.display_scale |
|
label.location = {0, (resolution.height) - ((20 + 8) * player.display_scale)} |
|
|
|
end |
|
|
|
lib.create_cutscene = function(player, goal_position) |
|
local offset = rotate({60, 0}, (entry_angle - 0.25) * math.pi * 2) |
|
local start_position = {goal_position[1] + offset[1], goal_position[2] + offset[2]} |
|
player.set_controller |
|
{ |
|
type = defines.controllers.cutscene, |
|
waypoints = |
|
{ |
|
{ |
|
position = goal_position, |
|
transition_time = 450, |
|
zoom = 2, |
|
time_to_wait = 150 |
|
}, |
|
{ |
|
target = player.character, |
|
transition_time = 150, |
|
zoom = 1.5, |
|
time_to_wait = 0 |
|
} |
|
}, |
|
start_position = start_position, |
|
start_zoom = 2 |
|
} |
|
|
|
local label = player.gui.screen.add{type = "label", caption = {"skip-cutscene"}, name = "skip_cutscene_label"} |
|
set_label_size(player) |
|
end |
|
|
|
lib.is_crash_site_cutscene = function(event) |
|
return event.player_index == 1 and event.waypoint_index == 1 |
|
end |
|
|
|
lib.on_player_display_refresh = function(event) |
|
local player = game.get_player(event.player_index) |
|
set_label_size(player) |
|
end |
|
|
|
lib.default_ship_parts = default_ship_parts |
|
|
|
return lib |
|
|