diff --git a/code/__DEFINES/cult.dm b/code/__DEFINES/cult.dm
new file mode 100644
index 0000000000..71d4ad3af9
--- /dev/null
+++ b/code/__DEFINES/cult.dm
@@ -0,0 +1,9 @@
+//rune colors, for easy reference
+#define RUNE_COLOR_TALISMAN "#0000FF"
+#define RUNE_COLOR_TELEPORT "#551A8B"
+#define RUNE_COLOR_OFFER "#FFFFFF"
+#define RUNE_COLOR_DARKRED "#7D1717"
+#define RUNE_COLOR_MEDIUMRED "#C80000"
+#define RUNE_COLOR_RED "#FF0000"
+#define RUNE_COLOR_EMP "#4D94FF"
+#define RUNE_COLOR_SUMMON "#00FF00"
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index ca4093adf1..43b657dd9c 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -340,6 +340,20 @@ Proc for attack log creation, because really why not
qdel(progbar)
+//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action
+/mob/proc/break_do_after_checks(list/checked_health, check_clicks)
+ if(check_clicks && next_move > world.time)
+ return FALSE
+ return TRUE
+
+//pass a list in the format list("health" = mob's health var) to check health during this
+/mob/living/break_do_after_checks(list/checked_health, check_clicks)
+ if(islist(checked_health))
+ if(health < checked_health["health"])
+ return FALSE
+ checked_health["health"] = health
+ return ..()
+
/proc/do_after(mob/user, delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null)
if(!user)
return 0
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index 43d940d5e5..62559379c5 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -214,7 +214,7 @@
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands)
. = list()
if(!isinhands && current_charges)
- . += mutable_appearance('icons/effects/effects.dmi', "shield-cult", MOB_LAYER + 0.01)
+ . += mutable_appearance('icons/effects/cult_effects.dmi', "shield-cult", MOB_LAYER + 0.01)
/obj/item/clothing/suit/hooded/cultrobes/berserker
name = "flagellant's robes"
diff --git a/code/game/gamemodes/cult/rune_spawn_action.dm b/code/game/gamemodes/cult/rune_spawn_action.dm
new file mode 100644
index 0000000000..beffe924bc
--- /dev/null
+++ b/code/game/gamemodes/cult/rune_spawn_action.dm
@@ -0,0 +1,70 @@
+//after a delay, creates a rune below you. for constructs creating runes.
+/datum/action/innate/cult/create_rune
+ background_icon_state = "bg_cult"
+ var/obj/effect/rune/rune_type
+ var/cooldown = 0
+ var/base_cooldown = 900
+ var/scribe_time = 100
+ var/damage_interrupt = TRUE
+ var/action_interrupt = TRUE
+ var/obj/effect/overlay/temp/cult/rune_spawn/rune_word_type
+ var/obj/effect/overlay/temp/cult/rune_spawn/rune_innerring_type
+ var/obj/effect/overlay/temp/cult/rune_spawn/rune_center_type
+ var/rune_color
+
+/datum/action/innate/cult/create_rune/IsAvailable()
+ if(!rune_type || cooldown > world.time)
+ return FALSE
+ return ..()
+
+/datum/action/innate/cult/create_rune/Activate()
+ var/chosen_keyword
+ if(!isturf(owner.loc))
+ to_chat(owner, "")
var/oldcolor = color
- color = "#7D1717"
+ color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)
var/is_clock = is_servant_of_ratvar(L)
var/is_convertable = is_convertable_to_cult(L)
@@ -442,7 +442,7 @@ structure_check() searches for nearby cultist structures required for the invoca
invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!"
req_cultists = 9
icon = 'icons/effects/96x96.dmi'
- color = "#7D1717"
+ color = RUNE_COLOR_DARKRED
icon_state = "rune_large"
pixel_x = -32 //So the big ol' 96x96 sprite shows up right
pixel_y = -32
@@ -478,12 +478,10 @@ structure_check() searches for nearby cultist structures required for the invoca
send_to_playing_players('sound/effects/dimensional_rend.ogg')
var/turf/T = get_turf(src)
sleep(40)
- SSticker.mode.eldergod = FALSE
if(src)
- color = "#FF0000"
- deltimer(GLOB.blood_target_reset_timer)
- new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn and makes it the blood target even if the rune has been removed
-
+ color = RUNE_COLOR_RED
+ SSticker.mode.eldergod = FALSE
+ new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
if((istype(I, /obj/item/weapon/tome) && iscultist(user)))
@@ -504,7 +502,7 @@ structure_check() searches for nearby cultist structures required for the invoca
cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
- color = "#C80000"
+ color = RUNE_COLOR_MEDIUMRED
var/static/revives_used = 0
/obj/effect/rune/raise_dead/examine(mob/user)
@@ -595,7 +593,7 @@ structure_check() searches for nearby cultist structures required for the invoca
invocation = "Ta'gh fara'qha fel d'amar det!"
icon_state = "5"
allow_excess_invokers = 1
- color = "#4D94FF"
+ color = RUNE_COLOR_EMP
/obj/effect/rune/emp/invoke(var/list/invokers)
var/turf/E = get_turf(src)
@@ -625,7 +623,7 @@ structure_check() searches for nearby cultist structures required for the invoca
cultist_desc = "severs the link between one's spirit and body. This effect is taxing and one's physical body will take damage while this is active."
invocation = "Fwe'sh mah erl nyag r'ya!"
icon_state = "7"
- color = "#7D1717"
+ color = RUNE_COLOR_DARKRED
rune_in_use = 0 //One at a time, please!
construct_invoke = 0
var/mob/living/affecting = null
@@ -651,9 +649,9 @@ structure_check() searches for nearby cultist structures required for the invoca
var/mob/living/user = invokers[1]
..()
var/turf/T = get_turf(src)
- rune_in_use = 1
+ rune_in_use = TRUE
affecting = user
- user.color = "#7D1717"
+ user.add_atom_colour(RUNE_COLOR_DARKRED, ADMIN_COLOUR_PRIORITY)
user.visible_message("[user] freezes statue-still, glowing an unearthly red.", \
"You see what lies beyond. All is revealed. While this is a wondrous experience, your physical form will waste away in this state. Hurry...")
user.ghostize(1)
@@ -661,7 +659,7 @@ structure_check() searches for nearby cultist structures required for the invoca
if(!affecting)
visible_message("[src] pulses gently before falling dark.")
affecting = null //In case it's assigned to a number or something
- rune_in_use = 0
+ rune_in_use = FALSE
return
affecting.apply_damage(0.1, BRUTE)
if(!(user in T))
@@ -671,9 +669,9 @@ structure_check() searches for nearby cultist structures required for the invoca
if(user.key)
user.visible_message("[user] slowly relaxes, the glow around [user.p_them()] dimming.", \
"You are re-united with your physical form. [src] releases its hold over you.")
- user.color = initial(user.color)
+ user.remove_atom_colour(ADMIN_COLOUR_PRIORITY, RUNE_COLOR_DARKRED)
user.Weaken(3)
- rune_in_use = 0
+ rune_in_use = FALSE
affecting = null
return
if(user.stat == UNCONSCIOUS)
@@ -681,14 +679,14 @@ structure_check() searches for nearby cultist structures required for the invoca
var/mob/dead/observer/G = user.get_ghost()
to_chat(G, "You feel the link between you and your body weakening... you must hurry!")
if(user.stat == DEAD)
- user.color = initial(user.color)
- rune_in_use = 0
+ user.remove_atom_colour(ADMIN_COLOUR_PRIORITY, RUNE_COLOR_DARKRED)
+ rune_in_use = FALSE
affecting = null
var/mob/dead/observer/G = user.get_ghost()
to_chat(G, "You suddenly feel your physical form pass on. [src]'s exertion has killed you!")
return
sleep(1)
- rune_in_use = 0
+ rune_in_use = FALSE
//Rite of the Corporeal Shield: When invoked, becomes solid and cannot be passed. Invoke again to undo.
/obj/effect/rune/wall
@@ -696,7 +694,7 @@ structure_check() searches for nearby cultist structures required for the invoca
cultist_desc = "when invoked, makes a temporary invisible wall to block passage. Can be invoked again to reverse this."
invocation = "Khari'd! Eske'te tannin!"
icon_state = "1"
- color = "#C80000"
+ color = RUNE_COLOR_MEDIUMRED
CanAtmosPass = ATMOS_PASS_DENSITY
var/density_timer
var/recharging = FALSE
@@ -755,7 +753,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/wall/proc/recharge()
recharging = FALSE
- add_atom_colour("#C80000", FIXED_COLOUR_PRIORITY)
+ add_atom_colour(RUNE_COLOR_MEDIUMRED, FIXED_COLOUR_PRIORITY)
/obj/effect/rune/wall/proc/update_state()
deltimer(density_timer)
@@ -766,10 +764,10 @@ structure_check() searches for nearby cultist structures required for the invoca
shimmer.alpha = 60
shimmer.color = "#701414"
add_overlay(shimmer)
- add_atom_colour("#FF0000", FIXED_COLOUR_PRIORITY)
+ add_atom_colour(RUNE_COLOR_RED, FIXED_COLOUR_PRIORITY)
else
cut_overlays()
- add_atom_colour("#C80000", FIXED_COLOUR_PRIORITY)
+ add_atom_colour(RUNE_COLOR_MEDIUMRED, FIXED_COLOUR_PRIORITY)
//Rite of Joined Souls: Summons a single cultist.
/obj/effect/rune/summon
@@ -779,7 +777,7 @@ structure_check() searches for nearby cultist structures required for the invoca
req_cultists = 2
allow_excess_invokers = 1
icon_state = "5"
- color = "#00FF00"
+ color = RUNE_COLOR_SUMMON
/obj/effect/rune/summon/invoke(var/list/invokers)
var/mob/living/user = invokers[1]
@@ -824,7 +822,7 @@ structure_check() searches for nearby cultist structures required for the invoca
cultist_desc = "boils the blood of non-believers who can see the rune, rapidly dealing extreme amounts of damage. Requires 3 invokers."
invocation = "Dedo ol'btoh!"
icon_state = "4"
- color = "#C80000"
+ color = RUNE_COLOR_MEDIUMRED
light_color = LIGHT_COLOR_LAVA
req_cultists = 3
construct_invoke = 0
@@ -891,7 +889,7 @@ structure_check() searches for nearby cultist structures required for the invoca
invocation = "Gal'h'rfikk harfrandid mud'gib!" //how the fuck do you pronounce this
icon_state = "6"
construct_invoke = 0
- color = "#C80000"
+ color = RUNE_COLOR_MEDIUMRED
var/ghost_limit = 5
var/ghosts = 0
diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm
index 027df31acd..9a9d8c582b 100644
--- a/code/game/gamemodes/cult/talisman.dm
+++ b/code/game/gamemodes/cult/talisman.dm
@@ -49,7 +49,7 @@
/obj/item/weapon/paper/talisman/teleport
cultist_name = "Talisman of Teleportation"
cultist_desc = "A single-use talisman that will teleport a user to a random rune of the same keyword."
- color = "#551A8B" // purple
+ color = RUNE_COLOR_TELEPORT
invocation = "Sas'so c'arta forbici!"
health_cost = 5
creation_time = 80
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index 12225321d7..9d9694b076 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -18,620 +18,6 @@
..()
QDEL_IN(src, 10)
-/obj/effect/overlay/temp
- icon_state = "nothing"
- anchored = 1
- layer = ABOVE_MOB_LAYER
- mouse_opacity = 0
- var/duration = 10 //in deciseconds
- var/randomdir = TRUE
- var/timerid
-
-/obj/effect/overlay/temp/Destroy()
- . = ..()
- deltimer(timerid)
-
-/obj/effect/overlay/temp/Initialize()
- . = ..()
- if(randomdir)
- setDir(pick(GLOB.cardinal))
-
- timerid = QDEL_IN(src, duration)
-
-/obj/effect/overlay/temp/ex_act()
- return
-
-/obj/effect/overlay/temp/dir_setting
- randomdir = FALSE
-
-/obj/effect/overlay/temp/dir_setting/Initialize(mapload, set_dir)
- if(set_dir)
- setDir(set_dir)
- . = ..()
-
-/obj/effect/overlay/temp/dir_setting/bloodsplatter
- icon = 'icons/effects/blood.dmi'
- duration = 5
- randomdir = FALSE
- layer = BELOW_MOB_LAYER
- var/splatter_type = "splatter"
-
-/obj/effect/overlay/temp/dir_setting/bloodsplatter/Initialize(mapload, set_dir)
- if(set_dir in GLOB.diagonals)
- icon_state = "[splatter_type][pick(1, 2, 6)]"
- else
- icon_state = "[splatter_type][pick(3, 4, 5)]"
- . = ..()
- var/target_pixel_x = 0
- var/target_pixel_y = 0
- switch(set_dir)
- if(NORTH)
- target_pixel_y = 16
- if(SOUTH)
- target_pixel_y = -16
- layer = ABOVE_MOB_LAYER
- if(EAST)
- target_pixel_x = 16
- if(WEST)
- target_pixel_x = -16
- if(NORTHEAST)
- target_pixel_x = 16
- target_pixel_y = 16
- if(NORTHWEST)
- target_pixel_x = -16
- target_pixel_y = 16
- if(SOUTHEAST)
- target_pixel_x = 16
- target_pixel_y = -16
- layer = ABOVE_MOB_LAYER
- if(SOUTHWEST)
- target_pixel_x = -16
- target_pixel_y = -16
- layer = ABOVE_MOB_LAYER
- animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration)
-
-/obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter
- splatter_type = "xsplatter"
-
-/obj/effect/overlay/temp/dir_setting/speedbike_trail
- name = "speedbike trails"
- icon_state = "ion_fade"
- layer = BELOW_MOB_LAYER
- duration = 10
- randomdir = 0
-
-/obj/effect/overlay/temp/dir_setting/firing_effect
- icon = 'icons/effects/effects.dmi'
- icon_state = "firing_effect"
- duration = 2
-
-/obj/effect/overlay/temp/dir_setting/firing_effect/setDir(newdir)
- switch(newdir)
- if(NORTH)
- layer = BELOW_MOB_LAYER
- pixel_x = rand(-3,3)
- pixel_y = rand(4,6)
- if(SOUTH)
- pixel_x = rand(-3,3)
- pixel_y = rand(-1,1)
- else
- pixel_x = rand(-1,1)
- pixel_y = rand(-1,1)
- ..()
-
-/obj/effect/overlay/temp/dir_setting/firing_effect/energy
- icon_state = "firing_effect_energy"
- duration = 3
-
-/obj/effect/overlay/temp/dir_setting/firing_effect/magic
- icon_state = "shieldsparkles"
- duration = 3
-
-/obj/effect/overlay/temp/dir_setting/ninja
- name = "ninja shadow"
- icon = 'icons/mob/mob.dmi'
- icon_state = "uncloak"
- duration = 9
-
-/obj/effect/overlay/temp/dir_setting/ninja/cloak
- icon_state = "cloak"
-
-/obj/effect/overlay/temp/dir_setting/ninja/shadow
- icon_state = "shadow"
-
-/obj/effect/overlay/temp/dir_setting/ninja/phase
- name = "ninja energy"
- icon_state = "phasein"
-
-/obj/effect/overlay/temp/dir_setting/ninja/phase/out
- icon_state = "phaseout"
-
-/obj/effect/overlay/temp/dir_setting/wraith
- name = "blood"
- icon = 'icons/mob/mob.dmi'
- icon_state = "phase_shift2"
- duration = 12
-
-/obj/effect/overlay/temp/dir_setting/wraith/out
- icon_state = "phase_shift"
-
-/obj/effect/overlay/temp/dir_setting/tailsweep
- icon_state = "tailsweep"
- duration = 4
-
-/obj/effect/overlay/temp/wizard
- name = "water"
- icon = 'icons/mob/mob.dmi'
- icon_state = "reappear"
- duration = 5
-
-/obj/effect/overlay/temp/wizard/out
- icon_state = "liquify"
- duration = 12
-
-/obj/effect/overlay/temp/monkeyify
- icon = 'icons/mob/mob.dmi'
- icon_state = "h2monkey"
- duration = 22
-
-/obj/effect/overlay/temp/monkeyify/humanify
- icon_state = "monkey2h"
-
-/obj/effect/overlay/temp/borgflash
- icon = 'icons/mob/mob.dmi'
- icon_state = "blspell"
- duration = 5
-
-/obj/effect/overlay/temp/guardian
- randomdir = 0
-
-/obj/effect/overlay/temp/guardian/phase
- duration = 5
- icon_state = "phasein"
-
-/obj/effect/overlay/temp/guardian/phase/out
- icon_state = "phaseout"
-
-/obj/effect/overlay/temp/decoy
- desc = "It's a decoy!"
- duration = 15
-
-/obj/effect/overlay/temp/decoy/Initialize(mapload, atom/mimiced_atom)
- . = ..()
- alpha = initial(alpha)
- if(mimiced_atom)
- name = mimiced_atom.name
- appearance = mimiced_atom.appearance
- setDir(mimiced_atom.dir)
- mouse_opacity = 0
-
-/obj/effect/overlay/temp/decoy/fading/Initialize(mapload, atom/mimiced_atom)
- . = ..()
- animate(src, alpha = 0, time = duration)
-
-/obj/effect/overlay/temp/decoy/fading/fivesecond
- duration = 50
-
-/obj/effect/overlay/temp/small_smoke
- icon_state = "smoke"
- duration = 50
-
-/obj/effect/overlay/temp/fire
- icon = 'icons/effects/fire.dmi'
- icon_state = "3"
- duration = 20
-
-/obj/effect/overlay/temp/cult
- randomdir = 0
- duration = 10
-
-/obj/effect/overlay/temp/cult/sparks
- randomdir = 1
- name = "blood sparks"
- icon_state = "bloodsparkles"
-
-/obj/effect/overlay/temp/cult/blood // The traditional teleport
- name = "blood jaunt"
- duration = 12
- icon_state = "bloodin"
-
-/obj/effect/overlay/temp/cult/blood/out
- icon_state = "bloodout"
-
-/obj/effect/overlay/temp/dir_setting/cult/phase // The veil shifter teleport
- name = "phase glow"
- duration = 7
- icon_state = "cultin"
-
-/obj/effect/overlay/temp/dir_setting/cult/phase/out
- icon_state = "cultout"
-
-/obj/effect/overlay/temp/cult/sac
- name = "maw of Nar-Sie"
- icon_state = "sacconsume"
-
-/obj/effect/overlay/temp/cult/door
- name = "unholy glow"
- icon_state = "doorglow"
- layer = CLOSED_FIREDOOR_LAYER //above closed doors
-
-/obj/effect/overlay/temp/cult/door/unruned
- icon_state = "unruneddoorglow"
-
-/obj/effect/overlay/temp/cult/turf
- name = "unholy glow"
- icon_state = "wallglow"
- layer = ABOVE_NORMAL_TURF_LAYER
-
-/obj/effect/overlay/temp/cult/turf/floor
- icon_state = "floorglow"
- duration = 5
-
-
-/obj/effect/overlay/temp/ratvar
- name = "ratvar's light"
- icon = 'icons/effects/clockwork_effects.dmi'
- duration = 8
- randomdir = 0
- layer = ABOVE_NORMAL_TURF_LAYER
-
-/obj/effect/overlay/temp/ratvar/door
- icon_state = "ratvardoorglow"
- layer = CLOSED_DOOR_LAYER //above closed doors
-
-/obj/effect/overlay/temp/ratvar/door/window
- icon_state = "ratvarwindoorglow"
- layer = ABOVE_WINDOW_LAYER
-
-/obj/effect/overlay/temp/ratvar/beam
- icon_state = "ratvarbeamglow"
-
-/obj/effect/overlay/temp/ratvar/beam/door
- layer = CLOSED_DOOR_LAYER
-
-/obj/effect/overlay/temp/ratvar/beam/grille
- layer = BELOW_OBJ_LAYER
-
-/obj/effect/overlay/temp/ratvar/beam/itemconsume
- layer = HIGH_OBJ_LAYER
-
-/obj/effect/overlay/temp/ratvar/beam/falsewall
- layer = OBJ_LAYER
-
-/obj/effect/overlay/temp/ratvar/beam/catwalk
- layer = LATTICE_LAYER
-
-/obj/effect/overlay/temp/ratvar/wall
- icon_state = "ratvarwallglow"
-
-/obj/effect/overlay/temp/ratvar/wall/false
- layer = OBJ_LAYER
-
-/obj/effect/overlay/temp/ratvar/floor
- icon_state = "ratvarfloorglow"
-
-/obj/effect/overlay/temp/ratvar/floor/catwalk
- layer = LATTICE_LAYER
-
-/obj/effect/overlay/temp/ratvar/window
- icon_state = "ratvarwindowglow"
- layer = ABOVE_OBJ_LAYER
-
-/obj/effect/overlay/temp/ratvar/window/single
- icon_state = "ratvarwindowglow_s"
-
-/obj/effect/overlay/temp/ratvar/gear
- icon_state = "ratvargearglow"
- layer = BELOW_OBJ_LAYER
-
-/obj/effect/overlay/temp/ratvar/grille
- icon_state = "ratvargrilleglow"
- layer = BELOW_OBJ_LAYER
-
-/obj/effect/overlay/temp/ratvar/grille/broken
- icon_state = "ratvarbrokengrilleglow"
-
-/obj/effect/overlay/temp/ratvar/mending_mantra
- layer = ABOVE_MOB_LAYER
- duration = 20
- alpha = 200
- icon_state = "mending_mantra"
- light_range = 1.5
- light_color = "#1E8CE1"
-
-/obj/effect/overlay/temp/ratvar/mending_mantra/Initialize(mapload)
- . = ..()
- transform = matrix()*2
- var/matrix/M = transform
- M.Turn(90)
- animate(src, alpha = 20, time = duration, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
- animate(src, transform = M, time = duration, flags = ANIMATION_PARALLEL)
-
-/obj/effect/overlay/temp/ratvar/volt_hit
- name = "volt blast"
- layer = ABOVE_MOB_LAYER
- duration = 5
- icon_state = "volt_hit"
- light_range = 1.5
- light_power = 2
- light_color = LIGHT_COLOR_ORANGE
- var/mob/user
- var/damage = 20
-
-/obj/effect/overlay/temp/ratvar/volt_hit/Initialize(mapload, caster, multiplier)
- if(multiplier)
- damage *= multiplier
- duration = max(round(damage * 0.2), 1)
- . = ..()
-
-/obj/effect/overlay/temp/ratvar/volt_hit/true/Initialize(mapload, caster, multiplier)
- . = ..()
- user = caster
- if(user)
- var/matrix/M = new
- M.Turn(Get_Angle(src, user))
- transform = M
- INVOKE_ASYNC(src, .proc/volthit)
-
-/obj/effect/overlay/temp/ratvar/volt_hit/proc/volthit()
- if(user)
- Beam(get_turf(user), "volt_ray", time=duration, maxdistance=8, beam_type=/obj/effect/ebeam/volt_ray)
- var/hit_amount = 0
- var/turf/T = get_turf(src)
- for(var/mob/living/L in T)
- if(is_servant_of_ratvar(L))
- continue
- var/obj/item/I = L.null_rod_check()
- if(I)
- L.visible_message("Strange energy flows into [L]'s [I.name]!", \
- "Your [I.name] shields you from [src]!")
- continue
- L.visible_message("[L] is struck by a [name]!", "You're struck by a [name]!")
- L.apply_damage(damage, BURN, "chest", L.run_armor_check("chest", "laser", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 0, "Your armor was penetrated by [src]!"))
- add_logs(user, L, "struck with a volt blast")
- hit_amount++
- for(var/obj/mecha/M in T)
- if(M.occupant)
- if(is_servant_of_ratvar(M.occupant))
- continue
- to_chat(M.occupant, "Your [M.name] is struck by a [name]!")
- M.visible_message("[M] is struck by a [name]!")
- M.take_damage(damage, BURN, 0, 0)
- hit_amount++
- if(hit_amount)
- playsound(src, 'sound/machines/defib_zap.ogg', damage*hit_amount, 1, -1)
- else
- playsound(src, "sparks", 50, 1)
-
-/obj/effect/overlay/temp/ratvar/ocular_warden
- name = "warden's gaze"
- layer = ABOVE_MOB_LAYER
- icon_state = "warden_gaze"
- duration = 3
-
-/obj/effect/overlay/temp/ratvar/ocular_warden/Initialize()
- . = ..()
- pixel_x = rand(-8, 8)
- pixel_y = rand(-10, 10)
- animate(src, alpha = 0, time = 3, easing = EASE_OUT)
-
-/obj/effect/overlay/temp/ratvar/spearbreak
- icon = 'icons/effects/64x64.dmi'
- icon_state = "ratvarspearbreak"
- layer = BELOW_MOB_LAYER
- pixel_y = -16
- pixel_x = -16
-
-/obj/effect/overlay/temp/ratvar/geis_binding
- icon_state = "geisbinding"
-
-/obj/effect/overlay/temp/ratvar/geis_binding/top
- icon_state = "geisbinding_top"
-
-/obj/effect/overlay/temp/ratvar/component
- icon = 'icons/obj/clockwork_objects.dmi'
- icon_state = "belligerent_eye"
- layer = ABOVE_MOB_LAYER
- duration = 10
-
-/obj/effect/overlay/temp/ratvar/component/Initialize()
- . = ..()
- transform = matrix()*0.75
- pixel_x = rand(-10, 10)
- pixel_y = rand(-10, -2)
- animate(src, pixel_y = pixel_y + 10, alpha = 50, time = 10, easing = EASE_OUT)
-
-/obj/effect/overlay/temp/ratvar/component/cogwheel
- icon_state = "vanguard_cogwheel"
-
-/obj/effect/overlay/temp/ratvar/component/capacitor
- icon_state = "geis_capacitor"
-
-/obj/effect/overlay/temp/ratvar/component/alloy
- icon_state = "replicant_alloy"
-
-/obj/effect/overlay/temp/ratvar/component/ansible
- icon_state = "hierophant_ansible"
-
-/obj/effect/overlay/temp/ratvar/sigil
- name = "glowing circle"
- icon_state = "sigildull"
-
-/obj/effect/overlay/temp/ratvar/sigil/transgression
- color = "#FAE48C"
- layer = ABOVE_MOB_LAYER
- duration = 70
- light_range = 5
- light_power = 2
- light_color = "#FAE48C"
-
-/obj/effect/overlay/temp/ratvar/sigil/transgression/Initialize()
- . = ..()
- var/oldtransform = transform
- animate(src, transform = matrix()*2, time = 5)
- animate(transform = oldtransform, alpha = 0, time = 65)
-
-/obj/effect/overlay/temp/ratvar/sigil/vitality
- color = "#1E8CE1"
- icon_state = "sigilactivepulse"
- layer = ABOVE_MOB_LAYER
- light_range = 1.4
- light_power = 0.5
- light_color = "#1E8CE1"
-
-/obj/effect/overlay/temp/ratvar/sigil/accession
- color = "#AF0AAF"
- layer = ABOVE_MOB_LAYER
- duration = 70
- icon_state = "sigilactiveoverlay"
- alpha = 0
-
-
-/obj/effect/overlay/temp/revenant
- name = "spooky lights"
- icon_state = "purplesparkles"
-
-/obj/effect/overlay/temp/revenant/cracks
- name = "glowing cracks"
- icon_state = "purplecrack"
- duration = 6
-
-
-/obj/effect/overlay/temp/gravpush
- name = "gravity wave"
- icon_state = "shieldsparkles"
- duration = 5
-
-/obj/effect/overlay/temp/telekinesis
- name = "telekinetic force"
- icon_state = "empdisable"
- duration = 5
-
-/obj/effect/overlay/temp/emp
- name = "emp sparks"
- icon_state = "empdisable"
-
-/obj/effect/overlay/temp/emp/pulse
- name = "emp pulse"
- icon_state = "emppulse"
- duration = 8
- randomdir = 0
-
-/obj/effect/overlay/temp/gib_animation
- icon = 'icons/mob/mob.dmi'
- duration = 15
-
-/obj/effect/overlay/temp/gib_animation/Initialize(mapload, gib_icon)
- icon_state = gib_icon // Needs to be before ..() so icon is correct
- . = ..()
-
-/obj/effect/overlay/temp/gib_animation/ex_act(severity)
- return //so the overlay isn't deleted by the explosion that gibbed the mob.
-
-/obj/effect/overlay/temp/gib_animation/animal
- icon = 'icons/mob/animal.dmi'
-
-/obj/effect/overlay/temp/dust_animation
- icon = 'icons/mob/mob.dmi'
- duration = 15
-
-/obj/effect/overlay/temp/dust_animation/Initialize(mapload, dust_icon)
- icon_state = dust_icon // Before ..() so the correct icon is flick()'d
- . = ..()
-
-/obj/effect/overlay/temp/mummy_animation
- icon = 'icons/mob/mob.dmi'
- icon_state = "mummy_revive"
- duration = 20
-
-/obj/effect/overlay/temp/heal //color is white by default, set to whatever is needed
- name = "healing glow"
- icon_state = "heal"
- duration = 15
-
-/obj/effect/overlay/temp/heal/Initialize(mapload, colour)
- if(colour)
- color = colour
- . = ..()
- pixel_x = rand(-12, 12)
- pixel_y = rand(-9, 0)
-
-/obj/effect/overlay/temp/kinetic_blast
- name = "kinetic explosion"
- icon = 'icons/obj/projectiles.dmi'
- icon_state = "kinetic_blast"
- layer = ABOVE_ALL_MOB_LAYER
- duration = 4
-
-/obj/effect/overlay/temp/explosion
- name = "explosion"
- icon = 'icons/effects/96x96.dmi'
- icon_state = "explosion"
- pixel_x = -32
- pixel_y = -32
- duration = 8
-
-/obj/effect/overlay/temp/explosion/fast
- icon_state = "explosionfast"
- duration = 4
-
-/obj/effect/overlay/temp/blob
- name = "blob"
- icon_state = "blob_attack"
- alpha = 140
- randomdir = 0
- duration = 6
-
-/obj/effect/overlay/temp/impact_effect
- icon_state = "impact_bullet"
- duration = 5
-
-/obj/effect/overlay/temp/impact_effect/Initialize(mapload, atom/target, obj/item/projectile/P)
- if(target == P.original) //the projectile hit the target originally clicked
- pixel_x = P.p_x + target.pixel_x - 16 + rand(-4,4)
- pixel_y = P.p_y + target.pixel_y - 16 + rand(-4,4)
- else
- pixel_x = target.pixel_x + rand(-4,4)
- pixel_y = target.pixel_y + rand(-4,4)
- . = ..()
-
-/obj/effect/overlay/temp/impact_effect/red_laser
- icon_state = "impact_laser"
- duration = 4
-
-/obj/effect/overlay/temp/impact_effect/red_laser/wall
- icon_state = "impact_laser_wall"
- duration = 10
-
-/obj/effect/overlay/temp/impact_effect/blue_laser
- icon_state = "impact_laser_blue"
- duration = 4
-
-/obj/effect/overlay/temp/impact_effect/green_laser
- icon_state = "impact_laser_green"
- duration = 4
-
-/obj/effect/overlay/temp/impact_effect/purple_laser
- icon_state = "impact_laser_purple"
- duration = 4
-
-/obj/effect/overlay/temp/impact_effect/ion
- icon_state = "shieldsparkles"
- duration = 6
-
-/obj/effect/overlay/temp/heart
- name = "heart"
- icon = 'icons/mob/animal.dmi'
- icon_state = "heart"
- duration = 25
-
-/obj/effect/overlay/temp/heart/Initialize(mapload)
- . = ..()
- pixel_x = rand(-4,4)
- pixel_y = rand(-4,4)
-
- animate(src, pixel_y = pixel_y + 32, alpha = 0, time = 25)
-
/obj/effect/overlay/palmtree_r
name = "Palm tree"
icon = 'icons/misc/beach2.dmi'
diff --git a/code/game/objects/effects/temporary_visuals/clockcult.dm b/code/game/objects/effects/temporary_visuals/clockcult.dm
new file mode 100644
index 0000000000..65c9d30e47
--- /dev/null
+++ b/code/game/objects/effects/temporary_visuals/clockcult.dm
@@ -0,0 +1,218 @@
+//temporary visual effects(/obj/effect/overlay/temp) used by clockcult stuff
+/obj/effect/overlay/temp/ratvar
+ name = "ratvar's light"
+ icon = 'icons/effects/clockwork_effects.dmi'
+ duration = 8
+ randomdir = 0
+ layer = ABOVE_NORMAL_TURF_LAYER
+
+/obj/effect/overlay/temp/ratvar/door
+ icon_state = "ratvardoorglow"
+ layer = CLOSED_DOOR_LAYER //above closed doors
+
+/obj/effect/overlay/temp/ratvar/door/window
+ icon_state = "ratvarwindoorglow"
+ layer = ABOVE_WINDOW_LAYER
+
+/obj/effect/overlay/temp/ratvar/beam
+ icon_state = "ratvarbeamglow"
+
+/obj/effect/overlay/temp/ratvar/beam/door
+ layer = CLOSED_DOOR_LAYER
+
+/obj/effect/overlay/temp/ratvar/beam/grille
+ layer = BELOW_OBJ_LAYER
+
+/obj/effect/overlay/temp/ratvar/beam/itemconsume
+ layer = HIGH_OBJ_LAYER
+
+/obj/effect/overlay/temp/ratvar/beam/falsewall
+ layer = OBJ_LAYER
+
+/obj/effect/overlay/temp/ratvar/beam/catwalk
+ layer = LATTICE_LAYER
+
+/obj/effect/overlay/temp/ratvar/wall
+ icon_state = "ratvarwallglow"
+
+/obj/effect/overlay/temp/ratvar/wall/false
+ layer = OBJ_LAYER
+
+/obj/effect/overlay/temp/ratvar/floor
+ icon_state = "ratvarfloorglow"
+
+/obj/effect/overlay/temp/ratvar/floor/catwalk
+ layer = LATTICE_LAYER
+
+/obj/effect/overlay/temp/ratvar/window
+ icon_state = "ratvarwindowglow"
+ layer = ABOVE_OBJ_LAYER
+
+/obj/effect/overlay/temp/ratvar/window/single
+ icon_state = "ratvarwindowglow_s"
+
+/obj/effect/overlay/temp/ratvar/gear
+ icon_state = "ratvargearglow"
+ layer = BELOW_OBJ_LAYER
+
+/obj/effect/overlay/temp/ratvar/grille
+ icon_state = "ratvargrilleglow"
+ layer = BELOW_OBJ_LAYER
+
+/obj/effect/overlay/temp/ratvar/grille/broken
+ icon_state = "ratvarbrokengrilleglow"
+
+/obj/effect/overlay/temp/ratvar/mending_mantra
+ layer = ABOVE_MOB_LAYER
+ duration = 20
+ alpha = 200
+ icon_state = "mending_mantra"
+ light_range = 1.5
+ light_color = "#1E8CE1"
+
+/obj/effect/overlay/temp/ratvar/mending_mantra/Initialize(mapload)
+ . = ..()
+ transform = matrix()*2
+ var/matrix/M = transform
+ M.Turn(90)
+ animate(src, alpha = 20, time = duration, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
+ animate(src, transform = M, time = duration, flags = ANIMATION_PARALLEL)
+
+/obj/effect/overlay/temp/ratvar/volt_hit
+ name = "volt blast"
+ layer = ABOVE_MOB_LAYER
+ duration = 5
+ icon_state = "volt_hit"
+ light_range = 1.5
+ light_power = 2
+ light_color = LIGHT_COLOR_ORANGE
+ var/mob/user
+ var/damage = 20
+
+/obj/effect/overlay/temp/ratvar/volt_hit/Initialize(mapload, caster, multiplier)
+ if(multiplier)
+ damage *= multiplier
+ duration = max(round(damage * 0.2), 1)
+ . = ..()
+
+/obj/effect/overlay/temp/ratvar/volt_hit/true/Initialize(mapload, caster, multiplier)
+ . = ..()
+ user = caster
+ if(user)
+ var/matrix/M = new
+ M.Turn(Get_Angle(src, user))
+ transform = M
+ INVOKE_ASYNC(src, .proc/volthit)
+
+/obj/effect/overlay/temp/ratvar/volt_hit/proc/volthit()
+ if(user)
+ Beam(get_turf(user), "volt_ray", time=duration, maxdistance=8, beam_type=/obj/effect/ebeam/volt_ray)
+ var/hit_amount = 0
+ var/turf/T = get_turf(src)
+ for(var/mob/living/L in T)
+ if(is_servant_of_ratvar(L))
+ continue
+ var/obj/item/I = L.null_rod_check()
+ if(I)
+ L.visible_message("Strange energy flows into [L]'s [I.name]!", \
+ "Your [I.name] shields you from [src]!")
+ continue
+ L.visible_message("[L] is struck by a [name]!", "You're struck by a [name]!")
+ L.apply_damage(damage, BURN, "chest", L.run_armor_check("chest", "laser", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 0, "Your armor was penetrated by [src]!"))
+ add_logs(user, L, "struck with a volt blast")
+ hit_amount++
+ for(var/obj/mecha/M in T)
+ if(M.occupant)
+ if(is_servant_of_ratvar(M.occupant))
+ continue
+ to_chat(M.occupant, "Your [M.name] is struck by a [name]!")
+ M.visible_message("[M] is struck by a [name]!")
+ M.take_damage(damage, BURN, 0, 0)
+ hit_amount++
+ if(hit_amount)
+ playsound(src, 'sound/machines/defib_zap.ogg', damage*hit_amount, 1, -1)
+ else
+ playsound(src, "sparks", 50, 1)
+
+/obj/effect/overlay/temp/ratvar/ocular_warden
+ name = "warden's gaze"
+ layer = ABOVE_MOB_LAYER
+ icon_state = "warden_gaze"
+ duration = 3
+
+/obj/effect/overlay/temp/ratvar/ocular_warden/Initialize()
+ . = ..()
+ pixel_x = rand(-8, 8)
+ pixel_y = rand(-10, 10)
+ animate(src, alpha = 0, time = 3, easing = EASE_OUT)
+
+/obj/effect/overlay/temp/ratvar/spearbreak
+ icon = 'icons/effects/64x64.dmi'
+ icon_state = "ratvarspearbreak"
+ layer = BELOW_MOB_LAYER
+ pixel_y = -16
+ pixel_x = -16
+
+/obj/effect/overlay/temp/ratvar/geis_binding
+ icon_state = "geisbinding"
+
+/obj/effect/overlay/temp/ratvar/geis_binding/top
+ icon_state = "geisbinding_top"
+
+/obj/effect/overlay/temp/ratvar/component
+ icon = 'icons/obj/clockwork_objects.dmi'
+ icon_state = "belligerent_eye"
+ layer = ABOVE_MOB_LAYER
+ duration = 10
+
+/obj/effect/overlay/temp/ratvar/component/Initialize()
+ . = ..()
+ transform = matrix()*0.75
+ pixel_x = rand(-10, 10)
+ pixel_y = rand(-10, -2)
+ animate(src, pixel_y = pixel_y + 10, alpha = 50, time = 10, easing = EASE_OUT)
+
+/obj/effect/overlay/temp/ratvar/component/cogwheel
+ icon_state = "vanguard_cogwheel"
+
+/obj/effect/overlay/temp/ratvar/component/capacitor
+ icon_state = "geis_capacitor"
+
+/obj/effect/overlay/temp/ratvar/component/alloy
+ icon_state = "replicant_alloy"
+
+/obj/effect/overlay/temp/ratvar/component/ansible
+ icon_state = "hierophant_ansible"
+
+/obj/effect/overlay/temp/ratvar/sigil
+ name = "glowing circle"
+ icon_state = "sigildull"
+
+/obj/effect/overlay/temp/ratvar/sigil/transgression
+ color = "#FAE48C"
+ layer = ABOVE_MOB_LAYER
+ duration = 70
+ light_range = 5
+ light_power = 2
+ light_color = "#FAE48C"
+
+/obj/effect/overlay/temp/ratvar/sigil/transgression/Initialize()
+ . = ..()
+ var/oldtransform = transform
+ animate(src, transform = matrix()*2, time = 5)
+ animate(transform = oldtransform, alpha = 0, time = 65)
+
+/obj/effect/overlay/temp/ratvar/sigil/vitality
+ color = "#1E8CE1"
+ icon_state = "sigilactivepulse"
+ layer = ABOVE_MOB_LAYER
+ light_range = 1.4
+ light_power = 0.5
+ light_color = "#1E8CE1"
+
+/obj/effect/overlay/temp/ratvar/sigil/accession
+ color = "#AF0AAF"
+ layer = ABOVE_MOB_LAYER
+ duration = 70
+ icon_state = "sigilactiveoverlay"
+ alpha = 0
diff --git a/code/game/objects/effects/temporary_visuals/cult.dm b/code/game/objects/effects/temporary_visuals/cult.dm
new file mode 100644
index 0000000000..ad3f84fe06
--- /dev/null
+++ b/code/game/objects/effects/temporary_visuals/cult.dm
@@ -0,0 +1,144 @@
+//temporary visual effects(/obj/effect/overlay/temp) used by cult stuff
+/obj/effect/overlay/temp/cult
+ icon = 'icons/effects/cult_effects.dmi'
+ randomdir = 0
+ duration = 10
+
+/obj/effect/overlay/temp/cult/sparks
+ randomdir = 1
+ name = "blood sparks"
+ icon_state = "bloodsparkles"
+
+/obj/effect/overlay/temp/cult/blood // The traditional teleport
+ name = "blood jaunt"
+ duration = 12
+ icon_state = "bloodin"
+
+/obj/effect/overlay/temp/cult/blood/out
+ icon_state = "bloodout"
+
+/obj/effect/overlay/temp/dir_setting/cult/phase // The veil shifter teleport
+ name = "phase glow"
+ duration = 7
+ icon_state = "cultin"
+
+/obj/effect/overlay/temp/dir_setting/cult/phase/out
+ icon_state = "cultout"
+
+/obj/effect/overlay/temp/cult/sac
+ name = "maw of Nar-Sie"
+ icon_state = "sacconsume"
+
+/obj/effect/overlay/temp/cult/door
+ name = "unholy glow"
+ icon_state = "doorglow"
+ layer = CLOSED_FIREDOOR_LAYER //above closed doors
+
+/obj/effect/overlay/temp/cult/door/unruned
+ icon_state = "unruneddoorglow"
+
+/obj/effect/overlay/temp/cult/turf
+ name = "unholy glow"
+ icon_state = "wallglow"
+ layer = ABOVE_NORMAL_TURF_LAYER
+
+/obj/effect/overlay/temp/cult/turf/floor
+ icon_state = "floorglow"
+ duration = 5
+
+//visuals for runes being magically created
+/obj/effect/overlay/temp/cult/rune_spawn
+ icon_state = "runeouter"
+ alpha = 0
+ var/turnedness = 179 //179 turns counterclockwise, 181 turns clockwise
+
+/obj/effect/overlay/temp/cult/rune_spawn/Initialize(mapload, set_duration, set_color)
+ if(isnum(set_duration))
+ duration = set_duration
+ if(set_color)
+ add_atom_colour(set_color, FIXED_COLOUR_PRIORITY)
+ . = ..()
+ var/oldtransform = transform
+ transform = matrix()*2
+ var/matrix/M = transform
+ M.Turn(turnedness)
+ transform = M
+ animate(src, alpha = 255, time = duration, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
+ animate(src, transform = oldtransform, time = duration, flags = ANIMATION_PARALLEL)
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune1
+ icon_state = "rune1words"
+ turnedness = 181
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune1/inner
+ icon_state = "rune1inner"
+ turnedness = 179
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune1/center
+ icon_state = "rune1center"
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune2
+ icon_state = "rune2words"
+ turnedness = 181
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune2/inner
+ icon_state = "rune2inner"
+ turnedness = 179
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune2/center
+ icon_state = "rune2center"
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune3
+ icon_state = "rune3words"
+ turnedness = 181
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune3/inner
+ icon_state = "rune3inner"
+ turnedness = 179
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune3/center
+ icon_state = "rune3center"
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune4
+ icon_state = "rune4words"
+ turnedness = 181
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune4/inner
+ icon_state = "rune4inner"
+ turnedness = 179
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune4/center
+ icon_state = "rune4center"
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune5
+ icon_state = "rune5words"
+ turnedness = 181
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune5/inner
+ icon_state = "rune5inner"
+ turnedness = 179
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune5/center
+ icon_state = "rune5center"
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune6
+ icon_state = "rune6words"
+ turnedness = 181
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune6/inner
+ icon_state = "rune6inner"
+ turnedness = 179
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune6/center
+ icon_state = "rune6center"
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune7
+ icon_state = "rune7words"
+ turnedness = 181
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune7/inner
+ icon_state = "rune7inner"
+ turnedness = 179
+
+/obj/effect/overlay/temp/cult/rune_spawn/rune7/center
+ icon_state = "rune7center"
diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
new file mode 100644
index 0000000000..2ceea0aced
--- /dev/null
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -0,0 +1,312 @@
+//unsorted miscellaneous temporary visuals
+/obj/effect/overlay/temp/dir_setting/bloodsplatter
+ icon = 'icons/effects/blood.dmi'
+ duration = 5
+ randomdir = FALSE
+ layer = BELOW_MOB_LAYER
+ var/splatter_type = "splatter"
+
+/obj/effect/overlay/temp/dir_setting/bloodsplatter/Initialize(mapload, set_dir)
+ if(set_dir in GLOB.diagonals)
+ icon_state = "[splatter_type][pick(1, 2, 6)]"
+ else
+ icon_state = "[splatter_type][pick(3, 4, 5)]"
+ . = ..()
+ var/target_pixel_x = 0
+ var/target_pixel_y = 0
+ switch(set_dir)
+ if(NORTH)
+ target_pixel_y = 16
+ if(SOUTH)
+ target_pixel_y = -16
+ layer = ABOVE_MOB_LAYER
+ if(EAST)
+ target_pixel_x = 16
+ if(WEST)
+ target_pixel_x = -16
+ if(NORTHEAST)
+ target_pixel_x = 16
+ target_pixel_y = 16
+ if(NORTHWEST)
+ target_pixel_x = -16
+ target_pixel_y = 16
+ if(SOUTHEAST)
+ target_pixel_x = 16
+ target_pixel_y = -16
+ layer = ABOVE_MOB_LAYER
+ if(SOUTHWEST)
+ target_pixel_x = -16
+ target_pixel_y = -16
+ layer = ABOVE_MOB_LAYER
+ animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration)
+
+/obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter
+ splatter_type = "xsplatter"
+
+/obj/effect/overlay/temp/dir_setting/speedbike_trail
+ name = "speedbike trails"
+ icon_state = "ion_fade"
+ layer = BELOW_MOB_LAYER
+ duration = 10
+ randomdir = 0
+
+/obj/effect/overlay/temp/dir_setting/firing_effect
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "firing_effect"
+ duration = 2
+
+/obj/effect/overlay/temp/dir_setting/firing_effect/setDir(newdir)
+ switch(newdir)
+ if(NORTH)
+ layer = BELOW_MOB_LAYER
+ pixel_x = rand(-3,3)
+ pixel_y = rand(4,6)
+ if(SOUTH)
+ pixel_x = rand(-3,3)
+ pixel_y = rand(-1,1)
+ else
+ pixel_x = rand(-1,1)
+ pixel_y = rand(-1,1)
+ ..()
+
+/obj/effect/overlay/temp/dir_setting/firing_effect/energy
+ icon_state = "firing_effect_energy"
+ duration = 3
+
+/obj/effect/overlay/temp/dir_setting/firing_effect/magic
+ icon_state = "shieldsparkles"
+ duration = 3
+
+/obj/effect/overlay/temp/dir_setting/ninja
+ name = "ninja shadow"
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "uncloak"
+ duration = 9
+
+/obj/effect/overlay/temp/dir_setting/ninja/cloak
+ icon_state = "cloak"
+
+/obj/effect/overlay/temp/dir_setting/ninja/shadow
+ icon_state = "shadow"
+
+/obj/effect/overlay/temp/dir_setting/ninja/phase
+ name = "ninja energy"
+ icon_state = "phasein"
+
+/obj/effect/overlay/temp/dir_setting/ninja/phase/out
+ icon_state = "phaseout"
+
+/obj/effect/overlay/temp/dir_setting/wraith
+ name = "blood"
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "phase_shift2"
+ duration = 12
+
+/obj/effect/overlay/temp/dir_setting/wraith/out
+ icon_state = "phase_shift"
+
+/obj/effect/overlay/temp/dir_setting/tailsweep
+ icon_state = "tailsweep"
+ duration = 4
+
+/obj/effect/overlay/temp/wizard
+ name = "water"
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "reappear"
+ duration = 5
+
+/obj/effect/overlay/temp/wizard/out
+ icon_state = "liquify"
+ duration = 12
+
+/obj/effect/overlay/temp/monkeyify
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "h2monkey"
+ duration = 22
+
+/obj/effect/overlay/temp/monkeyify/humanify
+ icon_state = "monkey2h"
+
+/obj/effect/overlay/temp/borgflash
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "blspell"
+ duration = 5
+
+/obj/effect/overlay/temp/guardian
+ randomdir = 0
+
+/obj/effect/overlay/temp/guardian/phase
+ duration = 5
+ icon_state = "phasein"
+
+/obj/effect/overlay/temp/guardian/phase/out
+ icon_state = "phaseout"
+
+/obj/effect/overlay/temp/decoy
+ desc = "It's a decoy!"
+ duration = 15
+
+/obj/effect/overlay/temp/decoy/Initialize(mapload, atom/mimiced_atom)
+ . = ..()
+ alpha = initial(alpha)
+ if(mimiced_atom)
+ name = mimiced_atom.name
+ appearance = mimiced_atom.appearance
+ setDir(mimiced_atom.dir)
+ mouse_opacity = 0
+
+/obj/effect/overlay/temp/decoy/fading/Initialize(mapload, atom/mimiced_atom)
+ . = ..()
+ animate(src, alpha = 0, time = duration)
+
+/obj/effect/overlay/temp/decoy/fading/fivesecond
+ duration = 50
+
+/obj/effect/overlay/temp/small_smoke
+ icon_state = "smoke"
+ duration = 50
+
+/obj/effect/overlay/temp/fire
+ icon = 'icons/effects/fire.dmi'
+ icon_state = "3"
+ duration = 20
+
+/obj/effect/overlay/temp/revenant
+ name = "spooky lights"
+ icon_state = "purplesparkles"
+
+/obj/effect/overlay/temp/revenant/cracks
+ name = "glowing cracks"
+ icon_state = "purplecrack"
+ duration = 6
+
+/obj/effect/overlay/temp/gravpush
+ name = "gravity wave"
+ icon_state = "shieldsparkles"
+ duration = 5
+
+/obj/effect/overlay/temp/telekinesis
+ name = "telekinetic force"
+ icon_state = "empdisable"
+ duration = 5
+
+/obj/effect/overlay/temp/emp
+ name = "emp sparks"
+ icon_state = "empdisable"
+
+/obj/effect/overlay/temp/emp/pulse
+ name = "emp pulse"
+ icon_state = "emppulse"
+ duration = 8
+ randomdir = 0
+
+/obj/effect/overlay/temp/gib_animation
+ icon = 'icons/mob/mob.dmi'
+ duration = 15
+
+/obj/effect/overlay/temp/gib_animation/Initialize(mapload, gib_icon)
+ icon_state = gib_icon // Needs to be before ..() so icon is correct
+ . = ..()
+
+/obj/effect/overlay/temp/gib_animation/animal
+ icon = 'icons/mob/animal.dmi'
+
+/obj/effect/overlay/temp/dust_animation
+ icon = 'icons/mob/mob.dmi'
+ duration = 15
+
+/obj/effect/overlay/temp/dust_animation/Initialize(mapload, dust_icon)
+ icon_state = dust_icon // Before ..() so the correct icon is flick()'d
+ . = ..()
+
+/obj/effect/overlay/temp/mummy_animation
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "mummy_revive"
+ duration = 20
+
+/obj/effect/overlay/temp/heal //color is white by default, set to whatever is needed
+ name = "healing glow"
+ icon_state = "heal"
+ duration = 15
+
+/obj/effect/overlay/temp/heal/Initialize(mapload, set_color)
+ if(set_color)
+ add_atom_colour(set_color, FIXED_COLOUR_PRIORITY)
+ . = ..()
+ pixel_x = rand(-12, 12)
+ pixel_y = rand(-9, 0)
+
+/obj/effect/overlay/temp/kinetic_blast
+ name = "kinetic explosion"
+ icon = 'icons/obj/projectiles.dmi'
+ icon_state = "kinetic_blast"
+ layer = ABOVE_ALL_MOB_LAYER
+ duration = 4
+
+/obj/effect/overlay/temp/explosion
+ name = "explosion"
+ icon = 'icons/effects/96x96.dmi'
+ icon_state = "explosion"
+ pixel_x = -32
+ pixel_y = -32
+ duration = 8
+
+/obj/effect/overlay/temp/explosion/fast
+ icon_state = "explosionfast"
+ duration = 4
+
+/obj/effect/overlay/temp/blob
+ name = "blob"
+ icon_state = "blob_attack"
+ alpha = 140
+ randomdir = 0
+ duration = 6
+
+/obj/effect/overlay/temp/impact_effect
+ icon_state = "impact_bullet"
+ duration = 5
+
+/obj/effect/overlay/temp/impact_effect/Initialize(mapload, atom/target, obj/item/projectile/P)
+ if(target == P.original) //the projectile hit the target originally clicked
+ pixel_x = P.p_x + target.pixel_x - 16 + rand(-4,4)
+ pixel_y = P.p_y + target.pixel_y - 16 + rand(-4,4)
+ else
+ pixel_x = target.pixel_x + rand(-4,4)
+ pixel_y = target.pixel_y + rand(-4,4)
+ . = ..()
+
+/obj/effect/overlay/temp/impact_effect/red_laser
+ icon_state = "impact_laser"
+ duration = 4
+
+/obj/effect/overlay/temp/impact_effect/red_laser/wall
+ icon_state = "impact_laser_wall"
+ duration = 10
+
+/obj/effect/overlay/temp/impact_effect/blue_laser
+ icon_state = "impact_laser_blue"
+ duration = 4
+
+/obj/effect/overlay/temp/impact_effect/green_laser
+ icon_state = "impact_laser_green"
+ duration = 4
+
+/obj/effect/overlay/temp/impact_effect/purple_laser
+ icon_state = "impact_laser_purple"
+ duration = 4
+
+/obj/effect/overlay/temp/impact_effect/ion
+ icon_state = "shieldsparkles"
+ duration = 6
+
+/obj/effect/overlay/temp/heart
+ name = "heart"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "heart"
+ duration = 25
+
+/obj/effect/overlay/temp/heart/Initialize(mapload)
+ . = ..()
+ pixel_x = rand(-4,4)
+ pixel_y = rand(-4,4)
+ animate(src, pixel_y = pixel_y + 32, alpha = 0, time = 25)
diff --git a/code/game/objects/effects/temporary_visuals/temporary_visual.dm b/code/game/objects/effects/temporary_visuals/temporary_visual.dm
new file mode 100644
index 0000000000..8c7a178bd6
--- /dev/null
+++ b/code/game/objects/effects/temporary_visuals/temporary_visual.dm
@@ -0,0 +1,37 @@
+//temporary visual effects
+/obj/effect/overlay/temp
+ icon_state = "nothing"
+ anchored = 1
+ layer = ABOVE_MOB_LAYER
+ mouse_opacity = 0
+ var/duration = 10 //in deciseconds
+ var/randomdir = TRUE
+ var/timerid
+
+/obj/effect/overlay/temp/Initialize()
+ . = ..()
+ if(randomdir)
+ setDir(pick(GLOB.cardinal))
+
+ timerid = QDEL_IN(src, duration)
+
+/obj/effect/overlay/temp/Destroy()
+ . = ..()
+ deltimer(timerid)
+
+/obj/effect/overlay/temp/singularity_act()
+ return
+
+/obj/effect/overlay/temp/singularity_pull()
+ return
+
+/obj/effect/overlay/temp/ex_act()
+ return
+
+/obj/effect/overlay/temp/dir_setting
+ randomdir = FALSE
+
+/obj/effect/overlay/temp/dir_setting/Initialize(mapload, set_dir)
+ if(set_dir)
+ setDir(set_dir)
+ . = ..()
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 16910e05a6..fd119bf878 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -34,7 +34,7 @@
var/area/A = get_area(src)
if(A)
- var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/effects.dmi', "ghostalertsie")
+ var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/cult_effects.dmi', "ghostalertsie")
notify_ghosts("Nar-Sie has risen in \the [A.name]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, action=NOTIFY_ATTACK)
INVOKE_ASYNC(src, .proc/narsie_spawn_animation)
diff --git a/icons/effects/cult_effects.dmi b/icons/effects/cult_effects.dmi
new file mode 100644
index 0000000000..58a2d3c9c9
Binary files /dev/null and b/icons/effects/cult_effects.dmi differ
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index fe537a8e73..eab44acdd7 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 64d7bb0231..b9f0293318 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -33,6 +33,7 @@
#include "code\__DEFINES\combat.dm"
#include "code\__DEFINES\construction.dm"
#include "code\__DEFINES\contracts.dm"
+#include "code\__DEFINES\cult.dm"
#include "code\__DEFINES\DNA.dm"
#include "code\__DEFINES\events.dm"
#include "code\__DEFINES\flags.dm"
@@ -469,6 +470,7 @@
#include "code\game\gamemodes\cult\cult_items.dm"
#include "code\game\gamemodes\cult\cult_structures.dm"
#include "code\game\gamemodes\cult\ritual.dm"
+#include "code\game\gamemodes\cult\rune_spawn_action.dm"
#include "code\game\gamemodes\cult\runes.dm"
#include "code\game\gamemodes\cult\supply.dm"
#include "code\game\gamemodes\cult\talisman.dm"
@@ -728,6 +730,10 @@
#include "code\game\objects\effects\spawners\structure.dm"
#include "code\game\objects\effects\spawners\vaultspawner.dm"
#include "code\game\objects\effects\spawners\xeno_egg_delivery.dm"
+#include "code\game\objects\effects\temporary_visuals\clockcult.dm"
+#include "code\game\objects\effects\temporary_visuals\cult.dm"
+#include "code\game\objects\effects\temporary_visuals\miscellaneous.dm"
+#include "code\game\objects\effects\temporary_visuals\temporary_visual.dm"
#include "code\game\objects\items\apc_frame.dm"
#include "code\game\objects\items\blueprints.dm"
#include "code\game\objects\items\body_egg.dm"