diff --git a/code/controllers/subsystems/initialization/map_finalization.dm b/code/controllers/subsystems/initialization/map_finalization.dm
index 6efb4161bab..58806ccc9b8 100644
--- a/code/controllers/subsystems/initialization/map_finalization.dm
+++ b/code/controllers/subsystems/initialization/map_finalization.dm
@@ -102,7 +102,8 @@
if (!maploader.load_map(file(mfile), 0, 0, no_changeturf = TRUE))
log_ss("finalize", "Failed to load '[mfile]'!")
else
- log_ss("atlas", "Loaded space ruin in [(world.time - time)/10] seconds.")
+ log_ss("finalize", "Loaded space ruin on z [world.maxz] in [(world.time - time)/10] seconds.")
+ current_map.restricted_levels.Add(world.maxz)
QDEL_NULL(maploader)
/datum/controller/subsystem/finalize/proc/place_dungeon_spawns()
diff --git a/code/controllers/subsystems/initialization/misc_late.dm b/code/controllers/subsystems/initialization/misc_late.dm
index 7653f912727..59f743bdf03 100644
--- a/code/controllers/subsystems/initialization/misc_late.dm
+++ b/code/controllers/subsystems/initialization/misc_late.dm
@@ -17,7 +17,7 @@
teleportlocs += AR.name
teleportlocs[AR.name] = AR
- if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom))
+ if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom))
ghostteleportlocs += AR.name
ghostteleportlocs[AR.name] = AR
diff --git a/code/modules/mob/abstract/observer/observer.dm b/code/modules/mob/abstract/observer/observer.dm
index a4fe78afe21..2ef9afb252a 100644
--- a/code/modules/mob/abstract/observer/observer.dm
+++ b/code/modules/mob/abstract/observer/observer.dm
@@ -159,6 +159,47 @@ Works together with spawning an observer, noted above.
if(medHUD)
process_medHUD(src)
+ teleport_if_needed()
+
+/mob/abstract/observer/proc/on_restricted_level(var/check)
+ if(!check)
+ check = z
+ //Check if they are a staff member
+ if(check_rights(R_MOD|R_ADMIN|R_DEV, show_msg=FALSE, user=src))
+ return FALSE
+
+ //Check if the z level is in the restricted list
+ if (!(check in current_map.restricted_levels))
+ return FALSE
+
+ return TRUE
+
+/mob/abstract/observer/proc/teleport_to_spawn(var/message)
+ if(!message)
+ message = "You can not freely observe on this z-level."
+
+ //Teleport them back to the ghost spawn
+ var/obj/O = locate("landmark*Observer-Start")
+ if(istype(O))
+ to_chat(src, "[message]")
+ forceMove(O.loc)
+
+//Teleports the observer away from z-levels they shouldnt be on, if needed.
+/mob/abstract/observer/proc/teleport_if_needed()
+ if(!on_restricted_level())
+ return
+
+ if(following)
+ if(!iscarbon(following)) //If they are following something other than a carbon mob, teleport them
+ stop_following()
+ teleport_to_spawn("You can not follow \the [following] on this level.")
+ else
+ return
+ //If they are moving around freely, teleport them
+ teleport_to_spawn()
+ //And update their sight settings
+ updateghostsight()
+
/mob/abstract/observer/proc/process_medHUD(var/mob/M)
var/client/C = M.client
@@ -328,8 +369,15 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(!L || !L.len)
if(holyblock)
to_chat(usr, "This area has been entirely made into sacred grounds, you cannot enter it while you are in this plane of existence!")
+ return
else
to_chat(usr, "No area available.")
+ return
+
+ var/turf/P = pick(L)
+ if(on_restricted_level(P.z))
+ to_chat(usr, "You can not teleport to this area")
+ return
stop_following()
usr.forceMove(pick(L))
@@ -355,6 +403,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(src, "Now following \the [following]")
move_to_destination(following, following.loc, following.loc)
+ updateghostsight()
/mob/abstract/observer/proc/stop_following()
if(following)
@@ -362,10 +411,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
moved_event.unregister(following, src)
destroyed_event.unregister(following, src)
following = null
+
/mob/abstract/observer/move_to_destination(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(check_holy(T))
+ stop_following()
+ teleport_if_needed()
to_chat(usr, "You cannot follow something standing on holy grounds!")
return
..()
@@ -394,21 +446,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
forceMove(T)
else
to_chat(src, "This mob is not located in the game world.")
-/*
-/mob/abstract/observer/verb/boo()
- set category = "Ghost"
- set name = "Boo!"
- set desc= "Scare your crew members because of boredom!"
-
- if(bootime > world.time) return
- var/obj/machinery/light/L = locate(/obj/machinery/light) in view(1, src)
- if(L)
- L.flicker()
- bootime = world.time + 600
- return
- //Maybe in the future we can add more spooky code here!
- return
-*/
+
+ teleport_if_needed()
/mob/abstract/observer/memory()
set hidden = 1
@@ -420,6 +459,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/abstract/observer/Post_Incorpmove()
stop_following()
+ teleport_if_needed()
/mob/abstract/observer/verb/analyze_air()
set name = "Analyze Air"
@@ -839,12 +879,25 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
updateghostsight()
/mob/abstract/observer/proc/updateghostsight()
- if (!seedarkness)
- see_invisible = SEE_INVISIBLE_NOLIGHTING
- else
+ //if they are on a restricted level, then set the ghost vision for them.
+ if(on_restricted_level())
+ //On the restricted level they have the same sight as the mob
+ sight &= ~(SEE_TURFS | SEE_MOBS | SEE_OBJS)
+ see_in_dark = 2
see_invisible = SEE_INVISIBLE_OBSERVER
- if (!ghostvision)
- see_invisible = SEE_INVISIBLE_LIVING;
+ else
+ //Outside of the restrcited level, they have enhanced vision
+ sight |= (SEE_TURFS | SEE_MOBS | SEE_OBJS)
+ see_in_dark = 100
+ see_invisible = SEE_INVISIBLE_LEVEL_TWO
+
+ if (!seedarkness)
+ see_invisible = SEE_INVISIBLE_NOLIGHTING
+ else
+ see_invisible = SEE_INVISIBLE_OBSERVER
+ if (!ghostvision)
+ see_invisible = SEE_INVISIBLE_LIVING
+
updateghostimages()
/proc/updateallghostimages()
diff --git a/html/changelogs/arrow768.yml b/html/changelogs/arrow768.yml
new file mode 100644
index 00000000000..e6e6147f8ba
--- /dev/null
+++ b/html/changelogs/arrow768.yml
@@ -0,0 +1,41 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+# balance
+# admin
+# backend
+# security
+# refactor
+#################################
+
+# Your name.
+author: Arrow768
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - tweak: "Ghost are no longer able to freely move around on the derelict. They can follow human mobs on the drelict tough."
diff --git a/maps/_common/mapsystem/map.dm b/maps/_common/mapsystem/map.dm
index fd5ab9d110f..5fda01c0117 100644
--- a/maps/_common/mapsystem/map.dm
+++ b/maps/_common/mapsystem/map.dm
@@ -8,6 +8,7 @@
var/list/contact_levels = list() // Z-levels that can be contacted from the station, for eg announcements
var/list/player_levels = list() // Z-levels a character can typically reach
var/list/sealed_levels = list() // Z-levels that don't allow random transit at edge
+ var/list/restricted_levels = list() // Z-levels that dont allow ghosts to randomly move around
var/list/map_levels // Z-levels available to various consoles, such as the crew monitor. Defaults to station_levels if unset.
diff --git a/maps/aurora/code/aurora.dm b/maps/aurora/code/aurora.dm
index 370fd90416d..e469ce668e7 100644
--- a/maps/aurora/code/aurora.dm
+++ b/maps/aurora/code/aurora.dm
@@ -9,6 +9,7 @@
admin_levels = list(1)
contact_levels = list(3, 4, 5, 6)
player_levels = list(2, 3, 4, 5, 6, 7, 8)
+ restricted_levels = list()
accessible_z_levels = list("8" = 10, "7" = 15, "2" = 60)
base_turf_by_z = list(
"1" = /turf/space,