diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index f67a00faf56..f5b7f5bd10f 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -38,7 +38,7 @@ for(var/atom/movable/AM as mob|obj in src) Entered(AM) - + turfs += src if(dynamic_lighting) diff --git a/code/modules/clothing/spacesuits/rig/modules/utility.dm b/code/modules/clothing/spacesuits/rig/modules/utility.dm index 16c89569fc0..a3c2471011e 100644 --- a/code/modules/clothing/spacesuits/rig/modules/utility.dm +++ b/code/modules/clothing/spacesuits/rig/modules/utility.dm @@ -14,6 +14,8 @@ * /obj/item/rig_module/device/paperdispenser * /obj/item/rig_module/device/pen * /obj/item/rig_module/device/stamp + * /obj/item/rig_module/actuators + * /obj/item/rig_module/actuators/combat */ /obj/item/rig_module/device @@ -472,3 +474,143 @@ interface_desc = "Eats trash like no one's business." device_type = /obj/item/weapon/matter_decompiler + +/obj/item/rig_module/actuators + name = "leg actuators" + desc = "A set of electromechanical actuators, for safe travesal of multilevelled areas." + icon_state = "generic" + interface_name = "leg actuators" + interface_desc = "Allows you to fall from heights and to jump up onto ledges." + + disruptive = 1 + + use_power_cost = 5 + module_cooldown = 25 + + /* + * TOGGLE - dampens fall, on or off. + * SELECTABLE - Jump forward or up! + */ + toggleable = 1 + selectable = 1 + usable = 0 + + engage_string = "Toggle Leg Actuators" + activate_string = "Enable Leg Actuators" + deactivate_string = "Disable Leg Actuators" + + var/combatType = 0 // Determines whether or not the actuators can do special combat oriented tasks. + // Such as leaping faster, or grappling targets. + var/leapDistance = 4 // Determines how far the actuators allow you to leap (radius, inclusive). + +/obj/item/rig_module/actuators/combat + name = "military grade leg actuators" + desc = "A set of high-powered hydraulic actuators, for improved traversal of multilevelled areas." + interface_name = "combat leg actuators" + + combatType = 1 + leapDistance = 7 + + use_power_cost = 10 + +/obj/item/rig_module/actuators/engage(var/atom/target) + if (!..()) + return 0 + + // This is for when you toggle it on or off. Why do they both run the same + // proc chain ...? :l + if (!target) + return 1 + + var/mob/living/carbon/human/H = holder.wearer + + if (!isturf(H.loc)) + to_chat(H, "You cannot leap out of your current location!") + return 0 + + var/turf/T = get_turf(target) + + if (!T || T.density) + to_chat(H, "You cannot leap at solid walls!") + return 0 + + // Saved, we need it more than 1 place. + var/dist = max(get_dist(T, get_turf(H)), 0) + + if (dist) + for (var/A in T) + var/atom/aa = A + if (combatType && ismob(aa)) + continue + + if (aa.density) + to_chat(H, "You cannot leap at a location with solid objects on it!") + return 0 + + if (T.z != H.z || dist > leapDistance) + to_chat(H, "You cannot leap at such a distant object!") + return 0 + + // Handle leaping at targets with a combat capable version here. + if (combatType && dist && (ismob(target) || (locate(/mob/living) in T))) + H.leap(target, leapDistance) + return 1 + + // If dist -> horizontal leap. Otherwise, the user clicked the turf that they're + // currently on. Which means they want to do a vertical leap upwards! + if (dist) + H.visible_message("\The [H] leaps horizontally at \the [T]!", + "You leap horizontally at \the [T]!", + "You hear an electric whirr followed by a weighty thump!") + H.face_atom(T) + H.throw_at(T, leapDistance, 1, src) + return 1 + else + var/turf/simulated/open/TA = GetAbove(src) + if (!istype(TA)) + to_chat(H, "There is a ceiling above you that stop you from leaping upwards!") + return 0 + + for (var/atom/A in TA) + if (!A.CanPass(src, TA, 1.5, 0)) + to_chat(H, "\The [A] blocks you!") + return 0 + + var/turf/leapEnd = get_step(TA, H.dir) + if (!leapEnd || istype(leapEnd, /turf/simulated/open) || istype(leapEnd, /turf/space)\ + || leapEnd.density || leapEnd.contains_dense_objects()) + to_chat(H, "There is no valid ledge to scale ahead of you!") + return 0 + + H.visible_message("\The [H] leaps up, out of view!", + "You leap up!") + + // This setting is necessary even for combat type, to stop you from moving onto + // the turf, falling back down, and then getting forcemoved to the final destination. + LAZYADD(TA.climbers, H) + + H.forceMove(TA) + + // Combat type actuators are better, they allow you to jump instantly onto + // a ledge. Regular actuators make you have to climb the rest of the way. + if (!combatType) + H.visible_message("\The [H] starts pulling \himself up onto \the [leapEnd].", + "You start pulling yourself up onto \the [leapEnd].") + if (!do_after(H, 4 SECONDS, use_user_turf = TRUE)) + H.visible_message("\The [H] is interrupted and falls!", + "You are interrupted and fall back down!") + LAZYREMOVE(TA.climbers, H) + + ADD_FALLING_ATOM(H) + return 1 + + H.visible_message("\The [H] finishes climbing onto \the [leapEnd].", + "You finish climbing onto \the [leapEnd].") + else + H.visible_message("\The [H] lands on \the [leapEnd] with a heavy slam!", + "You land on \the [leapEnd] with a heavy thud!") + + LAZYREMOVE(TA.climbers, H) + H.forceMove(leapEnd) + + return 1 diff --git a/code/modules/clothing/spacesuits/rig/suits/light.dm b/code/modules/clothing/spacesuits/rig/suits/light.dm index 0795d09ec04..68b8a785e9c 100644 --- a/code/modules/clothing/spacesuits/rig/suits/light.dm +++ b/code/modules/clothing/spacesuits/rig/suits/light.dm @@ -97,7 +97,8 @@ /obj/item/rig_module/ai_container, /obj/item/rig_module/power_sink, /obj/item/rig_module/datajack, - /obj/item/rig_module/self_destruct + /obj/item/rig_module/self_destruct, + /obj/item/rig_module/actuators/combat ) ..() diff --git a/code/modules/clothing/spacesuits/rig/suits/merc.dm b/code/modules/clothing/spacesuits/rig/suits/merc.dm index d56db0c3f6d..211b783fc0d 100644 --- a/code/modules/clothing/spacesuits/rig/suits/merc.dm +++ b/code/modules/clothing/spacesuits/rig/suits/merc.dm @@ -25,12 +25,14 @@ /obj/item/rig_module/power_sink, /obj/item/rig_module/electrowarfare_suite, /obj/item/rig_module/chem_dispenser/combat, - /obj/item/rig_module/fabricator/energy_net + /obj/item/rig_module/fabricator/energy_net, + /obj/item/rig_module/actuators/combat ) //Has most of the modules removed /obj/item/weapon/rig/merc/empty initial_modules = list( /obj/item/rig_module/ai_container, - /obj/item/rig_module/electrowarfare_suite //might as well + /obj/item/rig_module/electrowarfare_suite, //might as well + /obj/item/rig_module/actuators/combat // What the dude above me said. ) diff --git a/code/modules/clothing/spacesuits/rig/suits/station.dm b/code/modules/clothing/spacesuits/rig/suits/station.dm index 3b56e45540b..6f0222d30be 100644 --- a/code/modules/clothing/spacesuits/rig/suits/station.dm +++ b/code/modules/clothing/spacesuits/rig/suits/station.dm @@ -81,7 +81,8 @@ /obj/item/rig_module/device/drill, /obj/item/rig_module/device/orescanner, /obj/item/rig_module/device/rcd, - /obj/item/rig_module/vision/meson + /obj/item/rig_module/vision/meson, + /obj/item/rig_module/actuators ) /obj/item/weapon/rig/industrial/syndicate @@ -147,7 +148,8 @@ /obj/item/rig_module/maneuvering_jets, /obj/item/rig_module/mounted/plasmacutter, /obj/item/rig_module/device/rcd, - /obj/item/rig_module/vision/meson + /obj/item/rig_module/vision/meson, + /obj/item/rig_module/actuators ) /obj/item/clothing/gloves/rig/ce diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm index 10bcfd127a2..3bdc97c1498 100644 --- a/code/modules/mob/living/carbon/human/human_powers.dm +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -49,7 +49,7 @@ if ((O.client && !( O.blinded ))) O.show_message(text("[] [failed ? "tried to tackle" : "has tackled"] down []!", src, T), 1) -/mob/living/carbon/human/proc/leap() +/mob/living/carbon/human/proc/leap(var/mob/living/T = null, var/max_range = 4) set category = "Abilities" set name = "Leap" set desc = "Leap at a target and grab them aggressively." @@ -61,17 +61,18 @@ src << "You cannot leap in your current state." return - var/list/choices = list() - for(var/mob/living/M in view(6,src)) - if(!istype(M,/mob/living/silicon)) - choices += M - choices -= src + if (!T) + var/list/choices = list() + for(var/mob/living/M in view(6,src)) + if(!istype(M,/mob/living/silicon)) + choices += M + choices -= src - var/mob/living/T = input(src,"Who do you wish to leap at?") as null|anything in choices + T = input(src,"Who do you wish to leap at?") as null|anything in choices if(!T || !src || src.stat) return - if(get_dist(get_turf(T), get_turf(src)) > 4) return + if(get_dist(get_turf(T), get_turf(src)) > max_range) return if(last_special > world.time) return @@ -85,7 +86,10 @@ src.visible_message("\The [src] leaps at [T]!") src.throw_at(get_step(get_turf(T),get_turf(src)), 4, 1, src) - playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) + + // Only Vox get to shriek. Seriously. + if (isvox(src)) + playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) sleep(5) diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm index 95a4613bdbb..35ebccfbf86 100644 --- a/code/modules/multiz/movement.dm +++ b/code/modules/multiz/movement.dm @@ -189,8 +189,12 @@ if(locate(/obj/structure/lattice, dest) || locate(/obj/structure/stairs, dest)) return FALSE + // The var/climbers API is implemented here. + if (LAZYLEN(dest.climbers) && (src in dest.climbers)) + return FALSE + // See if something prevents us from falling. - for(var/atom/A in below) + for (var/atom/A in below) if(!A.CanPass(src, dest)) return FALSE @@ -212,6 +216,10 @@ // Only things that stop mechas are atoms that, well, stop them. // Lattices and stairs get crushed in fall_through. /obj/mecha/can_fall(turf/below, turf/simulated/open/dest = src.loc) + // The var/climbers API is implemented here. + if (LAZYLEN(dest.climbers) && (src in dest.climbers)) + return FALSE + // See if something prevents us from falling. for(var/atom/A in below) if(!A.CanPass(src, dest)) diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm index a47b00b51b7..d74bd86aaf9 100644 --- a/code/modules/multiz/turf.dm +++ b/code/modules/multiz/turf.dm @@ -42,6 +42,9 @@ var/tmp/depth + var/tmp/list/climbers // A lazy list to contain a list of mobs who are currently scaling + // up this turf. Used in human/can_fall. + // An override of turf/Enter() to make it so that magboots allow you to stop // falling off the damned rock. /turf/simulated/open/Enter(mob/living/carbon/human/mover, atom/oldloc) @@ -66,6 +69,10 @@ above = null below = null + + LAZYCLEARLIST(climbers) + UNSETEMPTY(climbers) + return ..() /turf/simulated/open/get_smooth_underlay_icon(image/underlay_appearance, turf/asking_turf, adjacency_dir) diff --git a/html/changelogs/skull132-actuators.yml b/html/changelogs/skull132-actuators.yml new file mode 100644 index 00000000000..d761b3da3ef --- /dev/null +++ b/html/changelogs/skull132-actuators.yml @@ -0,0 +1,6 @@ +author: Skull132 + +delete-after: True + +changes: + - rscadd: "Added the leg actuator RIG module. These allow you to fall from heights if enabled, without taking damage; to leap horizontally (Vox style); and to climb up open turfs if you're facing a solid turf above you. Combat versions also allow you to grapel people."