diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index 3ecd0d0fc3c..d237c2c2c90 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -255,7 +255,7 @@
loot = list(
// Robotics
/obj/item/mmi/robotic_brain = 50, // Low-value, but we want to encourage getting more players back in the round.
- /obj/item/assembly/signaler/anomaly = 50, // anomaly core
+ /obj/item/assembly/signaler/anomaly/random = 50, // anomaly core
/obj/item/mecha_parts/mecha_equipment/weapon/energy/xray = 25, // mecha x-ray laser
/obj/item/mecha_parts/mecha_equipment/teleporter/precise = 25, // upgraded mecha teleporter
/obj/item/autosurgeon = 50,
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 650e8edf141..1691f18066e 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -261,7 +261,8 @@
name = "reactive armor"
desc = "Doesn't seem to do much for some reason."
var/active = FALSE
- var/emp_d = FALSE
+ /// Is the armor disabled, and prevented from reactivating temporarly?
+ var/disabled = FALSE
icon_state = "reactiveoff"
item_state = "reactiveoff"
blood_overlay_type = "armor"
@@ -272,8 +273,8 @@
/obj/item/clothing/suit/armor/reactive/attack_self(mob/user)
active = !(active)
- if(emp_d)
- to_chat(user, "[src] is disabled from an electromagnetic pulse!")
+ if(disabled)
+ to_chat(user, "[src] is disabled and rebooting!")
return
if(active)
to_chat(user, "[src] is now active.")
@@ -290,18 +291,37 @@
A.UpdateButtonIcon()
/obj/item/clothing/suit/armor/reactive/emp_act(severity)
+ var/emp_power = 5 + (severity-1 ? 0 : 5)
+ disable(emp_power)
+ ..()
+
+/obj/item/clothing/suit/armor/reactive/proc/disable(disable_time = 0)
active = FALSE
- emp_d = TRUE
+ disabled = TRUE
icon_state = "reactiveoff"
item_state = "reactiveoff"
if(istype(loc, /mob/living/carbon/human))
var/mob/living/carbon/human/C = loc
C.update_inv_wear_suit()
- addtimer(CALLBACK(src, .proc/reboot), 100 / severity)
- ..()
+ addtimer(CALLBACK(src, .proc/reboot), disable_time SECONDS)
/obj/item/clothing/suit/armor/reactive/proc/reboot()
- emp_d = FALSE
+ disabled = FALSE
+ active = TRUE
+ icon_state = "reactive"
+ item_state = "reactive"
+ if(ishuman(loc))
+ var/mob/living/carbon/human/C = loc
+ C.update_inv_wear_suit()
+
+/obj/item/clothing/suit/armor/reactive/proc/reaction_check(hitby)
+ if(prob(hit_reaction_chance))
+ if(istype(hitby, /obj/item/projectile))
+ var/obj/item/projectile/P = hitby
+ if(!P.nodamage)
+ return TRUE
+ else
+ return TRUE
//When the wearer gets hit, this armor will teleport the user a short distance away (to safety or to more danger, no one knows. That's the fun of it!)
/obj/item/clothing/suit/armor/reactive/teleport
@@ -312,7 +332,7 @@
/obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
- if(prob(hit_reaction_chance))
+ if(reaction_check(hitby))
var/mob/living/carbon/human/H = owner
owner.visible_message("The reactive teleport system flings [H] clear of [attack_text]!")
var/list/turfs = new/list()
@@ -332,33 +352,35 @@
if(!isturf(picked))
return
H.forceMove(picked)
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/item/clothing/suit/armor/reactive/fire
name = "reactive incendiary armor"
+ desc = "This armor uses the power of a pyro anomaly core to shoot protective jets of fire."
/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
- return 0
- if(prob(hit_reaction_chance))
+ return FALSE
+ if(reaction_check(hitby))
owner.visible_message("The [src] blocks the [attack_text], sending out jets of flame!")
for(var/mob/living/carbon/C in range(6, owner))
if(C != owner)
C.fire_stacks += 8
C.IgniteMob()
owner.fire_stacks = -20
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/item/clothing/suit/armor/reactive/stealth
name = "reactive stealth armor"
+ desc = "This armor uses an anomaly core combined with holographic projectors to make the user invisible temporarly, and make a fake image of the user."
/obj/item/clothing/suit/armor/reactive/stealth/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
- return 0
- if(prob(hit_reaction_chance))
+ return FALSE
+ if(reaction_check(hitby))
var/mob/living/simple_animal/hostile/illusion/escape/E = new(owner.loc)
E.Copy_Parent(owner, 50)
E.GiveTarget(owner) //so it starts running right away
@@ -367,23 +389,64 @@
owner.visible_message("[owner] is hit by [attack_text] in the chest!") //We pretend to be hit, since blocking it would stop the message otherwise
spawn(40)
owner.alpha = initial(owner.alpha)
- return 1
+ return TRUE
/obj/item/clothing/suit/armor/reactive/tesla
name = "reactive tesla armor"
+ desc = "This armor uses the power of a flux anomaly core to protect the user in shocking ways."
/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
- return 0
- if(prob(hit_reaction_chance))
+ return FALSE
+ if(reaction_check(hitby))
owner.visible_message("The [src] blocks the [attack_text], sending out arcs of lightning!")
for(var/mob/living/M in view(6, owner))
if(M == owner)
continue
owner.Beam(M,icon_state="lightning[rand(1, 12)]",icon='icons/effects/effects.dmi',time=5)
- M.adjustFireLoss(25)
+ M.adjustFireLoss(20)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
- return 1
+ disable(rand(2, 5)) // let's not have buckshot set it off 4 times and do 80 burn damage.
+ return TRUE
+
+/obj/item/clothing/suit/armor/reactive/repulse
+ name = "reactive repulse armor"
+ desc = "An experimental suit of armor that violently throws back attackers with the power of a gravitational anomaly core."
+ ///How strong the reactive armor is for throwing
+ var/repulse_power = 3
+ /// How far away are we finding things to throw
+ var/repulse_range = 5
+
+/obj/item/clothing/suit/armor/reactive/repulse/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(!active)
+ return FALSE
+ if(reaction_check(hitby))
+ owner.visible_message("[src] blocks [attack_text], converting the attack into a wave of force!")
+ var/list/thrownatoms = list()
+ for(var/turf/T in range(repulse_range, owner)) //Done this way so things don't get thrown all around hilariously.
+ for(var/atom/movable/AM in T)
+ thrownatoms += AM
+
+ for(var/am in thrownatoms)
+ var/atom/movable/AM = am
+ if(AM == owner || AM.anchored)
+ continue
+
+ var/throwtarget = get_edge_target_turf(owner, get_dir(owner, get_step_away(AM, owner)))
+ var/distfromuser = get_dist(owner, AM)
+ if(distfromuser == 0)
+ if(isliving(AM))
+ var/mob/living/M = AM
+ M.Weaken(3)
+ to_chat(M, "You're slammed into the floor by [owner]'s reactive armor!")
+ else
+ if(isliving(AM))
+ var/mob/living/M = AM
+ to_chat(M, "You're thrown back by the [owner]'s reactive armor!")
+ spawn(0)
+ AM.throw_at(throwtarget, ((clamp((repulse_power - (clamp(distfromuser - 2, 0, distfromuser))), 3, repulse_power))), 1)//So stuff gets tossed around at the same time.
+ disable(rand(2, 5))
+ return TRUE
//All of the armor below is mostly unused
diff --git a/code/modules/research/anomaly/anomaly.dm b/code/modules/research/anomaly/anomaly.dm
index c8401b6ed99..5074c94afc8 100644
--- a/code/modules/research/anomaly/anomaly.dm
+++ b/code/modules/research/anomaly/anomaly.dm
@@ -51,3 +51,47 @@
icon_state = "vortex_core"
anomaly_type = /obj/effect/anomaly/bhole
origin_tech = "engineering=7"
+
+/obj/item/assembly/signaler/anomaly/random
+ name = "Random anomaly core"
+
+/obj/item/assembly/signaler/anomaly/random/New()
+ ..()
+ var/list/types = list(/obj/item/assembly/signaler/anomaly/pyro, /obj/item/assembly/signaler/anomaly/grav, /obj/item/assembly/signaler/anomaly/flux, /obj/item/assembly/signaler/anomaly/bluespace, /obj/item/assembly/signaler/anomaly/vortex)
+ var/A = pick(types)
+ new A(loc)
+ qdel(src)
+
+/obj/item/reactive_armour_shell
+ name = "reactive armour shell"
+ desc = "An experimental suit of armour, awaiting installation of an anomaly core."
+ icon_state = "reactiveoff"
+ icon = 'icons/obj/clothing/suits.dmi'
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/reactive_armour_shell/attackby(obj/item/I, mob/user, params)
+ var/static/list/anomaly_armour_types = list(
+ /obj/item/assembly/signaler/anomaly/grav = /obj/item/clothing/suit/armor/reactive/repulse,
+ /obj/item/assembly/signaler/anomaly/flux = /obj/item/clothing/suit/armor/reactive/tesla,
+ /obj/item/assembly/signaler/anomaly/bluespace = /obj/item/clothing/suit/armor/reactive/teleport,
+ /obj/item/assembly/signaler/anomaly/pyro = /obj/item/clothing/suit/armor/reactive/fire
+ )
+
+ if(istype(I, /obj/item/assembly/signaler/anomaly))
+ var/obj/item/assembly/signaler/anomaly/A = I
+ var/armour_path = /obj/item/clothing/suit/armor/reactive/stealth //Fallback
+ if(istype(I, /obj/item/assembly/signaler/anomaly/grav))
+ armour_path = /obj/item/clothing/suit/armor/reactive/repulse
+ if(istype(I, /obj/item/assembly/signaler/anomaly/flux))
+ armour_path = /obj/item/clothing/suit/armor/reactive/tesla
+ if(istype(I, /obj/item/assembly/signaler/anomaly/bluespace))
+ armour_path = /obj/item/clothing/suit/armor/reactive/teleport
+ if(istype(I, /obj/item/assembly/signaler/anomaly/pyro))
+ armour_path = /obj/item/clothing/suit/armor/reactive/fire
+ if(istype(I, /obj/item/assembly/signaler/anomaly/vortex))
+ armour_path = /obj/item/clothing/suit/armor/reactive/stealth // Vortex needs one, this is just temporary(TM) till one is coded for them.
+ to_chat(user, "You insert [A] into the chest plate, and the armour gently hums to life.")
+ new armour_path(get_turf(src))
+ qdel(src)
+ qdel(A)
+ return ..()
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 417adf813d7..82cf2c7bbf6 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -257,3 +257,15 @@
build_path = /obj/item/gun/energy/immolator
locked = 1
category = list("Weapons")
+
+/datum/design/reactive_armour
+ name = "Reactive Armor Shell"
+ desc = "A reactive armor shell, that can have an anomaly core inserted to make a reactive armor"
+ id = "reactivearmor"
+ req_tech = list("combat" = 6, "materials" = 7, "engineering" = 5)
+ build_type = PROTOLATHE
+ materials = list(MAT_PLASMA = 8000, MAT_TITANIUM = 14000, MAT_BLUESPACE = 6000) //Big strong armor needs big-ish investment
+ build_path = /obj/item/reactive_armour_shell
+ locked = TRUE
+ access_requirement = list(ACCESS_RD)
+ category = list("Weapons")
diff --git a/code/modules/ruins/lavalandruin_code/ash_walker_den.dm b/code/modules/ruins/lavalandruin_code/ash_walker_den.dm
index dacc57af08c..e03b5a56b00 100644
--- a/code/modules/ruins/lavalandruin_code/ash_walker_den.dm
+++ b/code/modules/ruins/lavalandruin_code/ash_walker_den.dm
@@ -25,7 +25,7 @@
STOP_PROCESSING(SSprocessing, src)
/obj/structure/lavaland/ash_walker/deconstruct(disassembled)
- new /obj/item/assembly/signaler/anomaly(get_step(loc, pick(GLOB.alldirs)))
+ new /obj/item/assembly/signaler/anomaly/random(get_step(loc, pick(GLOB.alldirs)))
new /obj/effect/collapse(loc)
return ..()