diff --git a/code/datums/forced_movement.dm b/code/datums/forced_movement.dm new file mode 100644 index 00000000000..2f9867bafc3 --- /dev/null +++ b/code/datums/forced_movement.dm @@ -0,0 +1,90 @@ +//Just new and forget +/datum/forced_movement + var/atom/movable/victim + var/atom/target + var/last_processed + var/steps_per_tick + var/allow_climbing + var/datum/callback/on_step + var/moved_at_all = FALSE + //as fast as ssfastprocess +/datum/forced_movement/New(atom/movable/_victim, atom/_target, _steps_per_tick = 0.5, _allow_climbing = FALSE, datum/callback/_on_step = null) + victim = _victim + target = _target + steps_per_tick = _steps_per_tick + allow_climbing = _allow_climbing + on_step = _on_step + + . = ..() + + if(_victim && _target && _steps_per_tick && !_victim.force_moving) + last_processed = world.time + _victim.force_moving = src + START_PROCESSING(SSfastprocess, src) + else + qdel(src) //if you want to overwrite the current forced movement, call qdel(victim.force_moving) before creating this + +/datum/forced_movement/Destroy() + if(victim.force_moving == src) + victim.force_moving = null + if(moved_at_all) + victim.forceMove(victim.loc) //get the side effects of moving here that require us to currently not be force_moving aka reslipping on ice + STOP_PROCESSING(SSfastprocess, src) + victim = null + target = null + return ..() + +/datum/forced_movement/process() + if(qdeleted(victim) || !victim.loc || qdeleted(target) || !target.loc) + qdel(src) + return + var/steps_to_take = round(steps_per_tick * (world.time - last_processed)) + if(steps_to_take) + for(var/i in 1 to steps_to_take) + if(TryMove()) + moved_at_all = TRUE + if(on_step) + on_step.InvokeAsync() + else + qdel(src) + return + last_processed = world.time + +/datum/forced_movement/proc/TryMove(recursive = FALSE) + var/atom/movable/vic = victim //sanic + var/atom/tar = target + + if(!recursive) + . = step_towards(vic, tar) + + //shit way for getting around corners + if(!.) + if(tar.x > vic.x) + if(step(vic, EAST)) + . = TRUE + else if(tar.x < vic.x) + if(step(vic, WEST)) + . = TRUE + + if(!.) + if(tar.y > vic.y) + if(step(vic, NORTH)) + . = TRUE + else if(tar.y < vic.y) + if(step(vic, SOUTH)) + . = TRUE + + if(!.) + if(recursive) + return FALSE + else + . = TryMove(TRUE) + + . = . && (vic.loc != tar.loc) + +/mob/Bump(atom/A) + . = ..() + if(force_moving && force_moving.allow_climbing && istype(A,/obj/structure)) + var/obj/structure/S = A + if(S.climbable) + S.do_climb(src) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 876a4fa5ff2..204daf2536b 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -23,6 +23,7 @@ var/list/acted_explosions //for explosion dodging glide_size = 8 appearance_flags = TILE_BOUND + var/datum/forced_movement/force_moving = null //handled soley by forced_movement.dm @@ -139,10 +140,12 @@ if(pulledby) pulledby.stop_pulling() var/atom/oldloc = loc - if(oldloc) + var/same_loc = oldloc == destination.loc + if(oldloc && !same_loc) oldloc.Exited(src, destination) loc = destination - destination.Entered(src, oldloc) + if(oldloc && !same_loc) + destination.Entered(src, oldloc) var/area/old_area = get_area(oldloc) var/area/destarea = get_area(destination) if(old_area != destarea) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 34683c45b7a..69abe624adb 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -64,6 +64,12 @@ step(O, get_dir(O, src)) return +/obj/structure/proc/do_climb(atom/movable/A) + if(climbable) + density = 0 + . = step(A,get_dir(A,src.loc)) + density = 1 + /obj/structure/proc/climb_structure(mob/user) src.add_fingerprint(user) user.visible_message("[user] starts climbing onto [src].", \ @@ -76,8 +82,7 @@ structureclimber = user if(do_mob(user, user, adjusted_climb_time)) if(src.loc) //Checking if structure has been destroyed - density = 0 - if(step(user,get_dir(user,src.loc))) + if(do_climb(user)) user.visible_message("[user] climbs onto [src].", \ "You climb onto [src].") add_logs(user, src, "climbed onto") @@ -85,7 +90,6 @@ . = 1 else user << "You fail to climb onto [src]." - density = 1 structureclimber = null /obj/structure/examine(mob/user) diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 484cfdee7ac..68186429059 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -141,7 +141,7 @@ return 1 /turf/open/handle_slip(mob/living/carbon/C, s_amount, w_amount, obj/O, lube) - if((C.movement_type & FLYING) || C.slipping) + if(C.movement_type & FLYING) return 0 if(has_gravity(src)) var/obj/buckled_obj @@ -173,20 +173,12 @@ if(buckled_obj) buckled_obj.unbuckle_mob(C) - step(buckled_obj, olddir) - else if(lube&SLIDE) - C.slipping = TRUE - for(var/i=1, i<5, i++) - spawn (i) - if(i == 4) - C.slipping = FALSE - step(C, olddir) - C.spin(1,1) + lube |= SLIDE_ICE + + if(lube&SLIDE) + new /datum/forced_movement(C, get_ranged_target_turf(C, olddir, 4), 1, FALSE, CALLBACK(C, /mob/living/carbon/.proc/spin, 1, 1)) else if(lube&SLIDE_ICE) - C.slipping = TRUE - spawn(1) - C.slipping = FALSE - step(C, olddir) + new /datum/forced_movement(C, get_ranged_target_turf(C, olddir, 1), 1, FALSE) //spinning would be bad for ice, fucks up the next dir return 1 /turf/open/proc/MakeSlippery(wet_setting = TURF_WET_WATER, min_wet_time = 0, wet_time_to_add = 0) // 1 = Water, 2 = Lube, 3 = Ice, 4 = Permafrost, 5 = Slide diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 9a2d9acd6de..3361c29d954 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -193,14 +193,18 @@ if(firer) chain = firer.Beam(src, icon_state = "chain", time = INFINITY, maxdistance = INFINITY) ..() + //TODO: root the firer until the chain returns /obj/item/projectile/hook/on_hit(atom/target) . = ..() - if(isliving(target)) - var/mob/living/L = target - if(!L.anchored) - L.visible_message("[L] is snagged by [firer]'s hook!") - L.forceMove(get_turf(firer)) + if(istype(target, /atom/movable)) + var/atom/movable/A = target + if(A.anchored) + return + A.visible_message("[A] is snagged by [firer]'s hook!") + new /datum/forced_movement(A, get_turf(firer), 5, TRUE) + //TODO: keep the chain beamed to A + //TODO: needs a callback to delete the chain /obj/item/projectile/hook/Destroy() qdel(chain) diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm index e976375b6ab..81266f9d974 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm @@ -22,10 +22,7 @@ if(user.a_intent == INTENT_HARM) ..(user, 1) adjustBruteLoss(5 + rand(1,9)) - spawn() - step_away(src,user,15) - sleep(1) - step_away(src,user,15) + new /datum/forced_movement(src, get_step_away(user,src, 30), 1) return 1 /mob/living/carbon/alien/larva/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 809303da446..29965c802de 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -519,7 +519,7 @@ if (AM.density && AM.anchored) pressure_resistance_prob_delta -= 20 break - if(!slipping) + if(!force_moving) ..(pressure_difference, direction, pressure_resistance_prob_delta) /mob/living/verb/resist() diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 58625ace4a9..0b2fb83bc9f 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -74,6 +74,4 @@ var/list/status_effects //a list of all status effects the mob has - var/slipping = FALSE - var/list/implants = null \ No newline at end of file diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 76f768494d2..d029187d6bd 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -127,10 +127,10 @@ return 0 if(moving) return 0 + if(mob.force_moving) + return 0 if(isliving(mob)) var/mob/living/L = mob - if(L.slipping) - return 0 if(L.incorporeal_move) //Move though walls Process_Incorpmove(direct) return 0 diff --git a/tgstation.dme b/tgstation.dme index 223c360e542..fc8418fe000 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -196,6 +196,7 @@ #include "code\datums\dna.dm" #include "code\datums\dog_fashion.dm" #include "code\datums\emotes.dm" +#include "code\datums\forced_movement.dm" #include "code\datums\gas_overrides.dm" #include "code\datums\hud.dm" #include "code\datums\martial.dm"