From af8dd35b5fee4544caca834fd66926cb9656d4a2 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sun, 14 Feb 2021 11:26:24 +0100 Subject: [PATCH] [MIRROR] Reactive armor now has user-dangerous effects when it is EMP'd, updates table armor to 2021 (+Documentation) (#3369) * Reactive armor now has user-dangerous effects when it is EMP'd, updates table armor to 2021 (+Documentation) (#56408) Co-authored-by: ATH1909 <42606352+ATH1909@ users.noreply.github.com> * Reactive armor now has user-dangerous effects when it is EMP'd, updates table armor to 2021 (+Documentation) Co-authored-by: tralezab <40974010+tralezab@users.noreply.github.com> Co-authored-by: ATH1909 <42606352+ATH1909@ users.noreply.github.com> --- .../modules/clothing/suits/reactive_armour.dm | 310 ++++++++++++------ 1 file changed, 207 insertions(+), 103 deletions(-) diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index 7e9ff987562..efa70c5b271 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -27,8 +27,17 @@ /obj/item/clothing/suit/armor/reactive name = "reactive armor" desc = "Doesn't seem to do much for some reason." + ///Whether the armor will try to react to hits (is it on) var/active = FALSE - var/reactivearmor_cooldown_duration = 10 SECONDS //cooldown specific to reactive armor + ///This will be true for 30 seconds after an EMP, it makes the reaction effect dangerous to the user. + var/bad_effect = FALSE + ///Message sent when the armor is emp'd. It is not the message for when the emp effect goes off. + var/emp_message = "The reactive armor has been emp'd! Damn, now it's REALLY gonna not do much!" + ///Message sent when the armor is still on cooldown, but activates. + var/cooldown_message = "The reactive armor fails to do much, as it is recharging! From what? Only the reactive armor knows." + ///Duration of the cooldown specific to reactive armor for when it can activate again. + var/reactivearmor_cooldown_duration = 10 SECONDS + ///The cooldown itself of the reactive armor for when it can activate again. var/reactivearmor_cooldown = 0 icon_state = "reactiveoff" inhand_icon_state = "reactiveoff" @@ -51,59 +60,104 @@ add_fingerprint(user) return +/obj/item/clothing/suit/armor/reactive/hit_reaction(owner, hitby, attack_text, final_block_chance, damage, attack_type) + if(!active || !prob(hit_reaction_chance)) + return FALSE + if(world.time < reactivearmor_cooldown) + cooldown_activation(owner) + return FALSE + if(bad_effect) + return emp_activation(owner, hitby, attack_text, final_block_chance, damage, attack_type) + else + return reactive_activation(owner, hitby, attack_text, final_block_chance, damage, attack_type) + +/** + * A proc for doing cooldown effects (like the sparks on the tesla armor, or the semi-stealth on stealth armor) + * Called from the suit activating whilst on cooldown. + * You should be calling ..() + */ +/obj/item/clothing/suit/armor/reactive/proc/cooldown_activation(mob/living/carbon/human/owner) + owner.visible_message(cooldown_message) + +/** + * A proc for doing reactive armor effects. + * Called from the suit activating while off cooldown, with no emp. + * Returning TRUE will block the attack that triggered this + */ +/obj/item/clothing/suit/armor/reactive/proc/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("The reactive armor doesn't do much! No surprises here.") + return TRUE + +/** + * A proc for doing owner unfriendly reactive armor effects. + * Called from the suit activating while off cooldown, while the armor is still suffering from the effect of an EMP. + * Returning TRUE will block the attack that triggered this + */ +/obj/item/clothing/suit/armor/reactive/proc/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("The reactive armor doesn't do much, despite being emp'd! Besides giving off a special message, of course.") + return TRUE + /obj/item/clothing/suit/armor/reactive/emp_act(severity) . = ..() - if(. & EMP_PROTECT_SELF) + if(. & EMP_PROTECT_SELF || bad_effect || !active) //didn't get hit or already emp'd, or off return - active = FALSE - icon_state = "reactiveoff" - inhand_icon_state = "reactiveoff" - reactivearmor_cooldown = world.time + 200 + visible_message(emp_message) + bad_effect = TRUE + addtimer(VARSET_CALLBACK(src, bad_effect, FALSE), 30 SECONDS) //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 name = "reactive teleport armor" desc = "Someone separated our Research Director from his own head!" + emp_message = "The reactive armor's teleportation calculations begin spewing errors!" + cooldown_message = "The reactive teleport system is still recharging! It fails to activate!" + reactivearmor_cooldown_duration = 10 SECONDS var/tele_range = 6 var/rad_amount= 15 -/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 FALSE - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - owner.visible_message("The reactive teleport system is still recharging! It fails to teleport [owner]!") - return FALSE - owner.visible_message("The reactive teleport system flings [owner] clear of [attack_text], shutting itself off in the process!") - playsound(get_turf(owner),'sound/magic/blink.ogg', 100, TRUE) - do_teleport(owner, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE) - owner.rad_act(rad_amount) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return TRUE - return FALSE +/obj/item/clothing/suit/armor/reactive/teleport/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("The reactive teleport system flings [owner] clear of [attack_text]!") + playsound(get_turf(owner),'sound/magic/blink.ogg', 100, TRUE) + do_teleport(owner, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE) + owner.rad_act(rad_amount) + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE + +/obj/item/clothing/suit/armor/reactive/teleport/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("The reactive teleport system flings itself clear of [attack_text], leaving someone behind in the process!") + owner.dropItemToGround(src, TRUE, TRUE) + playsound(get_turf(owner),'sound/machines/buzz-sigh.ogg', 50, TRUE) + playsound(get_turf(owner),'sound/magic/blink.ogg', 100, TRUE) + do_teleport(src, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE) + owner.rad_act(rad_amount) + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return FALSE //you didn't actually evade the attack now did you //Fire /obj/item/clothing/suit/armor/reactive/fire name = "reactive incendiary armor" desc = "An experimental suit of armor with a reactive sensor array rigged to a flame emitter. For the stylish pyromaniac." + cooldown_message = "The reactive incendiary armor activates, but fails to send out flames as it is still recharging its flame jets!" + emp_message = "The reactive incendiary armor's targeting system begins rebooting..." -/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 FALSE - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - owner.visible_message("The reactive incendiary armor on [owner] activates, but fails to send out flames as it is still recharging its flame jets!") - return FALSE - owner.visible_message("[src] blocks [attack_text], sending out jets of flame!") - playsound(get_turf(owner),'sound/magic/fireball.ogg', 100, TRUE) - for(var/mob/living/carbon/C in range(6, owner)) - if(C != owner) - C.adjust_fire_stacks(8) - C.IgniteMob() - owner.set_fire_stacks(-20) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return TRUE +/obj/item/clothing/suit/armor/reactive/fire/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("[src] blocks [attack_text], sending out jets of flame!") + playsound(get_turf(owner),'sound/magic/fireball.ogg', 100, TRUE) + for(var/mob/living/carbon/carbon_victim in range(6, owner)) + if(carbon_victim != owner) + carbon_victim.adjust_fire_stacks(8) + carbon_victim.IgniteMob() + owner.set_fire_stacks(-20) + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE + +/obj/item/clothing/suit/armor/reactive/fire/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("[src] just makes [attack_text] worse by spewing molten death on [owner]!") + playsound(get_turf(owner),'sound/magic/fireball.ogg', 100, TRUE) + owner.adjust_fire_stacks(12) + owner.IgniteMob() + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration return FALSE //Stealth @@ -111,23 +165,50 @@ /obj/item/clothing/suit/armor/reactive/stealth name = "reactive stealth armor" desc = "An experimental suit of armor that renders the wearer invisible on detection of imminent harm, and creates a decoy that runs away from the owner. You can't fight what you can't see." + cooldown_message = "The reactive stealth system activates, but is not charged enough to fully cloak!" + emp_message = "The reactive stealth armor's threat assessment system crashes..." + ///when triggering while on cooldown will only flicker the alpha slightly. this is how much it removes. + var/cooldown_alpha_removal = 50 + ///cooldown alpha flicker- how long it takes to return to the original alpha + var/cooldown_animation_time = 3 SECONDS + ///how long they will be fully stealthed + var/stealth_time = 4 SECONDS + ///how long it will animate back the alpha to the original + var/animation_time = 2 SECONDS + var/in_stealth = FALSE -/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 FALSE - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - owner.visible_message("The reactive stealth system on [owner] activates, but is still recharging its holographic emitters!") - return - 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 - E.Goto(owner, E.move_to_delay, E.minimum_distance) - owner.alpha = 0 - 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 - addtimer(VARSET_CALLBACK(owner, alpha, initial(owner.alpha)), 4 SECONDS) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return TRUE +/obj/item/clothing/suit/armor/reactive/stealth/cooldown_activation(mob/living/carbon/human/owner) + if(in_stealth) + return //we don't want the cooldown message either) + owner.alpha = max(0, owner.alpha - cooldown_alpha_removal) + animate(owner, alpha = initial(owner.alpha), time = cooldown_animation_time) + ..() + +/obj/item/clothing/suit/armor/reactive/stealth/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + var/mob/living/simple_animal/hostile/illusion/escape/decoy = new(owner.loc) + decoy.Copy_Parent(owner, 50) + decoy.GiveTarget(owner) //so it starts running right away + decoy.Goto(owner, decoy.move_to_delay, decoy.minimum_distance) + owner.alpha = 0 + in_stealth = TRUE + 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 + addtimer(CALLBACK(src, .proc/end_stealth, owner), stealth_time) + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE + +/obj/item/clothing/suit/armor/reactive/stealth/proc/end_stealth(mob/living/carbon/human/owner) + in_stealth = FALSE + animate(owner, alpha = initial(owner.alpha), time = animation_time) + +/obj/item/clothing/suit/armor/reactive/stealth/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + if(!isliving(hitby)) + return FALSE //it just doesn't activate + var/mob/living/attacker = hitby + owner.visible_message("[src] activates, cloaking the wrong person!") + attacker.alpha = 0 + addtimer(VARSET_CALLBACK(attacker, alpha, initial(attacker.alpha)), 4 SECONDS) + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return FALSE //Tesla @@ -135,6 +216,8 @@ name = "reactive tesla armor" desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap." siemens_coefficient = -1 + cooldown_message = "The tesla capacitors on the reactive tesla armor are still recharging! The armor merely emits some sparks." + cooldown_message = "The tesla capacitors beep ominously for a moment." var/zap_power = 25000 var/zap_range = 20 var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE @@ -149,70 +232,91 @@ if(slot_flags & slot) //Was equipped to a valid slot for this item? REMOVE_TRAIT(user, TRAIT_TESLA_SHOCKIMMUNE, "reactive_tesla_armor") -/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 FALSE - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread - sparks.set_up(1, 1, src) - sparks.start() - owner.visible_message("The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.") - return - owner.visible_message("[src] blocks [attack_text], sending out arcs of lightning!") - tesla_zap(owner, zap_range, zap_power, zap_flags) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return TRUE +/obj/item/clothing/suit/armor/reactive/tesla/cooldown_activation(mob/living/carbon/human/owner) + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(1, 1, src) + sparks.start() + ..() + +/obj/item/clothing/suit/armor/reactive/tesla/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("[src] blocks [attack_text], sending out arcs of lightning!") + tesla_zap(owner, zap_range, zap_power, zap_flags) + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE + +/obj/item/clothing/suit/armor/reactive/tesla/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("[src] blocks [attack_text], but pulls a massive charge of energy into [owner] from the surrounding environment!") + REMOVE_TRAIT(owner, TRAIT_TESLA_SHOCKIMMUNE, "reactive_tesla_armor") //oops! can't shock without this! + electrocute_mob(owner, get_area(src), src, 1) + ADD_TRAIT(owner, TRAIT_TESLA_SHOCKIMMUNE, "reactive_tesla_armor") + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE //Repulse /obj/item/clothing/suit/armor/reactive/repulse name = "reactive repulse armor" desc = "An experimental suit of armor that violently throws back attackers." + cooldown_message = "The repulse generator is still recharging! It fails to generate a strong enough wave!" + emp_message = "The repulse generator is reset to default settings..." var/repulse_force = MOVE_FORCE_EXTREMELY_STRONG -/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(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - owner.visible_message("The repulse generator is still recharging!") - return FALSE - playsound(get_turf(owner),'sound/magic/repulse.ogg', 100, TRUE) - owner.visible_message("[src] blocks [attack_text], converting the attack into a wave of force!") - var/turf/T = get_turf(owner) - var/list/thrown_items = list() - for(var/atom/movable/A in range(T, 7)) - if(A == owner || A.anchored || thrown_items[A]) - continue - var/throwtarget = get_edge_target_turf(T, get_dir(T, get_step_away(A, T))) - A.safe_throw_at(throwtarget, 10, 1, force = repulse_force) - thrown_items[A] = A +/obj/item/clothing/suit/armor/reactive/repulse/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + playsound(get_turf(owner),'sound/magic/repulse.ogg', 100, TRUE) + owner.visible_message("[src] blocks [attack_text], converting the attack into a wave of force!") + var/turf/owner_turf = get_turf(owner) + var/list/thrown_items = list() + for(var/atom/movable/repulsed in range(owner_turf, 7)) + if(repulsed == owner || repulsed.anchored || thrown_items[repulsed]) + continue + var/throwtarget = get_edge_target_turf(owner_turf, get_dir(owner_turf, get_step_away(repulsed, owner_turf))) + repulsed.safe_throw_at(throwtarget, 10, 1, force = repulse_force) + thrown_items[repulsed] = repulsed - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return TRUE + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE + +/obj/item/clothing/suit/armor/reactive/repulse/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + playsound(get_turf(owner),'sound/magic/repulse.ogg', 100, TRUE) + owner.visible_message("[src] does not block [attack_text], and instead generates an attracting force!") + var/turf/owner_turf = get_turf(owner) + var/list/thrown_items = list() + for(var/atom/movable/repulsed in range(owner_turf, 7)) + if(repulsed == owner || repulsed.anchored || thrown_items[repulsed]) + continue + repulsed.safe_throw_at(owner, 10, 1, force = repulse_force) + thrown_items[repulsed] = repulsed + + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return FALSE /obj/item/clothing/suit/armor/reactive/table name = "reactive table armor" desc = "If you can't beat the memes, embrace them." + cooldown_message = "The reactive table armor's fabricators are still on cooldown!" + emp_message = "The reactive table armor's fabricators click and whirr ominously for a moment..." var/tele_range = 10 -/obj/item/clothing/suit/armor/reactive/table/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(prob(hit_reaction_chance)) - var/mob/living/carbon/human/H = owner - if(world.time < reactivearmor_cooldown) - owner.visible_message("The reactive table armor's fabricators are still on cooldown!") - return FALSE - owner.visible_message("The reactive teleport system flings [H] clear of [attack_text] and slams [H.p_them()] into a fabricated table!") - owner.visible_message("[H] GOES ON THE TABLE!!!") - owner.Paralyze(40) - do_teleport(owner, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE) - new /obj/structure/table(get_turf(owner)) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return TRUE - return FALSE +/obj/item/clothing/suit/armor/reactive/table/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("The reactive teleport system flings [owner] clear of [attack_text] and slams [owner.p_them()] into a fabricated table!") + owner.visible_message("[owner] GOES ON THE TABLE!!!") + owner.Knockdown(30) + owner.apply_damage(10, BRUTE) + owner.apply_damage(40, STAMINA) + playsound(owner, 'sound/effects/tableslam.ogg', 90, TRUE) + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table) + do_teleport(owner, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE) + new /obj/structure/table(get_turf(owner)) + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE + +/obj/item/clothing/suit/armor/reactive/table/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message("The reactive teleport system flings [owner] clear of [attack_text] and slams [owner.p_them()] into a fabricated glass table!") + owner.visible_message("[owner] GOES ON THE GLASS TABLE!!!") + do_teleport(owner, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE) + var/obj/structure/table/glass/shattering_table = new /obj/structure/table/glass(get_turf(owner)) + shattering_table.table_shatter(owner) + + reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration + return TRUE -/obj/item/clothing/suit/armor/reactive/table/emp_act() - return