diff --git a/code/datums/components/stationstuck.dm b/code/datums/components/stationstuck.dm
index b9027ef8115..615d6ff79a6 100644
--- a/code/datums/components/stationstuck.dm
+++ b/code/datums/components/stationstuck.dm
@@ -1,38 +1,60 @@
+
+#define PUNISHMENT_MURDER "murder"
+#define PUNISHMENT_GIB "gib"
+#define PUNISHMENT_TELEPORT "teleport"
+
//very similar to stationloving, but more made for mobs and not objects. used on derelict drones currently
+
+
+/*
+This component is similar to stationloving in that it is meant to keep something on the z-level
+The difference is that stationloving is for objects and stationstuck is for mobs.
+It has a punishment variable that is what happens to the parent when they leave the z-level. See punish() documentation
+*/
/datum/component/stationstuck
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
- var/murder = TRUE //teleports if not
+ var/punishment = PUNISHMENT_GIB //see defines above
var/stuck_zlevel
var/message = ""
-/datum/component/stationstuck/Initialize(_murder = TRUE, _message = "")
+/datum/component/stationstuck/Initialize(_punishment = PUNISHMENT_GIB, _message = "")
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
var/mob/living/L = parent
RegisterSignal(L, list(COMSIG_MOVABLE_Z_CHANGED), .proc/punish)
- murder = _murder
+ punishment = _punishment
message = _message
-
stuck_zlevel = L.z
-/datum/component/stationstuck/InheritComponent(datum/component/stationstuck/newc, original, _murder, _message)
+/datum/component/stationstuck/InheritComponent(datum/component/stationstuck/newc, original, _punishment, _message)
if(newc)
- murder = newc.murder
+ punishment = newc.punishment
message = newc.message
else
- murder = _murder
+ punishment = _punishment
message = _message
+/**
+ * Called when parent leaves the zlevel this is set to (aka whichever zlevel it was on when it was added)
+ * Sends a message, then does an effect depending on what the punishment was.
+ *
+ * Punishments:
+ * * PUNISHMENT_MURDER: kills parent
+ * * PUNISHMENT_GIB: gibs parent
+ * * PUNISHMENT_TELEPORT: finds a safe turf if possible, or a completely random one if not.
+ */
/datum/component/stationstuck/proc/punish()
var/mob/living/L = parent
if(message)
- var/span = murder ? "userdanger" : "danger"
+ var/span = punishment == PUNISHMENT_TELEPORT ? "danger" : "userdanger"
to_chat(L, "[message]")
- if(murder)
- L.gib()
- return
- var/targetturf = find_safe_turf(stuck_zlevel)
- if(!targetturf)
- targetturf = locate(world.maxx/2,world.maxy/2,stuck_zlevel)
- L.forceMove(targetturf)
- return targetturf
+ switch(punishment)
+ if(PUNISHMENT_MURDER)
+ L.death()
+ if(PUNISHMENT_GIB)
+ L.gib()
+ if(PUNISHMENT_TELEPORT)
+ var/targetturf = find_safe_turf(stuck_zlevel)
+ if(!targetturf)
+ targetturf = locate(world.maxx/2,world.maxy/2,stuck_zlevel)
+ L.forceMove(targetturf)
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index 62f9efaae8c..17085337550 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -724,3 +724,174 @@
belt = /obj/item/storage/belt/military/assault
id = /obj/item/card/id/syndicate_command/captain_id
backpack_contents = list(/obj/item/documents/syndicate/red, /obj/item/paper/fluff/ruins/forgottenship/password, /obj/item/gun/ballistic/automatic/pistol/aps)
+
+/obj/effect/mob_spawn/human/beach/alive
+ death = FALSE
+ roundstart = FALSE
+ random = TRUE
+ mob_name = "Beach Bum"
+ name = "beach bum sleeper"
+ icon = 'icons/obj/machines/sleeper.dmi'
+ icon_state = "sleeper"
+ short_desc = "You're, like, totally a dudebro, bruh."
+ flavour_text = "Ch'yea. You came here, like, on spring break, hopin' to pick up some bangin' hot chicks, y'knaw?"
+ assignedrole = "Beach Bum"
+
+/obj/effect/mob_spawn/human/beach/alive/lifeguard
+ short_desc = "You're a spunky lifeguard!"
+ flavour_text = "It's up to you to make sure nobody drowns or gets eaten by sharks and stuff."
+ mob_gender = "female"
+ name = "lifeguard sleeper"
+ id_job = "Lifeguard"
+ uniform = /obj/item/clothing/under/shorts/red
+
+/datum/outfit/beachbum
+ name = "Beach Bum"
+ glasses = /obj/item/clothing/glasses/sunglasses
+ r_pocket = /obj/item/storage/wallet/random
+ l_pocket = /obj/item/reagent_containers/food/snacks/pizzaslice/dank;
+ uniform = /obj/item/clothing/under/pants/youngfolksjeans
+ id = /obj/item/card/id
+
+/datum/outfit/beachbum/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ . = ..()
+ if(visualsOnly)
+ return
+ H.dna.add_mutation(STONER)
+
+/obj/effect/mob_spawn/human/bartender/alive
+ death = FALSE
+ roundstart = FALSE
+ random = TRUE
+ name = "bartender sleeper"
+ icon = 'icons/obj/machines/sleeper.dmi'
+ icon_state = "sleeper"
+ short_desc = "You are a space bartender!"
+ flavour_text = "Time to mix drinks and change lives. Smoking space drugs makes it easier to understand your patrons' odd dialect."
+ assignedrole = "Space Bartender"
+ id_job = "Bartender"
+
+/datum/outfit/spacebartender
+ name = "Space Bartender"
+ uniform = /obj/item/clothing/under/rank/civilian/bartender
+ back = /obj/item/storage/backpack
+ shoes = /obj/item/clothing/shoes/sneakers/black
+ suit = /obj/item/clothing/suit/armor/vest
+ glasses = /obj/item/clothing/glasses/sunglasses/reagent
+ id = /obj/item/card/id
+
+/datum/outfit/spacebartender/post_equip(mob/living/carbon/human/H, visualsOnly)
+ . = ..()
+ var/obj/item/card/id/id_card = H.wear_id
+ if(H.age < AGE_MINOR)
+ id_card.registered_age = AGE_MINOR
+ to_chat(H, "You're not technically old enough to access or serve alcohol, but your ID has been discreetly modified to display your age as [AGE_MINOR]. Try to keep that a secret!")
+
+/obj/effect/mob_spawn/human/skeleton/alive
+ death = FALSE
+ roundstart = FALSE
+ icon = 'icons/effects/blood.dmi'
+ icon_state = "remains"
+ short_desc = "By unknown powers, your skeletal remains have been reanimated!"
+ flavour_text = "Walk this mortal plane and terrorize all living adventurers who dare cross your path."
+ assignedrole = "Skeleton"
+
+/obj/effect/mob_spawn/human/skeleton/alive/special(mob/living/new_spawn)
+ to_chat(new_spawn, "You have this horrible lurching feeling deep down that your binding to this world will fail if you abandon this zone... Were you reanimated to protect something?")
+ new_spawn.AddComponent(/datum/component/stationstuck, PUNISHMENT_MURDER, "You experience a feeling like a stressed twine being pulled until it snaps. Then, merciful nothing.")
+
+/obj/effect/mob_spawn/human/zombie/alive
+ death = FALSE
+ roundstart = FALSE
+ icon = 'icons/effects/blood.dmi'
+ icon_state = "remains"
+ short_desc = "By unknown powers, your rotting remains have been resurrected!"
+ flavour_text = "Walk this mortal plane and terrorize all living adventurers who dare cross your path."
+
+/obj/effect/mob_spawn/human/zombie/alive/special(mob/living/new_spawn)
+ to_chat(new_spawn, "You have this horrible lurching feeling deep down that your binding to this world will fail if you abandon this zone... Were you reanimated to protect something?")
+ new_spawn.AddComponent(/datum/component/stationstuck, PUNISHMENT_MURDER, "You experience a feeling like a stressed twine being pulled until it snaps. Then, merciful nothing.")
+
+//terribly basic spawns below, please read the disclaimer. unless you're an admin. these are perfect for events as they have no intro text.
+
+//if you're going to use these in a map of some kind, add GUIDANCE or stationstuck component to them on spawn. see ash walkers and skeletons for an example of each. they're simply not very fleshed out.
+//if this is in your map, the player will have no idea what to do so will just go to the station and kill people until a policy headache arises
+
+//For ghost bar.
+/obj/effect/mob_spawn/human/alive/space_bar_patron
+ name = "Bar cryogenics"
+ mob_name = "Bar patron"
+ random = TRUE
+ permanent = TRUE
+ uses = -1
+ outfit = /datum/outfit/spacebartender
+ assignedrole = "Space Bar Patron"
+
+/obj/effect/mob_spawn/human/alive/space_bar_patron/attack_hand(mob/user)
+ var/despawn = alert("Return to cryosleep? (Warning, Your mob will be deleted!)", null, "Yes", "No")
+ if(despawn == "No" || !loc || !Adjacent(user))
+ return
+ user.visible_message("[user.name] climbs back into cryosleep...")
+ qdel(user)
+
+/datum/outfit/cryobartender
+ name = "Cryogenic Bartender"
+ uniform = /obj/item/clothing/under/rank/civilian/bartender
+ back = /obj/item/storage/backpack
+ shoes = /obj/item/clothing/shoes/sneakers/black
+ suit = /obj/item/clothing/suit/armor/vest
+ glasses = /obj/item/clothing/glasses/sunglasses/reagent
+
+/obj/effect/mob_spawn/human/nanotrasensoldier/alive
+ death = FALSE
+ roundstart = FALSE
+ mob_name = "Private Security Officer"
+ name = "sleeper"
+ icon = 'icons/obj/machines/sleeper.dmi'
+ icon_state = "sleeper"
+ faction = "nanotrasenprivate"
+ short_desc = "You are a Nanotrasen Private Security Officer!"
+
+/obj/effect/mob_spawn/human/commander/alive
+ death = FALSE
+ roundstart = FALSE
+ mob_name = "\improper Nanotrasen Commander"
+ name = "sleeper"
+ icon = 'icons/obj/machines/sleeper.dmi'
+ icon_state = "sleeper"
+ short_desc = "You are a Nanotrasen Commander!"
+
+/obj/effect/mob_spawn/human/doctor/alive
+ death = FALSE
+ roundstart = FALSE
+ random = TRUE
+ name = "sleeper"
+ icon = 'icons/obj/machines/sleeper.dmi'
+ icon_state = "sleeper"
+ short_desc = "You are a space doctor!"
+ assignedrole = "Space Doctor"
+
+/obj/effect/mob_spawn/human/doctor/alive/equip(mob/living/carbon/human/doctor)
+ . = ..()
+ // Remove radio and PDA so they wouldn't annoy station crew.
+ var/list/del_types = list(/obj/item/pda, /obj/item/radio/headset)
+ for(var/del_type in del_types)
+ var/obj/item/unwanted_item = locate(del_type) in doctor
+ qdel(unwanted_item)
+
+/obj/effect/mob_spawn/mouse
+ name = "sleeper"
+ mob_type = /mob/living/simple_animal/mouse
+ death = FALSE
+ roundstart = FALSE
+ icon = 'icons/obj/machines/sleeper.dmi'
+ icon_state = "sleeper"
+
+/obj/effect/mob_spawn/cow
+ name = "sleeper"
+ mob_type = /mob/living/simple_animal/cow
+ death = FALSE
+ roundstart = FALSE
+ mob_gender = FEMALE
+ icon = 'icons/obj/machines/sleeper.dmi'
+ icon_state = "sleeper"
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index b9a1c4e571b..d4480c422b7 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -2,6 +2,9 @@
//To do: Allow corpses to appear mangled, bloody, etc. Allow customizing the bodies appearance (they're all bald and white right now).
+
+//HEY! LISTEN! anything that is ALIVE and thus GHOSTS CAN TAKE is in ghost_role_spawners.dm!
+
/obj/effect/mob_spawn
name = "Mob Spawner"
density = TRUE
@@ -252,6 +255,7 @@
/obj/effect/mob_spawn/human/corpse/damaged
brute_damage = 1000
+//i left this here despite being a mob spawner because this is a base type
/obj/effect/mob_spawn/human/alive
icon = 'icons/obj/machines/sleeper.dmi'
icon_state = "sleeper"
@@ -291,23 +295,6 @@
O.Die() //call the facehugger's death proc
qdel(src)
-/obj/effect/mob_spawn/mouse
- name = "sleeper"
- mob_type = /mob/living/simple_animal/mouse
- death = FALSE
- roundstart = FALSE
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
-
-/obj/effect/mob_spawn/cow
- name = "sleeper"
- mob_type = /mob/living/simple_animal/cow
- death = FALSE
- roundstart = FALSE
- mob_gender = FEMALE
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
-
// I'll work on making a list of corpses people request for maps, or that I think will be commonly used. Syndicate operatives for example.
///////////Civilians//////////////////////
@@ -336,31 +323,11 @@
outfit = /datum/outfit/job/cook
icon_state = "corpsecook"
-
/obj/effect/mob_spawn/human/doctor
name = "Doctor"
outfit = /datum/outfit/job/doctor
icon_state = "corpsedoctor"
-
-/obj/effect/mob_spawn/human/doctor/alive
- death = FALSE
- roundstart = FALSE
- random = TRUE
- name = "sleeper"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- short_desc = "You are a space doctor!"
- assignedrole = "Space Doctor"
-
-/obj/effect/mob_spawn/human/doctor/alive/equip(mob/living/carbon/human/H)
- ..()
- // Remove radio and PDA so they wouldn't annoy station crew.
- var/list/del_types = list(/obj/item/pda, /obj/item/radio/headset)
- for(var/del_type in del_types)
- var/obj/item/I = locate(del_type) in H
- qdel(I)
-
/obj/effect/mob_spawn/human/engineer
name = "Engineer"
outfit = /datum/outfit/job/engineer/gloved
@@ -390,84 +357,19 @@
/obj/effect/mob_spawn/human/miner/explorer
outfit = /datum/outfit/job/miner/equipped
-
/obj/effect/mob_spawn/human/plasmaman
mob_species = /datum/species/plasmaman
outfit = /datum/outfit/plasmaman
-
/obj/effect/mob_spawn/human/bartender
name = "Space Bartender"
id_job = "Bartender"
id_access_list = list(ACCESS_BAR)
outfit = /datum/outfit/spacebartender
-/obj/effect/mob_spawn/human/bartender/alive
- death = FALSE
- roundstart = FALSE
- random = TRUE
- name = "bartender sleeper"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- short_desc = "You are a space bartender!"
- flavour_text = "Time to mix drinks and change lives. Smoking space drugs makes it easier to understand your patrons' odd dialect."
- assignedrole = "Space Bartender"
- id_job = "Bartender"
-
-/datum/outfit/spacebartender
- name = "Space Bartender"
- uniform = /obj/item/clothing/under/rank/civilian/bartender
- back = /obj/item/storage/backpack
- shoes = /obj/item/clothing/shoes/sneakers/black
- suit = /obj/item/clothing/suit/armor/vest
- glasses = /obj/item/clothing/glasses/sunglasses/reagent
- id = /obj/item/card/id
-
-/datum/outfit/spacebartender/post_equip(mob/living/carbon/human/H, visualsOnly)
- . = ..()
-
- var/obj/item/card/id/W = H.wear_id
- if(H.age < AGE_MINOR)
- W.registered_age = AGE_MINOR
- to_chat(H, "You're not technically old enough to access or serve alcohol, but your ID has been discreetly modified to display your age as [AGE_MINOR]. Try to keep that a secret!")
-
/obj/effect/mob_spawn/human/beach
outfit = /datum/outfit/beachbum
-/obj/effect/mob_spawn/human/beach/alive
- death = FALSE
- roundstart = FALSE
- random = TRUE
- mob_name = "Beach Bum"
- name = "beach bum sleeper"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- short_desc = "You're, like, totally a dudebro, bruh."
- flavour_text = "Ch'yea. You came here, like, on spring break, hopin' to pick up some bangin' hot chicks, y'knaw?"
- assignedrole = "Beach Bum"
-
-/obj/effect/mob_spawn/human/beach/alive/lifeguard
- short_desc = "You're a spunky lifeguard!"
- flavour_text = "It's up to you to make sure nobody drowns or gets eaten by sharks and stuff."
- mob_gender = "female"
- name = "lifeguard sleeper"
- id_job = "Lifeguard"
- uniform = /obj/item/clothing/under/shorts/red
-
-/datum/outfit/beachbum
- name = "Beach Bum"
- glasses = /obj/item/clothing/glasses/sunglasses
- r_pocket = /obj/item/storage/wallet/random
- l_pocket = /obj/item/reagent_containers/food/snacks/pizzaslice/dank;
- uniform = /obj/item/clothing/under/pants/youngfolksjeans
- id = /obj/item/card/id
-
-/datum/outfit/beachbum/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
- ..()
- if(visualsOnly)
- return
- H.dna.add_mutation(STONER)
-
/////////////////Officers+Nanotrasen Security//////////////////////
/obj/effect/mob_spawn/human/bridgeofficer
@@ -485,7 +387,6 @@
glasses = /obj/item/clothing/glasses/sunglasses
id = /obj/item/card/id
-
/obj/effect/mob_spawn/human/commander
name = "Commander"
id_job = "Commander"
@@ -505,7 +406,6 @@
r_pocket = /obj/item/lighter
id = /obj/item/card/id
-
/obj/effect/mob_spawn/human/nanotrasensoldier
name = "\improper Nanotrasen Private Security Officer"
id_job = "Private Security Force"
@@ -523,28 +423,8 @@
back = /obj/item/storage/backpack/security
id = /obj/item/card/id
-
-/obj/effect/mob_spawn/human/commander/alive
- death = FALSE
- roundstart = FALSE
- mob_name = "\improper Nanotrasen Commander"
- name = "sleeper"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- short_desc = "You are a Nanotrasen Commander!"
-
-/obj/effect/mob_spawn/human/nanotrasensoldier/alive
- death = FALSE
- roundstart = FALSE
- mob_name = "Private Security Officer"
- name = "sleeper"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- faction = "nanotrasenprivate"
- short_desc = "You are a Nanotrasen Private Security Officer!"
-
-
/////////////////Spooky Undead//////////////////////
+//there are living variants of many of these, they're now in ghost_role_spawners.dm
/obj/effect/mob_spawn/human/skeleton
name = "skeletal remains"
@@ -552,30 +432,12 @@
mob_species = /datum/species/skeleton
mob_gender = NEUTER
-/obj/effect/mob_spawn/human/skeleton/alive
- death = FALSE
- roundstart = FALSE
- icon = 'icons/effects/blood.dmi'
- icon_state = "remains"
- short_desc = "By unknown powers, your skeletal remains have been reanimated!"
- flavour_text = "Walk this mortal plain and terrorize all living adventurers who dare cross your path."
- assignedrole = "Skeleton"
-
/obj/effect/mob_spawn/human/zombie
name = "rotting corpse"
mob_name = "zombie"
mob_species = /datum/species/zombie
assignedrole = "Zombie"
-/obj/effect/mob_spawn/human/zombie/alive
- death = FALSE
- roundstart = FALSE
- icon = 'icons/effects/blood.dmi'
- icon_state = "remains"
- short_desc = "By unknown powers, your rotting remains have been resurrected!"
- flavour_text = "Walk this mortal plain and terrorize all living adventurers who dare cross your path."
-
-
/obj/effect/mob_spawn/human/abductor
name = "abductor"
mob_name = "alien"
@@ -586,30 +448,3 @@
name = "Abductor Corpse"
uniform = /obj/item/clothing/under/color/grey
shoes = /obj/item/clothing/shoes/combat
-
-
-//For ghost bar.
-/obj/effect/mob_spawn/human/alive/space_bar_patron
- name = "Bar cryogenics"
- mob_name = "Bar patron"
- random = TRUE
- permanent = TRUE
- uses = -1
- outfit = /datum/outfit/spacebartender
- assignedrole = "Space Bar Patron"
-
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/effect/mob_spawn/human/alive/space_bar_patron/attack_hand(mob/user)
- var/despawn = alert("Return to cryosleep? (Warning, Your mob will be deleted!)",,"Yes","No")
- if(despawn == "No" || !loc || !Adjacent(user))
- return
- user.visible_message("[user.name] climbs back into cryosleep...")
- qdel(user)
-
-/datum/outfit/cryobartender
- name = "Cryogenic Bartender"
- uniform = /obj/item/clothing/under/rank/civilian/bartender
- back = /obj/item/storage/backpack
- shoes = /obj/item/clothing/shoes/sneakers/black
- suit = /obj/item/clothing/suit/armor/vest
- glasses = /obj/item/clothing/glasses/sunglasses/reagent
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
index d77cc98cae4..0b3eee0384f 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
@@ -129,7 +129,7 @@
/mob/living/simple_animal/drone/derelict/Initialize()
. = ..()
- AddComponent(/datum/component/stationstuck, TRUE, "Your emergency station return device activates, sending you back to KS13!", "01000110 01010101 01000011 01001011 00100000 01011001 01001111 01010101
WARNING: Dereliction of KS13 detected. Self-destruct activated.")
+ AddComponent(/datum/component/stationstuck, PUNISHMENT_GIB, "01000110 01010101 01000011 01001011 00100000 01011001 01001111 01010101
WARNING: Dereliction of KS13 detected. Self-destruct activated.")