mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-22 03:27:46 +01:00
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:
co-authored by
vorestation-ci[bot] <199609141+vorestation-ci[bot]@users.noreply.github.com>
parent
81acf7df5c
commit
d59ad9df0c
@@ -0,0 +1,121 @@
|
||||
/obj/effect/anomaly
|
||||
name = "anomaly"
|
||||
desc = "A mysterious anomaly, seen commonly only in the region of space that the station orbits..."
|
||||
icon = 'icons/effects/anomalies.dmi'
|
||||
icon_state = "vortex"
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
light_range = 3
|
||||
|
||||
var/obj/item/assembly/signaler/anomaly/anomaly_core = /obj/item/assembly/signaler/anomaly
|
||||
var/area/impact_area
|
||||
|
||||
var/lifespan = ANOMALY_COUNTDOWN_TIMER
|
||||
var/death_time
|
||||
|
||||
var/countdown_colour
|
||||
var/obj/effect/countdown/anomaly/countdown
|
||||
|
||||
var/immortal = FALSE
|
||||
var/move_chance = ANOMALY_MOVECHANCE
|
||||
|
||||
/obj/effect/anomaly/Initialize(mapload, new_lifespan, drops_core = TRUE)
|
||||
. = ..()
|
||||
|
||||
START_PROCESSING(SSobj, src)
|
||||
impact_area = get_area(src)
|
||||
|
||||
if(!impact_area)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
if(!drops_core)
|
||||
anomaly_core = null
|
||||
|
||||
if(anomaly_core)
|
||||
anomaly_core = new anomaly_core(src)
|
||||
anomaly_core.code = rand(1, 100)
|
||||
anomaly_core.anomaly_type = type
|
||||
|
||||
anomaly_core.set_frequency(sanitize_frequency(get_rand_frequency()))
|
||||
|
||||
if(new_lifespan)
|
||||
lifespan = new_lifespan
|
||||
death_time = world.time + lifespan
|
||||
|
||||
countdown = new(src)
|
||||
if(countdown_colour)
|
||||
countdown_colour = countdown_colour
|
||||
|
||||
if(immortal)
|
||||
return
|
||||
countdown.start()
|
||||
|
||||
/obj/effect/anomaly/process(seconds_per_tick)
|
||||
anomalyEffect(seconds_per_tick)
|
||||
if(death_time < world.time && !immortal)
|
||||
if(loc)
|
||||
detonate()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/anomaly/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(countdown)
|
||||
QDEL_NULL(anomaly_core)
|
||||
return ..()
|
||||
|
||||
/obj/effect/anomaly/proc/anomalyEffect(seconds_per_tick)
|
||||
if(prob(move_chance))
|
||||
move_anomaly()
|
||||
|
||||
/obj/effect/anomaly/proc/move_anomaly()
|
||||
step(src, pick(GLOB.alldirs))
|
||||
|
||||
/obj/effect/anomaly/proc/detonate()
|
||||
return
|
||||
|
||||
/obj/effect/anomaly/ex_act(strength)
|
||||
if(strength <= 1)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/effect/anomaly/proc/anomalyNeutralize()
|
||||
new /obj/effect/effect/smoke/bad(loc)
|
||||
if(!isnull(anomaly_core))
|
||||
anomaly_core.forceMove(get_turf(src))
|
||||
anomaly_core = null
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/anomaly/proc/stabilize(anchor = FALSE, has_core = TRUE)
|
||||
immortal = TRUE
|
||||
name = (has_core ? "stable " : "hollow ") + name
|
||||
if(!has_core)
|
||||
QDEL_NULL(anomaly_core)
|
||||
if(anchor)
|
||||
move_chance = 0
|
||||
|
||||
/obj/effect/anomaly/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/analyzer))
|
||||
if(anomaly_core)
|
||||
to_chat(user, span_notice("Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(anomaly_core.frequency)], code [anomaly_core.code]."))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/proc/generate_anomaly(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5, has_changed_lifespan = TRUE)
|
||||
var/turf/local_turf = pick(RANGE_TURFS(anomalyrange, anomalycenter))
|
||||
if(!local_turf)
|
||||
return
|
||||
switch(type)
|
||||
if(FLUX_ANOMALY)
|
||||
var/explosive = has_changed_lifespan ? FLUX_NO_EMP : FLUX_LIGHT_EMP
|
||||
new /obj/effect/anomaly/flux(local_turf, has_changed_lifespan ? rand(25 SECONDS, 35 SECONDS) : null, FALSE, explosive)
|
||||
if(GRAVITATIONAL_ANOMALY)
|
||||
new /obj/effect/anomaly/grav(local_turf, has_changed_lifespan ? rand(20 SECONDS, 30 SECONDS) : null, FALSE)
|
||||
if(PYRO_ANOMALY)
|
||||
new /obj/effect/anomaly/pyro(local_turf, has_changed_lifespan ? rand(15 SECONDS, 25 SECONDS) : null, FALSE)
|
||||
if(HALLUCINATION_ANOMALY)
|
||||
new /obj/effect/anomaly/hallucination/supermatter(local_turf, has_changed_lifespan ? rand(15 SECONDS, 25 SECONDS) : null, FALSE)
|
||||
if(BIOSCRAMBLER_ANOMALY)
|
||||
new /obj/effect/anomaly/bioscrambler/docile(local_turf, null, FALSE)
|
||||
if(DIMENSIONAL_ANOMALY)
|
||||
new /obj/effect/anomaly/dimensional(local_turf, null, FALSE)
|
||||
@@ -0,0 +1,89 @@
|
||||
/obj/effect/anomaly/bioscrambler
|
||||
name = "bioscrambler anomaly"
|
||||
icon_state = "bioscrambler"
|
||||
anomaly_core = /obj/item/assembly/signaler/anomaly/bioscrambler
|
||||
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
lifespan = ANOMALY_COUNTDOWN_TIMER * 2
|
||||
|
||||
/// Who are we moving towards?
|
||||
var/datum/weakref/pursuit_target
|
||||
/// Cooldown for every anomaly pulse
|
||||
COOLDOWN_DECLARE(pulse_cooldown)
|
||||
/// How many seconds between each anomaly pulse
|
||||
var/pulse_delay = 10 SECONDS
|
||||
/// Range of anomaly pulse
|
||||
var/range = 2
|
||||
|
||||
/obj/effect/anomaly/bioscrambler/Initialize(mapload, new_lifespan, drops_core)
|
||||
. = ..()
|
||||
pursuit_target = WEAKREF(find_nearest_target())
|
||||
|
||||
/obj/effect/anomaly/bioscrambler/anomalyEffect(seconds_per_tick)
|
||||
. = ..()
|
||||
if(!COOLDOWN_FINISHED(src, pulse_cooldown))
|
||||
return
|
||||
|
||||
new /obj/effect/temp_visual/circle_wave/bioscrambler(get_turf(src))
|
||||
playsound(src, 'sound/effects/cosmic_energy.ogg', vol = 50, vary = TRUE)
|
||||
COOLDOWN_START(src, pulse_cooldown, pulse_delay)
|
||||
for(var/mob/living/carbon/human/nearby in viewers(range, src))
|
||||
var/susceptibility = GetAnomalySusceptibility(nearby)
|
||||
if(prob(susceptibility * 100))
|
||||
randmutb(nearby)
|
||||
domutcheck(nearby, null)
|
||||
nearby.balloon_alert(nearby, "something has changed about you")
|
||||
|
||||
/obj/effect/anomaly/bioscrambler/move_anomaly()
|
||||
update_target()
|
||||
if(isnull(pursuit_target))
|
||||
return ..()
|
||||
var/turf/step_turf = get_step(src, get_dir(src, pursuit_target.resolve()))
|
||||
step_to(src, step_turf)
|
||||
|
||||
/obj/effect/anomaly/bioscrambler/proc/update_target()
|
||||
var/mob/living/current_target = pursuit_target?.resolve()
|
||||
if(QDELETED(current_target))
|
||||
pursuit_target = null
|
||||
if(!isnull(pursuit_target) && prob(80))
|
||||
return
|
||||
var/mob/living/new_target = find_nearest_target()
|
||||
if(isnull(new_target))
|
||||
pursuit_target = null
|
||||
return
|
||||
if(new_target == current_target)
|
||||
return
|
||||
if(isbelly(new_target.loc) || istype(new_target.loc, /area/crew_quarters))
|
||||
return
|
||||
current_target = new_target
|
||||
pursuit_target = WEAKREF(new_target)
|
||||
|
||||
/obj/effect/anomaly/bioscrambler/proc/find_nearest_target()
|
||||
var/closest_distance = INFINITY
|
||||
var/mob/living/carbon/closest_target = null
|
||||
for(var/mob/living/carbon/target in GLOB.player_list)
|
||||
if(target.z != z)
|
||||
continue
|
||||
if(SEND_SIGNAL(target, COMSIG_CHECK_FOR_GODMODE) & COMSIG_GODMODE_CANCEL)
|
||||
continue
|
||||
if(target.stat >= UNCONSCIOUS)
|
||||
continue
|
||||
if(istype(get_area(target), /area/crew_quarters))
|
||||
continue
|
||||
var/distance_from_target = get_dist(src, target)
|
||||
if(distance_from_target >= closest_distance)
|
||||
continue
|
||||
closest_distance = distance_from_target
|
||||
closest_target = target
|
||||
|
||||
return closest_target
|
||||
|
||||
/// A bioscrambler anomaly subtype which does not pursue people, for purposes of a space ruin
|
||||
/obj/effect/anomaly/bioscrambler/docile
|
||||
|
||||
/obj/effect/anomaly/bioscrambler/docile/update_target()
|
||||
return
|
||||
|
||||
/obj/effect/anomaly/bioscrambler/detonate()
|
||||
COOLDOWN_RESET(src, pulse_cooldown)
|
||||
anomalyEffect()
|
||||
@@ -0,0 +1,94 @@
|
||||
/obj/effect/anomaly/bluespace
|
||||
name = "bluespace anomaly"
|
||||
icon_state = "bluespace"
|
||||
density = TRUE
|
||||
anomaly_core = /obj/item/assembly/signaler/anomaly/bluespace
|
||||
///range from which we can teleport someone
|
||||
var/teleport_range = 1
|
||||
///Distance we can teleport someone passively
|
||||
var/teleport_distance = 4
|
||||
|
||||
/obj/effect/anomaly/bluespace/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
apply_wibbly_filters(src)
|
||||
|
||||
/obj/effect/anomaly/bluespace/anomalyEffect()
|
||||
..()
|
||||
for(var/mob/living/M in range(teleport_range, src))
|
||||
var/susceptibility = GetAnomalySusceptibility(M)
|
||||
if(prob(100 * susceptibility))
|
||||
do_teleport(M, locate(M.x, M.y, M.z), teleport_distance, channel = TELEPORT_CHANNEL_BLUESPACE)
|
||||
|
||||
/obj/effect/anomaly/bluespace/Bumped(atom/movable/AM)
|
||||
if(isliving(AM) && prob(100 * GetAnomalySusceptibility(AM)))
|
||||
do_teleport(AM, locate(AM.x, AM.y, AM.z), 8, channel = TELEPORT_CHANNEL_BLUESPACE)
|
||||
|
||||
/obj/effect/anomaly/bluespace/detonate()
|
||||
playsound(src, 'sound/effects/cosmic_energy.ogg', vol = 50)
|
||||
|
||||
var/turf/impact_turf = pick(get_area_turfs(impact_area))
|
||||
if(!impact_area)
|
||||
return
|
||||
|
||||
var/obj/item/radio/beacon/chosen
|
||||
var/list/possible = list()
|
||||
for(var/obj/item/radio/beacon in GLOB.all_beacons)
|
||||
var/turf/turf = get_turf(beacon)
|
||||
if(!turf)
|
||||
continue
|
||||
if(!check_teleport_valid(src, turf))
|
||||
continue
|
||||
possible += beacon
|
||||
|
||||
if(possible.len > 0)
|
||||
chosen = pick(possible)
|
||||
|
||||
if(!chosen)
|
||||
return
|
||||
|
||||
var/turf/beacon_turf = get_turf(chosen)
|
||||
|
||||
playsound(beacon_turf, 'sound/effects/phasein.ogg', 100, TRUE)
|
||||
|
||||
var/datum/announcement/priority/announcement = new/datum/announcement/priority()
|
||||
announcement.Announce("Massive bluespace translocation detected", "Anomaly Alert")
|
||||
|
||||
var/list/flashers = list()
|
||||
for(var/mob/living/living in viewers(beacon_turf, null))
|
||||
if(living.flash_eyes())
|
||||
flashers += living
|
||||
|
||||
var/y_distance = beacon_turf.y - impact_turf.y
|
||||
var/x_distance = beacon_turf.x - impact_turf.x
|
||||
var/list/available_turfs = RANGE_TURFS(12, beacon_turf)
|
||||
for(var/atom/movable/movable in urange(12, impact_turf))
|
||||
if(istype(movable, /obj/item/radio/beacon) || iseffect(movable) || isEye(movable))
|
||||
continue
|
||||
if(movable.anchored)
|
||||
continue
|
||||
|
||||
var/turf/newloc = locate(movable.x + x_distance, movable.y + y_distance, beacon_turf.z) || pick(available_turfs)
|
||||
do_teleport(movable, newloc, no_effects = TRUE)
|
||||
|
||||
if(isliving(movable) && !(movable in flashers))
|
||||
var/mob/living/give_sparkles = movable
|
||||
give_sparkles.flash_eyes()
|
||||
|
||||
/obj/effect/anomaly/bluespace/stabilize(anchor, has_core)
|
||||
. = ..()
|
||||
teleport_range = 0
|
||||
|
||||
/obj/effect/anomaly/bluespace/big
|
||||
immortal = TRUE
|
||||
teleport_range = 2
|
||||
teleport_distance = 12
|
||||
anomaly_core = null
|
||||
|
||||
/obj/effect/anomaly/bluespace/big/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
transform *= 3
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/bluespace
|
||||
color = COLOR_BLUE_LIGHT
|
||||
duration = 1 SECONDS
|
||||
amount_to_scale = 5
|
||||
@@ -0,0 +1,90 @@
|
||||
/obj/effect/anomaly/dimensional
|
||||
name = "dimensional anomaly"
|
||||
icon_state = "dimensional"
|
||||
anomaly_core = /obj/item/assembly/signaler/anomaly/dimensional
|
||||
lifespan = ANOMALY_COUNTDOWN_TIMER * 20
|
||||
move_chance = 0
|
||||
/// 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 = list()
|
||||
/// 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
|
||||
/// How many times we can still teleport. Delete self if it hits 0 and we try to teleport. If immortal, will simply stay where it is
|
||||
var/teleports_left
|
||||
/// Minimum teleports it will do before going away permanently
|
||||
var/minimum_teleports = 1
|
||||
/// Maximum teleports it will do before going away permanently
|
||||
var/maximum_teleports = 4
|
||||
|
||||
/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)
|
||||
|
||||
teleports_left = rand(minimum_teleports, maximum_teleports)
|
||||
|
||||
/obj/effect/anomaly/dimensional/Destroy()
|
||||
theme = null
|
||||
target_turfs = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/anomaly/dimensional/anomalyEffect(seconds_per_tick)
|
||||
. = ..()
|
||||
transmute_area()
|
||||
|
||||
/obj/effect/anomaly/dimensional/proc/transmute_area()
|
||||
if(!theme)
|
||||
prepare_area()
|
||||
if(!target_turfs.len)
|
||||
if(teleports_left <= 0 && !immortal)
|
||||
detonate()
|
||||
return
|
||||
teleports_left--
|
||||
relocate()
|
||||
return
|
||||
|
||||
var/turf/affected_turf = target_turfs[1]
|
||||
theme.apply_theme(affected_turf, show_effect = TRUE)
|
||||
target_turfs -= affected_turf
|
||||
|
||||
/obj/effect/anomaly/dimensional/proc/prepare_area(new_theme_path)
|
||||
if(!new_theme_path)
|
||||
new_theme_path = pick(subtypesof(/datum/dimension_theme))
|
||||
|
||||
theme = new new_theme_path
|
||||
|
||||
apply_theme_icon()
|
||||
|
||||
target_turfs = list()
|
||||
for(var/turf/turf in spiral_range_turfs(range, src))
|
||||
if(theme.can_convert(turf))
|
||||
target_turfs += turf
|
||||
|
||||
/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
|
||||
|
||||
/obj/effect/anomaly/dimensional/proc/relocate()
|
||||
var/datum/anomaly_placer/placer = new()
|
||||
var/area/new_area = placer.find_valid_area()
|
||||
var/turf/new_turf = placer.find_valid_turf(new_area)
|
||||
|
||||
var/datum/announcement/priority/announcement = new/datum/announcement/priority()
|
||||
announcement.Announce("Dimensional instability relocated. Expected location: [new_area.name].", "Anomaly Alert")
|
||||
src.forceMove(new_turf)
|
||||
prepare_area()
|
||||
|
||||
/obj/effect/anomaly/dimensional/detonate()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/temp_visual/transmute_tile_flash
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "shieldsparkles"
|
||||
duration = 3
|
||||
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* Datum which describes a theme and replaces turfs and objects in specified locations to match that theme
|
||||
*/
|
||||
/datum/dimension_theme
|
||||
/// Human readable name of the theme
|
||||
var/name = "Unnamed Theme"
|
||||
/// An icon to display to represent the theme
|
||||
var/icon/icon = 'icons/obj/stacks.dmi'
|
||||
/// 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/effects/blind.ogg'
|
||||
/// Weighted list of turfs to replace the floor with.
|
||||
var/list/replace_floors = list(/turf/simulated/floor/tiled = 1)
|
||||
/// Typepath of turf to replace walls with.
|
||||
var/turf/replace_walls = /turf/simulated/wall
|
||||
/// 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/bed/chair = list(/obj/structure/bed/chair = 1),
|
||||
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock = 1, /obj/machinery/door/airlock/glass = 1),
|
||||
/obj/structure/table = list(/obj/structure/table = 1),
|
||||
/obj/structure/toilet = list(/obj/structure/toilet = 1)
|
||||
)
|
||||
/// List of random spawns to place in completely open turfs
|
||||
var/list/random_spawns
|
||||
/// Prob of placing a random spawn in a completely open turf
|
||||
var/random_spawn_chance = 0
|
||||
/// 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.icon_colour
|
||||
|
||||
|
||||
/**
|
||||
* Applies themed transformation to the provided turf.
|
||||
*
|
||||
* Arguments
|
||||
* * affected_turf - Turf to transform.
|
||||
* * skip_sound - If the sound shouldn't be played.
|
||||
* * show_effect - if the temp visual effect should be shown.
|
||||
*/
|
||||
/datum/dimension_theme/proc/apply_theme(turf/affected_turf, skip_sound = FALSE, show_effect = FALSE)
|
||||
if(!replace_turf(affected_turf))
|
||||
return
|
||||
if(!skip_sound)
|
||||
playsound(affected_turf, sound, 100, TRUE)
|
||||
if(show_effect)
|
||||
new /obj/effect/temp_visual/transmute_tile_flash(affected_turf)
|
||||
for(var/obj/object in affected_turf)
|
||||
replace_object(object)
|
||||
if(length(random_spawns) && prob(random_spawn_chance))
|
||||
var/random_spawn_picked = pick(random_spawns)
|
||||
new random_spawn_picked(affected_turf)
|
||||
|
||||
/datum/dimension_theme/proc/can_convert(var/turf/affected_turf)
|
||||
if(isspace(affected_turf))
|
||||
return FALSE
|
||||
if(isfloorturf(affected_turf))
|
||||
if(istype(get_area(affected_turf), /area/holodeck))
|
||||
return FALSE
|
||||
return replace_floors.len > 0
|
||||
if(iswall(affected_turf))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/dimension_theme/proc/replace_turf(turf/affected_turf)
|
||||
PROTECTED_PROC(TRUE)
|
||||
|
||||
if(isfloorturf(affected_turf))
|
||||
if(istype(get_area(affected_turf), /area/holodeck) || istype(get_area(affected_turf), /area/crew_quarters))
|
||||
return FALSE
|
||||
return transform_floor(affected_turf)
|
||||
|
||||
if(!iswall(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/affected_floor)
|
||||
PROTECTED_PROC(TRUE)
|
||||
|
||||
if(replace_floors.len == 0)
|
||||
return FALSE
|
||||
affected_floor.ChangeTurf(pick_weight(replace_floors))
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Replaces the provided object with a different one.
|
||||
*
|
||||
* Arguments
|
||||
* * object - Object to replace.
|
||||
*/
|
||||
/datum/dimension_theme/proc/replace_object(obj/object)
|
||||
PROTECTED_PROC(TRUE)
|
||||
|
||||
if(istype(object, /obj/structure/window) && window_colour)
|
||||
object.color = window_colour
|
||||
return
|
||||
|
||||
if(istype(object, /obj/structure/table) && material)
|
||||
var/obj/structure/table/table = object
|
||||
table.material = material
|
||||
table.update_connections(TRUE)
|
||||
table.update_icon()
|
||||
table.update_desc()
|
||||
table.update_material()
|
||||
return
|
||||
|
||||
if(istype(object, /obj/machinery/light))
|
||||
var/obj/machinery/light/light = object
|
||||
light.brightness_color = window_colour
|
||||
light.brightness_color_ns = window_colour
|
||||
light.set_light(0)
|
||||
light.update()
|
||||
|
||||
var/replace_path = get_replacement_object_typepath(object)
|
||||
if(!replace_path)
|
||||
return
|
||||
var/obj/new_object = new replace_path(object.loc)
|
||||
if(istype(object, /obj/machinery/door/airlock))
|
||||
if(istype(new_object, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/airlock = object
|
||||
var/obj/machinery/door/airlock/new_airlock = new_object
|
||||
new_airlock.req_access = airlock.req_one_access?.Copy()
|
||||
new_airlock.locked = airlock.locked
|
||||
if(istype(object, /obj/machinery/door/airlock/multi_tile))
|
||||
for(var/turf/location in object.locs)
|
||||
if(location == object.loc)
|
||||
continue
|
||||
var/obj/machinery/door/airlock/long_airlock = new replace_path(location)
|
||||
long_airlock.req_access = airlock.req_one_access?.Copy()
|
||||
long_airlock.locked = airlock.locked
|
||||
long_airlock.name = airlock.name
|
||||
new_object.name = object.name
|
||||
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)
|
||||
PROTECTED_PROC(TRUE)
|
||||
|
||||
for(var/type in replace_objs)
|
||||
if(istype(object, type))
|
||||
return pick_weight(replace_objs[type])
|
||||
|
||||
/datum/dimension_theme/gold
|
||||
name = "Gold"
|
||||
icon_state = "sheet-gold_2"
|
||||
material = /datum/material/gold
|
||||
replace_floors = list(/turf/simulated/floor/tiled/material/gold = 1)
|
||||
replace_objs = list(
|
||||
/obj/structure/bed/chair = list(/obj/structure/bed/chair = 1),
|
||||
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/gold = 1),
|
||||
/obj/structure/table = list(/obj/structure/table/gold = 1),
|
||||
/obj/structure/toilet = list(/obj/structure/toilet = 1)
|
||||
)
|
||||
replace_walls = /turf/simulated/wall/gold
|
||||
|
||||
/datum/dimension_theme/radioactive
|
||||
name = "Radioactive"
|
||||
icon_state = "sheet-uranium_2"
|
||||
material = /datum/material/uranium
|
||||
replace_floors = list(/turf/simulated/floor/tiled/material/uranium = 1)
|
||||
replace_objs = list(
|
||||
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/uranium = 1),
|
||||
)
|
||||
replace_walls = /turf/simulated/wall/uranium
|
||||
sound = 'sound/items/Welder.ogg'
|
||||
|
||||
/datum/dimension_theme/wood
|
||||
name = "Wood"
|
||||
icon_state = "sheet-plank"
|
||||
material = /datum/material/wood
|
||||
replace_floors = list(/turf/simulated/floor/wood = 1)
|
||||
replace_objs = list(
|
||||
/obj/structure/bed/chair = list(/obj/structure/bed/chair/wood = 1),
|
||||
/obj/machinery/door/airlock = list(/obj/structure/simple_door/wood = 1),
|
||||
/obj/structure/table = list(/obj/structure/table/woodentable = 1)
|
||||
)
|
||||
replace_walls = /turf/simulated/wall/wood
|
||||
/*
|
||||
/datum/dimension_theme/meat
|
||||
name = "Meat"
|
||||
icon = 'icons/obj/food.dmi'
|
||||
icon_state = "meat"
|
||||
material = /datum/material/flesh
|
||||
|
||||
/datum/dimension_theme/alien
|
||||
name = "Alien"
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "circuit"
|
||||
replace_floors = list(/turf/simulated/floor/redgrid = 1, /turf/simulated/floor/greengrid = 1, /turf/simulated/floor/bluegrid = 1)
|
||||
replace_objs = list(
|
||||
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/alien = 1),
|
||||
/obj/structure/table = list(/obj/structure/table/alien = 1, /obj/structure/table/alien/blue = 1)
|
||||
)
|
||||
*/
|
||||
/datum/dimension_theme/natural
|
||||
name = "Natural"
|
||||
icon = 'icons/obj/plants.dmi'
|
||||
icon_state = "plant-24"
|
||||
window_colour = "#0b8011ff"
|
||||
replace_floors = list(/turf/simulated/floor/grass = 1)
|
||||
replace_walls = /turf/simulated/wall/wood
|
||||
replace_objs = list(
|
||||
/obj/structure/bed/chair = list(/obj/structure/bed/chair/wood = 3, /obj/structure/bed/chair/wood/wings = 1),
|
||||
/obj/machinery/door/airlock = list(/obj/structure/simple_door/wood = 1),
|
||||
)
|
||||
random_spawns = list(
|
||||
/obj/structure/flora/grass/green = 3,
|
||||
/obj/structure/flora/bush = 3,
|
||||
/mob/living/simple_mob/vore/bee = 1,
|
||||
)
|
||||
random_spawn_chance = 10
|
||||
|
||||
/datum/dimension_theme/phoron
|
||||
name = "Phoron"
|
||||
icon_state = "sheet-phoron_2"
|
||||
material = /datum/material/phoron
|
||||
replace_floors = list(/turf/simulated/floor/tiled/material/phoron = 1)
|
||||
replace_objs = list(
|
||||
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/phoron = 1),
|
||||
)
|
||||
replace_walls = /turf/simulated/wall/phoron
|
||||
|
||||
/datum/dimension_theme/glass
|
||||
name = "Glass"
|
||||
icon_state = "sheet-glass_2"
|
||||
material = /datum/material/glass
|
||||
replace_floors = list(/turf/simulated/floor/glass = 1)
|
||||
replace_objs = list(
|
||||
/obj/machinery/door/airlock = list(/obj/machinery/door/airlock/glass = 1),
|
||||
/obj/structure/table = list(/obj/structure/table/glass = 1)
|
||||
)
|
||||
replace_walls = /obj/structure/window/basic/full
|
||||
|
||||
/datum/dimension_theme/snow
|
||||
name = "Snow"
|
||||
icon_state = "sheet-snow_2"
|
||||
material = /datum/material/snow
|
||||
replace_floors = list(/turf/simulated/floor/snow = 10, /turf/simulated/floor/outdoors/ice = 1)
|
||||
replace_objs = list(
|
||||
/obj/machinery/door/airlock = list(/obj/structure/simple_door/)
|
||||
)
|
||||
@@ -0,0 +1,63 @@
|
||||
/obj/effect/anomaly/flux
|
||||
name = "flux wave anomaly"
|
||||
icon_state = "flux"
|
||||
density = TRUE
|
||||
anomaly_core = /obj/item/assembly/signaler/anomaly/flux
|
||||
var/canshock = FALSE
|
||||
var/shockdamage = 20
|
||||
var/emp_zap = FLUX_EMP
|
||||
|
||||
/obj/effect/anomaly/flux/Initialize(mapload, new_lifespan, emp_zap = FLUX_EMP)
|
||||
. = ..()
|
||||
src.emp_zap = emp_zap
|
||||
var/static/list/loc_connections = list(
|
||||
COMSIG_ATOM_ENTERED = PROC_REF(on_entered)
|
||||
)
|
||||
AddElement(/datum/element/connect_loc, loc_connections)
|
||||
apply_wibbly_filters(src)
|
||||
|
||||
/obj/effect/anomaly/flux/anomalyEffect()
|
||||
..()
|
||||
canshock = TRUE
|
||||
for(var/mob/living/M in range(0, src))
|
||||
mobShock(M)
|
||||
|
||||
/obj/effect/anomaly/flux/proc/on_entered(datum/source, atom/movable/AM)
|
||||
SIGNAL_HANDLER
|
||||
mobShock(AM)
|
||||
|
||||
/obj/effect/anomaly/flux/Bump(atom/A)
|
||||
mobShock(A)
|
||||
|
||||
/obj/effect/anomaly/flux/Bumped(atom/movable/AM)
|
||||
mobShock(AM)
|
||||
|
||||
/obj/effect/anomaly/flux/attack_hand(mob/living/user)
|
||||
mobShock(user)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/anomaly/flux/attackby(obj/item/I, mob/user)
|
||||
mobShock(user)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/anomaly/flux/proc/mobShock(mob/living/M)
|
||||
if(canshock && istype(M))
|
||||
canshock = FALSE
|
||||
M.electrocute_act(shockdamage, name)
|
||||
|
||||
/obj/effect/anomaly/flux/detonate()
|
||||
switch(emp_zap)
|
||||
if(FLUX_EMP)
|
||||
empulse(src, 4, 16)
|
||||
explosion(src, heavy_impact_range = 1, light_impact_range = 4, flash_range = 6)
|
||||
if(FLUX_LIGHT_EMP)
|
||||
empulse(src, 4, 6)
|
||||
explosion(src, light_impact_range = 3, flash_range = 6)
|
||||
if(FLUX_NO_EMP)
|
||||
new /obj/effect/effect/sparks(loc)
|
||||
|
||||
/obj/effect/anomaly/flux/minor
|
||||
anomaly_core = null
|
||||
|
||||
/obj/effect/anomaly/flux/minor/Initialize(mapload, new_lifespan, emp_zap = FLUX_NO_EMP)
|
||||
return ..()
|
||||
@@ -0,0 +1,89 @@
|
||||
/obj/effect/anomaly/grav
|
||||
name = "gravitational anomaly"
|
||||
icon_state = "gravity"
|
||||
density = FALSE
|
||||
anomaly_core = /obj/item/assembly/signaler/anomaly/grav
|
||||
var/boing = FALSE
|
||||
var/object_launch_prob = 20
|
||||
|
||||
/obj/effect/anomaly/grav/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
var/static/list/loc_connections = list(
|
||||
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
|
||||
)
|
||||
AddElement(/datum/element/connect_loc, loc_connections)
|
||||
apply_wibbly_filters(src)
|
||||
|
||||
/obj/effect/anomaly/grav/anomalyEffect(seconds_per_tick)
|
||||
..()
|
||||
boing = TRUE
|
||||
for(var/obj/O in orange(4, src))
|
||||
if(!O.anchored)
|
||||
step_towards(O, src)
|
||||
for(var/mob/living/M in range(0, src))
|
||||
if(!M.can_overcome_gravity())
|
||||
gravShock(M)
|
||||
for(var/mob/living/M in range(4, src))
|
||||
if(!M.can_overcome_gravity())
|
||||
step_towards(M, src)
|
||||
for(var/obj/O in range(0, src))
|
||||
if(O.anchored)
|
||||
continue
|
||||
var/mob/living/target = locate() in view(4, src)
|
||||
if(target && !target.stat && prob(object_launch_prob))
|
||||
O.throw_at(target, 5, 10)
|
||||
|
||||
/obj/effect/anomaly/grav/proc/on_entered(datum/source, atom/movable/AM)
|
||||
SIGNAL_HANDLER
|
||||
gravShock(AM)
|
||||
|
||||
/obj/effect/anomaly/grav/Bump(atom/A)
|
||||
gravShock(A)
|
||||
|
||||
/obj/effect/anomaly/grav/Bumped(atom/movable/AM)
|
||||
gravShock(AM)
|
||||
|
||||
/obj/effect/anomaly/grav/proc/gravShock(mob/living/living_debris)
|
||||
if(boing && isliving(living_debris) && !living_debris.stat && !living_debris.can_overcome_gravity())
|
||||
living_debris.SetStunned(2)
|
||||
var/atom/target = get_edge_target_turf(living_debris, get_dir(src, get_step_away(living_debris, src)))
|
||||
living_debris.throw_at(target, 5, 1)
|
||||
boing = FALSE
|
||||
|
||||
/obj/effect/anomaly/grav/detonate()
|
||||
new /obj/effect/temp_visual/circle_wave/gravity(get_turf(src))
|
||||
playsound(src, 'sound/effects/cosmic_energy.ogg', vol = 50)
|
||||
|
||||
/* // Unfortunately couldn't get this one working. Maybe in the future.
|
||||
/obj/effect/anomaly/grav/high
|
||||
var/datum/proximity_monitor/advanced/gravity/grav_field
|
||||
|
||||
/obj/effect/anomaly/grav/high/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, PROC_REF(setup_grav_field))
|
||||
|
||||
/obj/effect/anomaly/grav/high/proc/setup_grav_field()
|
||||
grav_field = new(src, 7, TRUE, rand(0, 3))
|
||||
|
||||
/obj/effect/anomaly/grav/high/detonate()
|
||||
..()
|
||||
for(var/obj/machinery/gravity_generator/main/the_generator as anything in GLOB.machines)
|
||||
if(is_on_same_plane_or_station(the_generator.z))
|
||||
the_generator.breaker = FALSE
|
||||
the_generator.set_power()
|
||||
the_generator.charge_count = 10
|
||||
|
||||
/obj/effect/anomaly/grav/high/Destroy()
|
||||
QDEL_NULL(grav_field)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/anomaly/grav/high/big
|
||||
immortal = TRUE
|
||||
anomaly_core = null
|
||||
|
||||
/obj/effect/anomaly/grav/high/big/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
transform *= 3
|
||||
*/
|
||||
/obj/effect/temp_visual/circle_wave/gravity
|
||||
color = COLOR_NAVY
|
||||
@@ -0,0 +1,109 @@
|
||||
/obj/effect/anomaly/hallucination
|
||||
name = "hallucination anomaly"
|
||||
icon_state = "hallucination"
|
||||
anomaly_core = /obj/item/assembly/signaler/anomaly/hallucination
|
||||
/// Time passed since the last effect, increased by seconds_per_tick of the SSobj
|
||||
var/ticks = 0
|
||||
/// How many seconds between each small hallucination pulses
|
||||
var/release_delay = 5
|
||||
/// Messages sent to people feeling the pulses
|
||||
var/static/list/messages = list(
|
||||
span_warning("You feel your conscious mind fall apart!"),
|
||||
span_warning("Reality warps around you!"),
|
||||
span_warning("Something's whispering around you!"),
|
||||
span_warning("You are going insane!"),
|
||||
)
|
||||
///Do we spawn misleading decoys?
|
||||
var/spawn_decoys = TRUE
|
||||
|
||||
/obj/effect/anomaly/hallucination/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
apply_wibbly_filters(src)
|
||||
generate_decoys()
|
||||
|
||||
/obj/effect/anomaly/hallucination/anomalyEffect(seconds_per_tick)
|
||||
. = ..()
|
||||
ticks += seconds_per_tick
|
||||
if(ticks < release_delay)
|
||||
return
|
||||
ticks -= release_delay
|
||||
if(!isturf(loc))
|
||||
return
|
||||
|
||||
for(var/mob/living/carbon/human/hallucinator in viewers(5, src))
|
||||
var/susceptibility = GetAnomalySusceptibility(hallucinator)
|
||||
if(prob(susceptibility * 100))
|
||||
hallucinator.hallucination += 10
|
||||
if(prob(20))
|
||||
to_chat(hallucinator, pick(messages))
|
||||
if(prob(10))
|
||||
to_chat(hallucinator, span_danger("Your nose bleeds!"))
|
||||
hallucinator.drip(1)
|
||||
|
||||
/obj/effect/anomaly/hallucination/detonate()
|
||||
if(isturf(loc))
|
||||
return
|
||||
|
||||
for(var/mob/living/carbon/human/hallucinator in viewers(10, src))
|
||||
to_chat(hallucinator, pick(messages))
|
||||
hallucinator.hallucination += 25
|
||||
to_chat(hallucinator, span_danger("Your nose bleeds!"))
|
||||
hallucinator.drip(1)
|
||||
|
||||
/obj/effect/anomaly/hallucination/proc/generate_decoys()
|
||||
if(!spawn_decoys)
|
||||
return
|
||||
|
||||
for(var/turf/floor in orange(1, src))
|
||||
if(prob(35))
|
||||
new /obj/effect/anomaly/hallucination/decoy(floor)
|
||||
|
||||
/obj/effect/anomaly/hallucination/decoy
|
||||
anomaly_core = null
|
||||
var/report_text
|
||||
|
||||
/obj/effect/anomaly/hallucination/decoy/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
report_text = pick(
|
||||
"[src]'s unstable field is fluctuating along frequency 9999999.99999, code 9999999.99999. No, no, that can't be right?",
|
||||
"It doesn't detect anything. It awaits an input, as if you're pointing it towards nothing at all. What?",
|
||||
"The interface displays [pick("a bad memory from your past", "the frequency numbers in a language you cannot read", "the first 15 digits of Pi", "yourself, from behind, angled at a 3/4ths isometric perspective")]. What the hell?",
|
||||
"Nothing happens?",
|
||||
"It reports that you are a [pick("moron", "idiot", "cretin", "lowlife", "worthless denthead", "gump")]. Huh?",
|
||||
"It tells you to try again, because you're doing it all wrong. What?",
|
||||
"It occurs to you that the anomaly you're scanning isn't actually there.",
|
||||
"It's not working. You activate %TOOL% again. Still broken. You activate %TOOL%. You activate %TOOL%. Why isn't this working??",
|
||||
"Something happens. You can't tell what. The interface on %TOOL% remains blank.",
|
||||
"What are you even trying to accomplish here? Did you really think that was going to work?",
|
||||
"Someone behind you whispers the frequency code to you, but you can't quite hear them. The interface on %TOOL% remains blank.",
|
||||
"For a brief moment, you see yourself traversing a frozen forest, before snapping back to reality. The interface on %TOOL% remains blank.",
|
||||
"Nothing interesting happens. Are you sure you're actually using it on anything?",
|
||||
"For a moment you can feel your skin falling off, then blink as the sensation vanishes. What the hell did that mean?",
|
||||
"The interface reports that you are a complete failure, and have screwed everything up again. Great work.",
|
||||
"You realize that the formatting of this message is completely wrong, and get confused. Now why would that be?",
|
||||
"%TOOL% stares back at you. It looks dissapointed, its screen practically saying 'You missed the anomaly, you dolt. There's nothing there!'",
|
||||
"Nothing. Weird, maybe %TOOL% must be broken or something?",
|
||||
"You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. You activate %TOOL%. Why isn't it working??",
|
||||
)
|
||||
|
||||
/obj/effect/anomaly/hallucination/decoy/anomalyEffect(seconds_per_tick)
|
||||
if(SPT_PROB(move_chance, seconds_per_tick))
|
||||
move_anomaly()
|
||||
|
||||
/obj/effect/anomaly/hallucination/decoy/attackby(obj/item/tool, mob/user, params)
|
||||
if(istype(tool, /obj/item/analyzer))
|
||||
to_chat(user, span_notice("You activate \the [tool]. [replacetext(report_text, "%TOOL%", "[tool]")]"))
|
||||
return ..()
|
||||
|
||||
/obj/effect/anomaly/hallucination/decoy/detonate()
|
||||
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread
|
||||
sparks.set_up(3, 1, src)
|
||||
sparks.start()
|
||||
return
|
||||
|
||||
/obj/effect/anomaly/hallucination/decoy/generate_decoys()
|
||||
return
|
||||
|
||||
///Subtype for the SM that doesn't spawn decoys, because otherwise the whole area gets flooded with dummies.
|
||||
/obj/effect/anomaly/hallucination/supermatter
|
||||
spawn_decoys = FALSE
|
||||
@@ -0,0 +1,34 @@
|
||||
/obj/effect/anomaly/pyro
|
||||
name = "pyroclastic anomaly"
|
||||
icon_state = "pyroclastic"
|
||||
var/ticks = 0
|
||||
/// How many seconds between each gas release
|
||||
var/releasedelay = 15 SECONDS
|
||||
anomaly_core = /obj/item/assembly/signaler/anomaly/pyro
|
||||
|
||||
/obj/effect/anomaly/pyro/Initialize(mapload, new_lifespan, drops_core)
|
||||
. = ..()
|
||||
apply_wibbly_filters(src)
|
||||
|
||||
/obj/effect/anomaly/pyro/anomalyEffect(seconds_per_tick)
|
||||
..()
|
||||
ticks += seconds_per_tick
|
||||
if(ticks < releasedelay)
|
||||
return FALSE
|
||||
else
|
||||
ticks -= releasedelay
|
||||
var/turf/simulated/floor/tile = get_turf(src)
|
||||
if(istype(tile))
|
||||
tile.assume_gas(GAS_PHORON, 10, T20C)
|
||||
tile.hotspot_expose(700, 400)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/anomaly/pyro/detonate()
|
||||
var/turf/simulated/floor/tile = get_turf(src)
|
||||
if(istype(tile))
|
||||
tile.assume_gas(GAS_PHORON, 10, T20C)
|
||||
tile.hotspot_expose(700, 400)
|
||||
|
||||
var/new_colour = pick(/mob/living/simple_mob/slime/xenobio/red, /mob/living/simple_mob/slime/xenobio/orange)
|
||||
var/mob/living/simple_mob/slime/xenobio/pyro = new new_colour(tile)
|
||||
pyro.enrage()
|
||||
@@ -0,0 +1,45 @@
|
||||
/datum/anomaly_placer
|
||||
var/static/list/allowed_areas
|
||||
var/list/excluded = list(
|
||||
/area/crew_quarters,
|
||||
/area/shuttle,
|
||||
/area/space,
|
||||
/area/solar,
|
||||
/area/engineering/engine_room,
|
||||
/area/maintenance,
|
||||
/area/holodeck,
|
||||
/area/ai
|
||||
)
|
||||
|
||||
/datum/anomaly_placer/proc/find_valid_area()
|
||||
var/list/possible_areas = get_station_areas(excluded)
|
||||
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
|
||||
|
||||
/datum/anomaly_placer/proc/find_valid_turf(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 locaton [target_area]")
|
||||
|
||||
return pick(valid_turfs)
|
||||
|
||||
/datum/anomaly_placer/proc/is_valid_destination(turf/tested)
|
||||
if(isspace(tested))
|
||||
return FALSE
|
||||
if(tested.density)
|
||||
return FALSE
|
||||
if(isopenspace(tested))
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -0,0 +1,17 @@
|
||||
/obj/effect/spawner/lootdrop/environmentally_safe_anomaly
|
||||
name = "safe anomaly spawner"
|
||||
icon_state = "instability"
|
||||
loot = list(
|
||||
/obj/effect/anomaly/flux,
|
||||
/obj/effect/anomaly/bluespace,
|
||||
/obj/effect/anomaly/hallucination,
|
||||
/obj/effect/anomaly/bioscrambler/docile
|
||||
)
|
||||
|
||||
var/anchor_anomaly = FALSE
|
||||
|
||||
/obj/effect/spawner/lootdrop/environmentally_safe_anomaly/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
var/obj/effect/anomaly/anomaly = .
|
||||
anomaly.stabilize(anchor = anchor_anomaly)
|
||||
@@ -9,7 +9,7 @@
|
||||
anchored = TRUE
|
||||
plane = PLANE_GHOSTS
|
||||
color = "#ff0000"
|
||||
var/text_size = 3
|
||||
var/text_size = 3 // Larger values clip when the displayed text is larger than 2 digits
|
||||
var/started = FALSE
|
||||
var/displayed_text
|
||||
var/atom/attached_to
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
/obj/effect/countdown/singularity_act()
|
||||
return
|
||||
/*
|
||||
|
||||
/obj/effect/countdown/anomaly
|
||||
name = "anomaly countdown"
|
||||
|
||||
@@ -91,4 +91,3 @@
|
||||
else
|
||||
var/time_left = max(0, (A.death_time - world.time)/10)
|
||||
return round(time_left)
|
||||
*/
|
||||
|
||||
@@ -113,3 +113,35 @@
|
||||
pixel_y = rand(-9, 0)
|
||||
. = ..()
|
||||
// VOREStation Add End
|
||||
|
||||
/obj/effect/temp_visual/circle_wave
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
icon_state = "circle_wave"
|
||||
pixel_x = -16
|
||||
pixel_y = -16
|
||||
duration = 0.5 SECONDS
|
||||
color = COLOR_LIME
|
||||
var/max_alpha = 255
|
||||
var/amount_to_scale = 2
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/Initialize(mapload)
|
||||
transform = matrix().Scale(0.1)
|
||||
animate(src, transform = matrix().Scale(amount_to_scale), time = duration, flags = ANIMATION_PARALLEL)
|
||||
animate(src, alpha = max_alpha, time = duration * 0.6, flags = ANIMATION_PARALLEL)
|
||||
animate(alpha = 0, time = duration * 0.4)
|
||||
apply_wibbly_filters(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/bioscrambler
|
||||
color = COLOR_LIME
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/bioscrambler/light
|
||||
max_alpha = 128
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/void_conduit
|
||||
color = COLOR_FULL_TONER_BLACK
|
||||
duration = 12 SECONDS
|
||||
amount_to_scale = 12
|
||||
|
||||
/obj/effect/temp_visual/circle_wave/star_blast
|
||||
color = COLOR_VOID_PURPLE
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/obj/item/anomaly_neutralizer
|
||||
name = "anomaly neutralizer"
|
||||
desc = "A one-use device capable of instantly neutralizing anomalous or otherworldly entities."
|
||||
icon = 'icons/obj/devices/tool.dmi'
|
||||
icon_state = "neutralyzer"
|
||||
w_class = ITEMSIZE_SMALL
|
||||
slot_flags = SLOT_BELT
|
||||
item_flags = NOBLUDGEON
|
||||
|
||||
/obj/item/anomaly_neutralizer/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
AddComponent(/datum/component/effect_remover, \
|
||||
success_feedback = "You neutralize %THEEFFECT with %THEWEAPON, frying its circuitry in the process.", \
|
||||
on_clear_callback = CALLBACK(src, PROC_REF(on_anomaly_neutralized)), \
|
||||
effects_we_clear = list(/obj/effect/anomaly))
|
||||
|
||||
/obj/item/anomaly_neutralizer/proc/on_anomaly_neutralized(obj/effect/anomaly/target, mob/living/user)
|
||||
target.anomalyNeutralize()
|
||||
on_use(target, user)
|
||||
|
||||
/obj/item/anomaly_neutralizer/proc/on_use(obj/effect/target, mob/living/user)
|
||||
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread
|
||||
sparks.set_up(3, 1, src)
|
||||
sparks.start()
|
||||
qdel(src)
|
||||
|
||||
/obj/item/anomaly_releaser
|
||||
icon = 'icons/obj/devices/syndie_gadget.dmi'
|
||||
icon_state = "anomaly_releaser"
|
||||
name = "anomaly releaser"
|
||||
desc = "Single-use injector that releases and stabilizes anomalies by injecting an unknown substance."
|
||||
throwforce = 0
|
||||
w_class = ITEMSIZE_SMALL
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
|
||||
///icon state after being used up
|
||||
var/used_icon_state = "anomaly_releaser_used"
|
||||
///are we used? if used we can't be used again
|
||||
var/used = FALSE
|
||||
///Can we be used infinitely?
|
||||
var/infinite = FALSE
|
||||
Reference in New Issue
Block a user