Files
Bubberstation/code/game/objects/structures/railings.dm
MrMelbert c1ed62915b Adds UPSIDE_DOWN movetype for negative gravity / makes Atrocinator affected by less things (#79785)
## About The Pull Request

Fixes #79764

I was going to tackle this issue by slamming `TRAIT_NO_SLIP_ALL` on
Atrocinator users and calling it a day, but like, that didn't feel
proper.

So I thought hey, we could just give them the flying movetype, even
though they technically aren't flying it means they're unaffected by
things that flying would make you unaffected by.

Nope, this means the mob technically "negates gravity", so no falling
and no feetsteps.

Let's try floating - this give us feetsteps but no falling upwards. 

So instead of going back to square one, with `TRAIT_NO_SLIP_ALL`, I
decided to go for the more complex route of just adding a movetype.

Hence, move type `UPSIDE_DOWN`. This covers situations where a mob would
be "floating" above the ground, but still walking. ...Negative gravity.

This means overall the Atrociator acts more as you'd expect - you don't
slip on ice, you don't trigger bear traps or mouse traps, you can walk
over railings, unaffected by conveyor belts, etc.

## Why It's Good For The Game

Makes the Atrocinator a lot more consistent with how you'd expect for it
to work.

Admittedly it is a bit niche use of movetypes, but it can possibly be
expanded to more things in the future, who knows? I applied it to mobs
on meat spikes (even though they don't move), just for proof of concept.

## Changelog

🆑 Melbert
fix: Atrocinating mobs will now behave more as you'd expect. Meaning
they don't slip on wet patches, can't trigger bear traps / landmines /
mouse traps, ignore conveyors, and can walk over tables and railings.
fix: Floating mobs are unaffected by conveyor belts, acid (on the
ground), glass tables
fix: Floating mobs won't squish stuff like roaches anymore 
fix: Fixes bear traps triggering on floating / flying mobs 
/🆑

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2023-11-20 21:19:13 +00:00

191 lines
5.6 KiB
Plaintext

/obj/structure/railing
name = "railing"
desc = "Basic railing meant to protect idiots like you from falling."
icon = 'icons/obj/railings.dmi'
icon_state = "railing"
flags_1 = ON_BORDER_1
obj_flags = CAN_BE_HIT | BLOCKS_CONSTRUCTION_DIR
density = TRUE
anchored = TRUE
pass_flags_self = LETPASSTHROW|PASSSTRUCTURE
layer = ABOVE_MOB_LAYER
plane = GAME_PLANE_UPPER
/// armor is a little bit less than a grille. max_integrity about half that of a grille.
armor_type = /datum/armor/structure_railing
max_integrity = 25
var/climbable = TRUE
///Initial direction of the railing.
var/ini_dir
///item released when deconstructed
var/item_deconstruct = /obj/item/stack/rods
/datum/armor/structure_railing
melee = 35
bullet = 50
laser = 50
energy = 100
bomb = 10
/obj/structure/railing/corner //aesthetic corner sharp edges hurt oof ouch
icon_state = "railing_corner"
density = FALSE
climbable = FALSE
/obj/structure/railing/corner/end //end of a segment of railing without making a loop
icon_state = "railing_end"
/obj/structure/railing/corner/end/flip //same as above but flipped around
icon_state = "railing_end_flip"
/obj/structure/railing/Initialize(mapload)
. = ..()
ini_dir = dir
if(climbable)
AddElement(/datum/element/climbable)
if(density && flags_1 & ON_BORDER_1) // blocks normal movement from and to the direction it's facing.
var/static/list/loc_connections = list(
COMSIG_ATOM_EXIT = PROC_REF(on_exit),
)
AddElement(/datum/element/connect_loc, loc_connections)
var/static/list/tool_behaviors = list(
TOOL_WELDER = list(
SCREENTIP_CONTEXT_LMB = "Repair",
),
TOOL_WRENCH = list(
SCREENTIP_CONTEXT_LMB = "Anchor/Unanchor",
),
TOOL_WIRECUTTER = list(
SCREENTIP_CONTEXT_LMB = "Deconstruct",
),
)
AddElement(/datum/element/contextual_screentip_tools, tool_behaviors)
AddComponent(/datum/component/simple_rotation, ROTATION_NEEDS_ROOM)
/obj/structure/railing/examine(mob/user)
. = ..()
if(anchored == TRUE)
. += span_notice("The railing is <b>bolted</b> to the floor.")
else
. += span_notice("The railing is <i>unbolted</i> from the floor and can be deconstructed with <b>wirecutters</b>.")
/obj/structure/railing/attackby(obj/item/I, mob/living/user, params)
..()
add_fingerprint(user)
if(I.tool_behaviour == TOOL_WELDER && !user.combat_mode)
if(atom_integrity < max_integrity)
if(!I.tool_start_check(user, amount=1))
return
to_chat(user, span_notice("You begin repairing [src]..."))
if(I.use_tool(src, user, 40, volume=50))
atom_integrity = max_integrity
to_chat(user, span_notice("You repair [src]."))
else
to_chat(user, span_warning("[src] is already in good condition!"))
return
/obj/structure/railing/AltClick(mob/user)
return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation
/obj/structure/railing/wirecutter_act(mob/living/user, obj/item/I)
. = ..()
to_chat(user, span_warning("You cut apart the railing."))
I.play_tool_sound(src, 100)
deconstruct()
return TRUE
/obj/structure/railing/deconstruct(disassembled)
if((flags_1 & NODECONSTRUCT_1))
return ..()
var/rods_to_make = istype(src,/obj/structure/railing/corner) ? 1 : 2
var/obj/rod = new item_deconstruct(drop_location(), rods_to_make)
transfer_fingerprints_to(rod)
return ..()
///Implements behaviour that makes it possible to unanchor the railing.
/obj/structure/railing/wrench_act(mob/living/user, obj/item/I)
. = ..()
if(flags_1&NODECONSTRUCT_1)
return
to_chat(user, span_notice("You begin to [anchored ? "unfasten the railing from":"fasten the railing to"] the floor..."))
if(I.use_tool(src, user, volume = 75, extra_checks = CALLBACK(src, PROC_REF(check_anchored), anchored)))
set_anchored(!anchored)
to_chat(user, span_notice("You [anchored ? "fasten the railing to":"unfasten the railing from"] the floor."))
return TRUE
/obj/structure/railing/CanPass(atom/movable/mover, border_dir)
. = ..()
if(border_dir & dir)
return . || mover.throwing || (mover.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)
return TRUE
/obj/structure/railing/CanAStarPass(to_dir, datum/can_pass_info/pass_info)
if(!(to_dir & dir))
return TRUE
return ..()
/obj/structure/railing/proc/on_exit(datum/source, atom/movable/leaving, direction)
SIGNAL_HANDLER
if(leaving == src)
return // Let's not block ourselves.
if(!(direction & dir))
return
if (!density)
return
if (leaving.throwing)
return
if (leaving.movement_type & (PHASING|MOVETYPES_NOT_TOUCHING_GROUND))
return
if (leaving.move_force >= MOVE_FORCE_EXTREMELY_STRONG)
return
leaving.Bump(src)
return COMPONENT_ATOM_BLOCK_EXIT
/obj/structure/railing/proc/check_anchored(checked_anchored)
if(anchored == checked_anchored)
return TRUE
/obj/structure/railing/wooden_fence
name = "wooden fence"
desc = "wooden fence meant to keep animals in."
icon = 'icons/obj/structures.dmi'
icon_state = "wooden_railing"
item_deconstruct = /obj/item/stack/sheet/mineral/wood
plane = GAME_PLANE_FOV_HIDDEN
layer = ABOVE_MOB_LAYER
/obj/structure/railing/wooden_fence/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_change_layer))
adjust_dir_layer(dir)
/obj/structure/railing/wooden_fence/proc/on_change_layer(datum/source, old_dir, new_dir)
SIGNAL_HANDLER
adjust_dir_layer(new_dir)
/obj/structure/railing/wooden_fence/proc/adjust_dir_layer(direction)
var/new_layer = (direction & NORTH) ? MOB_LAYER : ABOVE_MOB_LAYER
layer = new_layer
/obj/structure/railing/corner/end/wooden_fence
icon = 'icons/obj/structures.dmi'
icon_state = "wooden_railing_corner"
/obj/structure/railing/corner/end/flip/wooden_fence
icon = 'icons/obj/structures.dmi'
icon_state = "wooden_railing_corner_flipped"