mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 01:34:01 +00:00
## About The Pull Request The initial dock for a custom shuttle - created when the shuttle is - had the name of the shuttle area it was created in, rather than the name of the area underneath the shuttle. Additionally, this dock was not deleted when the shuttle left, preventing it from setting down a dock back at that initial location. This PR fixes both of those issues. ## Why It's Good For The Game Fixes an issue someone on Manuel couldn't be bothered to open on github due to lack of motivation. ## Changelog 🆑 fix: An initially created custom shuttle will no longer state it is located at some place within itself. fix: Custom shuttles will no longer have their docking computers blocked by the area they were initially created at. /🆑
561 lines
23 KiB
Plaintext
561 lines
23 KiB
Plaintext
GLOBAL_LIST_EMPTY(shuttle_frames_by_turf)
|
|
|
|
/datum/shuttle_frame
|
|
/// The turfs that are part of this frame
|
|
var/list/turfs = list()
|
|
|
|
/// Turfs that are changing, but shouldn't be removed from the frame immediately in case they are still valid frame turfs after the change
|
|
var/list/possibly_valid_changing_turfs = list()
|
|
|
|
/// List of turfs to start the split check with (to avoid redundant flood fill checks)
|
|
var/list/deferred_update_turfs = list()
|
|
|
|
/// Turfs to check for the existence of shuttles - used for expanding custom shuttles
|
|
var/list/shuttle_tracking_turfs = list()
|
|
|
|
/// A list of shuttles on tracking turfs, each associated with a list of which tracking turfs the shuttle overlaps
|
|
var/list/adjacent_shuttles = list()
|
|
|
|
/// Turfs that are in our list of turfs, but also have had a shuttle land on them
|
|
var/list/shuttle_covered_turfs = list()
|
|
|
|
/datum/shuttle_frame/New(list/initial_turfs)
|
|
if(initial_turfs)
|
|
add_turfs(initial_turfs)
|
|
|
|
/datum/shuttle_frame/proc/start_tracking_turf_for_shuttles(turf/to_track, dir)
|
|
if(!shuttle_tracking_turfs[to_track])
|
|
var/obj/docking_port/mobile/custom/shuttle = SSshuttle.get_containing_shuttle(to_track)
|
|
if(istype(shuttle))
|
|
if(!adjacent_shuttles[shuttle])
|
|
start_tracking_shuttle(shuttle)
|
|
adjacent_shuttles[shuttle][to_track] = TRUE
|
|
RegisterSignals(to_track, list(COMSIG_TURF_ON_SHUTTLE_MOVE, COMSIG_TURF_REMOVED_FROM_SHUTTLE), PROC_REF(shuttle_leave_react))
|
|
RegisterSignals(to_track, list(COMSIG_TURF_AFTER_SHUTTLE_MOVE, COMSIG_TURF_ADDED_TO_SHUTTLE), PROC_REF(shuttle_arrive_react))
|
|
shuttle_tracking_turfs[to_track] |= dir
|
|
|
|
/datum/shuttle_frame/proc/stop_tracking_turf_for_shuttles(turf/to_stop_tracking)
|
|
for(var/obj/docking_port/mobile/custom/shuttle as anything in adjacent_shuttles)
|
|
var/list/turfs_tracking_shuttle = adjacent_shuttles[shuttle]
|
|
if(turfs_tracking_shuttle[to_stop_tracking])
|
|
turfs_tracking_shuttle -= to_stop_tracking
|
|
if(!length(turfs_tracking_shuttle))
|
|
stop_tracking_shuttle(shuttle)
|
|
shuttle_tracking_turfs -= to_stop_tracking
|
|
UnregisterSignal(to_stop_tracking, list(COMSIG_TURF_ON_SHUTTLE_MOVE, COMSIG_TURF_REMOVED_FROM_SHUTTLE, COMSIG_TURF_AFTER_SHUTTLE_MOVE, COMSIG_TURF_ADDED_TO_SHUTTLE))
|
|
|
|
/datum/shuttle_frame/proc/shuttle_leave_react(turf/source)
|
|
SIGNAL_HANDLER
|
|
for(var/obj/docking_port/mobile/custom/shuttle as anything in adjacent_shuttles)
|
|
var/list/turfs_tracking_shuttle = adjacent_shuttles[shuttle]
|
|
if(turfs_tracking_shuttle[source])
|
|
turfs_tracking_shuttle -= source
|
|
if(!length(turfs_tracking_shuttle))
|
|
stop_tracking_shuttle(shuttle)
|
|
break
|
|
|
|
/datum/shuttle_frame/proc/shuttle_arrive_react(turf/source)
|
|
SIGNAL_HANDLER
|
|
var/obj/docking_port/mobile/custom/shuttle = SSshuttle.get_containing_shuttle(source)
|
|
if(istype(shuttle))
|
|
start_tracking_shuttle(shuttle)
|
|
adjacent_shuttles[shuttle][source] = TRUE
|
|
|
|
/datum/shuttle_frame/proc/start_tracking_shuttle(obj/docking_port/mobile/custom/shuttle)
|
|
adjacent_shuttles[shuttle] = list()
|
|
|
|
/datum/shuttle_frame/proc/stop_tracking_shuttle(obj/docking_port/mobile/custom/shuttle)
|
|
adjacent_shuttles -= shuttle
|
|
|
|
/datum/shuttle_frame/proc/add_turf(turf/new_turf)
|
|
if(GLOB.shuttle_frames_by_turf[new_turf])
|
|
stack_trace("turf already assigned to shuttle frame")
|
|
return
|
|
turfs[new_turf] = TRUE
|
|
if(SSshuttle.get_containing_shuttle(new_turf))
|
|
shuttle_covered_turfs[new_turf] = TRUE
|
|
if(shuttle_tracking_turfs[new_turf])
|
|
stop_tracking_turf_for_shuttles(new_turf)
|
|
RegisterSignal(new_turf, COMSIG_TURF_ON_SHUTTLE_MOVE, PROC_REF(shuttle_uncover_react))
|
|
RegisterSignal(new_turf, COMSIG_TURF_AFTER_SHUTTLE_MOVE, PROC_REF(shuttle_cover_react))
|
|
GLOB.shuttle_frames_by_turf[new_turf] = src
|
|
for(var/dir in GLOB.cardinals)
|
|
var/turf/neighbor = get_step(new_turf, dir)
|
|
if(turfs[neighbor])
|
|
continue
|
|
start_tracking_turf_for_shuttles(neighbor, REVERSE_DIR(dir))
|
|
|
|
/datum/shuttle_frame/proc/shuttle_cover_react(turf/source)
|
|
shuttle_covered_turfs[source] = TRUE
|
|
|
|
/datum/shuttle_frame/proc/shuttle_uncover_react(turf/source)
|
|
shuttle_covered_turfs -= source
|
|
|
|
/datum/shuttle_frame/proc/add_turfs(list/turfs)
|
|
for(var/turf in turfs)
|
|
add_turf(turf)
|
|
|
|
/datum/shuttle_frame/proc/remove_turf(turf/removed_turf)
|
|
if(possibly_valid_changing_turfs[removed_turf])
|
|
return
|
|
UnregisterSignal(removed_turf, list(COMSIG_TURF_ON_SHUTTLE_MOVE, COMSIG_TURF_AFTER_SHUTTLE_MOVE))
|
|
for(var/dir in GLOB.cardinals)
|
|
var/turf/check_turf = get_step(removed_turf, dir)
|
|
if(!turfs[check_turf])
|
|
shuttle_tracking_turfs[check_turf] &= ~REVERSE_DIR(dir)
|
|
if(!shuttle_tracking_turfs[check_turf])
|
|
stop_tracking_turf_for_shuttles(check_turf)
|
|
continue
|
|
else
|
|
shuttle_tracking_turfs[removed_turf] |= dir
|
|
deferred_update_turfs[check_turf] = TRUE
|
|
shuttle_covered_turfs -= removed_turf
|
|
turfs -= removed_turf
|
|
GLOB.shuttle_frames_by_turf -= removed_turf
|
|
if(!length(turfs))
|
|
qdel(src)
|
|
else
|
|
addtimer(CALLBACK(src, PROC_REF(auto_propagate_turf_removal)), 0, TIMER_UNIQUE | TIMER_DELETE_ME)
|
|
|
|
/datum/shuttle_frame/proc/remove_turfs(list/turfs)
|
|
for(var/turf in turfs)
|
|
remove_turf(turf)
|
|
|
|
/datum/shuttle_frame/proc/auto_propagate_turf_removal()
|
|
var/list/islands = list()
|
|
var/list/island_queues = list()
|
|
for(var/deferred_update_turf in deferred_update_turfs)
|
|
if(!turfs[deferred_update_turf])
|
|
continue
|
|
var/list/new_island = list()
|
|
new_island[deferred_update_turf] = TRUE
|
|
islands += list(list())
|
|
island_queues += list(new_island)
|
|
deferred_update_turfs.Cut()
|
|
var/islands_modified = TRUE
|
|
while(islands_modified && length(islands) > 1)
|
|
islands_modified = FALSE
|
|
for(var/island_idx in 1 to length(islands))
|
|
var/list/island = islands[island_idx]
|
|
var/list/queue = island_queues[island_idx]
|
|
if(!length(queue))
|
|
continue
|
|
var/turf/check_turf = popleft(queue)
|
|
if(!turfs[check_turf])
|
|
continue
|
|
island[check_turf] = TRUE
|
|
islands_modified = TRUE
|
|
var/list/to_enqueue = list()
|
|
for(var/dir in GLOB.cardinals)
|
|
var/turf/next_check_turf = get_step(check_turf, dir)
|
|
if(!(next_check_turf && turfs[next_check_turf]) || island[next_check_turf] || queue[next_check_turf])
|
|
continue
|
|
to_enqueue[next_check_turf] = TRUE
|
|
var/list/merge_indices = list()
|
|
for(var/other_island_idx in 1 to length(islands))
|
|
if(island_idx == other_island_idx)
|
|
continue
|
|
for(var/turf/enqueued_turf as anything in to_enqueue)
|
|
if(islands[other_island_idx][enqueued_turf])
|
|
merge_indices |= other_island_idx
|
|
to_enqueue -= enqueued_turf
|
|
for(var/merge_index in merge_indices)
|
|
island |= islands[merge_index]
|
|
queue |= island_queues[merge_index]
|
|
queue |= to_enqueue
|
|
var/total_removed = 0
|
|
for(var/merge_index in merge_indices)
|
|
var/effective_index = merge_index - total_removed
|
|
islands.Cut(effective_index, effective_index+1)
|
|
island_queues.Cut(effective_index, effective_index+1)
|
|
total_removed++
|
|
if(total_removed)
|
|
break
|
|
if(length(islands) < 2)
|
|
return
|
|
popleft(islands)
|
|
for(var/other_island in islands)
|
|
remove_turfs(other_island)
|
|
new /datum/shuttle_frame(other_island)
|
|
|
|
/proc/assign_shuttle_construction_turf_to_frame(turf/new_turf)
|
|
var/list/adjacent_frames = list()
|
|
for(var/dir in GLOB.cardinals)
|
|
var/turf/neighbor = get_step(new_turf, dir)
|
|
if(!neighbor)
|
|
continue
|
|
var/datum/shuttle_frame/frame = GLOB.shuttle_frames_by_turf[neighbor]
|
|
if(!frame)
|
|
continue
|
|
adjacent_frames |= frame
|
|
switch(length(adjacent_frames))
|
|
if(0)
|
|
new /datum/shuttle_frame(list(new_turf))
|
|
if(1)
|
|
var/datum/shuttle_frame/frame = adjacent_frames[1]
|
|
frame.add_turf(new_turf)
|
|
else
|
|
var/datum/shuttle_frame/frame = popleft(adjacent_frames)
|
|
for(var/datum/shuttle_frame/other_frame as anything in adjacent_frames)
|
|
var/list/turfs = other_frame.turfs.Copy()
|
|
other_frame.remove_turfs(turfs)
|
|
frame.add_turfs(turfs)
|
|
frame.add_turf(new_turf)
|
|
|
|
/// Helper proc that tests to ensure all whiteship templates can spawn at their docking port, and logs their sizes
|
|
/// This should be a unit test, but too much of our other code breaks during shuttle movement, so not yet, not yet.
|
|
/proc/test_whiteship_sizes()
|
|
var/obj/docking_port/stationary/port_type = /obj/docking_port/stationary/picked/whiteship
|
|
var/datum/turf_reservation/docking_yard = SSmapping.request_turf_block_reservation(
|
|
initial(port_type.width),
|
|
initial(port_type.height),
|
|
1,
|
|
)
|
|
var/turf/bottom_left = docking_yard.bottom_left_turfs[1]
|
|
var/turf/spawnpoint = locate(
|
|
bottom_left.x + initial(port_type.dwidth),
|
|
bottom_left.y + initial(port_type.dheight),
|
|
bottom_left.z,
|
|
)
|
|
|
|
var/obj/docking_port/stationary/picked/whiteship/port = new(spawnpoint)
|
|
var/list/ids = port.shuttlekeys
|
|
var/height = 0
|
|
var/width = 0
|
|
var/dheight = 0
|
|
var/dwidth = 0
|
|
var/delta_height = 0
|
|
var/delta_width = 0
|
|
for(var/id in ids)
|
|
var/datum/map_template/shuttle/our_template = SSmapping.shuttle_templates[id]
|
|
// We do a standard load here so any errors will properly runtimes
|
|
var/obj/docking_port/mobile/ship = SSshuttle.action_load(our_template, port)
|
|
if(ship)
|
|
ship.jumpToNullSpace()
|
|
ship = null
|
|
// Yes this is very hacky, but we need to both allow loading a template that's too big to be an error state
|
|
// And actually get the sizing information from every shuttle
|
|
SSshuttle.load_template(our_template)
|
|
var/obj/docking_port/mobile/theoretical_ship = SSshuttle.preview_shuttle
|
|
if(theoretical_ship)
|
|
height = max(theoretical_ship.height, height)
|
|
width = max(theoretical_ship.width, width)
|
|
dheight = max(theoretical_ship.dheight, dheight)
|
|
dwidth = max(theoretical_ship.dwidth, dwidth)
|
|
delta_height = max(theoretical_ship.height - theoretical_ship.dheight, delta_height)
|
|
delta_width = max(theoretical_ship.width - theoretical_ship.dwidth, delta_width)
|
|
theoretical_ship.jumpToNullSpace()
|
|
qdel(port, TRUE)
|
|
log_world("Whiteship sizing information. Use this to set the docking port, and the map size\n\
|
|
Max Height: [height] \n\
|
|
Max Width: [width] \n\
|
|
Max DHeight: [dheight] \n\
|
|
Max DWidth: [dwidth] \n\
|
|
The following are the safest bet for map sizing. Anything smaller then this could in the worst case not fit in the docking port\n\
|
|
Max Combined Width: [height + dheight] \n\
|
|
Max Combinded Height [width + dwidth]")
|
|
|
|
/proc/custom_shuttle_room_check(obj/docking_port/mobile/custom/shuttle, list/neighboring_areas = list(), turf/check_turf)
|
|
if(SSshuttle.get_containing_shuttle(check_turf) != shuttle)
|
|
return EXTRA_ROOM_CHECK_SKIP
|
|
var/area/check_area = check_turf.loc
|
|
if(check_area != shuttle.default_area)
|
|
neighboring_areas[check_area] = TRUE
|
|
return EXTRA_ROOM_CHECK_SKIP
|
|
var/move_mode = MOVE_AREA
|
|
move_mode = check_turf.fromShuttleMove(move_mode = move_mode)
|
|
if(move_mode & (MOVE_CONTENTS | MOVE_TURF))
|
|
return
|
|
for(var/atom/movable/movable as anything in check_turf.contents)
|
|
CHECK_TICK
|
|
if(movable.loc != check_turf)
|
|
continue
|
|
move_mode = movable.hypotheticalShuttleMove(0, move_mode, shuttle)
|
|
if(!(move_mode & (MOVE_CONTENTS | MOVE_TURF)))
|
|
return EXTRA_ROOM_CHECK_SKIP
|
|
|
|
/proc/shuttle_build_check(turf/origin, list/turfs, list/areas)
|
|
var/z = origin.z
|
|
var/using_prepassed_turfs = !!length(turfs)
|
|
if(using_prepassed_turfs && !(turfs[origin]))
|
|
. |= ORIGIN_NOT_ON_SHUTTLE
|
|
if(length(SSshuttle.custom_shuttles) >= CONFIG_GET(number/max_shuttle_count))
|
|
. |= TOO_MANY_SHUTTLES
|
|
var/max_turfs = CONFIG_GET(number/max_shuttle_size)
|
|
if(!using_prepassed_turfs)
|
|
var/datum/shuttle_frame/frame = GLOB.shuttle_frames_by_turf[origin]
|
|
if(!frame)
|
|
. |= ORIGIN_NOT_ON_SHUTTLE
|
|
else
|
|
turfs += (frame.turfs - frame.shuttle_covered_turfs)
|
|
var/turf_count = length(turfs)
|
|
if(turf_count > max_turfs)
|
|
. |= ABOVE_MAX_SHUTTLE_SIZE
|
|
. |= shuttle_area_check(turfs.Copy(), areas, z)
|
|
|
|
/proc/shuttle_expand_check(turf/origin, obj/docking_port/mobile/shuttle, list/turfs, list/areas)
|
|
var/z = origin.z
|
|
var/using_prepassed_turfs = !!length(turfs)
|
|
if(using_prepassed_turfs && !(turfs[origin]))
|
|
. |= ORIGIN_NOT_ON_SHUTTLE
|
|
var/max_turfs = CONFIG_GET(number/max_shuttle_size) - shuttle.turf_count
|
|
var/list/adjacent_shuttles
|
|
if(!using_prepassed_turfs)
|
|
var/datum/shuttle_frame/frame = GLOB.shuttle_frames_by_turf[origin]
|
|
if(!frame)
|
|
. |= ORIGIN_NOT_ON_SHUTTLE
|
|
else
|
|
turfs += (frame.turfs - frame.shuttle_covered_turfs)
|
|
adjacent_shuttles = frame.adjacent_shuttles
|
|
var/turf_count = length(turfs)
|
|
if(turf_count > max_turfs)
|
|
. |= ABOVE_MAX_SHUTTLE_SIZE
|
|
if(adjacent_shuttles && !adjacent_shuttles[shuttle])
|
|
. |= FRAME_NOT_ADJACENT_TO_LINKED_SHUTTLE
|
|
. |= shuttle_area_check(turfs.Copy(), areas, z)
|
|
|
|
/*
|
|
* Check to see if the following conditions are met:
|
|
* 1. All turfs in the region are within whitelisted areas
|
|
* 2. The region does not contain the APC of a non-custom area
|
|
* 3. If the region contains the APC of a custom area, it contains the entire area
|
|
*/
|
|
/proc/shuttle_area_check(list/turfs, list/areas, z)
|
|
for(var/area/custom_area as anything in GLOB.custom_areas)
|
|
var/list/area_turfs = custom_area.get_turfs_by_zlevel(z)
|
|
var/turf_count = length(area_turfs)
|
|
if(!turf_count)
|
|
continue
|
|
var/list/turfs_not_in_frame = area_turfs - turfs
|
|
var/turfs_not_in_frame_count = length(turfs_not_in_frame)
|
|
if(turfs_not_in_frame_count == turf_count)
|
|
continue
|
|
if(turfs_not_in_frame_count)
|
|
if(custom_area.apc)
|
|
var/obj/machinery/power/apc/apc = custom_area.apc
|
|
var/list/wallmount_comps = apc.GetComponents(/datum/component/wall_mounted)
|
|
var/datum/component/wall_mounted/wallmount_comp = length(wallmount_comps) && wallmount_comps[1]
|
|
if(turfs[get_turf(apc)] || (wallmount_comp && turfs[wallmount_comp.hanging_wall_turf]))
|
|
. |= CUSTOM_AREA_NOT_COMPLETELY_CONTAINED
|
|
else if(areas)
|
|
areas[custom_area] = area_turfs - turfs_not_in_frame
|
|
turfs -= area_turfs
|
|
while(length(turfs))
|
|
var/turf/checked_turf = pick(turfs)
|
|
var/area/checked_area = checked_turf.loc
|
|
var/list/area_turfs = checked_area.get_turfs_by_zlevel(z)
|
|
if(!checked_area.allow_shuttle_docking)
|
|
. |= INTERSECTS_NON_WHITELISTED_AREA
|
|
if(checked_area.apc)
|
|
var/obj/machinery/power/apc/apc = checked_area.apc
|
|
var/list/wallmount_comps = apc.GetComponents(/datum/component/wall_mounted)
|
|
var/datum/component/wall_mounted/wallmount_comp = length(wallmount_comps) && wallmount_comps[1]
|
|
if(turfs[get_turf(apc)] || (wallmount_comp && turfs[wallmount_comp.hanging_wall_turf]))
|
|
. |= CONTAINS_APC_OF_NON_CUSTOM_AREA
|
|
turfs -= area_turfs
|
|
|
|
/proc/convert_areas_to_shuttle_areas(list/turfs, list/in_areas, list/out_areas, list/underlying_areas, area_type = /area/shuttle/custom)
|
|
for(var/area/area as anything in in_areas)
|
|
var/area/new_area = new area_type()
|
|
new_area.setup(area.name)
|
|
out_areas += new_area
|
|
var/list/area_turfs = in_areas[area]
|
|
var/datum/component/custom_area/custom_area = area.GetComponent(/datum/component/custom_area)
|
|
if(custom_area)
|
|
underlying_areas += (custom_area.previous_areas & area_turfs)
|
|
set_turfs_to_area(area_turfs, new_area)
|
|
turfs -= area_turfs
|
|
new_area.reg_in_areas_in_z()
|
|
new_area.create_area_lighting_objects()
|
|
new_area.power_change()
|
|
for(var/obj/machinery/door/firedoor/firelock as anything in area.firedoors)
|
|
firelock.CalculateAffectingAreas()
|
|
if(!area.has_contained_turfs())
|
|
qdel(area)
|
|
|
|
/proc/create_shuttle(mob/user, turf/origin, list/turfs, list/areas, shuttle_dir, port_dir = NORTH, area_type = /area/shuttle/custom, docking_port_type = /obj/docking_port/mobile/custom, obj/docking_port/stationary/dock_at, name, id, replace, custom = TRUE, force)
|
|
if(!ispath(docking_port_type, /obj/docking_port/mobile))
|
|
CRASH("docking_port_type must be /obj/docking_port/mobile or a subpath")
|
|
if(!ispath(area_type, /area/shuttle))
|
|
CRASH("area_type must be /area/shuttle or a subpath")
|
|
if(!istype(dock_at))
|
|
dock_at = new(origin)
|
|
dock_at.unregister()
|
|
dock_at.delete_after = TRUE
|
|
dock_at.shuttle_id = null
|
|
var/area/origin_area = get_area(origin)
|
|
dock_at.name = origin_area.name
|
|
dock_at.dir = port_dir
|
|
|
|
var/list/default_area_turfs = turfs.Copy()
|
|
// Convert each custom area into a shuttle area, then remove the affected turfs from the list of turfs to add to the default area
|
|
var/list/shuttle_areas = list()
|
|
var/list/underlying_areas = list()
|
|
convert_areas_to_shuttle_areas(default_area_turfs, areas, shuttle_areas, underlying_areas, area_type)
|
|
for(var/turf/turf as anything in default_area_turfs)
|
|
underlying_areas[turf] = turf.loc
|
|
|
|
// Merge the remaining frame turfs into a default shuttle area
|
|
var/list/affected_areas = list()
|
|
var/area/default_area = new area_type()
|
|
default_area.setup(name)
|
|
set_turfs_to_area(default_area_turfs, default_area, affected_areas)
|
|
default_area.reg_in_areas_in_z()
|
|
default_area.create_area_lighting_objects()
|
|
default_area.power_change()
|
|
for(var/area_name in affected_areas)
|
|
var/area/merged_area = affected_areas[area_name]
|
|
for(var/obj/machinery/door/firedoor/firelock as anything in merged_area.firedoors)
|
|
firelock.CalculateAffectingAreas()
|
|
if(!merged_area.has_contained_turfs())
|
|
qdel(merged_area)
|
|
shuttle_areas.Insert(1, default_area)
|
|
|
|
var/obj/docking_port/mobile/mobile_port = new docking_port_type(origin, shuttle_areas)
|
|
mobile_port.underlying_areas_by_turf += underlying_areas
|
|
mobile_port.name = name
|
|
mobile_port.shuttle_id = id
|
|
mobile_port.port_direction = REVERSE_DIR(shuttle_dir)
|
|
mobile_port.dir = port_dir
|
|
mobile_port.calculate_docking_port_information()
|
|
mobile_port.turf_count = length(turfs)
|
|
|
|
for(var/turf/turf as anything in turfs)
|
|
turf.stack_below_baseturf(/turf/open/floor/plating, /turf/baseturf_skipover/shuttle)
|
|
SEND_SIGNAL(turf, COMSIG_TURF_ADDED_TO_SHUTTLE, mobile_port)
|
|
if(!turf.depth_to_find_baseturf(/turf/baseturf_skipover/shuttle))
|
|
continue
|
|
var/turf/new_ceiling = get_step_multiz(turf, UP) // check if a ceiling is needed
|
|
if(new_ceiling)
|
|
// generate ceiling
|
|
if(!(istype(new_ceiling, /turf/open/floor/engine/hull/ceiling) || new_ceiling.depth_to_find_baseturf(/turf/open/floor/engine/hull/ceiling)))
|
|
if(istype(new_ceiling, /turf/open/openspace) || istype(new_ceiling, /turf/open/space/openspace))
|
|
new_ceiling.place_on_top(/turf/open/floor/engine/hull/ceiling)
|
|
else
|
|
new_ceiling.stack_ontop_of_baseturf(/turf/open/openspace, /turf/open/floor/engine/hull/ceiling)
|
|
new_ceiling.stack_ontop_of_baseturf(/turf/open/space/openspace, /turf/open/floor/engine/hull/ceiling)
|
|
|
|
mobile_port.register(replace, custom)
|
|
if(mobile_port.get_docked() != dock_at)
|
|
mobile_port.initiate_docking(dock_at, force = TRUE)
|
|
|
|
message_admins("[key_name(user)] has created a shuttle at [ADMIN_VERBOSEJMP(origin)].")
|
|
log_shuttle("[key_name(user)] has created a shuttle at [get_area(origin)].")
|
|
|
|
return mobile_port
|
|
|
|
/proc/expand_shuttle(mob/user, obj/docking_port/mobile/shuttle, list/turfs, list/areas)
|
|
var/list/default_area_turfs = turfs.Copy()
|
|
// Convert each custom area into a shuttle area, then remove the affected turfs from the list of turfs to add to the default area
|
|
var/list/shuttle_areas = list()
|
|
var/list/underlying_areas = list()
|
|
convert_areas_to_shuttle_areas(default_area_turfs, areas, shuttle_areas, underlying_areas, shuttle.area_type)
|
|
for(var/turf/turf as anything in default_area_turfs)
|
|
underlying_areas[turf] = turf.loc
|
|
|
|
var/list/affected_areas = list()
|
|
var/area/default_area = shuttle.shuttle_areas[1]
|
|
set_turfs_to_area(default_area_turfs, default_area, affected_areas)
|
|
default_area.power_change()
|
|
|
|
for(var/area_name in affected_areas)
|
|
var/area/merged_area = affected_areas[area_name]
|
|
for(var/obj/machinery/door/firedoor/firelock as anything in merged_area.firedoors)
|
|
firelock.CalculateAffectingAreas()
|
|
if(!merged_area.has_contained_turfs())
|
|
qdel(merged_area)
|
|
|
|
for(var/area/shuttle_area as anything in shuttle_areas)
|
|
shuttle.shuttle_areas[shuttle_area] = TRUE
|
|
|
|
var/list/bounds = shuttle.return_coords()
|
|
var/x0 = bounds[1]
|
|
var/y0 = bounds[2]
|
|
var/x1 = bounds[3]
|
|
var/y1 = bounds[4]
|
|
var/bounds_need_recalculation
|
|
for(var/turf/turf as anything in turfs)
|
|
turf.stack_below_baseturf(/turf/open/floor/plating, /turf/baseturf_skipover/shuttle)
|
|
SEND_SIGNAL(turf, COMSIG_TURF_ADDED_TO_SHUTTLE, shuttle)
|
|
if(turf.depth_to_find_baseturf(/turf/baseturf_skipover/shuttle))
|
|
var/turf/new_ceiling = get_step_multiz(turf, UP) // check if a ceiling is needed
|
|
if(new_ceiling)
|
|
// generate ceiling
|
|
if(!(istype(new_ceiling, /turf/open/floor/engine/hull/ceiling) || new_ceiling.depth_to_find_baseturf(/turf/open/floor/engine/hull/ceiling)))
|
|
if(istype(new_ceiling, /turf/open/openspace) || istype(new_ceiling, /turf/open/space/openspace))
|
|
new_ceiling.place_on_top(/turf/open/floor/engine/hull/ceiling)
|
|
else
|
|
new_ceiling.stack_ontop_of_baseturf(/turf/open/openspace, /turf/open/floor/engine/hull/ceiling)
|
|
new_ceiling.stack_ontop_of_baseturf(/turf/open/space/openspace, /turf/open/floor/engine/hull/ceiling)
|
|
if(bounds_need_recalculation)
|
|
continue
|
|
if(!(ISINRANGE(turf.x, x0, x1) && ISINRANGE(turf.y, y0, y1)))
|
|
bounds_need_recalculation = TRUE
|
|
|
|
shuttle.turf_count += length(turfs)
|
|
shuttle.underlying_areas_by_turf += underlying_areas
|
|
SEND_SIGNAL(shuttle, COMSIG_SHUTTLE_EXPANDED, turfs)
|
|
if(bounds_need_recalculation)
|
|
QDEL_NULL(shuttle.assigned_transit)
|
|
shuttle.calculate_docking_port_information()
|
|
shuttle.initiate_docking(shuttle.get_docked(), force = TRUE)
|
|
|
|
message_admins("[key_name(user)] has expanded [shuttle] at [ADMIN_VERBOSEJMP(user)].")
|
|
log_shuttle("[key_name(user)] expanded [shuttle] at [get_area(user)].")
|
|
|
|
/proc/clear_empty_shuttle_turfs(obj/docking_port/mobile/shuttle)
|
|
var/shuttle_z = shuttle.z
|
|
var/bounds_need_recalculation
|
|
var/docking_port_needs_relocated
|
|
var/list/bounds = shuttle.return_coords()
|
|
var/x0 = bounds[1]
|
|
var/y0 = bounds[2]
|
|
var/x1 = bounds[3]
|
|
var/y1 = bounds[4]
|
|
for(var/area/area as anything in shuttle.shuttle_areas)
|
|
var/list/turfs = area.get_turfs_by_zlevel(shuttle_z)
|
|
turfs = turfs.Copy()
|
|
for(var/turf/turf as anything in turfs)
|
|
var/move_mode = turf.fromShuttleMove(move_mode = MOVE_AREA)
|
|
if(move_mode & (MOVE_TURF | MOVE_CONTENTS))
|
|
continue
|
|
for(var/atom/movable/movable as anything in turf.contents)
|
|
//CHECK_TICK
|
|
if(movable.loc != turf)
|
|
continue
|
|
if(movable == shuttle)
|
|
continue
|
|
move_mode = movable.hypotheticalShuttleMove(0, move_mode, shuttle)
|
|
if(move_mode & (MOVE_TURF | MOVE_CONTENTS))
|
|
continue
|
|
if(shuttle.loc == turf)
|
|
docking_port_needs_relocated = TRUE
|
|
bounds_need_recalculation = TRUE
|
|
var/area/new_area = shuttle.underlying_areas_by_turf[turf]
|
|
if(!istype(new_area))
|
|
new_area = GLOB.areas_by_type[SHUTTLE_DEFAULT_UNDERLYING_AREA]
|
|
if(!istype(new_area))
|
|
new_area = new SHUTTLE_DEFAULT_UNDERLYING_AREA(null)
|
|
shuttle.underlying_areas_by_turf -= turf
|
|
shuttle.turf_count--
|
|
turfs -= turf
|
|
turf.change_area(area, new_area)
|
|
SEND_SIGNAL(turf, COMSIG_TURF_REMOVED_FROM_SHUTTLE, shuttle)
|
|
if(bounds_need_recalculation)
|
|
continue
|
|
if(turf.x == x0 || turf.x == x1 || turf.y == y0 || turf.y == y1)
|
|
bounds_need_recalculation = TRUE
|
|
if(!length(turfs))
|
|
var/obj/docking_port/mobile/custom/as_custom = shuttle
|
|
if(!(istype(as_custom) && area == as_custom.default_area))
|
|
shuttle.shuttle_areas -= area
|
|
qdel(area)
|
|
if(!shuttle.turf_count)
|
|
qdel(shuttle)
|
|
return
|
|
if(docking_port_needs_relocated)
|
|
shuttle.forceMove(pick(shuttle.underlying_areas_by_turf))
|
|
if(bounds_need_recalculation)
|
|
QDEL_NULL(shuttle.assigned_transit)
|
|
shuttle.calculate_docking_port_information()
|