diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index f13f43e5e1f..d2cc3abef75 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -87,6 +87,8 @@
#define STATUS_EFFECT_SHADOW_BOXING /datum/status_effect/shadow_boxing
+#define STATUS_EFFECT_CLINGTENTACLE /datum/status_effect/cling_tentacle //Imobilises target for 3 seconds
+
//#define STATUS_EFFECT_NECROPOLIS_CURSE /datum/status_effect/necropolis_curse
//#define CURSE_BLINDING 1 //makes the edges of the target's screen obscured
//#define CURSE_SPAWNING 2 //spawns creatures that attack the target only
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 7d18528528c..3b5ec35b7e4 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -266,6 +266,17 @@
owner.apply_damage(damage, BRUTE)
shadow_to_animation(get_turf(attacker), get_turf(owner), attacker)
+/datum/status_effect/cling_tentacle
+ id = "cling_tentacle"
+ alert_type = null
+ duration = 3 SECONDS
+
+/datum/status_effect/cling_tentacle/on_apply()
+ ADD_TRAIT(owner, TRAIT_IMMOBILIZED, "[id]")
+ return ..()
+
+/datum/status_effect/cling_tentacle/on_remove()
+ REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, "[id]")
// start of `living` level status procs.
diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm
index e194201221b..95541cfc6a8 100644
--- a/code/game/objects/items/weapons/handcuffs.dm
+++ b/code/game/objects/items/weapons/handcuffs.dm
@@ -1,3 +1,8 @@
+/obj/item/restraints
+ name = "bugged restraints" //This item existed before this pr, but had no name or such. Better warn people if it exists
+ desc = "Should not exist. Report me to a(n) coder/admin!"
+ var/cuffed_state = "handcuff"
+
/obj/item/restraints/handcuffs
name = "handcuffs"
desc = "Use this to keep prisoners in line."
@@ -17,7 +22,6 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50)
var/cuffsound = 'sound/weapons/handcuffs.ogg'
// Icon state for cuffed overlay on a mob
- var/cuffed_state = "handcuff"
var/trashtype = null //For disposable cuffs
var/ignoresClumsy = FALSE
diff --git a/code/game/objects/items/weapons/legcuffs.dm b/code/game/objects/items/weapons/legcuffs.dm
index 19f5c8dfd0c..ce42d0251ed 100644
--- a/code/game/objects/items/weapons/legcuffs.dm
+++ b/code/game/objects/items/weapons/legcuffs.dm
@@ -4,6 +4,7 @@
gender = PLURAL
icon = 'icons/obj/items.dmi'
icon_state = "handcuff"
+ cuffed_state = "legcuff"
flags = CONDUCT
throwforce = 0
w_class = WEIGHT_CLASS_NORMAL
@@ -20,6 +21,8 @@
origin_tech = "engineering=4"
var/armed = FALSE
var/trap_damage = 20
+ ///Do we want the beartrap not to make a visable message on arm? Use when a beartrap is applied by something else.
+ var/silent_arming = FALSE
var/obj/item/grenade/iedcasing/IED = null
var/obj/item/assembly/signaler/sig = null
@@ -97,8 +100,9 @@
armed = FALSE
update_icon()
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
- L.visible_message("[L] triggers \the [src].", \
- "You trigger \the [src]!")
+ if(!silent_arming)
+ L.visible_message("[L] triggers \the [src].", \
+ "You trigger \the [src]!")
if(IED && isturf(src.loc))
IED.active = TRUE
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 76421ed6672..111d2b7cd9c 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -163,10 +163,10 @@
name = "Tentacle"
desc = "We ready a tentacle to grab items or victims with. Costs 10 chemicals."
helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \
- Help will drag the target closer. \
- Disarm will grab whatever the target is holding. \
- Grab will put the target in our grip after we catch it. \
- Harm will drag the target closer and stab it if we are holding a sharp weapon in our other hand. \
+ Help will drag the target closer and shake them up. \
+ Disarm will grab whatever the target is holding, and knock them down if they are not holding anything. \
+ Grab will immobilize the target and wrap a tentacle around them. \
+ Harm will drag the target closer and hit them with the object in our other hand. \
Cannot be used while in our lesser form."
button_icon_state = "tentacle"
chemical_cost = 10
@@ -215,6 +215,7 @@
caliber = "tentacle"
icon_state = "tentacle_end"
muzzle_flash_effect = null
+ muzzle_flash_color = null
var/obj/item/gun/magic/tentacle/gun //the item that shot it
/obj/item/ammo_casing/magic/tentacle/New(obj/item/gun/magic/tentacle/tentacle_gun)
@@ -233,6 +234,7 @@
damage_type = BRUTE
range = 8
hitsound = 'sound/weapons/thudswoosh.ogg'
+ reflectability = REFLECTABILITY_NEVER //Let us not reflect this ever. It's not quite a bullet, and a cling should never wrap its tentacle around itself, it controls its body well
var/obj/item/ammo_casing/magic/tentacle/source //the item that shot it
/obj/item/projectile/tentacle/New(obj/item/ammo_casing/magic/tentacle/tentacle_casing)
@@ -244,30 +246,15 @@
chain = firer.Beam(src, icon_state = "tentacle", time = INFINITY, maxdistance = INFINITY, beam_sleep_time = 1)
..()
-/obj/item/projectile/tentacle/proc/reset_throw(mob/living/carbon/human/H)
- if(H.in_throw_mode)
- H.throw_mode_off() //Don't annoy the changeling if he doesn't catch the item
-
-/mob/proc/tentacle_grab(mob/living/carbon/C)
- if(Adjacent(C))
- var/obj/item/grab/G = C.grabbedby(src,1)
- if(istype(G))
- G.state = GRAB_AGGRESSIVE //Instant aggressive grab
-
/mob/proc/tentacle_stab(mob/living/carbon/C)
if(Adjacent(C))
var/obj/item/I = r_hand
- if(!is_sharp(I))
+ if(!I || istype(I, /obj/item/gun/magic/tentacle))
I = l_hand
- if(!is_sharp(I))
+ if(!I || istype(I, /obj/item/gun/magic/tentacle))
return
-
- C.visible_message("[src] impales [C] with [I]!", "[src] impales you with [I]!")
- add_attack_logs(src, C, "[src] pulled [C] with a tentacle, attacking them with [I]") //Attack log is here so we can fetch the item they're stabbing with.
- C.apply_damage(I.force, BRUTE, "chest")
- do_item_attack_animation(C, used_item = I)
- add_blood(C)
- playsound(get_turf(src), I.hitsound, 75, 1)
+ add_attack_logs(src, C, "[src] pulled [C] with a tentacle, attacking them with [I]")
+ I.melee_attack_chain(src, C)//Hits the victim with whatever they are holding that is no the zero force tentacle
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = 0)
@@ -278,10 +265,10 @@
if(isitem(target))
var/obj/item/I = target
if(!I.anchored)
- to_chat(firer, "You pull [I] towards yourself.")
- add_attack_logs(src, I, "[src] pulled [I] towards them with a tentacle")
- H.throw_mode_on()
- I.throw_at(H, 10, 2)
+ to_chat(firer, "You grab [I] with your tentacle.")
+ add_attack_logs(H, I, "[src] grabs [I] with a tentacle")
+ I.forceMove(H.loc)
+ I.attack_hand(H)//The tentacle takes the item back with them and makes them pick it up. No silly throw mode.
. = 1
else if(isliving(target))
@@ -291,47 +278,76 @@
var/mob/living/carbon/C = L
switch(firer.a_intent)
if(INTENT_HELP)
- C.visible_message("[L] is pulled by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
+ C.visible_message("[L] is pulled to their feet towards [H]!","A tentacle grabs you and pulls you up towards [H]!")
add_attack_logs(H, L, "[H] pulled [L] towards them with a tentacle")
C.throw_at(get_step_towards(H,C), 8, 2)
- return 1
+ C.AdjustParalysis(-2 SECONDS)
+ C.AdjustStunned(-4 SECONDS)
+ C.AdjustWeakened(-4 SECONDS)
+ C.AdjustKnockDown(-4 SECONDS)
+ C.adjustStaminaLoss(-25)
+ return TRUE
if(INTENT_DISARM)
var/obj/item/I = C.get_active_hand()
if(I)
if(C.drop_item())
C.visible_message("[I] is yanked out of [C]'s hand by [src]!","A tentacle pulls [I] away from you!")
- add_attack_logs(src, C, "[src] has grabbed [I] out of [C]'s hand with a tentacle")
+ add_attack_logs(H, C, "[H] has grabbed [I] out of [C]'s hand with a tentacle")
on_hit(I) //grab the item as if you had hit it directly with the tentacle
- return 1
- else
- to_chat(firer, "You can't seem to pry [I] out of [C]'s hands!")
- add_attack_logs(src, C, "[src] tried to grab [I] out of [C]'s hand with a tentacle, but failed")
- return 0
- else
- to_chat(firer, "[C] has nothing in hand to disarm!")
- return 0
+ return TRUE
+ to_chat(firer, "You can't seem to pry [I] out of [C]'s hands!")
+ add_attack_logs(H, C, "[H] tried to grab [I] out of their hand with a tentacle, but failed")
+ C.visible_message("[C] is knocked over by [src]!", "A tentacle hits you in the chest and knocks you over!")
+ add_attack_logs(H, C, "[H] knocked over with a tentacle")
+ C.KnockDown(2 SECONDS) //Not useless with antidrop.
+ return TRUE
if(INTENT_GRAB)
- C.visible_message("[L] is grabbed by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
- add_attack_logs(H, C, "[H] grabbed [C] with a changeling tentacle")
- C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(H, TYPE_PROC_REF(/mob, tentacle_grab), C))
- return 1
+ C.visible_message("[L] is entangled by [H]'s tentacle!", "A tentacle grabs you and wraps around your legs!")
+ add_attack_logs(H, C, "imobilised with a changeling tentacle")
+ if(!iscarbon(H))
+ return TRUE
+ var/obj/item/restraints/legcuffs/beartrap/changeling/B = new(H.loc)
+ B.Crossed(C)
+ return TRUE
if(INTENT_HARM)
C.visible_message("[L] is thrown towards [H] by a tentacle!","A tentacle grabs you and throws you towards [H]!")
C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(H, TYPE_PROC_REF(/mob, tentacle_stab), C))
- return 1
+ return TRUE
else
L.visible_message("[L] is pulled by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
L.throw_at(get_step_towards(H,L), 8, 2)
- . = 1
+ . = TRUE
/obj/item/projectile/tentacle/Destroy()
qdel(chain)
source = null
return ..()
+/obj/item/restraints/legcuffs/beartrap/changeling
+ name = "tentacle mass"
+ desc = "A disgusting mass of flesh wrapped around some poor persons legs."
+ icon_state = "fleshtrap" //Never on ground, only on examine, so doesn't need to be super detaled
+ trap_damage = 5
+ armed = TRUE
+ anchored = TRUE
+ silent_arming = TRUE
+ breakouttime = 5 SECONDS
+ cuffed_state = "fleshlegcuff"
+ flags = DROPDEL
+
+/obj/item/restraints/legcuffs/beartrap/changeling/Crossed(AM, oldloc)
+ if(!iscarbon(AM) || !armed)
+ return
+ var/mob/living/carbon/C = AM
+ C.apply_status_effect(STATUS_EFFECT_CLINGTENTACLE)
+
+ ..()
+
+ if(!iscarbon(loc)) // if it fails to latch onto someone for whatever reason, delete itself, we don't want unarmed ones lying around.
+ qdel(src)
/***************************************\
|****************SHIELD*****************|
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 08fdb582d3b..0b0b8fa108d 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -8,8 +8,10 @@
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
- var/obj/item/restraints/handcuffs/handcuffed = null //Whether or not the mob is handcuffed, restraints/handcuffs/ required for var/cuffed_state
- var/obj/item/legcuffed = null //Same as handcuffs but for legs. Bear traps use this.
+ /// Whether or not the mob is handcuffed, restraints/handcuffs/ required for var/cuffed_state
+ var/obj/item/restraints/handcuffs/handcuffed = null
+ /// Same as handcuffs but for legs. Bear traps use this.
+ var/obj/item/restraints/legcuffs/legcuffed = null
var/obj/item/head = null
var/obj/item/clothing/suit/wear_suit = null //TODO: necessary? Are they even used? ~Carn
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index f24ed93b701..2c557e34b9f 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -1047,7 +1047,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
remove_overlay(LEGCUFF_LAYER)
clear_alert("legcuffed")
if(legcuffed)
- overlays_standing[LEGCUFF_LAYER] = mutable_appearance('icons/mob/mob.dmi', "legcuff", layer = -LEGCUFF_LAYER)
+ overlays_standing[LEGCUFF_LAYER] = mutable_appearance('icons/mob/mob.dmi', legcuffed.cuffed_state, layer = -LEGCUFF_LAYER)
throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = legcuffed)
if(m_intent != MOVE_INTENT_WALK)
m_intent = MOVE_INTENT_WALK
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index 9d8d4181dce..90c30c0c3d8 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 5371bccda14..97ab37d8a33 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ