mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-30 08:29:57 +01:00
Rewriting multiz movement to be gooder (#2464)
Intent: implement all of the features from #2442 while also unfucking the multiz movement files to be more readable and not recurse. To that end, this PR does the following: All multiz travel is now arbitrated by SSfalling. This will eliminate the need for recursion without relying on timers. Timers would be a bit scary. The call chain for multiz movement now looks like this (in terms of overwritable procs): can_fall() (Can lead into fall_impact() & fall_collateral() if returns FALSE) fall_through() IF current block is open space ELSE fall_impact() & fall_collateral() Removed almost every istype(src, A) check in the movement.dm file by exercising proper parenting and call chains. Documented and standardized the contents of multiz/movement.dm. Because this is an API we're going to be relying on very heavily, I'd like to get this right before we move on. A lot of minor tweaks, like swapping usr over to the applicable mob, and so on.
This commit is contained in:
+345
-125
@@ -1,3 +1,10 @@
|
||||
/atom/movable
|
||||
/** Used to check wether or not an atom is being handled by SSfalling. */
|
||||
var/tmp/multiz_falling = 0
|
||||
|
||||
/**
|
||||
* Verb for the mob to move up a z-level if possible.
|
||||
*/
|
||||
/mob/verb/up()
|
||||
set name = "Move Upwards"
|
||||
set category = "IC"
|
||||
@@ -5,6 +12,9 @@
|
||||
if(zMove(UP))
|
||||
to_chat(usr, "<span class='notice'>You move upwards.</span>")
|
||||
|
||||
/**
|
||||
* Verb for the mob to move down a z-level if possible.
|
||||
*/
|
||||
/mob/verb/down()
|
||||
set name = "Move Down"
|
||||
set category = "IC"
|
||||
@@ -12,62 +22,117 @@
|
||||
if(zMove(DOWN))
|
||||
to_chat(usr, "<span class='notice'>You move down.</span>")
|
||||
|
||||
/**
|
||||
* Used to check if a mob can move up or down a Z-level and to then actually do the move.
|
||||
*
|
||||
* @param direction The direction in which we're moving. Expects defines UP or DOWN.
|
||||
*
|
||||
* @return TRUE if the mob has been successfully moved a Z-level.
|
||||
* FALSE otherwise.
|
||||
*/
|
||||
/mob/proc/zMove(direction)
|
||||
if(eyeobj)
|
||||
// In the case of an active eyeobj, move that instead.
|
||||
if (eyeobj)
|
||||
return eyeobj.zMove(direction)
|
||||
if(!can_ztravel())
|
||||
to_chat(usr, "<span class='warning'>You lack means of travel in that direction.</span>")
|
||||
return
|
||||
|
||||
// Check if we can actually travel a Z-level.
|
||||
if (!can_ztravel())
|
||||
to_chat(src, "<span class='warning'>You lack means of travel in that direction.</span>")
|
||||
return FALSE
|
||||
|
||||
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
|
||||
|
||||
if(!destination)
|
||||
to_chat(usr, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
return 0
|
||||
to_chat(src, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
return FALSE
|
||||
|
||||
var/turf/start = get_turf(src)
|
||||
if(!start.CanZPass(src, direction))
|
||||
to_chat(usr, "<span class='warning'>\The [start] is in the way.</span>")
|
||||
return 0
|
||||
to_chat(src, "<span class='warning'>\The [start] is in the way.</span>")
|
||||
return FALSE
|
||||
|
||||
if(!destination.CanZPass(src, direction))
|
||||
to_chat(usr, "<span class='warning'>You bump against \the [destination].</span>")
|
||||
return 0
|
||||
to_chat(src, "<span class='warning'>You bump against \the [destination].</span>")
|
||||
return FALSE
|
||||
|
||||
var/area/area = get_area(src)
|
||||
if(direction == UP && area.has_gravity && !usr.CanAvoidGravity())
|
||||
to_chat(usr, "<span class='warning'>Gravity stops you from moving upward.</span>")
|
||||
return 0
|
||||
|
||||
for(var/atom/A in destination)
|
||||
if(!A.CanPass(src, start, 1.5, 0))
|
||||
to_chat(usr, "<span class='warning'>\The [A] blocks you.</span>")
|
||||
return 0
|
||||
// If we want to move up,but the current area has gravity. Invoke CanAvoidGravity()
|
||||
// to check if this move is possible.
|
||||
if(direction == UP && area.has_gravity && !CanAvoidGravity())
|
||||
to_chat(src, "<span class='warning'>Gravity stops you from moving upward.</span>")
|
||||
return FALSE
|
||||
|
||||
// Check for blocking atoms at the destination.
|
||||
for (var/atom/A in destination)
|
||||
if (!A.CanPass(src, start, 1.5, 0))
|
||||
to_chat(src, "<span class='warning'>\The [A] blocks you.</span>")
|
||||
return FALSE
|
||||
|
||||
// Actually move.
|
||||
Move(destination)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/eye/zMove(direction)
|
||||
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
|
||||
if(destination)
|
||||
setLoc(destination)
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
to_chat(owner, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
|
||||
/mob/dead/observer/zMove(direction)
|
||||
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
|
||||
if(destination)
|
||||
forceMove(destination)
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
to_chat(src, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
|
||||
/mob/living/carbon/human/bst/zMove(direction)
|
||||
var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
|
||||
if(destination)
|
||||
forceMove(destination)
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
to_chat(src, "<span class='notice'>There is nothing of interest in this direction.</span>")
|
||||
|
||||
/**
|
||||
* @brief Used to determine whether or not a given mob can override gravity when
|
||||
* An initial check for Z-level travel. Called relatively early in mob/proc/zMove.
|
||||
*
|
||||
* Useful for overwriting and special conditions for STOPPING z-level transit.
|
||||
*
|
||||
* @return TRUE if the mob can move a Z-level of its own volition.
|
||||
* FALSE otherwise.
|
||||
*/
|
||||
/mob/proc/can_ztravel()
|
||||
return FALSE
|
||||
|
||||
/mob/dead/observer/can_ztravel()
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/can_ztravel()
|
||||
if(incapacitated())
|
||||
return FALSE
|
||||
|
||||
if(Allow_Spacemove())
|
||||
return TRUE
|
||||
|
||||
if(Check_Shoegrip()) //scaling hull with magboots
|
||||
for(var/turf/simulated/T in trange(1,src))
|
||||
if(T.density)
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/robot/can_ztravel()
|
||||
if(incapacitated() || is_dead())
|
||||
return FALSE
|
||||
|
||||
if(Allow_Spacemove()) //Checks for active jetpack
|
||||
return TRUE
|
||||
|
||||
for(var/turf/simulated/T in trange(1,src)) //Robots get "magboots"
|
||||
if(T.density)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Used to determine whether or not a given mob can override gravity when
|
||||
* attempting to Z-move UP.
|
||||
*
|
||||
* Returns FALSE in standard mob cases. Exists for carbon/human and other child overrides.
|
||||
@@ -78,6 +143,8 @@
|
||||
/mob/proc/CanAvoidGravity()
|
||||
return FALSE
|
||||
|
||||
// Humans and borgs have jetpacks which allows them to override gravity! Or rather,
|
||||
// they can have them. So we override and check.
|
||||
/mob/living/carbon/human/CanAvoidGravity()
|
||||
if (!restrained())
|
||||
var/obj/item/weapon/tank/jetpack/thrust = GetJetpack(src)
|
||||
@@ -95,75 +162,36 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/proc/can_ztravel()
|
||||
return 0
|
||||
|
||||
/mob/dead/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(!below)
|
||||
return
|
||||
|
||||
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()
|
||||
/**
|
||||
* An overridable proc used by SSfalling to determine whether or not an atom
|
||||
* should continue falling to the next level, or stop processing and be caught
|
||||
* in midair, effectively. One of the ways to make things never fall is to make
|
||||
* this return FALSE.
|
||||
*
|
||||
* If the mob has fallen and is stopped amidst a fall by this, fall_impact is
|
||||
* invoked with the second argument being TRUE. As opposed to the default value, FALSE.
|
||||
*
|
||||
* @param below The turf that the mob is expected to end up at.
|
||||
*
|
||||
* @return TRUE if the atom can continue falling in its present situation.
|
||||
* FALSE if it should stop falling and not invoke fall_through or fall_impact
|
||||
* this cycle.
|
||||
*/
|
||||
/atom/movable/proc/can_fall(turf/below)
|
||||
// Anchored things don't fall.
|
||||
if(anchored)
|
||||
return FALSE
|
||||
|
||||
if(locate(/obj/structure/lattice, loc))
|
||||
// Lattices and stairs stop things from falling.
|
||||
if(locate(/obj/structure/lattice, loc) || locate(/obj/structure/stairs, loc))
|
||||
return FALSE
|
||||
|
||||
// See if something prevents us from falling.
|
||||
var/turf/below = GetBelow(src)
|
||||
for(var/atom/A in below)
|
||||
if(!A.CanPass(src, src.loc))
|
||||
return FALSE
|
||||
|
||||
// True otherwise.
|
||||
return TRUE
|
||||
|
||||
/obj/effect/can_fall()
|
||||
@@ -172,18 +200,23 @@
|
||||
/obj/effect/decal/cleanable/can_fall()
|
||||
return TRUE
|
||||
|
||||
/obj/item/pipe/can_fall()
|
||||
var/turf/simulated/open/below = loc
|
||||
below = below.below
|
||||
|
||||
/obj/item/pipe/can_fall(turf/below)
|
||||
. = ..()
|
||||
|
||||
if(anchored)
|
||||
return FALSE
|
||||
|
||||
if((locate(/obj/structure/disposalpipe/up) in below) || locate(/obj/machinery/atmospherics/pipe/zpipe/up in below))
|
||||
return FALSE
|
||||
|
||||
// Only things that stop mechas are atoms that, well, stop them.
|
||||
// Lattices and stairs get crushed in fall_through.
|
||||
/obj/mecha/can_fall(turf/below)
|
||||
// See if something prevents us from falling.
|
||||
for(var/atom/A in below)
|
||||
if(!A.CanPass(src, src.loc))
|
||||
return FALSE
|
||||
|
||||
// True otherwise.
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/can_fall()
|
||||
// Special condition for jetpack mounted folk!
|
||||
if (!restrained())
|
||||
@@ -195,6 +228,9 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/bst/can_fall()
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/robot/can_fall()
|
||||
var/obj/item/weapon/tank/jetpack/thrust = GetJetpack(src)
|
||||
|
||||
@@ -203,46 +239,95 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/atom/movable/proc/handle_fall(var/turf/landing)
|
||||
Move(landing)
|
||||
if(locate(/obj/structure/stairs) in landing)
|
||||
return 1
|
||||
/**
|
||||
* Invoked by SSfalling when an atom is moved one open turf to another via falling.
|
||||
*
|
||||
* src.loc can be assumed to be of type /turf/simulated/open.
|
||||
*/
|
||||
/atom/movable/proc/fall_through()
|
||||
visible_message("\The [src] falls from the level above through \the [loc]!",
|
||||
"You hear a whoosh of displaced air.")
|
||||
|
||||
if(istype(landing, /turf/simulated/open))
|
||||
visible_message("\The [src] falls from the level above through \the [landing]!", "You hear a whoosh of displaced air.")
|
||||
else if(!istype(landing, /turf/space))
|
||||
visible_message("\The [src] falls from the level above and slams onto \the [landing]!", "You hear something slam onto the floor.")
|
||||
/mob/fall_through()
|
||||
visible_message("\The [src] falls from the level above through \the [loc]!",
|
||||
"You fall through \the [loc]!", "You hear a whoosh of displaced air.")
|
||||
|
||||
/mob/living/handle_fall(var/turf/landing)
|
||||
if(..())
|
||||
return 1
|
||||
/obj/mecha/fall_through()
|
||||
var/obj/structure/lattice/L = locate() in loc
|
||||
if (L)
|
||||
visible_message("<span class='danger'>\The [src] crushes \the [L] with its weight!</span>")
|
||||
qdel(L)
|
||||
|
||||
var/area/area1 = get_area(landing)
|
||||
if(!area1.has_gravity())
|
||||
return 1
|
||||
var/obj/structure/stairs/S = locate() in loc
|
||||
if (S)
|
||||
visible_message("<span class='danger'>\The [src] crushes \the [S] with its weight!</span>")
|
||||
qdel(S)
|
||||
|
||||
if(istype(landing, /turf/simulated/open))
|
||||
z_levels_fallen++ // Don't damage them but keep track of this.
|
||||
return 1
|
||||
/**
|
||||
* Invoked when an atom has landed on a tile through which they can no longer fall.
|
||||
*
|
||||
* src.loc now contains the final and updated position of the atom.
|
||||
*
|
||||
* @param levels_fallen How many Z-levels the atom has fallen before landing
|
||||
* on its current loc.
|
||||
* @param stopped_early TRUE if the fall was stopped by can_fall.
|
||||
* FALSE if the fall was stopped by the fact that the atom
|
||||
* was no longer on an open turf.
|
||||
*
|
||||
* @return TRUE if the proc ran completely. FALSE otherwise. Used to determine
|
||||
* if child procs should continue running or not, really.
|
||||
*/
|
||||
/atom/movable/proc/fall_impact(levels_fallen, stopped_early = FALSE)
|
||||
// No gravity, stop falling into spess!
|
||||
var/area/area = get_area(src)
|
||||
if (istype(loc, /turf/space) || (area && !area.has_gravity))
|
||||
return FALSE
|
||||
|
||||
if(istype(landing, /turf/space))
|
||||
z_levels_fallen = 0 // turns out they didn't hit anything solid. Lucky them.
|
||||
return 1
|
||||
visible_message("\The [src] falls and lands on \the [loc]!", "You hear a thud!")
|
||||
|
||||
if(!z_levels_fallen) // Checks if they only fell down one floor.
|
||||
z_levels_fallen = 1
|
||||
return TRUE
|
||||
|
||||
if(!istype(src, /mob/living/carbon/human))
|
||||
var/damage = 30*z_levels_fallen
|
||||
apply_damage(rand(0, damage), BRUTE)
|
||||
apply_damage(rand(0, damage), BRUTE)
|
||||
apply_damage(rand(0, damage), BRUTE)
|
||||
z_levels_fallen = 0
|
||||
// Mobs take damage if they fall!
|
||||
/mob/living/fall_impact(levels_fallen, stopped_early = FALSE)
|
||||
// No gravity, stop falling into spess!
|
||||
var/area/area = get_area(src)
|
||||
if (istype(loc, /turf/space) || (area && !area.has_gravity))
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/handle_fall(var/turf/landing)
|
||||
if(..())
|
||||
return
|
||||
var/damage = 30*species.fall_mod*z_levels_fallen
|
||||
visible_message("\The [src] falls and lands on \the [loc]!",
|
||||
"With a loud thud, you land on \the [loc]!", "You hear a thud!")
|
||||
|
||||
var/damage = 30 * levels_fallen
|
||||
apply_damage(rand(0, damage), BRUTE)
|
||||
apply_damage(rand(0, damage), BRUTE)
|
||||
apply_damage(rand(0, damage), BRUTE)
|
||||
|
||||
// The only piece of duplicate code. I was so close. Soooo close. :ree:
|
||||
if(!isSynthetic())
|
||||
switch(damage)
|
||||
if(-INFINITY to 10)
|
||||
playsound(src.loc, "sound/weapons/bladeslice.ogg", 50, 1)
|
||||
if(11 to 50)
|
||||
playsound(src.loc, "sound/weapons/punch[rand(1, 4)].ogg", 75, 1)
|
||||
if(51 to INFINITY)
|
||||
playsound(src.loc, "sound/weapons/heavysmash.ogg", 100, 1)
|
||||
else
|
||||
playsound(src.loc, "sound/weapons/genhit1.ogg", 75, 1)
|
||||
else
|
||||
playsound(src.loc, "sound/weapons/smash.ogg", 75, 1)
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/fall_impact(levels_fallen, stopped_early = FALSE)
|
||||
// No gravity, stop falling into spess!
|
||||
var/area/area = get_area(src)
|
||||
if (istype(loc, /turf/space) || (area && !area.has_gravity))
|
||||
return FALSE
|
||||
|
||||
visible_message("\The [src] falls and lands on \the [loc]!",
|
||||
"With a loud thud, you land on \the [loc]!", "You hear a thud!")
|
||||
|
||||
var/damage = 25 * species.fall_mod * levels_fallen
|
||||
if(prob(20)) //landed on their head
|
||||
apply_damage(rand(0, damage), BRUTE, "head")
|
||||
|
||||
@@ -265,13 +350,148 @@
|
||||
apply_damage(rand(0, (damage/2)), BRUTE, "l_foot")
|
||||
if(prob(50))
|
||||
apply_damage(rand(0, (damage/2)), BRUTE, "groin")
|
||||
apply_damage(rand(0, damage), BRUTE, "chest")
|
||||
|
||||
apply_damage(rand(0, damage), BRUTE, "chest")
|
||||
|
||||
Weaken(rand(0, damage/2))
|
||||
z_levels_fallen = 0 // reset their fallen variable.
|
||||
|
||||
updatehealth()
|
||||
|
||||
/mob/living/carbon/human/bst/can_fall()
|
||||
// Humans can be synthetic. Never forgetti.
|
||||
if(!isSynthetic())
|
||||
switch(damage)
|
||||
if(-INFINITY to 10)
|
||||
playsound(src.loc, "sound/weapons/bladeslice.ogg", 50, 1)
|
||||
if(11 to 50)
|
||||
playsound(src.loc, "sound/weapons/punch[rand(1, 4)].ogg", 75, 1)
|
||||
if(51 to INFINITY)
|
||||
playsound(src.loc, "sound/weapons/heavysmash.ogg", 100, 1)
|
||||
else
|
||||
playsound(src.loc, "sound/weapons/genhit1.ogg", 75, 1)
|
||||
else
|
||||
playsound(src.loc, "sound/weapons/smash.ogg", 75, 1)
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/bst/fall_impact()
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/bst/handle_fall(turf/landing)
|
||||
return
|
||||
/obj/mecha/fall_impact(levels_fallen, stopped_early = FALSE)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
|
||||
var/damage = 40 * levels_fallen
|
||||
take_damage(rand(0, damage))
|
||||
take_damage(rand(0, damage))
|
||||
take_damage(rand(0, damage))
|
||||
take_damage(rand(0, damage))
|
||||
|
||||
playsound(loc, "sound/effects/bang.ogg", 100, 1)
|
||||
playsound(loc, "sound/effects/bamf.ogg", 100, 1)
|
||||
|
||||
/obj/vehicle/fall_impact(levels_fallen, stopped_early = FALSE)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
|
||||
var/damage = 35 * levels_fallen
|
||||
health -= (rand(0, damage) * brute_dam_coeff)
|
||||
health -= (rand(0, damage) * brute_dam_coeff)
|
||||
health -= (rand(0, damage) * brute_dam_coeff)
|
||||
health -= (rand(0, damage) * brute_dam_coeff)
|
||||
|
||||
playsound(loc, "sound/effects/clang.ogg", 75, 1)
|
||||
|
||||
/**
|
||||
* Used to handle damage dealing for objects post fall. Why is it separated from
|
||||
* fall_impact? Because putting this into fall_impact would make the procs a huge
|
||||
* mess of snowflake istype(src, x) checks. And I'm trying to avoid this by making
|
||||
* the system quite atomic.
|
||||
*
|
||||
* @param levels_fallen How many Z-levels the atom has fallen before landing
|
||||
* on its current loc.
|
||||
* @param stopped_early TRUE if the fall was stopped by can_fall.
|
||||
* FALSE if the fall was stopped by the fact that the atom
|
||||
* was no longer on an open turf.
|
||||
*
|
||||
* @return The /mob/living that was hit. null if no mob was hit.
|
||||
*/
|
||||
/atom/movable/proc/fall_collateral(levels_fallen, stopped_early = FALSE)
|
||||
// No gravity, stop falling into spess!
|
||||
var/area/area = get_area(src)
|
||||
if (istype(loc, /turf/space) || (area && !area.has_gravity))
|
||||
return null
|
||||
|
||||
var/list/fall_specs = fall_get_specs(levels_fallen)
|
||||
var/weight = fall_specs[1]
|
||||
var/fall_force = fall_specs[2]
|
||||
|
||||
var/speed = levels_fallen * throw_speed
|
||||
var/mass = (weight / THROWNOBJ_KNOCKBACK_DIVISOR) + density + opacity
|
||||
var/momentum = speed * mass
|
||||
var/damage = round(fall_force * (speed / THROWNOBJ_KNOCKBACK_DIVISOR) * momentum)
|
||||
|
||||
var/miss_chance = max(15 * (levels_fallen - 1), 0)
|
||||
|
||||
if (prob(miss_chance))
|
||||
return null
|
||||
|
||||
if (damage < 1)
|
||||
return null
|
||||
|
||||
var/mob/living/L = null
|
||||
|
||||
// Can't use locate due to the if check.
|
||||
for (var/mob/living/ll in loc)
|
||||
// in contents check exists for vehicles, mechas, etcetera.
|
||||
if (ll != src && !(ll in contents))
|
||||
L = ll
|
||||
break
|
||||
|
||||
if (!L)
|
||||
return null
|
||||
|
||||
if (ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
H.apply_damage(rand(damage / 2, damage), BRUTE, "head")
|
||||
H.apply_damage(damage, BRUTE, "chest")
|
||||
|
||||
if (damage >= THROWNOBJ_KNOCKBACK_DIVISOR)
|
||||
H.Weaken(rand(damage / 4, damage / 2))
|
||||
else
|
||||
L.apply_damage(damage, BRUTE)
|
||||
L.apply_damage(rand(damage / 2, damage), BRUTE)
|
||||
|
||||
L.visible_message("<span class='danger'>\The [L] had \the [src] fall onto \him!</span>",
|
||||
"<span class='danger'>You had \the [src] fall onto you and strike you!</span>")
|
||||
|
||||
admin_attack_log((ismob(src) ? src : null), L, "fell onto", "was fallen on by", "fell ontop of")
|
||||
|
||||
playsound(L.loc, "sound/waepons/genhit[rand(1, 3)].ogg", 75, 1)
|
||||
|
||||
return L
|
||||
|
||||
/mob/fall_collateral(levels_fallen, stopped_early = FALSE)
|
||||
. = ..()
|
||||
|
||||
if (.)
|
||||
to_chat(src, "<span class='danger'>You fell ontop of \the [.]!</span>")
|
||||
|
||||
/**
|
||||
* Helper proc for customizing which attributes should be used in fall damage
|
||||
* calculations. Allows for greater control over the damage. (Drop pods, anyone?)
|
||||
*
|
||||
* @param levels_fallen How many Z-levels the atom has fallen before landing
|
||||
* on its current loc.
|
||||
*
|
||||
* @return A two entity list: list(weight, fall_force)
|
||||
*/
|
||||
/atom/movable/proc/fall_get_specs(levels_fallen)
|
||||
return list(1, throw_range)
|
||||
|
||||
/obj/fall_get_specs(levels_fallen)
|
||||
return list(w_class, throwforce)
|
||||
|
||||
/mob/fall_get_specs(levels_fallen)
|
||||
return list(mob_size, throw_range)
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
////////////////////////////
|
||||
// parent class for pipes //
|
||||
////////////////////////////
|
||||
obj/machinery/atmospherics/pipe/zpipe
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "up"
|
||||
/obj/machinery/atmospherics/pipe/zpipe
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "up"
|
||||
|
||||
name = "upwards pipe"
|
||||
desc = "A pipe segment to connect upwards."
|
||||
name = "upwards pipe"
|
||||
desc = "A pipe segment to connect upwards."
|
||||
|
||||
volume = 70
|
||||
volume = 70
|
||||
|
||||
dir = SOUTH
|
||||
initialize_directions = SOUTH
|
||||
dir = SOUTH
|
||||
initialize_directions = SOUTH
|
||||
|
||||
var/minimum_temperature_difference = 300
|
||||
var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
|
||||
var/minimum_temperature_difference = 300
|
||||
var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
|
||||
|
||||
var/maximum_pressure = 70*ONE_ATMOSPHERE
|
||||
var/fatigue_pressure = 55*ONE_ATMOSPHERE
|
||||
alert_pressure = 55*ONE_ATMOSPHERE
|
||||
var/maximum_pressure = 70*ONE_ATMOSPHERE
|
||||
var/fatigue_pressure = 55*ONE_ATMOSPHERE
|
||||
alert_pressure = 55*ONE_ATMOSPHERE
|
||||
|
||||
|
||||
level = 1
|
||||
level = 1
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/New()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/New()
|
||||
..()
|
||||
switch(dir)
|
||||
if(SOUTH)
|
||||
@@ -48,13 +48,13 @@ obj/machinery/atmospherics/pipe/zpipe/New()
|
||||
invisibility = i ? 101 : 0
|
||||
update_icon()
|
||||
|
||||
obj/machinery/atmospherics/pipe/up/process()
|
||||
/obj/machinery/atmospherics/pipe/up/process()
|
||||
if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle
|
||||
..()
|
||||
else
|
||||
. = PROCESS_KILL
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure)
|
||||
/obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure)
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
|
||||
var/pressure_difference = pressure - environment.return_pressure()
|
||||
@@ -69,34 +69,34 @@ obj/machinery/atmospherics/pipe/zpipe/check_pressure(pressure)
|
||||
|
||||
else return 1
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/proc/burst()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/proc/burst()
|
||||
src.visible_message("<span class='warning'>\The [src] bursts!</span>");
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
|
||||
var/datum/effect/effect/system/smoke_spread/smoke = new
|
||||
smoke.set_up(1,0, src.loc, 0)
|
||||
smoke.start()
|
||||
qdel(src) // NOT qdel.
|
||||
qdel(src) // Yes QDel.
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/proc/normalize_dir()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/proc/normalize_dir()
|
||||
if(dir==3)
|
||||
set_dir(1)
|
||||
else if(dir==12)
|
||||
set_dir(4)
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/Destroy()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/Destroy()
|
||||
if(node1)
|
||||
node1.disconnect(src)
|
||||
if(node2)
|
||||
node2.disconnect(src)
|
||||
return ..()
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/pipeline_expansion()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/pipeline_expansion()
|
||||
return list(node1, node2)
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/update_icon()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/update_icon()
|
||||
return
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/disconnect(obj/machinery/atmospherics/reference)
|
||||
/obj/machinery/atmospherics/pipe/zpipe/disconnect(obj/machinery/atmospherics/reference)
|
||||
if(reference == node1)
|
||||
if(istype(node1, /obj/machinery/atmospherics/pipe))
|
||||
qdel(parent)
|
||||
@@ -111,14 +111,14 @@ obj/machinery/atmospherics/pipe/zpipe/disconnect(obj/machinery/atmospherics/refe
|
||||
/////////////////////////
|
||||
// the elusive up pipe //
|
||||
/////////////////////////
|
||||
obj/machinery/atmospherics/pipe/zpipe/up
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "up"
|
||||
/obj/machinery/atmospherics/pipe/zpipe/up
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "up"
|
||||
|
||||
name = "upwards pipe"
|
||||
desc = "A pipe segment to connect upwards."
|
||||
name = "upwards pipe"
|
||||
desc = "A pipe segment to connect upwards."
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/up/initialize()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/up/initialize()
|
||||
normalize_dir()
|
||||
var/node1_dir
|
||||
|
||||
@@ -149,14 +149,14 @@ obj/machinery/atmospherics/pipe/zpipe/up/initialize()
|
||||
// and the down pipe //
|
||||
///////////////////////
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/down
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "down"
|
||||
/obj/machinery/atmospherics/pipe/zpipe/down
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "down"
|
||||
|
||||
name = "downwards pipe"
|
||||
desc = "A pipe segment to connect downwards."
|
||||
name = "downwards pipe"
|
||||
desc = "A pipe segment to connect downwards."
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/down/initialize()
|
||||
/obj/machinery/atmospherics/pipe/zpipe/down/initialize()
|
||||
normalize_dir()
|
||||
var/node1_dir
|
||||
|
||||
@@ -187,7 +187,7 @@ obj/machinery/atmospherics/pipe/zpipe/down/initialize()
|
||||
// supply/scrubbers //
|
||||
///////////////////////
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/up/scrubbers
|
||||
/obj/machinery/atmospherics/pipe/zpipe/up/scrubbers
|
||||
icon_state = "up-scrubbers"
|
||||
name = "upwards scrubbers pipe"
|
||||
desc = "A scrubbers pipe segment to connect upwards."
|
||||
@@ -195,7 +195,7 @@ obj/machinery/atmospherics/pipe/zpipe/up/scrubbers
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/up/supply
|
||||
/obj/machinery/atmospherics/pipe/zpipe/up/supply
|
||||
icon_state = "up-supply"
|
||||
name = "upwards supply pipe"
|
||||
desc = "A supply pipe segment to connect upwards."
|
||||
@@ -203,7 +203,7 @@ obj/machinery/atmospherics/pipe/zpipe/up/supply
|
||||
icon_connect_type = "-supply"
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/down/scrubbers
|
||||
/obj/machinery/atmospherics/pipe/zpipe/down/scrubbers
|
||||
icon_state = "down-scrubbers"
|
||||
name = "downwards scrubbers pipe"
|
||||
desc = "A scrubbers pipe segment to connect downwards."
|
||||
@@ -211,7 +211,7 @@ obj/machinery/atmospherics/pipe/zpipe/down/scrubbers
|
||||
icon_connect_type = "-scrubbers"
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/down/supply
|
||||
/obj/machinery/atmospherics/pipe/zpipe/down/supply
|
||||
icon_state = "down-supply"
|
||||
name = "downwards supply pipe"
|
||||
desc = "A supply pipe segment to connect downwards."
|
||||
@@ -220,12 +220,12 @@ obj/machinery/atmospherics/pipe/zpipe/down/supply
|
||||
color = PIPE_COLOR_BLUE
|
||||
|
||||
// Colored misc. pipes
|
||||
obj/machinery/atmospherics/pipe/zpipe/up/cyan
|
||||
/obj/machinery/atmospherics/pipe/zpipe/up/cyan
|
||||
color = PIPE_COLOR_CYAN
|
||||
obj/machinery/atmospherics/pipe/zpipe/down/cyan
|
||||
/obj/machinery/atmospherics/pipe/zpipe/down/cyan
|
||||
color = PIPE_COLOR_CYAN
|
||||
|
||||
obj/machinery/atmospherics/pipe/zpipe/up/red
|
||||
/obj/machinery/atmospherics/pipe/zpipe/up/red
|
||||
color = PIPE_COLOR_RED
|
||||
obj/machinery/atmospherics/pipe/zpipe/down/red
|
||||
/obj/machinery/atmospherics/pipe/zpipe/down/red
|
||||
color = PIPE_COLOR_RED
|
||||
|
||||
@@ -131,47 +131,47 @@
|
||||
opacity = 0
|
||||
anchored = 1
|
||||
|
||||
Initialize()
|
||||
. = ..()
|
||||
for(var/turf/turf in locs)
|
||||
var/turf/simulated/open/above = GetAbove(turf)
|
||||
if(!above)
|
||||
warning("Stair created without level above: ([loc.x], [loc.y], [loc.z])")
|
||||
return qdel(src)
|
||||
if(!istype(above))
|
||||
above.ChangeTurf(/turf/simulated/open)
|
||||
/obj/structure/stairs/Initialize()
|
||||
. = ..()
|
||||
for(var/turf/turf in locs)
|
||||
var/turf/simulated/open/above = GetAbove(turf)
|
||||
if(!above)
|
||||
warning("Stair created without level above: ([loc.x], [loc.y], [loc.z])")
|
||||
return qdel(src)
|
||||
if(!istype(above))
|
||||
above.ChangeTurf(/turf/simulated/open)
|
||||
|
||||
Uncross(atom/movable/A)
|
||||
if(A.dir == dir)
|
||||
// This is hackish but whatever.
|
||||
var/turf/target = get_step(GetAbove(A), dir)
|
||||
var/turf/source = A.loc
|
||||
if(target.Enter(A, source))
|
||||
A.loc = target
|
||||
target.Entered(A, source)
|
||||
return 0
|
||||
return 1
|
||||
/obj/structure/stairs/Uncross(atom/movable/A)
|
||||
if(A.dir == dir)
|
||||
// This is hackish but whatever.
|
||||
var/turf/target = get_step(GetAbove(A), dir)
|
||||
var/turf/source = A.loc
|
||||
if(target.Enter(A, source))
|
||||
A.loc = target
|
||||
target.Entered(A, source)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
CanPass(obj/mover, turf/source, height, airflow)
|
||||
return airflow || !density
|
||||
/obj/structure/stairs/CanPass(obj/mover, turf/source, height, airflow)
|
||||
return airflow || !density
|
||||
|
||||
// type paths to make mapping easier.
|
||||
north
|
||||
dir = NORTH
|
||||
bound_height = 64
|
||||
bound_y = -32
|
||||
pixel_y = -32
|
||||
// type paths to make mapping easier.
|
||||
/obj/structure/stairs/north
|
||||
dir = NORTH
|
||||
bound_height = 64
|
||||
bound_y = -32
|
||||
pixel_y = -32
|
||||
|
||||
south
|
||||
dir = SOUTH
|
||||
bound_height = 64
|
||||
/obj/structure/stairs/south
|
||||
dir = SOUTH
|
||||
bound_height = 64
|
||||
|
||||
east
|
||||
dir = EAST
|
||||
bound_width = 64
|
||||
bound_x = -32
|
||||
pixel_x = -32
|
||||
/obj/structure/stairs/east
|
||||
dir = EAST
|
||||
bound_width = 64
|
||||
bound_x = -32
|
||||
pixel_x = -32
|
||||
|
||||
west
|
||||
dir = WEST
|
||||
bound_width = 64
|
||||
/obj/structure/stairs/west
|
||||
dir = WEST
|
||||
bound_width = 64
|
||||
|
||||
+38
-16
@@ -1,18 +1,32 @@
|
||||
/**
|
||||
* Used to check wether or not an atom can pass through a turf.
|
||||
*
|
||||
* @param A The atom that's moving either up or down from this turf or to it.
|
||||
* @param direction The direction of the atom's movement in relation to its
|
||||
* current position.
|
||||
*
|
||||
* @return TRUE if A can pass in the movement direction, FALSE if not.
|
||||
*/
|
||||
/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
|
||||
return FALSE
|
||||
if(direction == DOWN) //on a turf above, trying to enter
|
||||
return !density
|
||||
|
||||
/turf/simulated/open/CanZPass(atom, direction)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/turf/space/CanZPass(atom, direction)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Open turf class.
|
||||
*
|
||||
* All atoms are able to pass through this, and also to see under it.
|
||||
*/
|
||||
/turf/simulated/open
|
||||
name = "open space"
|
||||
icon = 'icons/turf/space.dmi'
|
||||
@@ -39,15 +53,6 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/turf/simulated/open/proc/is_above_space()
|
||||
var/turf/T = GetBelow(src)
|
||||
while (T && T.is_hole)
|
||||
if (istype(T, /turf/space))
|
||||
return TRUE
|
||||
T = GetBelow(T)
|
||||
|
||||
return FALSE
|
||||
|
||||
/turf/simulated/open/Destroy()
|
||||
SSopenturf.openspace_turfs -= src
|
||||
SSopenturf.queued_turfs -= src
|
||||
@@ -63,6 +68,20 @@
|
||||
below = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Used to check wether or not the specific open turf eventually leads into spess.
|
||||
*
|
||||
* @return TRUE if the turfs/holes eventually lead into space. FALSE otherwise.
|
||||
*/
|
||||
/turf/simulated/open/proc/is_above_space()
|
||||
var/turf/T = GetBelow(src)
|
||||
while (T && T.is_hole)
|
||||
if (istype(T, /turf/space))
|
||||
return TRUE
|
||||
T = GetBelow(T)
|
||||
|
||||
return FALSE
|
||||
|
||||
/turf/simulated/open/airless
|
||||
oxygen = 0
|
||||
nitrogen = 0
|
||||
@@ -77,12 +96,15 @@
|
||||
SSopenturf.openspace_turfs += src
|
||||
update()
|
||||
|
||||
/**
|
||||
* Updates the turf with open turf's variables and basically resets it properly.
|
||||
*/
|
||||
/turf/simulated/open/proc/update()
|
||||
below = GetBelow(src)
|
||||
below.above = src
|
||||
levelupdate()
|
||||
for(var/atom/movable/A in src)
|
||||
A.fall()
|
||||
for (var/atom/movable/A in src)
|
||||
ADD_FALLING_ATOM(A)
|
||||
update_icon()
|
||||
|
||||
/turf/simulated/open/update_dirt()
|
||||
@@ -90,7 +112,7 @@
|
||||
|
||||
/turf/simulated/open/Entered(atom/movable/mover)
|
||||
..()
|
||||
mover.fall()
|
||||
ADD_FALLING_ATOM(mover)
|
||||
update_icon()
|
||||
|
||||
// override to make sure nothing is hidden
|
||||
@@ -142,4 +164,4 @@
|
||||
|
||||
//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
|
||||
return TRUE
|
||||
|
||||
Reference in New Issue
Block a user