From d6bcdcf833c98397afb01a17c0862cc64b7cc2d2 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:59:53 +0300 Subject: [PATCH] Changes wall leaning into a component, makes windows leanable (#85771) ## About The Pull Request Requires #85491 to be merged first, as otherwise leaning on directional windows looks incredibly goofy You can now lean on both fulltile and directional windows, and its possible to easily extend this functionality to other objects. Dunno if this even deserves to be called a refactor so not marking it in any way. ## Why It's Good For The Game Just makes sense that you'd be able to do it ## Changelog :cl: add: You can now lean on windows the same way you can lean on walls fix: You no longer stop leaning on walls after clicking on anything /:cl: --- .../signals/signals_mob/signals_mob_living.dm | 2 + code/datums/components/leanable.dm | 111 ++++++++++++++++++ .../game/objects/structures/windows/window.dm | 20 ++++ code/game/turfs/closed/walls.dm | 73 ++---------- tgstation.dme | 1 + 5 files changed, 145 insertions(+), 62 deletions(-) create mode 100644 code/datums/components/leanable.dm diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 285c0b0ac4e..8305b356957 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -294,3 +294,5 @@ #define COMSIG_MOB_ENSLAVED_TO "mob_enslaved_to" /// From /obj/item/proc/attack_atom: (mob/living/attacker, atom/attacked) #define COMSIG_LIVING_ATTACK_ATOM "living_attack_atom" +/// From /mob/living/proc/stop_leaning() +#define COMSIG_LIVING_STOPPED_LEANING "living_stopped_leaning" diff --git a/code/datums/components/leanable.dm b/code/datums/components/leanable.dm new file mode 100644 index 00000000000..24dbcc601ae --- /dev/null +++ b/code/datums/components/leanable.dm @@ -0,0 +1,111 @@ +/// Things with this component can be leaned onto, optionally exclusive to RMB dragging +/datum/component/leanable + /// How much will mobs that lean onto this object be offset + var/leaning_offset = 11 + /// List of click modifiers that are required to be present for leaning to trigger + var/list/click_mods = null + /// Callback called for additional checks if a lean is valid + var/datum/callback/lean_check = null + /// Whenever this object can be leaned on from the same turf as its' own. Do not use without a custom lean_check! + var/same_turf = FALSE + /// List of mobs currently leaning on our parent + var/list/leaning_mobs = list() + +/datum/component/leanable/Initialize(leaning_offset = 11, list/click_mods = null, datum/callback/lean_check = null, same_turf = FALSE) + . = ..() + src.leaning_offset = leaning_offset + src.click_mods = click_mods + src.lean_check = lean_check + src.same_turf = same_turf + +/datum/component/leanable/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(mousedrop_receive)) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + +/datum/component/leanable/Destroy(force) + for (var/mob/living/leaner as anything in leaning_mobs) + leaner.stop_leaning() + leaning_mobs = null + return ..() + +/datum/component/leanable/proc/on_moved(datum/source) + SIGNAL_HANDLER + for (var/mob/living/leaner as anything in leaning_mobs) + leaner.stop_leaning() + +/datum/component/leanable/proc/mousedrop_receive(atom/source, atom/movable/dropped, mob/user, params) + if (dropped != user) + return + if (islist(click_mods)) + var/list/modifiers = params2list(params) + for (var/modifier in click_mods) + if (!LAZYACCESS(modifiers, modifier)) + return + if (!iscarbon(dropped) && !iscyborg(dropped)) + return + var/mob/living/leaner = dropped + if (leaner.incapacitated(IGNORE_RESTRAINTS) || leaner.stat != CONSCIOUS || HAS_TRAIT(leaner, TRAIT_NO_TRANSFORM)) + return + if (HAS_TRAIT_FROM(leaner, TRAIT_UNDENSE, LEANING_TRAIT)) + return + var/turf/checked_turf = get_step(leaner, REVERSE_DIR(leaner.dir)) + if (checked_turf != get_turf(source) && (!same_turf || get_turf(source) != get_turf(leaner))) + return + if (!isnull(lean_check) && !lean_check.Invoke(dropped, params)) + return + leaner.start_leaning(source, leaning_offset) + leaning_mobs += leaner + RegisterSignals(leaner, list(COMSIG_LIVING_STOPPED_LEANING, COMSIG_QDELETING), PROC_REF(stopped_leaning)) + return COMPONENT_CANCEL_MOUSEDROPPED_ONTO + +/datum/component/leanable/proc/stopped_leaning(datum/source) + SIGNAL_HANDLER + leaning_mobs -= source + UnregisterSignal(source, list(COMSIG_LIVING_STOPPED_LEANING, COMSIG_QDELETING)) + +/mob/living/proc/start_leaning(atom/lean_target, leaning_offset) + var/new_y = base_pixel_y + pixel_y + var/new_x = base_pixel_x + pixel_x + switch(dir) + if(SOUTH) + new_y += leaning_offset + if(NORTH) + new_y -= leaning_offset + if(WEST) + new_x += leaning_offset + if(EAST) + new_x -= leaning_offset + + animate(src, 0.2 SECONDS, pixel_x = new_x, pixel_y = new_y) + add_traits(list(TRAIT_UNDENSE, TRAIT_EXPANDED_FOV), LEANING_TRAIT) + visible_message( + span_notice("[src] leans against [lean_target]."), + span_notice("You lean against [lean_target]."), + ) + RegisterSignals(src, list( + COMSIG_MOB_CLIENT_PRE_MOVE, + COMSIG_LIVING_DISARM_HIT, + COMSIG_LIVING_GET_PULLED, + COMSIG_MOVABLE_TELEPORTING, + ), PROC_REF(stop_leaning)) + RegisterSignal(src, COMSIG_ATOM_POST_DIR_CHANGE, PROC_REF(lean_dir_changed)) + update_fov() + +/mob/living/proc/stop_leaning() + SIGNAL_HANDLER + UnregisterSignal(src, list( + COMSIG_MOB_CLIENT_PRE_MOVE, + COMSIG_LIVING_DISARM_HIT, + COMSIG_LIVING_GET_PULLED, + COMSIG_MOVABLE_TELEPORTING, + COMSIG_ATOM_POST_DIR_CHANGE, + )) + animate(src, 0.2 SECONDS, pixel_x = base_pixel_x, pixel_y = base_pixel_y) + remove_traits(list(TRAIT_UNDENSE, TRAIT_EXPANDED_FOV), LEANING_TRAIT) + SEND_SIGNAL(src, COMSIG_LIVING_STOPPED_LEANING) + update_fov() + +/mob/living/proc/lean_dir_changed(atom/source, old_dir, new_dir) + SIGNAL_HANDLER + if (old_dir != new_dir) + INVOKE_ASYNC(src, PROC_REF(stop_leaning)) diff --git a/code/game/objects/structures/windows/window.dm b/code/game/objects/structures/windows/window.dm index 37823278634..3975993066c 100644 --- a/code/game/objects/structures/windows/window.dm +++ b/code/game/objects/structures/windows/window.dm @@ -41,6 +41,8 @@ var/datum/material/glass_material_datum = /datum/material/glass /// Whether or not we're disappearing but dramatically var/dramatically_disappearing = FALSE + /// If we added a leaning component to ourselves + var/added_leaning = FALSE /datum/armor/structure_window melee = 50 @@ -90,6 +92,24 @@ if (flags_1 & ON_BORDER_1) AddElement(/datum/element/connect_loc, loc_connections) +/obj/structure/window/mouse_drop_receive(atom/dropping, mob/user, params) + . = ..() + if (added_leaning) + return + /// For performance reasons and to cut down on init times we are "lazy-loading" the leaning component when someone drags their sprite onto us, and then calling dragging code again to trigger the component + AddComponent(/datum/component/leanable, 11, same_turf = (flags_1 & ON_BORDER_1), lean_check = CALLBACK(src, PROC_REF(lean_check))) + added_leaning = TRUE + dropping.base_mouse_drop_handler(src, null, null, params) + +/obj/structure/window/proc/lean_check(mob/living/leaner, list/modifiers) + if (!(flags_1 & ON_BORDER_1)) + return TRUE + + if (leaner.loc == loc) + return dir == REVERSE_DIR(leaner.dir) + + return get_dir(src, leaner) == dir && leaner.dir == dir + /obj/structure/window/setDir(newdir) . = ..() if(fulltile) diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 9f6d3db4d0a..27b320a1a0c 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -1,5 +1,3 @@ -#define LEANING_OFFSET 11 - /turf/closed/wall name = "wall" desc = "A huge chunk of iron used to separate rooms." @@ -30,67 +28,11 @@ var/girder_type = /obj/structure/girder /// A turf that will replace this turf when this turf is destroyed var/decon_type + /// If we added a leaning component to ourselves + var/added_leaning = FALSE var/list/dent_decals -/turf/closed/wall/mouse_drop_receive(atom/dropping, mob/user, params) - if(dropping != user) - return - if(!iscarbon(dropping) && !iscyborg(dropping)) - return - var/mob/living/leaner = dropping - if(leaner.incapacitated(IGNORE_RESTRAINTS) || leaner.stat != CONSCIOUS || HAS_TRAIT(leaner, TRAIT_NO_TRANSFORM)) - return - if(!leaner.density || leaner.pulledby || leaner.buckled || !(leaner.mobility_flags & MOBILITY_STAND)) - return - if(HAS_TRAIT_FROM(leaner, TRAIT_UNDENSE, LEANING_TRAIT)) - return - var/turf/checked_turf = get_step(leaner, REVERSE_DIR(leaner.dir)) - if(checked_turf != src) - return - leaner.start_leaning(src) - -/mob/living/proc/start_leaning(turf/closed/wall/wall) - var/new_y = base_pixel_y + pixel_y - var/new_x = base_pixel_x + pixel_x - switch(dir) - if(SOUTH) - new_y += LEANING_OFFSET - if(NORTH) - new_y -= LEANING_OFFSET - if(WEST) - new_x += LEANING_OFFSET - if(EAST) - new_x -= LEANING_OFFSET - - animate(src, 0.2 SECONDS, pixel_x = new_x, pixel_y = new_y) - add_traits(list(TRAIT_UNDENSE, TRAIT_EXPANDED_FOV), LEANING_TRAIT) - visible_message( - span_notice("[src] leans against [wall]."), - span_notice("You lean against [wall]."), - ) - RegisterSignals(src, list( - COMSIG_MOB_CLIENT_PRE_MOVE, - COMSIG_LIVING_DISARM_HIT, - COMSIG_LIVING_GET_PULLED, - COMSIG_MOVABLE_TELEPORTING, - COMSIG_ATOM_DIR_CHANGE, - ), PROC_REF(stop_leaning)) - update_fov() - -/mob/living/proc/stop_leaning() - SIGNAL_HANDLER - UnregisterSignal(src, list( - COMSIG_MOB_CLIENT_PRE_MOVE, - COMSIG_LIVING_DISARM_HIT, - COMSIG_LIVING_GET_PULLED, - COMSIG_MOVABLE_TELEPORTING, - COMSIG_ATOM_DIR_CHANGE, - )) - animate(src, 0.2 SECONDS, pixel_x = base_pixel_x, pixel_y = base_pixel_y) - remove_traits(list(TRAIT_UNDENSE, TRAIT_EXPANDED_FOV), LEANING_TRAIT) - update_fov() - /turf/closed/wall/Initialize(mapload) . = ..() if(!can_engrave) @@ -107,6 +49,15 @@ fixed_underlay = string_assoc_list(fixed_underlay) underlays += underlay_appearance +/turf/closed/wall/mouse_drop_receive(atom/dropping, mob/user, params) + . = ..() + if (added_leaning) + return + /// For performance reasons and to cut down on init times we are "lazy-loading" the leaning component when someone drags their sprite onto us, and then calling dragging code again to trigger the component + AddComponent(/datum/component/leanable, 11) + added_leaning = TRUE + dropping.base_mouse_drop_handler(src, null, null, params) + /turf/closed/wall/atom_destruction(damage_flag) . = ..() dismantle_wall(TRUE, FALSE) @@ -389,5 +340,3 @@ /turf/closed/wall/Exited(atom/movable/gone, direction) . = ..() SEND_SIGNAL(gone, COMSIG_LIVING_WALL_EXITED, src) - -#undef LEANING_OFFSET diff --git a/tgstation.dme b/tgstation.dme index 7c487ab7466..201270a73bc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1149,6 +1149,7 @@ #include "code\datums\components\jukebox.dm" #include "code\datums\components\keep_me_secure.dm" #include "code\datums\components\knockoff.dm" +#include "code\datums\components\leanable.dm" #include "code\datums\components\leash.dm" #include "code\datums\components\life_link.dm" #include "code\datums\components\light_eater.dm"