diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index 671bf0540b8..9a7cd21ce3f 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -13,7 +13,8 @@
// Otherwise jump
else
- loc = get_turf(A)
+ following = null
+ forceMove(get_turf(A))
/mob/dead/observer/ClickOn(var/atom/A, var/params)
if(client.buildmode)
@@ -33,28 +34,6 @@
// Not all of them require checking, see below
A.attack_ghost(src)
-
-// This is the ghost's follow verb with an argument
-/mob/dead/observer/proc/ManualFollow(var/atom/target)
- following = target
- if(target)
- src << "\blue Now following [target]"
- spawn(0)
- var/turf/pos = get_turf(src)
- while(loc == pos && target && following == target)
-
- var/turf/T = get_turf(target)
- if(!T)
- break
- if(following != target)
- break
- if(!client)
- break
- loc = T
- pos = loc
- sleep(15)
- following = null
-
// We don't need a fucking toggle.
/mob/dead/observer/ShiftClickOn(var/atom/A)
A.examine()
@@ -71,33 +50,20 @@
if(S)
var/obj/machinery/computer/teleporter/com = S.teleporter_console
if(com && com.target)
- user.loc = get_turf(com.target)
+ user.forceMove(get_turf(com.target))
/obj/effect/portal/attack_ghost(mob/user as mob)
if(target)
- user.loc = get_turf(target)
+ user.forceMove(get_turf(target))
/obj/machinery/gateway/centerstation/attack_ghost(mob/user as mob)
if(awaygate)
- user.loc = awaygate.loc
+ user.forceMove(awaygate.loc)
else
user << "[src] has no destination."
/obj/machinery/gateway/centeraway/attack_ghost(mob/user as mob)
if(stationgate)
- user.loc = stationgate.loc
+ user.forceMove(stationgate.loc)
else
user << "[src] has no destination."
-
-// -------------------------------------------
-// This was supposed to be used by adminghosts
-// I think it is a *terrible* idea
-// but I'm leaving it here anyway
-// commented out, of course.
-
-/atom/proc/attack_admin(mob/user as mob)
- if(!user || !user.client || !user.client.holder)
- return
- attack_hand(user)
-
-
diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm
index ca47ab1afc7..e7c77f639f3 100644
--- a/code/modules/awaymissions/gateway.dm
+++ b/code/modules/awaymissions/gateway.dm
@@ -125,13 +125,13 @@ obj/machinery/gateway/centerstation/process()
if(!awaygate) return
if(awaygate.calibrated)
- M.loc = get_step(awaygate.loc, SOUTH)
+ M.forceMove(get_step(awaygate.loc, SOUTH))
M.dir = SOUTH
return
else
var/obj/effect/landmark/dest = pick(awaydestinations)
if(dest)
- M.loc = dest.loc
+ M.forceMove(dest.loc)
M.dir = SOUTH
use_power(5000)
return
@@ -230,7 +230,7 @@ obj/machinery/gateway/centerstation/process()
if(E.imp_in == M)//Checking that it's actually implanted vs just in their pocket
M << "\black The station gate has detected your exile implant and is blocking your entry."
return
- M.loc = get_step(stationgate.loc, SOUTH)
+ M.forceMove(get_step(stationgate.loc, SOUTH))
M.dir = SOUTH
@@ -242,4 +242,5 @@ obj/machinery/gateway/centerstation/process()
else
user << "Recalibration successful!: \black This gate's systems have been fine tuned. Travel to this gate will now be on target."
calibrated = 1
- return
\ No newline at end of file
+ return
+
\ No newline at end of file
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 6a2722470b2..3c61d7c2f6e 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -79,7 +79,7 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi
mind = body.mind //we don't transfer the mind but we keep a reference to it.
if(!T) T = pick(latejoin) //Safety in case we cannot find the body's position
- loc = T
+ forceMove(T)
if(!name) //To prevent nameless ghosts
name = capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names))
@@ -96,12 +96,12 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi
/mob/dead/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
return 1
+
+
/*
Transfer_mind is there to check if mob is being deleted/not going to have a body.
Works together with spawning an observer, noted above.
*/
-
-
/mob/dead/observer/Life()
..()
if(!loc) return
@@ -200,10 +200,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
-/mob/dead/observer/Move(NewLoc, direct)
+/mob/dead/observer/Move(NewLoc, direct)
+ following = null
dir = direct
if(NewLoc)
- loc = NewLoc
+ forceMove(NewLoc)
for(var/obj/effect/step_trigger/S in NewLoc)
S.Crossed(src)
@@ -212,7 +213,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
A.Entered(src)
return
- loc = get_turf(src) //Get out of closets and such as a ghost
+ forceMove(get_turf(src)) //Get out of closets and such as a ghost
if((direct & NORTH) && y < world.maxy)
y++
else if((direct & SOUTH) && y > 1)
@@ -228,6 +229,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/area/A = get_area_master(src)
if(A)
A.Entered(src)
+
+ ..()
/mob/dead/observer/experience_pressure_difference()
return 0
@@ -326,7 +329,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
M.antagHUD = 1
src << "\blue AntagHUD Enabled"
-/mob/dead/observer/proc/dead_tele()
+/mob/dead/observer/proc/dead_tele(A in ghostteleportlocs)
set category = "Ghost"
set name = "Teleport"
set desc= "Teleport to a location"
@@ -338,73 +341,107 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
usr.verbs -= /mob/dead/observer/proc/dead_tele
spawn(30)
usr.verbs += /mob/dead/observer/proc/dead_tele
- var/A
- A = input("Area to jump to", "BOOYEA", A) as null|anything in ghostteleportlocs
+
var/area/thearea = ghostteleportlocs[A]
if(!thearea) return
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
- L+=T
+ L += T
if(!L || !L.len)
- usr << "No area available."
+ usr << "No area available."
usr.forceMove(pick(L))
+ following = null
-/mob/dead/observer/verb/follow()
+/mob/dead/observer/verb/follow(input in getmobs())
set category = "Ghost"
set name = "Follow" // "Haunt"
set desc = "Follow and haunt a mob."
- if(istype(usr, /mob/dead/observer))
- var/list/mobs = getmobs()
- var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs
- var/mob/target = mobs[input]
- if(target && target != usr)
- following = target
- spawn(0)
- var/turf/pos = get_turf(src)
- while(src.loc == pos)
+ var/target = getmobs()[input]
+ if(!target) return
+ ManualFollow(target)
+// This is the ghost's follow verb with an argument
+/mob/dead/observer/proc/ManualFollow(var/atom/movable/target)
+ if(!target)
+ return
+
+ if(target != src)
+ if(following && following == target)
+ return
+ following = target
+ src << "Now following [target]"
+ if(ismob(target))
+ forceMove(get_turf(target))
+ var/mob/M = target
+ M.following_mobs += src
+ else
+ spawn(0)
+ while(target && following == target && client)
var/turf/T = get_turf(target)
if(!T)
break
- if(following != target)
- break
- if(!client)
- break
- src.loc = T
- pos = src.loc
+ // To stop the ghost flickering.
+ if(loc != T)
+ forceMove(T)
sleep(15)
- following = null
+/mob/proc/update_following()
+ . = get_turf(src)
+ for(var/mob/dead/observer/M in following_mobs)
+ if(M.following != src)
+ following_mobs -= M
+ else
+ if(M.loc != .)
+ M.forceMove(.)
-/mob/dead/observer/verb/jumptomob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak
+/mob
+ var/list/following_mobs = list()
+
+/mob/Destroy()
+ for(var/mob/dead/observer/M in following_mobs)
+ M.following = null
+ following_mobs = null
+ return ..()
+
+/mob/dead/observer/Destroy()
+ if(ismob(following))
+ var/mob/M = following
+ M.following_mobs -= src
+ following = null
+ return ..()
+
+/mob/Move()
+ . = ..()
+ if(.)
+ update_following()
+
+/mob/Life()
+ // to catch teleports etc which directly set loc
+ update_following()
+ return ..()
+
+/mob/dead/observer/verb/jumptomob(target in getmobs()) //Moves the ghost instead of just changing the ghosts's eye -Nodrak
set category = "Ghost"
set name = "Jump to Mob"
set desc = "Teleport to a mob"
if(istype(usr, /mob/dead/observer)) //Make sure they're an observer!
-
- var/list/dest = list() //List of possible destinations (mobs)
- var/target = null //Chosen target.
-
- dest += getmobs() //Fill list, prompt user with list
- target = input("Please, select a player!", "Jump to Mob", null, null) as null|anything in dest
-
if (!target)//Make sure we actually have a target
return
else
- var/mob/M = dest[target] //Destination mob
- var/mob/A = src //Source mob
+ var/mob/M = getmobs()[target] //Destination mob
var/turf/T = get_turf(M) //Turf of the destination mob
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
- A.loc = T
+ forceMove(T)
+ following = null
else
- A << "This mob is not located in the game world."
+ src << "This mob is not located in the game world."
/* Now a spell. See spells.dm
@@ -548,7 +585,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
if(!client)
return
- loc = T
+ forceMove(T)
following = null
..()
//END TELEPORT HREF CODE
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 65864f5d912..fa834fa581b 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -526,7 +526,7 @@
src << "You wriggle out of [M]'s grip!"
else if(istype(H.loc,/obj/item))
src << "You struggle free of [H.loc]."
- H.loc = get_turf(H)
+ H.forceMove(get_turf(H))
if(istype(M))
for(var/atom/A in M.contents)