Files
Bubberstation/code/modules/shuttle/on_move.dm
Archemagus 4ec4fffeeb Enchanced docking behaviour for airlock_pump (#86944)
## About The Pull Request
Now after docking pump measure pressure on docked airlock, if it's in
safe range both airlock sides will open for easy boarding process,
instead just switching them like access airlocks

If docked entity pressure is lower then internal, then airlock will
cycle only to external pressure, not to vacuum.
Also if opening airlocks, eash door also measures external pressure, to
safe the day from bad pilot, when half of doors docked and other half
still looking into space.

With new qol features pump now automatically detects docking\undocking
to minimize vacuuming and extra headbumps.

Described behaviours tested, and work even for airlocks installed on
shuttles, evac included, but night coding is messy, so a review will be
nice.

## Why It's Good For The Game

If engis decide to build custom departure this feature should prevent
crew from screaming "Malf AI" and speed up boarding\unboarding process
(May be after this people will start to love those pumps)

## Changelog
🆑
qol: Airlock_pump now dock with shuttles in more pleasant way
/🆑
2024-11-11 00:43:36 -08:00

412 lines
15 KiB
Plaintext

/*
All ShuttleMove procs go here
*/
/************************************Base procs************************************/
// Called on every turf in the shuttle region, returns a bitflag for allowed movements of that turf
// returns the new move_mode (based on the old)
/turf/proc/fromShuttleMove(turf/newT, move_mode)
if(!(move_mode & MOVE_AREA) || !isshuttleturf(src))
return move_mode
return move_mode | MOVE_TURF | MOVE_CONTENTS
// Called from the new turf before anything has been moved
// Only gets called if fromShuttleMove returns true first
// returns the new move_mode (based on the old)
/turf/proc/toShuttleMove(turf/oldT, move_mode, obj/docking_port/mobile/shuttle)
. = move_mode
if(!(. & MOVE_TURF))
return
var/shuttle_dir = shuttle.dir
for(var/atom/movable/thing as anything in contents)
if(thing.resistance_flags & SHUTTLE_CRUSH_PROOF)
continue
if(isliving(thing))
var/mob/living/living_thing = thing
if(living_thing.incorporeal_move) // Don't crush incorporeal things
continue
living_thing.buckled?.unbuckle_mob(living_thing, force = TRUE)
living_thing.pulledby?.stop_pulling()
living_thing.stop_pulling()
living_thing.visible_message(span_warning("[shuttle] slams into [living_thing]!"))
SSblackbox.record_feedback("tally", "shuttle_gib", 1, living_thing.type)
log_shuttle("[key_name(living_thing)] was shuttle gibbed by [shuttle].")
living_thing.investigate_log("has been gibbed by [shuttle].", INVESTIGATE_DEATHS)
living_thing.gib(DROP_ALL_REMAINS)
else if(!ismob(thing)) //non-living mobs shouldn't be affected by shuttles, which is why this is an else
if(!thing.anchored)
step(thing, shuttle_dir)
else
qdel(thing)
// Called on the old turf to move the turf data
/turf/proc/onShuttleMove(turf/newT, list/movement_force, move_dir)
if(newT == src) // In case of in place shuttle rotation shenanigans.
return
// Destination turf changes.
// Baseturfs is definitely a list or this proc wouldnt be called.
var/shuttle_depth = depth_to_find_baseturf(/turf/baseturf_skipover/shuttle)
if(!shuttle_depth)
CRASH("A turf queued to move via shuttle somehow had no skipover in baseturfs. [src]([type]):[loc]")
//SKYRAT EDIT ADDITION
if(newT.lgroup)
newT.lgroup.remove_from_group(newT)
if(newT.liquids)
if(newT.liquids.immutable)
newT.liquids.remove_turf(src)
else
qdel(newT.liquids, TRUE)
if(lgroup)
lgroup.remove_from_group(src)
if(liquids)
liquids.ChangeToNewTurf(newT)
newT.reasses_liquids()
//SKYRAT EDIT END
newT.CopyOnTop(src, 1, shuttle_depth, TRUE)
newT.blocks_air = TRUE
newT.air_update_turf(TRUE, FALSE)
blocks_air = TRUE
air_update_turf(TRUE, TRUE)
if(isopenturf(newT))
var/turf/open/new_open = newT
new_open.copy_air_with_tile(src)
SEND_SIGNAL(src, COMSIG_TURF_ON_SHUTTLE_MOVE, newT)
return TRUE
// Called on the new turf after everything has been moved
/turf/proc/afterShuttleMove(turf/oldT, rotation)
//Dealing with the turf we left behind
oldT.TransferComponents(src)
SSexplosions.wipe_turf(src)
var/shuttle_depth = depth_to_find_baseturf(/turf/baseturf_skipover/shuttle)
if(shuttle_depth)
oldT.ScrapeAway(shuttle_depth)
if(rotation)
shuttleRotate(rotation) //see shuttle_rotate.dm
return TRUE
/turf/proc/lateShuttleMove(turf/oldT)
blocks_air = initial(blocks_air)
air_update_turf(TRUE, blocks_air)
oldT.blocks_air = initial(oldT.blocks_air)
oldT.air_update_turf(TRUE, oldT.blocks_air)
/////////////////////////////////////////////////////////////////////////////////////
// Called on every atom in shuttle turf contents before anything has been moved
// returns the new move_mode (based on the old)
// WARNING: Do not leave turf contents in beforeShuttleMove or dock() will runtime
/atom/movable/proc/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
return move_mode
/// Called on atoms to move the atom to the new location
/atom/movable/proc/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
if(newT == oldT) // In case of in place shuttle rotation shenanigans.
return
if(loc != oldT) // This is for multi tile objects
return
abstract_move(newT)
return TRUE
// Called on atoms after everything has been moved
/atom/movable/proc/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
SEND_SIGNAL(src, COMSIG_ATOM_AFTER_SHUTTLE_MOVE, oldT)
if(light)
update_light()
if(rotation)
shuttleRotate(rotation)
return TRUE
/atom/movable/proc/lateShuttleMove(turf/oldT, list/movement_force, move_dir)
if(!movement_force || anchored)
return
var/throw_force = movement_force["THROW"]
if(!throw_force)
return
var/turf/target = get_edge_target_turf(src, move_dir)
var/range = throw_force * 10
range = CEILING(rand(range-(range*0.1), range+(range*0.1)), 10)/10
var/speed = range/5
safe_throw_at(target, range, speed, force = MOVE_FORCE_EXTREMELY_STRONG)
/////////////////////////////////////////////////////////////////////////////////////
// Called on areas before anything has been moved
// returns the new move_mode (based on the old)
/area/proc/beforeShuttleMove(list/shuttle_areas)
if(!shuttle_areas[src])
return NONE
return MOVE_AREA
// Called on areas to move their turf between areas
/area/proc/onShuttleMove(turf/oldT, turf/newT, area/underlying_old_area)
if(newT == oldT) // In case of in place shuttle rotation shenanigans.
return TRUE
oldT.change_area(src, underlying_old_area)
//The old turf has now been given back to the area that turf originaly belonged to
var/area/old_dest_area = newT.loc
parallax_movedir = old_dest_area.parallax_movedir
newT.change_area(old_dest_area, src)
return TRUE
// Called on areas after everything has been moved
/area/proc/afterShuttleMove(new_parallax_dir)
parallax_movedir = new_parallax_dir
return TRUE
/area/proc/lateShuttleMove()
return
/************************************Turf move procs************************************/
/************************************Area move procs************************************/
/************************************Machinery move procs************************************/
/obj/machinery/door/airlock/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
if (cycle_pump)
INVOKE_ASYNC(cycle_pump, TYPE_PROC_REF(/obj/machinery/atmospherics/components/unary/airlock_pump, undock))
for(var/obj/machinery/door/airlock/other_airlock in range(2, src)) // includes src, extended because some escape pods have 1 plating turf exposed to space
other_airlock.shuttledocked = FALSE
other_airlock.air_tight = TRUE
if (other_airlock.cycle_pump)
INVOKE_ASYNC(other_airlock.cycle_pump, TYPE_PROC_REF(/obj/machinery/atmospherics/components/unary/airlock_pump, undock))
continue
INVOKE_ASYNC(other_airlock, TYPE_PROC_REF(/obj/machinery/door/, close), FALSE, TRUE) // force crush
/obj/machinery/door/airlock/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
var/current_area = get_area(src)
var/turf/local_turf
var/tile_air_pressure
for(var/obj/machinery/door/airlock/other_airlock in orange(2, src)) // does not include src, extended because some escape pods have 1 plating turf exposed to space
if(get_area(other_airlock) != current_area) // does not include double-wide airlocks unless actually docked
// Cycle linking is only disabled if we are actually adjacent to another airlock
shuttledocked = TRUE
other_airlock.shuttledocked = TRUE
if (other_airlock.cycle_pump)
local_turf = get_step(src, REVERSE_DIR(other_airlock.cycle_pump.dir))
tile_air_pressure = 0
if (local_turf)
tile_air_pressure = max(0, local_turf.return_air().return_pressure())
INVOKE_ASYNC(other_airlock.cycle_pump, TYPE_PROC_REF(/obj/machinery/atmospherics/components/unary/airlock_pump, on_dock_request), tile_air_pressure)
// Save external airlocks turf in case our own docking purpouses
local_turf = get_turf(other_airlock)
if (cycle_pump)
tile_air_pressure = 0
if (local_turf)
local_turf = get_step(local_turf, REVERSE_DIR(cycle_pump.dir))
if (local_turf)
tile_air_pressure = max(0, local_turf.return_air().return_pressure())
INVOKE_ASYNC(cycle_pump, TYPE_PROC_REF(/obj/machinery/atmospherics/components/unary/airlock_pump, on_dock_request), tile_air_pressure)
else
// In case, somebody decides to build an airlock on evac shuttle, we count CentComs blastdoors as valid docking airlock
local_turf = get_step(src, REVERSE_DIR(cycle_pump.dir))
if (local_turf)
for(var/obj/machinery/door/poddoor/shuttledock/centcom_airlock in local_turf)
// For some reason on docking moment those tiles are vacuum, and pump denies safe_dock attempt
// To fix this we're lying, that external pressure is nominal
INVOKE_ASYNC(cycle_pump, TYPE_PROC_REF(/obj/machinery/atmospherics/components/unary/airlock_pump, on_dock_request), ONE_ATMOSPHERE)
break
/obj/machinery/camera/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
if(. & MOVE_AREA)
. |= MOVE_CONTENTS
GLOB.cameranet.removeCamera(src)
/obj/machinery/camera/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
GLOB.cameranet.addCamera(src)
/obj/machinery/mech_bay_recharge_port/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir)
. = ..()
recharging_turf = get_step(loc, dir)
/obj/machinery/atmospherics/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
if(pipe_vision_img)
pipe_vision_img.loc = loc
/obj/machinery/computer/auxiliary_base/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
if(is_mining_level(z)) //Avoids double logging and landing on other Z-levels due to badminnery
SSblackbox.record_feedback("associative", "colonies_dropped", 1, list("x" = x, "y" = y, "z" = z))
/obj/machinery/atmospherics/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
var/missing_nodes = FALSE
for(var/i in 1 to device_type)
if(nodes[i])
var/obj/machinery/atmospherics/node = nodes[i]
var/connected = FALSE
for(var/D in GLOB.cardinals)
if(node in get_step(src, D))
connected = TRUE
break
if(!connected)
nullify_node(i)
if(!nodes[i])
missing_nodes = TRUE
if(missing_nodes)
atmos_init()
for(var/obj/machinery/atmospherics/A in pipeline_expansion())
A.atmos_init()
if(A.return_pipenet())
A.add_member(src)
SSair.add_to_rebuild_queue(src)
else
// atmos_init() calls update_appearance(), so we don't need to call it
update_appearance()
/obj/machinery/navbeacon/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
GLOB.navbeacons["[z]"] -= src
GLOB.deliverybeacons -= src
/obj/machinery/navbeacon/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
if(codes[NAVBEACON_PATROL_MODE])
if(!GLOB.navbeacons["[z]"])
GLOB.navbeacons["[z]"] = list()
GLOB.navbeacons["[z]"] += src //Register with the patrol list!
if(codes[NAVBEACON_DELIVERY_MODE])
GLOB.deliverybeacons += src
GLOB.deliverybeacontags += location
/************************************Mob move procs************************************/
/mob/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
if(HAS_TRAIT(src, TRAIT_BLOCK_SHUTTLE_MOVEMENT))
return
. = ..()
/mob/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
if(HAS_TRAIT(src, TRAIT_BLOCK_SHUTTLE_MOVEMENT))
return
. = ..()
if(client && movement_force)
var/shake_force = max(movement_force["THROW"], movement_force["KNOCKDOWN"])
if(buckled)
shake_force *= 0.25
shake_camera(src, shake_force, 1)
/mob/living/lateShuttleMove(turf/oldT, list/movement_force, move_dir)
if(buckled)
return
. = ..()
var/knockdown = movement_force["KNOCKDOWN"]
if(knockdown)
Paralyze(knockdown)
/mob/living/simple_animal/hostile/megafauna/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
. = ..()
message_admins("Megafauna [src] [ADMIN_FLW(src)] moved via shuttle from [ADMIN_COORDJMP(oldT)] to [ADMIN_COORDJMP(loc)]")
/************************************Structure move procs************************************/
/obj/structure/grille/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
if(. & MOVE_AREA)
. |= MOVE_CONTENTS
/obj/structure/lattice/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
if(. & MOVE_AREA)
. |= MOVE_CONTENTS
/obj/structure/cable/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
cut_cable_from_powernet(FALSE)
/obj/structure/cable/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
Connect_cable(TRUE)
propagate_if_no_network()
/obj/machinery/power/shuttle_engine/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
if(. & MOVE_AREA)
. |= MOVE_CONTENTS
/obj/structure/ladder/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
if (!(resistance_flags & INDESTRUCTIBLE))
disconnect()
/obj/structure/ladder/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
if (!(resistance_flags & INDESTRUCTIBLE))
LateInitialize()
/obj/structure/ladder/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
if (resistance_flags & INDESTRUCTIBLE)
// simply don't be moved
return FALSE
return ..()
/************************************Misc move procs************************************/
/obj/docking_port/mobile/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
. = ..()
if(moving_dock == src)
. |= MOVE_CONTENTS
// Never move the stationary docking port, otherwise things get WEIRD
/obj/docking_port/stationary/onShuttleMove()
return FALSE
// Holy shit go away
/obj/effect/abstract/z_holder/onShuttleMove()
return FALSE
// Special movable stationary port, for your mothership shenanigans
/obj/docking_port/stationary/movable/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
if(!moving_dock.can_move_docking_ports || old_dock == src)
return FALSE
if(newT == oldT) // In case of in place shuttle rotation shenanigans.
return
if(loc != oldT) // This is for multi tile objects
return
abstract_move(newT)
return TRUE
/obj/docking_port/stationary/public_mining_dock/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock)
shuttle_id = "mining_public" //It will not move with the base, but will become enabled as a docking point.