diff --git a/code/datums/elements/waddling.dm b/code/datums/elements/waddling.dm index ef2e73b67a5..d85129b070b 100644 --- a/code/datums/elements/waddling.dm +++ b/code/datums/elements/waddling.dm @@ -19,7 +19,8 @@ Waddle(target) /datum/element/waddling/proc/Waddle(atom/movable/target) - animate(target, pixel_z = 4, time = 0) + var/current_pixel_z = target.pixel_z + animate(target, pixel_z = target.pixel_z + 4, time = 0) var/prev_trans = matrix(target.transform) - animate(pixel_z = 0, transform = turn(target.transform, pick(-12, 0, 12)), time = 2) - animate(pixel_z = 0, transform = prev_trans, time = 0) + animate(pixel_z = target.pixel_z - 4, transform = turn(target.transform, pick(-12, 0, 12)), time = 2) + animate(pixel_z = current_pixel_z, transform = prev_trans, time = 0) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index c2763b987df..1b358fe1acf 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -565,6 +565,8 @@ if(isspaceturf(get_turf(user))) // Can't fall onto nothing. return + user.pixel_z = initial(user.pixel_z) + if(user.m_intent == MOVE_INTENT_RUN) user.Weaken(10 SECONDS) else diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 47ba86c7220..0397bc662de 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -32,6 +32,8 @@ return ..() /obj/structure/Destroy() + if(climbable) + structure_gone(src) if(SSticker) GLOB.cameranet.updateVisibility(src) if(smooth) @@ -49,6 +51,9 @@ if(!..()) return FALSE + if(climbable) + structure_gone(old) + if(creates_cover) if(isturf(old)) REMOVE_TRAIT(old, TRAIT_TURF_COVERED, UNIQUE_TRAIT_SOURCE(src)) @@ -56,7 +61,6 @@ ADD_TRAIT(loc, TRAIT_TURF_COVERED, UNIQUE_TRAIT_SOURCE(src)) return TRUE - /obj/structure/has_prints() return TRUE @@ -79,6 +83,32 @@ do_climb(usr) +/obj/structure/proc/animate_jumping_off(mob/living/user) + if(!user.flying && user.mob_has_gravity()) + var/delay = user.movement_delay()/4 + sleep(delay) + animate(user, pixel_z = initial(user.pixel_z), time = 3, easing = BACK_EASING|EASE_IN) + +/obj/structure/proc/animate_climb(mob/living/user) + if(!istype(user)) + return + if(!user.checkpass(PASSTABLE) && !user.flying && user.mob_size > MOB_SIZE_SMALL) + var/delay = user.movement_delay()/2 + sleep(delay) + animate(user, pixel_z = 16, time = 1, easing = LINEAR_EASING) + if(user.floating) + user.float(TRUE) + +/obj/structure/Uncrossed(atom/movable/mover) + . = ..() + if(!istype(mover, /mob/living)) + return + if(climbable) + var/turf/T = get_turf(mover) + var/obj/structure/other_structure = locate(/obj/structure) in T + if(!other_structure?.climbable) + animate_jumping_off(mover) + /obj/structure/MouseDrop_T(atom/movable/dropping, mob/user, params) . = ..() if(!. && dropping == user) @@ -94,18 +124,28 @@ return T return null -/obj/structure/proc/do_climb(var/mob/living/user) +/obj/structure/proc/climb_check(mob/living/user) + if(user.mob_size == MOB_SIZE_SMALL) + return FALSE + if(user.flying) + return FALSE if(!can_touch(user) || !climbable) return FALSE var/blocking_object = density_check() if(blocking_object) - to_chat(user, "You cannot climb [src], as it is blocked by \a [blocking_object]!") + to_chat(user, span_warning("You cannot climb [src], as it is blocked by \a [blocking_object]!")) return FALSE - var/turf/T = src.loc - if(!T || !istype(T)) return FALSE + if(!T || !istype(T)) + return FALSE - usr.visible_message("[user] starts climbing onto \the [src]!") + return TRUE + +/obj/structure/proc/do_climb(mob/living/user) + if(!climb_check(user)) + return FALSE + + user.visible_message(span_warning("[user] starts climbing onto \the [src]!")) climber = user if(!do_after(user, 50, target = src)) climber = null @@ -115,12 +155,13 @@ climber = null return FALSE - usr.loc = get_turf(src) + user.loc = get_turf(src) + animate_climb(user) + if(get_turf(user) == get_turf(src)) - usr.visible_message("[user] climbs onto \the [src]!") + user.visible_message(span_warning("[user] climbs onto \the [src]!")) clumse_stuff(climber) - climber = null return TRUE @@ -165,49 +206,65 @@ AM.force /= force_mult AM.throwforce /= force_mult +/obj/structure/proc/get_fall_damage(mob/living/L) + if(prob(25)) + + var/damage = rand(15,30) + var/mob/living/carbon/human/H = L + if(!istype(H)) + to_chat(H, span_warning("You land heavily!")) + L.adjustBruteLoss(damage) + return + + var/obj/item/organ/external/affecting + + switch(pick(list("ankle","wrist","head","knee","elbow"))) + if("ankle") + affecting = H.get_organ(pick(BODY_ZONE_PRECISE_L_FOOT, BODY_ZONE_PRECISE_R_FOOT)) + if("knee") + affecting = H.get_organ(pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + if("wrist") + affecting = H.get_organ(pick(BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND)) + if("elbow") + affecting = H.get_organ(pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) + if("head") + affecting = H.get_organ(BODY_ZONE_HEAD) + + if(affecting) + to_chat(L, span_warning("You land heavily on your [affecting.name]!")) + affecting.receive_damage(damage, 0) + if(affecting.parent) + affecting.parent.add_autopsy_data("Misadventure", damage) + else + to_chat(H, span_warning("You land heavily!")) + H.adjustBruteLoss(damage) + + H.UpdateDamageIcon() + +/obj/structure/proc/structure_gone(atom/location) + for(var/mob/living/carbon/human/H in get_turf(location)) + H.pixel_z = initial(H.pixel_z) + if(H.lying || H.mob_size <= MOB_SIZE_SMALL) + continue + to_chat(H, span_warning("You stop feeling \the [src] beneath your feet.")) + if(H.m_intent == MOVE_INTENT_WALK) + H.Weaken(3 SECONDS) + if(H.m_intent == MOVE_INTENT_RUN) + H.Weaken(10 SECONDS) + get_fall_damage(H) /obj/structure/proc/structure_shaken() for(var/mob/living/M in get_turf(src)) - if(M.lying) return //No spamming this on people. + if(M.lying) + continue //No spamming this on people. M.Weaken(10 SECONDS) - 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(BODY_ZONE_PRECISE_L_FOOT, BODY_ZONE_PRECISE_R_FOOT)) - if("knee") - affecting = H.get_organ(pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) - if("wrist") - affecting = H.get_organ(pick(BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND)) - if("elbow") - affecting = H.get_organ(pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) - if("head") - affecting = H.get_organ(BODY_ZONE_HEAD) - - if(affecting) - to_chat(M, "You land heavily on your [affecting.name]!") - affecting.receive_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() + to_chat(M, span_warning("You topple as \the [src] moves under you!")) + + get_fall_damage(M) + return /obj/structure/proc/can_touch(mob/living/user) @@ -229,14 +286,14 @@ . = ..() if(!(resistance_flags & INDESTRUCTIBLE)) if(resistance_flags & ON_FIRE) - . += "It's on fire!" + . += span_warning("It's on fire!") if(broken) - . += "It appears to be broken." + . += span_notice("It appears to be broken.") var/examine_status = examine_status(user) if(examine_status) . += examine_status if(climbable) - . += "You can Click-Drag someone to [src] to put them on the table after a short delay." + . += span_info("You can Click-Drag someone to [src] to put them on the structure after a short delay.") /obj/structure/proc/examine_status(mob/user) //An overridable proc, mostly for falsewalls. var/healthpercent = (obj_integrity/max_integrity) * 100 @@ -247,7 +304,7 @@ . += "It appears heavily damaged." if(0 to 25) if(!broken) - . += "It's falling apart!" + . += span_warning("It's falling apart!") /obj/structure/proc/prevents_buckled_mobs_attacking() return FALSE diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm index 3e3781c55c9..d1e033de241 100644 --- a/code/game/objects/structures/fence.dm +++ b/code/game/objects/structures/fence.dm @@ -67,6 +67,31 @@ return TRUE return FALSE +/obj/structure/fence/do_climb(mob/living/user) + if(!climb_check(user)) + return FALSE + + user.visible_message("[user] starts climbing onto \the [src]!") + climber = user + if(!do_after(user, CLIMB_TIME, target = src)) + climber = null + return FALSE + + if(!can_touch(user) || !climbable) + climber = null + return FALSE + + user.loc = get_turf(src) + + if(get_turf(user) == get_turf(src)) + user.visible_message("[user] climbs onto \the [src]!") + + clumse_stuff(climber) + + climber = null + + return TRUE + /* Shock user with probability prb (if all connections & power are working) Returns TRUE if shocked, FALSE otherwise diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 34b3f63fb2b..1822c032169 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -138,16 +138,53 @@ return TRUE return FALSE +/obj/structure/railing/proc/hopping(mob/living/user) + if(!istype(user)) + return + var/delay = user.movement_delay()/2 + sleep(delay) + animate(user, pixel_z = 10, time = 3, easing = CIRCULAR_EASING|EASE_OUT) + delay = user.movement_delay()/4 + sleep(delay) + animate(user, pixel_z = initial(user.pixel_z), time = 3, easing = CIRCULAR_EASING|EASE_OUT) + if(user.floating) + user.float(TRUE) + /obj/structure/railing/do_climb(mob/living/user) + if(!climb_check(user)) + return FALSE + var/initial_mob_loc = get_turf(user) - . = ..() - if(.) - currently_climbed = TRUE - if(initial_mob_loc != get_turf(src)) // If we are on the railing, we want to move in the same dir as the railing. Otherwise we get put on the railing - currently_climbed = FALSE - return - user.Move(get_step(user, dir), TRUE) + + user.visible_message("[user] starts climbing onto \the [src]!") + climber = user + if(!do_after(user, 50, target = src)) + climber = null + return FALSE + + if(!can_touch(user) || !climbable) + climber = null + return FALSE + + user.loc = get_turf(src) + hopping(user) + + if(get_turf(user) == get_turf(src)) + user.visible_message("[user] climbs onto \the [src]!") + + clumse_stuff(climber) + + climber = null + + currently_climbed = TRUE + + if(initial_mob_loc != get_turf(src)) // If we are on the railing, we want to move in the same dir as the railing. Otherwise we get put on the railing currently_climbed = FALSE + return TRUE + user.loc = get_step(user, dir) + currently_climbed = FALSE + + return TRUE /obj/structure/railing/proc/can_be_rotated(mob/user) if(anchored) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 9364329513e..dc81f0dd761 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -137,6 +137,10 @@ var/mob/living/user = AM clumse_stuff(user) +/obj/structure/table/climb_check(mob/living/user) + . = ..() + if(user.checkpass(PASSTABLE)) + return FALSE /obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0) if(height == 0) @@ -147,14 +151,14 @@ var/mob/living/M = mover if(M.flying) return TRUE + var/obj/structure/table/other_table = locate(/obj/structure/table) in get_turf(mover) + var/obj/structure/other_object = locate(/obj/structure) in get_turf(mover) + if(other_object?.climbable && !other_table?.flipped) + return TRUE if(istype(mover) && mover.checkpass(PASSTABLE)) return TRUE if(mover.throwing) return TRUE - if(length(get_atoms_of_type(get_turf(mover), /obj/structure/table) - mover)) - var/obj/structure/table/other_table = locate(/obj/structure/table) in get_turf(mover) - if(!other_table.flipped) - return TRUE if(flipped) if(get_dir(loc, target) == dir) return !density @@ -487,6 +491,7 @@ debris -= AM if(istype(AM, /obj/item/shard)) AM.throw_impact(L) + L.pixel_z = initial(L.pixel_z) L.Weaken(10 SECONDS) qdel(src) @@ -732,6 +737,9 @@ if(OldLoc != held.loc) held_items -= held_uid continue + if(istype(held, /mob/living)) + held.pixel_z = 16 + held.glide_size = glide_size held.forceMove(NewLoc) @@ -791,12 +799,24 @@ . = ..() . += "It's held together by a couple of bolts." +/obj/structure/rack/climb_check(mob/living/user) + . = ..() + if(user.checkpass(PASSTABLE)) + return FALSE /obj/structure/rack/CanPass(atom/movable/mover, turf/target, height=0) if(height==0) return TRUE if(!density) //Because broken racks -Agouri |TODO: SPRITE!| return TRUE + if(ismob(mover)) + var/mob/living/M = mover + if(M.flying) + return TRUE + var/obj/structure/table/other_table = locate(/obj/structure/table) in get_turf(mover) + var/obj/structure/other_object = locate(/obj/structure) in get_turf(mover) + if(other_object?.climbable && !other_table?.flipped) + return TRUE if(istype(mover) && mover.checkpass(PASSTABLE)) return TRUE if(mover.throwing) @@ -865,6 +885,7 @@ desc = "Made with the skulls of the fallen." icon = 'icons/obj/stationobjs.dmi' icon_state = "minibar" + climbable = TRUE /obj/structure/rack/skeletal_bar/left icon_state = "minibar_left" @@ -872,6 +893,12 @@ /obj/structure/rack/skeletal_bar/right icon_state = "minibar_right" +/obj/structure/rack/skeletal_bar/MouseDrop_T(atom/movable/dropping, mob/user, params) + . = ..() + if(!. && dropping == user) + do_climb(user) + return TRUE + /obj/structure/rack/gunrack name = "gun rack" desc = "A gun rack for storing guns."