diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index df83eeefcb5..18c1c438b18 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -13,9 +13,15 @@ #define COMSIG_MOVABLE_CROSS_OVER "movable_cross_am" ///from base of atom/movable/Bump(): (/atom) #define COMSIG_MOVABLE_BUMP "movable_bump" -///from base of atom/movable/newtonian_move(): (inertia_direction) +///from base of atom/movable/newtonian_move(): (inertia_direction, start_delay) #define COMSIG_MOVABLE_NEWTONIAN_MOVE "movable_newtonian_move" #define COMPONENT_MOVABLE_NEWTONIAN_BLOCK (1<<0) +///from datum/component/drift/apply_initial_visuals(): () +#define COMSIG_MOVABLE_DRIFT_VISUAL_ATTEMPT "movable_drift_visual_attempt" + #define DRIFT_VISUAL_FAILED (1<<0) +///from datum/component/drift/allow_final_movement(): () +#define COMSIG_MOVABLE_DRIFT_BLOCK_INPUT "movable_drift_block_input" + #define DRIFT_ALLOW_INPUT (1<<0) ///from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum) #define COMSIG_MOVABLE_IMPACT "movable_impact" #define COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH (1<<0) //if true, flip if the impact will push what it hits @@ -81,6 +87,6 @@ #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 -/// from base of atom/movable/Process_Spacemove(): (movement_dir) +/// from base of atom/movable/Process_Spacemove(): (movement_dir, continuous_move) #define COMSIG_MOVABLE_SPACEMOVE "spacemove" #define COMSIG_MOVABLE_STOP_SPACEMOVE (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm index 31dc06ac577..2384eec0c3b 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm @@ -5,8 +5,10 @@ ///signal sent out by an atom when it checks if it can be pulled, for additional checks #define COMSIG_ATOM_CAN_BE_PULLED "movable_can_be_pulled" #define COMSIG_ATOM_CANT_PULL (1 << 0) -///signal sent out by an atom when it is no longer being pulled by something else +///signal sent out by an atom when it is no longer being pulled by something else : (atom/puller) #define COMSIG_ATOM_NO_LONGER_PULLED "movable_no_longer_pulled" +///signal sent out by an atom when it is no longer pulling something : (atom/pulling) +#define COMSIG_ATOM_NO_LONGER_PULLING "movable_no_longer_pulling" ///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels) #define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact" ///called on a movable (NOT living) when it starts pulling (atom/movable/pulled, state, force) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 89acad38c49..eb95a016d78 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -291,6 +291,21 @@ ///called in /obj/item/gun/ballistic/process_chamber (casing) #define COMSIG_CASING_EJECTED "casing_ejected" +// Jetpack things +// Please kill me + +//called in /obj/item/tank/jetpack/proc/turn_on() : () +#define COMSIG_JETPACK_ACTIVATED "jetpack_activated" + #define JETPACK_ACTIVATION_FAILED (1<<0) +//called in /obj/item/tank/jetpack/proc/turn_off() : () +#define COMSIG_JETPACK_DEACTIVATED "jetpack_deactivated" + +//called in /obj/item/organ/cyberimp/chest/thrusters/proc/toggle() : () +#define COMSIG_THRUSTER_ACTIVATED "jetmodule_activated" + #define THRUSTER_ACTIVATION_FAILED (1<<0) +//called in /obj/item/organ/cyberimp/chest/thrusters/proc/toggle() : () +#define COMSIG_THRUSTER_DEACTIVATED "jetmodule_deactivated" + // /obj/effect/proc_holder/spell signals ///called from /obj/effect/proc_holder/spell/cast_check (src) diff --git a/code/controllers/subsystem/movement/movement_types.dm b/code/controllers/subsystem/movement/movement_types.dm index d1ea92376fd..b21466709b8 100644 --- a/code/controllers/subsystem/movement/movement_types.dm +++ b/code/controllers/subsystem/movement/movement_types.dm @@ -77,6 +77,18 @@ /datum/move_loop/proc/set_delay(new_delay) delay = max(new_delay, world.tick_lag) +///Pauses the move loop for some passed in period +///This functionally means shifting its timer up, and clearing it from its current bucket +/datum/move_loop/proc/pause_for(time) + if(!controller || !running) //No controller or not running? go away + return + //Dequeue us from our current bucket + controller.dequeue_loop(src) + //Offset our timer + timer = world.time + time + //Now requeue us with our new target start time + controller.queue_loop(src) + /datum/move_loop/process() var/old_delay = delay //The signal can sometimes change delay diff --git a/code/datums/components/drift.dm b/code/datums/components/drift.dm index 4cfc1372a79..4d509026a44 100644 --- a/code/datums/components/drift.dm +++ b/code/datums/components/drift.dm @@ -5,9 +5,16 @@ var/atom/inertia_last_loc var/old_dir var/datum/move_loop/move/drifting_loop + ///Should we ignore the next glide rate input we get? + ///This is to some extent a hack around the order of operations + ///Around COMSIG_MOVELOOP_POSTPROCESS. I'm sorry lad + var/ignore_next_glide = FALSE + ///Have we been delayed? IE: active, but not working right this second? + var/delayed = FALSE var/block_inputs_until -/datum/component/drift/Initialize(direction, instant = FALSE) +/// Accepts three args. The direction to drift in, if the drift is instant or not, and if it's not instant, the delay on the start +/datum/component/drift/Initialize(direction, instant = FALSE, start_delay = 0) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE . = ..() @@ -29,6 +36,16 @@ if(drifting_loop.running) drifting_start(drifting_loop) // There's a good chance it'll autostart, gotta catch that + var/visual_delay = movable_parent.inertia_move_delay + + // Start delay is essentially a more granular version of instant + // Isn't used in the standard case, just for things that have odd wants + if(!instant && start_delay) + drifting_loop.pause_for(start_delay) + visual_delay = start_delay + + apply_initial_visuals(visual_delay) + /datum/component/drift/Destroy() inertia_last_loc = null if(!QDELETED(drifting_loop)) @@ -38,6 +55,23 @@ movable_parent.inertia_moving = FALSE return ..() +/datum/component/drift/proc/apply_initial_visuals(visual_delay) + // If something "somewhere" doesn't want us to apply our glidesize delays, don't + if(SEND_SIGNAL(parent, COMSIG_MOVABLE_DRIFT_VISUAL_ATTEMPT) & DRIFT_VISUAL_FAILED) + return + + // Ignore the next glide because it's literally just us + ignore_next_glide = TRUE + var/atom/movable/movable_parent = parent + movable_parent.set_glide_size(MOVEMENT_ADJUSTED_GLIDE_SIZE(visual_delay, SSspacedrift.visual_delay)) + if(ismob(parent)) + var/mob/mob_parent = parent + //Ok this is slightly weird, but basically, we need to force the client to glide at our rate + //Make sure moving into a space move looks like a space move essentially + //There is an inbuilt assumption that gliding will be added as a part of a move call, but eh + //It's ok if it's not, it's just important if it is. + mob_parent.client?.visual_delay = MOVEMENT_ADJUSTED_GLIDE_SIZE(visual_delay, SSspacedrift.visual_delay) + /datum/component/drift/proc/newtonian_impulse(datum/source, inertia_direction) SIGNAL_HANDLER var/atom/movable/movable_parent = parent @@ -53,18 +87,25 @@ inertia_last_loc = movable_parent.loc RegisterSignal(movable_parent, COMSIG_MOVABLE_MOVED, .proc/handle_move) RegisterSignal(movable_parent, COMSIG_MOVABLE_NEWTONIAN_MOVE, .proc/newtonian_impulse) + // We will use glide size to intuit how long to delay our loop's next move for + // This way you can't ride two movements at once while drifting, since that'd be dumb as fuck + RegisterSignal(movable_parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, .proc/handle_glidesize_update) + // If you stop pulling something mid drift, I want it to retain that momentum + RegisterSignal(movable_parent, COMSIG_ATOM_NO_LONGER_PULLING, .proc/stopped_pulling) /datum/component/drift/proc/drifting_stop() SIGNAL_HANDLER var/atom/movable/movable_parent = parent movable_parent.inertia_moving = FALSE - UnregisterSignal(movable_parent, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_NEWTONIAN_MOVE)) + ignore_next_glide = FALSE + UnregisterSignal(movable_parent, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_NEWTONIAN_MOVE, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, COMSIG_ATOM_NO_LONGER_PULLING)) /datum/component/drift/proc/before_move(datum/source) SIGNAL_HANDLER var/atom/movable/movable_parent = parent movable_parent.inertia_moving = TRUE old_dir = movable_parent.dir + delayed = FALSE /datum/component/drift/proc/after_move(datum/source, succeeded, visual_delay) SIGNAL_HANDLER @@ -75,11 +116,12 @@ var/atom/movable/movable_parent = parent movable_parent.inertia_moving = FALSE movable_parent.setDir(old_dir) - if(movable_parent.Process_Spacemove(0)) + if(movable_parent.Process_Spacemove(drifting_loop.direction, continuous_move = TRUE)) glide_to_halt(visual_delay) return inertia_last_loc = movable_parent.loc + ignore_next_glide = TRUE /datum/component/drift/proc/loop_death(datum/source) SIGNAL_HANDLER @@ -88,16 +130,44 @@ /datum/component/drift/proc/handle_move(datum/source, old_loc) SIGNAL_HANDLER + // This can happen, because signals once sent cannot be stopped + if(QDELETED(src)) + return var/atom/movable/movable_parent = parent if(!isturf(movable_parent.loc)) qdel(src) return if(movable_parent.inertia_moving) //This'll be handled elsewhere return - if(!movable_parent.Process_Spacemove(0)) + if(!movable_parent.Process_Spacemove(drifting_loop.direction, continuous_move = TRUE)) return qdel(src) +/// We're going to take the passed in glide size +/// and use it to manually delay our loop for that period +/// to allow the other movement to complete +/datum/component/drift/proc/handle_glidesize_update(datum/source, glide_size) + SIGNAL_HANDLER + // If we aren't drifting, or this is us, fuck off + var/atom/movable/movable_parent = parent + if(!drifting_loop || movable_parent.inertia_moving) + return + // If we are drifting, but this set came from the moveloop itself, drop the input + // I'm sorry man + if(ignore_next_glide) + ignore_next_glide = FALSE + return + var/glide_delay = round(world.icon_size / glide_size, 1) * world.tick_lag + drifting_loop.pause_for(glide_delay) + delayed = TRUE + +/// If we're pulling something and stop, we want it to continue at our rate and such +/datum/component/drift/proc/stopped_pulling(datum/source, atom/movable/was_pulling) + SIGNAL_HANDLER + // This does mean it falls very slightly behind, but otherwise they'll potentially run into us + var/next_move_in = drifting_loop.timer - world.time + world.tick_lag + was_pulling.newtonian_move(drifting_loop.direction, start_delay = next_move_in) + /datum/component/drift/proc/glide_to_halt(glide_for) if(!ismob(parent)) qdel(src) @@ -105,7 +175,8 @@ var/mob/mob_parent = parent var/client/our_client = mob_parent.client - if(!our_client) + // If we're not active, don't do the glide because it'll look dumb as fuck + if(!our_client || delayed) qdel(src) return @@ -115,5 +186,8 @@ RegisterSignal(parent, COMSIG_MOB_CLIENT_PRE_MOVE, .proc/allow_final_movement) /datum/component/drift/proc/allow_final_movement(datum/source) + // Some things want to allow movement out of spacedrift, we should let them + if(SEND_SIGNAL(parent, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT) & DRIFT_ALLOW_INPUT) + return if(world.time < block_inputs_until) return COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE diff --git a/code/datums/components/jetpack.dm b/code/datums/components/jetpack.dm new file mode 100644 index 00000000000..d6085d57f7a --- /dev/null +++ b/code/datums/components/jetpack.dm @@ -0,0 +1,149 @@ +// Welcome to the jetpack component +// Apply this to something when you want it to be "like a jetpack" +// So propulsion through space on move, that sort of thing +/datum/component/jetpack + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + var/datum/callback/check_on_move + var/datum/callback/get_mover + /// If we should stabilize ourselves when not drifting + var/stabilize = FALSE + /// The signal we listen for as an activation + var/activation_signal + /// The signal we listen for as a de-activation + var/deactivation_signal + /// The return flag our parent expects for a failed activation + var/return_flag + var/datum/effect_system/trail_follow/trail + /// The typepath to instansiate our trail as, when we need it + var/effect_type + +/** + * Arguments: + * * stabilize - If we should drift when we finish moving, or sit stable in space] + * * activation_signal - Signal we activate on + * * deactivation_signal - Signal we deactivate on + * * return_flag - Flag to return if activation fails + * * get_mover - Callback we use to get the "moving" thing, for trail purposes, alongside signal registration + * * check_on_move - Callback we call each time we attempt a move, we expect it to retun true if the move is ok, false otherwise. It expects an arg, TRUE if fuel should be consumed, FALSE othewise + * * effect_type - Type of trail_follow to spawn + */ +/datum/component/jetpack/Initialize(stabilize, activation_signal, deactivation_signal, return_flag, datum/callback/get_mover, datum/callback/check_on_move, datum/effect_system/trail_follow/effect_type) + . = ..() + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + if(!activation_signal) // Can't activate? go away + return COMPONENT_INCOMPATIBLE + + RegisterSignal(parent, activation_signal, .proc/activate) + if(deactivation_signal) + RegisterSignal(parent, deactivation_signal, .proc/deactivate) + + src.check_on_move = check_on_move + src.get_mover = get_mover + src.stabilize = stabilize + src.return_flag = return_flag + src.activation_signal = activation_signal + src.deactivation_signal = deactivation_signal + src.effect_type = effect_type + +/datum/component/jetpack/InheritComponent(datum/component/component, original, stabilize, activation_signal, deactivation_signal, return_flag, datum/callback/get_mover, datum/callback/check_on_move, datum/effect_system/trail_follow/effect_type) + UnregisterSignal(parent, src.activation_signal) + if(src.deactivation_signal) + UnregisterSignal(parent, src.deactivation_signal) + RegisterSignal(parent, activation_signal, .proc/activate) + if(deactivation_signal) + RegisterSignal(parent, deactivation_signal, .proc/deactivate) + + src.check_on_move = check_on_move + src.get_mover = get_mover + src.stabilize = stabilize + src.activation_signal = activation_signal + src.deactivation_signal = deactivation_signal + src.effect_type = effect_type + + if(trail && effect_type != trail.type) + QDEL_NULL(trail) + setup_trail() + +/datum/component/jetpack/Destroy() + QDEL_NULL(trail) + QDEL_NULL(check_on_move) + return ..() + +/datum/component/jetpack/proc/setup_trail() + var/mob/moving = get_mover.Invoke() + if(!moving || trail) + return + trail = new effect_type + trail.auto_process = FALSE + trail.set_up(moving) + +/datum/component/jetpack/proc/activate(datum/source) + SIGNAL_HANDLER + var/mob/moving = get_mover.Invoke() + if(!thrust(moving)) + return return_flag + trail.start() + RegisterSignal(moving, COMSIG_MOVABLE_MOVED, .proc/move_react) + RegisterSignal(moving, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move_react) + RegisterSignal(moving, COMSIG_MOVABLE_SPACEMOVE, .proc/spacemove_react) + RegisterSignal(moving, COMSIG_MOVABLE_DRIFT_VISUAL_ATTEMPT, .proc/block_starting_visuals) + RegisterSignal(moving, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT, .proc/ignore_ending_block) + +/datum/component/jetpack/proc/deactivate(datum/source) + SIGNAL_HANDLER + QDEL_NULL(trail) + var/mob/moving = get_mover.Invoke() + if(moving) + UnregisterSignal(moving, COMSIG_MOVABLE_MOVED) + UnregisterSignal(moving, COMSIG_MOVABLE_PRE_MOVE) + UnregisterSignal(moving, COMSIG_MOVABLE_SPACEMOVE) + UnregisterSignal(moving, COMSIG_MOVABLE_DRIFT_VISUAL_ATTEMPT) + UnregisterSignal(moving, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT) + +/datum/component/jetpack/proc/move_react(mob/user) + SIGNAL_HANDLER + if(!user || !user.client)//Don't allow jet self using + return + if(!isturf(user.loc))//You can't use jet in nowhere or from mecha/closet + return + if(!(user.movement_type & FLOATING) || user.buckled)//You don't want use jet in gravity or while buckled. + return + if(user.pulledby)//You don't must use jet if someone pull you + return + if(user.throwing)//You don't must use jet if you thrown + return + if(length(user.client.keys_held & user.client.movement_keys))//You use jet when press keys. yes. + thrust() + +/datum/component/jetpack/proc/pre_move_react(mob/user) + SIGNAL_HANDLER + trail.oldposition = get_turf(user) + +/datum/component/jetpack/proc/spacemove_react(mob/user, movement_dir, continuous_move) + SIGNAL_HANDLER + if(!continuous_move && movement_dir) + return COMSIG_MOVABLE_STOP_SPACEMOVE + // Check if we have the fuel to stop this. Do NOT cosume any fuel, just check + // This is done because things other then us can use our fuel + if(stabilize && check_on_move.Invoke(FALSE)) + return COMSIG_MOVABLE_STOP_SPACEMOVE + +/// Returns true if the thrust went well, false otherwise +/datum/component/jetpack/proc/thrust() + if(!check_on_move.Invoke(TRUE)) + return FALSE + if(!trail) + setup_trail() + trail.generate_effect() + return TRUE + +/// Basically, tell the drift component not to do its starting visuals, because they look dumb for us +/datum/component/jetpack/proc/block_starting_visuals(datum/source) + SIGNAL_HANDLER + return DRIFT_VISUAL_FAILED + +/// If we're on, don't let the drift component block movements at the end since we can speed +/datum/component/jetpack/proc/ignore_ending_block(datum/source) + SIGNAL_HANDLER + return DRIFT_ALLOW_INPUT diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index e6adb2d19c6..340ffe14302 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -235,7 +235,7 @@ /datum/component/riding/proc/Unbuckle(atom/movable/M) addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE) -/datum/component/riding/proc/Process_Spacemove(direction) +/datum/component/riding/proc/Process_Spacemove(direction, continuous_move) var/atom/movable/AM = parent return override_allow_spacemove || AM.has_gravity() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 570f8b8e875..ce8539a8dd0 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -29,6 +29,9 @@ var/inertia_moving = FALSE ///Delay in deciseconds between inertia based movement var/inertia_move_delay = 5 + ///The last time we pushed off something + ///This is a hack to get around dumb him him me scenarios + var/last_pushoff /// Things we can pass through while moving. If any of this matches the thing we're trying to pass's [pass_flags_self], then we can pass through. var/pass_flags = NONE /// If false makes [CanPass][/atom/proc/CanPass] call [CanPassThrough][/atom/movable/proc/CanPassThrough] on this type instead of using default behaviour @@ -373,12 +376,14 @@ return TRUE /atom/movable/proc/stop_pulling() - if(pulling) - SEND_SIGNAL(pulling, COMSIG_ATOM_NO_LONGER_PULLED, src) - pulling.set_pulledby(null) - setGrabState(GRAB_PASSIVE) - pulling = null - + if(!pulling) + return + pulling.set_pulledby(null) + setGrabState(GRAB_PASSIVE) + var/atom/movable/old_pulling = pulling + pulling = null + SEND_SIGNAL(old_pulling, COMSIG_ATOM_NO_LONGER_PULLED, src) + SEND_SIGNAL(src, COMSIG_ATOM_NO_LONGER_PULLING, old_pulling) ///Reports the event of the change in value of the pulledby variable. /atom/movable/proc/set_pulledby(new_pulledby) @@ -976,9 +981,10 @@ * * Arguments: * * movement_dir - 0 when stopping or any dir when trying to move + * * continuous_move - If this check is coming from something in the context of already drifting */ -/atom/movable/proc/Process_Spacemove(movement_dir = 0) - if(SEND_SIGNAL(src, COMSIG_MOVABLE_SPACEMOVE, movement_dir) & COMSIG_MOVABLE_STOP_SPACEMOVE) +/atom/movable/proc/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_SPACEMOVE, movement_dir, continuous_move) & COMSIG_MOVABLE_STOP_SPACEMOVE) return TRUE if(has_gravity(src)) @@ -1000,16 +1006,15 @@ /// Only moves the object if it's under no gravity -/// Accepts the direction to move, and if the push should be instant -/atom/movable/proc/newtonian_move(direction, instant = FALSE) - if(!isturf(loc) || Process_Spacemove(0)) +/// Accepts the direction to move, if the push should be instant, and an optional parameter to fine tune the start delay +/atom/movable/proc/newtonian_move(direction, instant = FALSE, start_delay = 0) + if(!isturf(loc) || Process_Spacemove(direction, continuous_move = TRUE)) return FALSE - if(SEND_SIGNAL(src, COMSIG_MOVABLE_NEWTONIAN_MOVE, direction) & COMPONENT_MOVABLE_NEWTONIAN_BLOCK) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_NEWTONIAN_MOVE, direction, start_delay) & COMPONENT_MOVABLE_NEWTONIAN_BLOCK) return TRUE - set_glide_size(MOVEMENT_ADJUSTED_GLIDE_SIZE(inertia_move_delay, SSspacedrift.visual_delay)) - AddComponent(/datum/component/drift, direction, instant) + AddComponent(/datum/component/drift, direction, instant, start_delay) return TRUE @@ -1164,23 +1169,19 @@ SEND_SIGNAL(src, COMSIG_STORAGE_ENTERED, master_storage) /atom/movable/proc/get_spacemove_backup() - var/atom/movable/dense_object_backup for(var/checked_range in orange(1, get_turf(src))) if(isarea(checked_range)) continue - else if(isturf(checked_range)) + if(isturf(checked_range)) var/turf/turf = checked_range if(!turf.density) continue return turf - else - var/atom/movable/checked_atom = checked_range - if(checked_atom.density || !checked_atom.CanPass(src, get_dir(src, checked_atom))) - if(checked_atom.anchored) - return checked_atom - dense_object_backup = checked_atom - break - . = dense_object_backup + var/atom/movable/checked_atom = checked_range + if(checked_atom.density || !checked_atom.CanPass(src, get_dir(src, checked_atom))) + if(checked_atom.last_pushoff == world.time) + continue + return checked_atom ///called when a mob resists while inside a container that is itself inside something. /atom/movable/proc/relay_container_resist_act(mob/living/user, obj/container) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 1ea0ead9e69..88a3ad7e89a 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -801,7 +801,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ HC = null return ..() -/obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0) +/obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) return TRUE /obj/effect/overlay/holo_pad_hologram/examine(mob/user) diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm index 44c69ee37eb..1a7a329e32f 100644 --- a/code/game/objects/effects/effect_system/effect_system.dm +++ b/code/game/objects/effects/effect_system/effect_system.dm @@ -20,7 +20,8 @@ would spawn and follow the beaker, even if it is carried or thrown. GLOB.cameranet.updateVisibility(src) return ..() -/obj/effect/particle_effect/newtonian_move(direction, instant = FALSE) // Prevents effects from getting registered for SSspacedrift +// Prevents effects from getting registered for SSspacedrift +/obj/effect/particle_effect/newtonian_move(direction, instant = FALSE, start_delay = 0) return TRUE /datum/effect_system diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index b4e3a5fc437..1caa38d5da8 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -44,7 +44,8 @@ return FALSE return ..() -/obj/effect/portal/newtonian_move(direction, instant = FALSE) // Prevents portals spawned by jaunter/handtele from floating into space when relocated to an adjacent tile. +// Prevents portals spawned by jaunter/handtele from floating into space when relocated to an adjacent tile. +/obj/effect/portal/newtonian_move(direction, instant = FALSE, start_delay = 0) return TRUE /obj/effect/portal/attackby(obj/item/W, mob/user, params) diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm index 3e3eb90e583..d2d02e0048b 100644 --- a/code/game/objects/items/tanks/jetpack.dm +++ b/code/game/objects/items/tanks/jetpack.dm @@ -12,18 +12,23 @@ var/on = FALSE var/stabilizers = FALSE var/full_speed = TRUE // If the jetpack will have a speedboost in space/nograv or not - var/datum/effect_system/trail_follow/ion/ion_trail + var/datum/callback/get_mover + var/datum/callback/check_on_move /obj/item/tank/jetpack/Initialize(mapload) . = ..() - ion_trail = new - ion_trail.auto_process = FALSE - ion_trail.set_up(src) + get_mover = CALLBACK(src, .proc/get_user) + check_on_move = CALLBACK(src, .proc/allow_thrust, 0.01) + refresh_jetpack() /obj/item/tank/jetpack/Destroy() - QDEL_NULL(ion_trail) + get_mover = null + check_on_move = null return ..() +/obj/item/tank/jetpack/proc/refresh_jetpack() + AddComponent(/datum/component/jetpack, stabilizers, COMSIG_JETPACK_ACTIVATED, COMSIG_JETPACK_DEACTIVATED, JETPACK_ACTIVATION_FAILED, get_mover, check_on_move, /datum/effect_system/trail_follow/ion) + /obj/item/tank/jetpack/item_action_slot_check(slot) if(slot == ITEM_SLOT_BACK) return TRUE @@ -49,12 +54,11 @@ cycle(user) else if(istype(action, /datum/action/item_action/jetpack_stabilization)) if(on) - stabilizers = !stabilizers + set_stabilizers(!stabilizers) to_chat(user, span_notice("You turn the jetpack stabilization [stabilizers ? "on" : "off"].")) else toggle_internals(user) - /obj/item/tank/jetpack/proc/cycle(mob/user) if(user.incapacitated()) return @@ -70,83 +74,60 @@ to_chat(user, span_notice("You turn the jetpack off.")) update_action_buttons() +/obj/item/tank/jetpack/proc/set_stabilizers(new_stabilizers) + if(new_stabilizers == stabilizers) + return + stabilizers = new_stabilizers + refresh_jetpack() /obj/item/tank/jetpack/proc/turn_on(mob/user) - if(!allow_thrust(0.01, user)) + if(SEND_SIGNAL(src, COMSIG_JETPACK_ACTIVATED) & JETPACK_ACTIVATION_FAILED) return FALSE on = TRUE icon_state = "[initial(icon_state)]-on" - ion_trail.start() - RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/move_react) - RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move_react) - RegisterSignal(user, COMSIG_MOVABLE_SPACEMOVE, .proc/spacemove_react) if(full_speed) user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) return TRUE - /obj/item/tank/jetpack/proc/turn_off(mob/user) + SEND_SIGNAL(src, COMSIG_JETPACK_DEACTIVATED) on = FALSE - stabilizers = FALSE + set_stabilizers(FALSE) icon_state = initial(icon_state) - ion_trail.stop() if(user) - UnregisterSignal(user, COMSIG_MOVABLE_MOVED) - UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE) - UnregisterSignal(user, COMSIG_MOVABLE_SPACEMOVE) user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) -/obj/item/tank/jetpack/proc/move_react(mob/user) - SIGNAL_HANDLER - if(!on)//If jet dont work, it dont work - return - if(!user || !user.client)//Don't allow jet self using - return - if(!isturf(user.loc))//You can't use jet in nowhere or from mecha/closet - return - if(!(user.movement_type & FLOATING) || user.buckled)//You don't want use jet in gravity or while buckled. - return - if(user.pulledby)//You don't must use jet if someone pull you - return - if(user.throwing)//You don't must use jet if you thrown - return - if(length(user.client.keys_held & user.client.movement_keys))//You use jet when press keys. yes. - allow_thrust(0.01, user) - -/obj/item/tank/jetpack/proc/pre_move_react(mob/user) - SIGNAL_HANDLER - ion_trail.oldposition = get_turf(src) - -/obj/item/tank/jetpack/proc/spacemove_react(mob/user, movement_dir) - SIGNAL_HANDLER - - if(on && (movement_dir || stabilizers)) - return COMSIG_MOVABLE_STOP_SPACEMOVE - -/obj/item/tank/jetpack/proc/allow_thrust(num, mob/living/user) +/obj/item/tank/jetpack/proc/allow_thrust(num, use_fuel = TRUE) if((num < 0.005 || air_contents.total_moles() < num)) - turn_off(user) - return + turn_off(get_user()) + return FALSE + + // We've got the gas, it's chill + if(!use_fuel) + return TRUE var/datum/gas_mixture/removed = remove_air(num) if(removed.total_moles() < 0.005) - turn_off(user) - return + turn_off(get_user()) + return FALSE - var/turf/T = get_turf(user) + var/turf/T = get_turf(src) T.assume_air(removed) - ion_trail.generate_effect() - return TRUE +// Gives the jetpack component the user it expects +/obj/item/tank/jetpack/proc/get_user() + if(!ismob(loc)) + return null + return loc + /obj/item/tank/jetpack/suicide_act(mob/user) - if (istype(user, /mob/living/carbon/human/)) - var/mob/living/carbon/human/H = user - H.say("WHAT THE FUCK IS CARBON DIOXIDE?") - H.visible_message(span_suicide("[user] is suffocating [user.p_them()]self with [src]! It looks like [user.p_they()] didn't read what that jetpack says!")) - return (OXYLOSS) - else - ..() + if (!istype(user, /mob/living/carbon/human)) + return ..() + var/mob/living/carbon/human/suffocater = user + suffocater.say("WHAT THE FUCK IS CARBON DIOXIDE?") + suffocater.visible_message(span_suicide("[user] is suffocating [user.p_them()]self with [src]! It looks like [user.p_they()] didn't read what that jetpack says!")) + return (OXYLOSS) /obj/item/tank/jetpack/improvised name = "improvised jetpack" @@ -159,7 +140,10 @@ gas_type = null //it starts empty full_speed = FALSE //moves at modsuit jetpack speeds -/obj/item/tank/jetpack/improvised/allow_thrust(num, mob/living/user) +/obj/item/tank/jetpack/improvised/allow_thrust(num) + var/mob/user = get_user() + if(!user) + return FALSE if(rand(0,250) == 0) to_chat(user, span_notice("You feel your jetpack's engines cut out.")) turn_off(user) diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 29cf2d3a80d..3cf32f9e273 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -369,7 +369,8 @@ playsound(src,'sound/effects/bamf.ogg',100,TRUE) qdel(src) -/obj/effect/resin_container/newtonian_move(direction, instant = FALSE) // Please don't spacedrift thanks +// Please don't spacedrift thanks +/obj/effect/resin_container/newtonian_move(direction, instant = FALSE, start_delay = 0) return TRUE #undef EXTINGUISHER diff --git a/code/modules/antagonists/blob/blob_mobs.dm b/code/modules/antagonists/blob/blob_mobs.dm index 44adf6483cc..8337c7853b3 100644 --- a/code/modules/antagonists/blob/blob_mobs.dm +++ b/code/modules/antagonists/blob/blob_mobs.dm @@ -80,7 +80,7 @@ SSmove_manager.jps_move(moving = src, chasing = target, delay = delay, repath_delay = 2 SECONDS, minimum_distance = minimum_distance, simulated_only = FALSE, skip_first = TRUE, timeout = 5 SECONDS, flags = MOVEMENT_LOOP_IGNORE_GLIDE) return TRUE -/mob/living/simple_animal/hostile/blob/Process_Spacemove(movement_dir = 0) +/mob/living/simple_animal/hostile/blob/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) for(var/obj/structure/blob/B in range(1, src)) return 1 return ..() diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index dce106ee6d1..11da329dda5 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -196,7 +196,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 /obj/effect/immovablerod/singularity_pull() return -/obj/effect/immovablerod/Process_Spacemove() +/obj/effect/immovablerod/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) return TRUE /obj/effect/immovablerod/Bump(atom/clong) diff --git a/code/modules/meteors/meteors.dm b/code/modules/meteors/meteors.dm index 63962fe2706..2df987aa3cb 100644 --- a/code/modules/meteors/meteors.dm +++ b/code/modules/meteors/meteors.dm @@ -143,7 +143,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust=1)) //for space dust eve qdel(src) return -/obj/effect/meteor/Process_Spacemove() +/obj/effect/meteor/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) return TRUE //Keeps us from drifting for no reason /obj/effect/meteor/Bump(atom/A) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 9c458e849dc..2734ccb3b53 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -992,7 +992,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp // Ghosts have no momentum, being massless ectoplasm -/mob/dead/observer/Process_Spacemove(movement_dir) +/mob/dead/observer/Process_Spacemove(movement_dir, continuous_move = FALSE) return TRUE /mob/dead/observer/vv_edit_var(var_name, var_value) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index d37a5a216f2..34e2a4c9b3d 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -34,7 +34,7 @@ if(shoes && body_position == STANDING_UP && loc == NewLoc && has_gravity(loc)) SEND_SIGNAL(shoes, COMSIG_SHOES_STEP_ACTION) -/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) +/mob/living/carbon/human/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) if(movement_type & FLYING || HAS_TRAIT(src, TRAIT_FREE_FLOAT_MOVEMENT)) return TRUE return ..() diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 02ae2695bd3..7e1d636874e 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -232,7 +232,7 @@ if(delold) qdel(src) -/mob/living/silicon/pai/Process_Spacemove(movement_dir = 0) +/mob/living/silicon/pai/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) . = ..() if(!.) add_movespeed_modifier(/datum/movespeed_modifier/pai_spacewalk) diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index 9a417298cd0..b7d3e59a5da 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -1,4 +1,4 @@ -/mob/living/silicon/robot/Process_Spacemove(movement_dir = 0) +/mob/living/silicon/robot/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) . = ..() if(.) return TRUE diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 26ad57e4dce..e8994c97748 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -677,7 +677,7 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list( . = ..() ADD_TRAIT(src, TRAIT_AI_BAGATTACK, INNATE_TRAIT) -/mob/living/simple_animal/pet/dog/corgi/puppy/void/Process_Spacemove(movement_dir = 0) +/mob/living/simple_animal/pet/dog/corgi/puppy/void/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) return 1 //Void puppies can navigate space. diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index b331fd63ed8..851ceb2b1b2 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -282,7 +282,7 @@ if(ranged) //We ranged? Shoot at em if(!target.Adjacent(target_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown OpenFire(target) - if(!Process_Spacemove()) //Drifting + if(!Process_Spacemove(0)) //Drifting SSmove_manager.stop_looping(src) return 1 if(retreat_distance != null) //If we have a retreat distance, check if we need to run from our target diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 2ddfcb99c98..8e848f82db9 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -366,7 +366,7 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( icon_state = icon_living drop_held_item(0) -/mob/living/simple_animal/parrot/Process_Spacemove() +/mob/living/simple_animal/parrot/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) if(!stat) //Birds can fly, fun fact. No I don't care that space doesn't have air. Space parrots bitch return TRUE return ..() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 939b00c8454..3f27aac3135 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -262,16 +262,23 @@ /mob/living/simple_animal/proc/handle_automated_movement() set waitfor = FALSE - if(!stop_automated_movement && wander) - if((isturf(loc) || allow_movement_on_non_turfs) && (mobility_flags & MOBILITY_MOVE)) //This is so it only moves if it's not inside a closet, gentics machine, etc. - turns_since_move++ - if(turns_since_move >= turns_per_move) - if(!(stop_automated_movement_when_pulled && pulledby)) //Some animals don't move when pulled - var/anydir = pick(GLOB.cardinals) - if(Process_Spacemove(anydir)) - Move(get_step(src, anydir), anydir) - turns_since_move = 0 - return 1 + if(stop_automated_movement || !wander) + return + if(!isturf(loc) && !allow_movement_on_non_turfs) + return + if(!(mobility_flags & MOBILITY_MOVE)) //This is so it only moves if it's not inside a closet, gentics machine, etc. + return TRUE + + turns_since_move++ + if(turns_since_move < turns_per_move) + return TRUE + if(stop_automated_movement_when_pulled && pulledby) //Some animals don't move when pulled + return TRUE + var/anydir = pick(GLOB.cardinals) + if(Process_Spacemove(anydir)) + Move(get_step(src, anydir), anydir) + turns_since_move = 0 + return TRUE /mob/living/simple_animal/proc/handle_automated_speech(override) set waitfor = FALSE diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index eb34b11844c..e4dc91172bb 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -221,7 +221,7 @@ Atkcool = TRUE addtimer(VARSET_CALLBACK(src, Atkcool, FALSE), 4.5 SECONDS) -/mob/living/simple_animal/slime/Process_Spacemove(movement_dir = 0) +/mob/living/simple_animal/slime/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) return 2 /mob/living/simple_animal/slime/get_status_tab_items() diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 3a06f8a6676..7b4aba4a17d 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -262,7 +262,6 @@ L.setDir(direct) return TRUE - /** * Handles mob/living movement in space (or no gravity) * @@ -272,23 +271,34 @@ * * You can move in space if you have a spacewalk ability */ -/mob/Process_Spacemove(movement_dir = 0) +/mob/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) . = ..() if(. || HAS_TRAIT(src, TRAIT_SPACEWALK)) return TRUE - var/atom/movable/backup = get_spacemove_backup(movement_dir) - if(backup) - if(istype(backup) && movement_dir && !backup.anchored) - if(backup.newtonian_move(turn(movement_dir, 180), instant = TRUE)) //You're pushing off something movable, so it moves - to_chat(src, span_info("You push off of [backup] to propel yourself.")) + + // FUCK OFF + if(buckled) return TRUE - return FALSE + + var/atom/movable/backup = get_spacemove_backup(movement_dir, continuous_move) + if(!backup) + return FALSE + if(continuous_move || !istype(backup) || !movement_dir || backup.anchored) + return TRUE + // last pushoff exists for one reason + // to ensure pushing a mob doesn't just lead to it considering us as backup, and failing + last_pushoff = world.time + if(backup.newtonian_move(turn(movement_dir, 180), instant = TRUE)) //You're pushing off something movable, so it moves + // We set it down here so future calls to Process_Spacemove by the same pair in the same tick don't lead to fucky + backup.last_pushoff = world.time + to_chat(src, span_info("You push off of [backup] to propel yourself.")) + return TRUE /** * Finds a target near a mob that is viable for pushing off when moving. - * Takes the intended movement direction as input. + * Takes the intended movement direction as input, alongside if the context is checking if we're allowed to continue drifting */ -/mob/get_spacemove_backup(moving_direction) +/mob/get_spacemove_backup(moving_direction, continuous_move) for(var/atom/pushover as anything in range(1, get_turf(src))) if(pushover == src) continue @@ -313,8 +323,17 @@ var/pass_allowed = rebound.CanPass(src, get_dir(rebound, src)) if(!rebound.density && pass_allowed) continue - if(moving_direction == get_dir(src, pushover) && !pass_allowed) // Can't push "off" of something that you're walking into + //Sometime this tick, this pushed off something. Doesn't count as a valid pushoff target + if(rebound.last_pushoff == world.time) continue + if(continuous_move && !pass_allowed) + var/datum/move_loop/move/rebound_engine = SSmove_manager.processing_on(rebound, SSspacedrift) + // If you're moving toward it and you're both going the same direction, stop + if(moving_direction == get_dir(src, pushover) && rebound_engine && moving_direction == rebound_engine.direction) + continue + else if(!pass_allowed) + if(moving_direction == get_dir(src, pushover)) // Can't push "off" of something that you're walking into + continue if(rebound.anchored) return rebound if(pulling == rebound) @@ -331,14 +350,6 @@ var/turf/turf = get_turf(src) return !isgroundlessturf(turf) && HAS_TRAIT(src, TRAIT_NEGATES_GRAVITY) -/mob/newtonian_move(direction, instant = FALSE) - . = ..() - if(!.) //Only do this if we're actually going somewhere - return - if(!client) - return - client.visual_delay = MOVEMENT_ADJUSTED_GLIDE_SIZE(inertia_move_delay, SSspacedrift.visual_delay) //Make sure moving into a space move looks like a space move - /// Called when this mob slips over, override as needed /mob/proc/slip(knockdown_amount, obj/O, lube, paralyze, force_drop) mind?.add_memory(MEMORY_SLIPPED, list(DETAIL_WHAT_BY = O, DETAIL_PROTAGONIST = src), story_value = STORY_VALUE_OKAY) diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 286feb9eace..cebfb1dea0f 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -95,38 +95,38 @@ var/stabilizers = FALSE /// Do we give the wearer a speed buff. var/full_speed = FALSE - /// The ion trail particles left after the jetpack. - var/datum/effect_system/trail_follow/ion/grav_allowed/ion_trail + var/datum/callback/get_mover + var/datum/callback/check_on_move /obj/item/mod/module/jetpack/Initialize(mapload) . = ..() - ion_trail = new() - ion_trail.auto_process = FALSE - ion_trail.set_up(src) + get_mover = CALLBACK(src, .proc/get_user) + check_on_move = CALLBACK(src, .proc/allow_thrust) + refresh_jetpack() /obj/item/mod/module/jetpack/Destroy() - QDEL_NULL(ion_trail) + get_mover = null + check_on_move = null return ..() +/obj/item/mod/module/jetpack/proc/refresh_jetpack() + AddComponent(/datum/component/jetpack, stabilizers, COMSIG_MODULE_TRIGGERED, COMSIG_MODULE_DEACTIVATED, COMSIG_MODULE_TRIGGERED, get_mover, check_on_move, /datum/effect_system/trail_follow/ion/grav_allowed) + +/obj/item/mod/module/jetpack/proc/set_stabilizers(new_stabilizers) + if(stabilizers == new_stabilizers) + return + stabilizers = new_stabilizers + refresh_jetpack() + /obj/item/mod/module/jetpack/on_activation() . = ..() if(!.) return - ion_trail.start() - RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, .proc/move_react) - RegisterSignal(mod.wearer, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move_react) - RegisterSignal(mod.wearer, COMSIG_MOVABLE_SPACEMOVE, .proc/spacemove_react) if(full_speed) mod.wearer.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) /obj/item/mod/module/jetpack/on_deactivation(display_message = TRUE, deleting = FALSE) . = ..() - if(!.) - return - ion_trail.stop() - UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED) - UnregisterSignal(mod.wearer, COMSIG_MOVABLE_PRE_MOVE) - UnregisterSignal(mod.wearer, COMSIG_MOVABLE_SPACEMOVE) if(full_speed) mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) @@ -137,41 +137,18 @@ /obj/item/mod/module/jetpack/configure_edit(key, value) switch(key) if("stabilizers") - stabilizers = text2num(value) + set_stabilizers(text2num(value)) -/obj/item/mod/module/jetpack/proc/move_react(mob/user) - SIGNAL_HANDLER - - if(!active)//If jet dont work, it dont work - return - if(!isturf(mod.wearer.loc))//You can't use jet in nowhere or from mecha/closet - return - if(!(mod.wearer.movement_type & FLOATING) || mod.wearer.buckled)//You don't want use jet in gravity or while buckled. - return - if(mod.wearer.pulledby)//You don't must use jet if someone pull you - return - if(mod.wearer.throwing)//You don't must use jet if you thrown - return - if(user.client && length(user.client.keys_held & user.client.movement_keys))//You use jet when press keys. yes. - allow_thrust() - -/obj/item/mod/module/jetpack/proc/pre_move_react(mob/user) - SIGNAL_HANDLER - - ion_trail.oldposition = get_turf(src) - -/obj/item/mod/module/jetpack/proc/spacemove_react(mob/user, movement_dir) - SIGNAL_HANDLER - - if(active && (stabilizers || movement_dir)) - return COMSIG_MOVABLE_STOP_SPACEMOVE - -/obj/item/mod/module/jetpack/proc/allow_thrust() +/obj/item/mod/module/jetpack/proc/allow_thrust(use_fuel = TRUE) + if(!use_fuel) + return check_power(use_power_cost) if(!drain_power(use_power_cost)) - return - ion_trail.generate_effect() + return FALSE return TRUE +/obj/item/mod/module/jetpack/proc/get_user() + return mod.wearer + /obj/item/mod/module/jetpack/advanced name = "MOD advanced ion jetpack module" desc = "An improvement on the previous model of electric thrusters. This one achieves higher speeds through \ diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index ba2b2bd4691..aecad164c01 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -646,7 +646,7 @@ var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle) return get_line(current, ending) -/obj/projectile/Process_Spacemove(movement_dir = 0) +/obj/projectile/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) return TRUE //Bullets don't drift in space /obj/projectile/process() diff --git a/code/modules/surgery/organs/augments_chest.dm b/code/modules/surgery/organs/augments_chest.dm index 7d3f569911a..4498cf5d58c 100644 --- a/code/modules/surgery/organs/augments_chest.dm +++ b/code/modules/surgery/organs/augments_chest.dm @@ -128,81 +128,68 @@ actions_types = list(/datum/action/item_action/organ_action/toggle) w_class = WEIGHT_CLASS_NORMAL var/on = FALSE - var/datum/effect_system/trail_follow/ion/ion_trail + var/datum/callback/get_mover + var/datum/callback/check_on_move -/obj/item/organ/cyberimp/chest/thrusters/Insert(mob/living/carbon/thruster_owner, special = 0) +/obj/item/organ/cyberimp/chest/thrusters/Initialize(mapload) . = ..() - if(!ion_trail) - ion_trail = new - ion_trail.auto_process = FALSE - ion_trail.set_up(thruster_owner) + get_mover = CALLBACK(src, .proc/get_user) + check_on_move = CALLBACK(src, .proc/allow_thrust, 0.01) + refresh_jetpack() + +/obj/item/organ/cyberimp/chest/thrusters/Destroy() + get_mover = null + check_on_move = null + return ..() + +/obj/item/organ/cyberimp/chest/thrusters/proc/refresh_jetpack() + AddComponent(/datum/component/jetpack, FALSE, COMSIG_THRUSTER_ACTIVATED, COMSIG_THRUSTER_DEACTIVATED, THRUSTER_ACTIVATION_FAILED, get_mover, check_on_move, /datum/effect_system/trail_follow/ion) /obj/item/organ/cyberimp/chest/thrusters/Remove(mob/living/carbon/thruster_owner, special = 0) if(on) - toggle(silent = TRUE) + deactivate(silent = TRUE) ..() /obj/item/organ/cyberimp/chest/thrusters/ui_action_click() toggle() /obj/item/organ/cyberimp/chest/thrusters/proc/toggle(silent = FALSE) - if(!on) - if((organ_flags & ORGAN_FAILING)) - if(!silent) - to_chat(owner, span_warning("Your thrusters set seems to be broken!")) - return FALSE - if(allow_thrust(0.01)) - on = TRUE - ion_trail.start() - RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/move_react) - RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move_react) - RegisterSignal(owner, COMSIG_MOVABLE_SPACEMOVE, .proc/spacemove_react) - owner.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) - if(!silent) - to_chat(owner, span_notice("You turn your thrusters set on.")) + if(on) + deactivate() else - ion_trail.stop() - UnregisterSignal(owner, COMSIG_MOVABLE_MOVED) - UnregisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE) - UnregisterSignal(owner, COMSIG_MOVABLE_SPACEMOVE) - owner.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) + activate() + +/obj/item/organ/cyberimp/chest/thrusters/proc/activate(silent = FALSE) + if(on) + return + if(organ_flags & ORGAN_FAILING) if(!silent) - to_chat(owner, span_notice("You turn your thrusters set off.")) - on = FALSE + to_chat(owner, span_warning("Your thrusters set seems to be broken!")) + return + if(SEND_SIGNAL(src, COMSIG_THRUSTER_ACTIVATED) & THRUSTER_ACTIVATION_FAILED) + return + + on = TRUE + owner.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) + if(!silent) + to_chat(owner, span_notice("You turn your thrusters set on.")) + update_appearance() + +/obj/item/organ/cyberimp/chest/thrusters/proc/deactivate(silent = FALSE) + if(!on) + return + SEND_SIGNAL(src, COMSIG_THRUSTER_DEACTIVATED) + owner.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) + if(!silent) + to_chat(owner, span_notice("You turn your thrusters set off.")) + on = FALSE update_appearance() /obj/item/organ/cyberimp/chest/thrusters/update_icon_state() icon_state = "[base_icon_state][on ? "-on" : null]" return ..() -/obj/item/organ/cyberimp/chest/thrusters/proc/move_react() - SIGNAL_HANDLER - if(!on)//If jet dont work, it dont work - return - if(!owner)//Don't allow jet self using - return - if(!isturf(owner.loc))//You can't use jet in nowhere or in mecha/closet - return - if(!(owner.movement_type & FLOATING) || owner.buckled)//You don't want use jet in gravity or while buckled. - return - if(owner.pulledby)//You don't must use jet if someone pull you - return - if(owner.throwing)//You don't must use jet if you thrown - return - if(length(owner.client.keys_held & owner.client.movement_keys))//You use jet when press keys. yes. - allow_thrust(0.01) - -/obj/item/organ/cyberimp/chest/thrusters/proc/pre_move_react() - SIGNAL_HANDLER - ion_trail.oldposition = get_turf(owner) - -/obj/item/organ/cyberimp/chest/thrusters/proc/spacemove_react(mob/user, movement_dir) - SIGNAL_HANDLER - - if(on && movement_dir) - return COMSIG_MOVABLE_STOP_SPACEMOVE - -/obj/item/organ/cyberimp/chest/thrusters/proc/allow_thrust(num) +/obj/item/organ/cyberimp/chest/thrusters/proc/allow_thrust(num, use_fuel = TRUE) if(!owner) return FALSE @@ -213,27 +200,29 @@ // Priority 1: use air from environment. var/datum/gas_mixture/environment = owner_turf.return_air() if(environment && environment.return_pressure() > 30) - ion_trail.generate_effect() return TRUE // Priority 2: use plasma from internal plasma storage. // (just in case someone would ever use this implant system to make cyber-alien ops with jetpacks and taser arms) - if(owner.getPlasma() >= num*100) - owner.adjustPlasma(-num*100) - ion_trail.generate_effect() + if(owner.getPlasma() >= num * 100) + if(use_fuel) + owner.adjustPlasma(-num * 100) return TRUE // Priority 3: use internals tank. - var/datum/gas_mixture/internal_mix = owner.internal.return_air() + var/datum/gas_mixture/internal_mix = owner.internal?.return_air() if(internal_mix && internal_mix.total_moles() > num) + if(!use_fuel) + return TRUE var/datum/gas_mixture/removed = internal_mix.remove(num) if(removed.total_moles() > 0.005) owner_turf.assume_air(removed) - ion_trail.generate_effect() return TRUE else owner_turf.assume_air(removed) - ion_trail.generate_effect() - toggle(silent = TRUE) + deactivate(silent = TRUE) return FALSE + +/obj/item/organ/cyberimp/chest/thrusters/proc/get_user() + return owner diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm index a48cfc3ccf6..8d37932e6cd 100644 --- a/code/modules/vehicles/mecha/mecha_movement.dm +++ b/code/modules/vehicles/mecha/mecha_movement.dm @@ -18,22 +18,23 @@ to_chat(occupants, "[icon2html(src, occupants)][span_warning("Air port connection has been severed!")]") log_message("Lost connection to gas port.", LOG_MECHA) -/obj/vehicle/sealed/mecha/Process_Spacemove(movement_dir = 0) +// Do whatever you do to mobs to these fuckers too +/obj/vehicle/sealed/mecha/Process_Spacemove(movement_dir = 0, continuous_move = FALSE) . = ..() if(.) - return + return TRUE - var/atom/backup = get_spacemove_backup(movement_dir) - if(backup && movement_dir) - if(isturf(backup)) //get_spacemove_backup() already checks if a returned turf is solid, so we can just go - return TRUE - if(istype(backup, /atom/movable)) - var/atom/movable/movable_backup = backup - if((!movable_backup.anchored) && (movable_backup.newtonian_move(turn(movement_dir, 180)))) - step_silent = TRUE - if(return_drivers()) - to_chat(occupants, "[icon2html(src, occupants)][span_info("The [src] push off [movable_backup] to propel yourself.")]") + var/atom/movable/backup = get_spacemove_backup(movement_dir, continuous_move) + if(backup) + if(!istype(backup) || !movement_dir || backup.anchored || continuous_move) //get_spacemove_backup() already checks if a returned turf is solid, so we can just go return TRUE + last_pushoff = world.time + if(backup.newtonian_move(turn(movement_dir, 180), instant = TRUE)) + backup.last_pushoff = world.time + step_silent = TRUE + if(return_drivers()) + to_chat(occupants, "[icon2html(src, occupants)][span_info("The [src] push off [backup] to propel yourself.")]") + return TRUE if(active_thrusters?.thrust(movement_dir)) step_silent = TRUE diff --git a/tgstation.dme b/tgstation.dme index abc9c35c4b6..2c019aa885c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -758,6 +758,7 @@ #include "code\datums\components\infective.dm" #include "code\datums\components\irradiated.dm" #include "code\datums\components\itempicky.dm" +#include "code\datums\components\jetpack.dm" #include "code\datums\components\jousting.dm" #include "code\datums\components\knockoff.dm" #include "code\datums\components\label.dm"