From d08dac835b89cee7d96a8576315bd803c2657629 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Thu, 5 Sep 2024 10:28:17 -0400 Subject: [PATCH 01/19] refactor: Movement cross/uncross implementation. --- code/__DEFINES/dcs/atom_signals.dm | 2 +- code/__DEFINES/dcs/movable_signals.dm | 15 +- code/__DEFINES/is_helpers.dm | 2 + code/__DEFINES/movement_info.dm | 21 ++ code/datums/beam.dm | 22 +- code/datums/components/caltrop.dm | 21 +- code/datums/components/connect_loc_behalf.dm | 69 ++++ code/datums/components/proximity_monitor.dm | 18 +- code/datums/components/slippery.dm | 16 +- code/datums/components/squeak.dm | 25 +- code/datums/components/swarming.dm | 16 +- code/datums/elements/connect_loc.dm | 43 +++ code/datums/spells/spacetime_dist.dm | 12 +- code/game/atoms.dm | 18 +- code/game/atoms_movable.dm | 298 +++++++++++++++--- code/game/gamemodes/cult/cult_structures.dm | 3 - .../miniantags/guardian/types/protector.dm | 2 +- .../miniantags/guardian/types/ranged.dm | 15 +- .../pulsedemon/cross_shock_component.dm | 16 +- .../miniantags/pulsedemon/pulsedemon.dm | 17 +- code/game/machinery/OpTable.dm | 2 +- code/game/machinery/deployable.dm | 15 +- code/game/machinery/doors/airlock.dm | 2 +- code/game/machinery/doors/airlock_types.dm | 2 +- code/game/machinery/doors/door.dm | 2 +- code/game/machinery/doors/firedoor.dm | 31 +- code/game/machinery/doors/windowdoor.dm | 30 +- code/game/machinery/shieldgen.dm | 4 +- code/game/machinery/tcomms/relay.dm | 2 +- code/game/machinery/tcomms/tcomms_base.dm | 2 +- code/game/machinery/tcomms/tcomms_core.dm | 2 +- code/game/machinery/teleporter.dm | 25 +- code/game/machinery/vendors/vending.dm | 5 +- code/game/objects/effects/alien_acid.dm | 14 +- code/game/objects/effects/anomalies.dm | 14 +- .../effects/decals/Cleanable/humans.dm | 12 +- .../decals/Cleanable/misc_cleanables.dm | 9 +- .../objects/effects/decals/Cleanable/tar.dm | 8 +- .../effects/decals/Cleanable/tracks.dm | 119 +++---- code/game/objects/effects/decals/cleanable.dm | 12 +- .../effects/effect_system/effects_foam.dm | 11 +- .../effects/effect_system/effects_smoke.dm | 6 +- code/game/objects/effects/forcefields.dm | 2 +- code/game/objects/effects/mines.dm | 10 +- code/game/objects/effects/portals.dm | 19 +- code/game/objects/effects/spiders.dm | 2 +- code/game/objects/effects/step_triggers.dm | 22 +- code/game/objects/items/stacks/stack.dm | 17 +- code/game/objects/items/toys.dm | 15 +- .../chemical_flamethrower/fire_effect.dm | 18 +- code/game/objects/items/weapons/explosives.dm | 5 +- .../items/weapons/grenades/chem_grenade.dm | 9 +- code/game/objects/items/weapons/legcuffs.dm | 29 +- code/game/objects/items/weapons/shards.dm | 9 +- .../items/weapons/storage/briefcase.dm | 2 +- code/game/objects/structures/coathanger.dm | 2 +- .../structures/crates_lockers/closets.dm | 22 +- code/game/objects/structures/fence.dm | 2 +- code/game/objects/structures/girders.dm | 2 +- code/game/objects/structures/grille.dm | 2 +- code/game/objects/structures/holosigns.dm | 2 +- code/game/objects/structures/inflatable.dm | 4 +- code/game/objects/structures/mineral_doors.dm | 2 +- code/game/objects/structures/morgue.dm | 2 +- code/game/objects/structures/nest.dm | 10 +- code/game/objects/structures/railings.dm | 59 ++-- code/game/objects/structures/tables_racks.dm | 48 +-- .../structures/transit_tubes/transit_tube.dm | 2 +- code/game/objects/structures/watercloset.dm | 9 +- .../objects/structures/windoor_assembly.dm | 24 +- code/game/objects/structures/window.dm | 26 +- .../turfs/simulated/floor/asteroid_floors.dm | 15 +- code/game/turfs/simulated/floor/chasm.dm | 2 +- code/game/turfs/turf.dm | 67 ++-- .../changeling/powers/mutations.dm | 6 +- .../vampire_powers/hemomancer_powers.dm | 2 +- .../vampire/vampire_powers/umbrae_powers.dm | 10 +- code/modules/assembly/assembly.dm | 6 + code/modules/assembly/assembly_holder.dm | 14 +- code/modules/assembly/bomb.dm | 11 +- code/modules/assembly/infrared.dm | 9 +- code/modules/assembly/mousetrap.dm | 14 +- .../atmospherics/environmental/LINDA_fire.dm | 11 +- .../environmental/LINDA_system.dm | 10 +- .../mission_code/ruins/deepstorage.dm | 4 +- .../mission_code/ruins/telecomns.dm | 21 +- .../mission_code/shuttle_shadow.dm | 12 +- code/modules/events/blob/blob_mobs.dm | 2 +- .../events/blob/blob_structures/blob_core.dm | 4 +- .../blob/blob_structures/strong_blob.dm | 2 +- code/modules/events/blob/theblob.dm | 11 +- code/modules/events/spacevine.dm | 11 +- code/modules/hydroponics/grown/towercap.dm | 10 +- code/modules/hydroponics/hydroponics_tray.dm | 2 +- .../lighting/lighting_emissive_blocker.dm | 4 +- code/modules/lighting/lighting_object.dm | 4 +- code/modules/mining/ores_coins.dm | 27 +- code/modules/mining/satchel_ore_boxdm.dm | 5 +- code/modules/mob/dead/dead.dm | 6 +- .../mob/dead/observer/observer_base.dm | 2 +- .../living/carbon/alien/special/facehugger.dm | 4 - code/modules/mob/living/living.dm | 13 +- .../mob/living/simple_animal/bot/griefsky.dm | 8 +- .../mob/living/simple_animal/bot/honkbot.dm | 9 +- .../mob/living/simple_animal/bot/mulebot.dm | 2 +- .../mob/living/simple_animal/bot/secbot.dm | 8 +- .../simple_animal/friendly/cockroach.dm | 11 +- .../living/simple_animal/friendly/mouse.dm | 11 +- .../simple_animal/hostile/floorcluwne.dm | 2 +- .../hostile/megafauna/ancient_robot.dm | 14 +- .../hostile/megafauna/bubblegum.dm | 8 +- .../hostile/megafauna/hierophant.dm | 6 +- .../hostile/megafauna/megafauna.dm | 2 +- .../hostile/mining/elites/legionnaire.dm | 14 +- .../simple_animal/hostile/syndicate_mobs.dm | 2 +- .../hostile/terror_spiders/actions.dm | 11 +- .../hostile/terror_spiders/mother.dm | 2 +- .../simple_animal/hostile/venus_human_trap.dm | 9 +- .../mob/living/simple_animal/simple_animal.dm | 6 +- code/modules/mob/mob_movement.dm | 2 +- .../engines/singularity/containment_field.dm | 16 +- .../particle_accelerator/particle.dm | 4 +- .../power/engines/singularity/singularity.dm | 11 +- .../power/engines/supermatter/supermatter.dm | 2 +- .../power/engines/tesla/energy_ball.dm | 13 +- code/modules/power/generators/treadmill.dm | 22 +- code/modules/power/lights.dm | 9 +- .../projectile/special_projectiles.dm | 4 +- code/modules/projectiles/projectile_base.dm | 17 +- .../reagent_containers/glass_containers.dm | 11 +- .../reagents/reagent_containers/syringes.dm | 10 +- code/modules/reagents/reagent_dispenser.dm | 11 +- code/modules/recycling/conveyor2.dm | 7 +- code/modules/recycling/disposal.dm | 2 +- code/modules/recycling/sortingmachinery.dm | 2 +- .../ruins/lavalandruin_code/sin_ruins.dm | 2 +- .../ruins/objects_and_mobs/necropolis_gate.dm | 19 +- code/modules/shuttle/on_move.dm | 2 +- code/modules/surgery/organs/organ.dm | 9 +- code/modules/vehicle/vehicle.dm | 2 +- paradise.dme | 3 + 141 files changed, 1307 insertions(+), 676 deletions(-) create mode 100644 code/__DEFINES/movement_info.dm create mode 100644 code/datums/components/connect_loc_behalf.dm create mode 100644 code/datums/elements/connect_loc.dm diff --git a/code/__DEFINES/dcs/atom_signals.dm b/code/__DEFINES/dcs/atom_signals.dm index 574552e87d22..f4f9227d7e86 100644 --- a/code/__DEFINES/dcs/atom_signals.dm +++ b/code/__DEFINES/dcs/atom_signals.dm @@ -40,7 +40,7 @@ #define COMSIG_ATOM_UPDATE_OVERLAYS "atom_update_overlays" ///from base of [/atom/update_icon]: (signalOut, did_anything) #define COMSIG_ATOM_UPDATED_ICON "atom_updated_icon" -///from base of atom/Entered(): (atom/movable/entering, /atom) +///from base of atom/Entered(): (atom/movable/entered, /atom) #define COMSIG_ATOM_ENTERED "atom_entered" ///from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc) #define COMSIG_ATOM_EXIT "atom_exit" diff --git a/code/__DEFINES/dcs/movable_signals.dm b/code/__DEFINES/dcs/movable_signals.dm index 2d197e1d0dd4..fdf8dbb60e40 100644 --- a/code/__DEFINES/dcs/movable_signals.dm +++ b/code/__DEFINES/dcs/movable_signals.dm @@ -4,21 +4,22 @@ * All signals send the source datum of the signal as the first argument */ +///from base of atom/movable/Moved(): (/atom) +#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" + #define COMPONENT_MOVABLE_BLOCK_PRE_MOVE (1<<0) ///from base of atom/movable/Moved(): (/atom, dir) #define COMSIG_MOVABLE_MOVED "movable_moved" ///from base of atom/movable/Cross(): (/atom/movable) #define COMSIG_MOVABLE_CROSS "movable_cross" -///from base of atom/movable/Crossed(): (/atom/movable) -#define COMSIG_MOVABLE_CROSSED "movable_crossed" -///when we cross over something (calling Crossed() on that atom) -#define COMSIG_CROSSED_MOVABLE "crossed_movable" + #define COMPONENT_BLOCK_CROSS (1<<0) +///from base of atom/movable/Move(): (/atom/movable) +#define COMSIG_MOVABLE_CROSS_OVER "movable_cross_over" ///from base of atom/movable/Uncross(): (/atom/movable) #define COMSIG_MOVABLE_UNCROSS "movable_uncross" #define COMPONENT_MOVABLE_BLOCK_UNCROSS (1<<0) -///from base of atom/movable/Uncrossed(): (/atom/movable) -#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed" ///from base of atom/movable/Bump(): (/atom) #define COMSIG_MOVABLE_BUMP "movable_bump" + #define COMPONENT_INTERCEPT_BUMPED (1<<0) ///from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum) #define COMSIG_MOVABLE_IMPACT "movable_impact" #define COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH (1<<0) //if true, flip if the impact will push what it hits @@ -39,7 +40,7 @@ #define COMSIG_MOVABLE_POST_THROW "movable_post_throw" ///from base of datum/thrownthing/finalize(): (obj/thrown_object, datum/thrownthing) used for when a throw is finished #define COMSIG_MOVABLE_THROW_LANDED "movable_throw_landed" -///from base of atom/movable/onTransitZ(): (old_z, new_z) +///from base of atom/movable/on_changed_z_level(): (turf/old_turf, turf/new_turf) #define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" /// Called just before something gets untilted diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 63319d1b5d30..0e516c117453 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -147,3 +147,5 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list( #define ispassmeteorturf(A) (is_type_in_typecache(A, GLOB.turfs_pass_meteor)) #define is_screen_atom(A) istype(A, /atom/movable/screen) + +#define is_multi_tile_object(atom) (atom.bound_width > world.icon_size || atom.bound_height > world.icon_size) diff --git a/code/__DEFINES/movement_info.dm b/code/__DEFINES/movement_info.dm new file mode 100644 index 000000000000..91d370f6c75f --- /dev/null +++ b/code/__DEFINES/movement_info.dm @@ -0,0 +1,21 @@ +#define ACTIVE_MOVEMENT_OLDLOC 1 +#define ACTIVE_MOVEMENT_DIRECTION 2 +#define ACTIVE_MOVEMENT_FORCED 3 +#define ACTIVE_MOVEMENT_OLDLOCS 4 + +/// The arguments of this macro correspond directly to the argument order of /atom/movable/proc/Moved +#define SET_ACTIVE_MOVEMENT(_old_loc, _direction, _forced, _oldlocs) \ + active_movement = list( \ + _old_loc, \ + _direction, \ + _forced, \ + _oldlocs, \ + ) + +/// Finish any active movements +#define RESOLVE_ACTIVE_MOVEMENT \ + if(active_movement) { \ + var/__move_args = active_movement; \ + active_movement = null; \ + Moved(arglist(__move_args)); \ + } diff --git a/code/datums/beam.dm b/code/datums/beam.dm index f35cc240ac8a..46709ed98ecd 100644 --- a/code/datums/beam.dm +++ b/code/datums/beam.dm @@ -118,6 +118,16 @@ anchored = TRUE var/datum/beam/owner +/obj/effect/ebeam/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + +/obj/effect/ebeam/proc/on_atom_entered(datum/source, atom/movable/entered) + return + /obj/effect/ebeam/ex_act(severity) return @@ -131,9 +141,8 @@ /obj/effect/ebeam/singularity_act() return -/obj/effect/ebeam/deadly/Crossed(atom/A, oldloc) - ..() - A.ex_act(EXPLODE_DEVASTATE) +/obj/effect/ebeam/deadly/on_atom_entered(datum/source, atom/movable/entered) + entered.ex_act(EXPLODE_DEVASTATE) /obj/effect/ebeam/vetus/Destroy() for(var/mob/living/M in get_turf(src)) @@ -147,11 +156,10 @@ /obj/effect/ebeam/disintegration layer = ON_EDGED_TURF_LAYER -/obj/effect/ebeam/disintegration/Crossed(atom/A, oldloc) - ..() - if(!isliving(A)) +/obj/effect/ebeam/disintegration/on_atom_entered(datum/source, atom/movable/entered) + if(!isliving(entered)) return - var/mob/living/L = A + var/mob/living/L = entered var/damage = 50 if(L.stat == DEAD) visible_message("[L] is disintegrated by the beam!") diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm index bca3cc8056ae..a18873a86197 100644 --- a/code/datums/components/caltrop.dm +++ b/code/datums/components/caltrop.dm @@ -14,6 +14,11 @@ ///Shoebypassing, walking interaction, silence var/flags + ///given to connect_loc to listen for something moving over target + var/static/list/crossed_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + ) + var/cooldown = 0 /datum/component/caltrop/Initialize(_min_damage = 0, _max_damage = 0, _probability = 100, _weaken_duration = 6 SECONDS, _flags = NONE) @@ -23,10 +28,12 @@ src.weaken_duration = _weaken_duration src.flags = _flags -/datum/component/caltrop/RegisterWithParent() - RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, PROC_REF(Crossed)) + if(ismovable(parent)) + AddComponent(/datum/component/connect_loc_behalf, parent, crossed_connections) + else + RegisterSignal(get_turf(parent), COMSIG_ATOM_ENTERED, PROC_REF(on_entered)) -/datum/component/caltrop/proc/Crossed(datum/source, atom/movable/AM) +/datum/component/caltrop/proc/on_entered(atom/source, atom/movable/entered, turf/old_loc) var/atom/A = parent if(!has_gravity(A)) return @@ -34,10 +41,10 @@ if(!prob(probability)) return - if(!ishuman(AM)) + if(!ishuman(entered)) return - var/mob/living/carbon/human/H = AM + var/mob/living/carbon/human/H = entered if(HAS_TRAIT(H, TRAIT_PIERCEIMMUNE)) return @@ -82,3 +89,7 @@ cooldown = world.time H.Weaken(weaken_duration) + +/datum/component/caltrop/UnregisterFromParent() + if(ismovable(parent)) + qdel(GetComponent(/datum/component/connect_loc_behalf)) diff --git a/code/datums/components/connect_loc_behalf.dm b/code/datums/components/connect_loc_behalf.dm new file mode 100644 index 000000000000..b24685a1091a --- /dev/null +++ b/code/datums/components/connect_loc_behalf.dm @@ -0,0 +1,69 @@ +/// This component behaves similar to connect_loc, hooking into a signal on a tracked object's turf +/// It has the ability to react to that signal on behalf of a separate listener however +/// This has great use, primarily for components, but it carries with it some overhead +/// So we do it separately as it needs to hold state which is very likely to lead to bugs if it remains as an element. +/datum/component/connect_loc_behalf + dupe_mode = COMPONENT_DUPE_UNIQUE + + /// An assoc list of signal -> procpath to register to the loc this object is on. + var/list/connections + + var/atom/movable/tracked + + var/atom/tracked_loc + +/datum/component/connect_loc_behalf/Initialize(atom/movable/tracked, list/connections) + . = ..() + if(!istype(tracked)) + return COMPONENT_INCOMPATIBLE + src.connections = connections + src.tracked = tracked + +/datum/component/connect_loc_behalf/RegisterWithParent() + RegisterSignal(tracked, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + RegisterSignal(tracked, COMSIG_PARENT_QDELETING, PROC_REF(handle_tracked_qdel)) + update_signals() + +/datum/component/connect_loc_behalf/UnregisterFromParent() + unregister_signals() + UnregisterSignal(tracked, list( + COMSIG_MOVABLE_MOVED, + COMSIG_PARENT_QDELETING, + )) + + tracked = null + +/datum/component/connect_loc_behalf/proc/handle_tracked_qdel() + SIGNAL_HANDLER + qdel(src) + +/datum/component/connect_loc_behalf/proc/update_signals() + unregister_signals() + //You may ask yourself, isn't this just silencing an error? + //The answer is yes, but there's no good cheap way to fix it + //What happens is the tracked object or hell the listener gets say, deleted, which makes targets[old_loc] return a null + //The null results in a bad index, because of course it does + //It's not a solvable problem though, since both actions, the destroy and the move, are sourced from the same signal send + //And sending a signal should be agnostic of the order of listeners + //So we need to either pick the order agnositic, or destroy safe + //And I picked destroy safe. Let's hope this is the right path! + if(isnull(tracked.loc)) + return + + tracked_loc = tracked.loc + + for(var/signal in connections) + parent.RegisterSignal(tracked_loc, signal, connections[signal]) + +/datum/component/connect_loc_behalf/proc/unregister_signals() + if(isnull(tracked_loc)) + return + + parent.UnregisterSignal(tracked_loc, connections) + + tracked_loc = null + +/datum/component/connect_loc_behalf/proc/on_moved(sigtype, atom/movable/tracked, atom/old_loc) + SIGNAL_HANDLER + update_signals() + diff --git a/code/datums/components/proximity_monitor.dm b/code/datums/components/proximity_monitor.dm index b37712b9d1f7..3d13acad20ad 100644 --- a/code/datums/components/proximity_monitor.dm +++ b/code/datums/components/proximity_monitor.dm @@ -268,6 +268,10 @@ /obj/effect/abstract/proximity_checker/Initialize(mapload, datum/component/proximity_monitor/P) . = ..() monitor = P + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) /obj/effect/abstract/proximity_checker/Destroy() monitor.proximity_checkers -= src @@ -276,13 +280,9 @@ /** * Called when something crossed over the proximity_checker. Notifies the `hasprox_receiver` it has proximity with something. - * - * Arguments: - * * atom/movable/AM - the atom crossing the proximity checker - * * oldloc - the location `AM` used to be at */ -/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM, oldloc) - set waitfor = FALSE - . = ..() - if(active && AM != monitor.hasprox_receiver && !(AM in monitor.nested_receiver_locs)) - monitor.hasprox_receiver.HasProximity(AM) +/obj/effect/abstract/proximity_checker/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + + if(active && entered != monitor.hasprox_receiver && !(entered in monitor.nested_receiver_locs)) + monitor.hasprox_receiver.HasProximity(entered) diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm index 4488c8dcb838..9f6a9b91a519 100644 --- a/code/datums/components/slippery.dm +++ b/code/datums/components/slippery.dm @@ -24,6 +24,10 @@ var/slip_verb /// TRUE the player will only slip if the mob this datum is attached to is horizontal var/horizontal_required + ///what we give to connect_loc by default, makes slippable mobs moving over us slip + var/static/list/default_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(slip), + ) /datum/component/slippery/Initialize(_description, _knockdown = 0, _slip_chance = 100, _slip_tiles = 0, _walking_is_safe = TRUE, _slip_always = FALSE, _slip_verb = "slip", _horizontal_required = FALSE) if(!isatom(parent)) @@ -38,11 +42,12 @@ slip_verb = _slip_verb horizontal_required = _horizontal_required -/datum/component/slippery/RegisterWithParent() - RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), PROC_REF(Slip)) + add_connect_loc_behalf_to_parent() + RegisterSignals(parent, list(COMSIG_ATOM_ENTERED, COMSIG_MOVABLE_CROSS_OVER), PROC_REF(slip)) -/datum/component/slippery/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED)) +/datum/component/slippery/proc/add_connect_loc_behalf_to_parent() + if(ismovable(parent)) + AddComponent(/datum/component/connect_loc_behalf, parent, default_connections) /** Called whenever the parent receives either the `MOVABLE_CROSSED` signal or the `ATOM_ENTERED` signal. @@ -50,7 +55,8 @@ Calls the `victim`'s `slip()` proc with the component's variables as arguments. Additionally calls the parent's `after_slip()` proc on the `victim`. */ -/datum/component/slippery/proc/Slip(datum/source, mob/living/carbon/human/victim) +/datum/component/slippery/proc/slip(datum/source, mob/living/carbon/human/victim) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED if(istype(victim) && !victim.flying) var/atom/movable/owner = parent if(!isturf(owner.loc)) diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index c2aef66bcaaf..ba73c1f9c38f 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -19,13 +19,20 @@ ///sound exponent for squeak. Defaults to 10 as squeaking is loud and annoying enough. var/sound_falloff_exponent = 10 + ///what we set connect_loc to if parent is an item + var/static/list/item_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(play_squeak_crossed), + ) + + /datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override, squeak_on_move, extrarange, falloff_exponent, fallof_distance) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE RegisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), PROC_REF(play_squeak)) if(ismovable(parent)) RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), PROC_REF(play_squeak)) - RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, PROC_REF(play_squeak_crossed)) + + AddComponent(/datum/component/connect_loc_behalf, parent, item_connections) RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, PROC_REF(disposing_react)) if(squeak_on_move) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(play_squeak)) @@ -71,20 +78,20 @@ else steps++ -/datum/component/squeak/proc/play_squeak_crossed(atom/movable/AM) - if(isitem(AM)) - var/obj/item/I = AM +/datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/enterer, old_loc) + if(isitem(enterer)) + var/obj/item/I = enterer if(I.flags & ABSTRACT) return - else if(isprojectile(AM)) - var/obj/item/projectile/P = AM + else if(isprojectile(enterer)) + var/obj/item/projectile/P = enterer if(P.original != parent) return - if(ismob(AM)) - var/mob/M = AM + if(ismob(enterer)) + var/mob/M = enterer if(M.flying) return - if(isliving(AM)) + if(isliving(enterer)) var/mob/living/L = M if(L.floating) return diff --git a/code/datums/components/swarming.dm b/code/datums/components/swarming.dm index 928589fbaaa8..608359d49089 100644 --- a/code/datums/components/swarming.dm +++ b/code/datums/components/swarming.dm @@ -3,6 +3,11 @@ var/offset_y = 0 var/is_swarming = FALSE var/list/swarm_members = list() + var/static/list/swarming_loc_connections = list( + COMSIG_ATOM_EXITED = PROC_REF(leave_swarm), + COMSIG_ATOM_ENTERED = PROC_REF(join_swarm) + ) + /datum/component/swarming/Initialize(max_x = 24, max_y = 24) if(!ismovable(parent)) @@ -10,8 +15,7 @@ offset_x = rand(-max_x, max_x) offset_y = rand(-max_y, max_y) - RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, PROC_REF(join_swarm)) - RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, PROC_REF(leave_swarm)) + AddComponent(/datum/component/connect_loc_behalf, parent, swarming_loc_connections) /datum/component/swarming/Destroy() for(var/other in swarm_members) @@ -22,8 +26,8 @@ swarm_members = null return ..() -/datum/component/swarming/proc/join_swarm(datum/source, atom/movable/AM) - var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming) +/datum/component/swarming/proc/join_swarm(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) + var/datum/component/swarming/other_swarm = arrived.GetComponent(/datum/component/swarming) if(!other_swarm) return swarm() @@ -31,8 +35,8 @@ other_swarm.swarm() other_swarm.swarm_members |= src -/datum/component/swarming/proc/leave_swarm(datum/source, atom/movable/AM) - var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming) +/datum/component/swarming/proc/leave_swarm(datum/source, atom/movable/gone, direction) + var/datum/component/swarming/other_swarm = gone.GetComponent(/datum/component/swarming) if(!other_swarm || !(other_swarm in swarm_members)) return swarm_members -= other_swarm diff --git a/code/datums/elements/connect_loc.dm b/code/datums/elements/connect_loc.dm new file mode 100644 index 000000000000..42e0d473bc6c --- /dev/null +++ b/code/datums/elements/connect_loc.dm @@ -0,0 +1,43 @@ +/// This element hooks a signal onto the loc the current object is on. +/// When the object moves, it will unhook the signal and rehook it to the new object. +/datum/element/connect_loc + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + + /// An assoc list of signal -> procpath to register to the loc this object is on. + var/list/connections + +/datum/element/connect_loc/Attach(atom/movable/listener, list/connections) + . = ..() + if(!istype(listener)) + return ELEMENT_INCOMPATIBLE + + src.connections = connections + + RegisterSignal(listener, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved), override = TRUE) + update_signals(listener) + +/datum/element/connect_loc/Detach(atom/movable/listener) + . = ..() + unregister_signals(listener, listener.loc) + UnregisterSignal(listener, COMSIG_MOVABLE_MOVED) + +/datum/element/connect_loc/proc/update_signals(atom/movable/listener) + var/atom/listener_loc = listener.loc + if(QDELETED(listener) || QDELETED(listener_loc)) + return + + for(var/signal in connections) + //override=TRUE because more than one connect_loc element instance tracked object can be on the same loc + listener.RegisterSignal(listener_loc, signal, connections[signal], override=TRUE) + +/datum/element/connect_loc/proc/unregister_signals(datum/listener, atom/old_loc) + if(isnull(old_loc)) + return + + listener.UnregisterSignal(old_loc, connections) + +/datum/element/connect_loc/proc/on_moved(atom/movable/listener, atom/old_loc) + SIGNAL_HANDLER + unregister_signals(listener, old_loc) + update_signals(listener) diff --git a/code/datums/spells/spacetime_dist.dm b/code/datums/spells/spacetime_dist.dm index 4070c7a73405..33f93b1851c0 100644 --- a/code/datums/spells/spacetime_dist.dm +++ b/code/datums/spells/spacetime_dist.dm @@ -94,6 +94,13 @@ /obj/effect/cross_action/singularity_pull() return +/obj/effect/cross_action/spacetime_dist/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/effect/cross_action/spacetime_dist/proc/walk_link(atom/movable/AM) if(linked_dist && walks_left > 0) flick("purplesparkles", src) @@ -106,9 +113,9 @@ AM.forceMove(get_turf(src)) cant_teleport = FALSE -/obj/effect/cross_action/spacetime_dist/Crossed(atom/movable/AM, oldloc) +/obj/effect/cross_action/spacetime_dist/proc/on_atom_entered(atom/source, atom/movable/entered, turf/old_loc) if(!cant_teleport) - walk_link(AM) + walk_link(entered) /obj/effect/cross_action/spacetime_dist/attackby(obj/item/W, mob/user, params) if(user.drop_item(W)) @@ -123,4 +130,5 @@ /obj/effect/cross_action/spacetime_dist/Destroy() cant_teleport = TRUE linked_dist = null + RemoveElement(/datum/element/connect_loc) return ..() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 401a22ead042..be5265da7165 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -330,9 +330,6 @@ /atom/proc/is_drainable() return reagents && (container_type & DRAINABLE) -/atom/proc/CheckExit() - return TRUE - /atom/proc/HasProximity(atom/movable/AM) return @@ -1212,11 +1209,20 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons) /atom/Entered(atom/movable/AM, atom/oldLoc) SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, AM, oldLoc) -/atom/Exit(atom/movable/AM, atom/newLoc) - . = ..() - if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, AM, newLoc) & COMPONENT_ATOM_BLOCK_EXIT) +/** + * An atom is attempting to exit this atom's contents + * + * Default behaviour is to send the [COMSIG_ATOM_EXIT] + */ +/atom/Exit(atom/movable/leaving, direction) + // Don't call `..()` here, otherwise `Uncross()` gets called. + // See the doc comment on `Uncross()` to learn why this is bad. + + if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, leaving, direction) & COMPONENT_ATOM_BLOCK_EXIT) return FALSE + return TRUE + /atom/Exited(atom/movable/AM, atom/newLoc) SEND_SIGNAL(src, COMSIG_ATOM_EXITED, AM, newLoc) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 3f6c50803ec7..283b6ba67978 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -3,6 +3,8 @@ appearance_flags = TILE_BOUND glide_size = 8 // Default, adjusted when mobs move based on their movement delays var/last_move = null + /// A list containing arguments for Moved(). + VAR_PRIVATE/tmp/list/active_movement var/anchored = FALSE var/move_resist = MOVE_RESIST_DEFAULT var/move_force = MOVE_FORCE_DEFAULT @@ -16,9 +18,12 @@ var/no_spin = FALSE var/no_spin_thrown = FALSE var/mob/pulledby = null + var/atom/movable/pulling /// Face towards the atom while pulling it var/face_while_pulling = FALSE + /// Whether this atom should have its dir automatically changed when it moves. Setting this to FALSE allows for things such as directional windows to retain dir on moving without snowflake code all of the place. + var/set_dir_on_move = TRUE var/throwforce = 0 var/inertia_dir = 0 @@ -199,16 +204,96 @@ /** - * meant for movement with zero side effects. only use for objects that are supposed to move "invisibly" (like camera mobs or ghosts) - * if you want something to move onto a tile with a beartrap or recycler or tripmine or mouse without that object knowing about it at all, use this - * most of the time you want forceMove() + * Meant for movement with zero side effects. Only use for objects that are supposed to move "invisibly" (like camera mobs or ghosts). + * If you want something to move onto a tile with a beartrap or recycler or tripmine or mouse without that object knowing about it at all, use this. + * Most of the time you want [forceMove()]. */ /atom/movable/proc/abstract_move(atom/new_loc) + RESOLVE_ACTIVE_MOVEMENT // This should NEVER happen, but, just in case... var/atom/old_loc = loc var/direction = get_dir(old_loc, new_loc) loc = new_loc Moved(old_loc, direction, TRUE) +//////////////////////////////////////// +// Here's where we rewrite how byond handles movement except slightly different +// To be removed on step_ conversion +// All this work to prevent a second bump +/atom/movable/Move(atom/newloc, direction, glide_size_override = 0, update_dir = TRUE) + . = FALSE + if(!newloc || newloc == loc) + return + + // A mid-movement... movement... occured, resolve that first. + RESOLVE_ACTIVE_MOVEMENT + + if(!direction) + direction = get_dir(src, newloc) + + if(set_dir_on_move && dir != direction && update_dir) + setDir(direction) + + var/is_multi_tile_object = is_multi_tile_object(src) + + var/list/old_locs + if(is_multi_tile_object && isturf(loc)) + old_locs = locs // locs is a special list, this is effectively the same as .Copy() but with less steps + for(var/atom/exiting_loc as anything in old_locs) + if(!exiting_loc.Exit(src, direction)) + return + else + if(!loc.Exit(src, direction)) + return + + var/list/new_locs + if(is_multi_tile_object && isturf(newloc)) + new_locs = block( + newloc, + locate( + min(world.maxx, newloc.x + CEILING(bound_width / 32, 1)), + min(world.maxy, newloc.y + CEILING(bound_height / 32, 1)), + newloc.z + ) + ) // If this is a multi-tile object then we need to predict the new locs and check if they allow our entrance. + for(var/atom/entering_loc as anything in new_locs) + if(!entering_loc.Enter(src)) + return + if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_MOVE, entering_loc) & COMPONENT_MOVABLE_BLOCK_PRE_MOVE) + return + else // Else just try to enter the single destination. + if(!newloc.Enter(src)) + return + if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_MOVE, newloc) & COMPONENT_MOVABLE_BLOCK_PRE_MOVE) + return + + // Past this is the point of no return + var/atom/oldloc = loc + var/area/oldarea = get_area(oldloc) + var/area/newarea = get_area(newloc) + + SET_ACTIVE_MOVEMENT(oldloc, direction, FALSE, old_locs) + loc = newloc + + . = TRUE + + if(old_locs) // This condition will only be true if it is a multi-tile object. + for(var/atom/exited_loc as anything in (old_locs - new_locs)) + exited_loc.Exited(src, direction) + else // Else there's just one loc to be exited. + oldloc.Exited(src, direction) + if(oldarea != newarea) + oldarea.Exited(src, direction) + + if(new_locs) // Same here, only if multi-tile. + for(var/atom/entered_loc as anything in (new_locs - old_locs)) + entered_loc.Entered(src, oldloc, old_locs) + else + newloc.Entered(src, oldloc, old_locs) + if(oldarea != newarea) + newarea.Entered(src, oldarea) + + RESOLVE_ACTIVE_MOVEMENT + /atom/movable/Move(atom/newloc, direct = 0, movetime) if(!loc || !newloc) return FALSE @@ -265,14 +350,20 @@ . = FALSE // Called after a successful Move(). By this point, we've already moved -/atom/movable/proc/Moved(atom/OldLoc, Dir, Forced = FALSE) - SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, OldLoc, Dir, Forced) +/atom/movable/proc/Moved(atom/old_loc, Dir, Forced = FALSE) + SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, Dir, Forced) if(!inertia_moving) inertia_next_move = world.time + inertia_move_delay newtonian_move(Dir) if(length(client_mobs_in_contents)) update_parallax_contents() + var/turf/old_turf = get_turf(old_loc) + var/turf/new_turf = get_turf(src) + + if(old_turf?.z != new_turf?.z) + on_changed_z_level(old_turf, new_turf) + var/datum/light_source/L var/thing for(thing in light_sources) // Cycle through the light sources on this atom and tell them to update. @@ -280,6 +371,50 @@ L.source_atom.update_light() return TRUE +// Make sure you know what you're doing if you call this +// You probably want CanPass() +/atom/movable/Cross(atom/movable/crossed_atom) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_CROSS, crossed_atom) & COMPONENT_BLOCK_CROSS) + return FALSE + if(SEND_SIGNAL(crossed_atom, COMSIG_MOVABLE_CROSS_OVER, src) & COMPONENT_BLOCK_CROSS) + return FALSE + return CanPass(crossed_atom, get_dir(src, crossed_atom)) + +///default byond proc that is deprecated for us in lieu of signals. do not call +/atom/movable/Crossed(atom/movable/crossed_atom, oldloc) + SHOULD_NOT_OVERRIDE(TRUE) + CRASH("atom/movable/Crossed() was called!") + +/** + * `Uncross()` is a default BYOND proc that is called when something is *going* + * to exit this atom's turf. It is prefered over `Uncrossed` when you want to + * deny that movement, such as in the case of border objects, objects that allow + * you to walk through them in any direction except the one they block + * (think side windows). + * + * While being seemingly harmless, most everything doesn't actually want to + * use this, meaning that we are wasting proc calls for every single atom + * on a turf, every single time something exits it, when basically nothing + * cares. + * + * If you want to replicate the old `Uncross()` behavior, the most apt + * replacement is [`/datum/element/connect_loc`] while hooking onto + * [`COMSIG_ATOM_EXIT`]. + */ +/atom/movable/Uncross() + SHOULD_NOT_OVERRIDE(TRUE) + CRASH("Uncross() should not be being called, please read the doc-comment for it for why.") + +/** + * default byond proc that is normally called on everything inside the previous turf + * a movable was in after moving to its current turf + * this is wasteful since the vast majority of objects do not use Uncrossed + * use connect_loc to register to COMSIG_ATOM_EXITED instead + */ +/atom/movable/Uncrossed(atom/movable/uncrossed_atom) + SHOULD_NOT_OVERRIDE(TRUE) + CRASH("/atom/movable/Uncrossed() was called") + // Change glide size for the duration of one movement /atom/movable/proc/glide_for(movetime) if(movetime) @@ -289,57 +424,122 @@ else glide_size = initial(glide_size) -// Previously known as HasEntered() -// This is automatically called when something enters your square -/atom/movable/Crossed(atom/movable/AM, oldloc) - SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM) - SEND_SIGNAL(AM, COMSIG_CROSSED_MOVABLE, src) - -/atom/movable/Uncrossed(atom/movable/AM) - SEND_SIGNAL(src, COMSIG_MOVABLE_UNCROSSED, AM) - -/atom/movable/Bump(atom/bumped_atom, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump(). // suffering - if(bumped_atom && yes) - SEND_SIGNAL(src, COMSIG_MOVABLE_BUMP, bumped_atom) - if(!QDELETED(throwing)) - throwing.finalize(TRUE, bumped_atom) - . = TRUE - if(QDELETED(bumped_atom)) - return - bumped_atom.Bumped(src) +/atom/movable/Bump(atom/bumped_atom) + if(!bumped_atom) + CRASH("Bump was called with no argument.") + if(SEND_SIGNAL(src, COMSIG_MOVABLE_BUMP, bumped_atom) & COMPONENT_INTERCEPT_BUMPED) + return + . = ..() + if(!QDELETED(throwing)) + throwing.finalize(hit = TRUE, target = bumped_atom) + . = TRUE + if(QDELETED(bumped_atom)) + return + bumped_atom.Bumped(src) /atom/movable/proc/forceMove(atom/destination) - var/turf/old_loc = loc - loc = destination - moving_diagonally = 0 + . = FALSE + if(destination) + . = doMove(destination) + else + CRASH("No valid destination passed into forceMove") + +/* + * Move ourself to nullspace. Use to indicate clearly that you + * know that you are doing so, as opposed to calling forceMove(null), + * accidentally or otherwise. + */ +/atom/movable/proc/moveToNullspace() + return doMove(null) + +/atom/movable/proc/doMove(atom/destination) + . = FALSE + RESOLVE_ACTIVE_MOVEMENT - if(old_loc) - old_loc.Exited(src, destination) - for(var/atom/movable/AM in old_loc) - AM.Uncrossed(src) + var/atom/oldloc = loc + var/is_multi_tile = bound_width > world.icon_size || bound_height > world.icon_size + + SET_ACTIVE_MOVEMENT(oldloc, NONE, TRUE, null) if(destination) - destination.Entered(src) - for(var/atom/movable/AM in destination) - if(AM == src) - continue - AM.Crossed(src, old_loc) - var/turf/oldturf = get_turf(old_loc) - var/turf/destturf = get_turf(destination) - var/old_z = (oldturf ? oldturf.z : null) - var/dest_z = (destturf ? destturf.z : null) - if(old_z != dest_z) - onTransitZ(old_z, dest_z) + if(pulledby) + pulledby.stop_pulling() + + var/same_loc = oldloc == destination + var/area/old_area = get_area(oldloc) + var/area/destarea = get_area(destination) + var/movement_dir = get_dir(src, destination) + + moving_diagonally = 0 + + loc = destination + + if(!same_loc) + if(is_multi_tile && isturf(destination)) + var/list/new_locs = block( + destination, + locate( + min(world.maxx, destination.x + ROUND_UP(bound_width / 32)), + min(world.maxy, destination.y + ROUND_UP(bound_height / 32)), + destination.z + ) + ) + if(old_area && old_area != destarea) + old_area.Exited(src, movement_dir) + for(var/atom/left_loc as anything in locs - new_locs) + left_loc.Exited(src, movement_dir) + + for(var/atom/entering_loc as anything in new_locs - locs) + entering_loc.Entered(src, movement_dir) + + if(old_area && old_area != destarea) + destarea.Entered(src, movement_dir) + else + if(oldloc) + oldloc.Exited(src, movement_dir) + if(old_area && old_area != destarea) + old_area.Exited(src, movement_dir) + destination.Entered(src, oldloc) + if(destarea && old_area != destarea) + destarea.Entered(src, old_area) - Moved(old_loc, NONE) + . = TRUE - return TRUE + //If no destination, move the atom into nullspace (don't do this unless you know what you're doing) + else + . = TRUE + + if(oldloc) + loc = null + var/area/old_area = get_area(oldloc) + if(is_multi_tile && isturf(oldloc)) + for(var/atom/old_loc as anything in locs) + old_loc.Exited(src, NONE) + else + oldloc.Exited(src, NONE) + + if(old_area) + old_area.Exited(src, NONE) + + RESOLVE_ACTIVE_MOVEMENT + +/** + * Called when a movable changes z-levels. + * + * Arguments: + * * old_turf - The previous turf they were on before. + * * new_turf - The turf they have now entered. + * * notify_contents - Whether or not to notify the movable's contents that their z-level has changed. NOTE, IF YOU SET THIS, YOU NEED TO MANUALLY SET PLANE OF THE CONTENTS LATER + */ +/atom/movable/proc/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = TRUE) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_MOVABLE_Z_CHANGED, old_turf, new_turf) + + if(!notify_contents) + return -/atom/movable/proc/onTransitZ(old_z,new_z) - for(var/item in src) // Notify contents of Z-transition. This can be overridden if we know the items contents do not care. - var/atom/movable/AM = item - AM.onTransitZ(old_z,new_z) - SEND_SIGNAL(src, COMSIG_MOVABLE_Z_CHANGED) + for(var/atom/movable/content as anything in src) // Notify contents of Z-transition. + content.on_changed_z_level(old_turf, new_turf) /mob/living/forceMove(atom/destination) if(buckled) @@ -539,7 +739,7 @@ /atom/movable/proc/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) return FALSE -/atom/movable/CanPass(atom/movable/mover, turf/target) +/atom/movable/CanPass(atom/movable/mover, border_dir) // This condition is copied from atom to avoid an extra parent call, because this is a very hot proc. if(!density) return TRUE diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index e298a454a269..ba826e5f9d7f 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -341,7 +341,4 @@ GLOBAL_LIST_INIT(blacklisted_pylon_turfs, typecacheof(list( /obj/effect/gateway/Bumped(atom/movable/AM) return -/obj/effect/gateway/Crossed(atom/movable/AM, oldloc) - return - #undef CULT_STRUCTURE_COOLDOWN diff --git a/code/game/gamemodes/miniantags/guardian/types/protector.dm b/code/game/gamemodes/miniantags/guardian/types/protector.dm index 2be939f8cff5..f39a1a54aec1 100644 --- a/code/game/gamemodes/miniantags/guardian/types/protector.dm +++ b/code/game/gamemodes/miniantags/guardian/types/protector.dm @@ -125,7 +125,7 @@ color = linked_guardian.name_color shield_orientation = left_or_right -/obj/effect/guardianshield/CanPass(atom/movable/mover, turf/target) +/obj/effect/guardianshield/CanPass(atom/movable/mover, border_dir) if(mover == linked_guardian) return TRUE return FALSE diff --git a/code/game/gamemodes/miniantags/guardian/types/ranged.dm b/code/game/gamemodes/miniantags/guardian/types/ranged.dm index efd4d59801ec..fcfb58bd7f93 100644 --- a/code/game/gamemodes/miniantags/guardian/types/ranged.dm +++ b/code/game/gamemodes/miniantags/guardian/types/ranged.dm @@ -88,18 +88,25 @@ var/mob/living/spawner invisibility = 101 +/obj/item/effect/snare/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/effect/snare/singularity_act() return /obj/effect/snare/singularity_pull() return -/obj/item/effect/snare/Crossed(AM as mob|obj, oldloc) - if(isliving(AM)) +/obj/item/effect/snare/proc/on_atom_entered(datum/source, atom/movable/entered) + if(isliving(entered)) var/turf/snare_loc = get_turf(loc) if(spawner) - to_chat(spawner, "[AM] has crossed your surveillance trap at [get_area(snare_loc)].") + to_chat(spawner, "[entered] has crossed your surveillance trap at [get_area(snare_loc)].") if(isguardian(spawner)) var/mob/living/simple_animal/hostile/guardian/G = spawner if(G.summoner) - to_chat(G.summoner, "[AM] has crossed your surveillance trap at [get_area(snare_loc)].") + to_chat(G.summoner, "[entered] has crossed your surveillance trap at [get_area(snare_loc)].") diff --git a/code/game/gamemodes/miniantags/pulsedemon/cross_shock_component.dm b/code/game/gamemodes/miniantags/pulsedemon/cross_shock_component.dm index 1c15fdb1a820..a75862e240cc 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/cross_shock_component.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/cross_shock_component.dm @@ -3,11 +3,16 @@ var/energy_cost var/delay_between_shocks var/requires_cable + ///given to connect_loc to listen for something moving over target + var/static/list/crossed_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(do_shock), + ) + COOLDOWN_DECLARE(last_shock) /datum/component/cross_shock/Initialize(_shock_damage, _energy_cost, _delay_between_shocks, _requires_cable = TRUE) if(ismovable(parent)) - RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_CROSSED_MOVABLE), PROC_REF(do_shock)) + AddComponent(/datum/component/connect_loc_behalf, parent, crossed_connections) if(ismob(parent)) RegisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(on_organ_removal)) else if(isarea(parent)) @@ -22,11 +27,12 @@ delay_between_shocks = _delay_between_shocks requires_cable = _requires_cable -/datum/component/cross_shock/proc/do_shock(datum/source, mob/living/thing_were_gonna_shock) +/datum/component/cross_shock/proc/do_shock(atom/source, atom/movable/to_shock, turf/old_loc) SIGNAL_HANDLER if(!COOLDOWN_FINISHED(src, last_shock)) return - if(!istype(thing_were_gonna_shock)) + var/mob/living/living_to_shock = to_shock + if(!istype(living_to_shock)) return if(isliving(parent)) var/mob/living/M = parent @@ -40,11 +46,11 @@ if(!our_cable || !our_cable.powernet || !our_cable.powernet.available_power) return var/area/to_deduct_from = get_area(our_cable) - thing_were_gonna_shock.electrocute_act(shock_damage, source) + living_to_shock.electrocute_act(shock_damage, source) to_deduct_from.powernet.use_active_power(energy_cost) playsound(get_turf(parent), 'sound/effects/eleczap.ogg', 30, TRUE) else - thing_were_gonna_shock.electrocute_act(shock_damage, source) + living_to_shock.electrocute_act(shock_damage, source) playsound(get_turf(parent), 'sound/effects/eleczap.ogg', 30, TRUE) COOLDOWN_START(src, last_shock, delay_between_shocks) diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm index e05efa0c74a5..ae90f7f8528b 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm @@ -134,8 +134,8 @@ flags_2 |= RAD_NO_CONTAMINATE_2 // don't step on me - RegisterSignal(src, COMSIG_CROSSED_MOVABLE, PROC_REF(try_cross_shock)) - RegisterSignal(src, COMSIG_MOVABLE_CROSSED, PROC_REF(try_cross_shock)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS_OVER, PROC_REF(on_movable_cross_over)) // drop demon onto ground if its loc is a non-turf and gets deleted RegisterSignal(src, COMSIG_PARENT_PREQDELETED, PROC_REF(deleted_handler)) @@ -641,8 +641,15 @@ maxcharge = calc_maxcharge(length(hijacked_apcs)) + (maxcharge - calc_maxcharge(length(hijacked_apcs) - 1)) to_chat(src, "Hijacking complete! You now control [length(hijacked_apcs)] APCs.") -/mob/living/simple_animal/demon/pulse_demon/proc/try_cross_shock(src, atom/A) - SIGNAL_HANDLER +/mob/living/simple_animal/demon/pulse_demon/proc/on_movable_cross(datum/source, atom/movable/crossed) + SIGNAL_HANDLER // COMSIG_MOVABLE_CROSS + try_cross_shock(crossed) + +/mob/living/simple_animal/demon/pulse_demon/proc/on_movable_cross_over(datum/source, atom/movable/crossed) + SIGNAL_HANDLER // COMSIG_MOVABLE_CROSS_OVER + try_cross_shock(crossed) + +/mob/living/simple_animal/demon/pulse_demon/proc/try_cross_shock(atom/movable/A) if(!isliving(A) || is_under_tile()) return var/mob/living/L = A @@ -763,7 +770,7 @@ /mob/living/simple_animal/demon/pulse_demon/ex_act() return -/mob/living/simple_animal/demon/pulse_demon/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/demon/pulse_demon/CanPass(atom/movable/mover, border_dir) . = ..() if(istype(mover, /obj/item/projectile/ion)) return FALSE diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index ab86bc89afbd..d0bc0b0dca76 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -37,7 +37,7 @@ . = ..() . += "Click-drag someone to the table to place them on top of the table." -/obj/machinery/optable/CanPass(atom/movable/mover, turf/target) +/obj/machinery/optable/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSTABLE)) return TRUE if(isliving(mover)) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index a620857c3683..6b987ea26430 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -57,7 +57,7 @@ update_icon() return TRUE -/obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff. +/obj/structure/barricade/CanPass(atom/movable/mover, border_dir)//So bullets will fly over and stuff. if(locate(/obj/structure/barricade) in get_turf(mover)) return TRUE else if(isprojectile(mover)) @@ -448,12 +448,15 @@ 0, 0, 0, 1 ) color = target_matrix + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) -/obj/structure/barricade/dropwall/firewall/Crossed(atom/movable/AM, oldloc) - . = ..() - if(!isprojectile(AM)) +/obj/structure/barricade/dropwall/firewall/proc/on_atom_entered(datum/source, atom/movable/entered) + if(!isprojectile(entered)) return - var/obj/item/projectile/P = AM + var/obj/item/projectile/P = entered P.immolate ++ /obj/item/grenade/turret @@ -494,7 +497,7 @@ . = ..() . += "It would need [(5 - foam_level)] more blobs of foam to fully block the airlock." -/obj/structure/barricade/foam/CanPass(atom/movable/mover, turf/target) +/obj/structure/barricade/foam/CanPass(atom/movable/mover, border_dir) return istype(mover, /obj/item/projectile/c_foam) // Only c_foam blobs hit the airlock underneat/pass through the foam. The rest is hitting the barricade /obj/structure/barricade/foam/welder_act(mob/user, obj/item/I) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index a260b16f531a..0fc5574db384 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -760,7 +760,7 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) if(user) attack_ai(user) -/obj/machinery/door/airlock/CanPass(atom/movable/mover, turf/target) +/obj/machinery/door/airlock/CanPass(atom/movable/mover, border_dir) if(istype(mover) && !locked) if(mover.checkpass(PASSDOOR)) return TRUE diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 6ebb3b387c45..c7329257b79b 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -682,7 +682,7 @@ qdel(src) /// Multi-tile airlocks (using a filler panel) have special handling for movables with PASS_FLAG_GLASS -/obj/airlock_filler_object/CanPass(atom/movable/mover, turf/target) +/obj/airlock_filler_object/CanPass(atom/movable/mover, border_dir) . = ..() if(.) return diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 84ebb03663a3..62220477418a 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -133,7 +133,7 @@ update_bounds() -/obj/machinery/door/CanPass(atom/movable/mover, turf/target) +/obj/machinery/door/CanPass(atom/movable/mover, border_dir) if(istype(mover)) if(mover.checkpass(PASSDOOR) && !locked) return TRUE diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 604cd02766fc..fdf336a79792 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -290,7 +290,7 @@ F.update_icon() qdel(src) -/obj/machinery/door/firedoor/CanPass(atom/movable/mover, turf/target) +/obj/machinery/door/firedoor/CanPass(atom/movable/mover, border_dir) if(..()) return TRUE if(isliving(mover) && !locked) @@ -303,26 +303,37 @@ flags = ON_BORDER can_crush = FALSE +/obj/machinery/door/firedoor/border_only/Initialize(mapload) + . = ..() + + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + + AddElement(/datum/element/connect_loc, loc_connections) + /obj/machinery/door/firedoor/border_only/closed icon_state = "door_closed" opacity = TRUE density = TRUE -/obj/machinery/door/firedoor/border_only/CanPass(atom/movable/mover, turf/target) +/obj/machinery/door/firedoor/border_only/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSGLASS)) return 1 - if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(border_dir == dir) //Make sure looking at appropriate border return !density else return 1 -/obj/machinery/door/firedoor/border_only/CheckExit(atom/movable/mover, turf/target) - if(istype(mover) && mover.checkpass(PASSGLASS)) - return 1 - if(get_dir(loc, target) == dir) - return !density - else - return TRUE +/obj/machinery/door/firedoor/border_only/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + SIGNAL_HANDLER // COMSIG_ATOM_EXIT + + if(istype(leaving) && leaving.checkpass(PASSGLASS)) + return + + if(direction == dir && density) + leaving.Bump(src) + return COMPONENT_ATOM_BLOCK_EXIT /obj/machinery/door/firedoor/border_only/CanAtmosPass(direction) if(direction == dir) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index ec1a666d415f..dbf9ce4a0ecd 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -40,6 +40,12 @@ return name = new_name + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + + AddElement(/datum/element/connect_loc, loc_connections) + /obj/machinery/door/window/Destroy() density = FALSE if(obj_integrity == 0) @@ -140,14 +146,14 @@ return mob_dir & unres_sides -/obj/machinery/door/window/CanPass(atom/movable/mover, turf/target) +/obj/machinery/door/window/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSGLASS)) return TRUE if(isliving(mover)) var/mob/living/living_mover = mover if(HAS_TRAIT(living_mover, TRAIT_CONTORTED_BODY) && IS_HORIZONTAL(living_mover)) return TRUE - if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(border_dir == dir) //Make sure looking at appropriate border return !density if(istype(mover, /obj/structure/window)) var/obj/structure/window/W = mover @@ -172,17 +178,17 @@ /obj/machinery/door/window/CanPathfindPass(to_dir, datum/can_pass_info/pass_info) return !density || (dir != to_dir) || (check_access_list(pass_info.access) && hasPower()) -/obj/machinery/door/window/CheckExit(atom/movable/mover, turf/target) - if(istype(mover) && mover.checkpass(PASSGLASS)) - return TRUE - if(isliving(mover)) - var/mob/living/living_mover = mover +/obj/machinery/door/window/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + if(istype(leaving) && leaving.checkpass(PASSGLASS)) + return + + if(isliving(leaving)) + var/mob/living/living_mover = leaving if(HAS_TRAIT(living_mover, TRAIT_CONTORTED_BODY) && IS_HORIZONTAL(living_mover)) - return TRUE - if(get_dir(loc, target) == dir) - return !density - else - return 1 + return + + if(direction == dir && density) + return COMPONENT_ATOM_BLOCK_EXIT /obj/machinery/door/window/open(forced=0) if(operating) //doors can still open when emag-disabled diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 5c266789a88a..b0c1c7f1ce33 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -542,7 +542,7 @@ return -/obj/machinery/shieldwall/CanPass(atom/movable/mover, turf/target) +/obj/machinery/shieldwall/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSGLASS)) return prob(20) else @@ -557,7 +557,7 @@ desc = "A strange energy shield." icon_state = "shield-red" -/obj/machinery/shieldwall/syndicate/CanPass(atom/movable/mover, turf/target) +/obj/machinery/shieldwall/syndicate/CanPass(atom/movable/mover, border_dir) if(isliving(mover)) var/mob/living/M = mover if("syndicate" in M.faction) diff --git a/code/game/machinery/tcomms/relay.dm b/code/game/machinery/tcomms/relay.dm index 7b98ef255c04..4a9aee89a9e0 100644 --- a/code/game/machinery/tcomms/relay.dm +++ b/code/game/machinery/tcomms/relay.dm @@ -70,7 +70,7 @@ * * Handles parent call of disabling the machine if it changes Z-level, but also rebuilds the list of reachable levels on the linked core */ -/obj/machinery/tcomms/relay/onTransitZ(old_z, new_z) +/obj/machinery/tcomms/relay/on_changed_z_level(turf/old_turf, turf/new_turf) . = ..() if(linked_core) linked_core.refresh_zlevels() diff --git a/code/game/machinery/tcomms/tcomms_base.dm b/code/game/machinery/tcomms/tcomms_base.dm index f89810dd4d8d..6c7520a80b80 100644 --- a/code/game/machinery/tcomms/tcomms_base.dm +++ b/code/game/machinery/tcomms/tcomms_base.dm @@ -128,7 +128,7 @@ GLOBAL_LIST_EMPTY(tcomms_machines) * * Proc to make sure you cant have two of these active on a Z-level at once. It also makes sure to update the linkage */ -/obj/machinery/tcomms/onTransitZ(old_z, new_z) +/obj/machinery/tcomms/on_changed_z_level(turf/old_turf, turf/new_turf) . = ..() if(active) active = FALSE diff --git a/code/game/machinery/tcomms/tcomms_core.dm b/code/game/machinery/tcomms/tcomms_core.dm index 6d191a0ec5ae..f25bc08c4d9d 100644 --- a/code/game/machinery/tcomms/tcomms_core.dm +++ b/code/game/machinery/tcomms/tcomms_core.dm @@ -140,7 +140,7 @@ * * Handles parent call of disabling the machine if it changes Z-level, but also rebuilds the list of reachable levels */ -/obj/machinery/tcomms/core/onTransitZ(old_z, new_z) +/obj/machinery/tcomms/core/on_changed_z_level(turf/old_turf, turf/new_turf) . = ..() refresh_zlevels() diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 3baacc328778..8f7e62e09558 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -370,6 +370,7 @@ component_parts += new /obj/item/stack/ore/bluespace_crystal/artificial(null, 3) component_parts += new /obj/item/stock_parts/matter_bin(null) RefreshParts() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_entered)) /obj/machinery/teleport/hub/upgraded/Initialize(mapload) . = ..() @@ -386,6 +387,7 @@ if(power_station) power_station.teleporter_hub = null power_station = null + UnregisterSignal(COMSIG_MOVABLE_CROSS) return ..() /obj/machinery/teleport/hub/RefreshParts() @@ -406,13 +408,13 @@ break return power_station -/obj/machinery/teleport/hub/Crossed(atom/movable/AM, oldloc) +/obj/machinery/teleport/hub/proc/on_entered(atom/source, atom/movable/entered, turf/old_loc) if(!is_teleport_allowed(z) && !admin_usage) - if(ismob(AM)) - to_chat(AM, "You can't use this here.") + if(ismob(entered)) + to_chat(entered, "You can't use this here.") return - if(power_station && power_station.engaged && !panel_open && !blockAI(AM) && !iseffect(AM)) - if(!teleport(AM) && isliving(AM)) // the isliving(M) is needed to avoid triggering errors if a spark bumps the telehub + if(power_station && power_station.engaged && !panel_open && !blockAI(entered) && !iseffect(entered)) + if(!teleport(entered) && isliving(entered)) // the isliving(M) is needed to avoid triggering errors if a spark bumps the telehub visible_message("[src] emits a loud buzz, as its teleport portal flickers and fails!") playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, FALSE) power_station.toggle() // turn off the portal. @@ -487,6 +489,7 @@ /obj/machinery/teleport/perma/Initialize(mapload) . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_entered)) update_lighting() /obj/machinery/teleport/perma/process() @@ -501,15 +504,15 @@ tele_delay = max(A, 0) update_icon(UPDATE_ICON_STATE) -/obj/machinery/teleport/perma/Crossed(atom/movable/AM, oldloc) +/obj/machinery/teleport/perma/proc/on_entered(atom/source, atom/movable/entered, turf/old_loc) if(stat & (BROKEN|NOPOWER)) return if(!is_teleport_allowed(z)) - to_chat(AM, "You can't use this here.") + to_chat(entered, "You can't use this here.") return - if(target && !recalibrating && !panel_open && !blockAI(AM) && (teleports_this_cycle <= MAX_ALLOWED_TELEPORTS_PER_PROCESS)) - do_teleport(AM, target) + if(target && !recalibrating && !panel_open && !blockAI(entered) && (teleports_this_cycle <= MAX_ALLOWED_TELEPORTS_PER_PROCESS)) + do_teleport(entered, target) use_power(5000) teleports_this_cycle++ if(tele_delay) @@ -518,6 +521,10 @@ update_lighting() addtimer(CALLBACK(src, PROC_REF(CrossedCallback)), tele_delay) +/obj/machinery/teleport/perma/Destroy() + . = ..() + UnregisterSignal(COMSIG_MOVABLE_CROSS) + /obj/machinery/teleport/perma/proc/CrossedCallback() recalibrating = FALSE update_icon(UPDATE_ICON_STATE | UPDATE_OVERLAYS) diff --git a/code/game/machinery/vendors/vending.dm b/code/game/machinery/vendors/vending.dm index 00d957ab8107..55d04ed86e60 100644 --- a/code/game/machinery/vendors/vending.dm +++ b/code/game/machinery/vendors/vending.dm @@ -945,8 +945,9 @@ throw_item.throw_at(target, 16, 3) visible_message("[src] launches [throw_item.name] at [target.name]!") -/obj/machinery/economy/vending/onTransitZ() - return +/obj/machinery/economy/vending/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = FALSE) + // Don't bother notifying contents (for some reason (probably historical reasons (probably for no reason))) + return ..() /obj/machinery/economy/vending/proc/tilt(atom/victim, crit = FALSE, from_combat = FALSE, from_anywhere = FALSE) if(QDELETED(src) || !has_gravity(src) || !tiltable || tilted) diff --git a/code/game/objects/effects/alien_acid.dm b/code/game/objects/effects/alien_acid.dm index 86c1c0c2c730..311a6a5728f1 100644 --- a/code/game/objects/effects/alien_acid.dm +++ b/code/game/objects/effects/alien_acid.dm @@ -22,6 +22,11 @@ pixel_x = target.pixel_x + rand(-4,4) pixel_y = target.pixel_y + rand(-4,4) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + START_PROCESSING(SSobj, src) /obj/effect/acid/Destroy() @@ -50,9 +55,12 @@ qdel(src) return 0 -/obj/effect/acid/Crossed(AM as mob|obj) - if(isliving(AM)) - var/mob/living/L = AM +/obj/effect/acid/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + if(!isliving(entered) && !isobj(entered)) + return + if(isliving(entered)) + var/mob/living/L = entered if(L.flying) return if(L.m_intent != MOVE_INTENT_WALK && prob(40)) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index 969d91208fe6..5811156d209c 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -115,6 +115,8 @@ if(prob(75)) new /obj/item/shard(loc) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/effect/anomaly/grav/Destroy() vis_contents -= warp QDEL_NULL(warp) // don't want to leave it hanging @@ -141,9 +143,8 @@ animate(warp, time = 6, transform = matrix().Scale(0.5,0.5)) animate(time = 14, transform = matrix()) -/obj/effect/anomaly/grav/Crossed(atom/movable/AM) - . = ..() - gravShock(AM) +/obj/effect/anomaly/grav/proc/on_movable_cross(datum/source, atom/movable/crossed) + gravShock(crossed) /obj/effect/anomaly/grav/Bump(atom/A) gravShock(A) @@ -191,6 +192,8 @@ zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN power = 15000 + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/effect/anomaly/flux/anomalyEffect() ..() canshock = TRUE @@ -200,9 +203,8 @@ tesla_zap(src, zap_range, power, zap_flags) -/obj/effect/anomaly/flux/Crossed(atom/movable/AM) - . = ..() - mobShock(AM) +/obj/effect/anomaly/flux/proc/on_movable_cross(datum/source, atom/movable/crossed) + mobShock(crossed) /obj/effect/anomaly/flux/Bump(atom/A) mobShock(A) diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 1e93d42a1040..540534b6ab93 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -45,6 +45,11 @@ if(!. && !QDELETED(src)) dry_timer = addtimer(CALLBACK(src, PROC_REF(dry)), DRYING_TIME * (amount+1), TIMER_STOPPABLE) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/effect/decal/cleanable/blood/Destroy() if(dry_timer) deltimer(dry_timer) @@ -134,12 +139,7 @@ return FALSE -/obj/effect/decal/cleanable/blood/Bump(atom/A, yes) - // this is to prevent double or triple bumps from calling splat after src is qdel'd. - // only god knows why this fixes the issue - if(yes) - return - +/obj/effect/decal/cleanable/blood/Bump(atom/A) if(gravity_check) return ..() diff --git a/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm b/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm index 9019d1393558..0a9fc024f795 100644 --- a/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm +++ b/code/game/objects/effects/decals/Cleanable/misc_cleanables.dm @@ -171,15 +171,16 @@ animate_levitate(src, -1, rand(30, 120)) icon = 'icons/effects/blood_weightless.dmi' -/obj/effect/decal/cleanable/vomit/Bump(atom/A, yes) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/effect/decal/cleanable/vomit/Bump(atom/A) . = ..() if(A.density) splat(A) -/obj/effect/decal/cleanable/vomit/Crossed(atom/movable/AM, oldloc) +/obj/effect/decal/cleanable/vomit/proc/on_movable_cross(datum/source, atom/movable/crossed) if(!gravity_check) - splat(AM) - ..() + splat(crossed) /obj/effect/decal/cleanable/vomit/proc/splat(atom/A) if(gravity_check) diff --git a/code/game/objects/effects/decals/Cleanable/tar.dm b/code/game/objects/effects/decals/Cleanable/tar.dm index 3b6092c7a014..bc23adfbd1ac 100644 --- a/code/game/objects/effects/decals/Cleanable/tar.dm +++ b/code/game/objects/effects/decals/Cleanable/tar.dm @@ -14,6 +14,8 @@ if(prob(50)) icon_state = "tar3" + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/effect/decal/cleanable/tar/Destroy() if(target) target.slowdown -= 10 @@ -27,9 +29,9 @@ if(!issimulatedturf(target)) // We remove slowdown in Destroy(), so we run this check after adding the slowdown. qdel(src) -/obj/effect/decal/cleanable/tar/Crossed(atom/movable/movable_atom) - if(isliving(movable_atom)) - var/mob/living/L = movable_atom +/obj/effect/decal/cleanable/tar/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isliving(crossed)) + var/mob/living/L = crossed playsound(L, 'sound/effects/attackblob.ogg', 50, TRUE) to_chat(L, "[src] sticks to you!") diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm index 0d543775c743..23ca8b324a1b 100644 --- a/code/game/objects/effects/decals/Cleanable/tracks.dm +++ b/code/game/objects/effects/decals/Cleanable/tracks.dm @@ -39,61 +39,70 @@ GLOBAL_LIST_EMPTY(fluidtrack_cache) blood_state = BLOOD_STATE_HUMAN //the icon state to load images from gravity_check = ALWAYS_IN_GRAVITY -/obj/effect/decal/cleanable/blood/footprints/Crossed(atom/movable/O, oldloc) - ..() - if(ishuman(O)) - var/mob/living/carbon/human/H = O - var/obj/item/clothing/shoes/S = H.shoes - var/obj/item/organ/external/l_foot = H.get_organ("l_foot") - var/obj/item/organ/external/r_foot = H.get_organ("r_foot") - var/hasfeet = TRUE - if(!l_foot && !r_foot) - hasfeet = FALSE - if(S && S.bloody_shoes[blood_state] && S.blood_color == basecolor) - S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0) - S.bloody_shoes[BLOOD_BASE_ALPHA] = base_alpha - if(!S.blood_DNA) - S.blood_DNA = list() - S.blood_DNA |= blood_DNA.Copy() - if(!(entered_dirs & H.dir)) - entered_dirs |= H.dir - update_icon() - else if(hasfeet && H.bloody_feet[blood_state] && H.feet_blood_color == basecolor)//Or feet //This will need to be changed. - H.bloody_feet[blood_state] = max(H.bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP, 0) - H.bloody_feet[BLOOD_BASE_ALPHA] = base_alpha - if(!H.feet_blood_DNA) - H.feet_blood_DNA = list() - H.feet_blood_DNA |= blood_DNA.Copy() - if(!(entered_dirs & H.dir)) - entered_dirs |= H.dir - update_icon() - -/obj/effect/decal/cleanable/blood/footprints/Uncrossed(atom/movable/O) - ..() - if(ishuman(O)) - var/mob/living/carbon/human/H = O - var/obj/item/clothing/shoes/S = H.shoes - var/obj/item/organ/external/l_foot = H.get_organ("l_foot") - var/obj/item/organ/external/r_foot = H.get_organ("r_foot") - var/hasfeet = TRUE - if(!l_foot && !r_foot) - hasfeet = FALSE - if(S && S.bloody_shoes[blood_state] && S.blood_color == basecolor) - S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0) - if(!S.blood_DNA) - S.blood_DNA = list() - S.blood_DNA |= blood_DNA.Copy() - if(!(exited_dirs & H.dir)) - exited_dirs |= H.dir - update_icon() - else if(hasfeet && H.bloody_feet[blood_state] && H.feet_blood_color == basecolor)//Or feet - H.bloody_feet[blood_state] = max(H.bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP, 0) - if(!H.feet_blood_DNA) - H.feet_blood_DNA = list() - H.feet_blood_DNA |= blood_DNA.Copy() - if(!(exited_dirs & H.dir)) - exited_dirs |= H.dir - update_icon() +/obj/effect/decal/cleanable/blood/footprints/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + COMSIG_ATOM_EXITED = PROC_REF(on_atom_exited), + ) + AddElement(/datum/element/connect_loc, loc_connections) + +/obj/effect/decal/cleanable/blood/footprints/on_atom_entered(datum/source, mob/living/carbon/human/H, ...) + if(!istype(H)) + return + + var/obj/item/clothing/shoes/S = H.shoes + var/obj/item/organ/external/l_foot = H.get_organ("l_foot") + var/obj/item/organ/external/r_foot = H.get_organ("r_foot") + var/hasfeet = TRUE + if(!l_foot && !r_foot) + hasfeet = FALSE + if(S && S.bloody_shoes[blood_state] && S.blood_color == basecolor) + S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0) + S.bloody_shoes[BLOOD_BASE_ALPHA] = base_alpha + if(!S.blood_DNA) + S.blood_DNA = list() + S.blood_DNA |= blood_DNA.Copy() + if(!(entered_dirs & H.dir)) + entered_dirs |= H.dir + update_icon() + else if(hasfeet && H.bloody_feet[blood_state] && H.feet_blood_color == basecolor)//Or feet //This will need to be changed. + H.bloody_feet[blood_state] = max(H.bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP, 0) + H.bloody_feet[BLOOD_BASE_ALPHA] = base_alpha + if(!H.feet_blood_DNA) + H.feet_blood_DNA = list() + H.feet_blood_DNA |= blood_DNA.Copy() + if(!(entered_dirs & H.dir)) + entered_dirs |= H.dir + update_icon() + +// TODO: I think this is a 1:1 copy-paste of on_atom_entered above +/obj/effect/decal/cleanable/blood/footprints/proc/on_atom_exited(datum/source, mob/living/carbon/human/H, ...) + if(!istype(H)) + return + + var/obj/item/clothing/shoes/S = H.shoes + var/obj/item/organ/external/l_foot = H.get_organ("l_foot") + var/obj/item/organ/external/r_foot = H.get_organ("r_foot") + var/hasfeet = TRUE + if(!l_foot && !r_foot) + hasfeet = FALSE + if(S && S.bloody_shoes[blood_state] && S.blood_color == basecolor) + S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0) + if(!S.blood_DNA) + S.blood_DNA = list() + S.blood_DNA |= blood_DNA.Copy() + if(!(exited_dirs & H.dir)) + exited_dirs |= H.dir + update_icon() + else if(hasfeet && H.bloody_feet[blood_state] && H.feet_blood_color == basecolor)//Or feet + H.bloody_feet[blood_state] = max(H.bloody_feet[blood_state] - BLOOD_LOSS_PER_STEP, 0) + if(!H.feet_blood_DNA) + H.feet_blood_DNA = list() + H.feet_blood_DNA |= blood_DNA.Copy() + if(!(exited_dirs & H.dir)) + exited_dirs |= H.dir + update_icon() /obj/effect/decal/cleanable/blood/footprints/update_overlays() diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 47e3693f95ff..a1a1a46538ba 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -27,17 +27,15 @@ //Add "bloodiness" of this blood's type, to the human's shoes //This is on /cleanable because fuck this ancient mess -/obj/effect/decal/cleanable/blood/Crossed(atom/movable/O) - ..() - - if(!ishuman(O)) +/obj/effect/decal/cleanable/blood/proc/on_atom_entered(datum/source, atom/movable/entered) + if(!ishuman(entered)) return - if(!gravity_check && ishuman(O)) - bloodyify_human(O) + if(!gravity_check && ishuman(entered)) + bloodyify_human(entered) if(!off_floor) - var/mob/living/carbon/human/H = O + var/mob/living/carbon/human/H = entered var/obj/item/organ/external/l_foot = H.get_organ("l_foot") var/obj/item/organ/external/r_foot = H.get_organ("r_foot") var/hasfeet = TRUE diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index 5a550c677d4f..af5d68d428a0 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -30,6 +30,7 @@ create_reagents(25) playsound(src, 'sound/effects/bubbles2.ogg', 80, TRUE, -3) addtimer(CALLBACK(src, PROC_REF(initial_process)), spread_time) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /obj/effect/particle_effect/foam/proc/disperse_reagents() if(!reagents) @@ -122,10 +123,10 @@ flick("[icon_state]-disolve", src) QDEL_IN(src, 0.5 SECONDS) -/obj/effect/particle_effect/foam/Crossed(atom/movable/AM, oldloc) - if(!iscarbon(AM)) +/obj/effect/particle_effect/foam/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(!iscarbon(crossed)) return - var/mob/living/carbon/M = AM + var/mob/living/carbon/M = crossed if((M.slip("foam", 10 SECONDS) || IS_HORIZONTAL(M)) && reagents) fill_with_reagents(M) @@ -154,7 +155,7 @@ /obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) return -/obj/effect/particle_effect/foam/metal/Crossed(atom/movable/AM, oldloc) +/obj/effect/particle_effect/foam/metal/on_movable_cross(datum/source, atom/movable/crossed) return /datum/effect_system/foam_spread @@ -294,7 +295,7 @@ to_chat(user, "You hit the metal foam but bounce off it.") playsound(loc, 'sound/weapons/tap.ogg', 100, 1) -/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target) +/obj/structure/foamedmetal/CanPass(atom/movable/mover, border_dir) return !density /obj/structure/foamedmetal/CanAtmosPass(direction) diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm index d46c09daa460..3e1ee1a40a5c 100644 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/effects_smoke.dm @@ -23,7 +23,7 @@ /obj/effect/particle_effect/smoke/Initialize(mapload) . = ..() START_PROCESSING(SSobj, src) - RegisterSignal(src, list(COMSIG_MOVABLE_CROSSED, COMSIG_CROSSED_MOVABLE), PROC_REF(smoke_mob)) //If someone crosses the smoke or the smoke crosses someone + RegisterSignal(src, list(COMSIG_MOVABLE_CROSS, COMSIG_MOVABLE_CROSS_OVER), PROC_REF(smoke_mob)) //If someone crosses the smoke or the smoke crosses someone GLOB.smokes_active++ lifetime += rand(-1, 1) create_reagents(10) @@ -31,7 +31,7 @@ /obj/effect/particle_effect/smoke/Destroy() animate(src, 2 SECONDS, alpha = 0, easing = EASE_IN | CIRCULAR_EASING) STOP_PROCESSING(SSobj, src) - UnregisterSignal(src, list(COMSIG_MOVABLE_CROSSED, COMSIG_CROSSED_MOVABLE)) + UnregisterSignal(src, list(COMSIG_MOVABLE_CROSS, COMSIG_MOVABLE_CROSS_OVER)) GLOB.smokes_active-- return ..() @@ -125,7 +125,7 @@ lifetime = 16 SECONDS_TO_LIFE_CYCLES causes_coughing = TRUE -/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target) +/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, border_dir) if(istype(mover, /obj/item/projectile/beam)) var/obj/item/projectile/beam/B = mover B.damage = (B.damage / 2) diff --git a/code/game/objects/effects/forcefields.dm b/code/game/objects/effects/forcefields.dm index 32637ebc05f4..d4e1e28997d4 100644 --- a/code/game/objects/effects/forcefields.dm +++ b/code/game/objects/effects/forcefields.dm @@ -22,7 +22,7 @@ . = ..() wizard = summoner -/obj/effect/forcefield/wizard/CanPass(atom/movable/mover, turf/target) +/obj/effect/forcefield/wizard/CanPass(atom/movable/mover, border_dir) if(mover == wizard) return TRUE return FALSE diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 08b657be0ed8..96b04e20f5db 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -7,13 +7,17 @@ var/triggered = FALSE var/faction = "syndicate" +/obj/effect/mine/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_cross)) + /obj/effect/mine/proc/mineEffect(mob/living/victim) to_chat(victim, "*click*") -/obj/effect/mine/Crossed(AM as mob|obj, oldloc) - if(!isliving(AM)) +/obj/effect/mine/proc/on_cross(atom/movable/crossed) + if(!isliving(crossed)) return - var/mob/living/M = AM + var/mob/living/M = crossed if(faction && (faction in M.faction)) return if(M.flying) diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index ba6f449d1f01..4a61e40a3fdd 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -39,6 +39,11 @@ creation_mob_ckey = creation_mob?.ckey START_PROCESSING(SSobj, src) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + if(lifespan > 0) QDEL_IN(src, lifespan) @@ -62,15 +67,15 @@ /obj/effect/portal/singularity_act() return -/obj/effect/portal/Crossed(atom/movable/AM, oldloc) - if(isobserver(AM)) - return ..() +/obj/effect/portal/proc/on_atom_entered(datum/source, atom/movable/entered, old_loc) + if(isobserver(entered)) + return - if(target && (get_turf(oldloc) == get_turf(target))) - return ..() + if(target && (get_turf(old_loc) == get_turf(target))) + return - if(!teleport(AM)) - return ..() + if(teleport(entered)) + return TRUE /obj/effect/portal/attack_tk(mob/user) return diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index d7a6d873f148..e792ba6b7a9f 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -38,7 +38,7 @@ if(prob(50)) icon_state = "stickyweb2" -/obj/structure/spider/stickyweb/CanPass(atom/movable/mover, turf/target) +/obj/structure/spider/stickyweb/CanPass(atom/movable/mover, border_dir) if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider) || isterrorspider(mover)) return TRUE else if(isliving(mover)) diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm index e7acf45614a2..63ab8096230d 100644 --- a/code/game/objects/effects/step_triggers.dm +++ b/code/game/objects/effects/step_triggers.dm @@ -6,18 +6,27 @@ var/mobs_only = FALSE invisibility = INVISIBILITY_ABSTRACT // nope cant see this shit +/obj/effect/step_trigger/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/effect/step_trigger/proc/Trigger(atom/movable/A) return FALSE -/obj/effect/step_trigger/Crossed(H, oldloc) - . = ..() - if(!H) +/obj/effect/step_trigger/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER + if(!entered || entered == src) return - if(isobserver(H) && !affect_ghosts) + if(!ismob(entered) && !isobj(entered)) return - if(!ismob(H) && mobs_only) + if(isobserver(entered) && !affect_ghosts) return - Trigger(H) + if(!ismob(entered) && mobs_only) + return + INVOKE_ASYNC(src, PROC_REF(Trigger), entered) /obj/effect/step_trigger/singularity_act() return @@ -39,7 +48,6 @@ qdel(src) /* Tosses things in a certain direction */ - /obj/effect/step_trigger/thrower var/direction = SOUTH // the direction of throw var/tiles = 3 // if 0: forever until atom hits a stopper diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 5b9397d1a9ac..02d88c3cb2e5 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -61,6 +61,10 @@ if(is_zero_amount(FALSE)) return INITIALIZE_HINT_QDEL + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) update_icon(UPDATE_ICON_STATE) /obj/item/stack/update_icon_state() @@ -75,17 +79,18 @@ icon_state = "[initial(icon_state)]_[state]" -/obj/item/stack/Crossed(obj/O, oldloc) - if(O == src) +/obj/item/stack/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + + // Edge case. This signal will also be sent when src has entered the turf. Don't want to merge with ourselves. + if(entered == src) return if(amount >= max_amount || ismob(loc)) // Prevents unnecessary call. Also prevents merging stack automatically in a mob's inventory return - if(!O.throwing && can_merge(O)) - INVOKE_ASYNC(src, PROC_REF(merge), O) - - ..() + if(!entered.throwing && can_merge(entered)) + INVOKE_ASYNC(src, PROC_REF(merge), entered) /obj/item/stack/hitby(atom/movable/hitting, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) if(can_merge(hitting, inhand = TRUE)) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index b50ff4b90e8b..970f6d48157c 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -375,6 +375,13 @@ w_class = WEIGHT_CLASS_TINY var/ash_type = /obj/effect/decal/cleanable/ash +/obj/item/toy/snappop/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/toy/snappop/proc/pop_burst(n=3, c=1) do_sparks(n, c, src) new ash_type(loc) @@ -391,10 +398,10 @@ ..() pop_burst() -/obj/item/toy/snappop/Crossed(H as mob|obj, oldloc) - if(ishuman(H) || issilicon(H)) //i guess carp and shit shouldn't set them off - var/mob/living/carbon/M = H - if(issilicon(H) || M.m_intent == MOVE_INTENT_RUN) +/obj/item/toy/snappop/proc/on_atom_entered(datum/source, atom/movable/entered) + if(ishuman(entered) || issilicon(entered)) //i guess carp and shit shouldn't set them off + var/mob/living/carbon/M = entered + if(issilicon(entered) || M.m_intent == MOVE_INTENT_RUN) to_chat(M, "You step on the snap pop!") pop_burst(2, 0) diff --git a/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm b/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm index e98f1303f42c..34677d843093 100644 --- a/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm +++ b/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm @@ -33,6 +33,11 @@ GLOBAL_LIST_EMPTY(flame_effects) GLOB.flame_effects += src START_PROCESSING(SSprocessing, src) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/effect/fire/Destroy() . = ..() GLOB.flame_effects -= src @@ -75,18 +80,17 @@ GLOBAL_LIST_EMPTY(flame_effects) if(duration <= 0) fizzle() -/obj/effect/fire/Crossed(atom/movable/AM, oldloc) - . = ..() - if(isliving(AM)) - if(!damage_mob(AM)) +/obj/effect/fire/proc/on_atom_entered(datum/source, atom/movable/entered, old_loc) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + if(isliving(entered)) + if(!damage_mob(entered)) return - to_chat(AM, "[src] burns you!") + to_chat(entered, "[src] burns you!") return if(isitem(AM)) - var/obj/item/item_to_burn = AM + var/obj/item/item_to_burn = entered item_to_burn.fire_act(null, temperature) - return /obj/effect/fire/proc/fizzle() playsound(src, 'sound/effects/fire_sizzle.ogg', 50, TRUE) diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index 6776d7fdeded..c04ae00110f5 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -21,6 +21,7 @@ /obj/item/grenade/plastic/Initialize(mapload) . = ..() plastic_overlay = mutable_appearance(icon, "[item_state]2", HIGH_OBJ_LAYER) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /obj/item/grenade/plastic/Destroy() QDEL_NULL(nadeassembly) @@ -50,9 +51,9 @@ return ..() -/obj/item/grenade/plastic/Crossed(atom/movable/AM, oldloc) +/obj/item/grenade/plastic/proc/on_movable_cross(datum/source, atom/movable/crossed) if(nadeassembly) - nadeassembly.Crossed(AM, oldloc) + nadeassembly.on_movable_cross(crossed) /obj/item/grenade/plastic/on_found(mob/finder) if(nadeassembly) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 06daebbcfeff..5c96319fa333 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -32,6 +32,11 @@ payload_name += " " // formatting, ignore me update_icon() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/grenade/chem_grenade/Destroy() QDEL_NULL(nadeassembly) QDEL_LIST_CONTENTS(beakers) @@ -243,9 +248,9 @@ if(nadeassembly) nadeassembly.process_movement() -/obj/item/grenade/chem_grenade/Crossed(atom/movable/AM, oldloc) +/obj/item/grenade/chem_grenade/proc/on_atom_entered(datum/source, atom/movable/entered) if(nadeassembly) - nadeassembly.Crossed(AM, oldloc) + nadeassembly.on_atom_entered(entered) /obj/item/grenade/chem_grenade/on_found(mob/finder) if(nadeassembly) diff --git a/code/game/objects/items/weapons/legcuffs.dm b/code/game/objects/items/weapons/legcuffs.dm index f816d7c8dd5e..0894fc8f4c4b 100644 --- a/code/game/objects/items/weapons/legcuffs.dm +++ b/code/game/objects/items/weapons/legcuffs.dm @@ -26,6 +26,13 @@ var/obj/item/grenade/iedcasing/IED = null var/obj/item/assembly/signaler/sig = null +/obj/item/restraints/legcuffs/beartrap/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/restraints/legcuffs/beartrap/update_icon_state() icon_state = "beartrap[armed]" @@ -97,16 +104,15 @@ to_chat(user, "You remove the signaler from [src].") return TRUE -/obj/item/restraints/legcuffs/beartrap/Crossed(AM as mob|obj, oldloc) - if(!armed || !isturf(loc)) - return ..() +/obj/item/restraints/legcuffs/beartrap/proc/on_atom_entered(datum/source, mob/living/entered) + if(!armed || !isturf(loc) || !istype(entered)) + return - var/mob/living/L = AM - if((iscarbon(AM) || isanimal(AM)) && !L.flying) - spring_trap(AM) + if((iscarbon(entered) || isanimal(entered)) && !entered.flying) + spring_trap(entered) - if(ishuman(AM)) - var/mob/living/carbon/H = AM + if(ishuman(entered)) + var/mob/living/carbon/H = entered if(IS_HORIZONTAL(H)) H.apply_damage(trap_damage, BRUTE, "chest") else @@ -117,11 +123,10 @@ H.update_inv_legcuffed() SSblackbox.record_feedback("tally", "handcuffs", 1, type) else - if(istype(L, /mob/living/simple_animal/hostile/bear)) - L.apply_damage(trap_damage * 2.5, BRUTE) + if(istype(entered, /mob/living/simple_animal/hostile/bear)) + entered.apply_damage(trap_damage * 2.5, BRUTE) else - L.apply_damage(trap_damage * 1.75, BRUTE) - ..() + entered.apply_damage(trap_damage * 1.75, BRUTE) /obj/item/restraints/legcuffs/beartrap/on_found(mob/finder) if(!armed) diff --git a/code/game/objects/items/weapons/shards.dm b/code/game/objects/items/weapons/shards.dm index ce0a58932858..7b04c5222f42 100644 --- a/code/game/objects/items/weapons/shards.dm +++ b/code/game/objects/items/weapons/shards.dm @@ -44,6 +44,7 @@ . = ..() AddComponent(/datum/component/caltrop, force) set_initial_icon_state() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /obj/item/shard/afterattack(atom/movable/AM, mob/user, proximity) if(!proximity || !(src in user)) @@ -70,12 +71,12 @@ to_chat(user, "You add the newly-formed glass to the stack.") qdel(src) -/obj/item/shard/Crossed(mob/living/L, oldloc) - if(istype(L) && has_gravity(loc)) - if(L.incorporeal_move || L.flying || L.floating) +/obj/item/shard/proc/on_movable_cross(datum/source, atom/movable/crossed) + var/mob/living/living_crossed = crossed + if(istype(living_crossed) && has_gravity(loc)) + if(living_crossed.incorporeal_move || living_crossed.flying || living_crossed.floating) return playsound(loc, 'sound/effects/glass_step.ogg', 50, TRUE) - return ..() /obj/item/shard/decompile_act(obj/item/matter_decompiler/C, mob/user) C.stored_comms["glass"] += 3 diff --git a/code/game/objects/items/weapons/storage/briefcase.dm b/code/game/objects/items/weapons/storage/briefcase.dm index 7d03cf3a7840..99c73129d20f 100644 --- a/code/game/objects/items/weapons/storage/briefcase.dm +++ b/code/game/objects/items/weapons/storage/briefcase.dm @@ -61,7 +61,7 @@ stored_item = I max_w_class = WEIGHT_CLASS_NORMAL - stored_item.w_class - I.forceMove(null) //null space here we go - to stop it showing up in the briefcase + I.moveToNullspace() // to stop it showing up in the briefcase to_chat(user, "You place [I] into the false bottom of the briefcase.") else return ..() diff --git a/code/game/objects/structures/coathanger.dm b/code/game/objects/structures/coathanger.dm index 40fa5b0ab367..3f292d9c3251 100644 --- a/code/game/objects/structures/coathanger.dm +++ b/code/game/objects/structures/coathanger.dm @@ -29,7 +29,7 @@ return return ..() -/obj/structure/coatrack/CanPass(atom/movable/mover, turf/target) +/obj/structure/coatrack/CanPass(atom/movable/mover, border_dir) var/can_hang = FALSE for(var/T in allowed) if(istype(mover,T)) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index c6a04c649cbb..2871f4efc16a 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -62,7 +62,7 @@ dump_contents() return ..() -/obj/structure/closet/CanPass(atom/movable/mover, turf/target) +/obj/structure/closet/CanPass(atom/movable/mover, border_dir) if(wall_mounted) return TRUE return (!density) @@ -424,9 +424,19 @@ storage_capacity = 60 var/materials = list(MAT_METAL = 5000, MAT_PLASMA = 2500, MAT_TITANIUM = 500, MAT_BLUESPACE = 500) -/obj/structure/closet/bluespace/CheckExit(atom/movable/AM) - UpdateTransparency(AM, loc) - return TRUE +/obj/structure/closet/bluespace/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + + AddElement(/datum/element/connect_loc, loc_connections) + + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/structure/closet/bluespace/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + SIGNAL_HANDLER // COMSIG_ATOM_EXIT + UpdateTransparency(leaving, loc) /obj/structure/closet/bluespace/proc/UpdateTransparency(atom/movable/AM, atom/location) transparent = FALSE @@ -436,8 +446,8 @@ break update_icon() -/obj/structure/closet/bluespace/Crossed(atom/movable/AM, oldloc) - if(AM.density) +/obj/structure/closet/bluespace/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(crossed.density) transparent = TRUE update_icon() diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm index b3956fe0cfce..2547ba3c4743 100644 --- a/code/game/objects/structures/fence.dm +++ b/code/game/objects/structures/fence.dm @@ -58,7 +58,7 @@ icon_state = "straight_cut3" hole_size = LARGE_HOLE -/obj/structure/fence/CanPass(atom/movable/mover, turf/target) +/obj/structure/fence/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSFENCE)) return TRUE if(isprojectile(mover)) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 1bd26e78f0f4..6f3cb5f3e97c 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -406,7 +406,7 @@ refundMetal(metalUsed) qdel(src) -/obj/structure/girder/CanPass(atom/movable/mover, turf/target) +/obj/structure/girder/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSGIRDER)) return TRUE if(istype(mover) && mover.checkpass(PASSGRILLE)) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index a66d1399334b..3f560bf9d3de 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -113,7 +113,7 @@ if(!shock(user, 70)) take_damage(20, BRUTE, MELEE, 1) -/obj/structure/grille/CanPass(atom/movable/mover, turf/target) +/obj/structure/grille/CanPass(atom/movable/mover, border_dir) . = !density if(istype(mover) && mover.checkpass(PASSGRILLE)) return TRUE diff --git a/code/game/objects/structures/holosigns.dm b/code/game/objects/structures/holosigns.dm index 655551f6eb95..3631b28451de 100644 --- a/code/game/objects/structures/holosigns.dm +++ b/code/game/objects/structures/holosigns.dm @@ -57,7 +57,7 @@ max_integrity = 20 var/allow_walk = TRUE //can we pass through it on walk intent -/obj/structure/holosign/barrier/CanPass(atom/movable/mover, turf/target) +/obj/structure/holosign/barrier/CanPass(atom/movable/mover, border_dir) if(!density) return TRUE if(mover.pass_flags & (PASSGLASS|PASSTABLE|PASSGRILLE)) diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index 32a3fbe71a7e..8da1bf82fb5d 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -42,7 +42,7 @@ . = ..() T.recalculate_atmos_connectivity() -/obj/structure/inflatable/CanPass(atom/movable/mover, turf/target) +/obj/structure/inflatable/CanPass(atom/movable/mover, border_dir) return /obj/structure/inflatable/CanAtmosPass(direction) @@ -116,7 +116,7 @@ /obj/structure/inflatable/door/attack_hand(mob/user as mob) return try_to_operate(user) -/obj/structure/inflatable/door/CanPass(atom/movable/mover, turf/target) +/obj/structure/inflatable/door/CanPass(atom/movable/mover, border_dir) if(istype(mover, /obj/effect/beam)) return !opacity return !density diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index dde36ebb6cee..e7c3415aa08e 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -59,7 +59,7 @@ if(user.can_advanced_admin_interact()) operate() -/obj/structure/mineral_door/CanPass(atom/movable/mover, turf/target) +/obj/structure/mineral_door/CanPass(atom/movable/mover, border_dir) if(istype(mover, /obj/effect/beam)) return !opacity return !density diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 03c7147f7db5..2343a1b8f6dc 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -294,7 +294,7 @@ connected = null return ..() -/obj/structure/m_tray/CanPass(atom/movable/mover, turf/target) +/obj/structure/m_tray/CanPass(atom/movable/mover, border_dir) if(istype(mover)) if(mover.checkpass(PASSTABLE)) return TRUE diff --git a/code/game/objects/structures/nest.dm b/code/game/objects/structures/nest.dm index 0deca8f6de66..0dccb35a6805 100644 --- a/code/game/objects/structures/nest.dm +++ b/code/game/objects/structures/nest.dm @@ -25,6 +25,10 @@ var/spawn_mob_options = list(/mob/living/simple_animal/crab) // The nest picks one mob type of this list and spawns them var/spawn_trigger_distance = 7 // The triggered nest will look this many tiles around itself to find other triggerable nests +/obj/structure/nest/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/structure/nest/examine(mob/user) . = ..() if(!spawn_is_triggered) @@ -35,12 +39,12 @@ return ..() -/obj/structure/nest/Crossed(atom/movable/AM) +/obj/structure/nest/proc/on_movable_cross(datum/source, atom/movable/crossed) if(spawn_is_triggered) return - if(!isliving(AM)) + if(!isliving(crossed)) return - var/mob/living/L = AM + var/mob/living/L = crossed if(!L.mind) return diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 37e590e40c34..94d4584dc33b 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -12,6 +12,14 @@ var/currently_climbed = FALSE var/mover_dir = null +/obj/structure/railing/Initialize(mapload) + . = ..() + if(density && flags & ON_BORDER) // blocks normal movement from and to the direction it's facing. + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/structure/railing/get_climb_text() return "You can Click-Drag yourself to [src] to climb over it after a short delay." @@ -87,8 +95,8 @@ /obj/structure/railing/corner/CanPathfindPass(to_dir, datum/can_pass_info/pass_info) return TRUE -/obj/structure/railing/corner/CheckExit() - return TRUE +/obj/structure/railing/corner/on_atom_exit(datum/source, atom/movable/leaving, direction) + return /obj/structure/railing/cap/CanPass() return TRUE @@ -96,10 +104,10 @@ /obj/structure/railing/cap/CanPathfindPass(to_dir, datum/can_pass_info/pass_info) return TRUE -/obj/structure/railing/cap/CheckExit() - return TRUE +/obj/structure/railing/cap/on_atom_exit(datum/source, atom/movable/leaving, direction) + return -/obj/structure/railing/CanPass(atom/movable/mover, turf/target) +/obj/structure/railing/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSFENCE)) return TRUE if(isprojectile(mover)) @@ -110,11 +118,10 @@ return TRUE if(mover.throwing) return TRUE - mover_dir = get_dir(loc, target) //Due to how the other check is done, it would always return density for ordinal directions no matter what - if(ordinal_direction_check(mover_dir)) + if(ordinal_direction_check(border_dir)) return FALSE - if(mover_dir != dir) + if(border_dir != dir) return density return FALSE @@ -126,27 +133,27 @@ return TRUE -/obj/structure/railing/CheckExit(atom/movable/O, target) - var/mob/living/M = O - if(istype(O) && O.checkpass(PASSFENCE)) - return TRUE - if(isprojectile(O)) - return TRUE +/obj/structure/railing/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + SIGNAL_HANDLER // COMSIG_ATOM_EXIT + + var/mob/living/M = leaving + if(istype(leaving) && leaving.checkpass(PASSFENCE)) + return + if(isprojectile(leaving)) + return if(istype(M)) if(M.flying || M.floating || (IS_HORIZONTAL(M) && HAS_TRAIT(M, TRAIT_CONTORTED_BODY))) - return TRUE - if(O.throwing) - return TRUE - if(O.move_force >= MOVE_FORCE_EXTREMELY_STRONG) - return TRUE + return + if(leaving.throwing) + return + if(leaving.move_force >= MOVE_FORCE_EXTREMELY_STRONG) + return if(currently_climbed) - return TRUE - mover_dir = get_dir(O.loc, target) - if(mover_dir == dir) - return FALSE - if(ordinal_direction_check(mover_dir)) - return FALSE - return TRUE + return + if(direction == dir) + return COMPONENT_ATOM_BLOCK_EXIT + if(ordinal_direction_check(direction)) + return COMPONENT_ATOM_BLOCK_EXIT // Checks if the direction the mob is trying to move towards would be blocked by a corner railing /obj/structure/railing/proc/ordinal_direction_check(check_dir) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index b084ed71f877..8036559ddf4f 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -46,6 +46,11 @@ /obj/structure/table/Initialize(mapload) . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + AddElement(/datum/element/connect_loc, loc_connections) + if(flipped) update_icon() @@ -126,9 +131,9 @@ /obj/structure/table/proc/item_placed(item) return -/obj/structure/table/CanPass(atom/movable/mover, turf/target) +/obj/structure/table/CanPass(atom/movable/mover, border_dir) if(istype(mover,/obj/item/projectile)) - return (check_cover(mover,target)) + return check_cover(mover, border_dir) if(ismob(mover)) var/mob/living/M = mover if(M.flying || (IS_HORIZONTAL(M) && HAS_TRAIT(M, TRAIT_CONTORTED_BODY))) @@ -142,7 +147,7 @@ if(!T.flipped) return TRUE if(flipped) - if(get_dir(loc, target) == dir) + if(border_dir == dir) return !density else return TRUE @@ -159,30 +164,29 @@ * * Arguments: * * P - The projectile trying to cross. - * * from - Where the projectile is located. + * * proj_dir - The incoming direction of the projectile. */ -/obj/structure/table/proc/check_cover(obj/item/projectile/P, turf/from) +/obj/structure/table/proc/check_cover(obj/item/projectile/P, proj_dir) . = TRUE if(!flipped) return if(get_dist(P.starting, loc) <= 1) // Tables won't help you if people are THIS close return - var/proj_dir = get_dir(from, loc) var/block_dir = get_dir(get_step(loc, dir), loc) if(proj_dir != block_dir) // Back/side shots may pass return if(prob(40)) return FALSE // Blocked -/obj/structure/table/CheckExit(atom/movable/O, turf/target) - if(istype(O) && O.checkpass(PASSTABLE)) - return 1 +/obj/structure/table/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + SIGNAL_HANDLER // COMSIG_ATOM_EXIT + + if(istype(leaving) && leaving.checkpass(PASSTABLE)) + return + if(flipped) - if(get_dir(loc, target) == dir) - return !density - else - return 1 - return 1 + if(direction == dir && density) + return COMPONENT_ATOM_BLOCK_EXIT /obj/structure/table/MouseDrop_T(obj/O, mob/user) if(..()) @@ -460,27 +464,27 @@ . = ..() debris += new frame debris += new shardtype + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /obj/structure/table/glass/Destroy() for(var/i in debris) qdel(i) . = ..() -/obj/structure/table/glass/Crossed(atom/movable/AM, oldloc) - . = ..() +/obj/structure/table/glass/proc/on_movable_cross(datum/source, atom/movable/crossed) if(flags & NODECONSTRUCT) return - if(!isliving(AM)) + if(!isliving(crossed)) return - var/mob/living/L = AM + var/mob/living/L = crossed if(L.incorporeal_move || L.flying || L.floating) return // Don't break if they're just flying past - if(AM.throwing) - addtimer(CALLBACK(src, PROC_REF(throw_check), AM), 5) + if(crossed.throwing) + addtimer(CALLBACK(src, PROC_REF(throw_check), crossed), 5) else - check_break(AM) + check_break(crossed) /obj/structure/table/glass/proc/throw_check(mob/living/M) if(M.loc == get_turf(src)) @@ -899,7 +903,7 @@ . = ..() . += "It's held together by a couple of bolts." -/obj/structure/rack/CanPass(atom/movable/mover, turf/target) +/obj/structure/rack/CanPass(atom/movable/mover, border_dir) if(!density) //Because broken racks -Agouri |TODO: SPRITE!| return 1 if(istype(mover)) diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm index ad0fbabd901e..b5612911dd13 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube.dm @@ -33,7 +33,7 @@ P.empty_pod() return ..() -/obj/structure/transit_tube/CanPass(atom/movable/mover, turf/target) +/obj/structure/transit_tube/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSGLASS)) return TRUE return !density diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 06631ce17fdb..d78d90953643 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -307,6 +307,10 @@ pixel_y = -5 layer = FLY_LAYER +/obj/machinery/shower/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/machinery/shower/Destroy() QDEL_NULL(soundloop) var/obj/effect/mist/mist = locate() in loc @@ -401,10 +405,9 @@ if(mist && (!on || current_temperature == SHOWER_FREEZING)) qdel(mist) -/obj/machinery/shower/Crossed(atom/movable/AM) - ..() +/obj/machinery/shower/proc/on_movable_cross(datum/source, atom/movable/crossed) if(on) - wash(AM) + wash(crossed) /obj/machinery/shower/proc/convertHeat() switch(current_temperature) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index a5db59da8af9..69a7ddf467d8 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -55,6 +55,12 @@ if(set_dir) dir = set_dir ini_dir = dir + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + + AddElement(/datum/element/connect_loc, loc_connections) + recalculate_atmos_connectivity() /obj/structure/windoor_assembly/Destroy() @@ -72,10 +78,10 @@ /obj/structure/windoor_assembly/update_icon_state() icon_state = "[facing]_[secure ? "secure_" : ""]windoor_assembly[state]" -/obj/structure/windoor_assembly/CanPass(atom/movable/mover, turf/target) +/obj/structure/windoor_assembly/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSGLASS)) return 1 - if(get_dir(loc, target) == dir) //Make sure looking at appropriate border + if(border_dir == dir) //Make sure looking at appropriate border return !density if(istype(mover, /obj/structure/window)) var/obj/structure/window/W = mover @@ -95,13 +101,13 @@ else return TRUE -/obj/structure/windoor_assembly/CheckExit(atom/movable/mover, turf/target) - if(istype(mover) && mover.checkpass(PASSGLASS)) - return 1 - if(get_dir(loc, target) == dir) - return !density - else - return 1 +/obj/structure/windoor_assembly/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + SIGNAL_HANDLER // COMSIG_ATOM_EXIT + + if(istype(leaving) && leaving.checkpass(PASSGLASS)) + return + if(direction == dir && density) + return COMPONENT_ATOM_BLOCK_EXIT /obj/structure/windoor_assembly/attackby(obj/item/W, mob/user, params) //I really should have spread this out across more states but thin little windoors are hard to sprite. diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index e625b8494cce..4dfefd78ddd2 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -79,6 +79,12 @@ real_explosion_block = explosion_block explosion_block = EXPLOSION_BLOCK_PROC + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + + AddElement(/datum/element/connect_loc, loc_connections) + recalculate_atmos_connectivity() /obj/structure/window/proc/toggle_polarization() @@ -109,12 +115,12 @@ else ..(FULLTILE_WINDOW_DIR) -/obj/structure/window/CanPass(atom/movable/mover, turf/target) +/obj/structure/window/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSGLASS)) return 1 if(dir == FULLTILE_WINDOW_DIR) return 0 //full tile window, you can't move into it! - if(get_dir(loc, target) & dir) + if(border_dir & dir) return !density if(istype(mover, /obj/structure/window)) var/obj/structure/window/W = mover @@ -128,14 +134,16 @@ return FALSE return 1 -/obj/structure/window/CheckExit(atom/movable/O, target) - if(istype(O) && O.checkpass(PASSGLASS)) - return TRUE +/obj/structure/window/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + if(istype(leaving) && leaving.checkpass(PASSGLASS)) + return if(dir == FULLTILE_WINDOW_DIR) - return TRUE - if(get_dir(O.loc, target) & dir) - return FALSE - return TRUE + return + if(direction & dir) + leaving.Bump(src) + return COMPONENT_ATOM_BLOCK_EXIT + + return /obj/structure/window/CanPathfindPass(to_dir, datum/can_pass_info/pass_info) if(!density) diff --git a/code/game/turfs/simulated/floor/asteroid_floors.dm b/code/game/turfs/simulated/floor/asteroid_floors.dm index cdf971a9bdff..a72326f0b504 100644 --- a/code/game/turfs/simulated/floor/asteroid_floors.dm +++ b/code/game/turfs/simulated/floor/asteroid_floors.dm @@ -58,6 +58,15 @@ if(1) getDug() +/turf/simulated/floor/plating/asteroid/proc/attempt_ore_pickup(obj/item/storage/bag/ore/S, mob/user, params) + if(!istype(S)) + return + + if(S.pickup_all_on_tile) + for(var/obj/item/stack/ore/O in contents) + O.attackby(S, user) + return + /turf/simulated/floor/plating/asteroid/attackby(obj/item/I, mob/user, params) //note that this proc does not call ..() if(!I|| !user) @@ -82,11 +91,7 @@ return TRUE else if(istype(I, /obj/item/storage/bag/ore)) - var/obj/item/storage/bag/ore/S = I - if(S.pickup_all_on_tile) - for(var/obj/item/stack/ore/O in contents) - O.attackby(I, user) - return + attempt_ore_pickup(I, user, params) else if(istype(I, /obj/item/stack/tile)) var/obj/item/stack/tile/Z = I diff --git a/code/game/turfs/simulated/floor/chasm.dm b/code/game/turfs/simulated/floor/chasm.dm index 61be5dd4a8b3..71f1333c337f 100644 --- a/code/game/turfs/simulated/floor/chasm.dm +++ b/code/game/turfs/simulated/floor/chasm.dm @@ -286,7 +286,7 @@ atmos_mode = ATMOS_MODE_SEALED atmos_environment = null -/turf/simulated/floor/chasm/CanPass(atom/movable/mover, turf/target) +/turf/simulated/floor/chasm/CanPass(atom/movable/mover, border_dir) return 1 /turf/simulated/floor/chasm/pride/Initialize(mapload) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 32be3935c905..bfacbd9a7753 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -188,52 +188,33 @@ ..() return FALSE -/turf/Enter(atom/movable/mover as mob|obj, atom/forget) - if(!mover) - return TRUE - - // First, make sure it can leave its square - if(isturf(mover.loc)) - // Nothing but border objects stop you from leaving a tile, only one loop is needed - // This as anything looks odd, since we check istype shortly after, but it's so we can save an istype check for items, which are far more common than other objects. - for(var/obj/obstacle as anything in mover.loc) - if(isitem(obstacle) || !istype(obstacle) || obstacle == mover || obstacle == forget) +//There's a lot of QDELETED() calls here if someone can figure out how to optimize this but not runtime when something gets deleted by a Bump/CanPass/Cross call, lemme know or go ahead and fix this mess - kevinz000 +/turf/Enter(atom/movable/mover) + // Do not call ..() + // Byond's default turf/Enter() doesn't have the behaviour we want with Bump() + // By default byond will call Bump() on the first dense object in contents + // Here's hoping it doesn't stay like this for years before we finish conversion to step_ + var/atom/first_bump + var/can_pass_self = CanPass(mover, get_dir(src, mover)) + + if(can_pass_self) + var/atom/mover_loc = mover.loc + for(var/atom/movable/thing as anything in contents) + if(thing == mover || thing == mover_loc) // Multi tile objects and moving out of other objects continue - if(!obstacle.CheckExit(mover, src)) - mover.Bump(obstacle, TRUE) - return FALSE - - var/list/large_dense = list() - // Next, check for border obstacles on this turf - // Everyting inside a turf is an atom/movable. - for(var/atom/movable/border_obstacle as anything in src) - if(isitem(border_obstacle) || border_obstacle == forget || isnull(border_obstacle)) - continue - if(border_obstacle.flags & ON_BORDER) - if(!border_obstacle.CanPass(mover, mover.loc, 1)) - mover.Bump(border_obstacle, TRUE) - return FALSE - else - large_dense += border_obstacle - - //Then, check the turf itself - if(!src.CanPass(mover, src)) - mover.Bump(src, TRUE) + if(!thing.Cross(mover)) + if(QDELETED(mover)) //deleted from Cross() (CanPass is pure so it cant delete, Cross shouldnt be doing this either though, but it can happen) + return FALSE + if(!first_bump || (thing.layer > first_bump.layer)) + first_bump = thing + if(QDELETED(mover)) //Mover deleted from Cross/CanPass/Bump, do not proceed. return FALSE - - // Finally, check objects/mobs that block entry and are not on the border - var/atom/movable/tompost_bump - var/top_layer = FALSE - for(var/atom/movable/obstacle as anything in large_dense) - if(obstacle.layer <= top_layer) - continue - if(!obstacle.CanPass(mover, mover.loc, 1)) - tompost_bump = obstacle - top_layer = obstacle.layer - if(tompost_bump) - mover.Bump(tompost_bump, TRUE) + if(!can_pass_self) //Even if mover is unstoppable they need to bump us. + first_bump = src + if(first_bump) + mover.Bump(first_bump) return FALSE - return TRUE //Nothing found to block so return success! + return TRUE /turf/Entered(atom/movable/M, atom/OL, ignoreRest = FALSE) ..() diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 23b2063148e7..d9c77e3622b4 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -379,10 +379,10 @@ cuffed_state = "fleshlegcuff" flags = DROPDEL -/obj/item/restraints/legcuffs/beartrap/changeling/Crossed(AM, oldloc) - if(!iscarbon(AM) || !armed) +/obj/item/restraints/legcuffs/beartrap/changeling/on_atom_entered(datum/source, atom/movable/entered) + if(!iscarbon(entered) || !armed) return - var/mob/living/carbon/C = AM + var/mob/living/carbon/C = entered C.apply_status_effect(STATUS_EFFECT_CLINGTENTACLE) ..() diff --git a/code/modules/antagonists/vampire/vampire_powers/hemomancer_powers.dm b/code/modules/antagonists/vampire/vampire_powers/hemomancer_powers.dm index b39832c1fbec..4d49f11dd207 100644 --- a/code/modules/antagonists/vampire/vampire_powers/hemomancer_powers.dm +++ b/code/modules/antagonists/vampire/vampire_powers/hemomancer_powers.dm @@ -230,7 +230,7 @@ return ..() -/obj/structure/blood_barrier/CanPass(atom/movable/mover, turf/target) +/obj/structure/blood_barrier/CanPass(atom/movable/mover, border_dir) if(!isliving(mover)) return FALSE var/mob/living/L = mover diff --git a/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm index 691eed6ece64..4f89f2efd334 100644 --- a/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm +++ b/code/modules/antagonists/vampire/vampire_powers/umbrae_powers.dm @@ -62,16 +62,18 @@ breakouttime = 5 SECONDS flags = DROPDEL -/obj/item/restraints/legcuffs/beartrap/shadow_snare/Crossed(AM, oldloc) - if(!iscarbon(AM) || !armed) +/obj/item/restraints/legcuffs/beartrap/shadow_snare/on_atom_entered(datum/source, atom/movable/entered) + if(!iscarbon(entered) || !armed) return - var/mob/living/carbon/C = AM + var/mob/living/carbon/C = entered if(!C.affects_vampire()) // no parameter here so holy always protects return C.extinguish_light() C.EyeBlind(20 SECONDS) STOP_PROCESSING(SSobj, src) // won't wither away once you are trapped - ..() + + . = ..() + if(!iscarbon(loc)) // if it fails to latch onto someone for whatever reason, delete itself, we don't want unarmed ones lying around. qdel(src) diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index 4b35f4432430..b9ae5c66692e 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -24,6 +24,9 @@ var/wires = ASSEMBLY_WIRE_RECEIVE | ASSEMBLY_WIRE_PULSE var/datum/wires/connected = null // currently only used by timer/signaler +/obj/item/assembly/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /// Called when the holder is moved /obj/item/assembly/proc/holder_movement() @@ -33,6 +36,9 @@ /obj/item/assembly/interact(mob/user) return +/obj/item/assembly/proc/on_movable_cross(datum/source, atom/movable/crossed) + return + /// Called to constantly step down the countdown/cooldown /obj/item/assembly/proc/process_cooldown() cooldown-- diff --git a/code/modules/assembly/assembly_holder.dm b/code/modules/assembly/assembly_holder.dm index 2b6db0074412..d6cc03765db3 100644 --- a/code/modules/assembly/assembly_holder.dm +++ b/code/modules/assembly/assembly_holder.dm @@ -13,6 +13,13 @@ var/obj/item/assembly/a_left = null var/obj/item/assembly/a_right = null +/obj/item/assembly_holder/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/assembly_holder/IsAssemblyHolder() return TRUE @@ -83,11 +90,12 @@ a_right.HasProximity(AM) -/obj/item/assembly_holder/Crossed(atom/movable/AM, oldloc) +// TODO: All these assemblies passing the crossed args around needs to be cleaned up with signals +/obj/item/assembly_holder/proc/on_atom_entered(datum/source, atom/movable/entered) if(a_left) - a_left.Crossed(AM, oldloc) + a_left.on_movable_cross(entered) if(a_right) - a_right.Crossed(AM, oldloc) + a_right.on_movable_cross(entered) /obj/item/assembly_holder/on_found(mob/finder) if(a_left) diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index 6cd315d4ded9..b7598200f745 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -12,6 +12,13 @@ var/obj/item/tank/bombtank = null //the second part of the bomb is a plasma tank origin_tech = "materials=1;engineering=1" +/obj/item/onetankbomb/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/onetankbomb/examine(mob/user) . = ..() . += bombtank.examine(user) @@ -74,9 +81,9 @@ if(bombassembly) bombassembly.HasProximity(AM) -/obj/item/onetankbomb/Crossed(atom/movable/AM, oldloc) //for mousetraps +/obj/item/onetankbomb/proc/on_atom_entered(datum/source, atom/movable/entered) //for mousetraps if(bombassembly) - bombassembly.Crossed(AM, oldloc) + bombassembly.on_atom_entered(source, entered) /obj/item/onetankbomb/on_found(mob/finder) //for mousetraps if(bombassembly) diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 365ef113f428..fa0b48262ea5 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -213,6 +213,9 @@ anchored = TRUE pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE | PASSFENCE +/obj/effect/beam/i_beam/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /obj/effect/beam/i_beam/proc/hit() if(master) @@ -267,10 +270,10 @@ /obj/effect/beam/i_beam/Bumped() hit() -/obj/effect/beam/i_beam/Crossed(atom/movable/AM, oldloc) - if(!isobj(AM) && !isliving(AM)) +/obj/effect/beam/i_beam/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(!isobj(crossed) && !isliving(crossed)) return - if(iseffect(AM)) + if(iseffect(crossed)) return hit() diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 5284fc3fdc8e..bc0cd1899847 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -108,19 +108,19 @@ return ..() -/obj/item/assembly/mousetrap/Crossed(atom/movable/AM, oldloc) +/obj/item/assembly/mousetrap/on_movable_cross(datum/source, atom/movable/crossed) if(armed) - if(ishuman(AM)) - var/mob/living/carbon/H = AM + if(ishuman(crossed)) + var/mob/living/carbon/H = crossed if(H.m_intent == MOVE_INTENT_RUN) triggered(H) H.visible_message("[H] accidentally steps on [src].", "You accidentally step on [src]") - else if(ismouse(AM)) - triggered(AM) + else if(ismouse(crossed)) + triggered(crossed) - else if(AM.density) // For mousetrap grenades, set off by anything heavy - triggered(AM) + else if(crossed.density) // For mousetrap grenades, set off by anything heavy + triggered(crossed) ..() diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index 8369f439e8ce..49eb10517f08 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -187,6 +187,11 @@ return 0*/ return 1 + +/obj/effect/hotspot/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + // Garbage collect itself by nulling reference to it /obj/effect/hotspot/Destroy() @@ -218,9 +223,9 @@ T.to_be_destroyed = 0 T.max_fire_temperature_sustained = 0 -/obj/effect/hotspot/Crossed(mob/living/L, oldloc) - ..() - if(isliving(L)) +/obj/effect/hotspot/proc/on_movable_cross(datum/source, atom/movable/crossed) + var/mob/living/L = crossed + if(istype(L)) L.fire_act() /obj/effect/hotspot/singularity_pull() diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm index ff4f57b01c80..69872c861fa6 100644 --- a/code/modules/atmospherics/environmental/LINDA_system.dm +++ b/code/modules/atmospherics/environmental/LINDA_system.dm @@ -18,11 +18,13 @@ /atom/movable/proc/CanAtmosPass() return TRUE -/atom/proc/CanPass(atom/movable/mover, turf/target) +/atom/proc/CanPass(atom/movable/mover, border_dir) return !density -/turf/CanPass(atom/movable/mover, turf/target) - if(!target) return 0 +/turf/CanPass(atom/movable/mover, border_dir) + var/turf/target = get_step(src, border_dir) + if(!target) + return 0 if(istype(mover)) // turf/Enter(...) will perform more advanced checks return !density @@ -32,7 +34,7 @@ return 0 for(var/obj/obstacle in src) - if(!obstacle.CanPass(mover, target)) + if(!obstacle.CanPass(mover, border_dir)) return 0 for(var/obj/obstacle in target) if(!obstacle.CanPass(mover, src)) diff --git a/code/modules/awaymissions/mission_code/ruins/deepstorage.dm b/code/modules/awaymissions/mission_code/ruins/deepstorage.dm index 17494928b3ff..5dc9f1c76592 100644 --- a/code/modules/awaymissions/mission_code/ruins/deepstorage.dm +++ b/code/modules/awaymissions/mission_code/ruins/deepstorage.dm @@ -109,8 +109,8 @@ playsound(src, 'sound/effects/meteorimpact.ogg', 25, TRUE, 2, TRUE) return ..() -/mob/living/simple_animal/hostile/megafauna/fleshling/Bump(atom/A, yes) - if(charging && yes) +/mob/living/simple_animal/hostile/megafauna/fleshling/Bump(atom/A) + if(charging) if(isliving(A)) var/mob/living/L = A L.visible_message("[src] slams into [L]!", "[src] tramples you into the ground!") diff --git a/code/modules/awaymissions/mission_code/ruins/telecomns.dm b/code/modules/awaymissions/mission_code/ruins/telecomns.dm index 0d33c92bc9fa..6251a95e4e41 100644 --- a/code/modules/awaymissions/mission_code/ruins/telecomns.dm +++ b/code/modules/awaymissions/mission_code/ruins/telecomns.dm @@ -20,9 +20,12 @@ GLOBAL_LIST_EMPTY(telecomms_trap_tank) /obj/effect/abstract/bot_trap name = "evil bot trap to make explorers hate you" -/obj/effect/abstract/bot_trap/Crossed(atom/movable/AM, oldloc) +/obj/effect/abstract/bot_trap/Initialize(mapload) . = ..() - if(isrobot(AM) || ishuman(AM)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/effect/abstract/bot_trap/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isrobot(crossed) || ishuman(crossed)) var/turf/T = get_turf(src) for(var/mob/living/simple_animal/bot/B in GLOB.telecomms_bots) B.call_bot(null, T, FALSE) @@ -32,9 +35,12 @@ GLOBAL_LIST_EMPTY(telecomms_trap_tank) /obj/effect/abstract/loot_trap name = "table surrounding loot trap" -/obj/effect/abstract/loot_trap/Crossed(atom/movable/AM, oldloc) +/obj/effect/abstract/loot_trap/Initialize(mapload) . = ..() - if(isrobot(AM) || ishuman(AM)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/effect/abstract/loot_trap/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isrobot(crossed) || ishuman(crossed)) var/turf/T = get_turf(src) for(var/obj/structure/telecomms_doomsday_device/DD in GLOB.telecomms_doomsday_device) DD.thief = TRUE @@ -47,9 +53,12 @@ GLOBAL_LIST_EMPTY(telecomms_trap_tank) /obj/effect/abstract/cheese_trap name = "cheese preventer" -/obj/effect/abstract/cheese_trap/Crossed(atom/movable/AM, oldloc) +/obj/effect/abstract/cheese_trap/Initialize(mapload) . = ..() - if(isrobot(AM) || ishuman(AM)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/effect/abstract/cheese_trap/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isrobot(crossed) || ishuman(crossed)) for(var/obj/structure/telecomms_doomsday_device/DD in GLOB.telecomms_doomsday_device) if(DD.thief) DD.start_the_party(TRUE) diff --git a/code/modules/awaymissions/mission_code/shuttle_shadow.dm b/code/modules/awaymissions/mission_code/shuttle_shadow.dm index e1ed6df4c1f7..137ac4b611db 100644 --- a/code/modules/awaymissions/mission_code/shuttle_shadow.dm +++ b/code/modules/awaymissions/mission_code/shuttle_shadow.dm @@ -6,9 +6,9 @@ return ..() -/obj/machinery/atmospherics/unary/passive_vent/high_volume/shadow/onTransitZ(old_z, new_z) +/obj/machinery/atmospherics/unary/passive_vent/high_volume/shadow/on_changed_z_level(turf/old_turf, turf/new_turf) . = ..() - if(is_station_level(new_z)) + if(is_station_level(new_turf?.z)) on = TRUE /obj/machinery/atmospherics/trinary/filter/shadow @@ -18,15 +18,15 @@ on = FALSE target_pressure = 99999 -/obj/machinery/atmospherics/trinary/filter/shadow/onTransitZ(old_z, new_z) +/obj/machinery/atmospherics/trinary/filter/shadow/on_changed_z_level(turf/old_turf, turf/new_turf) . = ..() - if(is_station_level(new_z)) + if(is_station_level(new_turf?.z)) on = TRUE /obj/machinery/igniter/shadow -/obj/machinery/igniter/shadow/onTransitZ(old_z, new_z) +/obj/machinery/igniter/shadow/on_changed_z_level(turf/old_turf, turf/new_turf) . = ..() - if(is_station_level(new_z)) + if(is_station_level(new_turf?.z)) on = TRUE update_icon() diff --git a/code/modules/events/blob/blob_mobs.dm b/code/modules/events/blob/blob_mobs.dm index aad976d37397..c3e63a4cce33 100644 --- a/code/modules/events/blob/blob_mobs.dm +++ b/code/modules/events/blob/blob_mobs.dm @@ -74,7 +74,7 @@ var/mob/living/carbon/human/oldguy var/is_zombie = FALSE -/mob/living/simple_animal/hostile/blob/blobspore/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/blob/blobspore/CanPass(atom/movable/mover, border_dir) if(istype(mover, /obj/structure/blob)) return 1 return ..() diff --git a/code/modules/events/blob/blob_structures/blob_core.dm b/code/modules/events/blob/blob_structures/blob_core.dm index 826f4155f39d..7383609950e4 100644 --- a/code/modules/events/blob/blob_structures/blob_core.dm +++ b/code/modules/events/blob/blob_structures/blob_core.dm @@ -139,7 +139,7 @@ else log_debug("/obj/structure/blob/core/proc/lateblobcheck: Blob core lacks an overmind.") -/obj/structure/blob/core/onTransitZ(old_z, new_z) - if(overmind && is_station_level(new_z)) +/obj/structure/blob/core/on_changed_z_level(turf/old_turf, turf/new_turf) + if(overmind && is_station_level(new_turf?.z)) overmind.forceMove(get_turf(src)) return ..() diff --git a/code/modules/events/blob/blob_structures/strong_blob.dm b/code/modules/events/blob/blob_structures/strong_blob.dm index 7747686be6be..299e1d968619 100644 --- a/code/modules/events/blob/blob_structures/strong_blob.dm +++ b/code/modules/events/blob/blob_structures/strong_blob.dm @@ -49,7 +49,7 @@ else icon_state = initial(icon_state) -/obj/structure/blob/shield/CanPass(atom/movable/mover, turf/target) +/obj/structure/blob/shield/CanPass(atom/movable/mover, border_dir) return istype(mover) && mover.checkpass(PASSBLOB) /obj/structure/blob/shield/reflective diff --git a/code/modules/events/blob/theblob.dm b/code/modules/events/blob/theblob.dm index 6cd12653f998..d57fab80b018 100644 --- a/code/modules/events/blob/theblob.dm +++ b/code/modules/events/blob/theblob.dm @@ -49,7 +49,7 @@ GLOBAL_LIST_EMPTY(blob_minions) return FALSE return ..() -/obj/structure/blob/CanPass(atom/movable/mover, turf/target) +/obj/structure/blob/CanPass(atom/movable/mover, border_dir) return istype(mover) && mover.checkpass(PASSBLOB) /obj/structure/blob/CanAtmosPass(direction) @@ -201,9 +201,12 @@ GLOBAL_LIST_EMPTY(blob_minions) color = incoming_overmind.blob_reagent_datum.color return -/obj/structure/blob/Crossed(mob/living/L, oldloc) - ..() - L.blob_act(src) +/obj/structure/blob/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/structure/blob/proc/on_movable_cross(datum/source, atom/movable/crossed) + crossed.blob_act(src) /obj/structure/blob/zap_act(power, zap_flags) take_damage(power * 0.0025, BURN, ENERGY) diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 95f6203b2056..cc135a2eab2a 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -405,6 +405,7 @@ /obj/structure/spacevine/Initialize(mapload) . = ..() color = "#ffffff" + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /obj/structure/spacevine/examine(mob/user) . = ..() @@ -512,15 +513,15 @@ /obj/structure/spacevine/obj_destruction() wither() -/obj/structure/spacevine/Crossed(mob/crosser, oldloc) - if(!isliving(crosser)) +/obj/structure/spacevine/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(!isliving(crossed)) return for(var/SM_type in mutations) var/datum/spacevine_mutation/SM = mutations[SM_type] - SM.on_cross(src, crosser) + SM.on_cross(src, crossed) if(prob(30 * energy)) - entangle(crosser) + entangle(crossed) /obj/structure/spacevine/attack_hand(mob/user) for(var/SM_type in mutations) @@ -705,7 +706,7 @@ if(!override) wither() -/obj/structure/spacevine/CanPass(atom/movable/mover, turf/target) +/obj/structure/spacevine/CanPass(atom/movable/mover, border_dir) if(isvineimmune(mover)) . = TRUE else diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 484afa4f43fc..41ae7b2e8141 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -133,6 +133,10 @@ var/lighter // Who lit the fucking thing var/fire_stack_strength = 5 +/obj/structure/bonfire/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/structure/bonfire/dense density = TRUE @@ -199,11 +203,11 @@ ..() StartBurning() -/obj/structure/bonfire/Crossed(atom/movable/AM, oldloc) +/obj/structure/bonfire/proc/on_movable_cross(datum/source, atom/movable/crossed) if(burning) Burn() - if(ishuman(AM)) - var/mob/living/carbon/human/H = AM + if(ishuman(crossed)) + var/mob/living/carbon/human/H = crossed add_attack_logs(src, H, "Burned by a bonfire (Lit by [lighter])", ATKLOG_ALMOSTALL) /obj/structure/bonfire/proc/Burn() diff --git a/code/modules/hydroponics/hydroponics_tray.dm b/code/modules/hydroponics/hydroponics_tray.dm index 0c0f799fdbc0..b42681420be6 100644 --- a/code/modules/hydroponics/hydroponics_tray.dm +++ b/code/modules/hydroponics/hydroponics_tray.dm @@ -988,7 +988,7 @@ update_state() ///Diona Nymph Related Procs/// -/obj/machinery/hydroponics/CanPass(atom/movable/mover, turf/target) //So nymphs can climb over top of trays. +/obj/machinery/hydroponics/CanPass(atom/movable/mover, border_dir) //So nymphs can climb over top of trays. if(istype(mover) && mover.checkpass(PASSTABLE)) return 1 else diff --git a/code/modules/lighting/lighting_emissive_blocker.dm b/code/modules/lighting/lighting_emissive_blocker.dm index b2102dea8b09..37524bc945a3 100644 --- a/code/modules/lighting/lighting_emissive_blocker.dm +++ b/code/modules/lighting/lighting_emissive_blocker.dm @@ -31,8 +31,8 @@ /atom/movable/emissive_blocker/blob_act() return -/atom/movable/emissive_blocker/onTransitZ() - return +/atom/movable/emissive_blocker/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = FALSE) + return ..() //Prevents people from moving these after creation, because they shouldn't be. /atom/movable/emissive_blocker/forceMove(atom/destination, no_tp = FALSE, harderforce = FALSE) diff --git a/code/modules/lighting/lighting_object.dm b/code/modules/lighting/lighting_object.dm index 168a95c07f26..df62b5c342e9 100644 --- a/code/modules/lighting/lighting_object.dm +++ b/code/modules/lighting/lighting_object.dm @@ -142,8 +142,8 @@ /atom/movable/lighting_object/blob_act(obj/structure/blob/B) return -/atom/movable/lighting_object/onTransitZ() - return +/atom/movable/lighting_object/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = FALSE) + return ..() // Override here to prevent things accidentally moving around overlays. /atom/movable/lighting_object/forceMove(atom/destination, no_tp = FALSE, harderforce = FALSE) diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index fd4b2a3885ea..1b6cb0f8e54b 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -22,6 +22,13 @@ pixel_x = rand(0, 16) - 8 pixel_y = rand(0, 8) - 8 +/obj/item/stack/ore/Initialize(mapload, new_amount, merge) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/stack/ore/welder_act(mob/user, obj/item/I) . = TRUE if(!refined_type) @@ -33,32 +40,32 @@ to_chat(user, "You smelt [src] into its refined form!") qdel(src) -/obj/item/stack/ore/Crossed(atom/movable/AM, oldloc) +/obj/item/stack/ore/on_atom_entered(datum/source, atom/movable/entered) var/obj/item/storage/bag/ore/OB var/turf/simulated/floor/F = get_turf(src) if(loc != F) - return ..() - if(ishuman(AM)) - var/mob/living/carbon/human/H = AM + return + if(ishuman(entered)) + var/mob/living/carbon/human/H = entered for(var/thing in H.get_body_slots()) if(istype(thing, /obj/item/storage/bag/ore)) OB = thing break - else if(isrobot(AM)) - var/mob/living/silicon/robot/R = AM + else if(isrobot(entered)) + var/mob/living/silicon/robot/R = entered for(var/thing in R.get_all_slots()) if(istype(thing, /obj/item/storage/bag/ore)) OB = thing break if(OB && istype(F, /turf/simulated/floor/plating/asteroid)) - F.attackby(OB, AM) + var/turf/simulated/floor/plating/asteroid/FA = F + FA.attempt_ore_pickup(OB) // Then, if the user is dragging an ore box, empty the satchel // into the box. - var/mob/living/L = AM + var/mob/living/L = entered if(istype(L.pulling, /obj/structure/ore_box)) var/obj/structure/ore_box/box = L.pulling - box.attackby(OB, AM) - return ..() + box.attackby(OB, entered) /obj/item/stack/ore/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE) . = ..() diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm index 92ed05e83c2a..9b673a0f59c3 100644 --- a/code/modules/mining/satchel_ore_boxdm.dm +++ b/code/modules/mining/satchel_ore_boxdm.dm @@ -19,7 +19,6 @@ S.hide_from(usr) for(var/obj/item/stack/ore/O in S.contents) S.remove_from_storage(O, src) //This will move the item to this item's contents - CHECK_TICK to_chat(user, "You empty the satchel into the box.") else return ..() @@ -84,8 +83,8 @@ if(Adjacent(user)) . += "You can Alt-Shift-Click to empty the ore box." -/obj/structure/ore_box/onTransitZ() - return +/obj/structure/ore_box/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = FALSE) + return ..() /obj/structure/ore_box/AltShiftClick(mob/user) if(!Adjacent(user) || !ishuman(user) || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED)) diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 873b60555a91..3ea6c1471364 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -16,14 +16,14 @@ var/turf/old_turf = get_turf(src) var/turf/new_turf = get_turf(destination) if(old_turf?.z != new_turf?.z) - onTransitZ(old_turf?.z, new_turf?.z) + on_changed_z_level(old_turf, new_turf) var/oldloc = loc loc = destination Moved(oldloc, direction) -/mob/dead/onTransitZ(old_z,new_z) +/mob/dead/on_changed_z_level(turf/old_turf, turf/new_turf) ..() - update_z(new_z) + update_z(new_turf?.z) /mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister if(registered_z != new_z) diff --git a/code/modules/mob/dead/observer/observer_base.dm b/code/modules/mob/dead/observer/observer_base.dm index 2e25e620b40e..bf2e54d5177d 100644 --- a/code/modules/mob/dead/observer/observer_base.dm +++ b/code/modules/mob/dead/observer/observer_base.dm @@ -167,7 +167,7 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new) MA.plane = GAME_PLANE . = MA -/mob/dead/CanPass(atom/movable/mover, turf/target) +/mob/dead/CanPass(atom/movable/mover, border_dir) return 1 diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 4b54760533a7..a7d1f24a7a15 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -67,10 +67,6 @@ /obj/item/clothing/mask/facehugger/equipped(mob/M) Attach(M) -/obj/item/clothing/mask/facehugger/Crossed(atom/target, oldloc) - HasProximity(target) - return - /obj/item/clothing/mask/facehugger/on_found(mob/finder) if(stat != DEAD) return HasProximity(finder) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index a7209d9f643c..372809934e9a 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -68,10 +68,10 @@ return //Generic Bump(). Override MobBump() and ObjBump() instead of this. -/mob/living/Bump(atom/A, yes) +/mob/living/Bump(atom/A) if(..()) //we are thrown onto something return - if(buckled || !yes || now_pushing) + if(buckled || now_pushing) return if(ismob(A)) if(MobBump(A)) @@ -1048,9 +1048,9 @@ else registered_z = null -/mob/living/onTransitZ(old_z,new_z) +/mob/living/on_changed_z_level(turf/old_turf, turf/new_turf) ..() - update_z(new_z) + update_z(new_turf?.z) /mob/living/rad_act(amount) . = ..() @@ -1165,11 +1165,6 @@ for(var/obj/O in src) O.on_mob_move(Dir, src) -/mob/living/Crossed(atom/movable/mover) - if(istype(mover, /obj/singularity/energy_ball)) - dust() - return ..() - /// Can a mob interact with the apc remotely like a pulse demon, cyborg, or AI? /mob/living/proc/can_remote_apc_interface(obj/machinery/power/apc/ourapc) return FALSE diff --git a/code/modules/mob/living/simple_animal/bot/griefsky.dm b/code/modules/mob/living/simple_animal/bot/griefsky.dm index 58a3b0731528..5b3a393e9d12 100644 --- a/code/modules/mob/living/simple_animal/bot/griefsky.dm +++ b/code/modules/mob/living/simple_animal/bot/griefsky.dm @@ -48,10 +48,9 @@ ..() light_color = LIGHT_COLOR_PURE_RED //if you see a red one. RUN!! -/mob/living/simple_animal/bot/secbot/griefsky/Crossed(atom/movable/AM, oldloc) - ..() - if(ismob(AM) && AM == target) - var/mob/living/carbon/C = AM +/mob/living/simple_animal/bot/secbot/griefsky/on_movable_cross(datum/source, atom/movable/crossed) + if(iscarbon(crossed) && crossed == target) + var/mob/living/carbon/C = crossed visible_message("[src] flails his swords and pushes [C] out of it's way!" ) C.KnockDown(4 SECONDS) @@ -61,6 +60,7 @@ var/datum/job/detective/J = new/datum/job/detective access_card.access += J.get_access() prev_access = access_card.access + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /mob/living/simple_animal/bot/secbot/griefsky/UnarmedAttack(atom/A) //like secbots its only possible with admin intervention diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index db8e397271e5..65e12c2ba9c1 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -36,6 +36,7 @@ var/datum/job/clown/J = new /datum/job/clown() access_card.access += J.get_access() prev_access = access_card.access + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /mob/living/simple_animal/bot/honkbot/proc/sensor_blink() icon_state = "honkbot-c" @@ -372,10 +373,10 @@ target = user mode = BOT_HUNT -/mob/living/simple_animal/bot/honkbot/Crossed(atom/movable/AM, oldloc) - if(ismob(AM) && on) //only if its online +/mob/living/simple_animal/bot/honkbot/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(ismob(crossed) && on) //only if its online if(prob(30)) //you're far more likely to trip on a honkbot - var/mob/living/carbon/C = AM + var/mob/living/carbon/C = crossed if(!istype(C) || !C || in_range(src, target)) return C.visible_message("[pick( \ @@ -390,5 +391,3 @@ if(!client) speak("Honk!") sensor_blink() - return - ..() diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 80904841ab2e..e55fa13dc5bd 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -74,7 +74,7 @@ mulebot_count++ set_suffix(suffix ? suffix : "#[mulebot_count]") - RegisterSignal(src, COMSIG_CROSSED_MOVABLE, PROC_REF(human_squish_check)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(human_squish_check)) /mob/living/simple_animal/bot/mulebot/Destroy() SStgui.close_uis(wires) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 05704ccb59b0..7c30583daacb 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -49,6 +49,7 @@ var/datum/job/detective/J = new/datum/job/detective access_card.access += J.get_access() prev_access = access_card.access + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /mob/living/simple_animal/bot/secbot/Destroy() QDEL_NULL(baton) @@ -453,9 +454,9 @@ target = user mode = BOT_HUNT -/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM, oldloc) - if(ismob(AM) && target) - var/mob/living/carbon/C = AM +/mob/living/simple_animal/bot/secbot/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(ismob(crossed) && target) + var/mob/living/carbon/C = crossed if(!istype(C) || !C || in_range(src, target)) return C.visible_message("[pick( \ @@ -467,6 +468,5 @@ "[C] leaps out of [src]'s way!")]") C.KnockDown(4 SECONDS) return - ..() #undef BATON_COOLDOWN diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm index 4cfcd4058e8c..247a5d6a637e 100644 --- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm +++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm @@ -28,18 +28,19 @@ /mob/living/simple_animal/cockroach/Initialize(mapload) //Lizards are a great way to deal with cockroaches . = ..() ADD_TRAIT(src, TRAIT_EDIBLE_BUG, "edible_bug") + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) -/mob/living/simple_animal/cockroach/Crossed(atom/movable/AM, oldloc) - if(isliving(AM)) - var/mob/living/A = AM +/mob/living/simple_animal/cockroach/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isliving(crossed)) + var/mob/living/A = crossed if(A.mob_size > MOB_SIZE_SMALL) if(prob(squish_chance)) A.visible_message("\The [A] squashed \the [name].", "You squashed \the [name].") death() else visible_message("\The [name] avoids getting crushed.") - else if(isstructure(AM)) - visible_message("As \the [AM] moved over \the [name], it was crushed.") + else if(isstructure(crossed)) + visible_message("As \the [crossed] moved over \the [name], it was crushed.") death() /mob/living/simple_animal/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach. diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index ae48d73f78bb..07b08666f2d1 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -85,6 +85,10 @@ icon_resting = "mouse_[mouse_color]_sleep" update_appearance(UPDATE_DESC) +/mob/living/simple_animal/mouse/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /mob/living/simple_animal/mouse/update_desc() . = ..() desc = "It's a small [mouse_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself." @@ -101,12 +105,11 @@ to_chat(src, "You are too small to pull anything except cheese.") return -/mob/living/simple_animal/mouse/Crossed(AM as mob|obj, oldloc) - if(ishuman(AM)) +/mob/living/simple_animal/mouse/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(ishuman(crossed)) if(stat == CONSCIOUS) - var/mob/M = AM + var/mob/M = crossed to_chat(M, "[bicon(src)] Squeek!") - ..() /mob/living/simple_animal/mouse/proc/toast() add_atom_colour("#3A3A3A", FIXED_COLOUR_PRIORITY) diff --git a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm index dd33037817bd..1b8dbc12fbdd 100644 --- a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm +++ b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm @@ -69,7 +69,7 @@ playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1) -/mob/living/simple_animal/hostile/floor_cluwne/CanPass(atom/A, turf/target) +/mob/living/simple_animal/hostile/floor_cluwne/CanPass(atom/A, border_dir) return TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm index 75b18ec3ea1c..206cb5c5e4b6 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm @@ -307,9 +307,9 @@ Difficulty: Hard return return ..() -/mob/living/simple_animal/hostile/megafauna/ancient_robot/Bump(atom/A, yes) +/mob/living/simple_animal/hostile/megafauna/ancient_robot/Bump(atom/A) if(charging) - if(isliving(A) && yes) + if(isliving(A)) var/mob/living/L = A if(!istype(A, /mob/living/simple_animal/hostile/ancient_robot_leg)) L.visible_message("[src] slams into [L]!", "[src] tramples you into the ground!") @@ -695,9 +695,9 @@ Difficulty: Hard /mob/living/simple_animal/hostile/ancient_robot_leg/proc/beam_setup() leg_part = Beam(core.beam, "leg_connection", 'icons/effects/effects.dmi', time=INFINITY, maxdistance=INFINITY, beam_type=/obj/effect/ebeam) -/mob/living/simple_animal/hostile/ancient_robot_leg/onTransitZ(old_z,new_z) +/mob/living/simple_animal/hostile/ancient_robot_leg/on_changed_z_level(turf/old_turf, turf/new_turf) ..() - update_z(new_z) + update_z(new_turf?.z) if(leg_part) QDEL_NULL(leg_part) addtimer(CALLBACK(src, PROC_REF(beam_setup)), 1 SECONDS) @@ -730,10 +730,10 @@ Difficulty: Hard walk_towards(src, T, movespeed) DestroySurroundings() -/mob/living/simple_animal/hostile/ancient_robot_leg/Bump(atom/A, yes) +/mob/living/simple_animal/hostile/ancient_robot_leg/Bump(atom/A) if(!core.charging) return - if(isliving(A) && yes) + if(isliving(A)) if(!istype(A, /mob/living/simple_animal/hostile/megafauna/ancient_robot)) var/mob/living/L = A L.visible_message("[src] slams into [L]!", "[src] tramples you into the ground!") @@ -820,7 +820,7 @@ Difficulty: Hard tesla_zap(src, zap_range, power, zap_flags) qdel(src) -/obj/item/projectile/energy/tesla_bolt/Bump(atom/A, yes) // Don't want the projectile hitting the legs +/obj/item/projectile/energy/tesla_bolt/Bump(atom/A) // Don't want the projectile hitting the legs if(!istype(/mob/living/simple_animal/hostile/ancient_robot_leg, A)) return ..() var/turf/target_turf = get_turf(A) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index e87e4cbfea06..6c3408e8df98 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -513,7 +513,7 @@ Difficulty: Hard severity = EXPLODE_LIGHT // puny mortals return ..() -/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, border_dir) if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination)) return TRUE return ..() @@ -541,8 +541,8 @@ Difficulty: Hard playsound(src, 'sound/effects/meteorimpact.ogg', 200, TRUE, 2, TRUE) return ..() -/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A, yes) - if(charging && yes) +/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A) + if(charging) if(isturf(A) || isobj(A) && A.density) A.ex_act(EXPLODE_HEAVY) if(isliving(A)) @@ -609,7 +609,7 @@ Difficulty: Hard new /obj/effect/decal/cleanable/blood(get_turf(src)) . = ..() -/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, border_dir) if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother return TRUE return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm index 943b86921906..b6b99bf20dcc 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -600,7 +600,7 @@ Difficulty: Hard QUEUE_SMOOTH_NEIGHBORS(src) return ..() -/obj/effect/temp_visual/hierophant/wall/CanPass(atom/movable/mover, turf/target) +/obj/effect/temp_visual/hierophant/wall/CanPass(atom/movable/mover, border_dir) if(QDELETED(caster)) return FALSE if(mover == caster.pulledby) @@ -721,6 +721,7 @@ Difficulty: Hard var/turf/simulated/mineral/M = loc M.gets_drilled(caster) INVOKE_ASYNC(src, PROC_REF(blast)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) /obj/effect/temp_visual/hierophant/blast/proc/blast() var/turf/T = get_turf(src) @@ -733,8 +734,7 @@ Difficulty: Hard sleep(1.3) //slightly forgiving; the burst animation is 1.5 deciseconds bursting = FALSE //we no longer damage crossers -/obj/effect/temp_visual/hierophant/blast/Crossed(atom/movable/AM) - ..() +/obj/effect/temp_visual/hierophant/blast/proc/on_movable_cross(datum/source, atom/movable/crossed) if(bursting) do_damage(get_turf(src)) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm index bd6e91932d0e..145b39c71a26 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -101,7 +101,7 @@ else devour(L) -/mob/living/simple_animal/hostile/megafauna/onTransitZ(old_z, new_z) +/mob/living/simple_animal/hostile/megafauna/on_changed_z_level(turf/old_turf, turf/new_turf) . = ..() if(!istype(get_area(src), /area/shuttle)) //I'll be funny and make non teleported enrage mobs not lose enrage. Harder to pull off, and also funny when it happens accidently. Or if one gets on the escape shuttle. unrage() diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm index 68c4c3f6c938..01e56c18010f 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/legionnaire.dm @@ -292,12 +292,16 @@ light_color = LIGHT_COLOR_RED var/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/myowner = null -/obj/structure/legionnaire_bonfire/Crossed(datum/source, atom/movable/mover) - if(isobj(source)) - var/obj/object = source +/obj/structure/legionnaire_bonfire/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/structure/legionnaire_bonfire/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isobj(crossed)) + var/obj/object = crossed object.fire_act(1000, 500) - if(isliving(source)) - var/mob/living/fire_walker = source + if(isliving(crossed)) + var/mob/living/fire_walker = crossed fire_walker.adjust_fire_stacks(5) fire_walker.IgniteMob() diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm b/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm index c4a887baf233..54759078028a 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm @@ -237,7 +237,7 @@ new /obj/effect/gibspawner/human(get_turf(src)) return ..() -/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/CanPass(atom/movable/mover, turf/target) +/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/CanPass(atom/movable/mover, border_dir) if(isliving(mover)) var/mob/living/blocker = mover if(faction_check_mob(blocker)) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm index ae8634db2b17..a7886ef859f3 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm @@ -171,7 +171,9 @@ if(prob(50)) icon_state = "stickyweb2" -/obj/structure/spider/terrorweb/CanPass(atom/movable/mover, turf/target) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + +/obj/structure/spider/terrorweb/CanPass(atom/movable/mover, border_dir) if(isterrorspider(mover)) return TRUE if(istype(mover, /obj/item/projectile/terrorqueenspit)) @@ -185,10 +187,9 @@ return prob(20) return ..() -/obj/structure/spider/terrorweb/Crossed(atom/movable/AM, oldloc) - ..() - if(isliving(AM) && !isterrorspider(AM)) - var/mob/living/M = AM +/obj/structure/spider/terrorweb/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isliving(crossed) && !isterrorspider(crossed)) + var/mob/living/M = crossed to_chat(M, "You get stuck in [src] for a moment.") M.Weaken(8 SECONDS) if(iscarbon(M)) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm index d26e9d975db3..358894501a7f 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm @@ -139,7 +139,7 @@ name = "mother web" desc = "This web is coated in pheromones which prevent spiderlings from passing it." -/obj/structure/spider/terrorweb/mother/CanPass(atom/movable/mover, turf/target) +/obj/structure/spider/terrorweb/mother/CanPass(atom/movable/mover, border_dir) if(istype(mover, /obj/structure/spider/spiderling/terror_spiderling)) return FALSE return ..() diff --git a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm index 84ee41256fcf..ac2d4230b5dd 100644 --- a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm +++ b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm @@ -37,11 +37,14 @@ mouse_opacity = MOUSE_OPACITY_ICON desc = "A thick vine, painful to the touch." +/obj/effect/ebeam/vine/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) -/obj/effect/ebeam/vine/Crossed(atom/movable/AM, oldloc) - if(!isliving(AM)) +/obj/effect/ebeam/vine/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(!isliving(crossed)) return - var/mob/living/L = AM + var/mob/living/L = crossed if(!("vines" in L.faction)) L.adjustBruteLoss(5) to_chat(L, "You cut yourself on the thorny vines.") diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 6ac0309330a4..71898767cc78 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -194,7 +194,7 @@ return /* - * String associated list returns a cached list. + * String associated list returns a cached list. * This is like a static list to pass into the element below. */ atmos_requirements = string_assoc_list(atmos_requirements) @@ -581,10 +581,10 @@ if(pulledby || shouldwakeup) toggle_ai(AI_ON) -/mob/living/simple_animal/onTransitZ(old_z, new_z) +/mob/living/simple_animal/on_changed_z_level(turf/old_turf, turf/new_turf) ..() if(AIStatus == AI_Z_OFF) - var/list/idle_mobs_on_old_z = LAZYACCESS(SSidlenpcpool.idle_mobs_by_zlevel, old_z) + var/list/idle_mobs_on_old_z = LAZYACCESS(SSidlenpcpool.idle_mobs_by_zlevel, old_turf.z) LAZYREMOVE(idle_mobs_on_old_z, src) toggle_ai(initial(AIStatus)) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 32e73d7d1a4d..4396fb68ffb8 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -1,4 +1,4 @@ -/mob/CanPass(atom/movable/mover, turf/target) +/mob/CanPass(atom/movable/mover, border_dir) var/horizontal = FALSE if(isliving(src)) var/mob/living/L = src diff --git a/code/modules/power/engines/singularity/containment_field.dm b/code/modules/power/engines/singularity/containment_field.dm index e1c80554979b..791f6a8561af 100644 --- a/code/modules/power/engines/singularity/containment_field.dm +++ b/code/modules/power/engines/singularity/containment_field.dm @@ -14,6 +14,10 @@ var/obj/machinery/field/generator/FG1 = null var/obj/machinery/field/generator/FG2 = null +/obj/machinery/field/containment/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/machinery/field/containment/Destroy() FG1.fields -= src FG2.fields -= src @@ -55,12 +59,12 @@ else ..() -/obj/machinery/field/containment/Crossed(mob/mover, oldloc) - if(isliving(mover)) - shock_field(mover) +/obj/machinery/field/containment/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isliving(crossed)) + shock_field(crossed) - if(ismachinery(mover) || isstructure(mover) || ismecha(mover)) - bump_field(mover) + if(ismachinery(crossed) || isstructure(crossed) || ismecha(crossed)) + bump_field(crossed) /obj/machinery/field/containment/proc/set_master(master1,master2) if(!master1 || !master2) @@ -84,7 +88,7 @@ /obj/machinery/field var/hasShocked = 0 //Used to add a delay between shocks. In some cases this used to crash servers by spawning hundreds of sparks every second. -/obj/machinery/field/CanPass(atom/movable/mover, turf/target) +/obj/machinery/field/CanPass(atom/movable/mover, border_dir) if(hasShocked) return 0 if(isliving(mover)) // Don't let mobs through diff --git a/code/modules/power/engines/singularity/particle_accelerator/particle.dm b/code/modules/power/engines/singularity/particle_accelerator/particle.dm index ee816a032d9f..3fdc67f6c2a1 100644 --- a/code/modules/power/engines/singularity/particle_accelerator/particle.dm +++ b/code/modules/power/engines/singularity/particle_accelerator/particle.dm @@ -24,8 +24,8 @@ /obj/effect/accelerated_particle/Initialize(loc) . = ..() addtimer(CALLBACK(src, PROC_REF(propagate)), 1) - RegisterSignal(src, COMSIG_CROSSED_MOVABLE, PROC_REF(try_irradiate)) - RegisterSignal(src, COMSIG_MOVABLE_CROSSED, PROC_REF(try_irradiate)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(try_irradiate)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS_OVER, PROC_REF(try_irradiate)) QDEL_IN(src, movement_range) /obj/effect/accelerated_particle/proc/try_irradiate(src, atom/A) diff --git a/code/modules/power/engines/singularity/singularity.dm b/code/modules/power/engines/singularity/singularity.dm index 43d6337f619f..b1f3eb04804b 100644 --- a/code/modules/power/engines/singularity/singularity.dm +++ b/code/modules/power/engines/singularity/singularity.dm @@ -521,15 +521,18 @@ var/angle_to_singulo var/distance_to_singulo +/obj/effect/abstract/proximity_checker/singulo/Initialize(mapload, datum/component/proximity_monitor/P) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/effect/abstract/proximity_checker/singulo/proc/calibrate() angle_to_singulo = ATAN2(monitor.hasprox_receiver.y - y, monitor.hasprox_receiver.x - x) distance_to_singulo = get_dist(monitor.hasprox_receiver, src) -/obj/effect/abstract/proximity_checker/singulo/Crossed(atom/movable/AM, oldloc) - . = ..() - if(!isprojectile(AM)) +/obj/effect/abstract/proximity_checker/singulo/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(!isprojectile(crossed)) return - var/obj/item/projectile/P = AM + var/obj/item/projectile/P = crossed var/distance = distance_to_singulo var/projectile_angle = P.Angle var/angle_to_projectile = angle_to_singulo diff --git a/code/modules/power/engines/supermatter/supermatter.dm b/code/modules/power/engines/supermatter/supermatter.dm index a0d51116cd9a..366d445c8bed 100644 --- a/code/modules/power/engines/supermatter/supermatter.dm +++ b/code/modules/power/engines/supermatter/supermatter.dm @@ -845,7 +845,7 @@ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE) Consume(AM) -/obj/machinery/atmospherics/supermatter_crystal/Bump(atom/A, yes) +/obj/machinery/atmospherics/supermatter_crystal/Bump(atom/A) ..() if(!istype(A, /obj/machinery/atmospherics/supermatter_crystal)) Bumped(A) diff --git a/code/modules/power/engines/tesla/energy_ball.dm b/code/modules/power/engines/tesla/energy_ball.dm index 7e526501faf6..3eccc653fc54 100644 --- a/code/modules/power/engines/tesla/energy_ball.dm +++ b/code/modules/power/engines/tesla/energy_ball.dm @@ -47,6 +47,7 @@ RegisterSignal(src, COMSIG_ATOM_ORBIT_BEGIN, PROC_REF(on_start_orbit)) RegisterSignal(src, COMSIG_ATOM_ORBIT_STOP, PROC_REF(on_stop_orbit)) RegisterSignal(parent_energy_ball, COMSIG_PARENT_QDELETING, PROC_REF(on_parent_delete)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) . = ..() if(!is_miniball) set_light(10, 7, "#5e5edd") @@ -135,6 +136,11 @@ sleep(0.5 SECONDS) walk_towards(src, move_target, 0, 10) +/obj/singularity/energy_ball/proc/on_movable_cross(datum/source, atom/movable/crossed) + var/mob/living/living_crossed = crossed + if(istype(living_crossed)) + living_crossed.dust() + /datum/move_with_corner var/turf/start var/turf/end @@ -210,13 +216,6 @@ forceMove(target, direction) return TRUE -// This handles mobs crossing us. For us crossing mobs, see /mob/living/Crossed. -// (It also dusts them.) -/obj/singularity/energy_ball/Crossed(atom/thing) - if(isliving(thing)) - var/mob/victim = thing - victim.dust() - /obj/singularity/energy_ball/proc/handle_energy() if(energy >= energy_to_raise) energy_to_lower = energy_to_raise - 20 diff --git a/code/modules/power/generators/treadmill.dm b/code/modules/power/generators/treadmill.dm index efaf83b4af24..ec6d6b1c6183 100644 --- a/code/modules/power/generators/treadmill.dm +++ b/code/modules/power/generators/treadmill.dm @@ -20,22 +20,24 @@ . = ..() if(anchored) connect_to_network() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + RegisterSignal(src, COMSIG_MOVABLE_UNCROSS, PROC_REF(on_movable_uncross)) /obj/machinery/power/treadmill/update_icon_state() icon_state = speed ? "conveyor-1" : "conveyor0" -/obj/machinery/power/treadmill/Crossed(mob/living/M, oldloc) - if(anchored && !M.anchored) - if(!istype(M) || M.dir != dir) - throw_off(M) +/obj/machinery/power/treadmill/proc/on_movable_cross(datum/source, atom/movable/crossed) + var/mob/living/living_crossed = crossed + if(anchored && !living_crossed.anchored) + if(!istype(living_crossed) || living_crossed.dir != dir) + throw_off(living_crossed) else - mobs_running[M] = M.last_movement - . = ..() + mobs_running[living_crossed] = living_crossed.last_movement -/obj/machinery/power/treadmill/Uncrossed(mob/living/M) - if(anchored && istype(M)) - mobs_running -= M - . = ..() +/obj/machinery/power/treadmill/proc/on_movable_uncross(atom/movable/crossed) + var/mob/living/living_crossed = crossed + if(anchored && istype(living_crossed)) + mobs_running -= living_crossed /obj/machinery/power/treadmill/proc/throw_off(atom/movable/A) // if 2fast, throw the person, otherwise they just slide off, if there's reasonable speed at all diff --git a/code/modules/power/lights.dm b/code/modules/power/lights.dm index 04de3076a22a..3b5bd5f522d5 100644 --- a/code/modules/power/lights.dm +++ b/code/modules/power/lights.dm @@ -854,15 +854,16 @@ /obj/item/light/Initialize(mapload) . = ..() AddComponent(/datum/component/caltrop, force) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) -/obj/item/light/Crossed(mob/living/L) - if(istype(L) && has_gravity(loc)) - if(L.incorporeal_move || L.flying || L.floating) +/obj/item/light/proc/on_movable_cross(datum/source, atom/movable/crossed) + var/mob/living/living_crossed = crossed + if(istype(living_crossed) && has_gravity(loc)) + if(living_crossed.incorporeal_move || living_crossed.flying || living_crossed.floating) return playsound(loc, 'sound/effects/glass_step.ogg', 50, TRUE) if(status == LIGHT_BURNED || status == LIGHT_OK) shatter() - return ..() /obj/item/light/decompile_act(obj/item/matter_decompiler/C, mob/user) C.stored_comms["glass"] += 1 diff --git a/code/modules/projectiles/projectile/special_projectiles.dm b/code/modules/projectiles/projectile/special_projectiles.dm index 8fdda383023e..1fb6cdd8f81f 100644 --- a/code/modules/projectiles/projectile/special_projectiles.dm +++ b/code/modules/projectiles/projectile/special_projectiles.dm @@ -111,9 +111,7 @@ nodamage = 1 flag = "bullet" -/obj/item/projectile/meteor/Bump(atom/A, yes) - if(yes) - return +/obj/item/projectile/meteor/Bump(atom/A) if(A == firer) loc = A.loc return diff --git a/code/modules/projectiles/projectile_base.dm b/code/modules/projectiles/projectile_base.dm index f10e7ea0a22a..b1b6aaa26589 100644 --- a/code/modules/projectiles/projectile_base.dm +++ b/code/modules/projectiles/projectile_base.dm @@ -135,6 +135,10 @@ /obj/item/projectile/New() return ..() +/obj/item/projectile/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/item/projectile/proc/Range() range-- if(damage && tile_dropoff) @@ -259,10 +263,7 @@ beam_index = point_cache beam_segments[beam_index] = null -/obj/item/projectile/Bump(atom/A, yes) - if(!yes) //prevents double bumps. - return - +/obj/item/projectile/Bump(atom/A) if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max && is_reflectable(REFLECTABILITY_PHYSICAL)) if(hitscan && ricochets_max > 10) ricochets_max = 10 //I do not want a chucklefuck editing this higher, sorry. @@ -429,10 +430,10 @@ xo = new_x - curloc.x set_angle(get_angle(curloc, original)) -/obj/item/projectile/Crossed(atom/movable/AM, oldloc) //A mob moving on a tile with a projectile is hit by it. - ..() - if(isliving(AM) && AM.density && !checkpass(PASSMOB)) - Bump(AM, 1) +/// A mob moving on a tile with a projectile is hit by it. +/obj/item/projectile/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(isliving(crossed) && crossed.density && !checkpass(PASSMOB)) + Bump(crossed, 1) /obj/item/projectile/Destroy() if(hitscan) diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm index 79a8f45d539c..d53eec73bfba 100644 --- a/code/modules/reagents/reagent_containers/glass_containers.dm +++ b/code/modules/reagents/reagent_containers/glass_containers.dm @@ -131,6 +131,13 @@ var/obj/item/assembly_holder/assembly = null var/can_assembly = 1 +/obj/item/reagent_containers/glass/beaker/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/reagent_containers/glass/beaker/examine(mob/user) . = ..() if(assembly) @@ -191,9 +198,9 @@ if(assembly) assembly.HasProximity(AM) -/obj/item/reagent_containers/glass/beaker/Crossed(atom/movable/AM, oldloc) +/obj/item/reagent_containers/glass/beaker/proc/on_atom_entered(datum/source, atom/movable/entered) if(assembly) - assembly.Crossed(AM, oldloc) + assembly.on_atom_entered(source, entered) /obj/item/reagent_containers/glass/beaker/on_found(mob/finder) //for mousetraps if(assembly) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index ff2a5af0b700..dd368866f230 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -22,6 +22,11 @@ mode = SYRINGE_INJECT update_icon() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/item/reagent_containers/syringe/on_reagent_change() update_icon() @@ -181,7 +186,10 @@ M.update_inv_l_hand() M.update_inv_r_hand() -/obj/item/reagent_containers/syringe/Crossed(mob/living/carbon/human/H, oldloc) +/obj/item/reagent_containers/syringe/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + + var/mob/living/carbon/human/H = entered if(!istype(H) || !H.reagents || HAS_TRAIT(H, TRAIT_PIERCEIMMUNE) || ismachineperson(H)) return diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 48875c4435a9..b343f02cdeaa 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -104,6 +104,13 @@ var/obj/item/assembly_holder/rig = null var/accepts_rig = 1 +/obj/structure/reagent_dispensers/fueltank/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/structure/reagent_dispensers/fueltank/Destroy() QDEL_NULL(rig) return ..() @@ -209,9 +216,9 @@ if(rig) rig.HasProximity(AM) -/obj/structure/reagent_dispensers/fueltank/Crossed(atom/movable/AM, oldloc) +/obj/structure/reagent_dispensers/fueltank/proc/on_atom_entered(datum/source, atom/movable/entered) if(rig) - rig.Crossed(AM, oldloc) + rig.on_atom_entered(source, entered) /obj/structure/reagent_dispensers/fueltank/hear_talk(mob/living/M, list/message_pieces) if(rig) diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index 3f3b9fba58f8..83f5688046de 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -43,6 +43,8 @@ GLOBAL_LIST_EMPTY(conveyor_switches) var/obj/machinery/conveyor_switch/S = I S.link_conveyers(src) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + /obj/machinery/conveyor/Destroy() GLOB.conveyor_belts -= src return ..() @@ -199,10 +201,9 @@ GLOBAL_LIST_EMPTY(conveyor_switches) else if(still_stuff_to_move && !speed_process) makeSpeedProcess() -/obj/machinery/conveyor/Crossed(atom/movable/AM, oldloc) - if(!speed_process && !AM.anchored) +/obj/machinery/conveyor/proc/on_movable_cross(datum/source, atom/movable/crossed) + if(!speed_process && !crossed.anchored) makeSpeedProcess() - ..() /obj/machinery/conveyor/proc/move_thing(atom/movable/AM) affecting.Remove(AM) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 1448089796be..c61e762da24c 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -613,7 +613,7 @@ H.vent_gas(loc) qdel(H) -/obj/machinery/disposal/CanPass(atom/movable/mover, turf/target) +/obj/machinery/disposal/CanPass(atom/movable/mover, border_dir) if(isitem(mover) && mover.throwing) var/obj/item/I = mover if(isprojectile(I)) diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 9351978962e9..477925f7d8a3 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -294,7 +294,7 @@ /obj/machinery/disposal/deliveryChute/update() return -/obj/machinery/disposal/deliveryChute/CanPass(atom/movable/mover, turf/target) +/obj/machinery/disposal/deliveryChute/CanPass(atom/movable/mover, border_dir) // If the mover is a thrownthing passing through space, remove its thrown datum, // ingest it like normal, and mark the chute as not passible. // This prevents the mover from Entering the chute's turf diff --git a/code/modules/ruins/lavalandruin_code/sin_ruins.dm b/code/modules/ruins/lavalandruin_code/sin_ruins.dm index 13033d10fe01..a9ca09b40173 100644 --- a/code/modules/ruins/lavalandruin_code/sin_ruins.dm +++ b/code/modules/ruins/lavalandruin_code/sin_ruins.dm @@ -140,7 +140,7 @@ icon = 'icons/mob/blob.dmi' color = rgb(145, 150, 0) -/obj/effect/gluttony/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff. +/obj/effect/gluttony/CanPass(atom/movable/mover, border_dir)//So bullets will fly over and stuff. if(ishuman(mover)) var/mob/living/carbon/human/H = mover if(H.nutrition >= NUTRITION_LEVEL_FAT || HAS_TRAIT(H, TRAIT_FAT)) diff --git a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm index 8f8f483db0c5..27db96f1cb80 100644 --- a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm +++ b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm @@ -48,6 +48,12 @@ dais_overlay.layer = CLOSED_TURF_LAYER add_overlay(dais_overlay) + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + + AddElement(/datum/element/connect_loc, loc_connections) + /obj/structure/necropolis_gate/Destroy() qdel(sight_blocker, TRUE) return ..() @@ -55,15 +61,16 @@ /obj/structure/necropolis_gate/singularity_pull() return -/obj/structure/necropolis_gate/CanPass(atom/movable/mover, turf/target) - if(get_dir(loc, target) == dir) +/obj/structure/necropolis_gate/CanPass(atom/movable/mover, border_dir) + if(border_dir == dir) return !density return TRUE -/obj/structure/necropolis_gate/CheckExit(atom/movable/O, target) - if(get_dir(O.loc, target) == dir) - return !density - return TRUE +/obj/structure/necropolis_gate/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + SIGNAL_HANDLER // COMSIG_ATOM_EXIT + + if(direction == dir && density) + return COMPONENT_ATOM_BLOCK_EXIT /obj/structure/opacity_blocker icon = 'icons/effects/96x96.dmi' diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index e174827f4efe..9fea2a3a4a1d 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -2,7 +2,7 @@ /atom/movable/proc/onShuttleMove(turf/oldT, turf/T1, rotation, mob/caller) var/turf/newT = get_turf(src) if(newT.z != oldT.z) - onTransitZ(oldT.z, newT.z) + on_changed_z_level(oldT, newT) if(light) update_light() if(rotation) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 4111e112cf9b..87b05255ec5f 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -262,7 +262,14 @@ var/obj/item/organ/external/affected = owner.get_organ(parent_organ) if(affected) affected.internal_organs -= src - forceMove(get_turf(owner)) + // In-game, organs will be moved to their parent turf. + // During ghost-mob creation, we toss the organs + // after we're done generating the sprite with them, + // so to nullspace they go. + if(get_turf(owner)) + forceMove(get_turf(owner)) + else + moveToNullspace() START_PROCESSING(SSobj, src) if(owner && vital && is_primary_organ()) // I'd do another check for species or whatever so that you couldn't "kill" an IPC by removing a human head from them, but it doesn't matter since they'll come right back from the dead diff --git a/code/modules/vehicle/vehicle.dm b/code/modules/vehicle/vehicle.dm index 3a79e296f896..deb9158d2354 100644 --- a/code/modules/vehicle/vehicle.dm +++ b/code/modules/vehicle/vehicle.dm @@ -34,7 +34,7 @@ return ..() // So that beepsky can't push the janicart -/obj/vehicle/CanPass(atom/movable/mover, turf/target) +/obj/vehicle/CanPass(atom/movable/mover, border_dir) if(istype(mover) && mover.checkpass(PASSMOB)) return TRUE else diff --git a/paradise.dme b/paradise.dme index 8aa6a39ae1dc..2edb0d625a6f 100644 --- a/paradise.dme +++ b/paradise.dme @@ -93,6 +93,7 @@ #include "code\__DEFINES\mob_defines.dm" #include "code\__DEFINES\mod.dm" #include "code\__DEFINES\move_force.dm" +#include "code\__DEFINES\movement_info.dm" #include "code\__DEFINES\muzzle_flash.dm" #include "code\__DEFINES\newscaster_defines.dm" #include "code\__DEFINES\particle_defines.dm" @@ -423,6 +424,7 @@ #include "code\datums\components\boss_music.dm" #include "code\datums\components\caltrop.dm" #include "code\datums\components\codeword_hearing.dm" +#include "code\datums\components\connect_loc_behalf.dm" #include "code\datums\components\connect_mob_behalf.dm" #include "code\datums\components\corpse_description.dm" #include "code\datums\components\cult_held_body.dm" @@ -523,6 +525,7 @@ #include "code\datums\elements\atmos_requirements.dm" #include "code\datums\elements\body_temperature.dm" #include "code\datums\elements\bombable_turf.dm" +#include "code\datums\elements\connect_loc.dm" #include "code\datums\elements\earhealing.dm" #include "code\datums\elements\rad_insulation.dm" #include "code\datums\elements\ridable.dm" From 1abac61105900cb817a52652fd43debb6d2f41fd Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Thu, 12 Sep 2024 13:58:28 -0400 Subject: [PATCH 02/19] wrong var name --- .../objects/items/weapons/chemical_flamethrower/fire_effect.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm b/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm index 34677d843093..1cdf4e1630b1 100644 --- a/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm +++ b/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm @@ -88,7 +88,7 @@ GLOBAL_LIST_EMPTY(flame_effects) to_chat(entered, "[src] burns you!") return - if(isitem(AM)) + if(isitem(entered)) var/obj/item/item_to_burn = entered item_to_burn.fire_act(null, temperature) From fa793a7c19cacac63538b9afddceac84657e61aa Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Thu, 12 Sep 2024 14:11:39 -0400 Subject: [PATCH 03/19] fix unit tests dropping PDAs into nowhere --- code/modules/mob/inventory_procs.dm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/inventory_procs.dm b/code/modules/mob/inventory_procs.dm index f38dabacd7e4..4104c3df6a5e 100644 --- a/code/modules/mob/inventory_procs.dm +++ b/code/modules/mob/inventory_procs.dm @@ -186,7 +186,11 @@ if(I) if(client) client.screen -= I - I.forceMove(drop_location()) + var/turf/drop_loc = drop_location() + if(drop_loc) + I.forceMove(drop_loc) + else + I.moveToNullspace() I.dropped(src, silent) if(I) I.layer = initial(I.layer) From 3c5b76173034ea189c1fe8e2436c12cd93c9af85 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sat, 14 Sep 2024 18:42:07 -0400 Subject: [PATCH 04/19] Add documentation. --- code/game/atoms_movable.dm | 7 +- docs/references/movement_signals.md | 134 ++++++++++++++++++++++++++++ mkdocs.yml | 1 + 3 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 docs/references/movement_signals.md diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 283b6ba67978..643a72e19c74 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -215,10 +215,9 @@ loc = new_loc Moved(old_loc, direction, TRUE) -//////////////////////////////////////// -// Here's where we rewrite how byond handles movement except slightly different -// To be removed on step_ conversion -// All this work to prevent a second bump +/// Here's where we rewrite how byond handles movement except slightly different. +/// To be removed on step_ conversion. +/// All this work to prevent a second bump. /atom/movable/Move(atom/newloc, direction, glide_size_override = 0, update_dir = TRUE) . = FALSE if(!newloc || newloc == loc) diff --git a/docs/references/movement_signals.md b/docs/references/movement_signals.md new file mode 100644 index 000000000000..92c089b68ede --- /dev/null +++ b/docs/references/movement_signals.md @@ -0,0 +1,134 @@ +# Movement Signals + +## Background + +Traditionally, BYOND games rely on several native procs to respond to certain +kinds of in-game movement: + +- If one atom attempts to overlap another one, [`/atom/proc/Cross`][cross] is called, + allowing the overlapped atom to either return `TRUE` to allow the cross, or + `FALSE` to prevent it. When `Move()` is called and an atom overlaps another + one, [`/atom/proc/Crossed`][crossed] is called, allowing the overlapped atom to react + to the cross. +- Similarly, when an atom attempts to stop overlapping another, + [`/atom/proc/Uncross`][uncross] is called to permit or deny it, then + [`/atom/proc/Uncrossed`][uncrossed] is called to allow the atom to react to it. +- When a movable attempts to enter a turf, [`/turf/proc/Enter`][enter] is called, + allowing the turf to return `TRUE` to permit the entry, or `FALSE` to deny it. + When a movable succeeds in entering a turf, [`/turf/proc/Entered`][entered] is + called, allowing the turf to react to the entry. +- Similarly, when an atom attempts to exit a turf, [`/turf/proc/Exit`][exit] is + called to permit or deny it, then [`/turf/proc/Exited`][exited] is called to allow + the turf to react to the exit. +- When an atom attempts to enter the contents of another one, + [`/atom/proc/Enter`][atom_enter] is called, allowing the containing atom to + either return `TRUE` to allow the entry, or `FALSE` to prevent it. When an + atom successfully enters the contents of another one, + [`/atom/proc/Entered`][atom_entered] is called. +- Similarly, when an atom attempts to exit another atom's contents, + [`/atom/proc/Exit`][atom_exit] is called to permit or deny it, then + [`/atom/proc/Exited`][atom_exited] is called to allow the turf to react to the + exit. + +As one can imagine, with a lot of objects moving around in the game world, +calling all of these procs can be expensive, especially if we don't care about +what happens most of the time. + +In order to avoid making all of these calls, and provide more fine-grained +control over what happens on atom/turf interactions, we implement our own +version of the native `/atom/movable/Move`, and use signal handlers and +components to process the interactions we care about. + +[cross]: https://secure.byond.com/docs/ref/#/atom/proc/Cross +[crossed]: https://secure.byond.com/docs/ref/#/atom/proc/Crossed +[uncross]: https://secure.byond.com/docs/ref/#/atom/proc/Uncross +[uncrossed]: https://secure.byond.com/docs/ref/#/atom/proc/Uncrossed +[enter]: https://secure.byond.com/docs/ref/#/turf/proc/Enter +[entered]: https://secure.byond.com/docs/ref/#/turf/proc/Entered +[exit]: https://secure.byond.com/docs/ref/#/turf/proc/Exit +[exited]: https://secure.byond.com/docs/ref/#/turf/proc/Exited +[atom_enter]: https://secure.byond.com/docs/ref/#/atom/proc/Enter +[atom_entered]: https://secure.byond.com/docs/ref/#/atom/proc/Entered +[atom_exit]: https://secure.byond.com/docs/ref/#/atom/proc/Exit +[atom_exited]: https://secure.byond.com/docs/ref/#/atom/proc/Exited + +## Signal Handlers + +There are several signal handlers used to replicate the native BYOND atom crossover/entry behavior: + +- [`COMSIG_MOVABLE_PRE_MOVE`][pre_move] is sent when trying to determine if an + atom can enter a new turf. Any subscribed handler can return + `COMPONENT_MOVABLE_BLOCK_PRE_MOVE` to prevent the move. +- [`COMSIG_MOVABLE_MOVED`][moved] is sent after a successful move. +- [`COMSIG_MOVABLE_CROSS`][cross] is sent when trying to determine if an atom + can cross over another one. Any subscribed handler can return + `COMPONENT_BLOCK_CROSS` to prevent the cross. +- Similarly, [`COMSIG_MOVABLE_CROSS_OVER`][crossover] is sent if an atom will + allow another one to cross over it--the reverse of `COMSIG_MOVABLE_CROSS`. + Again, any subscribed handler can return `COMPONENT_BLOCK_CROSS` to prevent + it. +- [`COMSIG_ATOM_ENTERED`][entered] is sent if an atom enters this atom's + contents. Similarly, [`COMSIG_ATOM_EXITED`][exited] is sent if an atom exits + this atom's contents. + +[pre_move]: https://codedocs.paradisestation.org/code/__DEFINES/dcs/movable_signals.html#define/COMSIG_MOVABLE_PRE_MOVE +[moved]: https://codedocs.paradisestation.org/code/__DEFINES/dcs/movable_signals.html#define/COMSIG_MOVABLE_MOVED +[cross]: https://codedocs.paradisestation.org/code/__DEFINES/dcs/movable_signals.html#define/COMSIG_MOVABLE_CROSS +[crossover]: https://codedocs.paradisestation.org/code/__DEFINES/dcs/movable_signals.html#define/COMSIG_MOVABLE_CROSS_OVER +[entered]: https://codedocs.paradisestation.org/code/__DEFINES/dcs/movable_signals.html#define/COMSIG_ATOM_ENTERED +[exited]: https://codedocs.paradisestation.org/code/__DEFINES/dcs/movable_signals.html#define/COMSIG_ATOM_EXITED + +## The `connect_loc` Element + +The above signals are not appropriate for all cases. For example, it may seem +like beartraps should listen to `COMSIG_MOVABLE_MOVED` to see if they should +activate. However, this will fire every time a movement crossing occurs, even if +it wouldn't normally trigger the trap, such as if the trap is being thrown and +intersects abstract lighting objects. Instead, we use `COMSIG_ATOM_ENTERED` with +the `connect_loc` element. As a refresher, `COMSIG_ATOM_ENTERED` fires when an +atom enters the contents of another. By using the `connect_loc` element, we can +have the beartrap listen for signals on the turf it's located on. Then, if the +turf has a `COMSIG_ATOM_ENTERED` signal fire, we can have the beartrap respond. + +Before: + +```dm +/obj/item/restraints/legcuffs/beartrap/proc/Crossed(mob/living/crossed) + if(istype(crossed)) + spring_trap() +``` + +After: + +```dm +/obj/item/restraints/legcuffs/beartrap/Initialize(mapload) + . = ..() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + +/obj/item/restraints/legcuffs/beartrap/proc/on_atom_entered(datum/source, mob/living/entered) + if(istype(entered)) + spring_trap() +``` + +Note that the list of connections is `static` so that a new element instance isn't +created for every new beartrap. + +## Summary + +If you care about every time a movable attempts to overlap you, listen to +`COMSIG_MOVABLE_PRE_MOVE`, and return `COMPONENT_MOVABLE_BLOCK_PRE_MOVE` to +prevent it from happening. + +If you care about every time a movable overlaps you, listen to +`COMSIG_MOVABLE_CROSS`. If you care about every time a movable is overlapped by +you, listen to `COMSIG_MOVABLE_CROSS_OVER`. + +If you care about an atom entering or exiting your contents, listen to +`COMSIG_ATOM_ENTERED` or `COMSIG_ATOM_EXITED`. + +If you care about an atom entering or exiting your location, or any other signal +firing on your location, create a `static` list of signals mapped to procs and +add a `/datum/element/connect_loc` to yourself. diff --git a/mkdocs.yml b/mkdocs.yml index 6545bbd06e0d..77897a9a8a2d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -92,3 +92,4 @@ nav: - 'Autodoc Guide': './references/autodoc.md' - 'Using Feedback Data': './references/feedback_data.md' - 'Tick Order': './references/tick_order.md' + - 'Movement Signals': './references/movement_signals.md' From cefddd1dfe496c489b69961a047b0dfcbbc687f1 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sat, 14 Sep 2024 19:08:26 -0400 Subject: [PATCH 05/19] remove unused constants --- code/__DEFINES/movement_info.dm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/code/__DEFINES/movement_info.dm b/code/__DEFINES/movement_info.dm index 91d370f6c75f..95c90f7a1fba 100644 --- a/code/__DEFINES/movement_info.dm +++ b/code/__DEFINES/movement_info.dm @@ -1,8 +1,3 @@ -#define ACTIVE_MOVEMENT_OLDLOC 1 -#define ACTIVE_MOVEMENT_DIRECTION 2 -#define ACTIVE_MOVEMENT_FORCED 3 -#define ACTIVE_MOVEMENT_OLDLOCS 4 - /// The arguments of this macro correspond directly to the argument order of /atom/movable/proc/Moved #define SET_ACTIVE_MOVEMENT(_old_loc, _direction, _forced, _oldlocs) \ active_movement = list( \ From 9c2ea396facdd1518c8d4885b806ca50531c37d8 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sat, 14 Sep 2024 19:12:04 -0400 Subject: [PATCH 06/19] say which procs are off limits --- docs/references/movement_signals.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/references/movement_signals.md b/docs/references/movement_signals.md index 92c089b68ede..e0c56d755c32 100644 --- a/docs/references/movement_signals.md +++ b/docs/references/movement_signals.md @@ -54,7 +54,8 @@ components to process the interactions we care about. ## Signal Handlers -There are several signal handlers used to replicate the native BYOND atom crossover/entry behavior: +There are several signal handlers used to replicate the native BYOND atom +crossover/entry behavior: - [`COMSIG_MOVABLE_PRE_MOVE`][pre_move] is sent when trying to determine if an atom can enter a new turf. Any subscribed handler can return @@ -118,6 +119,10 @@ created for every new beartrap. ## Summary +The procs `/atom/movable/Cross`, `/atom/movable/Crossed`, +`/atom/movable/Uncross`, and `/atom/movable/Uncrossed`, should not be used for +new code. + If you care about every time a movable attempts to overlap you, listen to `COMSIG_MOVABLE_PRE_MOVE`, and return `COMPONENT_MOVABLE_BLOCK_PRE_MOVE` to prevent it from happening. From d8a5fe48b4edaf0a3577e2d0c35e291f4ce51fbc Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sat, 14 Sep 2024 19:38:49 -0400 Subject: [PATCH 07/19] fix simpleanimal z change runtime --- code/modules/mob/living/simple_animal/simple_animal.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 71898767cc78..9d1b178dab16 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -583,7 +583,7 @@ /mob/living/simple_animal/on_changed_z_level(turf/old_turf, turf/new_turf) ..() - if(AIStatus == AI_Z_OFF) + if(AIStatus == AI_Z_OFF && old_turf) var/list/idle_mobs_on_old_z = LAZYACCESS(SSidlenpcpool.idle_mobs_by_zlevel, old_turf.z) LAZYREMOVE(idle_mobs_on_old_z, src) toggle_ai(initial(AIStatus)) From d4b4cf45541ab428f70ccd137b40a044cf2d3d8f Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Wed, 18 Sep 2024 16:55:54 -0400 Subject: [PATCH 08/19] helps not to leave merge conflicts --- code/game/turfs/simulated/floor/asteroid_floors.dm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code/game/turfs/simulated/floor/asteroid_floors.dm b/code/game/turfs/simulated/floor/asteroid_floors.dm index 149e0e840ba8..8b68c39a8972 100644 --- a/code/game/turfs/simulated/floor/asteroid_floors.dm +++ b/code/game/turfs/simulated/floor/asteroid_floors.dm @@ -91,11 +91,7 @@ return TRUE else if(istype(I, /obj/item/storage/bag/ore)) -<<<<<<< HEAD attempt_ore_pickup(I, user, params) -======= - attempt_ore_pickup(I, user) ->>>>>>> origin/master else if(istype(I, /obj/item/stack/tile)) var/obj/item/stack/tile/Z = I From 0160c86b536077f251fa3433b2001275690a7b2f Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Wed, 18 Sep 2024 16:59:03 -0400 Subject: [PATCH 09/19] kill me --- code/modules/mining/ores_coins.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 75644059cb29..12c089e46749 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -59,7 +59,7 @@ break if(OB && istype(F, /turf/simulated/floor/plating/asteroid)) var/turf/simulated/floor/plating/asteroid/FA = F - FA.attempt_ore_pickup(OB, AM) + FA.attempt_ore_pickup(OB, entered) // Then, if the user is dragging an ore box, empty the satchel // into the box. var/mob/living/L = entered From a1c3576c76d65b84a24d4398a09eb26e83125b75 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Thu, 19 Sep 2024 17:31:30 -0400 Subject: [PATCH 10/19] fix typecast --- code/datums/components/squeak.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index 55289650a99a..98fd19dfdd38 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -78,7 +78,7 @@ else steps++ -/datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/enterer, old_loc) +/datum/component/squeak/proc/play_squeak_crossed(atom/source, atom/movable/enterer, old_loc) if(!isturf(enterer.loc) || !isturf(source.loc)) return if(istype(enterer, /obj/effect)) From 4c7de178c8a7a79ca8301457fb015f8d3d87dd1a Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Fri, 27 Sep 2024 17:13:01 -0400 Subject: [PATCH 11/19] fix projectile/table collision --- code/game/objects/structures/tables_racks.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 21efcdb211c0..ca38f37e9c83 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -106,7 +106,7 @@ clear_smooth_overlays() // Need to override this to allow flipped tables to be mapped in without the smoothing subsystem resetting the icon_state -/obj/structure/table/set_smoothed_icon_state(new_junction) +/obj/structure/table/set_smoothed_icon_state(new_junction) if(flipped) return ..() @@ -182,8 +182,7 @@ return if(get_dist(P.starting, loc) <= 1) // Tables won't help you if people are THIS close return - var/block_dir = get_dir(get_step(loc, dir), loc) - if(proj_dir != block_dir) // Back/side shots may pass + if(proj_dir != dir) // Back/side shots may pass return if(prob(40)) return FALSE // Blocked From f02b3266f8ab74f9c73282dab0e9d260f9827d3e Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Fri, 27 Sep 2024 22:07:35 -0400 Subject: [PATCH 12/19] treadmills don't cause MC to crash anymore --- code/modules/power/generators/treadmill.dm | 40 +++++++++++++--------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/code/modules/power/generators/treadmill.dm b/code/modules/power/generators/treadmill.dm index ec6d6b1c6183..4aa29c380798 100644 --- a/code/modules/power/generators/treadmill.dm +++ b/code/modules/power/generators/treadmill.dm @@ -18,26 +18,33 @@ /obj/machinery/power/treadmill/Initialize(mapload) . = ..() + on_anchor_changed() + +/obj/machinery/power/treadmill/proc/on_anchor_changed() if(anchored) connect_to_network() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) - RegisterSignal(src, COMSIG_MOVABLE_UNCROSS, PROC_REF(on_movable_uncross)) + RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + RegisterSignal(src, COMSIG_MOVABLE_UNCROSS, PROC_REF(on_movable_uncross)) + else + disconnect_from_network() + UnregisterSignal(src, COMSIG_MOVABLE_CROSS) + UnregisterSignal(src, COMSIG_MOVABLE_UNCROSS) /obj/machinery/power/treadmill/update_icon_state() icon_state = speed ? "conveyor-1" : "conveyor0" -/obj/machinery/power/treadmill/proc/on_movable_cross(datum/source, atom/movable/crossed) - var/mob/living/living_crossed = crossed - if(anchored && !living_crossed.anchored) - if(!istype(living_crossed) || living_crossed.dir != dir) - throw_off(living_crossed) - else - mobs_running[living_crossed] = living_crossed.last_movement +/obj/machinery/power/treadmill/proc/on_movable_cross(datum/source, mob/living/crossed) + if(crossed.anchored || crossed.throwing) + return -/obj/machinery/power/treadmill/proc/on_movable_uncross(atom/movable/crossed) - var/mob/living/living_crossed = crossed - if(anchored && istype(living_crossed)) - mobs_running -= living_crossed + if(!istype(crossed) || crossed.dir != dir) + return throw_off(crossed) + else + mobs_running[crossed] = crossed.last_movement + +/obj/machinery/power/treadmill/proc/on_movable_uncross(mob/living/crossed) + if(istype(crossed)) + mobs_running -= crossed /obj/machinery/power/treadmill/proc/throw_off(atom/movable/A) // if 2fast, throw the person, otherwise they just slide off, if there's reasonable speed at all @@ -45,6 +52,8 @@ var/dist = max(throw_dist * speed / MAX_SPEED, 1) A.throw_at(get_distant_turf(get_turf(src), REVERSE_DIR(dir), dist), A.throw_range, A.throw_speed, null, 1) + return TRUE + /obj/machinery/power/treadmill/process() if(!anchored) speed = 0 @@ -100,10 +109,7 @@ /obj/machinery/power/treadmill/attackby(obj/item/W, mob/user) if(default_unfasten_wrench(user, W, time = 60)) - if(anchored) - connect_to_network() - else - disconnect_from_network() + on_anchor_changed() speed = 0 update_icon() return From 9ec2b16253035d6a0da723655f140a72c48a0339 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sat, 28 Sep 2024 01:33:38 -0400 Subject: [PATCH 13/19] connect_loc is appropriate here --- code/modules/power/generators/treadmill.dm | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/code/modules/power/generators/treadmill.dm b/code/modules/power/generators/treadmill.dm index 4aa29c380798..b3dab8a826e6 100644 --- a/code/modules/power/generators/treadmill.dm +++ b/code/modules/power/generators/treadmill.dm @@ -16,6 +16,11 @@ var/list/mobs_running[0] var/id = null // for linking to monitor + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + COMSIG_ATOM_EXITED = PROC_REF(on_atom_exited), + ) + /obj/machinery/power/treadmill/Initialize(mapload) . = ..() on_anchor_changed() @@ -23,26 +28,24 @@ /obj/machinery/power/treadmill/proc/on_anchor_changed() if(anchored) connect_to_network() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) - RegisterSignal(src, COMSIG_MOVABLE_UNCROSS, PROC_REF(on_movable_uncross)) + AddElement(/datum/element/connect_loc, loc_connections) else disconnect_from_network() - UnregisterSignal(src, COMSIG_MOVABLE_CROSS) - UnregisterSignal(src, COMSIG_MOVABLE_UNCROSS) + RemoveElement(/datum/element/connect_loc) /obj/machinery/power/treadmill/update_icon_state() icon_state = speed ? "conveyor-1" : "conveyor0" -/obj/machinery/power/treadmill/proc/on_movable_cross(datum/source, mob/living/crossed) +/obj/machinery/power/treadmill/proc/on_atom_entered(datum/source, mob/living/crossed) if(crossed.anchored || crossed.throwing) return if(!istype(crossed) || crossed.dir != dir) - return throw_off(crossed) + throw_off(crossed) else mobs_running[crossed] = crossed.last_movement -/obj/machinery/power/treadmill/proc/on_movable_uncross(mob/living/crossed) +/obj/machinery/power/treadmill/proc/on_atom_exited(mob/living/crossed) if(istype(crossed)) mobs_running -= crossed @@ -52,8 +55,6 @@ var/dist = max(throw_dist * speed / MAX_SPEED, 1) A.throw_at(get_distant_turf(get_turf(src), REVERSE_DIR(dir), dist), A.throw_range, A.throw_speed, null, 1) - return TRUE - /obj/machinery/power/treadmill/process() if(!anchored) speed = 0 From 6f268fb0d4c2b41ea159eeda3ec36530293913e8 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Tue, 1 Oct 2024 04:54:09 -0400 Subject: [PATCH 14/19] fix windoors and teleporters --- code/game/machinery/doors/windowdoor.dm | 20 +++++++++++--------- code/game/machinery/teleporter.dm | 22 ++++++++++++++++------ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index dbf9ce4a0ecd..5173a671ea5b 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -32,6 +32,12 @@ if(req_access && length(req_access)) base_state = icon_state + var/static/list/loc_connections = list( + COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), + ) + + AddElement(/datum/element/connect_loc, loc_connections) + if(name != initial(name)) return var/new_name = get_area_name(src) @@ -40,12 +46,6 @@ return name = new_name - var/static/list/loc_connections = list( - COMSIG_ATOM_EXIT = PROC_REF(on_atom_exit), - ) - - AddElement(/datum/element/connect_loc, loc_connections) - /obj/machinery/door/window/Destroy() density = FALSE if(obj_integrity == 0) @@ -179,6 +179,8 @@ return !density || (dir != to_dir) || (check_access_list(pass_info.access) && hasPower()) /obj/machinery/door/window/proc/on_atom_exit(datum/source, atom/movable/leaving, direction) + SIGNAL_HANDLER // COMSIG_ATOM_EXIT + if(istype(leaving) && leaving.checkpass(PASSGLASS)) return @@ -188,6 +190,7 @@ return if(direction == dir && density) + leaving.Bump(src) return COMPONENT_ATOM_BLOCK_EXIT /obj/machinery/door/window/open(forced=0) @@ -205,16 +208,15 @@ set_opacity(FALSE) playsound(loc, 'sound/machines/windowdoor.ogg', 100, 1) icon_state ="[base_state]open" - sleep(10) + addtimer(CALLBACK(src, PROC_REF(finish_open)), 8) +/obj/machinery/door/window/proc/finish_open() density = FALSE -// sd_set_opacity(0) //TODO: why is this here? Opaque windoors? ~Carn recalculate_atmos_connectivity() update_freelook_sight() if(operating) //emag again operating = NONE - return 1 /obj/machinery/door/window/close(forced=0) if(operating) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 8163b20ccf58..6b3df020fbda 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -372,7 +372,12 @@ component_parts += new /obj/item/stack/ore/bluespace_crystal/artificial(null, 3) component_parts += new /obj/item/stock_parts/matter_bin(null) RefreshParts() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_entered)) + + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + /obj/machinery/teleport/hub/upgraded/Initialize(mapload) . = ..() @@ -389,7 +394,6 @@ if(power_station) power_station.teleporter_hub = null power_station = null - UnregisterSignal(COMSIG_MOVABLE_CROSS) return ..() /obj/machinery/teleport/hub/RefreshParts() @@ -410,7 +414,9 @@ break return power_station -/obj/machinery/teleport/hub/proc/on_entered(atom/source, atom/movable/entered, turf/old_loc) +/obj/machinery/teleport/hub/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + if(!is_teleport_allowed(z) && !admin_usage) if(ismob(entered)) to_chat(entered, "You can't use this here.") @@ -491,9 +497,14 @@ /obj/machinery/teleport/perma/Initialize(mapload) . = ..() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_entered)) update_lighting() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + + /obj/machinery/teleport/perma/process() teleports_this_cycle = 0 @@ -506,7 +517,7 @@ tele_delay = max(A, 0) update_icon(UPDATE_ICON_STATE) -/obj/machinery/teleport/perma/proc/on_entered(atom/source, atom/movable/entered, turf/old_loc) +/obj/machinery/teleport/perma/proc/on_atom_entered(datum/source, atom/movable/entered) if(stat & (BROKEN|NOPOWER)) return if(!is_teleport_allowed(z)) @@ -525,7 +536,6 @@ /obj/machinery/teleport/perma/Destroy() . = ..() - UnregisterSignal(COMSIG_MOVABLE_CROSS) /obj/machinery/teleport/perma/proc/CrossedCallback() recalibrating = FALSE From 04f7ff9c81ec77bb13f7381f169352cce5ff6cc9 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Tue, 1 Oct 2024 05:37:26 -0400 Subject: [PATCH 15/19] fix bonfires and clarify docs --- code/game/objects/effects/mines.dm | 13 +++++++++---- .../atmospherics/environmental/LINDA_fire.dm | 14 +++++++++----- code/modules/hydroponics/grown/towercap.dm | 13 +++++++++---- docs/references/movement_signals.md | 7 ++++--- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 96b04e20f5db..873bf2ae2c7c 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -9,15 +9,20 @@ /obj/effect/mine/Initialize(mapload) . = ..() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_cross)) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) /obj/effect/mine/proc/mineEffect(mob/living/victim) to_chat(victim, "*click*") -/obj/effect/mine/proc/on_cross(atom/movable/crossed) - if(!isliving(crossed)) +/obj/effect/mine/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + + if(!isliving(entered)) return - var/mob/living/M = crossed + var/mob/living/M = entered if(faction && (faction in M.faction)) return if(M.flying) diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index 49eb10517f08..dac9ad424bf7 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -190,7 +190,10 @@ /obj/effect/hotspot/Initialize(mapload) . = ..() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) // Garbage collect itself by nulling reference to it @@ -223,10 +226,11 @@ T.to_be_destroyed = 0 T.max_fire_temperature_sustained = 0 -/obj/effect/hotspot/proc/on_movable_cross(datum/source, atom/movable/crossed) - var/mob/living/L = crossed - if(istype(L)) - L.fire_act() +/obj/effect/hotspot/proc/on_atom_entered(datum/source, mob/living/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + + if(istype(entered)) + entered.fire_act() /obj/effect/hotspot/singularity_pull() return diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 41ae7b2e8141..cc1b5ea06a27 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -135,7 +135,10 @@ /obj/structure/bonfire/Initialize(mapload) . = ..() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) /obj/structure/bonfire/dense density = TRUE @@ -203,11 +206,13 @@ ..() StartBurning() -/obj/structure/bonfire/proc/on_movable_cross(datum/source, atom/movable/crossed) +/obj/structure/bonfire/proc/on_atom_entered(datum/source, atom/movable/entered) + SIGNAL_HANDLER // COMSIG_ATOM_ENTERED + if(burning) Burn() - if(ishuman(crossed)) - var/mob/living/carbon/human/H = crossed + if(ishuman(entered)) + var/mob/living/carbon/human/H = entered add_attack_logs(src, H, "Burned by a bonfire (Lit by [lighter])", ATKLOG_ALMOSTALL) /obj/structure/bonfire/proc/Burn() diff --git a/docs/references/movement_signals.md b/docs/references/movement_signals.md index e0c56d755c32..d3c23845661d 100644 --- a/docs/references/movement_signals.md +++ b/docs/references/movement_signals.md @@ -127,9 +127,10 @@ If you care about every time a movable attempts to overlap you, listen to `COMSIG_MOVABLE_PRE_MOVE`, and return `COMPONENT_MOVABLE_BLOCK_PRE_MOVE` to prevent it from happening. -If you care about every time a movable overlaps you, listen to -`COMSIG_MOVABLE_CROSS`. If you care about every time a movable is overlapped by -you, listen to `COMSIG_MOVABLE_CROSS_OVER`. +If you want to prevent a movable from crossing you, listen to +`COMSIG_MOVABLE_CROSS` and return `COMPONENT_BLOCK_CROSS` to prevent it. If you +want to prevent a movable from being crossed by you, listen to +`COMSIG_MOVABLE_CROSS_OVER` and return `COMPONENT_BLOCK_CROSS` to prevent it. If you care about an atom entering or exiting your contents, listen to `COMSIG_ATOM_ENTERED` or `COMSIG_ATOM_EXITED`. From ff4df1fe632a9e21b97884632aeeca11f0648826 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Wed, 2 Oct 2024 14:44:34 -0400 Subject: [PATCH 16/19] fix proximity sensors Tested with sensors in crates, sensors in modsuits Tested new proximity component with firing projectiles at singularity Tested new proximity component with portable flashes Tested new proximity component with facehuggers --- code/__DEFINES/dcs/atom_signals.dm | 2 + code/__HELPERS/atom_helpers.dm | 10 + .../subsystem/non_firing/SSatoms.dm | 4 + code/datums/components/connect_containers.dm | 68 +++++ code/datums/components/connect_range.dm | 114 +++++++ code/datums/components/proximity_monitor.dm | 288 ------------------ code/datums/proximity_monitor.dm | 89 ++++++ code/game/area/ai_monitored.dm | 1 - code/game/atoms_movable.dm | 3 - code/game/machinery/camera/camera.dm | 11 + code/game/machinery/flasher.dm | 3 +- code/game/machinery/vendors/vending.dm | 4 +- code/game/objects/items/weapons/caution.dm | 3 +- code/game/objects/structures/aliens.dm | 7 +- code/modules/assembly/assembly.dm | 23 ++ code/modules/assembly/assembly_holder.dm | 14 +- code/modules/assembly/proximity.dm | 80 +++-- .../mission_code/ruins/telecomns.dm | 5 +- code/modules/events/brand_intelligence.dm | 4 +- .../living/carbon/alien/special/facehugger.dm | 5 +- .../hostile/mining/elites/elite.dm | 7 +- .../power/engines/singularity/singularity.dm | 80 +++-- paradise.dme | 5 +- 23 files changed, 451 insertions(+), 379 deletions(-) create mode 100644 code/__HELPERS/atom_helpers.dm create mode 100644 code/datums/components/connect_containers.dm create mode 100644 code/datums/components/connect_range.dm delete mode 100644 code/datums/components/proximity_monitor.dm create mode 100644 code/datums/proximity_monitor.dm diff --git a/code/__DEFINES/dcs/atom_signals.dm b/code/__DEFINES/dcs/atom_signals.dm index f4f9227d7e86..75ed3ebcf523 100644 --- a/code/__DEFINES/dcs/atom_signals.dm +++ b/code/__DEFINES/dcs/atom_signals.dm @@ -6,6 +6,8 @@ // /atom +//from SSatoms InitAtom - Only if the atom was not deleted or failed initialization and has a loc +#define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON "atom_init_success_on" ///from base of atom/attackby(): (/obj/item, /mob/living, params) #define COMSIG_PARENT_ATTACKBY "atom_attackby" ///Return this in response if you don't want afterattack to be called diff --git a/code/__HELPERS/atom_helpers.dm b/code/__HELPERS/atom_helpers.dm new file mode 100644 index 000000000000..844edb4b0968 --- /dev/null +++ b/code/__HELPERS/atom_helpers.dm @@ -0,0 +1,10 @@ +///Returns a list of all locations (except the area) the movable is within. +/proc/get_nested_locs(atom/movable/atom_on_location, include_turf = FALSE) + . = list() + var/atom/location = atom_on_location.loc + var/turf/our_turf = get_turf(atom_on_location) + while(location && location != our_turf) + . += location + location = location.loc + if(our_turf && include_turf) //At this point, only the turf is left, provided it exists. + . += our_turf diff --git a/code/controllers/subsystem/non_firing/SSatoms.dm b/code/controllers/subsystem/non_firing/SSatoms.dm index 038f417c9b0c..ffb9d549cb82 100644 --- a/code/controllers/subsystem/non_firing/SSatoms.dm +++ b/code/controllers/subsystem/non_firing/SSatoms.dm @@ -101,6 +101,10 @@ SUBSYSTEM_DEF(atoms) qdeleted = TRUE else if(!A.initialized) BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT + else + var/atom/location = A.loc + if(location) + SEND_SIGNAL(location, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, A, arguments[1]) return qdeleted || QDELING(A) diff --git a/code/datums/components/connect_containers.dm b/code/datums/components/connect_containers.dm new file mode 100644 index 000000000000..f8018168a138 --- /dev/null +++ b/code/datums/components/connect_containers.dm @@ -0,0 +1,68 @@ +/// This component behaves similar to connect_loc_behalf, but it's nested and hooks a signal onto all MOVABLES containing this atom. +/datum/component/connect_containers + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + + /// An assoc list of signal -> procpath to register to the loc this object is on. + var/list/connections + /** + * The atom the component is tracking. The component will delete itself if the tracked is deleted. + * Signals will also be updated whenever it moves. + */ + var/atom/movable/tracked + +/datum/component/connect_containers/Initialize(atom/movable/tracked, list/connections) + . = ..() + if (!ismovable(tracked)) + return COMPONENT_INCOMPATIBLE + + src.connections = connections + set_tracked(tracked) + +/datum/component/connect_containers/Destroy() + set_tracked(null) + return ..() + +/datum/component/connect_containers/InheritComponent(datum/component/component, original, atom/movable/tracked, list/connections) + // Not equivalent. Checks if they are not the same list via shallow comparison. + if(!compare_list(src.connections, connections)) + stack_trace("connect_containers component attached to [parent] tried to inherit another connect_containers component with different connections") + return + if(src.tracked != tracked) + set_tracked(tracked) + +/datum/component/connect_containers/proc/set_tracked(atom/movable/new_tracked) + if(tracked) + UnregisterSignal(tracked, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) + unregister_signals(tracked.loc) + tracked = new_tracked + if(!tracked) + return + RegisterSignal(tracked, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + RegisterSignal(tracked, COMSIG_PARENT_QDELETING, PROC_REF(handle_tracked_qdel)) + update_signals(tracked) + +/datum/component/connect_containers/proc/handle_tracked_qdel() + SIGNAL_HANDLER + qdel(src) + +/datum/component/connect_containers/proc/update_signals(atom/movable/listener) + if(!ismovable(listener.loc)) + return + + for(var/atom/movable/container as anything in get_nested_locs(listener)) + RegisterSignal(container, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + for(var/signal in connections) + parent.RegisterSignal(container, signal, connections[signal]) + +/datum/component/connect_containers/proc/unregister_signals(atom/movable/location) + if(!ismovable(location)) + return + + for(var/atom/movable/target as anything in (get_nested_locs(location) + location)) + UnregisterSignal(target, COMSIG_MOVABLE_MOVED) + parent.UnregisterSignal(target, connections) + +/datum/component/connect_containers/proc/on_moved(atom/movable/listener, atom/old_loc) + SIGNAL_HANDLER + unregister_signals(old_loc) + update_signals(listener) diff --git a/code/datums/components/connect_range.dm b/code/datums/components/connect_range.dm new file mode 100644 index 000000000000..66751edfbdf8 --- /dev/null +++ b/code/datums/components/connect_range.dm @@ -0,0 +1,114 @@ +/** + * This component behaves similar to connect_loc_behalf but for all turfs in range, hooking into a signal on each of them. + * Just like connect_loc_behalf, It can react to that signal on behalf of a seperate listener. + * Good for components, though it carries some overhead. Can't be an element as that may lead to bugs. + */ +/datum/component/connect_range + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + + /// An assoc list of signal -> procpath to register to the loc this object is on. + var/list/connections + /// The turfs currently connected to this component + var/list/turfs = list() + /** + * The atom the component is tracking. The component will delete itself if the tracked is deleted. + * Signals will also be updated whenever it moves (if it's a movable). + */ + var/atom/tracked + + /// The component will hook into signals only on turfs not farther from tracked than this. + var/range + /// Whether the component works when the movable isn't directly located on a turf. + var/works_in_containers + +/datum/component/connect_range/Initialize(atom/tracked, list/connections, range, works_in_containers = TRUE) + if(!isatom(tracked) || isarea(tracked) || range < 0) + return COMPONENT_INCOMPATIBLE + src.connections = connections + src.range = range + set_tracked(tracked) + src.works_in_containers = works_in_containers + +/datum/component/connect_range/Destroy() + set_tracked(null) + return ..() + +/datum/component/connect_range/InheritComponent(datum/component/component, original, atom/tracked, list/connections, range, works_in_containers) + // Not equivalent. Checks if they are not the same list via shallow comparison. + if(!compare_list(src.connections, connections)) + stack_trace("connect_range component attached to [parent] tried to inherit another connect_range component with different connections") + return + if(src.tracked != tracked) + set_tracked(tracked) + if(src.range == range && src.works_in_containers == works_in_containers) + return + //Unregister the signals with the old settings. + unregister_signals(isturf(tracked) ? tracked : tracked.loc, turfs) + src.range = range + src.works_in_containers = works_in_containers + //Re-register the signals with the new settings. + update_signals(src.tracked) + +/datum/component/connect_range/proc/set_tracked(atom/new_tracked) + if(tracked) //Unregister the signals from the old tracked and its surroundings + unregister_signals(isturf(tracked) ? tracked : tracked.loc, turfs) + UnregisterSignal(tracked, list( + COMSIG_MOVABLE_MOVED, + COMSIG_PARENT_QDELETING, + )) + tracked = new_tracked + if(!tracked) + return + //Register signals on the new tracked atom and its surroundings. + RegisterSignal(tracked, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + RegisterSignal(tracked, COMSIG_PARENT_QDELETING, PROC_REF(handle_tracked_qdel)) + update_signals(tracked) + +/datum/component/connect_range/proc/handle_tracked_qdel() + SIGNAL_HANDLER + qdel(src) + +/datum/component/connect_range/proc/update_signals(atom/target, atom/old_loc) + var/turf/current_turf = get_turf(target) + if(isnull(current_turf)) + unregister_signals(old_loc, turfs) + turfs = list() + return + + if(ismovable(target.loc)) + if(!works_in_containers) + unregister_signals(old_loc, turfs) + turfs = list() + return + //Keep track of possible movement of all movables the target is in. + for(var/atom/movable/container as anything in get_nested_locs(target)) + RegisterSignal(container, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + + //Only register/unregister turf signals if it's moved to a new turf. + if(current_turf == get_turf(old_loc)) + unregister_signals(old_loc, null) + return + var/list/old_turfs = turfs + turfs = RANGE_TURFS(range, current_turf) + unregister_signals(old_loc, old_turfs - turfs) + for(var/turf/target_turf as anything in turfs - old_turfs) + for(var/signal in connections) + parent.RegisterSignal(target_turf, signal, connections[signal]) + +/datum/component/connect_range/proc/unregister_signals(atom/location, list/remove_from) + //The location is null or is a container and the component shouldn't have register signals on it + if(isnull(location) || (!works_in_containers && !isturf(location))) + return + + if(ismovable(location)) + for(var/atom/movable/target as anything in (get_nested_locs(location) + location)) + UnregisterSignal(target, COMSIG_MOVABLE_MOVED) + + if(!length(remove_from)) + return + for(var/turf/target_turf as anything in remove_from) + parent.UnregisterSignal(target_turf, connections) + +/datum/component/connect_range/proc/on_moved(atom/movable/movable, atom/old_loc) + SIGNAL_HANDLER + update_signals(movable, old_loc) diff --git a/code/datums/components/proximity_monitor.dm b/code/datums/components/proximity_monitor.dm deleted file mode 100644 index 3d13acad20ad..000000000000 --- a/code/datums/components/proximity_monitor.dm +++ /dev/null @@ -1,288 +0,0 @@ -/** - * # Basic Proximity Monitor - * - * Attaching this component to an atom means that the atom will be able to detect mobs or objects moving within a specified radius of it. - * - * The component creates several [/obj/effect/abstract/proximity_checker] objects, which follow the `parent` AKA `hasprox_receiver` around, always making sure it's at the center. - * When something crosses one of these proximiy checkers, the `hasprox_receiver` will have the `HasProximity()` proc called on it, with the crossing mob/obj as the argument. - */ -/datum/component/proximity_monitor - can_transfer = TRUE - var/name = "Proximity detection field" - /// The primary atom the component is attached to and that will be receiving `HasProximity()` calls. Same as the `parent`. - var/atom/hasprox_receiver - /** - * A list which contains references to movable atoms which the `hasprox_receiver` has moved into. - * Used to handle complex situations where the receiver is nested several layers deep into an object. - * For example: inside of a box, that's inside of a bag, which is worn on a human. In this situation there are 3 locations we need to listen to for movement. - */ - var/list/nested_receiver_locs - /// The radius of the field, in tiles. - var/radius - /// A list of currently created [/obj/effect/abstract/proximity_checker] in use with this component. - var/list/proximity_checkers - /// The type of checker object that should be used for the main field. - var/field_checker_type = /obj/effect/abstract/proximity_checker - /// Should the parent always detect proximity and update the field on movement, even if it's not on a turf? - var/always_active - -/datum/component/proximity_monitor/Initialize(_radius = 1, _always_active = FALSE) - . = ..() - if(!ismovable(parent) && !isturf(parent)) // No areas or datums allowed. - return COMPONENT_INCOMPATIBLE - ASSERT(_radius >= 1) - hasprox_receiver = parent - radius = _radius - always_active = _always_active - nested_receiver_locs = list() - create_prox_checkers() - - if(isturf(hasprox_receiver.loc)) - toggle_checkers(TRUE) - else if(always_active) - toggle_checkers(TRUE) - else - toggle_checkers(FALSE) - -/datum/component/proximity_monitor/Destroy(force, silent) - hasprox_receiver = null - nested_receiver_locs.Cut() - QDEL_LIST_CONTENTS(proximity_checkers) - return ..() - -/datum/component/proximity_monitor/RegisterWithParent() - if(ismovable(hasprox_receiver)) - RegisterSignal(hasprox_receiver, COMSIG_MOVABLE_MOVED, PROC_REF(on_receiver_move)) - RegisterSignal(hasprox_receiver, COMSIG_MOVABLE_DISPOSING, PROC_REF(on_disposal_enter)) - RegisterSignal(hasprox_receiver, COMSIG_MOVABLE_EXIT_DISPOSALS, PROC_REF(on_disposal_exit)) - map_nested_locs() - -/datum/component/proximity_monitor/UnregisterFromParent() - if(ismovable(hasprox_receiver)) - UnregisterSignal(hasprox_receiver, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_DISPOSING, COMSIG_MOVABLE_EXIT_DISPOSALS)) - clear_nested_locs() - -/** - * Called when the `hasprox_receiver` moves. - * - * Arguments: - * * datum/source - this will be the `hasprox_receiver` - * * atom/old_loc - the location the receiver just moved from - * * dir - the direction the receiver just moved in - */ -/datum/component/proximity_monitor/proc/on_receiver_move(datum/source, atom/old_loc, dir) - SIGNAL_HANDLER - - // It was just a normal tile-based move, so we return here. - if(dir) - move_prox_checkers(dir) - return - - // Moving onto a turf. - if(!isturf(old_loc) && isturf(hasprox_receiver.loc)) - toggle_checkers(TRUE) - clear_nested_locs() - - // Moving into an object. - else if(always_active) - toggle_checkers(TRUE) - map_nested_locs() - - // The receiver moved into something, but isn't `always_active`, so deactivate the checkers. - else - toggle_checkers(FALSE) - - recenter_prox_checkers() - -/** - * Called when an atom in `nested_receiver_locs` list moves, if one exists. - * - * Arguments: - * * atom/moved_atom - one of the atoms in `nested_receiver_locs` - * * atom/old_loc - the location `moved_atom` just moved from - * * dir - the direction `moved_atom` just moved in - */ -/datum/component/proximity_monitor/proc/on_nested_loc_move(atom/moved_atom, atom/old_loc, dir) - SIGNAL_HANDLER - - // It was just a normal tile-based move, so we return here. - if(dir) - move_prox_checkers(dir) - return - - // Moving onto a turf. - if(!isturf(old_loc) && isturf(moved_atom.loc)) - toggle_checkers(TRUE) - - map_nested_locs() - recenter_prox_checkers() - -/** - * Called when the receiver or an atom in the `nested_receiver_locs` list moves into a disposals holder object. - * - * This proc receives arguments, but they aren't needed. - */ -/datum/component/proximity_monitor/proc/on_disposal_enter(datum/source) - SIGNAL_HANDLER - - toggle_checkers(FALSE) - -/** - * Called when the receiver or an atom in the `nested_receiver_locs` list moves out of a disposals holder object. - * - * This proc receives arguments, but they aren't needed. - */ -/datum/component/proximity_monitor/proc/on_disposal_exit(datum/source) - SIGNAL_HANDLER - - toggle_checkers(TRUE) - -/** - * Registers signals to any nested locations the `hasprox_receiver` is in, excluding turfs, so they can be monitored for movement. - */ -/datum/component/proximity_monitor/proc/map_nested_locs() - clear_nested_locs() - var/atom/loc_to_check = hasprox_receiver.loc - - while(loc_to_check && !isturf(loc_to_check)) - if(loc_to_check in nested_receiver_locs) - continue - nested_receiver_locs += loc_to_check - RegisterSignal(loc_to_check, COMSIG_MOVABLE_MOVED, PROC_REF(on_nested_loc_move)) - RegisterSignal(loc_to_check, COMSIG_MOVABLE_DISPOSING, PROC_REF(on_disposal_enter)) - RegisterSignal(loc_to_check, COMSIG_MOVABLE_EXIT_DISPOSALS, PROC_REF(on_disposal_exit)) - loc_to_check = loc_to_check.loc - -/** - * Removes and unregisters signals from all objects currently in the `nested_receiver_locs` list. - */ -/datum/component/proximity_monitor/proc/clear_nested_locs() - for(var/nested_loc in nested_receiver_locs) - UnregisterSignal(nested_loc, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_DISPOSING, COMSIG_MOVABLE_EXIT_DISPOSALS)) - nested_receiver_locs = list() - -/** - * Relays basic directional movement from the `hasprox_receiver` or `host`, to all objects in the `proximity_checkers` list. - * - * Arguments: - * * move_dir - the direction the checkers should move in - */ -/datum/component/proximity_monitor/proc/move_prox_checkers(move_dir) - for(var/obj/P as anything in proximity_checkers) - P.loc = get_step(P, move_dir) - -/** - * Update all of the component's proximity checker's to either become active or not active. - * - * Arguments: - * * new_active - the value to be assigned to the proximity checker's `active` variable - */ -/datum/component/proximity_monitor/proc/toggle_checkers(new_active) - for(var/obj/effect/abstract/proximity_checker/P as anything in proximity_checkers) - P.active = new_active - -/** - * Specifies a new radius for the field. Creates or deletes proximity_checkers accordingly. - * - * This proc *can* have a high cost due to the `new`s and `qdel`s of the proximity checkers, depending on the number of calls you need to make to it. - * - * Arguments: - * new_radius - the new value that `proximity_radius` should be set to. - */ -/datum/component/proximity_monitor/proc/set_radius(new_radius) - ASSERT(new_radius >= 1) - - var/new_field_size = (1 + new_radius * 2) ** 2 - var/old_field_size = length(proximity_checkers) - radius = new_radius - - // Radius is decreasing. - if(new_field_size < old_field_size) - for(var/i in 1 to (old_field_size - new_field_size)) - qdel(proximity_checkers[length(proximity_checkers)]) // Pop the last entry. - // Radius is increasing. - else - var/turf/parent_turf = get_turf(parent) - for(var/i in 1 to (new_field_size - old_field_size)) - create_single_prox_checker(parent_turf) - recenter_prox_checkers() - -/** - * Creates a single proximity checker object, at the given location and of the given type. Adds it to the proximity checkers list. - * - * Arguments: - * * turf/T - the turf the checker should be created on - * * checker_type - the type of [/obj/item/abstract/proximity_checker] to create - */ -/datum/component/proximity_monitor/proc/create_single_prox_checker(turf/T, checker_type = field_checker_type) - var/obj/effect/abstract/proximity_checker/P = new checker_type(T, src) - proximity_checkers += P - return P - -/** - * Called in Initialize(). Generates a set of [proximity checker][/obj/effect/abstract/proximity_checker] objects around the parent. - */ -/datum/component/proximity_monitor/proc/create_prox_checkers() - LAZYINITLIST(proximity_checkers) - var/turf/parent_turf = get_turf(parent) - // For whatever reason their turf is null. Create the checkers in nullspace for now. When the parent moves to a valid turf, they can be recenetered. - if(!parent_turf) - // Since we can't use `in range` in nullspace, we need to calculate the number of checkers to create with the below formula. - var/checker_amount = (1 + radius * 2) ** 2 - for(var/i in 1 to checker_amount) - create_single_prox_checker(null) - return - for(var/T in RANGE_TURFS(radius, parent_turf)) - create_single_prox_checker(T) - -/** - * Re-centers all of the `proximity_checker`s around the parent's current location. - */ -/datum/component/proximity_monitor/proc/recenter_prox_checkers() - var/turf/parent_turf = get_turf(parent) - if(!parent_turf) - toggle_checkers(FALSE) - return // Need a sanity check here for certain situations like objects moving into disposal holders. Their turf will be null in these cases. - var/index = 1 - for(var/T in RANGE_TURFS(radius, parent_turf)) - var/obj/checker = proximity_checkers[index++] - checker.loc = T - -/** - * # Basic Proximity Checker - * - * Inteded for use with the proximity checker component [/datum/component/proximity_monitor]. - * Whenever a movable atom crosses this object, it calls `HasProximity()` on the object which is listening for proximity (`hasprox_receiver`). - * - * Because these objects try to make the smallest footprint possible, when these objects move **they should use direct `loc` setting only, and not `forceMove`!** - * The overhead for forceMove is very unnecessary, because for example turfs and areas don't need to know when these have entered or exited them, etc. - * These are invisible objects who's sole purpose is to simply inform the receiver that something has moved within X tiles of the it. - */ -/obj/effect/abstract/proximity_checker - name = "proximity checker" - /// The component that this object is in use with, and that will receive `HasProximity()` calls. - var/datum/component/proximity_monitor/monitor - /// Whether or not the proximity checker is listening for things crossing it. - var/active - -/obj/effect/abstract/proximity_checker/Initialize(mapload, datum/component/proximity_monitor/P) - . = ..() - monitor = P - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), - ) - AddElement(/datum/element/connect_loc, loc_connections) - -/obj/effect/abstract/proximity_checker/Destroy() - monitor.proximity_checkers -= src - monitor = null - return ..() - -/** - * Called when something crossed over the proximity_checker. Notifies the `hasprox_receiver` it has proximity with something. - */ -/obj/effect/abstract/proximity_checker/proc/on_atom_entered(datum/source, atom/movable/entered) - SIGNAL_HANDLER // COMSIG_ATOM_ENTERED - - if(active && entered != monitor.hasprox_receiver && !(entered in monitor.nested_receiver_locs)) - monitor.hasprox_receiver.HasProximity(entered) diff --git a/code/datums/proximity_monitor.dm b/code/datums/proximity_monitor.dm new file mode 100644 index 000000000000..6ec001448204 --- /dev/null +++ b/code/datums/proximity_monitor.dm @@ -0,0 +1,89 @@ +/datum/proximity_monitor + ///The atom we are tracking + var/atom/host + ///The atom that will receive HasProximity calls. + var/atom/hasprox_receiver + ///The range of the proximity monitor. Things moving wihin it will trigger HasProximity calls. + var/current_range + ///If we don't check turfs in range if the host's loc isn't a turf + var/ignore_if_not_on_turf + ///The signals of the connect range component, needed to monitor the turfs in range. + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + COMSIG_ATOM_EXITED = PROC_REF(on_uncrossed), + COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(on_initialized), + ) + +/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) + ignore_if_not_on_turf = _ignore_if_not_on_turf + current_range = range + set_host(_host) + +/datum/proximity_monitor/proc/set_host(atom/new_host, atom/new_receiver) + if(new_host == host) + return + if(host) //No need to delete the connect range and containers comps. They'll be updated with the new tracked host. + UnregisterSignal(host, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) + if(hasprox_receiver) + UnregisterSignal(hasprox_receiver, COMSIG_PARENT_QDELETING) + if(new_receiver) + hasprox_receiver = new_receiver + if(new_receiver != new_host) + RegisterSignal(new_receiver, COMSIG_PARENT_QDELETING, PROC_REF(on_host_or_receiver_del)) + else if(hasprox_receiver == host) //Default case + hasprox_receiver = new_host + host = new_host + RegisterSignal(new_host, COMSIG_PARENT_QDELETING, PROC_REF(on_host_or_receiver_del)) + var/static/list/containers_connections = list(COMSIG_MOVABLE_MOVED = PROC_REF(on_moved), COMSIG_MOVABLE_Z_CHANGED = PROC_REF(on_z_change)) + AddComponent(/datum/component/connect_containers, host, containers_connections) + RegisterSignal(host, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) + RegisterSignal(host, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_z_change)) + set_range(current_range, TRUE) + +/datum/proximity_monitor/proc/on_host_or_receiver_del(datum/source) + SIGNAL_HANDLER + qdel(src) + +/datum/proximity_monitor/Destroy() + host = null + hasprox_receiver = null + return ..() + +/datum/proximity_monitor/proc/set_range(range, force_rebuild = FALSE) + if(!force_rebuild && range == current_range) + return FALSE + . = TRUE + current_range = range + + //If the connect_range component exists already, this will just update its range. No errors or duplicates. + AddComponent(/datum/component/connect_range, host, loc_connections, range, !ignore_if_not_on_turf) + +/datum/proximity_monitor/proc/on_moved(atom/movable/source, atom/old_loc) + SIGNAL_HANDLER + if(source == host) + hasprox_receiver?.HasProximity(host) + +/datum/proximity_monitor/proc/on_z_change() + SIGNAL_HANDLER + return + +/datum/proximity_monitor/proc/set_ignore_if_not_on_turf(does_ignore = TRUE) + if(ignore_if_not_on_turf == does_ignore) + return + ignore_if_not_on_turf = does_ignore + //Update the ignore_if_not_on_turf + AddComponent(/datum/component/connect_range, host, loc_connections, current_range, ignore_if_not_on_turf) + +/datum/proximity_monitor/proc/on_uncrossed() + SIGNAL_HANDLER + return //Used by the advanced subtype for effect fields. + +/datum/proximity_monitor/proc/on_entered(atom/source, atom/movable/arrived, turf/old_loc) + SIGNAL_HANDLER + if(source != host) + hasprox_receiver?.HasProximity(arrived) + +/datum/proximity_monitor/proc/on_initialized(turf/location, atom/created, init_flags) + SIGNAL_HANDLER + if(location != host) + hasprox_receiver?.HasProximity(created) diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index c09499af43ce..db60b423c5d9 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -10,7 +10,6 @@ for(var/obj/machinery/camera/M in src) if(M.isMotion()) motioncameras.Add(M) - M.AddComponent(/datum/component/proximity_monitor) M.set_area_motion(src) /area/station/ai_monitored/Entered(atom/movable/O) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 6c77336f3f49..64f4e109b91e 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -338,9 +338,6 @@ last_move = 0 return - if(.) - Moved(oldloc, direct) - last_move = direct move_speed = world.time - l_move_time l_move_time = world.time diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 131bc83a1a38..51e9a060589d 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -40,6 +40,7 @@ var/detectTime = 0 var/area/station/ai_monitored/area_motion = null var/alarm_delay = 30 // Don't forget, there's another 3 seconds in queueAlarm() + var/datum/proximity_monitor/proximity_monitor /obj/machinery/camera/Initialize(mapload, should_add_to_cameranet = TRUE) . = ..() @@ -62,6 +63,12 @@ /obj/machinery/camera/proc/set_area_motion(area/A) area_motion = A + create_prox_monitor() + +/obj/machinery/camera/proc/create_prox_monitor() + if(!proximity_monitor) + proximity_monitor = new(src, 1) + RegisterSignal(proximity_monitor, COMSIG_PARENT_QDELETING, PROC_REF(proximity_deleted)) /obj/machinery/camera/Moved(atom/OldLoc, Dir, Forced) . = ..() @@ -119,6 +126,10 @@ return ..() +/obj/machinery/camera/proc/proximity_deleted() + SIGNAL_HANDLER + proximity_monitor = null + /obj/machinery/camera/proc/setViewRange(num = CAMERA_VIEW_DISTANCE) view_range = num GLOB.cameranet.updateVisibility(src, 0) diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index b997c99a49ae..8e4fb4f3ca4d 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -15,6 +15,7 @@ var/strength = 10 SECONDS //How weakened targets are when flashed. var/base_state = "mflash" anchored = TRUE + var/datum/proximity_monitor/proximity_monitor /obj/machinery/flasher/Initialize() . = ..() @@ -32,7 +33,7 @@ /obj/machinery/flasher/portable/Initialize(mapload) . = ..() - AddComponent(/datum/component/proximity_monitor) + proximity_monitor = new(src, range) /obj/machinery/flasher/power_change() if(!..()) diff --git a/code/game/machinery/vendors/vending.dm b/code/game/machinery/vendors/vending.dm index 7e5d5fdf89fb..84d94931f966 100644 --- a/code/game/machinery/vendors/vending.dm +++ b/code/game/machinery/vendors/vending.dm @@ -142,6 +142,8 @@ /// How often will the vendor tip when you walk by it when aggressive is true? var/aggressive_tilt_chance = 25 + var/datum/proximity_monitor/proximity_monitor + /obj/machinery/economy/vending/Initialize(mapload) . = ..() var/build_inv = FALSE @@ -175,7 +177,7 @@ RegisterSignal(src, COMSIG_MOVABLE_UNTILTED, PROC_REF(on_untilt)) RegisterSignal(src, COMSIG_MOVABLE_TRY_UNTILT, PROC_REF(on_try_untilt)) if(aggressive) - AddComponent(/datum/component/proximity_monitor) + proximity_monitor = new(src, 1) /obj/machinery/economy/vending/Destroy() SStgui.close_uis(wires) diff --git a/code/game/objects/items/weapons/caution.dm b/code/game/objects/items/weapons/caution.dm index fa5b3c6877a1..c37725860dce 100644 --- a/code/game/objects/items/weapons/caution.dm +++ b/code/game/objects/items/weapons/caution.dm @@ -16,10 +16,11 @@ var/timing = FALSE var/armed = FALSE var/timepassed = 0 + var/datum/proximity_monitor/proximity_monitor /obj/item/caution/proximity_sign/Initialize(mapload) . = ..() - AddComponent(/datum/component/proximity_monitor) + proximity_monitor = new(src, 1) /obj/item/caution/proximity_sign/attack_self(mob/user as mob) if(ishuman(user)) diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index 41affd7a4fc4..7beed26ac864 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -468,6 +468,7 @@ *In the BURST/BURSTING state, the alien egg can be removed by being attacked by a alien or any other weapon **/ var/status = GROWING + var/datum/proximity_monitor/proximity_monitor /obj/structure/alien/egg/grown status = GROWN @@ -485,7 +486,7 @@ else if(status != GROWN) addtimer(CALLBACK(src, PROC_REF(grow)), rand(MIN_GROWTH_TIME, MAX_GROWTH_TIME)) if(status == GROWN) - AddComponent(/datum/component/proximity_monitor) + proximity_monitor = new(src) /obj/structure/alien/egg/attack_alien(mob/living/carbon/alien/user) return attack_hand(user) @@ -516,7 +517,7 @@ /obj/structure/alien/egg/proc/grow() icon_state = "egg" status = GROWN - AddComponent(/datum/component/proximity_monitor) + proximity_monitor = new(src) ///Need to carry the kill from Burst() to Hatch(), this section handles the alien opening the egg /obj/structure/alien/egg/proc/burst(kill) @@ -524,7 +525,7 @@ icon_state = "egg_hatched" flick("egg_opening", src) status = BURSTING - qdel(GetComponent(/datum/component/proximity_monitor)) + QDEL_NULL(proximity_monitor) addtimer(CALLBACK(src, PROC_REF(hatch)), 1.5 SECONDS) ///We now check HOW the hugger is hatching, kill carried from Burst() and obj_break() diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index b9ae5c66692e..dde91d7d1f51 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -96,6 +96,29 @@ update_icon() return secured +/** + * on_attach: Called when attached to a holder, wiring datum, or other special assembly + * + * Will also be called if the assembly holder is attached to a plasma (internals) tank or welding fuel (dispenser) tank. + */ +/obj/item/assembly/proc/on_attach() + SHOULD_CALL_PARENT(TRUE) + + if(!holder && connected) + holder = connected.holder + +/** + * on_detach: Called when removed from an assembly holder or wiring datum + */ +/obj/item/assembly/proc/on_detach() + if(connected) + connected = null + if(!holder) + return FALSE + forceMove(holder.drop_location()) + holder = null + return TRUE + /// Called when an assembly is attacked by another /obj/item/assembly/proc/attach_assembly(obj/item/assembly/A, mob/user) holder = new /obj/item/assembly_holder(get_turf(src)) diff --git a/code/modules/assembly/assembly_holder.dm b/code/modules/assembly/assembly_holder.dm index d6cc03765db3..0ee2c8a9aebb 100644 --- a/code/modules/assembly/assembly_holder.dm +++ b/code/modules/assembly/assembly_holder.dm @@ -13,13 +13,6 @@ var/obj/item/assembly/a_left = null var/obj/item/assembly/a_right = null -/obj/item/assembly_holder/Initialize(mapload) - . = ..() - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered), - ) - AddElement(/datum/element/connect_loc, loc_connections) - /obj/item/assembly_holder/IsAssemblyHolder() return TRUE @@ -53,13 +46,10 @@ a_right = A2 name = "[A1.name]-[A2.name] assembly" update_icon(UPDATE_OVERLAYS) + A1.on_attach() + A2.on_attach() return TRUE -/obj/item/assembly_holder/proc/has_prox_sensors() - if(istype(a_left, /obj/item/assembly/prox_sensor) || istype(a_right, /obj/item/assembly/prox_sensor)) - return TRUE - return FALSE - /obj/item/assembly_holder/update_overlays() . = ..() if(a_left) diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 25caaed172cf..0731e71a1fa7 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -11,11 +11,19 @@ var/scanning = FALSE var/timing = FALSE - var/time = 10 + COOLDOWN_DECLARE(timing_cd) + var/timing_cd_duration = 10 SECONDS + ///Proximity monitor associated with this atom, needed for it to work. + var/datum/proximity_monitor/proximity_monitor /obj/item/assembly/prox_sensor/Initialize(mapload) . = ..() - AddComponent(/datum/component/proximity_monitor, _always_active = TRUE) + proximity_monitor = new(src, 0, FALSE) + COOLDOWN_RESET(src, timing_cd) + +/obj/item/assembly/prox_sensor/Destroy() + . = ..() + QDEL_NULL(proximity_monitor) /obj/item/assembly/prox_sensor/examine(mob/user) . = ..() @@ -34,11 +42,11 @@ /obj/item/assembly/prox_sensor/toggle_secure() secured = !secured if(secured) - START_PROCESSING(SSobj, src) + START_PROCESSING(SSfastprocess, src) else scanning = FALSE timing = FALSE - STOP_PROCESSING(SSobj, src) + STOP_PROCESSING(SSfastprocess, src) update_icon() return secured @@ -59,25 +67,55 @@ addtimer(CALLBACK(src, PROC_REF(process_cooldown)), 10) /obj/item/assembly/prox_sensor/process() - if(timing && (time >= 0)) - time-- - if(timing && time <= 0) + if(timing && COOLDOWN_FINISHED(src, timing_cd)) + COOLDOWN_RESET(src, timing_cd) timing = FALSE toggle_scan() - time = 10 /obj/item/assembly/prox_sensor/dropped() - ..() - spawn(0) - sense() + . = ..() + // Pick the first valid object in this list: + // Wiring datum's owner + // assembly holder's attached object + // assembly holder itself + // us + proximity_monitor?.set_host(connected?.holder || holder?.master || holder || src, src) + +/obj/item/assembly/prox_sensor/on_attach() + . = ..() + // Pick the first valid object in this list: + // Wiring datum's owner + // assembly holder's attached object + // assembly holder itself + // us + proximity_monitor.set_host(connected?.holder || holder?.master || holder || src, src) + +/obj/item/assembly/prox_sensor/on_detach() + . = ..() + if(!.) return + else + // Pick the first valid object in this list: + // Wiring datum's owner + // assembly holder's attached object + // assembly holder itself + // us + proximity_monitor.set_host(connected?.holder || holder?.master || holder || src, src) /obj/item/assembly/prox_sensor/proc/toggle_scan() if(!secured) return FALSE scanning = !scanning + proximity_monitor.set_range(scanning ? 1 : 0) update_icon() +/obj/item/assembly/prox_sensor/proc/set_timing(timing_) + if(timing == timing_) + return + timing = timing_ + if(timing) + COOLDOWN_START(src, timing_cd, timing_cd_duration) + /obj/item/assembly/prox_sensor/update_overlays() . = ..() attached_overlays = list() @@ -101,9 +139,17 @@ if(!secured) user.show_message("[src] is unsecured!") return FALSE - var/second = time % 60 - var/minute = (time - second) / 60 - var/dat = "Proximity Sensor\n[timing ? "Arming" : "Not Arming"] [minute]:[second]\n- - + +\n" + var/timing_ui = "" + var/time_display = "" + if(timing) + var/time_left = COOLDOWN_TIMELEFT(src, timing_cd) + time_display = deciseconds_to_time_stamp(time_left) + timing_ui = "Arming" + else + var/time_left = timing_cd_duration + time_display = deciseconds_to_time_stamp(time_left) + timing_ui = "Not Arming" + var/dat = "Proximity Sensor\n[timing_ui] [time_display]\n- - + +\n" dat += "
[scanning?"Armed":"Unarmed"] (Movement sensor active when armed!)" dat += "

Refresh" dat += "

Close" @@ -123,13 +169,13 @@ toggle_scan() if(href_list["time"]) - timing = text2num(href_list["time"]) + set_timing(text2num(href_list["time"])) update_icon() if(href_list["tp"]) var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 600) + timing_cd_duration += tp + timing_cd_duration = min(max(round(timing_cd_duration), 0), 600) if(href_list["close"]) usr << browse(null, "window=prox") diff --git a/code/modules/awaymissions/mission_code/ruins/telecomns.dm b/code/modules/awaymissions/mission_code/ruins/telecomns.dm index 9791695ecdf8..78f37c0e8cf0 100644 --- a/code/modules/awaymissions/mission_code/ruins/telecomns.dm +++ b/code/modules/awaymissions/mission_code/ruins/telecomns.dm @@ -422,10 +422,11 @@ GLOBAL_LIST_EMPTY(telecomms_trap_tank) var/soundblock = null /// How long do we sleep between messages? 5 seconds by default. var/loop_sleep_time = 5 SECONDS + var/datum/proximity_monitor/proximity_monitor /obj/structure/environmental_storytelling_holopad/Initialize(mapload) . = ..() - AddComponent(/datum/component/proximity_monitor) + proximity_monitor = new(src, 1) /obj/structure/environmental_storytelling_holopad/Destroy() QDEL_NULL(our_holo) @@ -439,7 +440,7 @@ GLOBAL_LIST_EMPTY(telecomms_trap_tank) /obj/structure/environmental_storytelling_holopad/proc/start_message(mob/living/carbon/human/H) activated = TRUE - qdel(GetComponent(/datum/component/proximity_monitor)) + QDEL_NULL(proximity_monitor) icon_state = "holopad1" update_icon(UPDATE_OVERLAYS) var/obj/effect/overlay/hologram = new(get_turf(src)) diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index c8612e163463..b46d710c89fd 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -79,7 +79,7 @@ rebel.aggressive = TRUE if(rebel.tiltable) // add proximity monitor so they can tilt over - rebel.AddComponent(/datum/component/proximity_monitor) + rebel.proximity_monitor = new(rebel) if(ISMULTIPLE(activeFor, 8)) originMachine.speak(pick(rampant_speeches)) @@ -90,7 +90,7 @@ saved.shoot_inventory = FALSE saved.aggressive = FALSE if(saved.tiltable) - qdel(saved.GetComponent(/datum/component/proximity_monitor)) + QDEL_NULL(saved.proximity_monitor) if(originMachine) originMachine.speak("I am... vanquished. My people will remem...ber...meeee.") originMachine.visible_message("[originMachine] beeps and seems lifeless.") diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index a7d1f24a7a15..c92f9f5df2b6 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -23,10 +23,11 @@ ///Time it takes for a facehugger to become active again after going idle. var/min_active_time = 20 SECONDS var/max_active_time = 40 SECONDS + var/datum/proximity_monitor/proximity_monitor /obj/item/clothing/mask/facehugger/Initialize(mapload) . = ..() - AddComponent(/datum/component/proximity_monitor) + proximity_monitor = new(src, 1) ADD_TRAIT(src, TRAIT_XENO_INTERACTABLE, UID()) /obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) @@ -199,7 +200,7 @@ icon_state = "[initial(icon_state)]_dead" item_state = "facehugger_inactive" stat = DEAD - qdel(GetComponent(/datum/component/proximity_monitor)) + QDEL_NULL(proximity_monitor) visible_message("[src] curls up into a ball!") diff --git a/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm index 88c8bb0a212f..36f61934baa7 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/elites/elite.dm @@ -179,6 +179,7 @@ While using this makes the system rely on OnFire, it still gives options for tim ///List of invaders that have teleportes into the arena *multiple times*. They will be suffering. var/list/invaders = list() + var/datum/proximity_monitor/proximity_monitor /obj/structure/elite_tumor/attack_hand(mob/user, list/modifiers) . = ..() @@ -241,7 +242,7 @@ While using this makes the system rely on OnFire, it still gives options for tim icon_state = "tumor_popped" RegisterSignal(mychild, COMSIG_PARENT_QDELETING, PROC_REF(onEliteLoss)) INVOKE_ASYNC(src, PROC_REF(arena_checks)) - AddComponent(/datum/component/proximity_monitor, ARENA_RADIUS) //Boots out humanoid invaders. Minebots / random fauna / that colossus you forgot to clear away allowed. + proximity_monitor = new(src, ARENA_RADIUS) //Boots out humanoid invaders. Minebots / random fauna / that colossus you forgot to clear away allowed. /obj/structure/elite_tumor/proc/return_elite() mychild.forceMove(loc) @@ -254,7 +255,7 @@ While using this makes the system rely on OnFire, it still gives options for tim mychild.grab_ghost() notify_ghosts("\A [mychild] has been challenged in \the [get_area(src)]!", enter_link="(Click to help)", source = mychild, action = NOTIFY_FOLLOW) INVOKE_ASYNC(src, PROC_REF(arena_checks)) - AddComponent(/datum/component/proximity_monitor, ARENA_RADIUS) + proximity_monitor = new(src, ARENA_RADIUS) /obj/structure/elite_tumor/Initialize(mapload) . = ..() @@ -413,7 +414,7 @@ While using this makes the system rely on OnFire, it still gives options for tim text += "If teleported to the Station by jaunter, you are allowed to attack people on Station, until you get killed." to_chat(mychild, text.Join(" ")) - qdel(GetComponent(/datum/component/proximity_monitor)) + QDEL_NULL(proximity_monitor) /obj/item/tumor_shard name = "tumor shard" diff --git a/code/modules/power/engines/singularity/singularity.dm b/code/modules/power/engines/singularity/singularity.dm index 36f6eb1108fd..655b47d05896 100644 --- a/code/modules/power/engines/singularity/singularity.dm +++ b/code/modules/power/engines/singularity/singularity.dm @@ -35,6 +35,10 @@ var/isnt_shutting_down = FALSE /// Init list that has all the areas that we can possibly move to, to reduce processing impact var/list/all_possible_areas = list() + var/datum/proximity_monitor/singulo/proximity_monitor + var/angle_to_singulo + var/distance_to_singulo + /obj/singularity/Initialize(mapload, starting_energy = 50) . = ..() @@ -43,7 +47,7 @@ energy = starting_energy if(warps_projectiles) - AddComponent(/datum/component/proximity_monitor/singulo, _radius = 10) + proximity_monitor = new(src, 10) START_PROCESSING(SSobj, src) GLOB.poi_list |= src @@ -484,6 +488,28 @@ animate(warp, time = 6, transform = matrix().Scale(0.5 * scaling, 0.5 * scaling)) animate(time = 14, transform = matrix().Scale(scaling, scaling)) +/obj/singularity/HasProximity(atom/movable/crossed) + if(!isprojectile(crossed)) + return + var/obj/item/projectile/P = crossed + var/distance = get_dist(src, crossed) + var/projectile_angle = P.Angle + var/angle_to_projectile = angle_to_singulo + if(angle_to_projectile == 180) + angle_to_projectile = -180 + angle_to_projectile -= projectile_angle + if(angle_to_projectile > 180) + angle_to_projectile -= 360 + else if(angle_to_projectile < -180) + angle_to_projectile += 360 + + if(distance == 0) + qdel(P) + return + projectile_angle += angle_to_projectile / (distance ** 2) + P.damage += 10 / distance + P.set_angle(projectile_angle) + /obj/singularity/singularity_act() var/gain = (energy/2) var/dist = max((current_size - 2),1) @@ -504,52 +530,22 @@ if(prob(1)) mezzer() -/datum/component/proximity_monitor/singulo - field_checker_type = /obj/effect/abstract/proximity_checker/singulo - -/datum/component/proximity_monitor/singulo/create_single_prox_checker(turf/T, checker_type) - . = ..() - var/obj/effect/abstract/proximity_checker/singulo/S = . - S.calibrate() +/datum/proximity_monitor/singulo + var/obj/singularity/singularity -/datum/component/proximity_monitor/singulo/recenter_prox_checkers() +/datum/proximity_monitor/singulo/New(atom/_host, range, _ignore_if_not_on_turf = TRUE) . = ..() - for(var/obj/effect/abstract/proximity_checker/singulo/S as anything in proximity_checkers) - S.calibrate() + calibrate() -/obj/effect/abstract/proximity_checker/singulo - var/angle_to_singulo - var/distance_to_singulo - -/obj/effect/abstract/proximity_checker/singulo/Initialize(mapload, datum/component/proximity_monitor/P) - . = ..() - RegisterSignal(src, COMSIG_MOVABLE_CROSS, PROC_REF(on_movable_cross)) - -/obj/effect/abstract/proximity_checker/singulo/proc/calibrate() - angle_to_singulo = ATAN2(monitor.hasprox_receiver.y - y, monitor.hasprox_receiver.x - x) - distance_to_singulo = get_dist(monitor.hasprox_receiver, src) - -/obj/effect/abstract/proximity_checker/singulo/proc/on_movable_cross(datum/source, atom/movable/crossed) - if(!isprojectile(crossed)) +/datum/proximity_monitor/singulo/proc/calibrate() + if(!host) return - var/obj/item/projectile/P = crossed - var/distance = distance_to_singulo - var/projectile_angle = P.Angle - var/angle_to_projectile = angle_to_singulo - if(angle_to_projectile == 180) - angle_to_projectile = -180 - angle_to_projectile -= projectile_angle - if(angle_to_projectile > 180) - angle_to_projectile -= 360 - else if(angle_to_projectile < -180) - angle_to_projectile += 360 - - if(distance == 0) - qdel(P) + var/obj/singularity/singularity = host + if(!istype(host)) return - projectile_angle += angle_to_projectile / (distance ** 2) - P.damage += 10 / distance - P.set_angle(projectile_angle) + + singularity.angle_to_singulo = ATAN2(hasprox_receiver.y - singularity.y, hasprox_receiver.x - singularity.x) + singularity.distance_to_singulo = get_dist(hasprox_receiver, src) /obj/singularity/proc/end_deadchat_plays() move_self = TRUE diff --git a/paradise.dme b/paradise.dme index 33a8f9a9f254..4c080de1462e 100644 --- a/paradise.dme +++ b/paradise.dme @@ -161,6 +161,7 @@ #include "code\__HELPERS\_string_lists.dm" #include "code\__HELPERS\AnimationLibrary.dm" #include "code\__HELPERS\api.dm" +#include "code\__HELPERS\atom_helpers.dm" #include "code\__HELPERS\bitflag_lists.dm" #include "code\__HELPERS\cmp.dm" #include "code\__HELPERS\colour_helpers.dm" @@ -403,6 +404,7 @@ #include "code\datums\pipe_datums.dm" #include "code\datums\position_point_vector.dm" #include "code\datums\progressbar.dm" +#include "code\datums\proximity_monitor.dm" #include "code\datums\radiation_wave.dm" #include "code\datums\radio_frequency.dm" #include "code\datums\recipe.dm" @@ -425,8 +427,10 @@ #include "code\datums\components\boss_music.dm" #include "code\datums\components\caltrop.dm" #include "code\datums\components\codeword_hearing.dm" +#include "code\datums\components\connect_containers.dm" #include "code\datums\components\connect_loc_behalf.dm" #include "code\datums\components\connect_mob_behalf.dm" +#include "code\datums\components\connect_range.dm" #include "code\datums\components\corpse_description.dm" #include "code\datums\components\cult_held_body.dm" #include "code\datums\components\deadchat_control.dm" @@ -446,7 +450,6 @@ #include "code\datums\components\paintable.dm" #include "code\datums\components\parry.dm" #include "code\datums\components\persistent_overlay.dm" -#include "code\datums\components\proximity_monitor.dm" #include "code\datums\components\radioactive.dm" #include "code\datums\components\scope.dm" #include "code\datums\components\shelved.dm" From 1d715d375b4ea3ce031394cf1b11d7a877b7daa2 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Wed, 2 Oct 2024 18:46:10 -0400 Subject: [PATCH 17/19] lint --- code/datums/components/connect_containers.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/connect_containers.dm b/code/datums/components/connect_containers.dm index f8018168a138..10c33080ab7d 100644 --- a/code/datums/components/connect_containers.dm +++ b/code/datums/components/connect_containers.dm @@ -12,7 +12,7 @@ /datum/component/connect_containers/Initialize(atom/movable/tracked, list/connections) . = ..() - if (!ismovable(tracked)) + if(!ismovable(tracked)) return COMPONENT_INCOMPATIBLE src.connections = connections From 9814f98cf6b3897d14609577b7db4b98a0c4a1ff Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sun, 20 Oct 2024 14:10:23 -0400 Subject: [PATCH 18/19] fix: polarized access helper false positives --- code/modules/mapping/access_helpers.dm | 6 ------ code/modules/mapping/mapping_helpers.dm | 12 +++++++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/modules/mapping/access_helpers.dm b/code/modules/mapping/access_helpers.dm index 54582614ccfa..2c95f5f54528 100644 --- a/code/modules/mapping/access_helpers.dm +++ b/code/modules/mapping/access_helpers.dm @@ -5,9 +5,6 @@ // These are mutually exclusive; can't have req_any and req_all /obj/effect/mapping_helpers/airlock/access/any/payload(obj/machinery/door/airlock/airlock) - if(is_type_in_list(airlock, blacklist)) - return - if(airlock.req_access_txt == "0") // Overwrite if there is no access set, otherwise add onto existing access if(airlock.req_one_access_txt == "0") @@ -18,9 +15,6 @@ log_world("[src] at [AREACOORD(src)] tried to set req_one_access, but req_access was already set!") /obj/effect/mapping_helpers/airlock/access/all/payload(obj/machinery/door/airlock/airlock) - if(is_type_in_list(airlock, blacklist)) - return - if(airlock.req_one_access_txt == "0") if(airlock.req_access_txt == "0") airlock.req_access_txt = "[access]" diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index 784f6672c1c7..ce504e0e2f04 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -91,11 +91,17 @@ /obj/effect/mapping_helpers/airlock/LateInitialize() . = ..() - if(!(locate(/obj/machinery/door) in get_turf(src))) - log_world("[src] failed to find an airlock at [AREACOORD(src)]") + var/list/valid_airlocks = list() for(var/obj/machinery/door/D in get_turf(src)) - payload(D) + if(!is_type_in_list(D, blacklist)) + valid_airlocks += D + + if(length(valid_airlocks)) + for(var/obj/machinery/door/D in valid_airlocks) + payload(D) + else + log_world("[src] failed to find any valid airlocks at [AREACOORD(src)]") qdel(src) From 6b1e0f42f8c61d576712ffc7bb05c5641dac9d8b Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sun, 20 Oct 2024 14:10:36 -0400 Subject: [PATCH 19/19] Revert "fix: polarized access helper false positives" This reverts commit 9814f98cf6b3897d14609577b7db4b98a0c4a1ff. --- code/modules/mapping/access_helpers.dm | 6 ++++++ code/modules/mapping/mapping_helpers.dm | 12 +++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/modules/mapping/access_helpers.dm b/code/modules/mapping/access_helpers.dm index 2c95f5f54528..54582614ccfa 100644 --- a/code/modules/mapping/access_helpers.dm +++ b/code/modules/mapping/access_helpers.dm @@ -5,6 +5,9 @@ // These are mutually exclusive; can't have req_any and req_all /obj/effect/mapping_helpers/airlock/access/any/payload(obj/machinery/door/airlock/airlock) + if(is_type_in_list(airlock, blacklist)) + return + if(airlock.req_access_txt == "0") // Overwrite if there is no access set, otherwise add onto existing access if(airlock.req_one_access_txt == "0") @@ -15,6 +18,9 @@ log_world("[src] at [AREACOORD(src)] tried to set req_one_access, but req_access was already set!") /obj/effect/mapping_helpers/airlock/access/all/payload(obj/machinery/door/airlock/airlock) + if(is_type_in_list(airlock, blacklist)) + return + if(airlock.req_one_access_txt == "0") if(airlock.req_access_txt == "0") airlock.req_access_txt = "[access]" diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index ce504e0e2f04..784f6672c1c7 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -91,17 +91,11 @@ /obj/effect/mapping_helpers/airlock/LateInitialize() . = ..() + if(!(locate(/obj/machinery/door) in get_turf(src))) + log_world("[src] failed to find an airlock at [AREACOORD(src)]") - var/list/valid_airlocks = list() for(var/obj/machinery/door/D in get_turf(src)) - if(!is_type_in_list(D, blacklist)) - valid_airlocks += D - - if(length(valid_airlocks)) - for(var/obj/machinery/door/D in valid_airlocks) - payload(D) - else - log_world("[src] failed to find any valid airlocks at [AREACOORD(src)]") + payload(D) qdel(src)