You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
14 KiB

Capsule = {}
-- constants
Capsule.name_space_capsule_gui_root = mod_prefix.."space-capsule-gui"
Capsule.name_space_capsule = mod_prefix.."space-capsule"
Capsule.name_space_capsule_vehicle = mod_prefix.."space-capsule-_-vehicle"
Capsule.name_space_capsule_vehicle_shadow = mod_prefix.."space-capsule-_-vehicle-shadow"
Capsule.name_space_capsule_vehicle_light = mod_prefix.."light-space-capsule"
Capsule.name_space_capsule_vehicle_light_launch = mod_prefix.."light-space-capsule-launch"
function Capsule.launch(vehicle)
local current_zone = Zone.from_surface(vehicle.surface)
if current_zone and Zone.is_space(current_zone) then
local shadow = vehicle.surface.find_entities_filtered{ area=util.position_to_area(vehicle.position, 1), name=Capsule.name_space_capsule_vehicle_shadow}[1]
local light = vehicle.surface.find_entities_filtered{ area=util.position_to_area(vehicle.position, 1), name=Capsule.name_space_capsule_vehicle_light}[1]
if light then light.destroy() end
light = vehicle.surface.create_entity{name = Capsule.name_space_capsule_vehicle_light_launch, position = vehicle.position, target=vehicle, speed = 0}
local passengers = {} -- characters not players
if vehicle.get_driver() then
table.insert(passengers, vehicle.get_driver())
end
if vehicle.get_passenger() then
table.insert(passengers, vehicle.get_passenger())
end
for _, passenger in pairs(passengers) do
if passenger.valid then passenger.destructible = false end
if remote.interfaces["jetpack"] and remote.interfaces["jetpack"]["block_jetpack"] then
remote.call("jetpack", "block_jetpack", {character=passenger})
end
if passenger.player then
close_own_guis(passenger.player)
end
end
local target_zone = Zone.find_nearest_solid_zone_from_zone(current_zone)
Zone.get_make_surface(target_zone)
local zone_assets = Zone.get_force_assets(vehicle.force.name, target_zone.index)
local landing_pads = {}
if zone_assets.rocket_landing_pad_names then
for name, pads in pairs(zone_assets.rocket_landing_pad_names) do
for _, pad in pairs(pads) do
table.insert(landing_pads, pad)
end
end
end
local destination_position
if #landing_pads > 0 then
local pad = landing_pads[math.random(#landing_pads)]
if pad and pad.container and pad.container.valid then
local surface = Zone.get_make_surface(target_zone)
destination_position = surface.find_non_colliding_position(Capsule.name_space_capsule_vehicle, pad.container.position, 32, 1) or pad.container.position
end
end
if not destination_position then
destination_position = Zone.find_zone_landing_position(target_zone)
end
global.space_capsule_launches = global.space_capsule_launches or {}
global.space_capsule_launches[vehicle.unit_number] = {
force_name = vehicle.force.name,
unit_number = vehicle.unit_number,
vehicle = vehicle,
shadow = shadow,
light = light,
start_position = vehicle.position,
launch_progress = 1,
destination_zone = target_zone,
destination_position = destination_position,
passengers = passengers,
}
else -- invalid
if vehicle.get_driver() and vehicle.get_driver().player then
vehicle.get_driver().player.print({"space-exploration.capsule_invalid_launch_location"})
end
if vehicle.get_passenger() and vehicle.get_passenger().player then
vehicle.get_driver().player.print({"space-exploration.capsule_invalid_launch_location"})
end
end
end
function Capsule.gui_close (player)
if player.gui.left[Capsule.name_space_capsule_gui_root] then
player.gui.left[Capsule.name_space_capsule_gui_root].destroy()
end
end
function Capsule.gui_open(player)
local gui = player.gui.left
close_own_guis(player)
local container = gui.add{ type = "frame", name = Capsule.name_space_capsule_gui_root, style="space_platform_container", direction="vertical"}
local zone = Zone.from_surface(player.surface)
local title = container.add{ type="label", name="title", caption={"space-exploration.space-capsule"}, style="space_platform_title"}
if not zone then
container.add{ type="label", name="status", caption={"space-exploration.capsule_status_invalid_launch_location"}}
container.add{ type="label", name="info", caption={"space-exploration.capsule_info"}}
elseif Zone.is_solid(zone) then
container.add{ type="label", name="status", caption={"space-exploration.capsule_not_enough_thrust", zone.type, zone.name}}
container.add{ type="label", name="info", caption={"space-exploration.capsule_info"}}
else
local destination = Zone.find_nearest_solid_zone_from_zone(zone)
container.add{ type="label", name="info", caption={"space-exploration.capsule_info"}}
if destination then
container.add{ type="label", name="status", caption={"space-exploration.capsule_status_ready"}}
container.add{ type="label", name="destination", caption={"space-exploration.capsule_destination", destination.name}}
local launch_button = container.add{ type="button", name="launch", caption={"space-exploration.button-launch"}, style="confirm_button"}
launch_button.style.top_margin = 10
launch_button.style.horizontally_stretchable = true
launch_button.style.horizontal_align = "left"
else
container.add{ type="label", name="status", caption={"space-exploration.capsule_status_invalid_launch_location"}}
end
end
end
function Capsule.on_gui_click(event)
if event.element and event.element.valid and event.element.name == "launch" then
local element = event.element
local root = gui_element_or_parent(element, Capsule.name_space_capsule_gui_root)
if root then
local player = game.players[event.player_index]
local vehicle = player.vehicle
if vehicle then
Capsule.launch(vehicle)
end
end
end
end
Event.addListener(defines.events.on_gui_click, Capsule.on_gui_click)
function Capsule.on_tick()
if global.space_capsule_launches then
for _, space_capsule in pairs(global.space_capsule_launches) do
if not(space_capsule.vehicle and space_capsule.vehicle.valid) then
global.space_capsule_launches[space_capsule.unit_number] = nil
if space_capsule.rocket_sound and space_capsule.rocket_sound.valid then
space_capsule.rocket_sound.destroy()
end
if space_capsule.light and space_capsule.light.valid then
space_capsule.light.destroy()
end
if space_capsule.shadow and space_capsule.shadow.valid then
space_capsule.shadow.destroy()
end
else
space_capsule.launch_progress = space_capsule.launch_progress + 1
local animation_speed = 1/3
local animation_move_frame = 19
local target_surface = Zone.get_make_surface(space_capsule.destination_zone)
space_capsule.vehicle.destructible = false
if space_capsule.launch_progress < animation_move_frame / animation_speed + 60 * 5 then
local animation_frames = 24
local animation_frame = math.max(math.min(math.floor(space_capsule.launch_progress * animation_speed), animation_frames), 1)
if animation_frame == 1 and not space_capsule.sounds_frame_1 then
space_capsule.sounds_frame_1 = true
space_capsule.rocket_sound = space_capsule.vehicle.surface.create_entity{
name=mod_prefix.."sound-continous-silo-rocket", position=space_capsule.vehicle.position, target=space_capsule.vehicle, speed=0}
space_capsule.vehicle.surface.create_entity{
name=mod_prefix.."sound-silo-clamps-on", position=space_capsule.vehicle.position, target=space_capsule.vehicle, speed=0}
space_capsule.vehicle.surface.create_entity{
name=mod_prefix.."sound-machine-close", position=space_capsule.vehicle.position, target=space_capsule.vehicle, speed=0}
end
if animation_frame == 19 and not space_capsule.sounds_frame_19 then
space_capsule.sounds_frame_19 = true
space_capsule.vehicle.surface.create_entity{
name=mod_prefix.."sound-train-breaks", position=space_capsule.vehicle.position, target=space_capsule.vehicle, speed=0}
end
local move_progress = math.max( 0, space_capsule.launch_progress - (animation_move_frame / animation_speed))
local move_y = math.pow( math.max(0, move_progress), 1.5) / 100
local position = {
x = space_capsule.start_position.x,
y = space_capsule.start_position.y - move_y
}
if space_capsule.light then
space_capsule.light.teleport({x = position.x, y = position.y + 1})
end
if space_capsule.rocket_sound and space_capsule.rocket_sound.valid then
space_capsule.rocket_sound.teleport(position)
end
space_capsule.vehicle.teleport(position)
space_capsule.vehicle.orientation = (animation_frame - 1) / animation_frames
if space_capsule.shadow then
space_capsule.shadow.graphics_variation = animation_frame
space_capsule.shadow.teleport({
x = space_capsule.start_position.x + move_y,
y = space_capsule.start_position.y
})
end
for _, passenger in pairs(space_capsule.passengers) do
if passenger.valid then
passenger.teleport({x = position.x, y = position.y - 0.5}) -- behind graphic
end
end
else
-- done
global.space_capsule_launches[space_capsule.unit_number] = nil
if space_capsule.rocket_sound and space_capsule.rocket_sound.valid then space_capsule.rocket_sound.destroy() end
if space_capsule.light and space_capsule.light.valid then space_capsule.light.destroy() end
if space_capsule.shadow and space_capsule.shadow.valid then space_capsule.shadow.destroy() end
local safe_pos = target_surface.find_non_colliding_position(Capsule.name_space_capsule_vehicle, space_capsule.destination_position, 32, 1)
safe_pos = safe_pos or space_capsule.destination_position
target_surface.request_to_generate_chunks(safe_pos, 1)
target_surface.force_generate_chunk_requests()
local vehicle_2 = target_surface.create_entity{
name = space_capsule.vehicle.name,
position = safe_pos,
force = space_capsule.vehicle.force
}
local inv_a = space_capsule.vehicle.get_inventory(defines.inventory.car_trunk)
local inv_b = vehicle_2.get_inventory(defines.inventory.car_trunk)
Util.copy_inventory(inv_a, inv_b)
space_capsule.vehicle.destroy()
space_capsule.vehicle = vehicle_2
space_capsule.vehicle.orientation = 0
space_capsule.shadow = target_surface.create_entity{name = Capsule.name_space_capsule_vehicle_shadow, position=safe_pos, force = "neutral"}
space_capsule.shadow.graphics_variation = 1
space_capsule.light = target_surface.create_entity{name = Capsule.name_space_capsule_vehicle_light, position = space_capsule.vehicle.position, speed = 0, target = space_capsule.vehicle}
for _, passenger in pairs(space_capsule.passengers) do
if passenger.valid then
passenger.destructible = true
if remote.interfaces["jetpack"] and remote.interfaces["jetpack"]["unblock_jetpack"] then
remote.call("jetpack", "unblock_jetpack", {character=passenger})
end
teleport_character_to_surface(passenger, target_surface, safe_pos)
end
end
end
end
end
end
end
-- TODO: only register this if that are any
Event.addListener(defines.events.on_tick, Capsule.on_tick)
function Capsule.on_entity_removed(event)
local entity = event.entity
if entity and entity.valid then
if entity.name == Capsule.name_space_capsule_vehicle then
local shadow = entity.surface.find_entities_filtered{ area=util.position_to_area(entity.position, 1), name=Capsule.name_space_capsule_vehicle_shadow}[1]
local light = entity.surface.find_entities_filtered{ area=util.position_to_area(entity.position, 1), name=Capsule.name_space_capsule_vehicle_light}[1]
if shadow then shadow.destroy() end
if light then light.destroy() end
end
end
end
Event.addListener(defines.events.on_entity_died, Capsule.on_entity_removed)
Event.addListener(defines.events.on_robot_mined_entity, Capsule.on_entity_removed)
Event.addListener(defines.events.on_player_mined_entity, Capsule.on_entity_removed)
Event.addListener(defines.events.script_raised_destroy, Capsule.on_entity_removed)
function Capsule.on_player_driving_changed_state(event)
local player = game.players[event.player_index]
if player then
if player.vehicle and player.vehicle.name == Capsule.name_space_capsule_vehicle then
Capsule.gui_open(player)
elseif player.gui.left[Capsule.name_space_capsule_gui_root] then
player.gui.left[Capsule.name_space_capsule_gui_root].destroy()
end
end
end
Event.addListener(defines.events.on_player_driving_changed_state, Capsule.on_player_driving_changed_state)
function Capsule.on_entity_created(event)
local entity
if event.entity and event.entity.valid then
entity = event.entity
end
if event.created_entity and event.created_entity.valid then
entity = event.created_entity
end
if not entity then return end
if entity.name == Capsule.name_space_capsule_vehicle then
entity.orientation = 0
entity.surface.create_entity{name = Capsule.name_space_capsule_vehicle_shadow, position = entity.position, force="neutral"}
entity.surface.create_entity{name = Capsule.name_space_capsule_vehicle_light, position = entity.position, speed = 0, target = entity}
end
end
Event.addListener(defines.events.on_built_entity, Capsule.on_entity_created)
Event.addListener(defines.events.on_robot_built_entity, Capsule.on_entity_created)
Event.addListener(defines.events.script_raised_built, Capsule.on_entity_created)
Event.addListener(defines.events.script_raised_revive, Capsule.on_entity_created)
return Capsule