[MIRROR] Dimensional Anomaly [MDB IGNORE] (#15974)

* Dimensional Anomaly (#69512)

About The Pull Request

Everyone has been asking: "When will there be an anomaly like the bioscrambler, but for the space station? Please, we need more things which replace objects with different objects from the same typepath."
Well I made it and it looked like ass because non-tiling floor and walls look terrible, so then I made this instead.
Dimensional.mp4

The "dimensional anomaly" shifts matter into a parallel dimension where objects are made out of something else.
Like the Bioscrambler anomaly, it does not expire on its own and only leaves when someone signals it or uses an anomaly remover.
When it spawns it picks a "theme" and converts terrain around it until it covers a 7x7 square, then it teleports somewhere else and picks a new theme.

A lot of these themes are relatively benign like "meat", "fancy carpet", or "gold". Some of them are kind of annoying like "icebox" because it creates floor which slows you down, or "clown" because bananium is intentionally annoying. Some of them are actively dangerous, mostly "uranium" and "plasma".
The main problem this will usually cause for crewmembers is decreasing area security. When it replaces doors it replaces them with ones which don't have any access control, and it will also replace RWalls with normal and much more vulnerable walls which will make breaking and entering significantly easier until someone has taken the time to fix the damage. But also sometimes it will irradiate them, you never know.

The fact that sometimes the changes are benign (or provide uncommon materials) and might be happening in places you don't care about access to might encourage people to push their luck and leave it alone until it starts turning the captain's office into a bamboo room or repainting medbay a fetching shade of flammable purple, which I would consider a success.
Armour.mp4

If you successfully harvest the anomaly core you can place it into the reactive armour to get Reactive Barricade Armour, which shifts your dimension when you take damage and attempts to place some randomised (not terribly durable) objects between you and hopefully your attacker (it really just picks up to four random unoccupied tiles next to you). If you're EMPed then the changes it make to the environment will often be as unpleasant for you as they are for a pursuer, and significantly more likely to harm both of you rather than just provide obstacles.

Other changes:
I split anomalies out into their own dmi file, seems to be all the rage lately.
I moved the anomaly placing code into a datum instead of the event because I wanted to reuse it but if you have a better idea about where I could have put it let me know.
This also fixes a bug where the material spreader component wasn't working when I applied plasma materials to something, the extra whitespace was parsing as another argument for some reason and meant it would runtime.
Supermatter delamination was still pointing to Delimber anomalies instead of Bioscrambler.

* Dimensional Anomaly

* Fixes the upstream merge skew

Co-authored-by: Jacquerel <hnevard@gmail.com>
Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com>
This commit is contained in:
SkyratBot
2022-09-05 23:59:34 +02:00
committed by GitHub
parent 1c511ec230
commit a4bfe65cb1
21 changed files with 816 additions and 46 deletions
+1
View File
@@ -52,6 +52,7 @@
#define BIOSCRAMBLER_ANOMALY "bioscrambler_anomaly"
#define HALLUCINATION_ANOMALY "hallucination_anomaly"
#define VORTEX_ANOMALY "vortex_anomaly"
#define DIMENSIONAL_ANOMALY "dimensional_anomaly"
#define SUPERMATTER_COUNTDOWN_TIME 30 SECONDS
+94 -8
View File
@@ -6,7 +6,8 @@
/obj/effect/anomaly
name = "anomaly"
desc = "A mysterious anomaly, seen commonly only in the region of space that the station orbits..."
icon_state = "bhole3"
icon = 'icons/effects/anomalies.dmi'
icon_state = "vortex"
density = FALSE
anchored = TRUE
light_range = 3
@@ -24,6 +25,8 @@
var/drops_core = TRUE
///Do we keep on living forever?
var/immortal = FALSE
///Do we stay in one place?
var/immobile = FALSE
/obj/effect/anomaly/Initialize(mapload, new_lifespan, drops_core = TRUE)
. = ..()
@@ -70,7 +73,7 @@
return ..()
/obj/effect/anomaly/proc/anomalyEffect(delta_time)
if(DT_PROB(ANOMALY_MOVECHANCE, delta_time))
if(!immobile && DT_PROB(ANOMALY_MOVECHANCE, delta_time))
step(src,pick(GLOB.alldirs))
/obj/effect/anomaly/proc/detonate()
@@ -90,7 +93,6 @@
qdel(src)
/obj/effect/anomaly/attackby(obj/item/weapon, mob/user, params)
if(weapon.tool_behaviour == TOOL_ANALYZER)
to_chat(user, span_notice("Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code]."))
@@ -110,6 +112,7 @@
/obj/effect/anomaly/grav
name = "gravitational anomaly"
icon = 'icons/effects/effects.dmi'
icon_state = "shield2"
density = FALSE
aSignal = /obj/item/assembly/signaler/anomaly/grav
@@ -197,7 +200,7 @@
/obj/effect/anomaly/flux
name = "flux wave anomaly"
icon_state = "electricity2"
icon_state = "flux"
density = TRUE
aSignal = /obj/item/assembly/signaler/anomaly/flux
var/canshock = FALSE
@@ -320,7 +323,7 @@
/obj/effect/anomaly/pyro
name = "pyroclastic anomaly"
icon_state = "mustard"
icon_state = "pyroclastic"
var/ticks = 0
/// How many seconds between each gas release
var/releasedelay = 10
@@ -366,7 +369,7 @@
/obj/effect/anomaly/bhole
name = "vortex anomaly"
icon_state = "bhole3"
icon_state = "vortex"
desc = "That's a nice station you have there. It'd be a shame if something happened to it."
aSignal = /obj/item/assembly/signaler/anomaly/vortex
@@ -430,7 +433,7 @@
/obj/effect/anomaly/bioscrambler
name = "bioscrambler anomaly"
icon_state = "bioscrambler_anomaly"
icon_state = "bioscrambler"
aSignal = /obj/item/assembly/signaler/anomaly/bioscrambler
immortal = TRUE
/// Cooldown for every anomaly pulse
@@ -502,7 +505,7 @@
/obj/effect/anomaly/hallucination
name = "hallucination anomaly"
icon_state = "hallucination_anomaly"
icon_state = "hallucination"
aSignal = /obj/item/assembly/signaler/anomaly/hallucination
/// Time passed since the last effect, increased by delta_time of the SSobj
var/ticks = 0
@@ -546,4 +549,87 @@
)
to_chat(near, span_warning(pick(messages)))
/////////////////////
/obj/effect/anomaly/dimensional
name = "dimensional anomaly"
icon_state = "dimensional"
aSignal = /obj/item/assembly/signaler/anomaly/dimensional
immortal = TRUE
immobile = TRUE
/// Range of effect, if left alone anomaly will convert a 2(range)+1 squared area.
var/range = 3
/// List of turfs this anomaly will try to transform before relocating
var/list/turf/target_turfs = new()
/// Current anomaly 'theme', dictates what tiles to create.
var/datum/dimension_theme/theme
/// Effect displaying on the anomaly to represent the theme.
var/mutable_appearance/theme_icon
/obj/effect/anomaly/dimensional/Initialize(mapload, new_lifespan, drops_core)
. = ..()
overlays += mutable_appearance('icons/effects/effects.dmi', "dimensional_overlay")
animate(src, transform = matrix()*0.85, time = 3, loop = -1)
animate(transform = matrix(), time = 3, loop = -1)
/obj/effect/anomaly/dimensional/anomalyEffect(delta_time)
. = ..()
transmute_area()
/**
* Transforms a turf in our prepared area.
*/
/obj/effect/anomaly/dimensional/proc/transmute_area()
if (!theme)
prepare_area()
if (!target_turfs.len)
relocate()
return
var/turf/affected_turf = target_turfs[1]
new /obj/effect/temp_visual/transmute_tile_flash(affected_turf)
theme.apply_theme(affected_turf)
target_turfs.Remove(affected_turf)
/**
* Prepare a new area for transformation into a new theme.
*/
/obj/effect/anomaly/dimensional/proc/prepare_area()
var/datum/dimension_theme/themes = new()
theme = themes.get_random_theme()
apply_theme_icon()
target_turfs = new()
var/list/turfs = spiral_range_turfs(range, src)
for (var/turf/turf in turfs)
if (theme.can_convert(turf))
target_turfs.Add(turf)
/**
* Applies an overlay icon based on the current theme.
*/
/obj/effect/anomaly/dimensional/proc/apply_theme_icon()
overlays -= theme_icon
theme_icon = mutable_appearance(theme.icon, theme.icon_state, FLOAT_LAYER - 1, appearance_flags = appearance_flags | RESET_TRANSFORM)
theme_icon.blend_mode = BLEND_INSET_OVERLAY
overlays += theme_icon
/**
* Moves the anomaly somewhere else and announces it.
*/
/obj/effect/anomaly/dimensional/proc/relocate()
var/datum/anomaly_placer/placer = new()
var/area/new_area = placer.findValidArea()
var/turf/new_turf = placer.findValidTurf(new_area)
priority_announce("Dimensional instability relocated. Expected location: [new_area.name].", "Anomaly Alert")
src.forceMove(new_turf)
prepare_area()
/obj/effect/temp_visual/transmute_tile_flash
icon = 'icons/effects/effects.dmi'
icon_state = "shield-flash"
duration = 3
#undef ANOMALY_MOVECHANCE
@@ -0,0 +1,328 @@
/**
* Datum which describes a theme and replaces turfs and objects in specified locations to match that theme
*/
/datum/dimension_theme
/// An icon to display to represent the theme
var/icon/icon
/// Icon state to use to represent the theme
var/icon_state
/// Typepath of custom material to use for objects.
var/datum/material/material
/// Sound to play when transforming a tile
var/sound = 'sound/magic/blind.ogg'
/// Weighted list of turfs to replace the floor with.
var/list/replace_floors = list(/turf/open/floor/material = 1)
/// Typepath of turf to replace walls with.
var/turf/replace_walls = /turf/closed/wall/material
/// List of weighted lists for object replacement. Key is an original typepath, value is a weighted list of typepaths to replace it with.
var/list/replace_objs = list(\
/obj/structure/chair = list(/obj/structure/chair/greyscale = 1), \
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/material = 1, /obj/machinery/door/airlock/material/glass = 1), \
/obj/structure/table = list(/obj/structure/table/greyscale = 1), \
/obj/structure/toilet = list(/obj/structure/toilet/greyscale = 1),)
/// Typepath of full-size windows which will replace existing ones
/// These need to be separate from replace_objs because we don't want to replace dir windows with full ones and they share typepath
var/obj/structure/window/replace_window
/// Colour to recolour windows with, replaced by material colour if material was specified.
var/window_colour = "#ffffff"
/datum/dimension_theme/New()
if (material)
var/datum/material/using_mat = GET_MATERIAL_REF(material)
window_colour = using_mat.greyscale_colors
/**
* Returns a subtype of dimensional theme.
*/
/datum/dimension_theme/proc/get_random_theme()
var/subtype = pick(subtypesof(/datum/dimension_theme))
return new subtype()
/**
* Applies themed transformation to the provided turf.
*
* Arguments
* * affected_turf - Turf to transform.
*/
/datum/dimension_theme/proc/apply_theme(turf/affected_turf)
if (!replace_turf(affected_turf))
return
playsound(affected_turf, sound, 100, TRUE)
for (var/obj/object in affected_turf)
replace_object(object)
if (material)
apply_materials(affected_turf)
/**
* Returns true if you actually can transform the provided turf.
*
* Arguments
* * affected_turf - Turf to transform.
*/
/datum/dimension_theme/proc/can_convert(turf/affected_turf)
if (isspaceturf(affected_turf))
return FALSE
if (isfloorturf(affected_turf))
if (isindestructiblefloor(affected_turf))
return FALSE
if (affected_turf.holodeck_compatible)
return FALSE
return replace_floors.len > 0
if (iswallturf(affected_turf))
if (isindestructiblewall(affected_turf))
return FALSE
return TRUE
return FALSE
/**
* Replaces the provided turf with a different one.
*
* Arguments
* * affected_turf - Turf to transform.
*/
/datum/dimension_theme/proc/replace_turf(turf/affected_turf)
if (isfloorturf(affected_turf))
if (isindestructiblefloor(affected_turf))
return FALSE
if (affected_turf.holodeck_compatible)
return FALSE
return transform_floor(affected_turf)
if (!iswallturf(affected_turf))
return FALSE
if (isindestructiblewall(affected_turf))
return FALSE
affected_turf.ChangeTurf(replace_walls)
return TRUE
/**
* Replaces the provided floor turf with a different one.
*
* Arguments
* * affected_floor - Floor turf to transform.
*/
/datum/dimension_theme/proc/transform_floor(turf/open/floor/affected_floor)
if (replace_floors.len == 0)
return FALSE
affected_floor.ChangeTurf(pick_weight(replace_floors), flags = CHANGETURF_INHERIT_AIR)
return TRUE
/**
* Replaces the provided object with a different one.
*
* Arguments
* * object - Object to replace.
*/
/datum/dimension_theme/proc/replace_object(obj/object)
if (istype(object, /obj/structure/window))
transform_window(object)
return
var/replace_path = get_replacement_object_typepath(object)
if (!replace_path)
return
var/obj/new_object = new replace_path(object.loc)
new_object.setDir(object.dir)
qdel(object)
/**
* Returns the typepath of an object to replace the provided object.
*
* Arguments
* * object - Object to transform.
*/
/datum/dimension_theme/proc/get_replacement_object_typepath(obj/object)
for (var/type in replace_objs)
if (istype(object, type))
return pick_weight(replace_objs[type])
return
/**
* Replaces a window with a different window and recolours it.
* This needs its own function because we only want to replace full tile windows.
*
* Arguments
* * object - Object to transform.
*/
/datum/dimension_theme/proc/transform_window(obj/structure/window/window)
if (!window.fulltile)
return
if (!replace_window)
window.add_atom_colour(window_colour, FIXED_COLOUR_PRIORITY)
return
var/obj/structure/window/new_window = new replace_window(window.loc)
new_window.add_atom_colour(window_colour, FIXED_COLOUR_PRIORITY)
qdel(window)
#define PERMITTED_MATERIAL_REPLACE_TYPES list(\
/obj/structure/chair, \
/obj/machinery/door/airlock, \
/obj/structure/table, \
/obj/structure/toilet, \
/obj/structure/window, \
/obj/structure/sink,)
/**
* Returns true if the provided object can have its material modified.
*
* Arguments
* * object - Object to transform.
*/
/datum/dimension_theme/proc/permit_replace_material(obj/object)
for (var/type in PERMITTED_MATERIAL_REPLACE_TYPES)
if (istype(object, type))
return TRUE
return FALSE
/**
* Applies a new custom material to the contents of a provided turf.
*
* Arguments
* * affected_turf - Turf to transform.
*/
/datum/dimension_theme/proc/apply_materials(turf/affected_turf)
var/list/custom_materials = list(GET_MATERIAL_REF(material) = MINERAL_MATERIAL_AMOUNT)
if (istype(affected_turf, /turf/open/floor/material) || istype(affected_turf, /turf/closed/wall/material))
affected_turf.set_custom_materials(custom_materials)
for (var/obj/thing in affected_turf)
if (!permit_replace_material(thing))
continue
thing.set_custom_materials(custom_materials)
#undef PERMITTED_MATERIAL_REPLACE_TYPES
/////////////////////
/datum/dimension_theme/gold
icon = 'icons/obj/stack_objects.dmi'
icon_state = "sheet-gold_2"
material = /datum/material/gold
/datum/dimension_theme/plasma
icon = 'icons/obj/clothing/masks.dmi'
icon_state = "gas_alt"
material = /datum/material/plasma
/datum/dimension_theme/clown
icon = 'icons/obj/clothing/masks.dmi'
icon_state = "clown"
material = /datum/material/bananium
sound = 'sound/items/bikehorn.ogg'
/datum/dimension_theme/radioactive
icon = 'icons/obj/ore.dmi'
icon_state = "Uranium ore"
material = /datum/material/uranium
sound = 'sound/items/welder.ogg'
/datum/dimension_theme/meat
icon = 'icons/obj/food/meat.dmi'
icon_state = "meat"
material = /datum/material/meat
sound = 'sound/items/eatfood.ogg'
/datum/dimension_theme/pizza
icon = 'icons/obj/food/pizza.dmi'
icon_state = "pizzamargherita"
material = /datum/material/pizza
sound = 'sound/items/eatfood.ogg'
/datum/dimension_theme/natural
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state = "map_flower"
window_colour = "#00f7ff"
replace_floors = list(/turf/open/floor/grass = 1)
replace_walls = /turf/closed/wall/mineral/wood/nonmetal
replace_objs = list(\
/obj/structure/chair = list(/obj/structure/chair/wood = 3, /obj/structure/chair/wood/wings = 1), \
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1), \
/obj/structure/table = list(/obj/structure/table/wood = 5, /obj/structure/table/wood/fancy = 1),)
/datum/dimension_theme/bamboo
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state = "bamboo"
replace_floors = list(/turf/open/floor/bamboo = 1)
replace_walls = /turf/closed/wall/mineral/bamboo
replace_window = /obj/structure/window/paperframe
replace_objs = list(\
/obj/structure/chair = list(/obj/structure/chair/stool/bamboo = 1), \
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1), \
/obj/structure/table = list(/obj/structure/table/wood = 1),)
/datum/dimension_theme/icebox
icon = 'icons/obj/clothing/shoes.dmi'
icon_state = "iceboots"
window_colour = "#00f7ff"
material = /datum/material/snow
replace_floors = list(/turf/open/floor/fake_snow = 10, /turf/open/floor/fakeice/slippery = 1)
replace_walls = /turf/closed/wall/mineral/snow
/datum/dimension_theme/lavaland
icon = 'icons/obj/stack_objects.dmi'
icon_state = "goliath_hide"
window_colour = "#860000"
replace_floors = list(/turf/open/floor/fakebasalt = 5, /turf/open/floor/fakepit = 1)
replace_walls = /turf/closed/wall/mineral/cult
replace_objs = list(\
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/external/glass/ruin = 1))
/datum/dimension_theme/space
icon = 'icons/effects/effects.dmi'
icon_state = "blessed"
window_colour = "#000000"
material = /datum/material/glass
replace_floors = list(/turf/open/floor/fakespace = 1)
replace_walls = /turf/closed/wall/rock/porous
replace_objs = list(/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/external/glass/ruin = 1))
/datum/dimension_theme/glass
icon = 'icons/obj/shards.dmi'
icon_state = "small"
material = /datum/material/glass
replace_floors = list(/turf/open/floor/glass = 1)
sound = SFX_SHATTER
/datum/dimension_theme/fancy
icon = 'icons/obj/clothing/hats.dmi'
icon_state = "fancycrown"
replace_walls = /turf/closed/wall/mineral/wood/nonmetal
#define FANCY_CARPETS list(\
/turf/open/floor/eighties, \
/turf/open/floor/eighties/red, \
/turf/open/floor/carpet/lone/star, \
/turf/open/floor/carpet/black, \
/turf/open/floor/carpet/blue, \
/turf/open/floor/carpet/cyan, \
/turf/open/floor/carpet/green, \
/turf/open/floor/carpet/orange, \
/turf/open/floor/carpet/purple, \
/turf/open/floor/carpet/red, \
/turf/open/floor/carpet/royalblack, \
/turf/open/floor/carpet/royalblue,)
/datum/dimension_theme/fancy/New()
replace_floors = list(pick(FANCY_CARPETS) = 1)
replace_objs = list(\
/obj/structure/chair = list(/obj/structure/chair/comfy = 1), \
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1), \
/obj/structure/table/wood = list(pick(subtypesof(/obj/structure/table/wood/fancy)) = 1),)
#undef FANCY_CARPETS
/datum/dimension_theme/disco
icon = 'icons/obj/lighting.dmi'
icon_state = "lbulb"
material = /datum/material/glass
replace_floors = list(/turf/open/floor/light = 1)
/datum/dimension_theme/disco/transform_floor(turf/open/floor/affected_floor)
. = ..()
if (!.)
return
var/turf/open/floor/light/disco_floor = affected_floor
disco_floor.currentcolor = pick(disco_floor.coloredlights)
disco_floor.update_appearance()
+3
View File
@@ -331,6 +331,9 @@
///How much damage the trap deals when triggered.
var/trap_damage = 20
/obj/item/restraints/legcuffs/beartrap/prearmed
armed = TRUE
/obj/item/restraints/legcuffs/beartrap/Initialize(mapload)
. = ..()
update_appearance()
@@ -776,6 +776,13 @@
icon_state = "ice_turf-0"
base_icon_state = "ice_turf-0"
/turf/open/floor/fakeice/slippery
desc = "Somehow, it is not melting under these conditions. Must be some very thick ice. Just as slippery too."
/turf/open/floor/fakeice/slippery/Initialize(mapload)
. = ..()
MakeSlippery(TURF_WET_PERMAFROST, INFINITY, 0, INFINITY, TRUE)
/turf/open/floor/fakespace
icon = 'icons/turf/space.dmi'
icon_state = "0"
+10
View File
@@ -1434,6 +1434,16 @@
crate_name = "raw bioscrambler anomaly"
crate_type = /obj/structure/closet/crate/secure/science
/datum/supply_pack/science/raw_dimensional_anomaly
name = "Raw Dimensional Anomaly"
desc = "The raw core of a dimensional anomaly, ready to be implosion-compressed into a powerful artifact."
cost = CARGO_CRATE_VALUE * 10
access = ACCESS_ORDNANCE
access_view = ACCESS_ORDNANCE
contains = list(/obj/item/raw_anomaly_core/dimensional)
crate_name = "raw dimensional anomaly"
crate_type = /obj/structure/closet/crate/secure/science
/datum/supply_pack/science/robotics
name = "Robotics Assembly Crate"
@@ -13,6 +13,7 @@
/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,
)
if(istype(weapon, /obj/item/assembly/signaler/anomaly))
@@ -454,3 +455,66 @@
qdel(picked_user_part)
nearby.update_body(TRUE)
balloon_alert(nearby, "something has changed about you")
// 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", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
playsound(get_turf(owner),'sound/magic/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
/**
* Returns a list of all atoms around the source which can be moved away from it.
*
* Arguments
* * source - Thing to try to move things away from.
*/
/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
/**
* Pushes something one tile away from the source.
*
* Arguments
* * victim - Thing being moved.
* * source - Thing to move it away from.
*/
/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.safe_throw_at(throwtarget, 1, 1, source, force = MOVE_FORCE_EXTREMELY_STRONG)
/obj/item/clothing/suit/armor/reactive/barricade/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(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
@@ -0,0 +1,190 @@
#define MAX_BARRIERS 4
#define MIN_BARRIERS 2
/***
* Datum describing a 'theme' which transforms a 3x3 area's turfs when applied.
* It also creates a number of themed barriers in that area.
*/
/datum/armour_dimensional_theme
var/datum/material/material
var/turf/replace_floor = /turf/open/floor/material
var/turf/replace_wall = /turf/closed/wall/material
var/obj/barricade = /obj/structure/table/greyscale
var/barricade_anchored = TRUE
/**
* Applies a random dimensional theme effect centered around a provided point.
* This will transform floors and walls, as well as creating some themed barriers in that area.
*
* Arguments
* * source - The central turf to apply outwards from.
* * dangerous - If true this will pick a 'dangerous' theme.
*/
/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)
/**
* Transforms turfs around a source point into a new themed material.
* Also place some barriers in unoccupied areas.
*
* Arguments
* * source - The central turf to apply outwards from.
*/
/datum/armour_dimensional_theme/proc/apply(turf/source)
var/obj/effect/particle_effect/fluid/smoke/poof = new(source)
poof.lifetime = 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)
/**
* Returns a list of turfs which it is valid to apply changes to.
*
* Arguments
* * source - The central turf to check outwards from.
*/
/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 (isspaceturf(check_turf))
target_area -= check_turf
continue
if (isindestructiblefloor(check_turf))
target_area -= check_turf
continue
if (isindestructiblewall(check_turf))
target_area -= check_turf
continue
if (check_turf.holodeck_compatible)
target_area -= check_turf
continue
return target_area
/**
* Changes a turf into a different turf
*
* Arguments
* * to_convert - Turf to convert.
*/
/datum/armour_dimensional_theme/proc/convert_turf(turf/to_convert)
if (isfloorturf(to_convert))
to_convert.ChangeTurf(replace_floor, flags = CHANGETURF_INHERIT_AIR)
else if (iswallturf(to_convert))
to_convert.ChangeTurf(replace_wall)
if (material)
var/list/custom_materials = list(GET_MATERIAL_REF(material) = MINERAL_MATERIAL_AMOUNT)
to_convert.set_custom_materials(custom_materials)
/**
* Places a random amount of themed barriers in unoccupied spaces adjacent to a source tile.
*
* Arguments
* * source - Central tile to place barriers around.
* * target_area - Tiles which have had their materials converted, needs further culling to remove dense tiles.
*/
/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.is_blocked_turf(exclude_mobs = TRUE))
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) = MINERAL_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--
/**
* Places a barrier at a specified turf.
*
* Arguments
* * source - Tile to place barrier upon.
* * materials - Custom material data to apply to the barrier.
*/
/datum/armour_dimensional_theme/proc/place_barrier(turf/source, list/materials)
var/obj/placed_barricade = new barricade(source)
if (barricade_anchored)
placed_barricade.anchored = TRUE
if (materials.len)
placed_barricade.set_custom_materials(materials)
/// Themes which will largely be probably useful for the user
/datum/armour_dimensional_theme/safe
/datum/armour_dimensional_theme/safe/natural
replace_wall = /turf/closed/wall/mineral/wood/nonmetal
replace_floor = /turf/open/floor/grass
barricade = /obj/structure/barricade/wooden
/datum/armour_dimensional_theme/safe/snow
material = /datum/material/snow
replace_wall = /turf/closed/wall/mineral/snow
replace_floor = /turf/open/floor/fake_snow
barricade = /obj/structure/statue/snow/snowman
/datum/armour_dimensional_theme/safe/space
material = /datum/material/glass
replace_wall = /turf/closed/wall/rock/porous
replace_floor = /turf/open/floor/fakespace
barricade = /obj/machinery/door/airlock/external/glass/ruin
/datum/armour_dimensional_theme/safe/glass
material = /datum/material/glass
replace_floor = /turf/open/floor/glass
/datum/armour_dimensional_theme/safe/secure
replace_wall = /turf/closed/wall/mineral/plastitanium/nodiagonal
replace_floor = /turf/open/floor/mineral/plastitanium
barricade = /obj/structure/holosign/barrier
/datum/armour_dimensional_theme/safe/meat
material = /datum/material/meat
/// Dangerous themes can potentially impede the user as much as people pursuing them
/datum/armour_dimensional_theme/dangerous
/datum/armour_dimensional_theme/dangerous/clown
material = /datum/material/bananium
barricade = /obj/item/restraints/legcuffs/beartrap/prearmed
barricade_anchored = FALSE
/datum/armour_dimensional_theme/dangerous/radioactive
material = /datum/material/uranium
barricade = /obj/structure/statue/uranium/nuke
/datum/armour_dimensional_theme/dangerous/plasma
material = /datum/material/plasma
barricade = /obj/structure/statue/plasma/xeno
/datum/armour_dimensional_theme/dangerous/ice
material = /datum/material/snow
replace_wall = /turf/closed/wall/mineral/snow
replace_floor = /turf/open/floor/fakeice/slippery
barricade = /obj/structure/statue/snow/snowlegion
/datum/armour_dimensional_theme/dangerous/lavaland
replace_floor = /turf/open/floor/fakebasalt
replace_wall = /turf/closed/wall/mineral/cult
/// Replace the barrier spawning to instead create weak lava.
/datum/armour_dimensional_theme/dangerous/lavaland/place_barrier(turf/source, list/materials)
source.ChangeTurf(/turf/open/lava/smooth/weak, flags = CHANGETURF_INHERIT_AIR)
#undef MAX_BARRIERS
#undef MIN_BARRIERS
+2 -2
View File
@@ -172,5 +172,5 @@
/obj/item/wizard_armour_charge
name = "battlemage shield charges"
desc = "A powerful rune that will increase the number of hits a suit of battlemage armour can take before failing.."
icon = 'icons/effects/effects.dmi'
icon_state = "electricity2"
icon = 'icons/effects/anomalies.dmi'
icon_state = "flux"
+5 -33
View File
@@ -10,48 +10,20 @@
/datum/round_event/anomaly
var/area/impact_area
var/datum/anomaly_placer/placer = new()
var/obj/effect/anomaly/anomaly_path = /obj/effect/anomaly/flux
announce_when = 1
/datum/round_event/anomaly/proc/findEventArea()
var/static/list/allowed_areas
if(!allowed_areas)
//Places that shouldn't explode
var/static/list/safe_area_types = typecacheof(list(
/area/station/ai_monitored/turret_protected/ai,
/area/station/ai_monitored/turret_protected/ai_upload,
/area/station/engineering,
/area/station/solars,
/area/station/holodeck,
/area/shuttle,
/area/station/maintenance,
/area/icemoon,
))
//Subtypes from the above that actually should explode.
var/static/list/unsafe_area_subtypes = typecacheof(list(/area/station/engineering/break_room))
allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes
var/list/possible_areas = typecache_filter_list(GLOB.sortedAreas,allowed_areas)
if (length(possible_areas))
return pick(possible_areas)
/datum/round_event/anomaly/setup()
impact_area = findEventArea()
if(!impact_area)
CRASH("No valid areas for anomaly found.")
var/list/turf_test = (get_area_turfs(impact_area) - typesof(/turf/open/lava))
if(!turf_test.len)
CRASH("Anomaly : No valid turfs found for [impact_area] - [impact_area.type]")
impact_area = placer.findValidArea()
/datum/round_event/anomaly/announce(fake)
priority_announce("Localized energetic flux wave detected on long range scanners. Expected location of impact: [impact_area.name].", "Anomaly Alert")
/datum/round_event/anomaly/start()
var/turf/T = pick((get_area_turfs(impact_area) - typesof(/turf/open/lava)))
var/turf/anomaly_turf = placer.findValidTurf(impact_area)
var/newAnomaly
if(T)
newAnomaly = new anomaly_path(T)
if(anomaly_turf)
newAnomaly = new anomaly_path(anomaly_turf)
if (newAnomaly)
announce_to_ghosts(newAnomaly)
@@ -0,0 +1,16 @@
/datum/round_event_control/anomaly/anomaly_dimensional
name = "Anomaly: Dimensional"
typepath = /datum/round_event/anomaly/anomaly_dimensional
min_players = 10
max_occurrences = 5
weight = 20
description = "This anomaly replaces the materials of the surrounding area."
/datum/round_event/anomaly/anomaly_dimensional
start_when = 10
announce_when = 3
anomaly_path = /obj/effect/anomaly/dimensional
/datum/round_event/anomaly/anomaly_dimensional/announce(fake)
priority_announce("Localized dimensional instability detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert")
+75
View File
@@ -0,0 +1,75 @@
/datum/anomaly_placer
var/static/list/allowed_areas
/**
* Returns an area which is safe to place an anomaly inside.
*/
/datum/anomaly_placer/proc/findValidArea()
if(!allowed_areas)
generateAllowedAreas()
var/list/possible_areas = typecache_filter_list(GLOB.sortedAreas,allowed_areas)
if (!length(possible_areas))
CRASH("No valid areas for anomaly found.")
var/area/landing_area = pick(possible_areas)
var/list/turf_test = get_area_turfs(landing_area)
if(!turf_test.len)
CRASH("Anomaly : No valid turfs found for [landing_area] - [landing_area.type]")
return landing_area
/**
* Returns a turf which is safe to place an anomaly on.
*
* Arguments
* * target_area - Area to return a turf from.
*/
/datum/anomaly_placer/proc/findValidTurf(area/target_area)
var/list/valid_turfs = list()
for (var/turf/try_turf as anything in get_area_turfs(target_area))
if (!is_valid_destination(try_turf))
continue
valid_turfs += try_turf
if (!valid_turfs.len)
CRASH("Dimensional anomaly attempted to reach invalid location [target_area].")
return pick(valid_turfs)
/**
* Returns true if the provided turf is valid to place an anomaly on.
*
* Arguments
* * tested - Turf to try landing on.
*/
/datum/anomaly_placer/proc/is_valid_destination(turf/tested)
if (isspaceturf(tested))
return FALSE
if (tested.is_blocked_turf(exclude_mobs = TRUE))
return FALSE
if (islava(tested))
return FALSE
if (ischasm(tested))
return FALSE
return TRUE
/**
* Populates the allowed areas list.
*/
/datum/anomaly_placer/proc/generateAllowedAreas()
//Places that shouldn't explode
var/static/list/safe_area_types = typecacheof(list(
/area/station/ai_monitored/turret_protected/ai,
/area/station/ai_monitored/turret_protected/ai_upload,
/area/station/engineering,
/area/station/solars,
/area/station/holodeck,
/area/shuttle,
/area/station/maintenance,
/area/icemoon,
))
//Subtypes from the above that actually should explode.
var/static/list/unsafe_area_subtypes = typecacheof(list(/area/station/engineering/break_room))
allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes
@@ -96,8 +96,8 @@
//jaunter tunnel
/obj/effect/portal/jaunt_tunnel
name = "jaunt tunnel"
icon = 'icons/effects/effects.dmi'
icon_state = "bhole3"
icon = 'icons/effects/anomalies.dmi'
icon_state = "vortex"
desc = "A stable hole in the universe made by a wormhole jaunter. Turbulent doesn't even begin to describe how rough passage through one of these is, but at least it will always get you somewhere near a beacon."
mech_sized = TRUE //save your ripley
innate_accuracy_penalty = 6
@@ -415,6 +415,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
new /obj/effect/anomaly/bhole(local_turf, 20, FALSE)
if(BIOSCRAMBLER_ANOMALY)
new /obj/effect/anomaly/bioscrambler(local_turf, null, FALSE)
if(DIMENSIONAL_ANOMALY)
new /obj/effect/anomaly/dimensional(local_turf, null, FALSE)
/obj/machinery/proc/supermatter_zap(atom/zapstart = src, range = 5, zap_str = 4000, zap_flags = ZAP_SUPERMATTER_FLAGS, list/targets_hit = list(), zap_cutoff = 1500, power_level = 0, zap_icon = DEFAULT_ZAP_ICON_STATE, color = null)
if(QDELETED(zapstart))
@@ -45,7 +45,7 @@
/// Spawns anomalies all over the station. Half instantly, the other half over time.
/datum/sm_delam/proc/effect_anomaly(obj/machinery/power/supermatter_crystal/sm)
var/anomalies = 10
var/list/anomaly_types = list(GRAVITATIONAL_ANOMALY = 55, HALLUCINATION_ANOMALY = 45, DELIMBER_ANOMALY = 35, FLUX_ANOMALY = 25, PYRO_ANOMALY = 5, VORTEX_ANOMALY = 1)
var/list/anomaly_types = list(GRAVITATIONAL_ANOMALY = 55, HALLUCINATION_ANOMALY = 45, DIMENSIONAL_ANOMALY = 35, BIOSCRAMBLER_ANOMALY = 35, FLUX_ANOMALY = 25, PYRO_ANOMALY = 5, VORTEX_ANOMALY = 1)
var/list/anomaly_places = GLOB.generic_event_spawns
// Spawns this many anomalies instantly. Spawns the rest with callbacks.
@@ -73,3 +73,9 @@
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/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
@@ -62,6 +62,12 @@
anomaly_type = /obj/item/assembly/signaler/anomaly/bioscrambler
icon_state = "rawcore_bioscrambler"
/obj/item/raw_anomaly_core/dimensional
name = "raw dimensional core"
desc = "The raw core of a dimensional anomaly, vibrating with infinite potential."
anomaly_type = /obj/item/assembly/signaler/anomaly/dimensional
icon_state = "rawcore_dimensional"
/obj/item/raw_anomaly_core/random/Initialize(mapload)
. = ..()
var/path = pick(subtypesof(/obj/item/raw_anomaly_core))
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 KiB

After

Width:  |  Height:  |  Size: 914 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 27 KiB

+4
View File
@@ -1525,6 +1525,7 @@
#include "code\game\objects\objs.dm"
#include "code\game\objects\structures.dm"
#include "code\game\objects\effects\anomalies.dm"
#include "code\game\objects\effects\anomaly_dimensional_themes.dm"
#include "code\game\objects\effects\blessing.dm"
#include "code\game\objects\effects\bump_teleporter.dm"
#include "code\game\objects\effects\contraband.dm"
@@ -2875,6 +2876,7 @@
#include "code\modules\clothing\suits\lasertag.dm"
#include "code\modules\clothing\suits\moth.dm"
#include "code\modules\clothing\suits\reactive_armour.dm"
#include "code\modules\clothing\suits\reactive_armour_dimensional_themes.dm"
#include "code\modules\clothing\suits\shirt.dm"
#include "code\modules\clothing\suits\straightjacket.dm"
#include "code\modules\clothing\suits\toggles.dm"
@@ -2929,9 +2931,11 @@
#include "code\modules\events\anomaly.dm"
#include "code\modules\events\anomaly_bioscrambler.dm"
#include "code\modules\events\anomaly_bluespace.dm"
#include "code\modules\events\anomaly_dimensional.dm"
#include "code\modules\events\anomaly_flux.dm"
#include "code\modules\events\anomaly_grav.dm"
#include "code\modules\events\anomaly_hallucination.dm"
#include "code\modules\events\anomaly_placer.dm"
#include "code\modules\events\anomaly_pyro.dm"
#include "code\modules\events\anomaly_vortex.dm"
#include "code\modules\events\aurora_caelus.dm"