diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 8db23214265..26bd4c697ae 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -178,7 +178,7 @@ var/const/enterloopsanity = 100
if(!(A.last_move)) return
if((istype(A, /mob/) && src.x > 2 && src.x < (world.maxx - 1) && src.y > 2 && src.y < (world.maxy-1)))
var/mob/M = A
- if(M.Process_Spacemove(1))
+ if(M.Allow_Spacemove(1))
M.inertia_dir = 0
return
spawn(5)
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index 04adf11fb94..8797e040811 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -8,6 +8,12 @@
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
qdel(L)
+// Called after turf replaces old one
+/turf/proc/post_change()
+ levelupdate()
+ var/turf/simulated/open/T = GetAbove(src)
+ if(istype(T))
+ T.update_icon()
//Creates a new turf
/turf/proc/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0)
@@ -17,8 +23,8 @@
// This makes sure that turfs are not changed to space when one side is part of a zone
if(N == /turf/space)
var/turf/below = GetBelow(src)
- if(istype(below) && (air_master.has_valid_zone(below) || air_master.has_valid_zone(src)))
- N = /turf/simulated/open
+ if(istype(below) && !istype(below,/turf/space))
+ N = below.density ? /turf/simulated/floor/airless : /turf/simulated/open
var/obj/fire/old_fire = fire
var/old_opacity = opacity
@@ -27,10 +33,13 @@
var/old_lighting_overlay = lighting_overlay
var/list/old_corners = corners
- //world << "Replacing [src.type] with [N]"
+// log_debug("Replacing [src.type] with [N]")
+
if(connections) connections.erase_all()
+ overlays.Cut()
+ underlays.Cut()
if(istype(src,/turf/simulated))
//Yeah, we're just going to rebuild the whole thing.
//Despite this being called a bunch during explosions,
@@ -38,44 +47,27 @@
var/turf/simulated/S = src
if(S.zone) S.zone.rebuild()
- if(ispath(N, /turf/simulated/floor))
- var/turf/simulated/W = new N( locate(src.x, src.y, src.z) )
+ var/turf/simulated/W = new N( locate(src.x, src.y, src.z) )
+
+ if(ispath(N, /turf/simulated))
if(old_fire)
fire = old_fire
-
if (istype(W,/turf/simulated/floor))
W.RemoveLattice()
+ else if(old_fire)
+ old_fire.RemoveFire()
- if(tell_universe)
- universe.OnTurfChange(W)
+ if(tell_universe)
+ universe.OnTurfChange(W)
- if(air_master)
- air_master.mark_for_update(src) //handle the addition of the new turf.
+ if(air_master)
+ air_master.mark_for_update(src) //handle the addition of the new turf.
- for(var/turf/space/S in range(W,1))
- S.update_starlight()
+ for(var/turf/space/S in range(W,1))
+ S.update_starlight()
- W.levelupdate()
- . = W
-
- else
-
- var/turf/W = new N( locate(src.x, src.y, src.z) )
-
- if(old_fire)
- old_fire.RemoveFire()
-
- if(tell_universe)
- universe.OnTurfChange(W)
-
- if(air_master)
- air_master.mark_for_update(src)
-
- for(var/turf/space/S in range(W,1))
- S.update_starlight()
-
- W.levelupdate()
- . = W
+ W.post_change()
+ . = W
lighting_overlay = old_lighting_overlay
affecting_lights = old_affecting_lights
@@ -87,3 +79,26 @@
lighting_build_overlay()
else
lighting_clear_overlay()
+
+/turf/proc/transport_properties_from(turf/other)
+ if(!istype(other, src.type))
+ return 0
+
+ src.set_dir(other.dir)
+ src.icon_state = other.icon_state
+ src.icon = other.icon
+ src.overlays = other.overlays.Copy()
+ src.underlays = other.underlays.Copy()
+ return 1
+
+//I would name this copy_from() but we remove the other turf from their air zone for some reason
+/turf/simulated/transport_properties_from(turf/simulated/other)
+ if(!..())
+ return 0
+
+ if(other.zone)
+ if(!src.air)
+ src.make_air()
+ src.air.copy_from(other.zone.air)
+ other.zone.remove(other)
+ return 1
diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm
index 07efb35d114..4ebdd5de1b1 100644
--- a/code/modules/clothing/spacesuits/rig/rig.dm
+++ b/code/modules/clothing/spacesuits/rig/rig.dm
@@ -846,9 +846,14 @@
if(!wearer.lastarea)
wearer.lastarea = get_area(wearer.loc)
- if((istype(wearer.loc, /turf/space)) || (wearer.lastarea.has_gravity == 0))
- if(!wearer.Process_Spacemove(0))
+ if(!wearer.check_solid_ground())
+ var/allowmove = wearer.Allow_Spacemove(0)
+ if(!allowmove)
return 0
+ else if(allowmove == -1 && wearer.handle_spaceslipping()) //Check to see if we slipped
+ return 0
+ else
+ wearer.inertia_dir = 0 //If not then we can reset inertia and move
if(malfunctioning)
direction = pick(cardinal)
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index a3f1fa409d2..254e729c773 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -75,7 +75,7 @@
-/mob/living/carbon/human/Process_Spacemove(var/check_drift = 0)
+/mob/living/carbon/human/Allow_Spacemove(var/check_drift = 0)
//Can we act?
if(restrained()) return 0
@@ -89,9 +89,6 @@
for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules)
thrust = module.jets
break
- else if(istype(back,/obj/item/weapon/storage/backpack/typec))
- inertia_dir = 0
- return 1
if(thrust)
if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.allow_thrust(0.01, src)))
@@ -99,9 +96,7 @@
return 1
//If no working jetpack then use the other checks
- if(..())
- return 1
- return 0
+ . = ..()
/mob/living/carbon/human/slip_chance(var/prob_slip = 5)
diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm
index 99ffce0eebb..2494f00f1e8 100644
--- a/code/modules/mob/living/carbon/metroid/metroid.dm
+++ b/code/modules/mob/living/carbon/metroid/metroid.dm
@@ -140,8 +140,8 @@
..()
-/mob/living/carbon/slime/Process_Spacemove()
- return 2
+/mob/living/carbon/slime/Allow_Spacemove()
+ return 1
/mob/living/carbon/slime/Stat()
..()
@@ -381,4 +381,4 @@
if(powerlevel > 10)
powerlevel = 10
adjustToxLoss(-10)
- nutrition = max(nutrition, get_max_nutrition())
\ No newline at end of file
+ nutrition = max(nutrition, get_max_nutrition())
diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index 5897fc6624f..b4c1414f7d9 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -3,23 +3,12 @@
return 0
..(prob_slip)
-/mob/living/silicon/robot/Process_Spacemove(var/check_drift = 0)//Cleaned up, fixed and simplified this function
- //If checkdrift is 0, we're checking to see if we can manually move, return true if jetpack is on
- //if checkdrift is 1, we're checking to see if we drift. Return true if jetpack AND stabilisers are on
- if(jetpack)
- //var/obj/item/weapon/tank/jetpack/J = internals
-
- if (check_drift)
- if (jetpack.stabilization_on && jetpack.allow_thrust(0.01))
- inertia_dir = 0
+/mob/living/silicon/robot/Allow_Spacemove()
+ if(module)
+ for(var/obj/item/weapon/tank/jetpack/J in module.modules)
+ if(J && J.allow_thrust(0.01))
return 1
-
- else if(jetpack.allow_thrust(0.01))
- inertia_dir = 0
- return 1
- if(..())//The parent function checks for nearby objects to hold onto
- return 1
- return 0
+ . = ..()
//No longer needed, but I'll leave it here incase we plan to re-use it.
/mob/living/silicon/robot/movement_delay()
@@ -42,4 +31,4 @@
return 0
if (cell_use_power(actuatorComponent.active_usage))
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm
index 6beb094c944..e42bc13d04f 100644
--- a/code/modules/mob/living/simple_animal/hostile/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bat.dm
@@ -44,7 +44,7 @@
if(istype(L))
owner = L
-/mob/living/simple_animal/hostile/scarybat/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/scarybat/Allow_Spacemove(var/check_drift = 0)
return ..() //No drifting in space for space carp! //original comments do not steal
/mob/living/simple_animal/hostile/scarybat/FindTarget()
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index a7ce2464778..4fb011c7e29 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -304,7 +304,7 @@
instant_aggro()
-/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/bear/Allow_Spacemove(var/check_drift = 0)
inertia_dir = 0
return 1 //No drifting in space for space bears!
//Fixed this, it wasnt working
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm
index a3e2724e13c..cca64d099d8 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/carp.dm
@@ -39,7 +39,7 @@
faction = "carp"
-/mob/living/simple_animal/hostile/carp/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/carp/Allow_Spacemove(var/check_drift = 0)
return 1 //No drifting in space for space carp! //original comments do not steal
/mob/living/simple_animal/hostile/carp/FindTarget()
@@ -68,4 +68,4 @@
/mob/living/simple_animal/hostile/carp/russian/FindTarget()
. = ..()
if(.)
- custom_emote(1,"spots a filthy capitalist!")
\ No newline at end of file
+ custom_emote(1,"spots a filthy capitalist!")
diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/hostile/faithless.dm
index 44d9c5d1ac4..417be0aa131 100644
--- a/code/modules/mob/living/simple_animal/hostile/faithless.dm
+++ b/code/modules/mob/living/simple_animal/hostile/faithless.dm
@@ -32,7 +32,7 @@
faction = "faithless"
-/mob/living/simple_animal/hostile/faithless/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/faithless/Allow_Spacemove(var/check_drift = 0)
return 1
/mob/living/simple_animal/hostile/faithless/FindTarget()
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm
index b4b21e02bcb..054daafeabc 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm
@@ -36,7 +36,7 @@
faction = "cavern"
-/mob/living/simple_animal/hostile/retaliate/cavern_dweller/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/retaliate/cavern_dweller/Allow_Spacemove(var/check_drift = 0)
return 1
/obj/item/projectile/beam/cavern
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
index b8e4bb63bc6..6bf45c5f234 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
@@ -58,7 +58,7 @@
ion_trail.set_up(src)
ion_trail.start()
-/mob/living/simple_animal/hostile/retaliate/malf_drone/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/retaliate/malf_drone/Allow_Spacemove(var/check_drift = 0)
return 1
/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets()
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 7f240e8a21e..524f89d0515 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -99,7 +99,7 @@
corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
speed = 0
-/mob/living/simple_animal/hostile/syndicate/melee/space/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/syndicate/melee/space/Allow_Spacemove(var/check_drift = 0)
return
/mob/living/simple_animal/hostile/syndicate/ranged
@@ -129,7 +129,7 @@
corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
speed = 0
-/mob/living/simple_animal/hostile/syndicate/ranged/space/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/hostile/syndicate/ranged/space/Allow_Spacemove(var/check_drift = 0)
return
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index acd83da6644..a282a861421 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -244,8 +244,14 @@
if(!mob.lastarea)
mob.lastarea = get_area(mob.loc)
- if((istype(mob.loc, /turf/space)) || (mob.lastarea.has_gravity == 0))
- if(!mob.Process_Spacemove(0)) return 0
+ if(!mob.check_solid_ground())
+ var/allowmove = mob.Allow_Spacemove(0)
+ if(!allowmove)
+ return 0
+ else if(allowmove == -1 && mob.handle_spaceslipping()) //Check to see if we slipped
+ return 0
+ else
+ mob.inertia_dir = 0 //If not then we can reset inertia and move
if(isobj(mob.loc) || ismob(mob.loc))//Inside an object, tell it we moved
var/atom/O = mob.loc
@@ -460,31 +466,33 @@
/mob/proc/Post_Incorpmove()
return
-///Process_Spacemove
-///Called by /client/Move()
-///For moving in space
-///Return 1 for movement 0 for none
-/mob/proc/Process_Spacemove(var/check_drift = 0)
-
+// Checks whether this mob is allowed to move in space
+// Return 1 for movement, 0 for none,
+// -1 to allow movement but with a chance of slipping
+/mob/proc/Allow_Spacemove(var/check_drift = 0)
if(!Check_Dense_Object()) //Nothing to push off of so end here
- update_floating(0)
return 0
- update_floating(1)
-
if(restrained()) //Check to see if we can do things
return 0
- //Check to see if we slipped
- if(prob(slip_chance(5)) && !buckled)
- src << "You slipped!"
- src.inertia_dir = src.last_move
- step(src, src.inertia_dir)
+ return -1
+
+//Checks if a mob has solid ground to stand on
+//If there's no gravity then there's no up or down so naturally you can't stand on anything.
+//For the same reason lattices in space don't count - those are things you grip, presumably.
+/mob/proc/check_solid_ground()
+ if(istype(loc, /turf/space))
return 0
- //If not then we can reset inertia and move
- inertia_dir = 0
+
+ if(!lastarea)
+ lastarea = get_area(loc)
+ if(!lastarea.has_gravity)
+ return 0
+
return 1
+
/mob/proc/Check_Dense_Object() //checks for anything to push off in the vicinity. also handles magboots on gravity-less floors tiles
var/shoegrip = Check_Shoegrip()
@@ -514,3 +522,12 @@
if(Check_Shoegrip())
return 0
return prob_slip
+
+//return 1 if slipped, 0 otherwise
+/mob/proc/handle_spaceslipping()
+ if(prob(slip_chance(5)) && !buckled)
+ to_chat(src, "You slipped!")
+ src.inertia_dir = src.last_move
+ step(src, src.inertia_dir)
+ return 1
+ return 0
diff --git a/code/modules/multiz/basic.dm b/code/modules/multiz/basic.dm
index e76c6516aa7..0ed4e5364a5 100644
--- a/code/modules/multiz/basic.dm
+++ b/code/modules/multiz/basic.dm
@@ -11,25 +11,43 @@ var/z_levels = 0 // Each bit represents a connection between adjacent levels. S
qdel(src)
// The storage of connections between adjacent levels means some bitwise magic is needed.
-proc/HasAbove(var/z)
+/proc/HasAbove(var/z)
if(z >= world.maxz || z > 16 || z < 1)
return 0
return z_levels & (1 << (z - 1))
-proc/HasBelow(var/z)
+/proc/HasBelow(var/z)
if(z > world.maxz || z > 17 || z < 2)
return 0
return z_levels & (1 << (z - 2))
// Thankfully, no bitwise magic is needed here.
-proc/GetAbove(var/atom/atom)
+/proc/GetAbove(var/atom/atom)
var/turf/turf = get_turf(atom)
if(!turf)
return null
return HasAbove(turf.z) ? get_step(turf, UP) : null
-proc/GetBelow(var/atom/atom)
+/proc/GetBelow(var/atom/atom)
var/turf/turf = get_turf(atom)
if(!turf)
return null
return HasBelow(turf.z) ? get_step(turf, DOWN) : null
+
+/proc/GetConnectedZlevels(z)
+ . = list(z)
+ for(var/level = z, HasBelow(level), level--)
+ . |= level-1
+ for(var/level = z, HasAbove(level), level++)
+ . |= level+1
+
+proc/AreConnectedZLevels(var/zA, var/zB)
+ return zA == zB || (zB in GetConnectedZlevels(zA))
+
+/proc/get_zstep(ref, dir)
+ if(dir == UP)
+ . = GetAbove(ref)
+ else if (dir == DOWN)
+ . = GetBelow(ref)
+ else
+ . = get_step(ref, dir)
\ No newline at end of file
diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm
index dd0a93fec11..98f3c17d123 100644
--- a/code/modules/multiz/movement.dm
+++ b/code/modules/multiz/movement.dm
@@ -1,51 +1,172 @@
-/obj/item/weapon/tank/jetpack/verb/moveup()
+/mob/verb/up()
set name = "Move Upwards"
- set category = "Object"
+ set category = "IC"
- . = 1
- if(!allow_thrust(0.01, usr))
- usr << "\The [src] is disabled."
+ if(zMove(UP))
+ to_chat(usr, "You move upwards.")
+
+/mob/verb/down()
+ set name = "Move Down"
+ set category = "IC"
+
+ if(zMove(DOWN))
+ to_chat(usr, "You move down.")
+
+/mob/proc/zMove(direction)
+ if(eyeobj)
+ return eyeobj.zMove(direction)
+ if(!can_ztravel())
+ to_chat(usr, "You lack means of travel in that direction.")
return
- var/turf/above = GetAbove(src)
- if(!istype(above))
- usr << "There is nothing of interest in this direction."
- return
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
- if(!istype(above, /turf/space) && !istype(above, /turf/simulated/open))
- usr << "You bump against \the [above]."
- return
+ if(!destination)
+ to_chat(usr, "There is nothing of interest in this direction.")
+ return 0
- for(var/atom/A in above)
- if(A.density)
- usr << "\The [A] blocks you."
- return
+ var/turf/start = get_turf(src)
+ if(!start.CanZPass(src, direction))
+ to_chat(usr, "\The [start] is in the way.")
+ return 0
+ if(!destination.CanZPass(src, direction))
+ to_chat(usr, "You bump against \the [destination].")
+ return 0
- usr.Move(above)
- usr << "You move upwards."
+ var/area/area = get_area(src)
+ if(direction == UP && area.has_gravity)
+ to_chat(usr, "Gravity stops you from moving upward.")
+ return 0
-/obj/item/weapon/tank/jetpack/verb/movedown()
- set name = "Move Downwards"
- set category = "Object"
+ for(var/atom/A in destination)
+ if(!A.CanPass(src, start, 1.5, 0))
+ to_chat(usr, "\The [A] blocks you.")
+ return 0
+ Move(destination)
+ return 1
- . = 1
- if(!allow_thrust(0.01, usr))
- usr << "\The [src] is disabled."
+/mob/eye/zMove(direction)
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
+ if(destination)
+ forceMove(destination)
+ else
+ to_chat(usr, "There is nothing of interest in this direction.")
+
+/mob/eye/zMove(direction)
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
+ if(destination)
+ setLoc(destination)
+ else
+ to_chat(usr, "There is nothing of interest in this direction.")
+
+/mob/proc/can_ztravel()
+ return 0
+
+/mob/observer/can_ztravel()
+ return 1
+
+/mob/living/carbon/human/can_ztravel()
+ if(incapacitated())
+ return 0
+
+ if(Allow_Spacemove())
+ return 1
+
+ if(Check_Shoegrip()) //scaling hull with magboots
+ for(var/turf/simulated/T in trange(1,src))
+ if(T.density)
+ return 1
+
+/mob/living/silicon/robot/can_ztravel()
+ if(incapacitated() || is_dead())
+ return 0
+
+ if(Allow_Spacemove()) //Checks for active jetpack
+ return 1
+
+ for(var/turf/simulated/T in trange(1,src)) //Robots get "magboots"
+ if(T.density)
+ return 1
+
+//FALLING STUFF
+
+//Holds fall checks that should not be overriden by children
+/atom/movable/proc/fall()
+ if(!isturf(loc))
return
var/turf/below = GetBelow(src)
- if(!istype(below))
- usr << "There is nothing of interest in this direction."
+ if(!below)
return
- if(below.density)
- usr << "You bump against \the [below]."
+ var/turf/T = loc
+ if(!T.CanZPass(src, DOWN) || !below.CanZPass(src, DOWN))
return
+ // No gravity in space, apparently.
+ var/area/area = get_area(src)
+ if(!area.has_gravity())
+ return
+
+ if(throwing)
+ return
+
+ if(can_fall())
+ handle_fall(below)
+
+//For children to override
+/atom/movable/proc/can_fall()
+ if(anchored)
+ return FALSE
+
+ if(locate(/obj/structure/lattice, loc))
+ return FALSE
+
+ // See if something prevents us from falling.
+ var/turf/below = GetBelow(src)
for(var/atom/A in below)
- if(A.density)
- usr << "\The [A] blocks you."
- return
+ if(!A.CanPass(src, src.loc))
+ return FALSE
- usr.Move(below)
- usr << "You move downwards."
+ return TRUE
+
+/obj/effect/can_fall()
+ return FALSE
+
+/obj/effect/decal/cleanable/can_fall()
+ return TRUE
+
+/obj/item/pipe/can_fall()
+ var/turf/simulated/open/below = loc
+ below = below.below
+
+ . = ..()
+
+ if(anchored)
+ return FALSE
+
+ if((locate(/obj/structure/disposalpipe/up) in below) || locate(/obj/machinery/atmospherics/pipe/zpipe/up in below))
+ return FALSE
+
+/atom/movable/proc/handle_fall(var/turf/landing)
+ Move(landing)
+ if(locate(/obj/structure/stairs) in landing)
+ return 1
+
+ if(istype(landing, /turf/simulated/open))
+ visible_message("\The [src] falls from the deck above through \the [landing]!", "You hear a whoosh of displaced air.")
+ else
+ visible_message("\The [src] falls from the deck above and slams into \the [landing]!", "You hear something slam into the deck.")
+
+/mob/living/carbon/human/handle_fall(var/turf/landing)
+ if(..())
+ return
+ var/damage = 10
+ apply_damage(rand(0, damage), BRUTE, "head")
+ apply_damage(rand(0, damage), BRUTE, "chest")
+ apply_damage(rand(0, damage), BRUTE, "l_leg")
+ apply_damage(rand(0, damage), BRUTE, "r_leg")
+ apply_damage(rand(0, damage), BRUTE, "l_arm")
+ apply_damage(rand(0, damage), BRUTE, "r_arm")
+ weakened = max(weakened,2)
+ updatehealth()
diff --git a/code/modules/multiz/pipes.dm b/code/modules/multiz/pipes.dm
index 1cb5b9b4da7..155ef0a7430 100644
--- a/code/modules/multiz/pipes.dm
+++ b/code/modules/multiz/pipes.dm
@@ -192,7 +192,6 @@ obj/machinery/atmospherics/pipe/zpipe/up/scrubbers
name = "upwards scrubbers pipe"
desc = "A scrubbers pipe segment to connect upwards."
connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
icon_connect_type = "-scrubbers"
color = PIPE_COLOR_RED
@@ -201,7 +200,6 @@ obj/machinery/atmospherics/pipe/zpipe/up/supply
name = "upwards supply pipe"
desc = "A supply pipe segment to connect upwards."
connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
@@ -210,7 +208,6 @@ obj/machinery/atmospherics/pipe/zpipe/down/scrubbers
name = "downwards scrubbers pipe"
desc = "A scrubbers pipe segment to connect downwards."
connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
icon_connect_type = "-scrubbers"
color = PIPE_COLOR_RED
@@ -219,6 +216,16 @@ obj/machinery/atmospherics/pipe/zpipe/down/supply
name = "downwards supply pipe"
desc = "A supply pipe segment to connect downwards."
connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
+
+// Colored misc. pipes
+obj/machinery/atmospherics/pipe/zpipe/up/cyan
+ color = PIPE_COLOR_CYAN
+obj/machinery/atmospherics/pipe/zpipe/down/cyan
+ color = PIPE_COLOR_CYAN
+
+obj/machinery/atmospherics/pipe/zpipe/up/red
+ color = PIPE_COLOR_RED
+obj/machinery/atmospherics/pipe/zpipe/down/red
+ color = PIPE_COLOR_RED
diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm
index 36a606bfcf9..62edc2d7689 100644
--- a/code/modules/multiz/structures.dm
+++ b/code/modules/multiz/structures.dm
@@ -4,54 +4,123 @@
/obj/structure/ladder
name = "ladder"
- desc = "A ladder. You can climb it up and down."
- icon_state = "ladderdown"
+ desc = "A ladder. You can climb it up and down."
+ icon_state = "ladder01"
icon = 'icons/obj/structures.dmi'
density = 0
opacity = 0
anchored = 1
- var/obj/structure/ladder/target
+ var/allowed_directions = DOWN
+ var/obj/structure/ladder/target_up
+ var/obj/structure/ladder/target_down
- initialize()
- // the upper will connect to the lower
- if(icon_state == "ladderup")
- return
+ var/const/climb_time = 2 SECONDS
+/obj/structure/ladder/initialize()
+ // the upper will connect to the lower
+ if(allowed_directions & DOWN) //we only want to do the top one, as it will initialize the ones before it.
for(var/obj/structure/ladder/L in GetBelow(src))
- if(L.icon_state == "ladderup")
- target = L
- L.target = src
+ if(L.allowed_directions & UP)
+ target_down = L
+ L.target_up = src
return
+ update_icon()
- Destroy()
- if(target && icon_state == "ladderdown")
- qdel(target)
- return ..()
+/obj/structure/ladder/Destroy()
+ if(target_down)
+ target_down.target_up = null
+ target_down = null
+ if(target_up)
+ target_up.target_down = null
+ target_up = null
+ return ..()
- attackby(obj/item/C as obj, mob/user as mob)
- . = ..()
- attack_hand(user)
+/obj/structure/ladder/attackby(obj/item/C as obj, mob/user as mob)
+ attack_hand(user)
+ return
+
+/obj/structure/ladder/attack_hand(var/mob/M)
+ if(!M.may_climb_ladders(src))
return
- attack_hand(var/mob/M)
- if(!target || !istype(target.loc, /turf))
- M << "\The [src] is incomplete and can't be climbed."
+ var/obj/structure/ladder/target_ladder = getTargetLadder(M)
+ if(!target_ladder)
+ return
+ if(!M.Move(get_turf(src)))
+ to_chat(M, "You fail to reach \the [src].")
+ return
+
+ var/direction = target_ladder == target_up ? "up" : "down"
+
+ M.visible_message("\The [M] begins climbing [direction] \the [src]!",
+ "You begin climbing [direction] \the [src]!",
+ "You hear the grunting and clanging of a metal ladder being used.")
+
+ target_ladder.audible_message("You hear something coming [direction] \the [src]")
+
+ if(do_after(M, climb_time, src))
+ climbLadder(M, target_ladder)
+
+/obj/structure/ladder/attack_ghost(var/mob/M)
+ var/target_ladder = getTargetLadder(M)
+ if(target_ladder)
+ M.forceMove(get_turf(target_ladder))
+
+/obj/structure/ladder/proc/getTargetLadder(var/mob/M)
+ if((!target_up && !target_down) || (target_up && !istype(target_up.loc, /turf) || (target_down && !istype(target_down.loc,/turf))))
+ to_chat(M, "\The [src] is incomplete and can't be climbed.")
+ return
+ if(target_down && target_up)
+ var/direction = alert(M,"Do you want to go up or down?", "Ladder", "Up", "Down", "Cancel")
+
+ if(direction == "Cancel")
return
- var/turf/T = target.loc
- for(var/atom/A in T)
- if(A.density)
- M << "\A [A] is blocking \the [src]."
- return
+ if(!M.may_climb_ladders(src))
+ return
- M.visible_message("\A [M] climbs [icon_state == "ladderup" ? "up" : "down"] \a [src]!",
- "You climb [icon_state == "ladderup" ? "up" : "down"] \the [src]!",
- "You hear the grunting and clanging of a metal ladder being used.")
- M.Move(T)
+ switch(direction)
+ if("Up")
+ return target_up
+ if("Down")
+ return target_down
+ else
+ return target_down || target_up
- CanPass(obj/mover, turf/source, height, airflow)
- return airflow || !density
+/mob/proc/may_climb_ladders(var/ladder)
+ if(!Adjacent(ladder))
+ to_chat(src, "You need to be next to \the [ladder] to start climbing.")
+ return FALSE
+ if(incapacitated())
+ to_chat(src, "You are physically unable to climb \the [ladder].")
+ return FALSE
+ return TRUE
+
+/mob/observer/ghost/may_climb_ladders(var/ladder)
+ return TRUE
+
+/obj/structure/ladder/proc/climbLadder(var/mob/M, var/target_ladder)
+ var/turf/T = get_turf(target_ladder)
+ for(var/atom/A in T)
+ if(!A.CanPass(M, M.loc, 1.5, 0))
+ to_chat(M, "\The [A] is blocking \the [src].")
+ return FALSE
+ return M.Move(T)
+
+/obj/structure/ladder/CanPass(obj/mover, turf/source, height, airflow)
+ return airflow || !density
+
+/obj/structure/ladder/update_icon()
+ icon_state = "ladder[!!(allowed_directions & UP)][!!(allowed_directions & DOWN)]"
+
+/obj/structure/ladder/up
+ allowed_directions = UP
+ icon_state = "ladder10"
+
+/obj/structure/ladder/updown
+ allowed_directions = UP|DOWN
+ icon_state = "ladder11"
/obj/structure/stairs
name = "Stairs"
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm
index b358cd0fbbd..c34b395ed1b 100644
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf.dm
@@ -1,88 +1,76 @@
+/turf/proc/CanZPass(atom/A, direction)
+ if(z == A.z) //moving FROM this turf
+ return direction == UP //can't go below
+ else
+ if(direction == UP) //on a turf below, trying to enter
+ return 0
+ if(direction == DOWN) //on a turf above, trying to enter
+ return !density
+
+/turf/simulated/open/CanZPass(atom, direction)
+ return 1
+
+/turf/space/CanZPass(atom, direction)
+ return 1
+
/turf/simulated/open
name = "open space"
icon = 'icons/turf/space.dmi'
- icon_state = "black"
- alpha = 16
- layer = 0
+ icon_state = ""
+ plane = PLANE_SPACE_BACKGROUND
density = 0
pathweight = 100000 //Seriously, don't try and path over this one numbnuts
var/turf/below
- var/list/underlay_references
- var/global/overlay_map = list()
+
+/turf/simulated/open/post_change()
+ ..()
+ update()
/turf/simulated/open/initialize()
..()
+ update()
+
+/turf/simulated/open/proc/update()
below = GetBelow(src)
- ASSERT(HasBelow(z))
+ levelupdate()
+ for(var/atom/movable/A in src)
+ A.fall()
+ update_icon()
+
+/turf/simulated/open/update_dirt()
+ return 0
/turf/simulated/open/Entered(var/atom/movable/mover)
- // only fall down in defined areas (read: areas with artificial gravitiy)
- if(!istype(below)) //make sure that there is actually something below
- below = GetBelow(src)
- if(!below)
- return
-
- // No gravity in space, apparently.
- var/area/area = get_area(src)
- if(area.name == "Space")
- return
-
- // Prevent pipes from falling into the void... if there is a pipe to support it.
- if(mover.anchored || istype(mover, /obj/item/pipe) && \
- (locate(/obj/structure/disposalpipe/up) in below) || \
- locate(/obj/machinery/atmospherics/pipe/zpipe/up in below))
- return
-
- // See if something prevents us from falling.
- var/soft = 0
- for(var/atom/A in below)
- if(A.density)
- if(!istype(A, /obj/structure/window))
- return
- else
- var/obj/structure/window/W = A
- if(W.is_fulltile())
- return
- // Dont break here, since we still need to be sure that it isnt blocked
- if(istype(A, /obj/structure/stairs))
- soft = 1
-
- // We've made sure we can move, now.
- mover.Move(below)
-
- if(!soft)
- if(!istype(mover, /mob))
- if(istype(below, /turf/simulated/open))
- mover.visible_message("\The [mover] falls from the deck above through \the [below]!", "You hear a whoosh of displaced air.")
- else
- mover.visible_message("\The [mover] falls from the deck above and slams into \the [below]!", "You hear something slam into the deck.")
- else
- var/mob/M = mover
- if(istype(below, /turf/simulated/open))
- below.visible_message("\The [mover] falls from the deck above through \the [below]!", "You hear a soft whoosh.[M.stat ? "" : ".. and some screaming."]")
- else
- M.visible_message("\The [mover] falls from the deck above and slams into \the [below]!", "You land on \the [below].", "You hear a soft whoosh and a crunch")
-
- // Handle people getting hurt, it's funny!
- if (istype(mover, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = mover
- var/damage = 5
- H.apply_damage(rand(0, damage), BRUTE, "head")
- H.apply_damage(rand(0, damage), BRUTE, "chest")
- H.apply_damage(rand(0, damage), BRUTE, "l_leg")
- H.apply_damage(rand(0, damage), BRUTE, "r_leg")
- H.apply_damage(rand(0, damage), BRUTE, "l_arm")
- H.apply_damage(rand(0, damage), BRUTE, "r_arm")
- H.weakened = max(H.weakened,2)
- H.updatehealth()
+ ..()
+ mover.fall()
// override to make sure nothing is hidden
/turf/simulated/open/levelupdate()
for(var/obj/O in src)
O.hide(0)
-// Straight copy from space.
+/turf/simulated/open/update_icon()
+ if(below)
+ underlays = list(image(icon = below.icon, icon_state = below.icon_state))
+
+ var/list/noverlays = list()
+ if(!istype(below,/turf/space))
+ noverlays += image(icon =icon, icon_state = "empty", layer = 2.45)
+
+ var/turf/simulated/T = get_step(src,NORTH)
+ if(istype(T) && !istype(T,/turf/simulated/open))
+ noverlays += image(icon ='icons/turf/cliff.dmi', icon_state = "metal", layer = 2.45)
+
+ var/obj/structure/stairs/S = locate() in below
+ if(S && S.loc == below)
+ var/image/I = image(icon = S.icon, icon_state = "below", dir = S.dir, layer = 2.45)
+ I.pixel_x = S.pixel_x
+ I.pixel_y = S.pixel_y
+ noverlays += I
+
+ overlays = noverlays
+
/turf/simulated/open/attackby(obj/item/C as obj, mob/user as mob)
if (istype(C, /obj/item/stack/rods))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
@@ -90,12 +78,12 @@
return
var/obj/item/stack/rods/R = C
if (R.use(1))
- user << "Constructing support lattice ..."
+ to_chat(user, "You lay down the support lattice.")
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
- ReplaceWithLattice()
+ new /obj/structure/lattice(locate(src.x, src.y, src.z))
return
- if (istype(C, /obj/item/stack/tile/floor))
+ if (istype(C, /obj/item/stack/tile))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
var/obj/item/stack/tile/floor/S = C
@@ -107,5 +95,15 @@
ChangeTurf(/turf/simulated/floor/airless)
return
else
- user << "The plating is going to need some support."
- return
\ No newline at end of file
+ to_chat(user, "The plating is going to need some support.")
+
+ //To lay cable.
+ if(istype(C, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/coil = C
+ coil.turf_place(src, user)
+ return
+ return
+
+//Most things use is_plating to test if there is a cover tile on top (like regular floors)
+/turf/simulated/open/is_plating()
+ return 1
diff --git a/icons/turf/cliff.dmi b/icons/turf/cliff.dmi
new file mode 100644
index 00000000000..a54e13656ea
Binary files /dev/null and b/icons/turf/cliff.dmi differ