ID:257757
 
//Title: Remote Objects and Turf-like Objects
//Credit to: Android Data
//Contributed by: Android Data
//Dependency of: Soft-coded Movement Procedures


/*
This snippet will make an additional argument ("direct") for
Enter(), Exit(), Entered() and Exited() and will allow you
to bind Enter() and such to objects which can "return 0" to
block movement and everything else a turf can.

It not just does that, but it also makes a new type of
objects: robjs or remote objects. These objects control
series of turfs. If you step onto the turf, this objects'
Enter()/Exit()/Entered()/Exited() procs will be called if
the turf nor it's area has density. It pretty much allows
you to make multiple /area's, controlled by a single remote
object.

The "direct" argument can have three possible values:
0 Object is indirectly entered. The object is
bumped into.
1 Object is directly entered. Example:
mob.Move(obj)
2 Object is a remote object and one of it's
turfs has been accessed.

UPDATE [13/12/2006]: added support for robj taking over clients (for now, just taking over the Click(), DblClick() and Move()) procs and added a proc that populates the areas list with every turf in a specific range
UPDATE [02/01/2007]: fixed it.
UPDATE [19/02/2007]: fixed a bug where non-dense objects couldn't move if there wasn't an obstruction on the tile they were moving from.
*/


atom
proc
GetObstructed()
movable
Move(atom/newloc, newdir)
if(newdir) dir = newdir

if(!newloc) return 0
if(!loc) {loc=newloc;return 0}

var/atom/oldloc = loc
if(loc && newloc && !newdir) dir = \
get_dir(loc, newloc)
if(oldloc && !oldloc.Exit(src,1)) \
return 0

var/area/area1 = oldloc
var/area/area2 = newloc
while(area1 && !isarea(area1)) \
area1 = area1.loc
while(area2 && !isarea(area2)) \
area2 = area2.loc

if(area1 && area1 != area2 && \
isturf(oldloc) && !area1.Exit(src,1)) return 0
var/atom/oldobstruction=oldloc.GetObstructed()
// if(oldobstruction==src) return 0
if(istype(oldobstruction,/robj))
if(!(newloc in \
oldobstruction:areas)&&(!oldobstruction.Exit(src,2, newloc))) \
return 0
else if(oldobstruction&&!oldobstruction.Exit(src,0)) \
return 0
var/atom/obstruction=newloc.GetObstructed()
if(newloc && !newloc.Enter(src,1))
if(newloc) Bump(obstruction)
return 0
if(area2 && area1 != area2 && \
isturf(newloc) && !area2.Enter(src,1))
if(newloc) Bump(obstruction)
return 0

// if something else moved us already, abort
if(loc != oldloc) return 0
loc = newloc

var/atom/obstruction2=oldloc.GetObstructed()
if(obstruction2 && obstruction2 in \
oldloc) obstruction2.Exited(src, 0)
else if(obstruction2) //robjs
var/robj/O2=obstruction2
if(istype(O2)&&!(newloc in \
O2.areas)) O2.Exited(src, 2, newloc)
if(obstruction && obstruction in \
newloc) obstruction.Entered(src, 0)
else if(obstruction) //robjs
var/robj/O=obstruction
if(istype(O)\
&&!(oldloc in O.areas)) O.Entered(src, 2, newloc)
if(oldloc) oldloc.Exited(src,1)
if(area1 && area1 != area2 && \
!isarea(oldloc)) area1.Exited(src, 1)
if(loc) loc.Entered(src, oldloc,1)
if(area2 && area1 != area2 && \
!isarea(loc)) area2.Entered(src, oldloc, 1)

return 1
Enter(atom/A,direct) return direct

turf/GetObstructed(atom/movable/A)
if(density) return src
if(loc.density) return loc
for(var/robj/R in world)
if(src in R.areas)
if(!A||(!(A.loc in R.areas))&&(!R.Enter(A,2,src))) return R
for(var/obj/O in src) if(O.density && \
(!A||!O.Enter(A,0))) return O
for(var/mob/M in src) if(M.density && \
(!A||!M.Enter(A,0))) return M
turf/Enter(atom/movable/A)
if(!A) return 0
if(!A.density) return 1
var/atom/D = GetObstructed(A)
return (!D || D == A) ? 1 : 0

robj
parent_type=/obj
var/list/areas //list of turfs it controls - usually done with block()

//begin changes 13/12/2006

client
var/robj/robj
Click()
if(robj&&!robj.Clicked(arglist(list(src)+args))) return 0
return ..()
DblClick()
if(robj&&!robj.DblClicked(arglist(list(src)+args))) return 0
return ..()
Move(atom/newloc,newdir)
if(robj)
var/x=robj.Moving(arglist(list(src)+args))
if(x!=-1) return x
return ..()

robj
proc
Clicked(Object,Location) return 1
DblClicked(Object,Location) return 1
Moving(mob/M,atom/newloc,newdir) return -1
generateAreas(atom/location,range) {ASSERT(location);ASSERT(range);areas=block(locate(location.x-range,location.y-range,location.z),locate(location.x+range,location.y+range,location.z));}

//end changes 13/12/2006