diff --git a/code/datums/beam.dm b/code/datums/beam.dm
index 7a8c802b42d..bb1cef167d6 100644
--- a/code/datums/beam.dm
+++ b/code/datums/beam.dm
@@ -15,12 +15,13 @@
var/static_beam = 0
var/beam_type = /obj/effect/ebeam //must be subtype
-/datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=50,maxdistance=10,btype = /obj/effect/ebeam)
+/datum/beam/New(beam_origin,beam_target,beam_icon='icons/effects/beam.dmi',beam_icon_state="b_beam",time=50,maxdistance=10,btype = /obj/effect/ebeam,beam_sleep_time=3)
endtime = world.time+time
origin = beam_origin
origin_oldloc = get_turf(origin)
target = beam_target
target_oldloc = get_turf(target)
+ sleep_time = beam_sleep_time
if(origin_oldloc == origin && target_oldloc == target)
static_beam = 1
max_distance = maxdistance
@@ -117,13 +118,13 @@
/obj/effect/ebeam/Destroy()
owner = null
return ..()
-
+
/obj/effect/ebeam/deadly/Crossed(atom/A)
..()
A.ex_act(1)
-/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10,beam_type=/obj/effect/ebeam)
- var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type)
+/atom/proc/Beam(atom/BeamTarget,icon_state="b_beam",icon='icons/effects/beam.dmi',time=50, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=3)
+ var/datum/beam/newbeam = new(src,BeamTarget,icon,icon_state,time,maxdistance,beam_type,beam_sleep_time)
spawn(0)
newbeam.Start()
return newbeam
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm
index c7d393b77a7..57f086b46ed 100644
--- a/code/game/gamemodes/changeling/powers/mutations.dm
+++ b/code/game/gamemodes/changeling/powers/mutations.dm
@@ -17,18 +17,21 @@
dna_cost = -1
genetic_damage = 1000
+ var/silent = FALSE
var/weapon_type
var/weapon_name_simple
/obj/effect/proc_holder/changeling/weapon/try_to_sting(var/mob/user, var/mob/target)
if(istype(user.l_hand, weapon_type)) //Not the nicest way to do it, but eh
qdel(user.l_hand)
- user.visible_message("With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "With a sickening crunch, [user] reforms his [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "[user] forces the airlock to open with \his [src]!", "We force the airlock to open.", "You hear a metal screeching sound.")
A.open(2)
+/***************************************\
+|***********COMBAT TENTACLES*************|
+\***************************************/
+
+/obj/effect/proc_holder/changeling/weapon/tentacle
+ name = "Tentacle"
+ desc = "We ready a tentacle to grab items or victims with."
+ helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \
+ Help will simply drag them closer, Disarm will grab whatever they are holding instead of them, Grab will put the victim in our hold after catching it, \
+ and Harm will stun it, and stab it if we are also holding a sharp weapon. Cannot be used while in lesser form."
+ chemical_cost = 10
+ dna_cost = 2
+ genetic_damage = 5
+ req_human = 1
+ max_genetic_damage = 10
+ weapon_type = /obj/item/weapon/gun/magic/tentacle
+ weapon_name_simple = "tentacle"
+ silent = TRUE
+
+/obj/item/weapon/gun/magic/tentacle
+ name = "tentacle"
+ desc = "A fleshy tentacle that can stretch out and grab things or people."
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "tentacle"
+ item_state = "tentacle"
+ flags = ABSTRACT | NODROP | NOBLUDGEON
+ w_class = WEIGHT_CLASS_HUGE
+ ammo_type = /obj/item/ammo_casing/magic/tentacle
+ fire_sound = 'sound/effects/splat.ogg'
+ force = 0
+ max_charges = 1
+ throwforce = 0 //Just to be on the safe side
+ throw_range = 0
+ throw_speed = 0
+
+/obj/item/weapon/gun/magic/tentacle/New(location,silent)
+ ..()
+ if(ismob(loc))
+ if(!silent)
+ loc.visible_message("[loc.name]\'s arm starts stretching inhumanly!", "Our arm twists and mutates, transforming it into a tentacle.", "You hear organic matter ripping and tearing!")
+ else
+ to_chat(loc, "You prepare to extend a tentacle.")
+
+/obj/item/weapon/gun/magic/tentacle/dropped()
+ . = ..()
+ qdel(src)
+
+/obj/item/weapon/gun/magic/tentacle/shoot_with_empty_chamber(mob/living/user as mob|obj)
+ to_chat(user, "The [name] is not ready yet.")
+
+/obj/item/weapon/gun/magic/tentacle/suicide_act(mob/user)
+ user.visible_message("[user] coils [src] tightly around \his neck! It looks like \he's trying to commit suicide.")
+ return (OXYLOSS)
+
+/obj/item/ammo_casing/magic/tentacle
+ name = "tentacle"
+ desc = "a tentacle."
+ projectile_type = /obj/item/projectile/tentacle
+ caliber = "tentacle"
+ icon_state = "tentacle_end"
+ var/obj/item/weapon/gun/magic/tentacle/gun //the item that shot it
+
+/obj/item/ammo_casing/magic/tentacle/New(obj/item/weapon/gun/magic/tentacle/tentacle_gun)
+ gun = tentacle_gun
+ ..()
+
+/obj/item/ammo_casing/magic/tentacle/Destroy()
+ gun = null
+ return ..()
+
+/obj/item/projectile/tentacle
+ name = "tentacle"
+ icon_state = "tentacle_end"
+ pass_flags = PASSTABLE
+ damage = 0
+ damage_type = BRUTE
+ range = 8
+ hitsound = 'sound/weapons/thudswoosh.ogg'
+ var/chain
+ 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)
+ source = tentacle_casing
+ ..()
+
+/obj/item/projectile/tentacle/fire(setAngle)
+ if(firer)
+ 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/weapon/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))
+ I = l_hand
+ if(!is_sharp(I))
+ return
+
+ C.visible_message("[src] impales [C] with [I]!", "[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.gun) //one tentacle only unless you miss
+ if(blocked >= 100)
+ return 0
+ var/mob/living/carbon/human/H = firer
+ if(istype(target, /obj/item))
+ var/obj/item/I = target
+ if(!I.anchored)
+ to_chat(firer, "You pull [I] towards yourself.")
+ H.throw_mode_on()
+ I.throw_at(H, 10, 2)
+ . = 1
+
+ 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(INTENT_HELP)
+ C.visible_message("[L] is pulled by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
+ C.throw_at(get_step_towards(H,C), 8, 2)
+ return 1
+
+ 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!")
+ 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!")
+ return 0
+ else
+ to_chat(firer, "[C] has nothing in hand to disarm!")
+ return 0
+
+ if(INTENT_GRAB)
+ C.visible_message("[L] is grabbed by [H]'s tentacle!","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 1
+
+ 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, /mob/proc/tentacle_stab, C))
+ return 1
+ 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
+
+/obj/item/projectile/tentacle/Destroy()
+ qdel(chain)
+ source = null
+ return ..()
+
/***************************************\
|****************SHIELD*****************|
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 548f1fb357b..c54060cca7e 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -266,6 +266,8 @@
if(!supress_message)
visible_message("[user] has grabbed [src] passively!")
+ return G
+
/mob/living/incapacitated()
if(stat || paralysis || stunned || weakened || restrained())
return 1
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index ec06922a07d..b45657fff51 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 08050649225..1461df9bbbe 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 90a218c7166..c66e67820a3 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi
index 316790998c5..8c3d0f2c81f 100644
Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index 83276e5ec57..e4569806d57 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ