diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index b61c1224794..86f5ffa1a9b 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -21,6 +21,7 @@
var/antagHUD = 0
universal_speak = 1
var/atom/movable/following = null
+
/mob/dead/observer/New(mob/body)
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
see_invisible = SEE_INVISIBLE_OBSERVER
@@ -496,3 +497,78 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
dat += data_core.get_manifest()
src << browse(dat, "window=manifest;size=370x420;can_close=1")
+
+//Used for drawing on walls with blood puddles as a spooky ghost.
+/mob/dead/verb/bloody_doodle()
+
+ set category = "Ghost"
+ set name = "Write in blood"
+ set desc = "If the round is sufficiently spooky, write a short message in blood on the floor or a wall. Remember, no IC in OOC or OOC in IC."
+
+ if(!(config.cult_ghostwriter))
+ src << "\red That verb is not currently permitted."
+ return
+
+ if (!src.stat)
+ return
+
+ if (usr != src)
+ return 0 //something is terribly wrong
+
+ var/ghosts_can_write
+ if(ticker.mode.name == "cult")
+ var/datum/game_mode/cult/C = ticker.mode
+ if(C.cult.len > config.cult_ghostwriter_req_cultists)
+ ghosts_can_write = 1
+
+ if(!ghosts_can_write)
+ src << "\red The veil is not thin enough for you to do that."
+ return
+
+ var/list/choices = list()
+ for(var/obj/effect/decal/cleanable/blood/B in view(1,src))
+ if(B.amount > 0)
+ choices += B
+
+ if(!choices.len)
+ src << "There is no blood to use nearby."
+ return
+
+ var/obj/effect/decal/cleanable/blood/choice = input(src,"What blood would you like to use?") in null|choices
+
+ var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West")
+ var/turf/simulated/T = src.loc
+ if (direction != "Here")
+ T = get_step(T,text2dir(direction))
+
+ if (!istype(T))
+ src << "You cannot doodle there."
+ return
+
+ if(!choice || choice.amount == 0 || !(src.Adjacent(choice)))
+ return
+
+ var/doodle_color = (choice.basecolor) ? choice.basecolor : "#A10808"
+
+ var/num_doodles = 0
+ for (var/obj/effect/decal/cleanable/blood/writing/W in T)
+ num_doodles++
+ if (num_doodles > 4)
+ src << "There is no space to write on!"
+ return
+
+ var/max_length = 50
+
+ var/message = stripped_input(src,"Write a message. It cannot be longer than [max_length] characters.","Blood writing", "")
+
+ if (message)
+
+ if (length(message) > max_length)
+ message += "-"
+ src << "You ran out of blood to write with!"
+
+ var/obj/effect/decal/cleanable/blood/writing/W = new(T)
+ W.basecolor = doodle_color
+ W.update_icon()
+ W.message = message
+ W.add_hiddenprint(src)
\ No newline at end of file