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