From 0dee8a0acee46b032cfed026719c3c199cfe7a3d Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Mon, 17 Jul 2023 13:39:51 -0700 Subject: [PATCH] dynamic climbing and object heights (#5692) Co-authored-by: silicons --- code/__DEFINES/_flags/atom_flags.dm | 5 +- code/__DEFINES/_flags/obj_flags.dm | 3 + code/__DEFINES/procs/do_after.dm | 2 + code/game/machinery/computer/atmos_control.dm | 3 + code/game/machinery/computer/computer.dm | 3 + code/game/machinery/computer/medical.dm | 4 +- code/game/machinery/computer/skills.dm | 3 + code/game/machinery/computer/timeclock_vr.dm | 2 + code/game/machinery/cryopod.dm | 2 + code/game/machinery/holopad.dm | 2 + code/game/machinery/lathes/lathe.dm | 3 + code/game/objects/items.dm | 3 + code/game/objects/items/poi_items.dm | 1 - code/game/objects/objs.dm | 197 +++++++++++++++--- code/game/objects/structures.dm | 123 +---------- code/game/objects/structures/cliff.dm | 15 +- .../structures/crates_lockers/crates.dm | 8 +- code/game/objects/structures/fence.dm | 7 +- code/game/objects/structures/girders.dm | 2 + code/game/objects/structures/gravemarker.dm | 3 +- code/game/objects/structures/janicart.dm | 3 +- code/game/objects/structures/ledges.dm | 38 +--- code/game/objects/structures/low_wall.dm | 4 + code/game/objects/structures/mop_bucket.dm | 3 +- code/game/objects/structures/railing.dm | 59 ++---- code/game/objects/structures/statues.dm | 4 +- code/game/turfs/turf.dm | 24 ++- .../atmospherics/machinery/machinery.dm | 2 + code/modules/events/meteor_strike_vr.dm | 5 +- code/modules/holomap/station_holomap.dm | 6 +- code/modules/mining/mine_outcrops.dm | 3 +- code/modules/mob/living/living_defines.dm | 7 + code/modules/mob/living/movement.dm | 45 +++- code/modules/mob/movement.dm | 5 +- code/modules/multiz/structures.dm | 4 +- .../overmap/legacy/ships/computers/helm.dm | 4 +- code/modules/projectiles/projectile.dm | 3 +- code/modules/tables/flipping.dm | 10 +- code/modules/tables/tables.dm | 5 +- 39 files changed, 352 insertions(+), 273 deletions(-) diff --git a/code/__DEFINES/_flags/atom_flags.dm b/code/__DEFINES/_flags/atom_flags.dm index d29d8ee6cdf..afb4dec9521 100644 --- a/code/__DEFINES/_flags/atom_flags.dm +++ b/code/__DEFINES/_flags/atom_flags.dm @@ -156,7 +156,9 @@ DEFINE_BITFIELD(movement_type, list( /// Don't let us buckle people to ourselves. #define BUCKLING_NO_USER_BUCKLE_OTHER_TO_SELF (1<<6) /// Lets the user avoid step checks. -#define BUCKLING_GROUND_HOIST (1<<7) +#define BUCKLING_GROUND_HOIST (1<<7) +/// projects our depth to the buckled object. you usually don't want this. +#define BUCKLING_PROJECTS_DEPTH (1<<8) DEFINE_BITFIELD(buckle_flags, list( BITFIELD(BUCKLING_REQUIRES_RESTRAINTS), @@ -167,4 +169,5 @@ DEFINE_BITFIELD(buckle_flags, list( BITFIELD(BUCKLING_NO_DEFAULT_RESIST), BITFIELD(BUCKLING_NO_USER_BUCKLE_OTHER_TO_SELF), BITFIELD(BUCKLING_GROUND_HOIST), + BITFIELD(BUCKLING_PROJECTS_DEPTH), )) diff --git a/code/__DEFINES/_flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm index bc1d453b201..14beb93e706 100644 --- a/code/__DEFINES/_flags/obj_flags.dm +++ b/code/__DEFINES/_flags/obj_flags.dm @@ -7,10 +7,13 @@ #define ON_BLUEPRINTS (1<<2) /// Prevent people from clicking under us #define OBJ_PREVENT_CLICK_UNDER (1<<3) +/// We ignore depth system when blocking mobs +#define OBJ_IGNORE_MOB_DEPTH (1<<4) DEFINE_BITFIELD(obj_flags, list( BITFIELD(EMAGGED), BITFIELD(CAN_BE_HIT), BITFIELD(ON_BLUEPRINTS), BITFIELD(OBJ_PREVENT_CLICK_UNDER), + BITFIELD(OBJ_IGNORE_MOB_DEPTH), )) diff --git a/code/__DEFINES/procs/do_after.dm b/code/__DEFINES/procs/do_after.dm index 2a8c22cc0f6..24d4fd21fd5 100644 --- a/code/__DEFINES/procs/do_after.dm +++ b/code/__DEFINES/procs/do_after.dm @@ -52,3 +52,5 @@ #define INTERACTING_FOR_ALT_CLICK "alt_click" /// Attempting to resist out of something #define INTERACTING_FOR_RESIST "resist" +/// Climbing a structure +#define INTERACTING_FOR_CLIMB "climb" diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm index 7351b5d8be4..4bda92467ab 100644 --- a/code/game/machinery/computer/atmos_control.dm +++ b/code/game/machinery/computer/atmos_control.dm @@ -26,6 +26,9 @@ icon_keyboard = "pcu_key" density = FALSE light_color = "#00cc00" + depth_level = 0 + depth_projected = FALSE + climb_allowed = FALSE /obj/machinery/computer/atmoscontrol/attack_ai(mob/user) ui_interact(user) diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 34af11784c4..956524447cf 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -7,6 +7,9 @@ use_power = USE_POWER_IDLE idle_power_usage = 300 active_power_usage = 300 + depth_level = 8 + depth_projected = TRUE + climb_allowed = TRUE //blocks_emissive = FALSE var/processing = FALSE diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 734cc897362..66badb710a0 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -507,7 +507,9 @@ light_color = "#5284e7" circuit = /obj/item/circuitboard/med_data/pcu density = FALSE - + depth_level = 0 + depth_projected = FALSE + climb_allowed = FALSE #undef FIELD #undef MED_FIELD diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm index 65b2b5870cc..ba55c1287be 100644 --- a/code/game/machinery/computer/skills.dm +++ b/code/game/machinery/computer/skills.dm @@ -14,6 +14,9 @@ req_one_access = list(ACCESS_COMMAND_BRIDGE) circuit = /obj/item/circuitboard/skills/pcu density = FALSE + depth_level = 0 + depth_projected = FALSE + climb_allowed = FALSE var/obj/item/card/id/scan = null var/authenticated = null var/rank = null diff --git a/code/game/machinery/computer/timeclock_vr.dm b/code/game/machinery/computer/timeclock_vr.dm index 8d18a35c73e..1b8cdfdd51b 100644 --- a/code/game/machinery/computer/timeclock_vr.dm +++ b/code/game/machinery/computer/timeclock_vr.dm @@ -16,6 +16,8 @@ density = FALSE circuit = /obj/item/circuitboard/timeclock clicksound = null + climb_allowed = FALSE + depth_projected = FALSE var/channel = "Common" //Radio channel to announce on var/obj/item/card/id/card // Inserted Id card diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 8eb507be9e9..2f740a0166e 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -15,6 +15,8 @@ icon_state = "cellconsole" circuit = /obj/item/circuitboard/cryopodcontrol density = FALSE + climb_allowed = FALSE + depth_projected = FALSE interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_ALLOW_SILICON var/mode = null diff --git a/code/game/machinery/holopad.dm b/code/game/machinery/holopad.dm index 7f53db68625..dfaf5ab0c7d 100644 --- a/code/game/machinery/holopad.dm +++ b/code/game/machinery/holopad.dm @@ -35,6 +35,8 @@ GLOBAL_VAR_INIT(holopad_connectivity_rebuild_queued, FALSE) active_power_usage = 100 light_range = 1.5 light_power = 0 + depth_projected = FALSE + climb_allowed = FALSE //? balancing /// base power used to project at all diff --git a/code/game/machinery/lathes/lathe.dm b/code/game/machinery/lathes/lathe.dm index 4c60f3c5269..71a0e394180 100644 --- a/code/game/machinery/lathes/lathe.dm +++ b/code/game/machinery/lathes/lathe.dm @@ -25,6 +25,9 @@ circuit = /obj/item/circuitboard/machine/lathe default_deconstruct = 0 SECONDS default_panel = 0 SECONDS + depth_projected = TRUE + depth_level = 8 + climb_allowed = TRUE /// icon state when printing, if any var/active_icon_state diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 949d4d23fdc..4a10872a747 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -4,6 +4,9 @@ w_class = ITEMSIZE_NORMAL // todo: better way, for now, block all rad contamination to interior rad_flags = RAD_BLOCK_CONTENTS + obj_flags = OBJ_IGNORE_MOB_DEPTH + depth_level = 0 + climb_allowed = FALSE //? Flags /// Item flags. diff --git a/code/game/objects/items/poi_items.dm b/code/game/objects/items/poi_items.dm index 5762579fcc9..f94168e7a5c 100644 --- a/code/game/objects/items/poi_items.dm +++ b/code/game/objects/items/poi_items.dm @@ -26,7 +26,6 @@ icon_state = "poireactor" icon_opened = "poireactor_open" icon_closed = "poireactor" - climbable = 0 starts_with = list( /obj/item/fuel_assembly/deuterium = 6) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 33bc578db28..623b05d1d00 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -18,6 +18,26 @@ /// If set, at least one of these accesses are needed to access this object. var/list/req_one_access + //? Climbing + /// people can climb onto us + var/climb_allowed = FALSE + /// people are allowed to knock climbers off of us + var/climb_knockable = TRUE + /// list of people currently climbing on us + /// currently, only /mob/living is allowed to climb + var/list/mob/living/climbing + /// nominal climb delay before modifiers + var/climb_delay = 3.5 SECONDS + + //? Depth + /// logical depth in pixels. people can freely run from high to low objects without being blocked. + /// + /// negative values are ignored as turfs are assumed to be depth 0 + /// unless we change that in the future + var/depth_level = 28 + /// contributes to depth when we're on a turf + var/depth_projected = FALSE + //? Economy /// economic category for objects var/economic_category_obj = ECONOMIC_CATEGORY_OBJ_DEFAULT @@ -163,7 +183,7 @@ /obj/proc/hides_under_flooring() return 0 - /** +/** * This proc is used for telling whether something can pass by this object in a given direction, for use by the pathfinding system. * * Trying to generate one long path across the station will call this proc on every single object on every single tile that we're seeing if we can move through, likely @@ -236,6 +256,157 @@ add_fingerprint(user) ..() +//? Climbing + +/obj/MouseDroppedOn(atom/dropping, mob/user, proximity, params) + if(drag_drop_climb_interaction(user, dropping)) + return CLICKCHAIN_DO_NOT_PROPAGATE + return ..() + +/obj/proc/drag_drop_climb_interaction(mob/user, atom/dropping) + if(!climb_allowed) + return FALSE + if(user != dropping) + return FALSE + // todo: better hinting to user for this + if(buckle_allowed && user.a_intent != INTENT_GRAB) + return FALSE + if(!user.Adjacent(src)) + return FALSE + . = TRUE + INVOKE_ASYNC(src, PROC_REF(attempt_climb_on), user) + +/obj/proc/attempt_climb_on(mob/living/climber, delay_mod = 1) + if(!istype(climber)) + return FALSE + if(!allow_climb_on(climber)) + climber.action_feedback(SPAN_WARNING("You can't climb onto [src]!"), src) + return FALSE + if(INTERACTING_WITH_FOR(climber, src, INTERACTING_FOR_CLIMB)) + return FALSE + climber.visible_action_feedback(SPAN_WARNING("[climber] starts climbing onto \the [src]!"), src, MESSAGE_RANGE_COMBAT_LOUD) + START_INTERACTING_WITH(climber, src, INTERACTING_FOR_CLIMB) + LAZYDISTINCTADD(climbing, climber) + . = do_after(climber, climb_delay * delay_mod, src, mobility_flags = MOBILITY_CAN_MOVE | MOBILITY_CAN_STAND | MOBILITY_IS_STANDING) + if(!INTERACTING_WITH_FOR(climber, src, INTERACTING_FOR_CLIMB)) + . = FALSE + LAZYREMOVE(climbing, climber) + STOP_INTERACTING_WITH(climber, src, INTERACTING_FOR_CLIMB) + if(!allow_climb_on(climber)) + climber.action_feedback(SPAN_WARNING("You couldn't climb onto [src]!"), src) + return FALSE + do_climb_on(climber) + +/obj/proc/allow_climb_on(mob/living/climber) + if(!istype(climber)) + return FALSE + if(!climb_allowed) + return FALSE + if(!climber.Adjacent(src)) + return FALSE + return TRUE + +/obj/proc/do_climb_on(mob/living/climber) + climber.visible_message(SPAN_WARNING("[climber] climbs onto \the [src]!")) + // all this effort just to avoid a splurtstation railing spare ID speedrun incident + var/old_depth = climber.depth_current + if(climber.depth_current < depth_level) + // basically, we don't force move them, we just elevate them to our level + // if something else blocks them, L + ratio + get parried + climber.change_depth(depth_level) + if(!step_towards(climber, do_climb_target(climber))) + climber.change_depth(old_depth) + +/obj/proc/do_climb_target(mob/living/climber) + return get_turf(src) + +/obj/attack_hand(mob/user, list/params) + . = ..() + if(.) + return + if(length(climbing) && user.a_intent == INTENT_HARM) + user.visible_message(SPAN_WARNING("[user] slams against \the [src]!")) + user.do_attack_animation(src) + shake_climbers() + return TRUE + +/obj/proc/shake_climbers() + for(var/mob/living/climber as anything in climbing) + climber.afflict_knockdown(1 SECONDS) + climber.visible_message(SPAN_WARNING("[climber] is toppled off of \the [src]!")) + STOP_INTERACTING_WITH(climber, src, INTERACTING_FOR_CLIMB) + climbing = null + + // disabled old, but fun code that knocks people on their ass if something is shaken without climbers + // being ontop of it + // consider re-enabling this sometime. + /* + for(var/mob/living/M in get_turf(src)) + if(M.lying) return //No spamming this on people. + + M.afflict_paralyze(20 * 3) + to_chat(M, "You topple as \the [src] moves under you!") + + if(prob(25)) + + var/damage = rand(15,30) + var/mob/living/carbon/human/H = M + if(!istype(H)) + to_chat(H, "You land heavily!") + M.adjustBruteLoss(damage) + return + + var/obj/item/organ/external/affecting + + switch(pick(list("ankle","wrist","head","knee","elbow"))) + if("ankle") + affecting = H.get_organ(pick(BP_L_FOOT, BP_R_FOOT)) + if("knee") + affecting = H.get_organ(pick(BP_L_LEG, BP_R_LEG)) + if("wrist") + affecting = H.get_organ(pick(BP_L_HAND, BP_R_HAND)) + if("elbow") + affecting = H.get_organ(pick(BP_L_ARM, BP_R_ARM)) + if("head") + affecting = H.get_organ(BP_HEAD) + + if(affecting) + to_chat(M, "You land heavily on your [affecting.name]!") + affecting.take_damage(damage, 0) + if(affecting.parent) + affecting.parent.add_autopsy_data("Misadventure", damage) + else + to_chat(H, "You land heavily!") + H.adjustBruteLoss(damage) + + H.UpdateDamageIcon() + H.update_health() + */ + +//? Materials + +/obj/get_materials() + . = materials.Copy() + +/** + * initialize materials + */ +/obj/proc/init_materials() + if(!isnull(material_defaults)) + set_material_parts(material_defaults) + for(var/key in material_defaults) + var/mat = material_defaults[key] + var/amt = material_parts[key] + materials[mat] += amt + +/** + * sets our material parts to a list by key / value + * this does not update [materials], you have to do that manually + * this is usually done in init using init_materials + */ +/obj/proc/set_material_parts(list/parts) + return + //? Resists /** @@ -308,27 +479,3 @@ var/shake_dir = pick(-1, 1) animate(src, transform=turn(matrix(), 8*shake_dir), pixel_x=init_px + 2*shake_dir, time=1) animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING) - -//? materials - -/obj/get_materials() - . = materials.Copy() - -/** - * initialize materials - */ -/obj/proc/init_materials() - if(!isnull(material_defaults)) - set_material_parts(material_defaults) - for(var/key in material_defaults) - var/mat = material_defaults[key] - var/amt = material_parts[key] - materials[mat] += amt - -/** - * sets our material parts to a list by key / value - * this does not update [materials], you have to do that manually - * this is usually done in init using init_materials - */ -/obj/proc/set_material_parts(list/parts) - return diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index f050a280f3f..f97ca561d5e 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -5,11 +5,7 @@ // todo: rename to default_unanchor, allow generic structure unanchoring. var/allow_unanchor = FALSE - - var/climbable - var/climb_delay = 3.5 SECONDS - var/breakable - var/list/climbers = list() + var/breakable = FALSE var/list/connections var/list/other_connections @@ -19,9 +15,6 @@ /obj/structure/Initialize(mapload) . = ..() - if(climbable) - add_obj_verb(src, /obj/structure/proc/climb_on) - if(smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK)) QUEUE_SMOOTH(src) QUEUE_SMOOTH_NEIGHBORS(src) @@ -48,11 +41,6 @@ if(H.species.can_shred(user)) attack_generic(user,1,"slices") - if(climbers.len && !(user in climbers)) - user.visible_message("[user.name] shakes \the [src].", \ - "You shake \the [src].") - structure_shaken() - return ..() /obj/structure/attack_tk() @@ -70,122 +58,17 @@ if(3.0) return -/obj/structure/proc/climb_on() - - set name = "Climb structure" - set desc = "Climbs onto a structure." - set category = "Object" - set src in oview(1) - - do_climb(usr) - -/obj/structure/MouseDroppedOnLegacy(mob/target, mob/user) - - var/mob/living/H = user - if(istype(H) && can_climb(H) && target == user) - do_climb(target) - else - return ..() - -/obj/structure/proc/can_climb(var/mob/living/user, post_climb_check=0) - if (!climbable || !can_touch(user) || (!post_climb_check && (user in climbers))) - return 0 - - if (!user.Adjacent(src)) - to_chat(user, "You can't climb there, the way is blocked.") - return 0 - - var/obj/occupied = turf_is_crowded() - if(occupied) - to_chat(user, "There's \a [occupied] in the way.") - return 0 - return 1 - /obj/structure/proc/turf_is_crowded() var/turf/T = get_turf(src) if(!T || !istype(T)) return 0 for(var/obj/O in T.contents) - if(istype(O,/obj/structure)) - var/obj/structure/S = O - if(S.climbable) continue + if(O.climb_allowed) + continue if(O && O.density && !(O.atom_flags & ATOM_BORDER)) //ATOM_BORDER structures are handled by the Adjacent() check. return O return 0 -// todo: climbable obj-level (to avoid element/signal spam) -/obj/structure/proc/do_climb(var/mob/living/user) - if (!can_climb(user)) - return - - usr.visible_message("[user] starts climbing onto \the [src]!") - climbers |= user - - if(!do_after(user, issmall(user) ? climb_delay * 0.6 : climb_delay, src, mobility_flags = MOBILITY_CAN_MOVE | MOBILITY_CAN_USE)) - climbers -= user - return - - if (!can_climb(user, post_climb_check=1)) - climbers -= user - return - - var/old = pass_flags & (ATOM_PASS_BUCKLED) - pass_flags |= ATOM_PASS_BUCKLED - usr.locationTransitForceMove(get_turf(src), allow_buckled = TRUE, allow_pulled = FALSE, allow_grabbed = TRUE) - pass_flags = (pass_flags & ~(ATOM_PASS_BUCKLED)) | (old & ATOM_PASS_BUCKLED) - - if (get_turf(user) == get_turf(src)) - usr.visible_message("[user] climbs onto \the [src]!") - climbers -= user - -/obj/structure/proc/structure_shaken() - for(var/mob/living/M in climbers) - M.afflict_paralyze(20 * 1) - to_chat(M, "You topple as you are shaken off \the [src]!") - climbers.Cut(1,2) - - for(var/mob/living/M in get_turf(src)) - if(M.lying) return //No spamming this on people. - - M.afflict_paralyze(20 * 3) - to_chat(M, "You topple as \the [src] moves under you!") - - if(prob(25)) - - var/damage = rand(15,30) - var/mob/living/carbon/human/H = M - if(!istype(H)) - to_chat(H, "You land heavily!") - M.adjustBruteLoss(damage) - return - - var/obj/item/organ/external/affecting - - switch(pick(list("ankle","wrist","head","knee","elbow"))) - if("ankle") - affecting = H.get_organ(pick(BP_L_FOOT, BP_R_FOOT)) - if("knee") - affecting = H.get_organ(pick(BP_L_LEG, BP_R_LEG)) - if("wrist") - affecting = H.get_organ(pick(BP_L_HAND, BP_R_HAND)) - if("elbow") - affecting = H.get_organ(pick(BP_L_ARM, BP_R_ARM)) - if("head") - affecting = H.get_organ(BP_HEAD) - - if(affecting) - to_chat(M, "You land heavily on your [affecting.name]!") - affecting.take_damage(damage, 0) - if(affecting.parent) - affecting.parent.add_autopsy_data("Misadventure", damage) - else - to_chat(H, "You land heavily!") - H.adjustBruteLoss(damage) - - H.UpdateDamageIcon() - H.update_health() - return - // todo: remove /obj/structure/proc/can_touch(var/mob/user) if (!user) diff --git a/code/game/objects/structures/cliff.dm b/code/game/objects/structures/cliff.dm index e6100d7aaa8..8dae834f31c 100644 --- a/code/game/objects/structures/cliff.dm +++ b/code/game/objects/structures/cliff.dm @@ -31,7 +31,7 @@ two tiles on initialization, and which way a cliff is facing may change during m anchored = TRUE density = TRUE opacity = FALSE - climbable = TRUE + climb_allowed = TRUE climb_delay = 10 SECONDS // TODO: IMPLEMENT THIS AGAIN, this was done in a horrifically slow and stupid way // block_turf_edges = TRUE // Don't want turf edges popping up from the cliff edge. @@ -219,19 +219,24 @@ two tiles on initialization, and which way a cliff is facing may change during m sleep(5) bottom_cliff.fall_off_cliff(L) -/obj/structure/cliff/can_climb(mob/living/user, post_climb_check = FALSE) +/obj/structure/cliff/allow_climb_on(mob/living/climber) + . = ..() + if(!.) + return + //! LEGAYC CODE START + var/mob/living/user = climber // Cliff climbing requires climbing gear. if(ishuman(user)) var/mob/living/carbon/human/H = user var/obj/item/clothing/shoes/shoes = H.shoes if(shoes && shoes.rock_climbing) - return ..() // Do the other checks too. + return TRUE var/obj/item/held = H.get_active_held_item() if(held && istype(held, /obj/item/pickaxe/icepick)) - return ..() //climb rock wall with ice pick. Makes sense. - + return TRUE to_chat(user, SPAN_WARNING( "\The [src] is too steep to climb unassisted.")) return FALSE + //! END // This tells AI mobs to not be dumb and step off cliffs willingly. /obj/structure/cliff/is_safe_to_step(mob/living/L) diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index f97e309e16a..cbcb39c99c7 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -5,7 +5,9 @@ desc = "A rectangular steel crate." icon = 'icons/obj/closets/bases/crate.dmi' closet_appearance = /singleton/closet_appearance/crate - climbable = 1 + climb_allowed = TRUE + depth_projected = TRUE + depth_level = 8 var/points_per_crate = 5 // mouse_drag_pointer = MOUSE_ACTIVE_POINTER //??? var/rigged = 0 @@ -44,9 +46,7 @@ O.forceMove(get_turf(src)) icon_state = icon_opened src.opened = 1 - - if(climbable) - structure_shaken() + shake_climbers() return 1 /obj/structure/closet/crate/close() diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm index 69405eb9c4f..81ac90e359f 100644 --- a/code/game/objects/structures/fence.dm +++ b/code/game/objects/structures/fence.dm @@ -94,11 +94,9 @@ if(MEDIUM_HOLE) visible_message(SPAN_NOTICE("\The [user] cuts into \the [src] some more.")) to_chat(user, SPAN_NOTICE("You could probably fit yourself through that hole now. Although climbing through would be much faster if you made it even bigger.")) - climbable = TRUE if(LARGE_HOLE) visible_message(SPAN_NOTICE("\The [user] completely cuts through \the [src].")) to_chat(user, SPAN_NOTICE("The hole in \the [src] is now big enough to walk through.")) - climbable = FALSE update_cut_status() return TRUE @@ -106,15 +104,20 @@ if(!cuttable) return density = TRUE + climb_allowed = initial(climb_allowed) + climb_delay = initial(climb_delay) switch(hole_size) if(NO_HOLE) icon_state = initial(icon_state) if(MEDIUM_HOLE) icon_state = "straight-cut2" + climb_allowed = TRUE if(LARGE_HOLE) icon_state = "straight-cut3" density = FALSE + climb_allowed = TRUE + climb_delay = 0 //FENCE DOORS diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index e30cd90d92d..ca18e4e9d96 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -6,6 +6,8 @@ density = TRUE plane = TURF_PLANE w_class = ITEMSIZE_HUGE + depth_level = 24 + depth_projected = TRUE var/state = 0 var/health = 200 diff --git a/code/game/objects/structures/gravemarker.dm b/code/game/objects/structures/gravemarker.dm index eb073df8cd6..4e52b35ec66 100644 --- a/code/game/objects/structures/gravemarker.dm +++ b/code/game/objects/structures/gravemarker.dm @@ -5,7 +5,8 @@ density = TRUE pass_flags_self = ATOM_PASS_THROWN | ATOM_PASS_CLICK | ATOM_PASS_TABLE | ATOM_PASS_OVERHEAD_THROW - climbable = TRUE + climb_allowed = TRUE + depth_level = 8 anchored = TRUE layer = ABOVE_JUNK_LAYER diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index 7b04af27eae..4e706767133 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -7,7 +7,8 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) icon_state = "cart" anchored = 0 density = 1 - climbable = 1 + climb_allowed = TRUE + depth_level = 20 atom_flags = OPENCONTAINER //copypaste sorry var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite diff --git a/code/game/objects/structures/ledges.dm b/code/game/objects/structures/ledges.dm index 059a5916a6f..4e715093f57 100644 --- a/code/game/objects/structures/ledges.dm +++ b/code/game/objects/structures/ledges.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/ledges.dmi' pass_flags_self = ATOM_PASS_TABLE | ATOM_PASS_THROWN | ATOM_PASS_CLICK | ATOM_PASS_OVERHEAD_THROW | ATOM_PASS_BUCKLED density = TRUE - climbable = TRUE + climb_allowed = TRUE anchored = TRUE var/solidledge = 1 atom_flags = ATOM_BORDER @@ -19,7 +19,7 @@ icon = 'icons/obj/ledges.dmi' density = TRUE pass_flags_self = ATOM_PASS_TABLE | ATOM_PASS_THROWN | ATOM_PASS_CLICK | ATOM_PASS_OVERHEAD_THROW | ATOM_PASS_BUCKLED - climbable = TRUE + climb_allowed = TRUE anchored = TRUE layer = STAIRS_LAYER @@ -51,37 +51,3 @@ if(!(get_dir(src, newLoc) & dir)) return TRUE return FALSE - -/obj/structure/ledge/do_climb(var/mob/living/user) - if(!can_climb(user)) - return - - usr.visible_message("[user] starts climbing onto \the [src]!") - climbers |= user - - if(!do_after(user,(issmall(user) ? 20 : 34))) - climbers -= user - return - - if(!can_climb(user, post_climb_check=1)) - climbers -= user - return - - if(get_turf(user) == get_turf(src)) - usr.forceMove(get_step(src, src.dir)) - else - usr.forceMove(get_turf(src)) - - usr.visible_message("[user] climbed over \the [src]!") - climbers -= user - -/obj/structure/ledge/can_climb(var/mob/living/user, post_climb_check=0) - if(!..()) - return 0 - - if(get_turf(user) == get_turf(src)) - var/obj/occupied = neighbor_turf_impassable() - if(occupied) - to_chat(user, "You can't climb there, there's \a [occupied] in the way.") - return 0 - return 1 diff --git a/code/game/objects/structures/low_wall.dm b/code/game/objects/structures/low_wall.dm index 333903bdf19..86df124311b 100644 --- a/code/game/objects/structures/low_wall.dm +++ b/code/game/objects/structures/low_wall.dm @@ -25,6 +25,10 @@ GLOBAL_LIST_INIT(wallframe_typecache, typecacheof(list( smoothing_flags = SMOOTH_BITMASK smoothing_groups = (SMOOTH_GROUP_LOW_WALL) canSmoothWith = (SMOOTH_GROUP_AIRLOCK+SMOOTH_GROUP_LOW_WALL+SMOOTH_GROUP_WALLS) + depth_projected = TRUE + depth_level = 8 + climb_allowed = TRUE + climb_delay = 2.0 SECONDS plane = OBJ_PLANE var/default_material = MAT_STEEL diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm index 8b086f10d7e..51e97f054af 100644 --- a/code/game/objects/structures/mop_bucket.dm +++ b/code/game/objects/structures/mop_bucket.dm @@ -4,7 +4,8 @@ icon = 'icons/obj/janitor.dmi' icon_state = "mopbucket" density = 1 - climbable = 1 + climb_allowed = TRUE + depth_level = 8 w_class = ITEMSIZE_NORMAL pressure_resistance = 5 atom_flags = OPENCONTAINER diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm index 1178892d49f..e6b9b7ea4ca 100644 --- a/code/game/objects/structures/railing.dm +++ b/code/game/objects/structures/railing.dm @@ -5,7 +5,8 @@ icon = 'icons/obj/railing.dmi' density = TRUE pass_flags_self = ATOM_PASS_THROWN | ATOM_PASS_CLICK | ATOM_PASS_TABLE | ATOM_PASS_OVERHEAD_THROW | ATOM_PASS_CLICK | ATOM_PASS_BUCKLED - climbable = TRUE + climb_allowed = TRUE + depth_level = 24 layer = WINDOW_LAYER anchored = TRUE atom_flags = ATOM_BORDER @@ -25,8 +26,6 @@ // TODO - "constructed" is not passed to us. We need to find a way to do this safely. if (constructed) // player-constructed railings anchored = 0 - if(climbable) - add_obj_verb(src, /obj/structure/proc/climb_on) if(src.anchored) update_icon(0) @@ -46,6 +45,10 @@ return TRUE if(!(get_dir(src, newLoc) & dir)) return TRUE + if(isliving(mover)) + var/mob/living/L = mover + if((L.depth_current >= depth_level) && !(obj_flags & OBJ_IGNORE_MOB_DEPTH)) + return TRUE return !density /obj/structure/railing/examine(mob/user, dist) @@ -268,55 +271,13 @@ switch(severity) if(1.0) qdel(src) - return if(2.0) qdel(src) - return if(3.0) qdel(src) - return - else - return - -// Duplicated from structures.dm, but its a bit different. -/obj/structure/railing/do_climb(var/mob/living/user) - if(!can_climb(user)) - return - - usr.visible_message("[user] starts climbing onto \the [src]!") - climbers |= user - - if(!do_after(user,(issmall(user) ? 20 : 34))) - climbers -= user - return - - if(!can_climb(user, post_climb_check=1)) - climbers -= user - return - - if(get_turf(user) == get_turf(src)) - usr.locationTransitForceMove(get_step(src, src.dir), allow_buckled = TRUE, allow_pulled = FALSE, allow_grabbed = TRUE) - else - usr.locationTransitForceMove(get_turf(src), allow_buckled = TRUE, allow_pulled = FALSE, allow_grabbed = TRUE) - - usr.visible_message("[user] climbed over \the [src]!") - if(!anchored) take_damage(maxhealth) // Fatboy - climbers -= user - -/obj/structure/railing/can_climb(var/mob/living/user, post_climb_check=0) - if(!..()) - return 0 - - // Normal can_climb() handles climbing from adjacent turf onto our turf. But railings also allow climbing - // from our turf onto an adjacent! If that is the case we need to do checks for that too... - if(get_turf(user) == get_turf(src)) - var/obj/occupied = neighbor_turf_impassable() - if(occupied) - to_chat(user, "You can't climb there, there's \a [occupied] in the way.") - return 0 - return 1 // TODO - This here might require some investigation +// todo: no, this here needs to be thrown out, we have depth system now /obj/structure/proc/neighbor_turf_impassable() var/turf/T = get_step(src, src.dir) if(!T || !istype(T)) @@ -326,6 +287,10 @@ for(var/obj/O in T.contents) if(istype(O,/obj/structure)) var/obj/structure/S = O - if(S.climbable) continue + if(S.climb_allowed) + continue if(O && O.density && !(O.atom_flags & ATOM_BORDER && !(turn(O.dir, 180) & dir))) return O + +/obj/structure/railing/do_climb_target(mob/living/climber) + return climber.loc == get_turf(src)? get_step(src, dir) : ..() diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index 20c5fe87b59..c615c6156d1 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -346,7 +346,9 @@ density = TRUE anchored = TRUE pass_flags_self = ATOM_PASS_THROWN | ATOM_PASS_OVERHEAD_THROW - climbable = TRUE + climb_allowed = TRUE + depth_projected = TRUE + depth_level = 24 /obj/structure/memorial/small icon = 'icons/obj/structures.dmi' diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 3e776a064e9..84c2615ccac 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -566,12 +566,7 @@ return TRUE return FALSE -//? Radiation - -/turf/proc/update_rad_insulation() - rad_insulation_contents = 1 - -//? atom color - we don't use the expensive system. +//? Atom Color - we don't use the expensive system. /turf/get_atom_colour() return color @@ -589,3 +584,20 @@ if(isnull(other.color)) return color = other.color + +//? Depth + +/** + * gets overall depth level for stuff standing on us + */ +/turf/proc/depth_level() + . = 0 + for(var/obj/O in src) + if(!O.depth_projected) + continue + . = max(., O.depth_level) + +//? Radiation + +/turf/proc/update_rad_insulation() + rad_insulation_contents = 1 diff --git a/code/modules/atmospherics/machinery/machinery.dm b/code/modules/atmospherics/machinery/machinery.dm index 0db1aeffbf9..dfe8bf9a638 100644 --- a/code/modules/atmospherics/machinery/machinery.dm +++ b/code/modules/atmospherics/machinery/machinery.dm @@ -20,6 +20,8 @@ Pipelines + Other Objects -> Pipe network // why block contents? so you ventcrawling little fucks don't pull a 2020 Citadel Main. rad_flags = RAD_BLOCK_CONTENTS | RAD_NO_CONTAMINATE atom_colouration_system = FALSE + climb_allowed = FALSE + depth_projected = FALSE ///The color of the pipe var/pipe_color diff --git a/code/modules/events/meteor_strike_vr.dm b/code/modules/events/meteor_strike_vr.dm index a65c3e3f754..4c306f10bce 100644 --- a/code/modules/events/meteor_strike_vr.dm +++ b/code/modules/events/meteor_strike_vr.dm @@ -77,8 +77,9 @@ desc = "A big hunk of star-stuff." icon = 'icons/obj/meteor.dmi' icon_state = "large" - density = 1 - climbable = 1 + density = TRUE + climb_allowed = TRUE + depth_level = 16 /obj/structure/meteorite/Initialize(mapload) . = ..() diff --git a/code/modules/holomap/station_holomap.dm b/code/modules/holomap/station_holomap.dm index 7d4ceb7f7b3..d1f740418da 100644 --- a/code/modules/holomap/station_holomap.dm +++ b/code/modules/holomap/station_holomap.dm @@ -6,12 +6,14 @@ desc = "A virtual map of the surrounding station." icon = 'icons/obj/machines/stationmap.dmi' icon_state = "station_map" - anchored = 1 - density = 0 + anchored = TRUE + density = FALSE use_power = USE_POWER_IDLE idle_power_usage = 10 active_power_usage = 500 circuit = /obj/item/circuitboard/station_map + depth_projected = FALSE + climb_allowed = FALSE // TODO - Port use_auto_lights from /vg - for now declare here var/use_auto_lights = 1 diff --git a/code/modules/mining/mine_outcrops.dm b/code/modules/mining/mine_outcrops.dm index aeaa981eda9..3cf2bc1c7bd 100644 --- a/code/modules/mining/mine_outcrops.dm +++ b/code/modules/mining/mine_outcrops.dm @@ -4,7 +4,8 @@ icon = 'icons/obj/outcrop.dmi' density = TRUE pass_flags_self = ATOM_PASS_THROWN | ATOM_PASS_OVERHEAD_THROW - climbable = TRUE + climb_allowed = TRUE + depth_level = 12 anchored = TRUE icon_state = "outcrop" var/mindrop = 5 diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 50b762dfef8..f21a67fc0b0 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -8,6 +8,7 @@ /mob/living see_invisible = SEE_INVISIBLE_LIVING movable_flags = MOVABLE_NO_THROW_SPIN | MOVABLE_NO_THROW_DAMAGE_SCALING | MOVABLE_NO_THROW_SPEED_SCALING + buckle_flags = BUCKLING_PROJECTS_DEPTH //* Health and life related vars *// /// Maximum health that should be possible. Avoid adjusting this if you can, and instead use modifiers datums. @@ -144,3 +145,9 @@ var/getting_up_penalized /// last delay before modifications while getting up - used by resist_a_rest, so reducing damage / whatever doesn't leave you with the same delay var/getting_up_original + + //? movement + /// current depth on turf in pixels + var/depth_current = 0 + /// set during move: staged depth; on successful move, we update depth_current if it's different. + var/tmp/depth_staged = 0 diff --git a/code/modules/mob/living/movement.dm b/code/modules/mob/living/movement.dm index 7e8dc397844..e7c3aa5f340 100644 --- a/code/modules/mob/living/movement.dm +++ b/code/modules/mob/living/movement.dm @@ -8,15 +8,26 @@ if(MOVE_INTENT_WALK) . += config_legacy.walk_speed +// todo: all this depth staged stuff is stupid and it should all be on /turf and cached someday +// this is however, faster, so that'll be a very long 'someday'. + /mob/living/Move(atom/newloc, direct, glide_size_override) + depth_staged = 0 if(buckled && buckled.loc != newloc) return FALSE - return ..() + . = ..() + depth_staged = null -/mob/living/Moved() +/mob/living/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) . = ..() if(s_active && !CheapReachability(s_active)) s_active.close(src) + if(forced && isnull(depth_staged) && isturf(loc)) + var/turf/T = loc + depth_staged = T.depth_level() + if(!isnull(depth_staged)) + change_depth(depth_staged) + depth_staged = null /mob/living/forceMove(atom/destination) if(buckled && (buckled.loc != destination)) @@ -44,6 +55,16 @@ return TRUE return ..() +/mob/living/CanPassThrough(atom/blocker, turf/target, blocker_opinion) + . = ..() + if(isobj(blocker)) + var/obj/O = blocker + if(O.depth_projected) + // FINE ILL USE UNLINT INSTEAD OF REMOVE PURITY + UNLINT(depth_staged = max(depth_staged, O.depth_level)) + if(!(O.obj_flags & OBJ_IGNORE_MOB_DEPTH) && O.depth_level <= depth_current) + return TRUE + /mob/living/can_cross_under(atom/movable/mover) if(isliving(mover)) var/mob/living/L = mover @@ -84,6 +105,8 @@ return FALSE return TRUE +//? Bumping / Crawling + /mob/living/Bump(atom/A) var/skip_atom_bump_handling if(throwing) @@ -357,3 +380,21 @@ // restore dir if needed if(their_dir) pushing.setDir(their_dir) + +//? Depth + +/mob/living/proc/change_depth(new_depth) + // depth is propagated up/down our buckled objects, and overridden by what we're buckled to + if(isliving(buckled) && (buckled.buckle_flags & BUCKLING_PROJECTS_DEPTH)) + var/mob/living/L = buckled + new_depth = L.depth_current + else if(isobj(buckled) && (buckled.buckle_flags & BUCKLING_PROJECTS_DEPTH)) + var/obj/O = buckled + new_depth = O.depth_level + if(new_depth == depth_current) + return + . = new_depth - depth_current + depth_current = new_depth + pixel_y += . + for(var/mob/living/L in buckled_mobs) + L.change_depth(new_depth) diff --git a/code/modules/mob/movement.dm b/code/modules/mob/movement.dm index ab0cb5a3774..a1d8a8784a6 100644 --- a/code/modules/mob/movement.dm +++ b/code/modules/mob/movement.dm @@ -519,14 +519,15 @@ // Called when a mob successfully moves. // Would've been an /atom/movable proc but it caused issues. -/mob/Moved(atom/oldloc) +/mob/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) . = ..() client?.parallax_holder?.Update() for(var/obj/O in contents) - O.on_loc_moved(oldloc) + O.on_loc_moved(old_loc) reset_pixel_shifting() // Received from Moved(), useful for items that need to know that their loc just moved. +// todo: REMOVE, this is bad for performance. /obj/proc/on_loc_moved(atom/oldloc) return diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm index 9fe6bd1c69d..e14fd0f798a 100644 --- a/code/modules/multiz/structures.dm +++ b/code/modules/multiz/structures.dm @@ -192,7 +192,7 @@ icon_state = "stair_u" opacity = TRUE density = TRUE // Too high to simply step up on - climbable = TRUE // But they can be climbed if the bottom is out + climb_allowed = TRUE var/obj/structure/stairs/top/top = null var/obj/structure/stairs/bottom/bottom = null @@ -265,7 +265,7 @@ /obj/structure/stairs/middle/MouseDroppedOnLegacy(mob/target, mob/user) . = ..() if(check_integrity()) - do_climb(user) + do_climb_on(user) transition_atom(user, get_turf(top)) // You can't really drag things when you have to climb up the gap in the stairs yourself /obj/structure/stairs/middle/Bumped(mob/user) diff --git a/code/modules/overmap/legacy/ships/computers/helm.dm b/code/modules/overmap/legacy/ships/computers/helm.dm index e90886ee0c1..c1a1c019300 100644 --- a/code/modules/overmap/legacy/ships/computers/helm.dm +++ b/code/modules/overmap/legacy/ships/computers/helm.dm @@ -282,7 +282,9 @@ GLOBAL_LIST_EMPTY(all_waypoints) icon_keyboard = null icon_screen = null circuit = /obj/item/circuitboard/nav/tele - density = 0 + density = FALSE + depth_projected = FALSE + climb_allowed = FALSE /obj/machinery/computer/ship/navigation/telescreen/update_icon() if(machine_stat & NOPOWER || machine_stat & BROKEN) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index d2e2b3d3b6f..bf7d6b858af 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -10,7 +10,8 @@ anchored = TRUE unacidable = TRUE pass_flags = ATOM_PASS_TABLE - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + depth_level = INFINITY // nothing should be passing over us from depth ////TG PROJECTILE SYTSEM //Projectile stuff diff --git a/code/modules/tables/flipping.dm b/code/modules/tables/flipping.dm index e271b22d138..b3f7b6cefd0 100644 --- a/code/modules/tables/flipping.dm +++ b/code/modules/tables/flipping.dm @@ -26,11 +26,7 @@ return usr.visible_message("[usr] flips \the [src]!") - - if(climbable) - structure_shaken() - - return + shake_climbers() /obj/structure/table/proc/unflipping_check(var/direction) @@ -86,7 +82,7 @@ if(dir != NORTH) plane = MOB_PLANE layer = ABOVE_MOB_LAYER - climbable = 0 //flipping tables allows them to be used as makeshift barriers + climb_delay = 10 SECONDS flipped = 1 atom_flags |= ATOM_BORDER for(var/D in list(turn(direction, 90), turn(direction, -90))) @@ -105,7 +101,7 @@ reset_plane_and_layer() flipped = 0 - climbable = initial(climbable) + climb_delay = initial(climb_delay) atom_flags &= ~ATOM_BORDER for(var/D in list(turn(dir, 90), turn(dir, -90))) var/obj/structure/table/T = locate() in get_step(src.loc,D) diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm index 06e121332be..9cca6dc8612 100644 --- a/code/modules/tables/tables.dm +++ b/code/modules/tables/tables.dm @@ -8,7 +8,6 @@ var/list/table_icon_cache = list() density = TRUE pass_flags_self = ATOM_PASS_THROWN | ATOM_PASS_CLICK | ATOM_PASS_TABLE | ATOM_PASS_OVERHEAD_THROW | ATOM_PASS_BUCKLED anchored = TRUE - climbable = TRUE layer = TABLE_LAYER surgery_odds = 66 connections = list("nw0", "ne0", "sw0", "se0") @@ -17,6 +16,10 @@ var/list/table_icon_cache = list() smoothing_groups = (SMOOTH_GROUP_TABLES) canSmoothWith = (SMOOTH_GROUP_TABLES + SMOOTH_GROUP_LOW_WALL) + climb_allowed = TRUE + depth_level = 8 + depth_projected = TRUE + var/flipped = 0 var/maxhealth = 10 var/health = 10