Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Standing on structures such as crates, tables and bed will now look like it. #885

Merged
merged 1 commit into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions code/__DEFINES/dcs/signals/signals_turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@
#define FOOTSTEP_OVERRIDEN (1<<0)
///from base of datum/thrownthing/finalize(): (turf/turf, atom/movable/thrownthing) when something is thrown and lands on us
#define COMSIG_TURF_MOVABLE_THROW_LANDED "turf_movable_throw_landed"

///From element/elevation/reset_elevation(): (list/values)
#define COMSIG_TURF_RESET_ELEVATION "turf_reset_elevation"
#define ELEVATION_CURRENT_PIXEL_SHIFT 1
#define ELEVATION_MAX_PIXEL_SHIFT 2
2 changes: 2 additions & 0 deletions code/__DEFINES/traits/declarations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NO_MIRROR_REFLECTION "no_mirror_reflection"
/// If this movable is currently treading in a turf with the immerse element.
#define TRAIT_IMMERSED "immersed"
/// From [/datum/element/elevation_core] for purpose of checking if the turf has the trait from an instance of the element
#define TRAIT_ELEVATED_TURF "elevated_turf"
/**
* With this, the immerse overlay will give the atom its own submersion visual overlay
* instead of one that's also shared with other movables, thus making editing its appearance possible.
Expand Down
7 changes: 6 additions & 1 deletion code/__DEFINES/traits/macros.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// This file contains all of the "dynamic" trait sources that can be used in a number of versatile and everchanging ways.
// This file contains all of the "dynamic" traits and trait sources that can be used
// in a number of versatile and everchanging ways.
// If it uses psuedo-variables like the examples below, it's a macro-trait.


/// From [/datum/element/elevation] for purpose of registering/removing signals and detaching the elevation_core when the trait is absent.
#define TRAIT_TURF_HAS_ELEVATED_OBJ(z) "turf_has_elevated_obj_[z]"

/// The item is magically cursed
#define CURSED_ITEM_TRAIT(item_type) "cursed_item_[item_type]"
/// A trait given by a specific status effect (not sure why we need both but whatever!)
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/traits/_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SPINNING_WEB_TURF" = TRAIT_SPINNING_WEB_TURF,
"TRAIT_TURF_IGNORE_SLIPPERY" = TRAIT_TURF_IGNORE_SLIPPERY,
"TRAIT_TURF_IGNORE_SLOWDOWN" = TRAIT_TURF_IGNORE_SLOWDOWN,
"TRAIT_ELEVATED_TURF" = TRAIT_ELEVATED_TURF,
),
// SKYRAT EDIT ADDITION START - SKYRAT TRAITS
/obj/item/toy/plush/skyrat = list(
Expand Down
169 changes: 169 additions & 0 deletions code/datums/elements/elevation.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/**
* Manages the elevation of the turf the source is on (can be the turf itself)
* The atom with the highest pixel_shift gets to set the elevation of the turf to that value.
*/
/datum/element/elevation
element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY
argument_hash_start_idx = 2
///The amount of pixel_z applied to the mob standing on the turf
var/pixel_shift

/datum/element/elevation/Attach(datum/target, pixel_shift)
. = ..()
if(!isatom(target) || isarea(target))
return ELEMENT_INCOMPATIBLE

src.pixel_shift = pixel_shift

if(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))

var/turf/turf = get_turf(target)
if(turf)
if(!HAS_TRAIT(turf, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift)))
RegisterSignal(turf, COMSIG_TURF_RESET_ELEVATION, PROC_REF(check_elevation))
RegisterSignal(turf, COMSIG_TURF_CHANGE, PROC_REF(pre_change_turf))
reset_elevation(turf)
ADD_TRAIT(turf, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), ref(target))

/datum/element/elevation/Detach(atom/movable/source)
unregister_turf(source, source.loc)
return ..()

/datum/element/elevation/proc/reset_elevation(turf/target)
var/list/current_values[2]
SEND_SIGNAL(target, COMSIG_TURF_RESET_ELEVATION, current_values)
var/current_pixel_shift = current_values[ELEVATION_CURRENT_PIXEL_SHIFT]
var/new_pixel_shift = current_values[ELEVATION_MAX_PIXEL_SHIFT]
if(new_pixel_shift == current_pixel_shift)
return
if(current_pixel_shift)
target.RemoveElement(/datum/element/elevation_core, current_pixel_shift)
if(new_pixel_shift)
target.AddElement(/datum/element/elevation_core, new_pixel_shift)

/datum/element/elevation/proc/check_elevation(turf/source, list/current_values)
SIGNAL_HANDLER
current_values[ELEVATION_MAX_PIXEL_SHIFT] = max(current_values[ELEVATION_MAX_PIXEL_SHIFT], pixel_shift)

/datum/element/elevation/proc/on_moved(atom/movable/source, atom/oldloc)
SIGNAL_HANDLER
unregister_turf(source, oldloc)
if(isturf(source.loc))
if(!HAS_TRAIT(source.loc, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift)))
RegisterSignal(source.loc, COMSIG_TURF_RESET_ELEVATION, PROC_REF(check_elevation))
RegisterSignal(source.loc, COMSIG_TURF_CHANGE, PROC_REF(pre_change_turf))
reset_elevation(source.loc)
ADD_TRAIT(source.loc, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), ref(source))

/datum/element/elevation/proc/unregister_turf(atom/movable/source, atom/location)
if(!isturf(location))
return
REMOVE_TRAIT(location, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), ref(source))
if(!HAS_TRAIT(location, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift)))
UnregisterSignal(location, list(COMSIG_TURF_RESET_ELEVATION, COMSIG_TURF_CHANGE))
reset_elevation(location)

///Changing or destroying the turf detaches the element, also we need to reapply the traits since they don't get passed down.
/datum/element/elevation/proc/pre_change_turf(turf/changed, path, list/new_baseturfs, flags, list/post_change_callbacks)
SIGNAL_HANDLER
var/list/trait_sources = GET_TRAIT_SOURCES(changed, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift))
trait_sources = trait_sources.Copy()
post_change_callbacks += CALLBACK(src, PROC_REF(post_change_turf), trait_sources)

/datum/element/elevation/proc/post_change_turf(list/trait_sources, turf/changed)
ADD_TRAIT(changed, TRAIT_TURF_HAS_ELEVATED_OBJ(pixel_shift), trait_sources)
reset_elevation(changed)

#define ELEVATE_TIME 0.2 SECONDS

/**
* The core element attached to the turf itself. Do not use this directly!
*
* Causes mobs walking over a turf with this element to be pixel shifted vertically by the pixel_shift amount.
* Because of the way it's structured, it should only be added through the elevation element (without the core suffix).
*
* To explain: in the case of multiple objects with (different instances of) the element being stacked on one turf somehow,
* we only want that with the highest pixel shift value to apply it to the turf, so that the mobs standing on top of it all
* doesn't look like it's floating off the pile.
*/
/datum/element/elevation_core
element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY
argument_hash_start_idx = 2
///The amount of pixel_z applied to the mob standing on the turf.
var/pixel_shift

/datum/element/elevation_core/Attach(datum/target, pixel_shift)
. = ..()
if(!isturf(target))
return ELEMENT_INCOMPATIBLE
if(!pixel_shift)
CRASH("attempted attaching /datum/element/elevation_core with a pixel_shift value of [isnull(pixel_shift) ? "null" : 0]")

RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(on_entered))
RegisterSignal(target, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, PROC_REF(on_initialized_on))
RegisterSignal(target, COMSIG_ATOM_EXITED, PROC_REF(on_exited))
RegisterSignal(target, COMSIG_TURF_RESET_ELEVATION, PROC_REF(on_reset_elevation))

src.pixel_shift = pixel_shift

ADD_TRAIT(target, TRAIT_ELEVATED_TURF, REF(src))

for(var/mob/living/living in target)
RegisterSignal(living, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_set_buckled))
elevate_mob(living)

/datum/element/elevation_core/Detach(datum/source)
/**
* Since the element can be removed outside of Destroy(),
* and even then, signals are passed down to the new turf,
* it's necessary to clear them here.
*/
UnregisterSignal(source, list(
COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON,
COMSIG_ATOM_ENTERED,
COMSIG_ATOM_EXITED,
COMSIG_TURF_RESET_ELEVATION,
))
REMOVE_TRAIT(source, TRAIT_ELEVATED_TURF, REF(src))
for(var/mob/living/living in source)
elevate_mob(living, -pixel_shift)
UnregisterSignal(living, COMSIG_LIVING_SET_BUCKLED)
return ..()

/datum/element/elevation_core/proc/on_entered(turf/source, atom/movable/entered, atom/old_loc)
SIGNAL_HANDLER
if((isnull(old_loc) || !HAS_TRAIT_FROM(old_loc, TRAIT_ELEVATED_TURF, REF(src))) && isliving(entered))
var/elevate_time = isturf(old_loc) && source.Adjacent(old_loc) ? ELEVATE_TIME : 0
elevate_mob(entered, elevate_time = elevate_time)

/datum/element/elevation_core/proc/on_initialized_on(turf/source, atom/movable/spawned)
SIGNAL_HANDLER
if(isliving(spawned))
elevate_mob(spawned)

/datum/element/elevation_core/proc/on_exited(turf/source, atom/movable/gone)
SIGNAL_HANDLER
if((isnull(gone.loc) || !HAS_TRAIT_FROM(gone.loc, TRAIT_ELEVATED_TURF, REF(src))) && isliving(gone))
var/elevate_time = isturf(gone.loc) && source.Adjacent(gone.loc) ? ELEVATE_TIME : 0
elevate_mob(gone, -pixel_shift, elevate_time)
UnregisterSignal(gone, COMSIG_LIVING_SET_BUCKLED)

/datum/element/elevation_core/proc/elevate_mob(mob/living/target, z_shift = pixel_shift, elevate_time = ELEVATE_TIME)
animate(target, pixel_z = z_shift, time = elevate_time, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
if(target.buckled && isvehicle(target.buckled))
animate(target.buckled, pixel_z = z_shift, time = elevate_time, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)

///Vehicles or other things the mob is buckled too also are shifted.
/datum/element/elevation_core/proc/on_set_buckled(mob/living/source, atom/movable/new_buckled)
SIGNAL_HANDLER
if(source.buckled && isvehicle(source.buckled))
animate(source.buckled, pixel_z = -pixel_shift, time = ELEVATE_TIME, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
if(new_buckled && isvehicle(new_buckled))
animate(source.buckled, pixel_z = pixel_shift, time = ELEVATE_TIME, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)

/datum/element/elevation_core/proc/on_reset_elevation(turf/source, list/current_values)
SIGNAL_HANDLER
current_values[ELEVATION_CURRENT_PIXEL_SHIFT] = pixel_shift

#undef ELEVATE_TIME
2 changes: 1 addition & 1 deletion code/datums/elements/embed.dm
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

if(blocked || !istype(victim) || HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
return FALSE

if(victim.status_flags & GODMODE)
return FALSE

Expand Down
9 changes: 5 additions & 4 deletions code/datums/elements/waddling.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
waddling_animation(moved)

/datum/element/waddling/proc/waddling_animation(atom/movable/target)
animate(target, pixel_z = 4, time = 0)
var/prev_trans = matrix(target.transform)
animate(pixel_z = 0, transform = turn(target.transform, pick(-12, 0, 12)), time=2)
animate(pixel_z = 0, transform = prev_trans, time = 0)
var/prev_pixel_z = target.pixel_z
animate(target, pixel_z = target.pixel_z + 4, time = 0)
var/prev_transform = target.transform
animate(pixel_z = prev_pixel_z, transform = turn(target.transform, pick(-12, 0, 12)), time=2)
animate(transform = prev_transform, time = 0)
2 changes: 1 addition & 1 deletion code/game/machinery/deployable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
/obj/structure/barricade/sandbags/Initialize(mapload)
. = ..()
AddElement(/datum/element/climbable)
AddElement(/datum/element/liquids_height, 20) //SKYRAT EDIT ADDITION
AddElement(/datum/element/elevation, pixel_shift = 12)

/obj/structure/barricade/security
name = "security barrier"
Expand Down
13 changes: 13 additions & 0 deletions code/game/machinery/stasis.dm
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,22 @@
var/mattress_state = "stasis_on"
var/obj/effect/overlay/vis/mattress_on

/obj/machinery/stasis/Initialize(mapload)
. = ..()
AddElement(/datum/element/elevation, pixel_shift = 6)

/obj/machinery/stasis/Destroy()
. = ..()

///Just like beds, the elevation looks good while standing, but not when buckled to the bed.
/obj/machinery/stasis/post_buckle_mob(mob/living/buckled)
. = ..()
buckled.pixel_y -= 6

/obj/machinery/stasis/post_unbuckle_mob(mob/living/buckled)
. = ..()
buckled.pixel_y += 6

/obj/machinery/stasis/examine(mob/user)
. = ..()
. += span_notice("Alt-click to [stasis_enabled ? "turn off" : "turn on"] the machine.")
Expand Down
1 change: 1 addition & 0 deletions code/game/objects/structures/beds_chairs/alien_nest.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
canSmoothWith = SMOOTH_GROUP_ALIEN_NEST
build_stack_type = null
flags_1 = NODECONSTRUCT_1
elevation = 0
var/static/mutable_appearance/nest_overlay = mutable_appearance('icons/mob/nonhuman-player/alien.dmi', "nestoverlay", LYING_MOB_LAYER)

/obj/structure/bed/nest/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user)
Expand Down
32 changes: 27 additions & 5 deletions code/game/objects/structures/beds_chairs/bed.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@
var/build_stack_type = /obj/item/stack/sheet/iron
/// How many mats to drop when deconstructed
var/build_stack_amount = 2
/// Mobs standing on it are nudged up by this amount. Also used to align the person back when buckled to it after init.
var/elevation = 8

/obj/structure/bed/Initialize(mapload)
. = ..()
AddElement(/datum/element/soft_landing)
if(elevation)
AddElement(/datum/element/elevation, pixel_shift = elevation)
register_context()

/obj/structure/bed/examine(mob/user)
Expand Down Expand Up @@ -63,6 +67,16 @@
deconstruct(disassembled = TRUE)
return TRUE

/obj/structure/bed/post_buckle_mob(mob/living/buckled)
. = ..()
buckled.base_pixel_y -= elevation
buckled.pixel_y -= elevation

/obj/structure/bed/post_unbuckle_mob(mob/living/buckled)
. = ..()
buckled.base_pixel_y += elevation
buckled.pixel_y += elevation

/// Medical beds
/obj/structure/bed/medical
name = "medical bed"
Expand All @@ -74,6 +88,7 @@
resistance_flags = NONE
build_stack_type = /obj/item/stack/sheet/mineral/titanium
build_stack_amount = 1
elevation = 0
/// The item it spawns when it's folded up.
var/foldable_type

Expand Down Expand Up @@ -117,11 +132,13 @@
balloon_alert(user, "brakes [anchored ? "applied" : "released"]")
update_appearance()

/obj/structure/bed/medical/post_buckle_mob(mob/living/patient)
/obj/structure/bed/medical/post_buckle_mob(mob/living/buckled)
. = ..()
set_density(TRUE)
update_appearance()

/obj/structure/bed/medical/post_unbuckle_mob(mob/living/patient)
/obj/structure/bed/medical/post_unbuckle_mob(mob/living/buckled)
. = ..()
set_density(FALSE)
update_appearance()

Expand All @@ -135,7 +152,6 @@
patient.pixel_y = patient.base_pixel_y
else
buckled_mobs[1].pixel_y = buckled_mobs[1].base_pixel_y

else
icon_state = "[base_icon_state]_down"

Expand Down Expand Up @@ -257,6 +273,7 @@
anchored = FALSE
build_stack_type = /obj/item/stack/sheet/mineral/wood
build_stack_amount = 10
elevation = 0
var/owned = FALSE

/obj/structure/bed/dogbed/ian
Expand Down Expand Up @@ -306,6 +323,7 @@
name = "dirty mattress"
desc = "An old grubby mattress. You try to not think about what could be the cause of those stains."
icon_state = "dirty_mattress"
elevation = 7

/obj/structure/bed/maint/Initialize(mapload)
. = ..()
Expand All @@ -322,11 +340,15 @@
var/mob/living/goldilocks

/obj/structure/bed/double/post_buckle_mob(mob/living/target)
. = ..()
if(buckled_mobs.len > 1 && !goldilocks) // Push the second buckled mob a bit higher from the normal lying position
target.pixel_y = target.base_pixel_y + 6
target.base_pixel_y += 12
target.pixel_y += 12
goldilocks = target

/obj/structure/bed/double/post_unbuckle_mob(mob/living/target)
target.pixel_y = target.base_pixel_y + target.body_position_pixel_y_offset
. = ..()
if(target == goldilocks)
target.base_pixel_y -= 12
target.pixel_y -= 12
goldilocks = null
Loading
Loading