[MIRROR] multiz movement refactor redux [MDB IGNORE] (#9925)

* multiz movement refactor redux (#62132)

* multiz movement refactor redux

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
SkyratBot
2021-12-07 14:27:12 +01:00
committed by GitHub
parent 736de4147d
commit 463c2fc71d
38 changed files with 497 additions and 260 deletions
@@ -72,3 +72,8 @@
#define COMSIG_MOVABLE_CHANGE_DUCT_LAYER "movable_change_duct_layer"
///Called when a movable is teleported from `do_teleport()`: (destination, channel)
#define COMSIG_MOVABLE_TELEPORTED "movable_teleported"
/// from /mob/living/can_z_move, sent to whatever the mob is buckled to. Only ridable movables should be ridden up or down btw.
#define COMSIG_BUCKLED_CAN_Z_MOVE "ridden_pre_can_z_move"
#define COMPONENT_RIDDEN_STOP_Z_MOVE 1
#define COMPONENT_RIDDEN_ALLOW_Z_MOVE 2
-5
View File
@@ -489,11 +489,6 @@ GLOBAL_LIST_INIT(pda_styles, sort_list(list(MONO, VT, ORBITRON, SHARE)))
//Misc text define. Does 4 spaces. Used as a makeshift tabulator.
#define FOURSPACES "&nbsp;&nbsp;&nbsp;&nbsp;"
// possible bitflag return values of intercept_zImpact(atom/movable/AM, levels = 1) calls
#define FALL_INTERCEPTED (1<<0) //Stops the movable from falling further and crashing on the ground
#define FALL_NO_MESSAGE (1<<1) //Used to suppress the "[A] falls through [old_turf]" messages where it'd make little sense at all, like going downstairs.
#define FALL_STOP_INTERCEPTING (1<<2) //Used in situations where halting the whole "intercept" loop would be better, like supermatter dusting (and thus deleting) the atom.
// Play time / EXP
#define PLAYTIME_HARDCORE_RANDOM 120
+50
View File
@@ -14,3 +14,53 @@ GLOBAL_VAR_INIT(glide_size_multiplier, 1.0)
/// The whole result is then clamped to within the range above.
/// Not very readable but it works
#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((32 / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))
/**
* currently_z_moving defines. Higher numbers mean higher priority.
* This one is for falling down open space from stuff such as deleted tile, pit grate...
*/
#define CURRENTLY_Z_FALLING 1
/// currently_z_moving is set to this in zMove() if 0.
#define CURRENTLY_Z_MOVING_GENERIC 2
/// This one is for falling down open space from movement.
#define CURRENTLY_Z_FALLING_FROM_MOVE 3
/// This one is for going upstairs.
#define CURRENTLY_Z_ASCENDING 4
/// possible bitflag return values of [atom/proc/intercept_zImpact] calls
/// Stops the movable from falling further and crashing on the ground. Example: stairs.
#define FALL_INTERCEPTED (1<<0)
/// Suppresses the "[movable] falls through [old_turf]" message because it'd make little sense in certain contexts like climbing stairs.
#define FALL_NO_MESSAGE (1<<1)
/// Used when the whole intercept_zImpact forvar loop should be stopped. For example: when someone falls into the supermatter and becomes dust.
#define FALL_STOP_INTERCEPTING (1<<2)
/// Used when the grip on a pulled object shouldn't be broken.
#define FALL_RETAIN_PULL (1<<3)
/// Runs check_pulling() by the end of [/atom/movable/proc/zMove] for every movable that's pulling something. Should be kept enabled unless you know what you are doing.
#define ZMOVE_CHECK_PULLING (1<<0)
/// Checks if pulledby is nearby. if not, stop being pulled.
#define ZMOVE_CHECK_PULLEDBY (1<<1)
/// flags for different checks done in [/atom/movable/proc/can_z_move]. Should be self-explainatory.
#define ZMOVE_FALL_CHECKS (1<<2)
#define ZMOVE_CAN_FLY_CHECKS (1<<3)
#define ZMOVE_INCAPACITATED_CHECKS (1<<4)
/// Doesn't call zPassIn() and zPassOut()
#define ZMOVE_IGNORE_OBSTACLES (1<<5)
/// Gives players chat feedbacks if they're unable to move through z levels.
#define ZMOVE_FEEDBACK (1<<6)
/// Whether we check the movable (if it exists) the living mob is buckled on or not.
#define ZMOVE_ALLOW_BUCKLED (1<<7)
/// If the movable is actually ventcrawling vertically.
#define ZMOVE_VENTCRAWLING (1<<8)
/// Includes movables that're either pulled by the source or mobs buckled to it in the list of moving movables.
#define ZMOVE_INCLUDE_PULLED (1<<9)
#define ZMOVE_CHECK_PULLS (ZMOVE_CHECK_PULLING|ZMOVE_CHECK_PULLEDBY)
/// Flags used in "Move Upwards" and "Move Downwards" verbs.
#define ZMOVE_FLIGHT_FLAGS (ZMOVE_CAN_FLY_CHECKS|ZMOVE_INCAPACITATED_CHECKS|ZMOVE_CHECK_PULLS|ZMOVE_ALLOW_BUCKLED)
/// Used when walking upstairs
#define ZMOVE_STAIRS_FLAGS (ZMOVE_CHECK_PULLEDBY|ZMOVE_ALLOW_BUCKLED)
/// Used for falling down open space.
#define ZMOVE_FALL_FLAGS (ZMOVE_FALL_CHECKS|ZMOVE_ALLOW_BUCKLED)
+2 -3
View File
@@ -195,10 +195,9 @@ SUBSYSTEM_DEF(throwing)
if (callback)
callback.Invoke()
if(!thrownthing.zfalling) // I don't think you can zfall while thrown but hey, just in case.
if(!thrownthing.currently_z_moving) // I don't think you can zfall while thrown but hey, just in case.
var/turf/T = get_turf(thrownthing)
if(T && thrownthing.has_gravity(T))
T.zFall(thrownthing)
T?.zFall(thrownthing)
if(thrownthing)
SEND_SIGNAL(thrownthing, COMSIG_MOVABLE_THROW_LANDED, src)
+2 -4
View File
@@ -71,10 +71,8 @@
qdel(src)
return
for(var/t in get_adjacent_open_turfs(living_guy))
var/turf/the_turf = t
if(the_turf.zPassOut(living_guy, DOWN) && living_guy.can_zFall(the_turf))
for(var/turf/the_turf as anything in get_adjacent_open_turfs(living_guy))
if(the_turf.zPassOut(living_guy, DOWN) && living_guy.can_z_move(DOWN, the_turf, z_move_flags = ZMOVE_FALL_FLAGS))
to_chat(living_guy, span_warning("A malevolent force guides you towards the edge..."))
living_guy.throw_at(the_turf, 1, 10, force = MOVE_FORCE_EXTREMELY_STRONG)
if(!permanent)
+12 -3
View File
@@ -63,6 +63,7 @@
RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
RegisterSignal(parent, COMSIG_MOVABLE_BUMP, .proc/vehicle_bump)
RegisterSignal(parent, COMSIG_BUCKLED_CAN_Z_MOVE, .proc/riding_can_z_move)
/**
* This proc handles all of the proc calls to things like set_vehicle_dir_layer() that a type of riding datum needs to call on creation
@@ -128,9 +129,12 @@
vehicle_moved(source, null, new_dir)
/// Check to see if we have all of the necessary bodyparts and not-falling-over statuses we need to stay onboard
/datum/component/riding/proc/ride_check(mob/living/rider)
return
/**
* Check to see if we have all of the necessary bodyparts and not-falling-over statuses we need to stay onboard.
* If not and if consequences is TRUE, well, there'll be consequences.
*/
/datum/component/riding/proc/ride_check(mob/living/rider, consequences = TRUE)
return TRUE
/datum/component/riding/proc/handle_vehicle_offsets(dir)
var/atom/movable/AM = parent
@@ -246,3 +250,8 @@
else
qdel(O)
return TRUE
/// Extra checks before buckled.can_z_move can be called in mob/living/can_z_move()
/datum/component/riding/proc/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
SIGNAL_HANDLER
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
+25 -11
View File
@@ -47,21 +47,21 @@
rider.log_message("started riding [living_parent]", LOG_ATTACK, color="pink")
// this applies to humans and most creatures, but is replaced again for cyborgs
/datum/component/riding/creature/ride_check(mob/living/rider)
/datum/component/riding/creature/ride_check(mob/living/rider, consequences = TRUE)
. = TRUE
var/mob/living/living_parent = parent
var/kick_us_off
if(living_parent.body_position != STANDING_UP) // if we move while on the ground, the rider falls off
kick_us_off = TRUE
. = FALSE
// for piggybacks and (redundant?) borg riding, check if the rider is stunned/restrained
else if((ride_check_flags & RIDER_NEEDS_ARMS) && (HAS_TRAIT(rider, TRAIT_RESTRAINED) || rider.incapacitated(TRUE, TRUE)))
kick_us_off = TRUE
. = FALSE
// for fireman carries, check if the ridden is stunned/restrained
else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || living_parent.incapacitated(TRUE, TRUE)))
kick_us_off = TRUE
. = FALSE
if(!kick_us_off)
return TRUE
if(. || !consequences)
return
rider.visible_message(span_warning("[rider] falls off of [living_parent]!"), \
span_warning("You fall off of [living_parent]!"))
@@ -158,6 +158,20 @@
proc_holder.remove_ranged_ability()
proc_holder.action.Unshare(rider)
/datum/component/riding/creature/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
if(!(z_move_flags & ZMOVE_CAN_FLY_CHECKS))
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
if(!can_be_driven)
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider, "<span class='notice'>[movable_parent] cannot be driven around. Unbuckle from [movable_parent.p_them()] first.<span>")
return COMPONENT_RIDDEN_STOP_Z_MOVE
if(!ride_check(rider, FALSE))
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider, "<span class='warning'>You're unable to ride [movable_parent] right now!</span>")
return COMPONENT_RIDDEN_STOP_Z_MOVE
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
///////Yes, I said humans. No, this won't end well...//////////
/datum/component/riding/creature/human
can_be_driven = FALSE
@@ -259,12 +273,12 @@
/datum/component/riding/creature/cyborg
can_be_driven = FALSE
/datum/component/riding/creature/cyborg/ride_check(mob/living/user)
/datum/component/riding/creature/cyborg/ride_check(mob/living/user, consequences = TRUE)
var/mob/living/silicon/robot/robot_parent = parent
if(!iscarbon(user))
return
var/mob/living/carbon/carbonuser = user
if(!carbonuser.usable_hands)
return TRUE
. = user.usable_hands
if(!. && consequences)
Unbuckle(user)
to_chat(user, span_warning("You can't grab onto [robot_parent] with no hands!"))
@@ -9,6 +9,29 @@
. = ..()
RegisterSignal(parent, COMSIG_RIDDEN_DRIVER_MOVE, .proc/driver_move)
/datum/component/riding/vehicle/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
if(!(z_move_flags & ZMOVE_CAN_FLY_CHECKS))
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
if(!keycheck(rider))
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider, "<span class='warning'>[movable_parent] has no key inserted!</span>")
return COMPONENT_RIDDEN_STOP_Z_MOVE
if(HAS_TRAIT(rider, TRAIT_INCAPACITATED))
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider, "<span class='warning'>You cannot operate [movable_parent] right now!</span>")
return COMPONENT_RIDDEN_STOP_Z_MOVE
if(ride_check_flags & RIDER_NEEDS_LEGS && HAS_TRAIT(rider, TRAIT_FLOORED))
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider, "<span class='warning'>You can't seem to manage that while unable to stand up enough to move [movable_parent]...</span>")
return COMPONENT_RIDDEN_STOP_Z_MOVE
if(ride_check_flags & RIDER_NEEDS_ARMS && HAS_TRAIT(rider, TRAIT_HANDS_BLOCKED))
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider, "<span class='warning'>You can't seem to hold onto [movable_parent] to move it...</span>")
return COMPONENT_RIDDEN_STOP_Z_MOVE
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
/datum/component/riding/vehicle/driver_move(atom/movable/movable_parent, mob/living/user, direction)
if(!COOLDOWN_FINISHED(src, vehicle_move_cooldown))
return COMPONENT_DRIVER_BLOCK_MOVE
+3
View File
@@ -69,6 +69,9 @@
source.movement_type &= ~flag
if((old_state & (FLOATING|FLYING)) && !(source.movement_type & (FLOATING|FLYING)))
stop_floating(source)
var/turf/pitfall = source.loc //Things that don't fly fall in open space.
if(istype(pitfall))
pitfall.zFall(source)
SEND_SIGNAL(source, COMSIG_MOVETYPE_FLAG_DISABLED, flag, old_state)
/// Called when the TRAIT_NO_FLOATING_ANIM trait is added to the movable. Stops it from bobbing up and down.
+1 -1
View File
@@ -9,7 +9,7 @@
#define HOLORECORD_MAX_LENGTH 200
/mob/camera/ai_eye/remote/holo/setLoc()
/mob/camera/ai_eye/remote/holo/setLoc(turf/destination, force_update = FALSE)
. = ..()
var/obj/machinery/holopad/H = origin
H?.move_hologram(eye_user, loc)
+2 -2
View File
@@ -1785,8 +1785,8 @@
filter_data = null
filters = null
/atom/proc/intercept_zImpact(atom/movable/hitting_atom, levels = 1)
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, hitting_atom, levels)
/atom/proc/intercept_zImpact(list/falling_movables, levels = 1)
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, falling_movables, levels)
/// Sets the custom materials for an item.
/atom/proc/set_custom_materials(list/materials, multiplier = 1)
+135 -47
View File
@@ -56,9 +56,9 @@
var/grab_state = 0
var/throwforce = 0
var/datum/component/orbiter/orbiting
var/can_be_z_moved = TRUE
var/zfalling = FALSE
///is the mob currently ascending or descending through z levels?
var/currently_z_moving
/// Either FALSE, [EMISSIVE_BLOCK_GENERIC], or [EMISSIVE_BLOCK_UNIQUE]
var/blocks_emissive = FALSE
@@ -167,20 +167,9 @@
if(emissive_block)
. += emissive_block
/atom/movable/proc/can_zFall(turf/source, levels = 1, turf/target, direction)
if(!direction)
direction = DOWN
if(!source)
source = get_turf(src)
if(!source)
return FALSE
if(!target)
target = get_step_multiz(source, direction)
if(!target)
return FALSE
return !(movement_type & FLYING) && has_gravity(source) && !throwing
/atom/movable/proc/onZImpact(turf/impacted_turf, levels)
/atom/movable/proc/onZImpact(turf/impacted_turf, levels, message = TRUE)
if(message)
visible_message("<span class='danger'>[src] crashes into [impacted_turf]!</span>")
var/atom/highest = impacted_turf
for(var/atom/hurt_atom as anything in impacted_turf.contents)
if(!hurt_atom.density)
@@ -191,23 +180,94 @@
INVOKE_ASYNC(src, .proc/SpinAnimation, 5, 2)
return TRUE
//For physical constraints to travelling up/down.
/atom/movable/proc/can_zTravel(turf/destination, direction)
var/turf/current_turf = get_turf(src)
if(!current_turf)
return FALSE
/*
* The core multi-z movement proc. Used to move a movable through z levels.
* If target is null, it'll be determined by the can_z_move proc, which can potentially return null if
* conditions aren't met (see z_move_flags defines in __DEFINES/movement.dm for info) or if dir isn't set.
* Bear in mind you don't need to set both target and dir when calling this proc, but at least one or two.
* This will set the currently_z_moving to CURRENTLY_Z_MOVING_GENERIC if unset, and then clear it after
* Forcemove().
*
*
* Args:
* * dir: the direction to go, UP or DOWN, only relevant if target is null.
* * target: The target turf to move the src to. Set by can_z_move() if null.
* * z_move_flags: bitflags used for various checks in both this proc and can_z_move(). See __DEFINES/movement.dm.
*/
/atom/movable/proc/zMove(dir, turf/target, z_move_flags = ZMOVE_FLIGHT_FLAGS)
if(!target)
target = can_z_move(dir, get_turf(src), null, z_move_flags)
if(!target)
set_currently_z_moving(FALSE, TRUE)
return FALSE
var/list/moving_movs = get_z_move_affected(z_move_flags)
for(var/atom/movable/movable as anything in moving_movs)
movable.currently_z_moving = currently_z_moving || CURRENTLY_Z_MOVING_GENERIC
movable.forceMove(target)
movable.set_currently_z_moving(FALSE, TRUE)
// This is run after ALL movables have been moved, so pulls don't get broken unless they are actually out of range.
if(z_move_flags & ZMOVE_CHECK_PULLS)
for(var/atom/movable/moved_mov as anything in moving_movs)
if(z_move_flags & ZMOVE_CHECK_PULLEDBY && moved_mov.pulledby && (moved_mov.z != moved_mov.pulledby.z || get_dist(moved_mov, moved_mov.pulledby) > 1))
moved_mov.pulledby.stop_pulling()
if(z_move_flags & ZMOVE_CHECK_PULLING)
moved_mov.check_pulling(TRUE)
return TRUE
/// Returns a list of movables that should also be affected when src moves through zlevels, and src.
/atom/movable/proc/get_z_move_affected(z_move_flags)
. = list(src)
if(buckled_mobs)
. |= buckled_mobs
if(!(z_move_flags & ZMOVE_INCLUDE_PULLED))
return
for(var/mob/living/buckled as anything in buckled_mobs)
if(buckled.pulling)
. |= buckled.pulling
if(pulling)
. |= pulling
/**
* Checks if the destination turf is elegible for z movement from the start turf to a given direction and returns it if so.
* Args:
* * direction: the direction to go, UP or DOWN, only relevant if target is null.
* * start: Each destination has a starting point on the other end. This is it. Most of the times the location of the source.
* * z_move_flags: bitflags used for various checks. See __DEFINES/movement.dm.
* * rider: A living mob in control of the movable. Only non-null when a mob is riding a vehicle through z-levels.
*/
/atom/movable/proc/can_z_move(direction, turf/start, turf/destination, z_move_flags = ZMOVE_FLIGHT_FLAGS, mob/living/rider)
if(!start)
start = get_turf(src)
if(!start)
return FALSE
if(!direction)
if(!destination)
return FALSE
direction = get_dir(current_turf, destination)
direction = get_dir_multiz(start, destination)
if(direction != UP && direction != DOWN)
return FALSE
if(!destination)
destination = get_step_multiz(src, direction)
destination = get_step_multiz(start, direction)
if(!destination)
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider || src, "<span class='warning'>There's nowhere to go in that direction!</span>")
return FALSE
return current_turf.zPassOut(src, direction, destination) && destination.zPassIn(src, direction, current_turf)
if(z_move_flags & ZMOVE_FALL_CHECKS && (throwing || (movement_type & (FLYING|FLOATING)) || !has_gravity(start)))
return FALSE
if(z_move_flags & ZMOVE_CAN_FLY_CHECKS && !(movement_type & (FLYING|FLOATING)) && has_gravity(start))
if(z_move_flags & ZMOVE_FEEDBACK)
if(rider)
to_chat(rider, "<span class='notice'>[src] is is not capable of flight.<span>")
else
to_chat(src, "<span class='notice'>You are not Superman.<span>")
return FALSE
if(!(z_move_flags & ZMOVE_IGNORE_OBSTACLES) && !(start.zPassOut(src, direction, destination) && destination.zPassIn(src, direction, start)))
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider || src, "<span class='warning'>You couldn't move there!</span>")
return FALSE
return destination //used by some child types checks and zMove()
/atom/movable/vv_edit_var(var_name, var_value)
var/static/list/banned_edits = list("step_x" = TRUE, "step_y" = TRUE, "step_size" = TRUE, "bounds" = TRUE)
@@ -336,23 +396,22 @@
var/mob/living/pulled_mob = moving_atom
set_pull_offsets(pulled_mob, grab_state)
/atom/movable/proc/check_pulling()
/**
* Checks if the pulling and pulledby should be stopped because they're out of reach.
* If z_allowed is TRUE, the z level of the pulling will be ignored.This is to allow things to be dragged up and down stairs.
*/
/atom/movable/proc/check_pulling(only_pulling = FALSE, z_allowed = FALSE)
if(pulling)
var/atom/movable/pullee = pulling
if(pullee && get_dist(src, pullee) > 1)
if(get_dist(src, pulling) > 1 || (z != pulling.z && !z_allowed))
stop_pulling()
return
if(!isturf(loc))
else if(!isturf(loc))
stop_pulling()
return
if(pullee && !isturf(pullee.loc) && pullee.loc != loc) //to be removed once all code that changes an object's loc uses forceMove().
log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.")
else if(pulling && !isturf(pulling.loc) && pulling.loc != loc) //to be removed once all code that changes an object's loc uses forceMove().
log_game("DEBUG:[src]'s pull on [pulling] wasn't broken despite [pulling] being in [pulling.loc]. Pull stopped manually.")
stop_pulling()
return
if(pulling.anchored || pulling.move_resist > move_force)
else if(pulling.anchored || pulling.move_resist > move_force)
stop_pulling()
return
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move.
if(!only_pulling && pulledby && moving_diagonally != FIRST_DIAG_STEP && (get_dist(src, pulledby) > 1 || z != pulledby.z)) //separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
@@ -457,7 +516,7 @@
var/atom/movable/pullee = pulling
var/turf/current_turf = loc
if(!moving_from_pull)
check_pulling()
check_pulling(z_allowed = TRUE)
if(!loc || !newloc)
return FALSE
var/atom/oldloc = loc
@@ -524,18 +583,26 @@
if(!loc || (loc == oldloc && oldloc != newloc))
last_move = 0
set_currently_z_moving(FALSE, TRUE)
return
if(. && pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move.
if(pulling.anchored)
stop_pulling()
else
var/pull_dir = get_dir(src, pulling)
//puller and pullee more than one tile away or in diagonal position and whatever the pullee is pulling isn't already moving from a pull as it'll most likely result in an infinite loop a la ouroborus.
if(!pulling.pulling?.moving_from_pull && (get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))))
pulling.moving_from_pull = src
pulling.Move(current_turf, get_dir(pulling, current_turf), glide_size) //the pullee tries to reach our previous position
pulling.moving_from_pull = null
if(!pulling.pulling?.moving_from_pull)
var/pull_dir = get_dir(pulling, src)
var/target_turf = current_turf
// Pulling things down/up stairs. zMove() has flags for check_pulling and stop_pulling calls.
// You may wonder why we're not just forcemoving the pulling movable and regrabbing it.
// The answer is simple. forcemoving and regrabbing is ugly and breaks conga lines.
if(pulling.z != z)
target_turf = get_step(pulling, get_dir(pulling, current_turf))
if(target_turf != current_turf || (moving_diagonally != SECOND_DIAG_STEP && ISDIAGONALDIR(pull_dir)) || get_dist(src, pulling) > 1)
pulling.move_from_pull(src, target_turf, glide_size)
check_pulling()
@@ -549,8 +616,20 @@
if(set_dir_on_move)
setDir(direct)
if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct, glide_size_override)) //movement failed due to buckled mob(s)
return FALSE
. = FALSE
if(currently_z_moving)
if(. && loc == newloc)
var/turf/pitfall = get_turf(src)
pitfall.zFall(src, falling_from_move = TRUE)
else
set_currently_z_moving(FALSE, TRUE)
/// Called when src is being moved to a target turf because another movable (puller) is moving around.
/atom/movable/proc/move_from_pull(atom/movable/puller, turf/target_turf, glide_size_override)
moving_from_pull = puller
Move(target_turf, get_dir(src, target_turf), glide_size_override)
moving_from_pull = null
/**
* Called after a successful Move(). By this point, we've already moved.
@@ -586,7 +665,6 @@
return TRUE
// Make sure you know what you're doing if you call this, this is intended to only be called by byond directly.
// You probably want CanPass()
/atom/movable/Cross(atom/movable/crossed_atom)
@@ -704,6 +782,15 @@
anchored = anchorvalue
SEND_SIGNAL(src, COMSIG_MOVABLE_SET_ANCHORED, anchorvalue)
/// Sets the currently_z_moving variable to a new value. Used to allow some zMovement sources to have precedence over others.
/atom/movable/proc/set_currently_z_moving(new_z_moving_value, forced = FALSE)
if(forced)
currently_z_moving = new_z_moving_value
return TRUE
var/old_z_moving_value = currently_z_moving
currently_z_moving = max(currently_z_moving, new_z_moving_value)
return currently_z_moving > old_z_moving_value
/atom/movable/proc/forceMove(atom/destination)
. = FALSE
if(destination)
@@ -719,7 +806,8 @@
move_stacks++
var/atom/oldloc = loc
if(destination)
if(pulledby)
///zMove already handles whether a pull from another movable should be broken.
if(pulledby && !currently_z_moving)
pulledby.stop_pulling()
var/same_loc = oldloc == destination
var/area/old_area = get_area(oldloc)
@@ -924,7 +1012,7 @@
/atom/movable/proc/handle_buckled_mob_movement(newloc, direct, glide_size_override)
for(var/mob/living/buckled_mob as anything in buckled_mobs)
if(!buckled_mob.Move(newloc, direct, glide_size_override))
if(buckled_mob.loc != newloc && !buckled_mob.Move(newloc, direct, glide_size_override))
Move(buckled_mob.loc, direct)
last_move = buckled_mob.last_move
inertia_dir = last_move
@@ -209,13 +209,7 @@
return eye_user.client
return null
/mob/camera/ai_eye/remote/xenobio/canZMove(direction, turf/target)
var/area/new_area = get_area(target)
if(new_area && new_area.name == allowed_area || new_area && (new_area.area_flags & XENOBIOLOGY_COMPATIBLE))
return TRUE
return FALSE
/mob/camera/ai_eye/remote/setLoc(destination)
/mob/camera/ai_eye/remote/setLoc(turf/destination, force_update = FALSE)
if(eye_user)
destination = get_turf(destination)
if (destination)
@@ -315,7 +309,7 @@
return
var/mob/living/user_mob = target
var/mob/camera/ai_eye/remote/remote_eye = user_mob.remote_control
if(remote_eye.zMove(UP, FALSE))
if(remote_eye.zMove(UP))
to_chat(user_mob, span_notice("You move upwards."))
else
to_chat(user_mob, span_notice("You couldn't move upwards!"))
@@ -330,7 +324,7 @@
return
var/mob/living/user_mob = target
var/mob/camera/ai_eye/remote/remote_eye = user_mob.remote_control
if(remote_eye.zMove(DOWN, FALSE))
if(remote_eye.zMove(DOWN))
to_chat(user_mob, span_notice("You move downwards."))
else
to_chat(user_mob, span_notice("You couldn't move downwards!"))
+9 -4
View File
@@ -138,7 +138,7 @@
* buckled_mob - The mob to be unbuckled
* force - TRUE if we should ignore buckled_mob.can_buckle_to
*/
/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force = FALSE)
/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force = FALSE, can_fall = TRUE)
if(!isliving(buckled_mob))
CRASH("Non-living [buckled_mob] thing called unbuckle_mob() for source.")
if(buckled_mob.buckled != src)
@@ -157,12 +157,17 @@
UnregisterSignal(src, COMSIG_MOVABLE_SET_ANCHORED)
SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)
var/turf/location = buckled_mob.loc
if(istype(location) && !buckled_mob.zfalling)
location.zFall(buckled_mob)
if(can_fall)
var/turf/location = buckled_mob.loc
if(istype(location) && !buckled_mob.currently_z_moving)
location.zFall(buckled_mob)
post_unbuckle_mob(.)
if(!QDELETED(buckled_mob) && !buckled_mob.currently_z_moving && isturf(buckled_mob.loc)) // In the case they unbuckled to a flying movable midflight.
var/turf/pitfall = buckled_mob.loc
pitfall?.zFall(buckled_mob)
/atom/movable/proc/on_set_anchored(atom/movable/source, anchorvalue)
SIGNAL_HANDLER
for(var/_buckled_mob in buckled_mobs)
+1 -1
View File
@@ -93,7 +93,7 @@
/obj/item/storage/box/mime/Moved(oldLoc, dir)
if (iscarbon(oldLoc))
alpha = 0
..()
return ..()
//Disk boxes
+1 -1
View File
@@ -164,7 +164,7 @@
if(..())
buckled_mob.pixel_y += 13
/obj/structure/bonfire/unbuckle_mob(mob/living/buckled_mob, force=FALSE)
/obj/structure/bonfire/unbuckle_mob(mob/living/buckled_mob, force = FALSE, can_fall = TRUE)
if(..())
buckled_mob.pixel_y -= 13
@@ -118,7 +118,7 @@
return INITIALIZE_HINT_QDEL
return ..()
/mob/camera/ai_eye/remote/base_construction/setLoc(destination)
/mob/camera/ai_eye/remote/base_construction/setLoc(turf/destination, force_update = FALSE)
var/area/curr_area = get_area(destination)
//Only move if we're in the allowed area. If no allowed area is defined, then we're free to move wherever.
if(!linked_console.allowed_area || istype(curr_area, linked_console.allowed_area))
@@ -60,7 +60,7 @@
//BUCKLE HOOKS
/obj/machinery/deployable_turret/unbuckle_mob(mob/living/buckled_mob,force = FALSE)
/obj/machinery/deployable_turret/unbuckle_mob(mob/living/buckled_mob, force = FALSE, can_fall = TRUE)
playsound(src,'sound/mecha/mechmove01.ogg', 50, TRUE)
for(var/obj/item/I in buckled_mob.held_items)
if(istype(I, /obj/item/gun_control))
+3 -15
View File
@@ -77,21 +77,9 @@
return
show_fluff_message(going_up, user)
var/turf/T = get_turf(ladder)
var/atom/movable/AM
if(user.pulling)
AM = user.pulling
AM.forceMove(T)
user.forceMove(T)
if(AM)
user.start_pulling(AM)
//reopening ladder radial menu ahead
T = get_turf(user)
var/obj/structure/ladder/ladder_structure = locate() in T
if (ladder_structure)
ladder_structure.use(user)
var/turf/target = get_turf(ladder)
user.zMove(target = target, z_move_flags = ZMOVE_CHECK_PULLEDBY|ZMOVE_ALLOW_BUCKLED|ZMOVE_INCLUDE_PULLED)
ladder.use(user) //reopening ladder radial menu ahead
/obj/structure/ladder/proc/use(mob/user, is_ghost=FALSE)
if (!is_ghost && !in_range(src, user))
+14 -16
View File
@@ -64,9 +64,10 @@
SIGNAL_HANDLER
if(leaving == src)
return // Let's not block ourselves.
return //Let's not block ourselves.
if(!isobserver(leaving) && isTerminator() && direction == dir)
leaving.set_currently_z_moving(CURRENTLY_Z_ASCENDING)
INVOKE_ASYNC(src, .proc/stair_ascend, leaving)
leaving.Bump(src)
return COMPONENT_ATOM_BLOCK_EXIT
@@ -80,23 +81,20 @@
icon_state = "stairs[isTerminator() ? "_t" : null]"
return ..()
/obj/structure/stairs/proc/stair_ascend(atom/movable/AM)
/obj/structure/stairs/proc/stair_ascend(atom/movable/climber)
var/turf/checking = get_step_multiz(get_turf(src), UP)
if(!istype(checking))
return
if(!checking.zPassIn(AM, UP, get_turf(src)))
if(!checking.zPassIn(climber, UP, get_turf(src)))
return
var/turf/target = get_step_multiz(get_turf(src), (dir|UP))
if(istype(target) && !target.can_zFall(AM, null, get_step_multiz(target, DOWN))) //Don't throw them into a tile that will just dump them back down.
if(isliving(AM))
var/mob/living/L = AM
var/pulling = L.pulling
if(pulling)
L.pulling.forceMove(target)
L.forceMove(target)
L.start_pulling(pulling)
else
AM.forceMove(target)
if(istype(target) && !climber.can_z_move(DOWN, target, z_move_flags = ZMOVE_FALL_FLAGS)) //Don't throw them into a tile that will just dump them back down.
climber.zMove(target = target, z_move_flags = ZMOVE_STAIRS_FLAGS)
/// Moves anything that's being dragged by src or anything buckled to it to the stairs turf.
climber.pulling?.move_from_pull(climber, loc, climber.glide_size)
for(var/mob/living/buckled as anything in climber.buckled_mobs)
buckled.pulling?.move_from_pull(buckled, loc, buckled.glide_size)
/obj/structure/stairs/vv_edit_var(var_name, var_value)
. = ..()
@@ -132,10 +130,10 @@
if(T && !istype(T))
T.ChangeTurf(/turf/open/openspace, flags = CHANGETURF_INHERIT_AIR)
/obj/structure/stairs/intercept_zImpact(atom/movable/AM, levels = 1)
/obj/structure/stairs/intercept_zImpact(list/falling_movables, levels = 1)
. = ..()
if(isTerminator())
. |= FALL_INTERCEPTED | FALL_NO_MESSAGE
if(levels == 1 && isTerminator()) // Stairs won't save you from a steep fall.
. |= FALL_INTERCEPTED | FALL_NO_MESSAGE | FALL_RETAIN_PULL
/obj/structure/stairs/proc/isTerminator() //If this is the last stair in a chain and should move mobs up
if(terminator_mode != STAIR_TERMINATOR_AUTOMATIC)
+37
View File
@@ -32,12 +32,49 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr
/turf/open/openspace/Initialize(mapload) // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker
. = ..()
overlays += GLOB.openspace_backdrop_one_for_all //Special grey square for projecting backdrop darkness filter on it.
RegisterSignal(src, COMSIG_ATOM_CREATED, .proc/on_atom_created)
return INITIALIZE_HINT_LATELOAD
/turf/open/openspace/LateInitialize()
. = ..()
AddElement(/datum/element/turf_z_transparency, FALSE)
/turf/open/openspace/ChangeTurf(path, list/new_baseturfs, flags)
UnregisterSignal(src, COMSIG_ATOM_CREATED)
return ..()
/**
* Prepares a moving movable to be precipitated if Move() is successful.
* This is done in Enter() and not Entered() because there's no easy way to tell
* if the latter was called by Move() or forceMove() while the former is only called by Move().
*/
/turf/open/openspace/Enter(atom/movable/movable, atom/oldloc)
. = ..()
if(.)
//higher priority than CURRENTLY_Z_FALLING so the movable doesn't fall on Entered()
movable.set_currently_z_moving(CURRENTLY_Z_FALLING_FROM_MOVE)
///Makes movables fall when forceMove()'d to this turf.
/turf/open/openspace/Entered(atom/movable/movable)
. = ..()
if(movable.set_currently_z_moving(CURRENTLY_Z_FALLING))
zFall(movable, falling_from_move = TRUE)
/**
* Drops movables spawned on this turf only after they are successfully initialized.
* so flying mobs, qdeleted movables and things that were moved somewhere else during
* Initialize() won't fall by accident.
*/
/turf/open/openspace/proc/on_atom_created(datum/source, atom/created_atom)
SIGNAL_HANDLER
if(ismovable(created_atom))
//Drop it only when it's finished initializing, not before.
addtimer(CALLBACK(src, .proc/zfall_if_on_turf, created_atom), 0 SECONDS)
/turf/open/openspace/proc/zfall_if_on_turf(atom/movable/movable)
if(QDELETED(movable) || movable.loc != src)
return
zFall(movable)
/turf/open/openspace/can_have_cabling()
if(locate(/obj/structure/lattice/catwalk, src))
return TRUE
+7 -15
View File
@@ -172,7 +172,7 @@
if(!arrived || src != arrived.loc)
return
if(destination_z && destination_x && destination_y && !(arrived.pulledby || !arrived.can_be_z_moved))
if(destination_z && destination_x && destination_y && !arrived.pulledby && !arrived.currently_z_moving)
var/tx = destination_x
var/ty = destination_y
var/turf/DT = locate(tx, ty, destination_z)
@@ -191,21 +191,13 @@
ty--
DT = locate(tx, ty, destination_z)
var/atom/movable/pulling = arrived.pulling
var/atom/movable/puller = arrived
arrived.forceMove(DT)
arrived.zMove(null, DT, ZMOVE_ALLOW_BUCKLED)
while (pulling != null)
var/next_pulling = pulling.pulling
var/turf/T = get_step(puller.loc, turn(puller.dir, 180))
pulling.can_be_z_moved = FALSE
pulling.forceMove(T)
puller.start_pulling(pulling)
pulling.can_be_z_moved = TRUE
puller = pulling
pulling = next_pulling
var/atom/movable/current_pull = arrived.pulling
while (current_pull)
var/turf/target_turf = get_step(current_pull.pulledby.loc, REVERSE_DIR(current_pull.pulledby.dir)) || current_pull.pulledby.loc
current_pull.zMove(null, target_turf, ZMOVE_ALLOW_BUCKLED)
current_pull = current_pull.pulling
/turf/open/space/MakeSlippery(wet_setting, min_wet_time, wet_time_to_add, max_wet_time, permanent)
+44 -28
View File
@@ -260,38 +260,56 @@ GLOBAL_LIST_EMPTY(station_turfs)
/turf/proc/zAirOut(direction, turf/source)
return FALSE
/turf/proc/zImpact(atom/movable/A, levels = 1, turf/prev_turf)
/// Precipitates a movable (plus whatever buckled to it) to lower z levels if possible and then calls zImpact()
/turf/proc/zFall(atom/movable/falling, levels = 1, force = FALSE, falling_from_move = FALSE)
var/turf/target = get_step_multiz(src, DOWN)
if(!target)
return FALSE
var/isliving = isliving(falling)
if(!isliving && !isobj(falling))
return
if(isliving)
var/mob/living/falling_living = falling
//relay this mess to whatever the mob is buckled to.
if(falling_living.buckled)
falling = falling_living.buckled
if(!falling_from_move && falling.currently_z_moving)
return
if(!force && !falling.can_z_move(DOWN, src, target, ZMOVE_FALL_FLAGS))
falling.set_currently_z_moving(FALSE, TRUE)
return FALSE
// So it doesn't trigger other zFall calls. Cleared on zMove.
falling.set_currently_z_moving(CURRENTLY_Z_FALLING)
falling.zMove(null, target, ZMOVE_CHECK_PULLEDBY)
target.zImpact(falling, levels, src)
return TRUE
///Called each time the target falls down a z level possibly making their trajectory come to a halt. see __DEFINES/movement.dm.
/turf/proc/zImpact(atom/movable/falling, levels = 1, turf/prev_turf)
var/flags = NONE
var/mov_name = A.name
var/list/falling_movables = falling.get_z_move_affected()
var/list/falling_mov_names
for(var/atom/movable/falling_mov as anything in falling_movables)
falling_mov_names += falling_mov.name
for(var/i in contents)
var/atom/thing = i
flags |= thing.intercept_zImpact(A, levels)
flags |= thing.intercept_zImpact(falling_movables, levels)
if(flags & FALL_STOP_INTERCEPTING)
break
if(prev_turf && !(flags & FALL_NO_MESSAGE))
prev_turf.visible_message(span_danger("[mov_name] falls through [prev_turf]!"))
if(flags & FALL_INTERCEPTED)
return
if(zFall(A, levels + 1))
for(var/mov_name in falling_mov_names)
prev_turf.visible_message(span_danger("[mov_name] falls through [prev_turf]!"))
if(!(flags & FALL_INTERCEPTED) && zFall(falling, levels + 1))
return FALSE
A.visible_message(span_danger("[A] crashes into [src]!"))
A.onZImpact(src, levels)
return TRUE
/turf/proc/can_zFall(atom/movable/A, levels = 1, turf/target)
SHOULD_BE_PURE(TRUE)
return zPassOut(A, DOWN, target) && target.zPassIn(A, DOWN, src)
/turf/proc/zFall(atom/movable/A, levels = 1, force = FALSE)
var/turf/target = get_step_multiz(src, DOWN)
if(!target || (!isobj(A) && !ismob(A)))
return FALSE
if(!force && (!can_zFall(A, levels, target) || !A.can_zFall(src, levels, target, DOWN)))
return FALSE
A.zfalling = TRUE
A.forceMove(target)
A.zfalling = FALSE
target.zImpact(A, levels, src)
for(var/atom/movable/falling_mov as anything in falling_movables)
if(!(flags & FALL_RETAIN_PULL))
falling_mov.stop_pulling()
if(!(flags & FALL_INTERCEPTED))
falling_mov.onZImpact(src, levels)
if(falling_mov.pulledby && (falling_mov.z != falling_mov.pulledby.z || get_dist(falling_mov, falling_mov.pulledby) > 1))
falling_mov.pulledby.stop_pulling()
return TRUE
/turf/proc/handleRCL(obj/item/rcl/C, mob/user)
@@ -361,14 +379,12 @@ GLOBAL_LIST_EMPTY(station_turfs)
/turf/open/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
..()
. = ..()
//melting
if(isobj(arrived) && air && air.temperature > T0C)
var/obj/O = arrived
if(O.obj_flags & FROZEN)
O.make_unfrozen()
if(!arrived.zfalling)
zFall(arrived)
// A proc in case it needs to be recreated or badmins want to change the baseturfs
/turf/proc/assemble_baseturfs(turf/fake_baseturf_type)
+1 -2
View File
@@ -106,8 +106,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(blobstrain.effectdesc)
to_chat(src, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> strain [blobstrain.effectdesc]")
/mob/camera/blob/can_zFall(turf/source, levels)
// Prevent blob from falling through zlevels
/mob/camera/blob/can_z_move(direction, turf/start, turf/destination, z_move_flags = NONE, mob/living/rider)
return FALSE
/mob/camera/blob/proc/is_valid_turf(turf/T)
@@ -134,6 +134,9 @@ the new instance inside the host to be updated to the template's stats.
follow_next(Dir & NORTHWEST)
last_move_tick = world.time
/mob/camera/disease/can_z_move(direction, turf/start, turf/destination, z_move_flags = NONE, mob/living/rider)
return FALSE
/mob/camera/disease/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
var/atom/movable/to_follow = speaker
+1 -1
View File
@@ -98,7 +98,7 @@
update_openspace()
var/turf/T = get_turf(src)
for(var/atom/movable/AM in T)
if(!AM.zfalling)
if(!AM.currently_z_moving)
T.zFall(AM)
/obj/structure/pitgrate/proc/reset_plane()
@@ -1,2 +1,11 @@
/mob/dead/observer/canZMove(direction, turf/target)
return TRUE
/mob/dead/observer/up()
set name = "Move Upwards"
set category = "IC"
if(zMove(UP, z_move_flags = ZMOVE_FEEDBACK))
to_chat(src, "<span class='notice'>You move upwards.</span>")
/mob/dead/observer/can_z_move(direction, turf/start, turf/destination, z_move_flags = NONE, mob/living/rider)
z_move_flags |= ZMOVE_IGNORE_OBSTACLES //observers do not respect these FLOORS you speak so much of.
return ..()
+17 -18
View File
@@ -41,9 +41,10 @@
QDEL_LAZYLIST(diseases)
return ..()
/mob/living/onZImpact(turf/T, levels)
/mob/living/onZImpact(turf/T, levels, message = TRUE)
if(!isgroundlessturf(T))
ZImpactDamage(T, levels)
message = FALSE
return ..()
/mob/living/proc/ZImpactDamage(turf/T, levels)
@@ -836,9 +837,10 @@
lying_angle_on_movement(direct)
if (buckled && buckled.loc != newloc) //not updating position
if (!buckled.anchored)
return buckled.Move(newloc, direct, glide_size)
else
return FALSE
buckled.moving_from_pull = moving_from_pull
. = buckled.Move(newloc, direct, glide_size)
buckled.moving_from_pull = null
return
var/old_direction = dir
var/turf/T = loc
@@ -848,12 +850,9 @@
. = ..()
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1 && (pulledby != moving_from_pull))//separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
else
if(isliving(pulledby))
var/mob/living/L = pulledby
L.set_pull_offsets(src, pulledby.grab_state)
if(moving_diagonally != FIRST_DIAG_STEP && isliving(pulledby))
var/mob/living/L = pulledby
L.set_pull_offsets(src, pulledby.grab_state)
if(active_storage && !(CanReach(active_storage.parent,view_only = TRUE)))
active_storage.close(src)
@@ -1565,15 +1564,15 @@
return L
/mob/living/forceMove(atom/destination)
stop_pulling()
if(buckled && !HAS_TRAIT(src, TRAIT_CANNOT_BE_UNBUCKLED))
buckled.unbuckle_mob(src, force = TRUE)
if(has_buckled_mobs())
unbuckle_all_mobs(force = TRUE)
if(!currently_z_moving)
stop_pulling()
if(buckled && !HAS_TRAIT(src, TRAIT_CANNOT_BE_UNBUCKLED))
buckled.unbuckle_mob(src, force = TRUE)
if(has_buckled_mobs())
unbuckle_all_mobs(force = TRUE)
. = ..()
if(.)
if(client)
reset_perspective()
if(. && client)
reset_perspective()
/mob/living/proc/update_z(new_z) // 1+ to register, null to unregister
+41 -3
View File
@@ -58,10 +58,48 @@
return
remove_movespeed_modifier(/datum/movespeed_modifier/bulky_drag)
/mob/living/canZMove(dir, turf/target)
/**
* We want to relay the zmovement to the buckled atom when possible
* and only run what we can't have on buckled.zMove() or buckled.can_z_move() here.
* This way we can avoid esoteric bugs, copypasta and inconsistencies.
*/
/mob/living/zMove(dir, turf/target, z_move_flags = ZMOVE_FLIGHT_FLAGS)
if(buckled)
return buckled.can_zTravel(target, dir) && (buckled.movement_type & FLYING | FLOATING)
return can_zTravel(target, dir) && (movement_type & FLYING | FLOATING)
if(buckled.currently_z_moving)
return FALSE
if(!(z_move_flags & ZMOVE_ALLOW_BUCKLED))
buckled.unbuckle_mob(src, force = TRUE, can_fall = FALSE)
else
if(!target)
target = can_z_move(dir, get_turf(src), null, z_move_flags, src)
if(!target)
return FALSE
return buckled.zMove(dir, target, z_move_flags) // Return value is a loc.
return ..()
/mob/living/can_z_move(direction, turf/start, turf/destination, z_move_flags = ZMOVE_FLIGHT_FLAGS, mob/living/rider)
if(z_move_flags & ZMOVE_INCAPACITATED_CHECKS && incapacitated())
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider || src, "<span class='warning'>[rider ? src : "You"] can't do that right now!</span>")
return FALSE
if(!buckled || !(z_move_flags & ZMOVE_ALLOW_BUCKLED))
return ..()
switch(SEND_SIGNAL(buckled, COMSIG_BUCKLED_CAN_Z_MOVE, direction, start, destination, z_move_flags, src))
if(COMPONENT_RIDDEN_ALLOW_Z_MOVE) // Can be ridden.
return buckled.can_z_move(direction, start, destination, z_move_flags, src)
if(COMPONENT_RIDDEN_STOP_Z_MOVE) // Is a ridable but can't be ridden right now. Feedback messages already done.
return FALSE
else
if(!(z_move_flags & ZMOVE_CAN_FLY_CHECKS) && !buckled.anchored)
return buckled.can_z_move(direction, start, destination, z_move_flags, src)
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(src, "<span class='notice'>Unbuckle from [buckled] first.<span>")
return FALSE
/mob/set_currently_z_moving(value)
if(buckled)
return buckled.set_currently_z_moving(value)
return ..()
/mob/living/keybind_face_direction(direction)
if(stat > SOFT_CRIT)
+6 -3
View File
@@ -999,12 +999,15 @@
set name = "Move Upwards"
set category = "IC"
if(zMove(UP, TRUE))
if(eyeobj.zMove(UP, z_move_flags = ZMOVE_FEEDBACK))
to_chat(src, span_notice("You move upwards."))
/mob/living/silicon/ai/zMove(dir, feedback = FALSE)
. = eyeobj.zMove(dir, feedback)
/mob/living/silicon/ai/down()
set name = "Move Down"
set category = "IC"
if(eyeobj.zMove(DOWN, z_move_flags = ZMOVE_FEEDBACK))
to_chat(src, span_notice("You move down."))
/// Proc to hook behavior to the changes of the value of [aiRestorePowerRoutine].
/mob/living/silicon/ai/proc/setAiRestorePowerRoutine(new_value)
@@ -101,24 +101,14 @@
if(ai.master_multicam)
ai.master_multicam.refresh_view()
//it uses setLoc not forceMove, talks to the sillycone and not the camera mob
/mob/camera/ai_eye/zMove(dir, feedback = FALSE)
if(dir != UP && dir != DOWN)
return FALSE
var/turf/target = get_step_multiz(src, dir)
if(!target)
if(feedback)
to_chat(ai, span_warning("There's nowhere to go in that direction!"))
return FALSE
if(!canZMove(dir, target))
if(feedback)
to_chat(ai, span_warning("You couldn't move there!"))
return FALSE
setLoc(target, TRUE)
return TRUE
/mob/camera/ai_eye/zMove(dir, turf/target, z_move_flags = NONE, recursions_left = 1, list/falling_movs)
. = ..()
if(.)
setLoc(loc, force_update = TRUE)
/mob/camera/ai_eye/canZMove(direction, turf/target) //cameras do not respect these FLOORS you speak so much of
return TRUE
/mob/camera/ai_eye/can_z_move(direction, turf/start, turf/destination, z_move_flags = NONE, mob/living/rider)
z_move_flags |= ZMOVE_IGNORE_OBSTACLES //cameras do not respect these FLOORS you speak so much of
return ..()
/mob/camera/ai_eye/Move()
return
@@ -132,7 +132,7 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
if(screen?.ai)
return screen.ai.client
/mob/camera/ai_eye/pic_in_pic/setLoc(turf/destination)
/mob/camera/ai_eye/pic_in_pic/setLoc(turf/destination, force_update = FALSE)
if (destination)
abstract_move(destination)
else
+13 -40
View File
@@ -510,13 +510,20 @@
var/turf/current_turf = get_turf(src)
var/turf/above_turf = SSmapping.get_turf_above(current_turf)
var/ventcrawling_mob = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING)
if(can_zFall(above_turf, 1, current_turf, DOWN) && !ventcrawling_mob) //Will be fall down if we go up?
to_chat(src, "<span class='notice'>You are not Superman.<span>")
var/ventcrawling_flag = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING) ? ZMOVE_VENTCRAWLING : 0
if(!above_turf)
to_chat(src, "<span class='warning'>There's nowhere to go in that direction!</span>")
return
if(zMove(UP, TRUE, ventcrawling_mob))
if(can_z_move(DOWN, above_turf, current_turf, ZMOVE_FALL_FLAGS|ventcrawling_flag)) //Will we fall down if we go up?
if(buckled)
to_chat(src, "<span class='notice'>[buckled] is is not capable of flight.<span>")
else
to_chat(src, "<span class='notice'>You are not Superman.<span>")
return
if(zMove(UP, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag))
to_chat(src, span_notice("You move upwards."))
///Moves a mob down a z level
@@ -524,44 +531,10 @@
set name = "Move Down"
set category = "IC"
var/ventcrawling_mob = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING)
if(zMove(DOWN, TRUE, ventcrawling_mob))
var/ventcrawling_flag = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING) ? ZMOVE_VENTCRAWLING : 0
if(zMove(DOWN, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag))
to_chat(src, span_notice("You move down."))
/mob/can_zFall(turf/source, levels, turf/target, direction)
if(buckled)
return buckled.can_zFall(source, levels, target, direction)
return ..()
///Move a mob between z levels, if it's valid to move z's on this turf
/mob/proc/zMove(dir, feedback = FALSE, ventcrawling = FALSE)
if(dir != UP && dir != DOWN)
return FALSE
if(incapacitated())
if(feedback)
to_chat(src, span_warning("You can't do that right now!"))
return FALSE
var/turf/target = get_step_multiz(src, dir)
if(!target)
if(feedback)
to_chat(src, span_warning("There's nowhere to go in that direction!"))
return FALSE
if(!canZMove(dir, target) && !ventcrawling)
if(feedback)
to_chat(src, span_warning("You couldn't move there!"))
return FALSE
if(!ventcrawling) //let this be handled in atmosmachinery.dm
return Move(target)
else
var/obj/machinery/atmospherics/pipe = loc
pipe.relaymove(src, dir)
return TRUE
/// Can this mob move between z levels
/mob/proc/canZMove(direction, turf/target)
return FALSE
/mob/abstract_move(atom/destination)
var/turf/new_turf = get_turf(destination)
if(is_secret_level(new_turf.z) && !client?.holder)
+1 -1
View File
@@ -417,7 +417,7 @@
//BUCKLE HOOKS
/obj/machinery/power/emitter/prototype/unbuckle_mob(mob/living/buckled_mob,force = 0)
/obj/machinery/power/emitter/prototype/unbuckle_mob(mob/living/buckled_mob, force = FALSE, can_fall = TRUE)
playsound(src,'sound/mecha/mechmove01.ogg', 50, TRUE)
manual = FALSE
for(var/obj/item/item in buckled_mob.held_items)
@@ -1085,9 +1085,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE)
Consume(hit_object)
/obj/machinery/power/supermatter_crystal/intercept_zImpact(atom/movable/hit_object, levels)
/obj/machinery/power/supermatter_crystal/intercept_zImpact(list/falling_movables, levels)
. = ..()
Bumped(hit_object)
for(var/atom/movable/hit_object as anything in falling_movables)
Bumped(hit_object)
. |= FALL_STOP_INTERCEPTING | FALL_INTERCEPTED
/obj/machinery/power/supermatter_crystal/proc/Consume(atom/movable/consumed_object)
@@ -10,13 +10,21 @@
allowed_area = A.name
. = ..()
/mob/camera/ai_eye/remote/xenobio/setLoc(destination)
/mob/camera/ai_eye/remote/xenobio/setLoc(turf/destination, force_update = FALSE)
var/area/new_area = get_area(destination)
if(new_area && new_area.name == allowed_area || new_area && (new_area.area_flags & XENOBIOLOGY_COMPATIBLE))
return ..()
else
return
/mob/camera/ai_eye/remote/xenobio/can_z_move(direction, turf/start, turf/destination, z_move_flags = NONE, mob/living/rider)
. = ..()
if(!.)
return
var/area/new_area = get_area(.)
if(new_area.name != allowed_area && !(new_area.area_flags & XENOBIOLOGY_COMPATIBLE))
return FALSE
/obj/machinery/computer/camera_advanced/xenobio
name = "Slime management console"
desc = "A computer used for remotely handling slimes."
+1 -1
View File
@@ -304,7 +304,7 @@
src.origin = origin
return ..()
/mob/camera/ai_eye/remote/shuttle_docker/setLoc(destination)
/mob/camera/ai_eye/remote/shuttle_docker/setLoc(turf/destination, force_update = FALSE)
. = ..()
var/obj/machinery/computer/camera_advanced/shuttle_docker/console = origin
console.checkLandingSpot()
+1 -1
View File
@@ -651,7 +651,7 @@ GLOBAL_LIST_EMPTY(vending_products)
to_chat(user, span_notice("You insert [I] into [src]'s input compartment."))
loaded_items++
/obj/machinery/vending/unbuckle_mob(mob/living/buckled_mob, force=FALSE)
/obj/machinery/vending/unbuckle_mob(mob/living/buckled_mob, force = FALSE, can_fall = TRUE)
if(!force)
return
. = ..()