Ports TG Anomalies (#18794)

* Anomalies

* Tiles

* Automatic changelog compile [ci skip]

* Bioscramble

* Reactive armour

* Reactive

* .

* Automatic changelog compile [ci skip]

* hallucination

* Snowy

* Bit of polishing

* change

* Cargo & Research

* fimx

* Anomaly stuffs

* Bioscrambler + Terrible fire armour

* Adjustment

* Less spammy

* Changes

---------

Co-authored-by: vorestation-ci[bot] <199609141+vorestation-ci[bot]@users.noreply.github.com>
This commit is contained in:
Guti
2025-12-11 12:47:48 +01:00
committed by GitHub
parent 81acf7df5c
commit d59ad9df0c
48 changed files with 1859 additions and 13 deletions
+3 -2
View File
@@ -160,7 +160,8 @@
body_parts_covered = CHEST
armor = list(melee = 40, bullet = 30, laser = 30, energy = 10, bomb = 10, bio = 0, rad = 0)
// Ooold, old reactive armor.
/*
//Reactive armor
//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
@@ -211,7 +212,7 @@
active = FALSE
icon_state = "reactiveoff"
..()
*/
// Alien armor has a chance to completely block attacks.
/obj/item/clothing/suit/armor/alien
name = "alien enhancement vest"
@@ -0,0 +1,356 @@
/obj/item/clothing/suit/armor/reactive_armor_shell
name = "reactive armor shell"
desc = "An experimental suit of armor, awaiting installation of an anomaly core."
icon_state = "reactiveoff"
w_class = ITEMSIZE_COST_LARGE
/obj/item/clothing/suit/armor/reactive_armor_shell/attackby(obj/item/I, mob/user)
. = ..()
var/static/list/anomaly_armour_types = list(
/obj/effect/anomaly/grav = /obj/item/clothing/suit/armor/reactive/repulse,
/obj/effect/anomaly/flux = /obj/item/clothing/suit/armor/reactive/tesla,
/obj/effect/anomaly/bluespace = /obj/item/clothing/suit/armor/reactive/teleport,
//obj/effect/anomaly/bioscrambler = /obj/item/clothing/suit/armor/reactive/bioscrambling,
/obj/effect/anomaly/hallucination = /obj/item/clothing/suit/armor/reactive/hallucinating,
/obj/effect/anomaly/dimensional = /obj/item/clothing/suit/armor/reactive/barricade,
/obj/effect/anomaly/pyro = /obj/item/clothing/suit/armor/reactive/fire
)
if(istype(I, /obj/item/assembly/signaler/anomaly))
var/obj/item/assembly/signaler/anomaly/anomaly = I
var/armour_path = is_path_in_list(anomaly.anomaly_type, anomaly_armour_types, TRUE)
if(!armour_path)
armour_path = /obj/item/clothing/suit/armor/reactive/stealth
to_chat(user, span_notice("You insert [anomaly] into the chest plate, and the armour gently hums to life."))
new armour_path(get_turf(src))
qdel(src)
qdel(anomaly)
return TRUE
/obj/item/clothing/suit/armor/reactive
name = "reactive armor"
desc = "Doesn't seem to do much for some reason."
icon_state = "reactiveoff"
blood_overlay_type = "armor"
armor = list(melee = 40, bullet = 35, laser = 35, energy = 10, bomb = 10, bio = 0, rad = 0)
var/hit_reaction_chance = 50
///Whether the armor will try to react to hits (is it on)
var/active = FALSE
///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 = span_warning("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 = span_danger("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
/obj/item/clothing/suit/armor/reactive/update_icon()
. = ..()
icon_state = "reactive[active ? null : "off"]"
/obj/item/clothing/suit/armor/reactive/attack_self(mob/user)
active = !active
to_chat(user, span_notice("[src] is now [active ? "active" : "inactive"]."))
update_icon()
add_fingerprint(user)
/obj/item/clothing/suit/armor/reactive/handle_shield(mob/user, damage, atom/damage_source, mob/attacker, def_zone, attack_text)
if(!active || !prob(hit_reaction_chance))
return FALSE
if(world.time < reactivearmor_cooldown)
cooldown_activation(user)
return FALSE
if(bad_effect)
return emp_activation(user, damage_source, attack_text, damage)
else
return reactive_activation(user, damage_source, attack_text, damage)
/obj/item/clothing/suit/armor/reactive/proc/cooldown_activation(var/mob/living/carbon/human/owner)
owner.visible_message(cooldown_message)
/obj/item/clothing/suit/armor/reactive/proc/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
owner.visible_message(span_danger("The reactive armor doesn't do much! No surprises here."))
return TRUE
/obj/item/clothing/suit/armor/reactive/proc/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
owner.visible_message(span_danger("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, recursive)
. = ..()
if(bad_effect || !active)
return
visible_message(emp_message)
bad_effect = TRUE
addtimer(VARSET_CALLBACK(src, bad_effect, FALSE), 30 SECONDS)
/obj/item/clothing/suit/armor/reactive/teleport
name = "reactive teleport armor"
desc = "Someone separated our Research Director from his own head!"
emp_message = span_warning("The reactive armor's teleportation calculations begin spewing errors!")
cooldown_message = span_danger("The reactive teleport system is still recharging! It fails to activate!")
reactivearmor_cooldown_duration = 10 SECONDS
var/tele_range = 6
/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)
owner.visible_message(span_danger("The reactive teleport system flings [owner] clear of [attack_text]!"))
playsound(get_turf(owner), 'sound/effects/phasein.ogg', 100, TRUE)
do_teleport(owner, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE)
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)
owner.visible_message(span_danger("The reactive teleport system flings itself clear of [attack_text], leaving someone behind in the process!"))
owner.drop_from_inventory(src, get_turf(src))
playsound(get_turf(owner),'sound/machines/buzz-sigh.ogg', 50, TRUE)
playsound(get_turf(owner), 'sound/effects/phasein.ogg', 100, TRUE)
do_teleport(src, get_turf(owner), tele_range, no_effects = TRUE, channel = TELEPORT_CHANNEL_BLUESPACE)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return FALSE
/obj/item/clothing/suit/armor/reactive/repulse
name = "reactive repulse armor"
desc = "An experimental suit of armor that violently throws back attackers."
cooldown_message = span_danger("The repulse generator is still recharging! It fails to generate a strong enough wave!")
emp_message = span_warning("The repulse generator is reset to default settings...")
/obj/item/clothing/suit/armor/reactive/repulse/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
playsound(get_turf(owner),'sound/effects/repulse.ogg', 100, TRUE)
owner.visible_message(span_danger("[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, 5))
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.throw_at(throwtarget, 10, 1)
thrown_items[repulsed] = repulsed
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", damage = 0)
playsound(get_turf(owner),'sound/effects/repulse.ogg', 100, TRUE)
owner.visible_message(span_danger("[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, 5))
if(repulsed == owner || repulsed.anchored || thrown_items[repulsed])
continue
repulsed.throw_at(owner, 10, 1)
thrown_items[repulsed] = repulsed
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return FALSE
// Tesla
/obj/item/clothing/suit/armor/reactive/tesla
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 = span_danger("The tesla capacitors on the reactive tesla armor are still recharging! The armor merely emits some sparks.")
emp_message = span_warning("The tesla capacitors beep ominously for a moment.")
clothing_traits = list(TRAIT_TESLA_SHOCKIMMUNE)
/// How strong are the zaps we give off?
var/zap_power = 2.5e4
/// How far to the zaps we give off go?
var/zap_range = 20
/obj/item/clothing/suit/armor/reactive/tesla/cooldown_activation(mob/living/carbon/human/owner)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/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", damage = 0)
owner.visible_message(span_danger("[src] blocks [attack_text], sending out arcs of lightning!"))
tesla_zap(owner, zap_range, zap_power)
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", damage = 0)
owner.visible_message(span_danger("[src] blocks [attack_text], but pulls a massive charge of energy into [owner] from the surrounding environment!"))
REMOVE_CLOTHING_TRAIT(owner, TRAIT_TESLA_SHOCKIMMUNE)
electrocute_mob(owner, get_area(src), src, 1)
ADD_CLOTHING_TRAIT(owner, TRAIT_TESLA_SHOCKIMMUNE)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return TRUE
// Sure we could, but- Not really THAT useful. Give them the stealth one.
/obj/item/clothing/suit/armor/reactive/bioscrambling
// Hallucinating
/obj/item/clothing/suit/armor/reactive/hallucinating
name = "reactive hallucinating armor"
desc = "An experimental suit of armor with sensitive detectors hooked up to the mind of the wearer, sending mind pulses that causes hallucinations around you."
cooldown_message = span_danger("The connection is currently out of sync... Recalibrating.")
emp_message = span_warning("You feel the backsurge of a mind pulse.")
clothing_traits = list(TRAIT_MADNESS_IMMUNE)
/obj/item/clothing/suit/armor/reactive/hallucinating/cooldown_activation(mob/living/carbon/human/owner)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(1, 1, src)
sparks.start()
..()
/obj/item/clothing/suit/armor/reactive/hallucinating/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
owner.visible_message(span_danger("[src] blocks [attack_text], sending out mental pulses!"))
for(var/mob/living/carbon/human/hallucinator in viewers(5, get_turf(src)))
if(hallucinator == owner)
continue
hallucinator.hallucination += 50
if(prob(10))
to_chat(hallucinator, span_danger("Your nose bleeds!"))
hallucinator.drip(1)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return TRUE
/obj/item/clothing/suit/armor/reactive/hallucinating/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
owner.visible_message(span_danger("[src] blocks [attack_text], but pulls a massive charge of mental energy into [owner] from the surrounding environment!"))
owner.hallucination += 75
to_chat(owner, span_danger("Your nose bleeds!"))
owner.drip(1)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return TRUE
// When the wearer gets hit, this armor will push people nearby and spawn some blocking objects.
/obj/item/clothing/suit/armor/reactive/barricade
name = "reactive barricade armor"
desc = "An experimental suit of armor that generates barriers from another world when it detects its bearer is in danger."
emp_message = span_warning("The reactive armor's dimensional coordinates are scrambled!")
cooldown_message = span_danger("The reactive barrier system is still recharging! It fails to activate!")
reactivearmor_cooldown_duration = 10 SECONDS
/obj/item/clothing/suit/armor/reactive/barricade/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
playsound(get_turf(owner),'sound/effects/repulse.ogg', 100, TRUE)
owner.visible_message(span_danger("The reactive armor interposes matter from another world between [src] and [attack_text]!"))
for (var/atom/movable/target in repulse_targets(owner))
repulse(target, owner)
var/datum/armour_dimensional_theme/theme = new()
theme.apply_random(get_turf(owner), dangerous = FALSE)
qdel(theme)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return TRUE
/obj/item/clothing/suit/armor/reactive/barricade/proc/repulse_targets(atom/source)
var/list/push_targets = list()
for (var/atom/movable/nearby_movable in view(1, source))
if(nearby_movable == source)
continue
if(nearby_movable.anchored)
continue
push_targets += nearby_movable
return push_targets
/obj/item/clothing/suit/armor/reactive/barricade/proc/repulse(atom/movable/victim, atom/source)
var/dist_from_caster = get_dist(victim, source)
if(dist_from_caster == 0)
return
if (isliving(victim))
to_chat(victim, span_userdanger("You're thrown back by a wave of pressure!"))
var/turf/throwtarget = get_edge_target_turf(source, get_dir(source, get_step_away(victim, source, 1)))
victim.throw_at(throwtarget, 1, 1)
/obj/item/clothing/suit/armor/reactive/barricade/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
owner.visible_message(span_danger("The reactive armor shunts matter from an unstable dimension!"))
var/datum/armour_dimensional_theme/theme = new()
theme.apply_random(get_turf(owner), dangerous = TRUE)
qdel(theme)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return FALSE
// 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 = span_danger("The reactive incendiary armor activates, but fails to send out flames as it is still recharging its flame jets!")
emp_message = span_warning("The reactive incendiary armor's targeting system begins rebooting...")
/obj/item/clothing/suit/armor/reactive/fire/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
owner.visible_message(span_danger("[src] blocks [attack_text], sending out jets of flame!"))
playsound(get_turf(owner), 'sound/magic/Fireball.ogg', 100, TRUE)
for(var/mob/living/carbon_victim in range(6, get_turf(src)))
if(carbon_victim != owner)
carbon_victim.adjust_fire_stacks(8)
carbon_victim.ignite_mob()
owner.set_wet_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", damage = 0)
owner.visible_message(span_danger("[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.ignite_mob()
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return FALSE
/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 = span_danger("The reactive stealth system activates, but is not charged enough to fully cloak!")
emp_message = span_warning("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/cooldown_activation(mob/living/carbon/human/owner)
if(in_stealth)
return
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, final_block_chance, damage)
var/mob/living/simple_mob/illusion/decoy = new(owner.loc)
decoy.copy_appearance(owner)
decoy.copy_overlays(owner, TRUE)
var/datum/ai_holder/AI = decoy.ai_holder
var/turf/rand_turf = pick(get_turf(orange(5, 10)))
AI.give_destination(rand_turf)
owner.alpha = 0
in_stealth = TRUE
owner.visible_message(span_danger("[owner] is hit by [attack_text] in the chest!"))
addtimer(CALLBACK(src, PROC_REF(end_stealth), owner), stealth_time)
decoy.say("*sidestep")
addtimer(CALLBACK(src, PROC_REF(destroy_illusion), decoy), stealth_time)
QDEL_IN(decoy, 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/proc/destroy_illusion(mob/illusion)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(3, 3, illusion)
sparks.start()
QDEL_IN(illusion, animation_time)
/obj/item/clothing/suit/armor/reactive/stealth/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0)
if(!isliving(hitby))
return FALSE
var/mob/living/attacker = hitby
owner.visible_message(span_danger("[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
@@ -0,0 +1,96 @@
#define MAX_BARRIERS 4
#define MIN_BARRIERS 2
/datum/armour_dimensional_theme
var/datum/material/material
var/turf/replace_floor = /turf/simulated/floor/tiled
var/turf/replace_wall = /turf/simulated/wall
var/obj/barricade = /obj/structure/barricade
var/barricade_anchored = TRUE
/datum/armour_dimensional_theme/proc/apply_random(turf/source, dangerous = FALSE)
var/theme_type
if(dangerous)
theme_type = pick(subtypesof(/datum/armour_dimensional_theme/dangerous))
else
theme_type = pick(subtypesof(/datum/armour_dimensional_theme/safe))
var/datum/armour_dimensional_theme/theme = new theme_type()
theme.apply(source)
qdel(theme)
/datum/armour_dimensional_theme/proc/apply(turf/source)
var/obj/effect/effect/smoke/poof = new(source)
poof.time_to_live = 2 SECONDS
var/list/target_area = get_target_area(source)
for (var/turf/target in target_area)
convert_turf(target)
place_barriers(source, target_area)
/datum/armour_dimensional_theme/proc/get_target_area(turf/source)
var/list/target_area = RANGE_TURFS(1, source)
for (var/turf/check_turf as anything in target_area)
if(isspace(check_turf))
target_area -= check_turf
continue
if(istype(get_area(check_turf), /area/holodeck))
continue
return target_area
/datum/armour_dimensional_theme/proc/convert_turf(turf/to_convert)
if(isfloorturf(to_convert))
var/turf/simulated/floor/floor = to_convert
floor.ChangeTurf(replace_floor)
else if(iswall(to_convert))
to_convert.ChangeTurf(replace_wall)
/datum/armour_dimensional_theme/proc/place_barriers(turf/source, list/target_area)
target_area -= source
for(var/turf/check_turf as anything in target_area)
if (!check_turf.density)
continue
target_area -= check_turf
var/to_place = rand(MIN_BARRIERS, MAX_BARRIERS)
var/list/custom_materials = list()
if(material)
custom_materials = list(GET_MATERIAL_REF(material) = SHEET_MATERIAL_AMOUNT)
while(target_area.len > 0 && to_place > 0)
var/turf/place_turf = pick(target_area)
place_barrier(place_turf, custom_materials)
target_area -= place_turf
to_place--
/datum/armour_dimensional_theme/proc/place_barrier(turf/source)
var/obj/structure/barricade/placed_barricade = new barricade(source, material.name)
if(!barricade_anchored)
placed_barricade.anchored = FALSE
/datum/armour_dimensional_theme/safe
/datum/armour_dimensional_theme/safe/natural
replace_wall = /turf/simulated/wall/wood
replace_floor = /turf/simulated/floor/wood
barricade = /obj/structure/barricade
material = /datum/material/wood
/datum/armour_dimensional_theme/safe/snow
replace_wall = /turf/simulated/wall/snowbrick
replace_floor = /turf/simulated/floor/snow
material = /datum/material/snow
/datum/armour_dimensional_theme/dangerous
/datum/armour_dimensional_theme/dangerous/radioactive
replace_wall = /turf/simulated/wall/uranium
replace_floor = /turf/simulated/floor/tiled/material/uranium
material = /datum/material/uranium
/datum/armour_dimensional_theme/dangerous/phoron
replace_wall = /turf/simulated/wall/phoron
replace_floor = /turf/simulated/floor/tiled/material/phoron
material = /datum/material/phoron
#undef MAX_BARRIERS
#undef MIN_BARRIERS
+1 -1
View File
@@ -49,7 +49,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
// Traditional hallucinations
/////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/living/carbon/proc/handle_hallucinations()
if(get_hallucination_component() || !client)
if(get_hallucination_component() || !client || HAS_TRAIT(src, TRAIT_MADNESS_IMMUNE))
return
LoadComponent(/datum/component/hallucinations)
+3
View File
@@ -663,6 +663,9 @@ var/list/mining_overlay_cache = list()
M.make_jittery(50) //SHAKY this used to be 1000(seizure) but I toned it to 50 to be less aggressive.
if(prob(25))
excavate_find(prob(25), finds[1])
if(prob(2))
var/anomaly = pick(FLUX_ANOMALY, GRAVITATIONAL_ANOMALY, PYRO_ANOMALY, HALLUCINATION_ANOMALY)
generate_anomaly(get_turf(src), anomaly, 1, FALSE)
else if(rand(1,500) == 1)
visible_message(span_notice("An old dusty crate was buried within!"))
new /obj/structure/closet/crate/secure/loot(src)
+1 -1
View File
@@ -1255,7 +1255,7 @@
Paralyse(3)
if(hallucination)
if(hallucination >= HALLUCINATION_THRESHOLD && !(species.flags & (NO_POISON|IS_PLANT|NO_HALLUCINATION)) )
if(hallucination >= HALLUCINATION_THRESHOLD && !(species.flags & (NO_POISON|IS_PLANT|NO_HALLUCINATION)) && !HAS_TRAIT(src, TRAIT_MADNESS_IMMUNE))
handle_hallucinations()
/* Stop spinning the view, it breaks too much.
if(client && prob(5))
@@ -301,6 +301,16 @@
if(grav_pulling)
supermatter_pull(src)
if(damage) // Start fucking things up
if(get_integrity() < 85 && prob(5))
generate_anomaly(get_ranged_target_turf(src, pick(GLOB.cardinal), rand(5, 10)), FLUX_ANOMALY)
if(get_integrity() < 75 && prob(5))
generate_anomaly(get_ranged_target_turf(src, pick(GLOB.cardinal), rand(5, 10)), HALLUCINATION_ANOMALY)
if(get_integrity() < 50 && prob(2))
generate_anomaly(get_ranged_target_turf(src, pick(GLOB.cardinal), rand(5, 10)), GRAVITATIONAL_ANOMALY)
if(get_integrity() < 25 && prob(0.3))
generate_anomaly(get_ranged_target_turf(src, pick(GLOB.cardinal), rand(5, 10)), PYRO_ANOMALY)
// Vary volume by power produced.
if(power)
// Volume will be 1 at no power, ~12.5 at ENERGY_NITROGEN, and 20+ at ENERGY_PHORON.
@@ -0,0 +1,92 @@
/obj/item/assembly/signaler/anomaly
name = "anomaly core"
desc = "The neutralized core of an anomaly. It'd probably be valuable for research."
icon_state = "anomaly_core"
var/anomaly_type = /obj/effect/anomaly
var/worth = 250 // Pricey... Should be hard-ish to obtain.
/obj/item/assembly/signaler/anomaly/Initialize(mapload)
. = ..()
if(worth)
AddElement(/datum/element/sellable)
/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
if(!signal)
return FALSE
if(signal.encryption != code)
return FALSE
for(var/obj/effect/anomaly/anomaly in get_turf(src))
anomaly.anomalyNeutralize()
return TRUE
/obj/item/assembly/signaler/anomaly/attack_self(mob/user)
return
/obj/item/assembly/signaler/anomaly/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/analyzer))
to_chat(user, span_notice("Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(frequency)], code [code]."))
return TRUE
if(istype(W, /obj/item/anomaly_releaser))
var/obj/item/anomaly_releaser/releaser = W
if(releaser.used)
return FALSE
if(!do_after(user, 3 SECONDS, src))
return FALSE
var/obj/item/assembly/signaler/anomaly/core = src
if(!core.anomaly_type)
return FALSE
var/obj/effect/anomaly/anomaly = new core.anomaly_type(get_turf(core))
anomaly.stabilize()
if(!releaser.infinite)
releaser.icon_state = releaser.used_icon_state
releaser.used = TRUE
releaser.name = "used " + name
qdel(src)
return ..()
/obj/item/assembly/signaler/anomaly/flux
name = "\improper flux anomaly core"
desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research."
icon_state = "flux_core"
anomaly_type = /obj/effect/anomaly/flux
/obj/item/assembly/signaler/anomaly/bluespace
name = "\improper bluespace anomaly core"
desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research."
icon_state = "anomaly_core"
anomaly_type = /obj/effect/anomaly/bluespace
/obj/item/assembly/signaler/anomaly/grav
name = "\improper gravitational anomaly core"
desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research."
icon_state = "grav_core"
anomaly_type = /obj/effect/anomaly/grav
/obj/item/assembly/signaler/anomaly/dimensional
name = "\improper dimensional anomaly core"
desc = "The neutralized core of a dimensional anomaly. Objects reflected on its surface don't look quite right. It'd probably be valuable for research."
icon_state = "dimensional_core"
anomaly_type = /obj/effect/anomaly/dimensional
/obj/item/assembly/signaler/anomaly/bioscrambler
name = "\improper bioscrambler anomaly core"
desc = "The neutralized core of a bioscrambler anomaly. It's squirming, as if moving. It'd probably be valuable for research."
icon_state = "bioscrambler_core"
anomaly_type = /obj/effect/anomaly/bioscrambler
/obj/item/assembly/signaler/anomaly/hallucination
name = "\improper hallucination anomaly core"
desc = "The neutralized core of a hallucination anomaly. It seems to be moving, but it's probably your imagination. It'd probably be valuable for research."
icon_state = "hallucination_core"
anomaly_type = /obj/effect/anomaly/hallucination
/obj/item/assembly/signaler/anomaly/pyro
name = "\improper pyroclastic anomaly core"
desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research."
icon_state = "pyro_core"
anomaly_type = /obj/effect/anomaly/pyro
@@ -276,3 +276,32 @@
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_BLUESPACE
)
departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_CARGO
/datum/design_techweb/anomaly_neutralizer
name = "Anomaly Neutralizer"
desc = "An advanced tool capable of instantly neutralizing anomalies, designed to capture the fleeting aberrations created by the engine."
id = "anomaly_neutralizer"
build_type = PROTOLATHE
materials = list(MAT_STEEL = SHEET_MATERIAL_AMOUNT, MAT_GOLD = SHEET_MATERIAL_AMOUNT, MAT_PHORON = SHEET_MATERIAL_AMOUNT * 2.5, MAT_URANIUM = SHEET_MATERIAL_AMOUNT)
build_path = /obj/item/anomaly_neutralizer
category = list(
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SCIENCE
)
departmental_flags = DEPARTMENT_BITFLAG_SCIENCE
/datum/design_techweb/reactive_armour
name = "Reactive Armor Shell"
desc = "An experimental suit of armour capable of utilizing an implanted anomaly core to protect the user."
id = "reactive_armour"
build_type = PROTOLATHE
materials = list(
MAT_STEEL = SHEET_MATERIAL_AMOUNT*5,
MAT_URANIUM = SHEET_MATERIAL_AMOUNT*4,
MAT_DIAMOND = SHEET_MATERIAL_AMOUNT*2.5,
MAT_SILVER = SHEET_MATERIAL_AMOUNT*2.5,
MAT_GOLD = SHEET_MATERIAL_AMOUNT*2.5
)
build_path = /obj/item/clothing/suit/armor/reactive_armor_shell
category = list(
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SCIENCE
)
@@ -108,9 +108,9 @@
"xenoarch_multitool",
"excavationdrill",
"ano_scanner",
// "anomaly_refinery",
// "anomaly_neutralizer",
// "reactive_armour",
//"anomaly_refinery",
"anomaly_neutralizer",
"reactive_armour",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS)
announce_channels = list(CHANNEL_SCIENCE)