kinesis changes + smaller misc modsuit stuff (#77241)

## About The Pull Request
renames plasmaman helmet exempt flag to stackable helmet exempt. hat
stabilizer now cares about this instead of letting you stack eva helmets
on top of modsuit helmets
improves some code that dripped in quality when i was on break
kinesis has some tweaks
previously it used to stun for a set amount of time - i think this is
because the creator couldnt figure out how to stop movement while being
held? this is changed, now as long as youre holding someone they are
immobilized
you can cancel your kinesis without throwing or moving out of range by
using right click on the click catcher
adds an admin version of kinesis just for the admin suit. it can grab
(almost) ANYTHING and config menu lets you enable phasing, which makes
it so the atom you grabbed phases through everything. pick up that can.

## Why It's Good For The Game
its fun

## Changelog
🆑
balance: hat stabilizer module can now hold what plasmaman helmets can
hold
qol: kinesis module can be stopped without launching an object with
right click
balance: kinesis module stuns last until the kinesis stops
add: admin suit has a version of kinesis that can pick up anything at
any range and can be configured to make grabbed mobs phase through walls
:)
/🆑
This commit is contained in:
Fikou
2023-08-02 19:47:57 +00:00
committed by GitHub
parent 3e72c200f0
commit ba6c2ffa4c
21 changed files with 203 additions and 100 deletions
+5 -7
View File
@@ -46,7 +46,9 @@
/obj/item/mod/construction/broken_core/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
balloon_alert(user, "repairing...")
if(!tool.use_tool(src, user, 5 SECONDS, volume = 30))
balloon_alert(user, "interrupted!")
return
new /obj/item/mod/core/standard(drop_location())
qdel(src)
@@ -66,20 +68,16 @@
/obj/item/mod/construction/lavalandcore/attackby(obj/item/weapon, mob/user, params)
if(!istype(weapon, /obj/item/stack/cable_coil))
return
return ..()
if(!weapon.tool_start_check(user, amount=2))
return
to_chat(user, span_notice("You start pushing the wires into the core..."))
balloon_alert(user, "installing wires...")
if(!weapon.use_tool(src, user, 5 SECONDS, amount = 2, volume = 30))
balloon_alert(user, "interrupted!")
return
to_chat(user, span_notice("You add the wires to the core."))
new /obj/item/mod/core/plasma/lavaland(drop_location())
qdel(src)
/obj/item/mod/construction/plating
name = "MOD external plating"
desc = "External plating used to finish a MOD control unit."
+26 -31
View File
@@ -370,49 +370,23 @@
light_system = MOVABLE_LIGHT
light_color = "#cc00cc"
light_range = 2
// Slightly better than the normal plasma core.
// Not super sure if this should just be the same, but will see.
maxcharge = 15000
charge = 15000
/// The mob to be spawned by the core
var/mob/living/spawned_mob_type = /mob/living/basic/butterfly/lavaland/temporary
/// Max number of mobs it can spawn
var/max_spawns = 3
/// Mob spawner for the core
var/datum/component/spawner/mob_spawner
/// Particle holder for pollen particles
var/obj/effect/abstract/particle_holder/particle_effect
/obj/item/mod/core/plasma/lavaland/Destroy()
if(mod?.wearer)
mod.wearer.particles = null
QDEL_NULL(particle_effect)
return ..()
/obj/item/mod/core/plasma/lavaland/proc/new_mob(spawner, mob/living/basic/butterfly/lavaland/temporary/spawned)
SIGNAL_HANDLER
if(spawned)
spawned.source = src
/obj/item/mod/core/plasma/lavaland/proc/on_toggle()
SIGNAL_HANDLER
if(mod.active)
START_PROCESSING(SSprocessing, src)
mod.wearer.particles = new /particles/pollen()
mob_spawner = mod.wearer.AddComponent(/datum/component/spawner, spawn_types=list(spawned_mob_type), spawn_time=5 SECONDS, max_spawned=3)
RegisterSignal(mob_spawner, COMSIG_SPAWNER_SPAWNED, PROC_REF(new_mob))
RegisterSignal(mod.wearer, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(flowas))
else
STOP_PROCESSING(SSprocessing, src)
mod.wearer.particles = null
UnregisterSignal(mob_spawner, COMSIG_SPAWNER_SPAWNED)
UnregisterSignal(mod.wearer, COMSIG_MOVABLE_PRE_MOVE)
for(var/datum/mob in mob_spawner.spawned_things)
qdel(mob)
qdel(mob_spawner)
/obj/item/mod/core/plasma/lavaland/install(obj/item/mod/control/mod_unit)
. = ..()
RegisterSignal(mod_unit, COMSIG_MOD_TOGGLED, PROC_REF(on_toggle))
@@ -421,7 +395,28 @@
. = ..()
UnregisterSignal(mod_unit, COMSIG_MOD_TOGGLED)
/obj/item/mod/core/plasma/lavaland/proc/flowas(mob/living/wearer)
/obj/item/mod/core/plasma/lavaland/proc/on_toggle()
SIGNAL_HANDLER
if(mod.active)
particle_effect = new(mod.wearer, /particles/pollen, PARTICLE_ATTACH_MOB)
mob_spawner = mod.wearer.AddComponent(/datum/component/spawner, spawn_types=list(spawned_mob_type), spawn_time=5 SECONDS, max_spawned=3)
RegisterSignal(mob_spawner, COMSIG_SPAWNER_SPAWNED, PROC_REF(new_mob))
RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(spread_flowers))
else
QDEL_NULL(particle_effect)
UnregisterSignal(mob_spawner, COMSIG_SPAWNER_SPAWNED)
UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED)
for(var/datum/mob in mob_spawner.spawned_things)
qdel(mob)
qdel(mob_spawner)
/obj/item/mod/core/plasma/lavaland/proc/new_mob(spawner, mob/living/basic/butterfly/lavaland/temporary/spawned)
SIGNAL_HANDLER
if(spawned)
spawned.source = src
/obj/item/mod/core/plasma/lavaland/proc/spread_flowers(atom/source, atom/oldloc, dir, forced)
SIGNAL_HANDLER
var/static/list/possible_flower_types = list(
/obj/structure/flora/bush/lavendergrass/style_random,
@@ -430,6 +425,6 @@
/obj/structure/flora/bush/flowers_pp/style_random,
)
var/chosen_type = pick(possible_flower_types)
var/flower_boots = new chosen_type(get_turf(wearer))
var/flower_boots = new chosen_type(get_turf(mod.wearer))
animate(flower_boots, alpha = 0, 1 SECONDS)
QDEL_IN(flower_boots, 1 SECONDS)
+3 -3
View File
@@ -1389,7 +1389,7 @@
slowdown_inactive = 1.5
slowdown_active = 1
ui_theme = "hackerman"
inbuilt_modules = list(/obj/item/mod/module/anomaly_locked/kinesis/prebuilt/prototype)
inbuilt_modules = list(/obj/item/mod/module/anomaly_locked/kinesis/prototype)
allowed_suit_storage = list(
/obj/item/analyzer,
/obj/item/t_scanner,
@@ -1717,7 +1717,7 @@
siemens_coefficient = 0
slowdown_inactive = 0.5
slowdown_active = 0
activation_step_time = 0.4 SECONDS
activation_step_time = MOD_ACTIVATION_STEP_TIME * 0.2
allowed_suit_storage = list(
/obj/item/gun,
)
@@ -1777,7 +1777,7 @@
siemens_coefficient = 0
slowdown_inactive = 0
slowdown_active = 0
activation_step_time = 0.1 SECONDS
activation_step_time = MOD_ACTIVATION_STEP_TIME * 0.01
allowed_suit_storage = list(
/obj/item/gun,
)
+3 -3
View File
@@ -344,7 +344,7 @@
)
default_pins = list(
/obj/item/mod/module/tether,
/obj/item/mod/module/anomaly_locked/kinesis/prebuilt/prototype,
/obj/item/mod/module/anomaly_locked/kinesis/prototype,
)
/obj/item/mod/control/pre_equipped/responsory
@@ -505,13 +505,13 @@
/obj/item/mod/module/quick_carry/advanced,
/obj/item/mod/module/magboot/advanced,
/obj/item/mod/module/jetpack/advanced,
/obj/item/mod/module/anomaly_locked/kinesis/plus,
/obj/item/mod/module/anomaly_locked/kinesis/admin,
)
default_pins = list(
/obj/item/mod/module/stealth/ninja,
/obj/item/mod/module/magboot/advanced,
/obj/item/mod/module/jetpack/advanced,
/obj/item/mod/module/anomaly_locked/kinesis/plus,
/obj/item/mod/module/anomaly_locked/kinesis/admin,
)
//these exist for the prefs menu
+122 -28
View File
@@ -21,8 +21,6 @@
var/hit_cooldown_time = 1 SECONDS
/// Stat required for us to grab a mob.
var/stat_required = DEAD
/// How long we stun a mob for.
var/mob_stun_time = 5 SECONDS
/// Atom we grabbed with kinesis.
var/atom/movable/grabbed_atom
/// Ref of the beam following the grabbed atom.
@@ -51,8 +49,9 @@
if(!mod.wearer.client)
return
if(grabbed_atom)
launch()
var/launched_object = grabbed_atom
clear_grab(playsound = FALSE)
launch(launched_object)
return
if(!range_check(target))
balloon_alert(mod.wearer, "too far!")
@@ -61,20 +60,7 @@
balloon_alert(mod.wearer, "can't grab!")
return
drain_power(use_power_cost)
grabbed_atom = target
if(isliving(grabbed_atom))
var/mob/living/grabbed_mob = grabbed_atom
grabbed_mob.Stun(mob_stun_time)
playsound(grabbed_atom, 'sound/effects/contractorbatonhit.ogg', 75, TRUE)
kinesis_icon = mutable_appearance(icon = 'icons/effects/effects.dmi', icon_state = "kinesis", layer = grabbed_atom.layer - 0.1)
kinesis_icon.appearance_flags = RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM
kinesis_icon.overlays += emissive_appearance(icon = 'icons/effects/effects.dmi', icon_state = "kinesis", offset_spokesman = grabbed_atom)
grabbed_atom.add_overlay(kinesis_icon)
kinesis_beam = mod.wearer.Beam(grabbed_atom, "kinesis")
kinesis_catcher = mod.wearer.overlay_fullscreen("kinesis", /atom/movable/screen/fullscreen/cursor_catcher/kinesis, 0)
kinesis_catcher.assign_to_mob(mod.wearer)
soundloop.start()
START_PROCESSING(SSfastprocess, src)
grab_atom(target)
/obj/item/mod/module/anomaly_locked/kinesis/on_deactivation(display_message = TRUE, deleting = FALSE)
. = ..()
@@ -158,6 +144,8 @@
if(!isliving(movable_target))
return FALSE
var/mob/living/living_target = movable_target
if(living_target.buckled)
return FALSE
if(living_target.stat < stat_required)
return FALSE
else if(isitem(movable_target))
@@ -168,9 +156,29 @@
return FALSE
return TRUE
/obj/item/mod/module/anomaly_locked/kinesis/proc/grab_atom(atom/movable/target)
grabbed_atom = target
if(isliving(grabbed_atom))
add_traits(grabbed_atom, list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), REF(src))
RegisterSignal(grabbed_atom, COMSIG_MOB_STATCHANGE, PROC_REF(on_statchange))
ADD_TRAIT(grabbed_atom, TRAIT_NO_FLOATING_ANIM, REF(src))
RegisterSignal(grabbed_atom, COMSIG_MOVABLE_SET_ANCHORED, PROC_REF(on_setanchored))
playsound(grabbed_atom, 'sound/effects/contractorbatonhit.ogg', 75, TRUE)
kinesis_icon = mutable_appearance(icon = 'icons/effects/effects.dmi', icon_state = "kinesis", layer = grabbed_atom.layer - 0.1)
kinesis_icon.appearance_flags = RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM
kinesis_icon.overlays += emissive_appearance(icon = 'icons/effects/effects.dmi', icon_state = "kinesis", offset_spokesman = grabbed_atom)
grabbed_atom.add_overlay(kinesis_icon)
kinesis_beam = mod.wearer.Beam(grabbed_atom, "kinesis")
kinesis_catcher = mod.wearer.overlay_fullscreen("kinesis", /atom/movable/screen/fullscreen/cursor_catcher/kinesis, 0)
kinesis_catcher.assign_to_mob(mod.wearer)
RegisterSignal(kinesis_catcher, COMSIG_CLICK, PROC_REF(on_catcher_click))
soundloop.start()
START_PROCESSING(SSfastprocess, src)
/obj/item/mod/module/anomaly_locked/kinesis/proc/clear_grab(playsound = TRUE)
if(!grabbed_atom)
return
. = grabbed_atom
if(playsound)
playsound(grabbed_atom, 'sound/effects/empulse.ogg', 75, TRUE)
STOP_PROCESSING(SSfastprocess, src)
@@ -178,6 +186,9 @@
mod.wearer.clear_fullscreen("kinesis")
grabbed_atom.cut_overlay(kinesis_icon)
QDEL_NULL(kinesis_beam)
if(isliving(grabbed_atom))
remove_traits(grabbed_atom, list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), REF(src))
REMOVE_TRAIT(grabbed_atom, TRAIT_NO_FLOATING_ANIM, REF(src))
if(!isitem(grabbed_atom))
animate(grabbed_atom, 0.2 SECONDS, pixel_x = grabbed_atom.base_pixel_x, pixel_y = grabbed_atom.base_pixel_y)
grabbed_atom = null
@@ -192,11 +203,31 @@
return FALSE
return TRUE
/obj/item/mod/module/anomaly_locked/kinesis/proc/launch()
playsound(grabbed_atom, 'sound/magic/repulse.ogg', 100, TRUE)
RegisterSignal(grabbed_atom, COMSIG_MOVABLE_IMPACT, PROC_REF(launch_impact))
var/turf/target_turf = get_turf_in_angle(get_angle(mod.wearer, grabbed_atom), get_turf(src), 10)
grabbed_atom.throw_at(target_turf, range = grab_range, speed = grabbed_atom.density ? 3 : 4, thrower = mod.wearer, spin = isitem(grabbed_atom))
/obj/item/mod/module/anomaly_locked/kinesis/proc/on_catcher_click(atom/source, location, control, params, user)
SIGNAL_HANDLER
var/list/modifiers = params2list(params)
if(LAZYACCESS(modifiers, RIGHT_CLICK))
clear_grab()
/obj/item/mod/module/anomaly_locked/kinesis/proc/on_statchange(mob/grabbed_mob, new_stat)
SIGNAL_HANDLER
if(new_stat < stat_required)
clear_grab()
/obj/item/mod/module/anomaly_locked/kinesis/proc/on_setanchored(atom/movable/grabbed_atom, anchorvalue)
SIGNAL_HANDLER
if(grabbed_atom.anchored)
clear_grab()
/obj/item/mod/module/anomaly_locked/kinesis/proc/launch(atom/movable/launched_object)
playsound(launched_object, 'sound/magic/repulse.ogg', 100, TRUE)
RegisterSignal(launched_object, COMSIG_MOVABLE_IMPACT, PROC_REF(launch_impact))
var/turf/target_turf = get_turf_in_angle(get_angle(mod.wearer, launched_object), get_turf(src), 10)
launched_object.throw_at(target_turf, range = grab_range, speed = launched_object.density ? 3 : 4, thrower = mod.wearer, spin = isitem(launched_object))
/obj/item/mod/module/anomaly_locked/kinesis/proc/launch_impact(atom/movable/source, atom/hit_atom, datum/thrownthing/thrownthing)
UnregisterSignal(source, COMSIG_MOVABLE_IMPACT)
@@ -215,25 +246,88 @@
if(damage_self && source.uses_integrity)
source.take_damage(source.max_integrity/5, BRUTE, MELEE)
/atom/movable/screen/fullscreen/cursor_catcher/kinesis
icon_state = "kinesis"
/obj/item/mod/module/anomaly_locked/kinesis/prebuilt
prebuilt = TRUE
/obj/item/mod/module/anomaly_locked/kinesis/prebuilt/prototype
/obj/item/mod/module/anomaly_locked/kinesis/prototype
name = "MOD prototype kinesis module"
prebuilt = TRUE
complexity = 0
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
removable = FALSE
/atom/movable/screen/fullscreen/cursor_catcher/kinesis
icon_state = "kinesis"
/obj/item/mod/module/anomaly_locked/kinesis/plus
name = "MOD kinesis+ module"
desc = "A modular plug-in to the forearm, this module was recently redeveloped in secret. \
The bane of all ne'er-do-wells, the kinesis+ module is a powerful tool that allows the user \
to manipulate the world around them. Like it's older counterpart, it's capable of manipulating \
structures, machinery, vehicles, and, thanks to the fruitful efforts of it's creators - living \
beings. They can, however, still struggle after an initial burst of inertia."
structures, machinery, vehicles, and, thanks to the fruitful efforts of its creators - living beings."
complexity = 0
prebuilt = TRUE
stat_required = CONSCIOUS
/// Admin suit version of kinesis. Can grab anything at any range, may enable phasing through walls.
/obj/item/mod/module/anomaly_locked/kinesis/admin
name = "MOD kinesis++ module"
desc = "A modular plug-in to the forearm, this module was recently reredeveloped in super secret. \
This one can force some of the grasped objects to phase through walls. Oh no."
complexity = 0
grab_range = INFINITY
use_power_cost = DEFAULT_CHARGE_DRAIN * 0
prebuilt = TRUE
stat_required = CONSCIOUS
/// Does our object phase through stuff?
var/phasing = FALSE
/obj/item/mod/module/anomaly_locked/kinesis/admin/grab_atom(atom/movable/target)
. = ..()
if(phasing)
ADD_TRAIT(grabbed_atom, TRAIT_MOVE_PHASING, REF(src))
/obj/item/mod/module/anomaly_locked/kinesis/admin/clear_grab(playsound)
. = ..()
if(!.)
return
var/atom/movable/previous_grab = .
if(phasing)
REMOVE_TRAIT(previous_grab, TRAIT_MOVE_PHASING, REF(src))
/obj/item/mod/module/anomaly_locked/kinesis/admin/can_grab(atom/target)
if(mod.wearer == target)
return FALSE
if(!ismovable(target))
return FALSE
var/atom/movable/movable_target = target
if(movable_target.throwing)
return FALSE
return TRUE
/obj/item/mod/module/anomaly_locked/kinesis/admin/range_check(atom/target)
if(!isturf(mod.wearer.loc))
return FALSE
if(ismovable(target) && !isturf(target.loc))
return FALSE
if(target.z != mod.wearer.z)
return FALSE
return TRUE
/obj/item/mod/module/anomaly_locked/kinesis/admin/on_setanchored(atom/movable/grabbed_atom, anchorvalue)
return //thog dont care
/obj/item/mod/module/anomaly_locked/kinesis/admin/get_configuration()
. = ..()
.["phasing"] = add_ui_configuration("Phasing", "bool", phasing)
/obj/item/mod/module/anomaly_locked/kinesis/admin/configure_edit(key, value)
switch(key)
if("phasing")
phasing = value
if(!grabbed_atom)
return
if(phasing)
ADD_TRAIT(grabbed_atom, TRAIT_MOVE_PHASING, REF(src))
else
REMOVE_TRAIT(grabbed_atom, TRAIT_MOVE_PHASING, REF(src))
+11 -3
View File
@@ -21,9 +21,19 @@
implant = new(src)
/obj/item/mod/module/pathfinder/Destroy()
implant = null
QDEL_NULL(implant)
return ..()
/obj/item/mod/module/pathfinder/Exited(atom/movable/gone, direction)
if(gone == implant)
implant = null
update_icon_state()
return ..()
/obj/item/mod/module/pathfinder/update_icon_state()
. = ..()
icon_state = implant ? "pathfinder" : "pathfinder_empty"
/obj/item/mod/module/pathfinder/examine(mob/user)
. = ..()
if(implant)
@@ -45,8 +55,6 @@
else
target.visible_message(span_notice("[user] implants [target]."), span_notice("[user] implants you with [implant]."))
playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6)
icon_state = "pathfinder_empty"
implant = null
/obj/item/mod/module/pathfinder/proc/attach(mob/living/user)
if(!ishuman(user))
+8 -2
View File
@@ -105,7 +105,9 @@
overlay_state_active = "module_jetpack_on"
/// Do we give the wearer a speed buff.
var/full_speed = FALSE
/// Do we have stabilizers? If yes the user won't move from inertia.
var/stabilize = TRUE
/// Callback to see if we can thrust the user.
var/thrust_callback
/obj/item/mod/module/jetpack/Initialize(mapload)
@@ -585,7 +587,7 @@
incompatible_modules = list(/obj/item/mod/module/hat_stabilizer)
/*Intentionally left inheriting 0 complexity and removable = TRUE;
even though it comes inbuilt into the Magnate/Corporate MODS and spawns in maints, I like the idea of stealing them*/
/// Currently "stored" hat. No armor or function will be inherited, ONLY the icon.
/// Currently "stored" hat. No armor or function will be inherited, only the icon and cover flags.
var/obj/item/clothing/head/attached_hat
/// Original cover flags for the MOD helmet, before a hat is placed
var/former_flags
@@ -616,14 +618,18 @@
SIGNAL_HANDLER
if(!istype(hitting_item, /obj/item/clothing/head))
return
var/obj/item/clothing/hat = hitting_item
if(!mod.active)
balloon_alert(user, "suit must be active!")
return
if(attached_hat)
balloon_alert(user, "hat already attached!")
return
if(hat.clothing_flags & STACKABLE_HELMET_EXEMPT)
balloon_alert(user, "invalid hat!")
return
if(mod.wearer.transferItemToLoc(hitting_item, src, force = FALSE, silent = TRUE))
attached_hat = hitting_item
attached_hat = hat
former_flags = mod.helmet.flags_cover
former_visor_flags = mod.helmet.visor_flags_cover
mod.helmet.flags_cover |= attached_hat.flags_cover
+1 -1
View File
@@ -137,9 +137,9 @@
holstered.forceMove(drop_location())
/obj/item/mod/module/holster/Exited(atom/movable/gone, direction)
. = ..()
if(gone == holstered)
holstered = null
return ..()
/obj/item/mod/module/holster/Destroy()
QDEL_NULL(holstered)