diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index be1b9db2254..1a1dc2b9e0b 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -108,7 +108,7 @@
return TRUE
-/atom/movable/proc/throw_at(atom/target, range, speed, thrower, var/do_throw_animation = TRUE)
+/atom/movable/proc/throw_at(atom/target, range, speed, thrower, var/do_throw_animation = TRUE, datum/callback/callback)
if(!target || !src) return 0
//use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target
@@ -184,7 +184,8 @@
src.SpinAnimation(speed = 4, loops = 1)
//done throwing, either because it hit something or it finished moving
- if(isobj(src)) src.throw_impact(get_turf(src),speed)
+ if(isobj(src))
+ src.throw_impact(get_turf(src),speed)
src.throwing = 0
src.thrower = null
src.throw_source = null
@@ -193,6 +194,9 @@
var/turf/Tloc = loc
Tloc.Entered(src)
+ if(callback)
+ callback.Invoke()
+
/atom/movable/proc/throw_at_random(var/include_own_turf, var/maxrange, var/speed)
var/list/turfs = RANGE_TURFS(maxrange, src)
if(!maxrange)
diff --git a/code/game/gamemodes/changeling/helpers/_store.dm b/code/game/gamemodes/changeling/helpers/_store.dm
index 7e692f81164..f94704d3756 100644
--- a/code/game/gamemodes/changeling/helpers/_store.dm
+++ b/code/game/gamemodes/changeling/helpers/_store.dm
@@ -194,6 +194,12 @@ var/list/datum/power/changeling/powerinstances = list()
//weapon and armor like powers
+/datum/power/changeling/combat_tentacle
+ name = "Mutate Tentacles"
+ desc = "Permits us to reshape our arms into a multi-purpose tentacles."
+ genomecost = 4
+ verbpath = /mob/proc/combat_tentacle
+
/datum/power/changeling/armblades
name = "Mutate Armblades"
desc = "Permits us to reshape our arms into a deadly blade."
diff --git a/code/game/gamemodes/changeling/implements/items.dm b/code/game/gamemodes/changeling/implements/items.dm
index a6ddf5d21d9..5417e0984ce 100644
--- a/code/game/gamemodes/changeling/implements/items.dm
+++ b/code/game/gamemodes/changeling/implements/items.dm
@@ -28,8 +28,8 @@
return ..()
/obj/item/melee/arm_blade/dropped(var/mob/living/user)
- visible_message("With a sickening crunch, [user] reforms their arm blade into an arm!",
- "You hear organic matter ripping and tearing!")
+ visible_message(SPAN_DANGER("With a sickening crunch, [user] reforms their arm blade into an arm!"),
+ SPAN_WARNING("You hear organic matter ripping and tearing!"))
playsound(loc, 'sound/effects/blobattack.ogg', 30, 1)
QDEL_IN(src, 1)
@@ -85,8 +85,8 @@
return ..()
/obj/item/shield/riot/changeling/dropped(var/mob/living/user)
- visible_message("With a sickening crunch, [user] reforms their shield into an arm!",
- "You hear organic matter ripping and tearing!")
+ visible_message(SPAN_DANGER("With a sickening crunch, [user] reforms their shield into an arm!"),
+ SPAN_WARNING("You hear organic matter ripping and tearing!"))
playsound(loc, 'sound/effects/blobattack.ogg', 30, 1)
QDEL_IN(src, 1)
@@ -122,3 +122,163 @@
edge = FALSE
throwforce = 5
w_class = ITEMSIZE_SMALL
+
+
+/***************************************\
+|***********COMBAT TENTACLES*************|
+\***************************************/
+
+/obj/item/gun/energy/tentacle
+ name = "tentacle"
+ desc = "A horrible amalgamation of blood and flesh, warped into the shape of a pulsing tentacle."
+ desc_info = null
+ desc_antag = "A fleshy tentacle that can stretch out and grab things or people."
+ icon = 'icons/obj/contained_items/weapons/ling_tentacle.dmi'
+ icon_state = "tentacle"
+ item_state = "tentacle"
+ flags = NOBLUDGEON
+ w_class = ITEMSIZE_HUGE
+ has_safety = FALSE
+ needspin = FALSE
+ pin = null
+ projectile_type = /obj/item/projectile/tentacle
+ fire_sound = 'sound/effects/splat.ogg'
+ force = 0
+ max_shots = 1
+ throwforce = 0 //Just to be on the safe side
+ throw_range = 0
+ throw_speed = 0
+ charge_failure_message = "cannot be charged."
+
+/obj/item/gun/energy/tentacle/update_icon()
+ return
+
+/obj/item/gun/energy/tentacle/dropped(mob/living/user)
+ if(power_supply?.charge > 0 && !user.stat)
+ user.visible_message(SPAN_DANGER("With a sickening crunch, [user] reforms their tentacle into an arm!"), SPAN_NOTICE("You reform your tentacle into an arm."), SPAN_WARNING("You hear organic matter ripping and tearing!"))
+ playsound(loc, 'sound/effects/blobattack.ogg', 30, 1)
+ QDEL_IN(src, 1)
+
+/obj/item/gun/energy/tentacle/handle_click_empty(user)
+ to_chat(user, SPAN_WARNING("\The [src] is not ready yet."))
+
+/obj/item/gun/energy/tentacle/handle_suicide(mob/living/user)
+ user.visible_message(SPAN_WARNING("[user] coils \the [src] tightly around [user.get_pronoun("his")] neck!"))
+ if(!do_after(user, 40))
+ return
+ user.adjustOxyLoss(300)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ var/obj/item/organ/internal/brain = H.internal_organs_by_name[BP_BRAIN]
+ if(brain)
+ brain.take_internal_damage(brain.max_damage)
+ user.death() // double tap - geeves
+
+/obj/item/projectile/tentacle
+ name = "tentacle"
+ icon = 'icons/obj/contained_items/weapons/ling_tentacle.dmi'
+ icon_state = "tentacle_end"
+ pass_flags = PASSTABLE
+ cant_miss = TRUE
+ damage = 0
+ damage_type = BRUTE
+ range = 8
+ hitsound = 'sound/weapons/thudswoosh.ogg'
+ var/chain
+ var/obj/item/gun/energy/tentacle/source //the item that shot it
+
+/obj/item/projectile/tentacle/New(obj/item/gun/energy/tentacle/tentacle_gun)
+ source = tentacle_gun
+ ..()
+
+/obj/item/projectile/tentacle/fire(setAngle)
+ if(firer)
+ chain = firer.Beam(src, icon_state = "tentacle", time = -1, 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/human/H)
+ if(ishuman(H) && Adjacent(H))
+ var/obj/item/grab/G = H.grabbedby(src, TRUE)
+ if(istype(G))
+ G.set_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))
+ I = l_hand
+ if(!is_sharp(I))
+ return
+
+ C.visible_message(SPAN_DANGER("[src] impales [C] with [I]!"), SPAN_DANGER("[src] impales you with [I]!"))
+ C.apply_damage(I.force, BRUTE, "chest")
+ do_attack_animation(C)
+ add_blood(C)
+ playsound(get_turf(src), I.hitsound, 75, 1)
+
+/obj/item/projectile/tentacle/on_hit(atom/target, blocked = 0)
+ qdel(source) //one tentacle only unless you miss
+ if(blocked >= 100)
+ return FALSE
+ var/mob/living/carbon/human/H = firer
+ if(istype(target, /obj/item))
+ var/obj/item/I = target
+ if(!I.anchored)
+ to_chat(firer, SPAN_NOTICE("You pull [I] towards yourself."))
+ H.throw_mode_on()
+ I.throw_at(H, 10, 2)
+ . = TRUE
+
+ else if(isliving(target))
+ var/mob/living/L = target
+ if(!L.anchored && !L.throwing)//avoid double hits
+ if(iscarbon(L))
+ var/mob/living/carbon/C = L
+ switch(firer.a_intent)
+ if(I_HELP)
+ C.visible_message(SPAN_DANGER("[L] is pulled by [H]'s tentacle!"), SPAN_DANGER("A tentacle grabs you and pulls you towards [H]!"))
+ C.throw_at(get_step_towards(H,C), 8, 2)
+ return TRUE
+
+ if(I_DISARM)
+ var/obj/item/I = C.get_active_hand()
+ if(!I || istype(I, /obj/item/grab))
+ I = C.get_inactive_hand()
+ if(I && !istype(I, /obj/item/grab))
+ if(C.unEquip(I))
+ C.visible_message(SPAN_DANGER("[I] is yanked out of [C]'s hand by [src]!"),SPAN_DANGER("A tentacle pulls [I] away from you!"))
+ I.throw_at(get_step_towards(H, C), 8, 2, callback = CALLBACK(H, /mob/proc/put_in_any_hand_if_possible, I))
+ return TRUE
+ else
+ to_chat(firer, SPAN_DANGER("You can't seem to pry [I] out of [C]'s hands!"))
+ return FALSE
+ else
+ to_chat(firer, SPAN_DANGER("[C] has nothing in hand to disarm!"))
+ return FALSE
+
+ if(I_GRAB)
+ C.visible_message(SPAN_DANGER("[L] is grabbed by [H]'s tentacle!"), SPAN_DANGER("A tentacle grabs you and pulls you towards [H]!"))
+ C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(H, /mob/proc/tentacle_grab, C))
+ return TRUE
+
+ if(I_HURT)
+ C.visible_message(SPAN_DANGER("[L] is thrown towards [H] by a tentacle!"), SPAN_DANGER("A tentacle grabs you and throws you towards [H]!"))
+ C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(H, /mob/proc/tentacle_stab, C))
+ return TRUE
+ else
+ L.visible_message(SPAN_DANGER("[L] is pulled by [H]'s tentacle!"), SPAN_DANGER("A tentacle grabs you and pulls you towards [H]!"))
+ L.throw_at(get_step_towards(H,L), 8, 2)
+ . = TRUE
+
+/obj/item/projectile/tentacle/on_impact(var/atom/A)
+ if(isturf(A))
+ qdel(source)
+
+/obj/item/projectile/tentacle/Destroy()
+ qdel(chain)
+ source = null
+ return ..()
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/implements/powers/body.dm b/code/game/gamemodes/changeling/implements/powers/body.dm
index db673a2ff9e..079845ddb14 100644
--- a/code/game/gamemodes/changeling/implements/powers/body.dm
+++ b/code/game/gamemodes/changeling/implements/powers/body.dm
@@ -372,6 +372,43 @@
if(src && src.mind && src.mind.changeling)
src.mind.changeling.mimicing = ""
+/mob/proc/combat_tentacle()
+ set category = "Changeling"
+ set name = "Form Tentacle (20)"
+ set desc = "Rupture the flesh and mend the bone of your hand into a multi-purpose tentacle."
+
+ var/datum/changeling/changeling = changeling_power(20, 0, 0)
+ if(!changeling)
+ return FALSE
+ mind.changeling.chem_charges -= 20
+
+ var/mob/living/carbon/M = src
+
+ if(M.l_hand && M.r_hand)
+ to_chat(M, SPAN_WARNING("Your hands are full."))
+ return
+
+ if(M.handcuffed)
+ var/cuffs = M.handcuffed
+ M.u_equip(M.handcuffed)
+ qdel(cuffs)
+
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket))
+ src.visible_message("[H] tears through the [H.wear_suit] with their spindly arm tentacle!",
+ "We tear through the [H.wear_suit] with our arm tentacle!",
+ "You hear cloth ripping and tearing!")
+ QDEL_IN(H.wear_suit, 0)
+ H.unEquip(H.wear_suit, force = TRUE)
+
+ var/obj/item/gun/energy/tentacle/T = new(M)
+ M.put_in_hands(T)
+ playsound(loc, 'sound/effects/splat.ogg', 30, 1)
+ src.visible_message("A spindly tentacle forms around [M]\'s arm!",
+ "Our arm twists and mutates, transforming it into a tentacle.",
+ "You hear organic matter ripping and tearing!")
+
/mob/proc/armblades()
set category = "Changeling"
set name = "Form Blades (20)"
diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm
index 58bc2c26f63..eaadb7b65f4 100644
--- a/code/game/gamemodes/vampire/vampire_powers.dm
+++ b/code/game/gamemodes/vampire/vampire_powers.dm
@@ -1011,8 +1011,7 @@
else
r_hand = G
- G.state = GRAB_AGGRESSIVE
- G.icon_state = "grabbed1"
+ G.set_state(GRAB_AGGRESSIVE)
G.synch()
verbs -= /mob/living/carbon/human/proc/grapple
diff --git a/code/modules/martial_arts/sleeping_carp.dm b/code/modules/martial_arts/sleeping_carp.dm
index 98c6f9da2fd..bf6c4e5bd7d 100644
--- a/code/modules/martial_arts/sleeping_carp.dm
+++ b/code/modules/martial_arts/sleeping_carp.dm
@@ -102,7 +102,7 @@
D.grabbedby(A,1)
var/obj/item/grab/G = A.get_active_hand()
if(G)
- G.state = GRAB_AGGRESSIVE //Instant aggressive grab
+ G.set_state(GRAB_AGGRESSIVE) //Instant aggressive grab
/datum/martial_art/the_sleeping_carp/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
add_to_streak("D",D)
diff --git a/code/modules/martial_arts/unathi.dm b/code/modules/martial_arts/unathi.dm
index 24bbfbc1b47..a4b5d0c7a91 100644
--- a/code/modules/martial_arts/unathi.dm
+++ b/code/modules/martial_arts/unathi.dm
@@ -30,7 +30,7 @@
D.grabbedby(A,1)
var/obj/item/grab/G = A.get_active_hand()
if(G && prob(50))
- G.state = GRAB_AGGRESSIVE
+ G.set_state(GRAB_AGGRESSIVE)
D.visible_message("[A] gets a strong grip on [D]!")
return 1
diff --git a/code/modules/martial_arts/vaurca.dm b/code/modules/martial_arts/vaurca.dm
index 238a7787d38..d92301fdb50 100644
--- a/code/modules/martial_arts/vaurca.dm
+++ b/code/modules/martial_arts/vaurca.dm
@@ -59,7 +59,7 @@
if(istype(A.get_active_hand(),/obj/item/grab))
var/obj/item/grab/G = A.get_active_hand()
if(G && G.affecting == D)
- G.state = GRAB_AGGRESSIVE
+ G.set_state(GRAB_AGGRESSIVE)
D.visible_message(SPAN_DANGER("[A] gets a strong grip on [D]!"))
if(isvaurca(A))
A.bugbite(TRUE)
diff --git a/code/modules/martial_arts/wrestling.dm b/code/modules/martial_arts/wrestling.dm
index 2aa041e6dee..d614e0bf746 100644
--- a/code/modules/martial_arts/wrestling.dm
+++ b/code/modules/martial_arts/wrestling.dm
@@ -11,7 +11,7 @@
D.grabbedby(A,1)
var/obj/item/grab/G = A.get_active_hand()
if(G && prob(50))
- G.state = GRAB_AGGRESSIVE
+ G.set_state(GRAB_AGGRESSIVE)
D.visible_message("[A] has [D] in a clinch!")
else
D.visible_message("[A] fails to get [D] in a clinch!")
diff --git a/code/modules/martial_arts/zombie.dm b/code/modules/martial_arts/zombie.dm
index f0770469f3c..484e594be8a 100644
--- a/code/modules/martial_arts/zombie.dm
+++ b/code/modules/martial_arts/zombie.dm
@@ -26,7 +26,7 @@
/datum/martial_art/zombie/proc/check_grab(var/mob/living/carbon/human/A)
var/obj/item/grab/G = A.get_active_hand()
if(G)
- G.state = GRAB_AGGRESSIVE
+ G.set_state(GRAB_AGGRESSIVE)
G.icon_state = "grabbed1"
G.hud.icon_state = "reinforce1"
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
index 4fac2a1d9f5..bd156f9e5e9 100644
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ b/code/modules/mob/living/carbon/human/human_attackhand.dm
@@ -194,10 +194,7 @@
H.do_attack_animation(src)
playsound(loc, /decl/sound_category/grab_sound, 50, FALSE, -1)
if(H.gloves && istype(H.gloves,/obj/item/clothing/gloves/force/syndicate)) //only antag gloves can do this for now
- G.state = GRAB_AGGRESSIVE
- G.icon_state = "grabbed1"
- G.hud.icon_state = "reinforce1"
- G.last_action = world.time
+ G.set_state(GRAB_AGGRESSIVE)
visible_message("[M] gets a strong grip on [src]!")
return 1
visible_message("[M] has grabbed [src] passively!")
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 1aba1476965..bc1166c99a8 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -559,14 +559,11 @@ emp_act
user.do_attack_animation(src)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(user.gloves && istype(user.gloves,/obj/item/clothing/gloves/force/syndicate)) //only antag gloves can do this for now
- G.state = GRAB_AGGRESSIVE
- G.icon_state = "grabbed1"
- G.hud.icon_state = "reinforce1"
- G.last_action = world.time
+ G.set_state(GRAB_AGGRESSIVE)
visible_message("[user] gets a strong grip on [src]!")
- return 1
+ return G
visible_message("[user] has grabbed [src] passively!")
- return 1
+ return G
/mob/living/carbon/human/set_on_fire()
..()
diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm
index 77a420d8db8..df90801616e 100644
--- a/code/modules/mob/living/carbon/human/human_powers.dm
+++ b/code/modules/mob/living/carbon/human/human_powers.dm
@@ -170,8 +170,7 @@ mob/living/carbon/human/proc/change_monitor()
else
r_hand = G
- G.state = GRAB_PASSIVE
- G.icon_state = "grabbed1"
+ G.set_state(GRAB_AGGRESSIVE)
G.synch()
return TRUE
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index 91a35c3e72b..d621de1c5df 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -88,6 +88,45 @@
return affecting
return null
+/obj/item/grab/proc/set_state(var/set_state)
+ last_action = world.time
+ switch(set_state)
+ if(GRAB_PASSIVE)
+ state = initial(state)
+ icon_state = initial(icon_state)
+ if(hud)
+ hud.icon_state = initial(hud.icon_state)
+ if(GRAB_AGGRESSIVE)
+ state = GRAB_AGGRESSIVE
+ icon_state = "grabbed1"
+ hud.icon_state = "reinforce1"
+ if(GRAB_NECK)
+ state = GRAB_NECK
+ icon_state = "grabbed+1"
+ if(hud)
+ hud.icon_state = "kill"
+ hud.name = "kill"
+ if(affecting)
+ affecting.Stun(10)
+ if(assailant)
+ assailant.visible_message(SPAN_WARNING("[assailant] reinforces [assailant.get_pronoun("his")] grip on [affecting]'s neck!"), SPAN_WARNING("You reinforce your grip on [affecting]'s neck!"))
+ if(GRAB_KILL)
+ state = GRAB_KILL
+ icon_state = "grabbed+1"
+ if(hud)
+ hud.icon_state = "kill1"
+ hud.name = "loosen"
+ if(affecting)
+ affecting.setClickCooldown(10)
+ if(ishuman(affecting))
+ var/mob/living/carbon/human/A = affecting
+ if (!(A.species.flags & NO_BREATHE))
+ A.losebreath += 4
+ affecting.set_dir(WEST)
+ if(assailant)
+ assailant.visible_message(SPAN_DANGER("[assailant] starts strangling [affecting]!"), SPAN_DANGER("You start strangling [affecting]!"))
+ else
+ crash_with("Grab set to illegal state with set_state: [set_state]")
//This makes sure that the grab screen object is displayed in the correct hand.
/obj/item/grab/proc/synch()
@@ -275,49 +314,32 @@
assailant.visible_message(SPAN_WARNING("[assailant] pins [affecting] down to the ground by the hands!"), SPAN_WARNING("You pin [affecting] down to the ground by the hands!"))
apply_pinning(affecting, assailant)
- state = GRAB_AGGRESSIVE
- icon_state = "grabbed1"
- hud.icon_state = "reinforce1"
+ set_state(GRAB_AGGRESSIVE)
else if(state < GRAB_NECK)
if(isslime(affecting))
assailant.visible_message(SPAN_WARNING("[assailant] tries to squeeze [affecting], but [assailant.get_pronoun("his")] hands sink right through!"), SPAN_WARNING("You try to squeeze [affecting], but your hands sink right through!"))
return
playsound(loc, /decl/sound_category/grab_sound, 50, FALSE, -1)
- assailant.visible_message(SPAN_WARNING("[assailant] reinforces [assailant.get_pronoun("his")] grip on [affecting]'s neck!"), SPAN_WARNING("You reinforce your grip on [affecting]'s neck!"))
- state = GRAB_NECK
- icon_state = "grabbed+1"
+ set_state(GRAB_NECK)
affecting.attack_log += "\[[time_stamp()]\] Has had their neck grabbed by [assailant.name] ([assailant.ckey])"
assailant.attack_log += "\[[time_stamp()]\] Grabbed the neck of [affecting.name] ([affecting.ckey])"
msg_admin_attack("[key_name_admin(assailant)] grabbed the neck of [key_name_admin(affecting)]",ckey=key_name(assailant),ckey_target=key_name(affecting))
- hud.icon_state = "kill"
- hud.name = "kill"
- affecting.Stun(10) //10 ticks of ensured grab
else if(state < GRAB_UPGRADING)
if(ishuman(affecting))
var/mob/living/carbon/human/H = affecting
if(H.head && (H.head.item_flags & AIRTIGHT))
assailant.visible_message(SPAN_WARNING("[affecting]'s headgear prevents [assailant] from choking them out!"), SPAN_WARNING("[affecting]'s headgear prevents you from choking them out!"))
return
- hud.icon_state = "kill1"
- hud.name = "loosen"
- state = GRAB_KILL
+ set_state(GRAB_KILL)
playsound(loc, /decl/sound_category/grab_sound, 50, FALSE, -1)
- assailant.visible_message(SPAN_DANGER("[assailant] starts strangling [affecting]!"), SPAN_DANGER("You start strangling [affecting]!"))
affecting.attack_log += "\[[time_stamp()]\] is being strangled by [assailant.name] ([assailant.ckey])"
assailant.attack_log += "\[[time_stamp()]\] is strangling [affecting.name] ([affecting.ckey])"
msg_admin_attack("[key_name_admin(assailant)] is strangling [key_name_admin(affecting)]",ckey=key_name(assailant),ckey_target=key_name(affecting))
-
- affecting.setClickCooldown(10)
- if(ishuman(affecting))
- var/mob/living/carbon/human/A = affecting
- if (!(A.species.flags & NO_BREATHE))
- A.losebreath += 4
- affecting.set_dir(WEST)
else if(state == GRAB_KILL)
hud.icon_state = "kill"
hud.name = "kill"
- state = GRAB_NECK
+ state = GRAB_NECK // this one doesn't get a set state because it's unique
assailant.visible_message(SPAN_WARNING("[assailant] stops strangling [affecting]!"), SPAN_WARNING("You stop strangling [affecting]!"))
adjust_position()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index ddb416ed2b8..71c6024ab42 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -488,7 +488,7 @@
damage_mult = 1.5
P.damage *= damage_mult
//you can't miss at point blank..
- P.can_miss = 1
+ P.cant_miss = TRUE
/obj/item/gun/proc/process_accuracy(obj/projectile, mob/user, atom/target, acc_mod, dispersion)
var/obj/item/projectile/P = projectile
@@ -543,7 +543,7 @@
mouthshoot = TRUE
M.visible_message(SPAN_WARNING("\The [user] sticks their gun in their mouth, ready to pull the trigger..."))
if(!do_after(user, 40))
- M.visible_message(SPAN_NOTICE("\The [user] decided life was worth living"))
+ M.visible_message(SPAN_NOTICE("\The [user] decided life was worth living."))
mouthshoot = FALSE
return
var/obj/item/projectile/in_chamber = consume_next_projectile()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index d1d97c7ad0a..43950046f3f 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -15,6 +15,7 @@
var/def_zone = "" //Aiming at
var/hit_zone // The place that actually got hit
var/mob/firer = null//Who shot it
+ var/no_attack_message
var/silenced = FALSE //Attack message
var/shot_from = "" // name of the object which shot us
@@ -23,7 +24,7 @@
var/dispersion = 0.0
//used for shooting at blank range, you shouldn't be able to miss
- var/can_miss = 0
+ var/cant_miss = FALSE
var/taser_effect = 0 //If set then the projectile will apply it's agony damage using stun_effect_act() to mobs it hits, and other damage will be ignored
@@ -190,8 +191,8 @@
return TRUE
result = target_mob.bullet_act(src, def_zone)
- if(result == PROJECTILE_FORCE_MISS && (can_miss == 0)) //if you're shooting at point blank you can't miss.
- if(!silenced)
+ if(result == PROJECTILE_FORCE_MISS && !cant_miss) //if you're shooting at point blank you can't miss.
+ if(!silenced && !no_attack_message)
target_mob.visible_message("\The [src] misses [target_mob] narrowly!")
playsound(target_mob, /decl/sound_category/bulletflyby_sound, 50, 1)
return FALSE
@@ -204,10 +205,11 @@
var/mob/living/simple_animal/SA = target_mob
impacted_organ = pick(SA.organ_names)
//hit messages
- if(silenced)
- to_chat(target_mob, "You've been hit in the [impacted_organ] by \a [src]!")
- else
- target_mob.visible_message("\The [target_mob] is hit by \a [src] in the [impacted_organ]!", "You are hit by \a [src] in the [impacted_organ]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
+ if(!no_attack_message)
+ if(silenced)
+ to_chat(target_mob, "You've been hit in the [impacted_organ] by \a [src]!")
+ else
+ target_mob.visible_message("\The [target_mob] is hit by \a [src] in the [impacted_organ]!", "You are hit by \a [src] in the [impacted_organ]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
var/no_clients = FALSE
//admin logs
diff --git a/html/changelogs/geeves-combat_tentacle.yml b/html/changelogs/geeves-combat_tentacle.yml
new file mode 100644
index 00000000000..6107229e0a3
--- /dev/null
+++ b/html/changelogs/geeves-combat_tentacle.yml
@@ -0,0 +1,6 @@
+author: Geeves
+
+delete-after: True
+
+changes:
+ - rscadd: "Ported Combat Tentacles for Changelings from Paradise station. You can use them to pull items or people towards you."
\ No newline at end of file
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index 3ab304ae67e..62256be2943 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/obj/contained_items/weapons/ling_tentacle.dmi b/icons/obj/contained_items/weapons/ling_tentacle.dmi
new file mode 100644
index 00000000000..c6adb8a09ad
Binary files /dev/null and b/icons/obj/contained_items/weapons/ling_tentacle.dmi differ