diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm index ef1956bdb64..6a4602ab254 100644 --- a/code/__defines/turfs.dm +++ b/code/__defines/turfs.dm @@ -12,3 +12,8 @@ // Roof related flags #define ROOF_FORCE_SPAWN 1 #define ROOF_CLEANUP 2 + +// MultiZ faller control. (Bit flags.) +// Default flag is needed for assoc lists to work. +#define CLIMBER_DEFAULT 1 +#define CLIMBER_NO_EXIT 2 diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 382391ab973..46539d51ed3 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -31,12 +31,12 @@ /proc/Centcomm_announce(var/msg, var/mob/Sender, var/iamessage) var/msg_cciaa = "[uppertext(boss_short)][iamessage ? " IA" : ""]:[key_name(Sender, 1)] (RPLY): [msg]" - msg = "[uppertext(boss_short)]M[iamessage ? " IA" : ""]:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (RPLY): [msg]" + var/msg_admin = "[uppertext(boss_short)][iamessage ? " IA" : ""]:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (RPLY): [msg]" var/cciaa_present = 0 var/cciaa_afk = 0 for(var/client/C in admins) if(R_ADMIN & C.holder.rights) - C << msg + C << msg_admin else if (R_CCIAA & C.holder.rights) cciaa_present++ if (C.is_afk()) diff --git a/code/modules/clothing/spacesuits/rig/modules/utility.dm b/code/modules/clothing/spacesuits/rig/modules/utility.dm index a2c60aa10f5..b66d1c5929a 100644 --- a/code/modules/clothing/spacesuits/rig/modules/utility.dm +++ b/code/modules/clothing/spacesuits/rig/modules/utility.dm @@ -566,7 +566,7 @@ // Handle leaping at targets with a combat capable version here. if (combatType && dist && (ismob(target) || (locate(/mob/living) in T))) - H.leap(target, leapDistance) + H.do_leap(target, leapDistance, FALSE) return 1 // If dist -> horizontal leap. Otherwise, the user clicked the turf that they're @@ -600,7 +600,7 @@ // This setting is necessary even for combat type, to stop you from moving onto // the turf, falling back down, and then getting forcemoved to the final destination. - LAZYADD(TA.climbers, H) + TA.add_climber(H, CLIMBER_NO_EXIT) H.forceMove(TA) @@ -612,9 +612,13 @@ if (!do_after(H, 4 SECONDS, use_user_turf = TRUE)) H.visible_message("\The [H] is interrupted and falls!", "You are interrupted and fall back down!") - LAZYREMOVE(TA.climbers, H) - ADD_FALLING_ATOM(H) + // Climbers will auto-fall if they exit the turf. This is for in case + // something else interrupts them. + if (H.loc == TA) + TA.remove_climber(H) + ADD_FALLING_ATOM(H) + return 1 H.visible_message("\The [H] finishes climbing onto \the [leapEnd].", @@ -623,7 +627,7 @@ H.visible_message("\The [H] lands on \the [leapEnd] with a heavy slam!", "You land on \the [leapEnd] with a heavy thud!") - LAZYREMOVE(TA.climbers, H) + // open/Exited() removes from climbers. H.forceMove(leapEnd) return 1 diff --git a/code/modules/mob/freelook/ai/update_triggers.dm b/code/modules/mob/freelook/ai/update_triggers.dm index 63ff0e292a5..2fe2a40a381 100644 --- a/code/modules/mob/freelook/ai/update_triggers.dm +++ b/code/modules/mob/freelook/ai/update_triggers.dm @@ -9,11 +9,11 @@ /mob/living/silicon/robot/Move() var/oldLoc = src.loc . = ..() - //if(.) - if(provides_camera_vision()) - if(!updating) - updating = 1 - addtimer(CALLBACK(src, .proc/camera_post_move, oldLoc), BORG_CAMERA_BUFFER) + if (.) + if(provides_camera_vision()) + if(!updating) + updating = 1 + addtimer(CALLBACK(src, .proc/camera_post_move, oldLoc), BORG_CAMERA_BUFFER) /mob/living/silicon/robot/proc/camera_post_move(oldLoc) if (oldLoc != loc) @@ -24,9 +24,9 @@ /mob/living/silicon/ai/Move() var/oldLoc = src.loc . = ..() - //if(.) - if(provides_camera_vision()) - addtimer(CALLBACK(src, .proc/camera_post_move, oldLoc), BORG_CAMERA_BUFFER, TIMER_UNIQUE) + if (.) + if(provides_camera_vision()) + addtimer(CALLBACK(src, .proc/camera_post_move, oldLoc), BORG_CAMERA_BUFFER, TIMER_UNIQUE) /mob/living/silicon/ai/proc/camera_post_move(oldLoc) if(oldLoc != src.loc) diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm index 3bdc97c1498..93203a05559 100644 --- a/code/modules/mob/living/carbon/human/human_powers.dm +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -49,72 +49,79 @@ if ((O.client && !( O.blinded ))) O.show_message(text("[] [failed ? "tried to tackle" : "has tackled"] down []!", src, T), 1) -/mob/living/carbon/human/proc/leap(var/mob/living/T = null, var/max_range = 4) +/mob/living/carbon/human/proc/leap(mob/living/T as mob in view(4)) set category = "Abilities" set name = "Leap" set desc = "Leap at a target and grab them aggressively." - if(last_special > world.time) - return + do_leap(T) + +/mob/living/carbon/human/proc/do_leap(mob/living/T, max_range = 4, restrict_special = TRUE) + if(restrict_special && last_special > world.time) + src << "You're too tired to leap!" + return FALSE + + if (status_flags & LEAPING) + src << "You're already leaping!" + return FALSE if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) - src << "You cannot leap in your current state." - return + src << "You cannot leap in your current state." + return FALSE - if (!T) + if (!T || issilicon(T)) // Silicon targets require us to rebuild the list. var/list/choices = list() - for(var/mob/living/M in view(6,src)) + for(var/mob/living/M in view(max_range, src)) if(!istype(M,/mob/living/silicon)) choices += M choices -= src T = input(src,"Who do you wish to leap at?") as null|anything in choices - if(!T || !src || src.stat) return + if(!T || QDELETED(src) || stat) + return FALSE - if(get_dist(get_turf(T), get_turf(src)) > max_range) return + if(get_dist(get_turf(T), get_turf(src)) > max_range) + src << "[T] is too far away!" + return FALSE - if(last_special > world.time) - return + if (restrict_special) + last_special = world.time + 75 - if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) - src << "You cannot leap in your current state." - return - - last_special = world.time + 75 status_flags |= LEAPING - src.visible_message("\The [src] leaps at [T]!") - src.throw_at(get_step(get_turf(T),get_turf(src)), 4, 1, src) + visible_message("[src] leaps at [T]!", "You leap at [T]!") + throw_at(get_step(get_turf(T), get_turf(src)), 4, 1, src) // Only Vox get to shriek. Seriously. if (isvox(src)) - playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) + playsound(loc, 'sound/voice/shriek1.ogg', 50, 1) sleep(5) - if(status_flags & LEAPING) status_flags &= ~LEAPING + if(status_flags & LEAPING) + status_flags &= ~LEAPING if(!src.Adjacent(T)) src << "You miss!" - return + return FALSE T.Weaken(3) // Pariahs are not good at leaping. This is snowflakey, pls fix. if(species.name == "Vox Pariah") src.Weaken(5) - return + return TRUE var/use_hand = "left" if(l_hand) if(r_hand) src << "You need to have one hand free to grab someone." - return + return TRUE else use_hand = "right" - src.visible_message("\The [src] seizes [T] aggressively!") + visible_message("[src] seizes [T] aggressively!", "You aggressively seize [T]!") var/obj/item/weapon/grab/G = new(src,T) if(use_hand == "left") @@ -126,6 +133,8 @@ G.icon_state = "grabbed1" G.synch() + return TRUE + /mob/living/carbon/human/proc/gut() set category = "Abilities" set name = "Gut" diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 16901b62493..83d203ec19c 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -367,7 +367,7 @@ cameraFollow = null /mob/living/silicon/Move(newloc, direct) - ..(newloc,direct) + . = ..() if (underdoor) underdoor = 0 if ((layer == UNDERDOOR))//if this is false, then we must have used hide, or had our layer changed by something else. We wont do anymore checks for this move proc diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm index 4ccc6cfd81b..5a0f53fa558 100644 --- a/code/modules/multiz/structures.dm +++ b/code/modules/multiz/structures.dm @@ -43,7 +43,9 @@ /obj/structure/ladder/attackby(obj/item/C as obj, mob/user as mob) attack_hand(user) - return + +/obj/structure/ladder/attack_robot(mob/user) + attack_hand(user) /obj/structure/ladder/attack_hand(var/mob/M) if(!M.may_climb_ladders(src)) @@ -102,6 +104,19 @@ return FALSE return TRUE +/mob/living/silicon/may_climb_ladders(ladder) + to_chat(src, "You're too heavy to climb [ladder]!") + return FALSE + +/mob/living/silicon/robot/drone/may_climb_ladders(ladder) + if(!Adjacent(ladder)) + to_chat(src, "You need to be next to \the [ladder] to start climbing.") + return FALSE + if(incapacitated()) + to_chat(src, "You are physically unable to climb \the [ladder].") + return FALSE + return TRUE + /mob/observer/ghost/may_climb_ladders(var/ladder) return TRUE diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm index 48a3071f6b8..6e91657e5e5 100644 --- a/code/modules/multiz/turf.dm +++ b/code/modules/multiz/turf.dm @@ -54,10 +54,32 @@ if (mover.Check_Shoegrip(FALSE) && mover.can_fall(below, src)) to_chat(mover, span("notice", "You are stopped from falling off the edge by \the [mover.shoes] you're wearing!")) - return 0 + return FALSE return ..() +// Add a falling atom by default. Even if it's not an atom that can actually fall. +// SSfalling will check this on its own and remove if necessary. This is saner, as it +// centralizes control to SSfalling. +/turf/simulated/open/Entered(atom/movable/mover) + ..() + ADD_FALLING_ATOM(mover) + update_icon() + +// Override to deny a climber exit if they're set to adhere to CLIMBER_NO_EXIT +/turf/simulated/open/Exit(atom/movable/mover, atom/newloc) + var/flags = remove_climber(mover) + + if (flags & CLIMBER_NO_EXIT) + ADD_FALLING_ATOM(mover) + return FALSE + + return ..() + +// Remove from climbers just in case. +/turf/simulated/open/Exited(atom/movable/mover, atom/newloc) + LAZYREMOVE(climbers, mover) + /turf/simulated/open/Destroy() SSopenturf.openspace_turfs -= src SSopenturf.queued_turfs -= src @@ -95,6 +117,42 @@ return FALSE +/** + * Used to add a climber to the climbers list. Climbers do not fall down this specific tile. + * + * @param climber The atom to be added as a climber. + * @param flags Bitflags to control the status of the climber. Should always be non-0! + * + * @return TRUE if a climber was successfully added. FALSE if the climber is already + * present or an error occured. + */ +/turf/simulated/open/proc/add_climber(atom/climber, flags = CLIMBER_DEFAULT) + if (!flags) + PROCLOG_WEIRD("Attempted to add climber [climber] without flags.") + return FALSE + + if (LAZYACCESS(climbers, climber)) + return FALSE + + LAZYINITLIST(climbers) + climbers[climber] = flags + return TRUE + +/** + * Used to remove a climber from the climbers list. Returns the flags the climber + * was assigned. + * + * @param climber The atom to be removed from climbers. + * + * @return The flags assigned to the climber if it was present in the list. 0 otherwise. + */ +/turf/simulated/open/proc/remove_climber(atom/climber) + . = 0 + + if (LAZYACCESS(climbers, climber)) + . = climbers[climber] + LAZYREMOVE(climbers, climber) + /turf/simulated/open/airless oxygen = 0 nitrogen = 0 @@ -127,11 +185,6 @@ /turf/simulated/open/update_dirt() return 0 -/turf/simulated/open/Entered(atom/movable/mover) - ..() - ADD_FALLING_ATOM(mover) - update_icon() - // override to make sure nothing is hidden /turf/simulated/open/levelupdate() for(var/obj/O in src) diff --git a/code/modules/shieldgen/shield_gen.dm b/code/modules/shieldgen/shield_gen.dm index eb3fe5fd1a1..a6b6bfa634a 100644 --- a/code/modules/shieldgen/shield_gen.dm +++ b/code/modules/shieldgen/shield_gen.dm @@ -43,7 +43,7 @@ field.Remove(D) D.loc = null return ..() - + /obj/machinery/shield_gen/emag_act(var/remaining_charges, var/mob/user) if(prob(75)) src.locked = !src.locked @@ -237,25 +237,9 @@ //TODO MAKE THIS MULTIZ COMPATIBLE //grab the border tiles in a circle around this machine /obj/machinery/shield_gen/proc/get_shielded_turfs() - var/list/out = list() - var/turf/gen_turf = get_turf(src) + if (!gen_turf) return - var/turf/T - for (var/x_offset = -field_radius; x_offset <= field_radius; x_offset++) - T = locate(gen_turf.x + x_offset, gen_turf.y - field_radius, gen_turf.z) - if (T) out += T - - T = locate(gen_turf.x + x_offset, gen_turf.y + field_radius, gen_turf.z) - if (T) out += T - - for (var/y_offset = -field_radius+1; y_offset < field_radius; y_offset++) - T = locate(gen_turf.x - field_radius, gen_turf.y + y_offset, gen_turf.z) - if (T) out += T - - T = locate(gen_turf.x + field_radius, gen_turf.y + y_offset, gen_turf.z) - if (T) out += T - - return out + . = RANGE_TURFS(field_radius, gen_turf) diff --git a/code/modules/shieldgen/shield_gen_external.dm b/code/modules/shieldgen/shield_gen_external.dm index 182339d64e5..4264b8579b7 100644 --- a/code/modules/shieldgen/shield_gen_external.dm +++ b/code/modules/shieldgen/shield_gen_external.dm @@ -11,17 +11,27 @@ //Search for space turfs within range that are adjacent to a simulated turf. /obj/machinery/shield_gen/external/get_shielded_turfs() var/list/out = list() - + var/turf/gen_turf = get_turf(src) if (!gen_turf) return - + + var/turf/U var/turf/T - for (var/x_offset = -field_radius; x_offset <= field_radius; x_offset++) - for (var/y_offset = -field_radius; y_offset <= field_radius; y_offset++) - T = locate(gen_turf.x + x_offset, gen_turf.y + y_offset, gen_turf.z) - if (istype(T, /turf/space)) - //check neighbors of T - if (locate(/turf/simulated/) in orange(1, T)) - out += T + + for (var/tt in RANGE_TURFS(field_radius, gen_turf)) + T = tt + // Ignore station areas. + if (the_station_areas[T.loc]) + continue + else if (istype(T, /turf/space) || istype(T, /turf/simulated/floor/asteroid) || isopenturf(T)) + for (var/uu in RANGE_TURFS(1, T)) + U = uu + if (T == U) + continue + + if (the_station_areas[U.loc]) + out += U + break + return out