diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm index c542d714ca6..7e791e6adda 100644 --- a/code/ATMOSPHERICS/atmospherics.dm +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -12,7 +12,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) /obj/machinery/atmospherics anchored = 1 layer = GAS_PIPE_HIDDEN_LAYER //under wires - plane = FLOOR_PLANE + plane = FLOOR_PLANE idle_power_usage = 0 active_power_usage = 0 power_channel = ENVIRON @@ -66,7 +66,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) if(level == 2 || !T.intact) plane = GAME_PLANE else - plane = FLOOR_PLANE + plane = FLOOR_PLANE /obj/machinery/atmospherics/proc/update_pipe_image() pipe_image = image(src, loc, layer = ABOVE_HUD_LAYER, dir = dir) //the 20 puts it above Byond's darkness (not its opacity view) @@ -258,7 +258,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) if(!direction || !(direction in cardinal)) //cant go this way. return - if(buckled_mob == user) + if(user in buckled_mobs)// fixes buckle ventcrawl edgecase fuck bug return var/obj/machinery/atmospherics/target_move = findConnecting(direction) diff --git a/code/ATMOSPHERICS/pipes/pipe.dm b/code/ATMOSPHERICS/pipes/pipe.dm index ec4f6bfd7ec..038180cdd7d 100644 --- a/code/ATMOSPHERICS/pipes/pipe.dm +++ b/code/ATMOSPHERICS/pipes/pipe.dm @@ -8,8 +8,8 @@ var/alert_pressure = 80*ONE_ATMOSPHERE //minimum pressure before check_pressure(...) should be called //Buckling - can_buckle = 1 - buckle_requires_restraints = 1 + can_buckle = TRUE + buckle_requires_restraints = TRUE buckle_lying = -1 /obj/machinery/atmospherics/pipe/New() diff --git a/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm b/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm index cb7ec277f95..1f40bdae665 100644 --- a/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm +++ b/code/ATMOSPHERICS/pipes/simple/pipe_simple_he.dm @@ -10,7 +10,7 @@ thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT color = "#404040" - buckle_lying = 1 + buckle_lying = TRUE var/icon_temperature = T20C //stop small changes in temperature causing icon refresh /obj/machinery/atmospherics/pipe/simple/heat_exchanging/process_atmos() @@ -50,10 +50,12 @@ animate(src, color = rgb(h_r, h_g, h_b), time = 20, easing = SINE_EASING) //burn any mobs buckled based on temperature - if(buckled_mob) + if(has_buckled_mobs()) var/heat_limit = 1000 if(pipe_air.temperature > heat_limit + 1) - buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, "chest") + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, "chest") /obj/machinery/atmospherics/pipe/simple/heat_exchanging/New() diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 8ce4d64911b..d49c0ee59eb 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -557,6 +557,7 @@ so as to remain in compliance with the most up-to-date laws." /obj/screen/alert/restrained/buckled name = "Buckled" desc = "You've been buckled to something. Click the alert to unbuckle unless you're handcuffed." + icon_state = "buckled" /obj/screen/alert/restrained/handcuffed name = "Handcuffed" @@ -570,6 +571,15 @@ so as to remain in compliance with the most up-to-date laws." if(isliving(usr)) var/mob/living/L = usr return L.resist() + +/obj/screen/alert/restrained/buckled/Click() + var/mob/living/L = usr + if(!istype(L) || !L.can_resist()) + return + L.changeNext_move(CLICK_CD_RESIST) + if(L.last_special <= world.time) + return L.resist_buckle() + // PRIVATE = only edit, use, or override these if you're editing the system as a whole // Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index bd06e0eb13d..65e188512d5 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -139,7 +139,7 @@ if(isliving(teleatom)) var/mob/living/L = teleatom if(L.buckled) - L.buckled.unbuckle_mob() + L.buckled.unbuckle_mob(L, force = TRUE) destarea.Entered(teleatom) diff --git a/code/datums/spells/area_teleport.dm b/code/datums/spells/area_teleport.dm index 70825f5195e..023939c2747 100644 --- a/code/datums/spells/area_teleport.dm +++ b/code/datums/spells/area_teleport.dm @@ -56,7 +56,7 @@ return if(target && target.buckled) - target.buckled.unbuckle_mob() + target.buckled.unbuckle_mob(target, force = TRUE) var/list/tempL = L var/attempt = null diff --git a/code/datums/spells/devil.dm b/code/datums/spells/devil.dm index 925b54d5e3c..12e2a44a8c1 100644 --- a/code/datums/spells/devil.dm +++ b/code/datums/spells/devil.dm @@ -131,14 +131,6 @@ playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1) var/obj/effect/dummy/slaughter/s_holder = new(loc) ExtinguishMob() - if(buckled) - buckled.unbuckle_mob(src,force=1) - if(has_buckled_mobs()) - unbuckle_mob() - if(pulledby) - pulledby.stop_pulling() - if(pulling) - stop_pulling() forceMove(s_holder) holder = s_holder notransform = FALSE diff --git a/code/datums/weather/weather_types/floor_is_lava.dm b/code/datums/weather/weather_types/floor_is_lava.dm index 72f49ad5057..9f98a481dbf 100644 --- a/code/datums/weather/weather_types/floor_is_lava.dm +++ b/code/datums/weather/weather_types/floor_is_lava.dm @@ -26,8 +26,10 @@ /datum/weather/floor_is_lava/weather_act(mob/living/L) if(issilicon(L)) return + if(istype(L.buckled, /obj/structure/bed)) + return for(var/obj/structure/O in L.loc) - if(O.density || O.buckled_mob && istype(O, /obj/structure/bed)) + if(O.density) return if(L.loc.density) return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index cb7bc3037b2..bfb2eb1d214 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -41,6 +41,7 @@ . = ..() /atom/movable/Destroy() + unbuckle_all_mobs(force = TRUE) if(loc) loc.handle_atom_del(src) for(var/atom/movable/AM in contents) @@ -109,7 +110,7 @@ log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.") stop_pulling() return - if(pulling.anchored) + if(pulling.anchored || pulling.move_resist > move_force) stop_pulling() return if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move. @@ -123,6 +124,7 @@ if(force < (move_resist * MOVE_FORCE_PULL_RATIO)) return FALSE return TRUE + // Used in shuttle movement and AI eye stuff. // Primarily used to notify objects being moved by a shuttle/bluespace fuckup. /atom/movable/proc/setLoc(var/T, var/teleported=0) @@ -200,7 +202,7 @@ src.move_speed = world.time - src.l_move_time src.l_move_time = world.time - if(. && buckled_mob && !handle_buckled_mob_movement(loc, direct)) //movement failed due to buckled mob + if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct)) //movement failed due to buckled mob . = 0 // Called after a successful Move(). By this point, we've already moved @@ -270,8 +272,10 @@ /mob/living/forceMove(atom/destination) if(buckled) addtimer(CALLBACK(src, .proc/check_buckled), 1, TIMER_UNIQUE) - if(buckled_mob) - addtimer(CALLBACK(buckled_mob, .proc/check_buckled), 1, TIMER_UNIQUE) + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + addtimer(CALLBACK(buckled_mob, .proc/check_buckled), 1, TIMER_UNIQUE) if(pulling) addtimer(CALLBACK(src, .proc/check_pull), 1, TIMER_UNIQUE) . = ..() @@ -423,12 +427,14 @@ return TRUE /atom/movable/proc/handle_buckled_mob_movement(newloc,direct) - if(!buckled_mob.Move(newloc, direct)) - loc = buckled_mob.loc - last_move = buckled_mob.last_move - inertia_dir = last_move - buckled_mob.inertia_dir = last_move - return 0 + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + if(!buckled_mob.Move(newloc, direct)) + forceMove(buckled_mob.loc) + last_move = buckled_mob.last_move + inertia_dir = last_move + buckled_mob.inertia_dir = last_move + return 0 return 1 /atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction) @@ -448,7 +454,7 @@ return FALSE /atom/movable/CanPass(atom/movable/mover, turf/target, height=1.5) - if(buckled_mob == mover) + if(mover in buckled_mobs) return 1 return ..() diff --git a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm index 2c34503781e..1ea0539620a 100644 --- a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm +++ b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm @@ -35,8 +35,6 @@ animation.dir = dir ExtinguishMob() - if(buckled) - buckled.unbuckle_mob() if(pulling && bloodcrawl == BLOODCRAWL_EAT) if(istype(pulling, /mob/living/)) var/mob/living/victim = pulling @@ -50,8 +48,9 @@ kidnapped = victim stop_pulling() flick("jaunt",animation) - loc = holder - holder = holder + + src.holder = holder + forceMove(holder) if(kidnapped) to_chat(src, "You begin to feast on [kidnapped]. You can not move while you are doing this.") diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm index 276f8d2eb1f..1671c4a03b0 100644 --- a/code/game/gamemodes/shadowling/shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm @@ -45,14 +45,14 @@ if(M in view_or_range(range, user, "view")) targets += M - + if(!targets.len) //doesn't waste the spell revert_cast(user) return perform(targets, user = user) return - + /obj/effect/proc_holder/spell/targeted/glare/cast(list/targets, mob/user = usr) for(var/mob/living/carbon/human/target in targets) @@ -139,8 +139,6 @@ target.ExtinguishMob() var/turf/T = get_turf(target) target.forceMove(T) //to properly move the mob out of a potential container - if(target.buckled) - target.buckled.unbuckle_mob() if(target.pulledby) target.pulledby.stop_pulling() target.stop_pulling() @@ -543,7 +541,7 @@ to_chat(user, "You must stand next to an APC to drain it!") charge_counter = charge_max return - + if(target_apc.cell?.charge == 0) to_chat(user, "APC must have a power to drain!") charge_counter = charge_max diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 7e1a375f15d..7db238533be 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -424,8 +424,6 @@ var/jaunt_duration = 50 //in deciseconds /obj/effect/proc_holder/spell/vampire/self/jaunt/cast(list/targets, mob/user = usr) - if(user.buckled) - user.buckled.unbuckle_mob() spawn(0) var/mob/living/U = user var/originalloc = get_turf(user.loc) @@ -439,8 +437,6 @@ animation.layer = 5 animation.master = holder U.ExtinguishMob() - if(user.buckled) - user.buckled.unbuckle_mob() flick("liquify", animation) user.forceMove(holder) user.client.eye = holder @@ -513,8 +509,6 @@ perform(turfs, user = user) /obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets, mob/user = usr) - if(usr.buckled) - user.buckled.unbuckle_mob() spawn(0) var/turf/picked = pick(targets) @@ -522,8 +516,6 @@ return var/mob/living/U = user U.ExtinguishMob() - if(user.buckled) - user.buckled.unbuckle_mob() var/atom/movable/overlay/animation = new /atom/movable/overlay(get_turf(user)) animation.name = user.name animation.density = 0 diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index af73a13f27c..de15a26264a 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -12,7 +12,7 @@ var/strapped = 0.0 var/obj/machinery/computer/operating/computer = null - buckle_lying = 90 + buckle_lying = -1 var/no_icon_updates = 0 //set this to 1 if you don't want the icons ever changing var/list/injected_reagents = list() var/reagent_target_amount = 1 diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 8f542a2ea3c..56618164bbb 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -554,7 +554,10 @@ var/list/turret_icons if(istype(A, /obj/vehicle)) var/obj/vehicle/T = A - assess_and_assign(T.buckled_mob, targets, secondarytargets) + if(T.has_buckled_mobs()) + for(var/m in T.buckled_mobs) + var/mob/living/buckled_mob = m + assess_and_assign(buckled_mob, targets, secondarytargets) if(isliving(A)) var/mob/living/C = A diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index a89be1c211e..72652958e7c 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -1,80 +1,103 @@ - - /atom/movable - var/can_buckle = 0 - var/buckle_lying = -1 //bed-like behaviour, forces mob.lying = buckle_lying if != -1 //except -1 actually means "rotate 90 degrees to the left" as it is used by 1*buckle_lying. + var/can_buckle = FALSE + var/buckle_lying = -1 //bed-like behaviour, forces mob.lying = buckle_lying if != -1 var/buckle_requires_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes - var/mob/living/buckled_mob = null + var/list/buckled_mobs = null //list() var/buckle_offset = 0 - + var/max_buckled_mobs = 1 + var/buckle_prevents_pull = FALSE //Interaction /atom/movable/attack_hand(mob/living/user) . = ..() - if(can_buckle && buckled_mob) - return user_unbuckle_mob(user) - -/atom/movable/attack_robot(mob/living/user) - . = ..() - if(can_buckle && buckled_mob && Adjacent(user)) // attack_robot is called on all ranges, so the Adjacent check is needed - return user_unbuckle_mob(user) + if(can_buckle && has_buckled_mobs()) + if(buckled_mobs.len > 1) + var/unbuckled = input(user, "Who do you wish to unbuckle?", "Unbuckle Who?") as null|mob in buckled_mobs + if(user_unbuckle_mob(unbuckled,user)) + return 1 + else + if(user_unbuckle_mob(buckled_mobs[1], user)) + return 1 /atom/movable/MouseDrop_T(mob/living/M, mob/living/user) . = ..() - if(can_buckle && istype(M)) - return user_buckle_mob(M, user) - - -//Cleanup -/atom/movable/Destroy() - . = ..() - unbuckle_mob() + if(can_buckle && istype(M) && istype(user)) + if(user_buckle_mob(M, user)) + return 1 /atom/movable/proc/has_buckled_mobs() - if(buckled_mob) + if(!buckled_mobs) + return FALSE + if(buckled_mobs.len) return TRUE - return FALSE //procs that handle the actual buckling and unbuckling -/atom/movable/proc/buckle_mob(mob/living/M, force = 0) - if((!can_buckle && !force)|| !istype(M) || (M.loc != loc) || M.buckled || M.buckled_mob || buckled_mob || (buckle_requires_restraints && !M.restrained()) || M == src) - return 0 +/atom/movable/proc/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) + if(!buckled_mobs) + buckled_mobs = list() - if((isslime(M) || isAI(M)) && !force) + if(!istype(M)) + return FALSE + + if(check_loc && M.loc != loc) + return FALSE + + if((!can_buckle && !force) || M.buckled || (buckled_mobs.len >= max_buckled_mobs) || (buckle_requires_restraints && !M.restrained()) || M == src) + return FALSE + M.buckling = src + if(!M.can_buckle() && !force) if(M == usr) - to_chat(M, "You are unable to buckle yourself to the [src]!") + to_chat(M, "You are unable to buckle yourself to [src]!") else - to_chat(usr, "You are unable to buckle [M] to the [src]!") - return 0 + to_chat(usr, "You are unable to buckle [M] to [src]!") + M.buckling = null + return FALSE + if(M.pulledby) + if(buckle_prevents_pull) + M.pulledby.stop_pulling() + + if(!check_loc && M.loc != loc) + M.forceMove(loc) + + M.buckling = null M.buckled = src - M.dir = dir - buckled_mob = M + M.setDir(dir) + buckled_mobs |= M M.update_canmove() + M.throw_alert("buckled", /obj/screen/alert/restrained/buckled) post_buckle_mob(M) - M.throw_alert("buckled", /obj/screen/alert/restrained/buckled, new_master = src) - return 1 -/obj/buckle_mob(mob/living/M, force = 0) + SEND_SIGNAL(src, COMSIG_MOVABLE_BUCKLE, M, force) + return TRUE + +/obj/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) . = ..() if(.) if(burn_state == ON_FIRE) //Sets the mob on fire if you buckle them to a burning atom/movableect M.adjust_fire_stacks(1) M.IgniteMob() -/atom/movable/proc/unbuckle_mob(force = FALSE) - if(buckled_mob && buckled_mob.buckled == src && (buckled_mob.can_unbuckle(usr) || force)) +/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force = FALSE) + if(istype(buckled_mob) && buckled_mob.buckled == src && (buckled_mob.can_unbuckle() || force)) . = buckled_mob buckled_mob.buckled = null buckled_mob.anchored = initial(buckled_mob.anchored) buckled_mob.update_canmove() buckled_mob.clear_alert("buckled") - buckled_mob = null + buckled_mobs -= buckled_mob + SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force) post_unbuckle_mob(.) -//Handle any extras after buckling/unbuckling -//Called on buckle_mob() and unbuckle_mob() +/atom/movable/proc/unbuckle_all_mobs(force = FALSE) + if(!has_buckled_mobs()) + return + for(var/m in buckled_mobs) + unbuckle_mob(m, force) + +//Handle any extras after buckling +//Called on buckle_mob() /atom/movable/proc/post_buckle_mob(mob/living/M) return @@ -83,36 +106,31 @@ return //Wrapper procs that handle sanity and user feedback -/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user) - if(!in_range(user, src) || user.stat || user.restrained()) - return +/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) + if(!in_range(user, src) || !isturf(user.loc) || user.incapacitated() || M.anchored) + return FALSE add_fingerprint(user) - - if(buckle_mob(M)) + . = buckle_mob(M, check_loc = check_loc) + if(.) if(M == user) - M.visible_message(\ - "[M] buckles themself to [src].",\ + M.visible_message("[M] buckles [M.p_them()]self to [src].",\ "You buckle yourself to [src].",\ "You hear metal clanking.") else - M.visible_message(\ - "[user] buckles [M] to [src]!",\ + M.visible_message("[user] buckles [M] to [src]!",\ "[user] buckles you to [src]!",\ "You hear metal clanking.") - return 1 -/atom/movable/proc/user_unbuckle_mob(mob/user) - var/mob/living/M = unbuckle_mob() +/atom/movable/proc/user_unbuckle_mob(mob/living/buckled_mob, mob/user) + var/mob/living/M = unbuckle_mob(buckled_mob) if(M) if(M != user) - M.visible_message(\ - "[user] unbuckles [M] from [src].",\ + M.visible_message("[user] unbuckles [M] from [src].",\ "[user] unbuckles you from [src].",\ "You hear metal clanking.") else - M.visible_message(\ - "[M] unbuckles themselves from [src].",\ + M.visible_message("[M] unbuckles [M.p_them()]self from [src].",\ "You unbuckle yourself from [src].",\ "You hear metal clanking.") add_fingerprint(user) @@ -120,4 +138,4 @@ /mob/living/proc/check_buckled() if(buckled && !(buckled in loc)) - buckled.unbuckle_mob(src, force=1) + buckled.unbuckle_mob(src, force = TRUE) \ No newline at end of file diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm index 314077db68e..cef14d28796 100644 --- a/code/game/objects/items/weapons/implants/implantchair.dm +++ b/code/game/objects/items/weapons/implants/implantchair.dm @@ -78,7 +78,7 @@ if(!ismob(G.affecting)) return var/mob/M = G.affecting - if(M.buckled_mob) + if(M.has_buckled_mobs()) to_chat(usr, "[M] will not fit into [src] because [M.p_they()] [M.p_have()] a slime latched onto [M.p_their()] head.") return if(put_mob(M)) diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm index ccee6c18feb..696d54cc3bf 100644 --- a/code/game/objects/items/weapons/scrolls.dm +++ b/code/game/objects/items/weapons/scrolls.dm @@ -51,7 +51,7 @@ if(!A) return - + var/area/thearea = teleportlocs[A] if(user.stat || user.restrained()) @@ -83,7 +83,7 @@ return if(user && user.buckled) - user.buckled.unbuckle_mob() + user.buckled.unbuckle_mob(user, force = TRUE) var/list/tempL = L var/attempt = null diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 4a2dadffcc7..965819dd436 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -69,7 +69,7 @@ continue if(istype(O, /obj/structure/bed)) //This is only necessary because of rollerbeds and swivel chairs. var/obj/structure/bed/B = O - if(B.buckled_mob) + if(B.has_buckled_mobs()) continue O.forceMove(src) itemcount++ @@ -161,7 +161,7 @@ if(C.use(15)) to_chat(user, "You rig [src].") rigged = TRUE - else + else to_chat(user, "You need atleast 15 wires to rig [src]!") return else if(istype(W, /obj/item/radio/electropack)) diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm index dcbc7c017bb..b8f0d6c5cb5 100644 --- a/code/game/objects/structures/electricchair.dm +++ b/code/game/objects/structures/electricchair.dm @@ -71,11 +71,12 @@ flick("echair_shock", src) do_sparks(12, 1, src) visible_message("The electric chair went off!", "You hear a deep sharp shock!") - if(buckled_mob) - buckled_mob.electrocute_act(110, src, 1) - to_chat(buckled_mob, "You feel a deep shock course through your body!") - spawn(1) + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m buckled_mob.electrocute_act(110, src, 1) + to_chat(buckled_mob, "You feel a deep shock course through your body!") + spawn(1) + buckled_mob.electrocute_act(110, src, 1) A.power_light = light - A.updateicon() - return + A.updateicon() \ No newline at end of file diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm index 30429e2ca2c..6d32aec248e 100644 --- a/code/game/objects/structures/guillotine.dm +++ b/code/game/objects/structures/guillotine.dm @@ -28,6 +28,10 @@ var/force_clap = FALSE //You WILL clap if I want you to var/current_action = 0 // What's currently happening to the guillotine +/obj/structure/guillotine/Initialize(mapload) + LAZYINITLIST(buckled_mobs) + return ..() + /obj/structure/guillotine/examine(mob/user) ..() @@ -84,7 +88,7 @@ else current_action = 0 else - unbuckle_mob() + unbuckle_all_mobs() else blade_status = GUILLOTINE_BLADE_MOVING icon_state = "guillotine_drop" @@ -97,7 +101,7 @@ /obj/structure/guillotine/proc/drop_blade(mob/user) if(has_buckled_mobs() && blade_sharpness) - var/mob/living/carbon/human/H = buckled_mob + var/mob/living/carbon/human/H = buckled_mobs[1] if(!H) blade_status = GUILLOTINE_BLADE_DROPPED @@ -116,7 +120,7 @@ head.droplimb() add_attack_logs(user, H, "beheaded with [src]") H.regenerate_icons() - unbuckle_mob() + unbuckle_all_mobs() kill_count += 1 var/blood_overlay = "bloody" @@ -219,7 +223,7 @@ else return ..() -/obj/structure/guillotine/buckle_mob(mob/living/M, force = 0) +/obj/structure/guillotine/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(!anchored) to_chat(usr, "The [src] needs to be wrenched to the floor!") return FALSE @@ -232,15 +236,19 @@ to_chat(usr, "You need to raise the blade before buckling someone in!") return FALSE - if(..()) - M.pixel_y -= GUILLOTINE_HEAD_OFFSET // Offset their body so it looks like they're in the guillotine - M.layer += GUILLOTINE_LAYER_DIFF + return ..(M, force, FALSE) -/obj/structure/guillotine/unbuckle_mob(force = 0) - if(buckled_mob) - buckled_mob.pixel_y += GUILLOTINE_HEAD_OFFSET // Move their body back - buckled_mob.layer -= GUILLOTINE_LAYER_DIFF - . = ..() +/obj/structure/guillotine/post_buckle_mob(mob/living/M) + if(!ishuman(M)) + return + M.pixel_y += -GUILLOTINE_HEAD_OFFSET // Offset their body so it looks like they're in the guillotine + M.layer += GUILLOTINE_LAYER_DIFF + ..() + +/obj/structure/guillotine/post_unbuckle_mob(mob/living/M) + M.pixel_y -= -GUILLOTINE_HEAD_OFFSET // Move their body back + M.layer -= GUILLOTINE_LAYER_DIFF + ..() #undef GUILLOTINE_BLADE_MAX_SHARP #undef GUILLOTINE_DECAP_MIN_SHARP diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 05f7f326898..e38af14ecc4 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -35,14 +35,20 @@ desc = "A spike for collecting meat from animals." density = 1 anchored = 1 - buckle_lying = 0 - can_buckle = 1 + buckle_lying = FALSE + can_buckle = TRUE +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/structure/kitchenspike/attack_hand(mob/user) + if(has_buckled_mobs()) + for(var/mob/living/L in buckled_mobs) + user_unbuckle_mob(L, user) + else + ..() - -/obj/structure/kitchenspike/attackby(obj/item/grab/G as obj, mob/user as mob) +/obj/structure/kitchenspike/attackby(obj/item/grab/G, mob/user) if(istype(G, /obj/item/crowbar)) - if(!buckled_mob) + if(!has_buckled_mobs()) playsound(loc, G.usesound, 100, 1) if(do_after(user, 20 * G.toolspeed, target = src)) to_chat(user, "You pry the spikes out of the frame.") @@ -55,11 +61,11 @@ return if(!istype(G, /obj/item/grab) || !G.affecting) return - if(buckled_mob) + if(has_buckled_mobs()) to_chat(user, "The spike already has something on it, finish collecting its meat first!") else if(isliving(G.affecting)) - if(!buckled_mob) + if(!has_buckled_mobs()) if(do_mob(user, src, 120)) if(spike(G.affecting)) G.affecting.visible_message("[user] slams [G.affecting] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.") @@ -68,56 +74,50 @@ to_chat(user, "You can't use that on the spike!") return -/obj/structure/kitchenspike/proc/spike(var/mob/living/victim) +/obj/structure/kitchenspike/proc/spike(mob/living/victim) if(!istype(victim)) - return + return FALSE - - if(buckled_mob) //to prevent spam/queing up attacks - return 0 + if(has_buckled_mobs()) //to prevent spam/queing up attacks + return FALSE if(victim.buckled) - return 0 - var/mob/living/H = victim + return FALSE playsound(loc, 'sound/effects/splat.ogg', 25, 1) - H.forceMove(loc) - H.emote("scream") - if(ishuman(H)) + victim.forceMove(drop_location()) + victim.emote("scream") + if(ishuman(victim)) + var/mob/living/carbon/human/H = victim H.add_splatter_floor() - H.adjustBruteLoss(30) - H.buckled = src - H.dir = 2 - buckled_mob = H - var/matrix/m180 = matrix() + victim.adjustBruteLoss(30) + victim.setDir(2) + buckle_mob(victim, force = TRUE) + var/matrix/m180 = matrix(victim.transform) m180.Turn(180) - animate(H, transform = m180, time = 3) - H.pixel_y = H.get_standard_pixel_y_offset(180) - return 1 - + animate(victim, transform = m180, time = 3) + victim.pixel_y = victim.get_standard_pixel_y_offset(180) + return TRUE /obj/structure/kitchenspike/user_buckle_mob(mob/living/M, mob/living/user) //Don't want them getting put on the rack other than by spiking return -/obj/structure/kitchenspike/user_unbuckle_mob(mob/living/carbon/human/user) - if(buckled_mob && buckled_mob.buckled == src) +/obj/structure/kitchenspike/user_unbuckle_mob(mob/living/buckled_mob, mob/living/carbon/human/user) + if(buckled_mob) var/mob/living/M = buckled_mob if(M != user) - M.visible_message(\ - "[user.name] tries to pull [M.name] free of the [src]!",\ - "[user.name] is trying to pull you off of [src], opening up fresh wounds!",\ + M.visible_message("[user] tries to pull [M] free of [src]!",\ + "[user] is trying to pull you off [src], opening up fresh wounds!",\ "You hear a squishy wet noise.") if(!do_after(user, 300, target = src)) if(M && M.buckled) - M.visible_message(\ - "[user.name] fails to free [M.name]!",\ - "[user.name] fails to pull you off of [src].") + M.visible_message("[user] fails to free [M]!",\ + "[user] fails to pull you off of [src].") return else - M.visible_message(\ - "[M.name] struggles to break free from the [src]!",\ - "You struggle to break free from the [src], exacerbating your wounds! (Stay still for two minutes.)",\ + M.visible_message("[M] struggles to break free from [src]!",\ + "You struggle to break free from [src], exacerbating your wounds! (Stay still for two minutes.)",\ "You hear a wet squishing noise..") M.adjustBruteLoss(30) if(!do_after(M, 1200, target = src)) @@ -126,13 +126,21 @@ return if(!M.buckled) return - var/matrix/m180 = matrix(M.transform) - m180.Turn(180) - animate(M, transform = m180, time = 3) - M.pixel_y = M.get_standard_pixel_y_offset(180) - M.adjustBruteLoss(30) - visible_message("[M] falls free of the [src]!") - unbuckle_mob() - M.emote("scream") - M.AdjustWeakened(10) + release_mob(M) +/obj/structure/kitchenspike/proc/release_mob(mob/living/M) + var/matrix/m180 = matrix(M.transform) + m180.Turn(180) + animate(M, transform = m180, time = 3) + M.pixel_y = M.get_standard_pixel_y_offset(180) + M.adjustBruteLoss(30) + src.visible_message(text("[M] falls free of [src]!")) + unbuckle_mob(M, force = TRUE) + M.emote("scream") + M.AdjustWeakened(10) + +/obj/structure/kitchenspike/Destroy() + if(has_buckled_mobs()) + for(var/mob/living/L in buckled_mobs) + release_mob(L) + return ..() \ No newline at end of file diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index 91e2d552859..c175dca567b 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -7,12 +7,6 @@ anchored = 1 layer = 4 armor = list(melee = 100, bullet = 80, laser = 80, energy = 100, bomb = 50, bio = 100, rad = 100) - var/list/mobs_can_pass = list( - /mob/living/carbon/slime, - /mob/living/simple_animal/mouse, - /mob/living/silicon/robot/drone, - /mob/living/simple_animal/bot/mulebot - ) var/state = PLASTIC_FLAPS_NORMAL /obj/structure/plasticflaps/examine(mob/user) @@ -66,43 +60,40 @@ return prob(60) var/obj/structure/bed/B = A - if(istype(A, /obj/structure/bed) && B.buckled_mob)//if it's a bed/chair and someone is buckled, it will not pass - return 0 + if(istype(A, /obj/structure/bed) && (B.has_buckled_mobs() || B.density))//if it's a bed/chair and is dense or someone is buckled, it will not pass + return FALSE if(istype(A, /obj/structure/closet/cardboard)) var/obj/structure/closet/cardboard/C = A if(C.move_delay) - return 0 + return FALSE - if(istype(A, /obj/vehicle)) //no vehicles - return 0 - - var/mob/living/M = A - if(istype(M)) - if(M.lying) - return ..() - for(var/mob_type in mobs_can_pass) - if(istype(A, mob_type)) - return ..() - if(istype(A, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.dna.species.is_small) - return ..() - return 0 + if(ismecha(A)) + return FALSE + else if(isliving(A)) // You Shall Not Pass! + var/mob/living/M = A + if(isbot(A)) //Bots understand the secrets + return TRUE + if(M.buckled && istype(M.buckled, /mob/living/simple_animal/bot/mulebot)) // mulebot passenger gets a free pass. + return TRUE + if(!M.lying && !M.ventcrawler && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass. + return FALSE return ..() /obj/structure/plasticflaps/CanAStarPass(ID, to_dir, caller) - if(istype(caller, /mob/living)) - for(var/mob_type in mobs_can_pass) - if(istype(caller, mob_type)) - return 1 + if(isliving(caller)) + if(isbot(caller)) + return TRUE var/mob/living/M = caller - if(!M.ventcrawler && M.mob_size > MOB_SIZE_SMALL) - return 0 - return 1 + if(!M.ventcrawler && M.mob_size != MOB_SIZE_TINY) + return FALSE + var/atom/movable/M = caller + if(M && M.pulling) + return CanAStarPass(ID, to_dir, M.pulling) + return TRUE //diseases, stings, etc can pass /obj/structure/plasticflaps/ex_act(severity) switch(severity) diff --git a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm index 33fe66c0f08..d3ee6c0bece 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm @@ -14,68 +14,67 @@ return ..() /obj/structure/bed/nest/user_unbuckle_mob(mob/living/user) - if(buckled_mob && buckled_mob.buckled == src) - var/mob/living/M = buckled_mob + if(has_buckled_mobs()) + for(var/buck in buckled_mobs) //breaking a nest releases all the buckled mobs, because the nest isn't holding them down anymore + var/mob/living/M = buck - if(user.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) - unbuckle_mob() + if(user.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) + unbuckle_mob(M) + add_fingerprint(user) + return + + if(M != user) + M.visible_message("[user.name] pulls [M.name] free from the sticky nest!",\ + "[user.name] pulls you free from the gelatinous resin.",\ + "You hear squelching...") + else + M.visible_message("[M.name] struggles to break free from the gelatinous resin!",\ + "You struggle to break free from the gelatinous resin... (Stay still for two minutes.)",\ + "You hear squelching...") + if(!do_after(M, 1200, target = src)) + if(M && M.buckled) + to_chat(M, "You fail to escape \the [src]!") + return + if(!M.buckled) + return + M.visible_message("[M.name] breaks free from the gelatinous resin!",\ + "You break free from the gelatinous resin!",\ + "You hear squelching...") + + unbuckle_mob(M) add_fingerprint(user) - return - - if(M != user) - M.visible_message(\ - "[user.name] pulls [M.name] free from the sticky nest!",\ - "[user.name] pulls you free from the gelatinous resin.",\ - "You hear squelching...") - - else - buckled_mob.visible_message(\ - "[buckled_mob.name] struggles to break free of the gelatinous resin...",\ - "You struggle to break free from the gelatinous resin... (This will take around 2 minutes and you need to stay still)",\ - "You hear squelching...") - if(!do_after(M, 1200, target = src)) - if(M && M.buckled) - to_chat(M, "You fail to escape \the [src]!") - return - if(!M.buckled) - return - M.visible_message(\ - "[M.name] breaks free from the gelatinous resin!",\ - "You break free from the gelatinous resin!",\ - "You hear squelching...") - unbuckle_mob() - add_fingerprint(user) /obj/structure/bed/nest/user_buckle_mob(mob/living/M, mob/living/user) - if( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.restrained() || usr.stat || M.buckled || istype(user, /mob/living/silicon/pai) ) + if (!ismob(M) || (get_dist(src, user) > 1) || (M.loc != loc) || user.incapacitated() || M.buckled) return if(M.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) return + if(!user.get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)) return - unbuckle_mob() + if(has_buckled_mobs()) + unbuckle_all_mobs() if(buckle_mob(M)) - M.visible_message(\ - "[user.name] secretes a thick vile goo, securing [M.name] into [src]!",\ + M.visible_message("[user.name] secretes a thick vile goo, securing [M.name] into [src]!",\ "[user.name] drenches you in a foul-smelling resin, trapping you in [src]!",\ "You hear squelching...") /obj/structure/bed/nest/post_buckle_mob(mob/living/M) - if(M == buckled_mob) - M.pixel_y = 0 - M.pixel_x = initial(M.pixel_x) + 2 - M.layer = MOB_LAYER - 0.3 - overlays += nest_overlay - else - M.pixel_x = M.get_standard_pixel_x_offset(M.lying) - M.pixel_y = M.get_standard_pixel_y_offset(M.lying) - M.layer = initial(M.layer) - overlays -= nest_overlay + M.pixel_y = 0 + M.pixel_x = initial(M.pixel_x) + 2 + M.layer = BELOW_MOB_LAYER + add_overlay(nest_overlay) + +/obj/structure/bed/nest/post_unbuckle_mob(mob/living/M) + M.pixel_x = M.get_standard_pixel_x_offset(M.lying) + M.pixel_y = M.get_standard_pixel_y_offset(M.lying) + M.layer = initial(M.layer) + cut_overlay(nest_overlay) /obj/structure/bed/nest/attackby(obj/item/W as obj, mob/user as mob, params) user.changeNext_move(CLICK_CD_MELEE) diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index adbeffd600d..0802c212560 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -29,8 +29,6 @@ desc = "For prime comfort during psychiatric evaluations." icon_state = "psychbed" buildstackamount = 5 - can_buckle = TRUE - buckle_lying = TRUE /obj/structure/bed/alien name = "resting contraption" @@ -66,20 +64,23 @@ anchored = FALSE comfort = 1 -/obj/structure/bed/roller/attackby(obj/item/W as obj, mob/user as mob, params) +/obj/structure/bed/roller/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/roller_holder)) - if(buckled_mob) - user_unbuckle_mob(user) + if(has_buckled_mobs()) + if(buckled_mobs.len > 1) + unbuckle_all_mobs() + user.visible_message("[user] unbuckles all creatures from [src].") + else + user_unbuckle_mob(buckled_mobs[1], user) else user.visible_message("[user] collapses \the [name].", "You collapse \the [name].") new/obj/item/roller(get_turf(src)) qdel(src) /obj/structure/bed/roller/post_buckle_mob(mob/living/M) - if(M == buckled_mob) - density = TRUE - icon_state = "up" - M.pixel_y = initial(M.pixel_y) + density = TRUE + icon_state = "up" + M.pixel_y = initial(M.pixel_y) /obj/structure/bed/roller/post_unbuckle_mob(mob/living/M) density = FALSE @@ -112,7 +113,7 @@ if(over_object == usr && Adjacent(usr) && (in_range(src, usr) || usr.contents.Find(src))) if(!ishuman(usr)) return - if(buckled_mob) + if(has_buckled_mobs()) return 0 usr.visible_message("[usr] collapses \the [name].", "You collapse \the [name].") new/obj/item/roller(get_turf(src)) diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 8192e39b85d..cdb502a695c 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -78,19 +78,20 @@ qdel(src) /obj/structure/chair/attack_tk(mob/user as mob) - if(buckled_mob) + if(!anchored || has_buckled_mobs() || !isturf(user.loc)) ..() else rotate() - return -/obj/structure/chair/proc/handle_rotation(direction) //making this into a seperate proc so office chairs can call it on Move() +/obj/structure/chair/proc/handle_rotation(direction) handle_layer() - if(buckled_mob) - buckled_mob.dir = dir + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(direction) /obj/structure/chair/proc/handle_layer() - if(buckled_mob && dir == NORTH) + if(has_buckled_mobs() && dir == NORTH) layer = ABOVE_MOB_LAYER else layer = OBJ_LAYER @@ -229,24 +230,20 @@ /obj/structure/chair/office/Bump(atom/A) ..() - if(!buckled_mob) + if(!has_buckled_mobs()) return if(propelled) - var/mob/living/occupant = buckled_mob - unbuckle_mob() - occupant.throw_at(A, 3, propelled) - occupant.apply_effect(6, STUN, 0) - occupant.apply_effect(6, WEAKEN, 0) - occupant.apply_effect(6, STUTTER, 0) - playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) - if(istype(A, /mob/living)) - var/mob/living/victim = A - victim.apply_effect(6, STUN, 0) - victim.apply_effect(6, WEAKEN, 0) - victim.apply_effect(6, STUTTER, 0) - victim.take_organ_damage(10) - occupant.visible_message("[occupant] crashed into \the [A]!") + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + unbuckle_mob(buckled_mob) + buckled_mob.throw_at(A, 3, propelled) + buckled_mob.apply_effect(6, STUN, 0) + buckled_mob.apply_effect(6, WEAKEN, 0) + buckled_mob.apply_effect(6, STUTTER, 0) + buckled_mob.take_organ_damage(10) + playsound(loc, 'sound/weapons/punch1.ogg', 50, 1, -1) + buckled_mob.visible_message("[buckled_mob] crashed into [A]!") /obj/structure/chair/office/light icon_state = "officechair_white" diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index e4e15d191e5..a837e632692 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -11,8 +11,10 @@ overlays = null var/image/O = image(icon = icon, icon_state = "[icon_state]_overlay", layer = FLY_LAYER, dir = src.dir) overlays += O - if(buckled_mob) - buckled_mob.dir = dir + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(dir) /obj/structure/chair/wheelchair/relaymove(mob/user, direction) if(propelled) @@ -27,7 +29,8 @@ var/calculated_move_delay calculated_move_delay += 2 //wheelchairs are not infact sport bikes - if(buckled_mob) + if(has_buckled_mobs()) + var/mob/living/buckled_mob = buckled_mobs[1] if(buckled_mob.incapacitated()) return 0 @@ -69,15 +72,15 @@ /obj/structure/chair/wheelchair/Bump(atom/A) ..() - if(!buckled_mob) + if(!has_buckled_mobs()) return - + var/mob/living/buckled_mob = buckled_mobs[1] if(istype(A, /obj/machinery/door)) A.Bumped(buckled_mob) if(propelled) var/mob/living/occupant = buckled_mob - unbuckle_mob() + unbuckle_mob(occupant) occupant.throw_at(A, 3, propelled) @@ -114,9 +117,10 @@ var/calculated_move_delay calculated_move_delay = 0 //bikes are infact sport bikes - if(buckled_mob) + if(has_buckled_mobs()) + var/mob/living/buckled_mob = buckled_mobs[1] if(buckled_mob.incapacitated()) - unbuckle_mob() //if the rider is incapacitated, unbuckle them (they can't balance so they fall off) + unbuckle_mob(buckled_mob) //if the rider is incapacitated, unbuckle them (they can't balance so they fall off) return 0 var/mob/living/thedriver = user @@ -151,4 +155,4 @@ . = 0 else - . = 1 + . = 1 \ No newline at end of file diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm index b2c29a5ee01..e35f9e86c68 100644 --- a/code/game/turfs/simulated/floor/lava.dm +++ b/code/game/turfs/simulated/floor/lava.dm @@ -84,17 +84,20 @@ var/mob/living/L = thing if(L.flying) continue //YOU'RE FLYING OVER IT + var/buckle_check = L.buckling + if(!buckle_check) + buckle_check = L.buckled + if(isobj(buckle_check)) + var/obj/O = buckle_check + if(O.resistance_flags & LAVA_PROOF) + continue + else if(isliving(buckle_check)) + var/mob/living/live = buckle_check + if("lava" in live.weather_immunities) + continue + if("lava" in L.weather_immunities) continue - if(L.buckled) - if(isobj(L.buckled)) - var/obj/O = L.buckled - if(O.resistance_flags & LAVA_PROOF) - continue - if(isliving(L.buckled)) //Goliath riding - var/mob/living/live = L.buckled - if("lava" in live.weather_immunities) - continue L.adjustFireLoss(20) if(L) //mobs turning into object corpses could get deleted here. diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index d6e72f1505c..699cbf5f803 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -248,23 +248,32 @@ var/obj/machinery/gateway/centerstation/the_gateway = null toggleoff() -/obj/machinery/gateway/centeraway/Bumped(atom/movable/M as mob|obj) +/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM) if(!ready) return if(!active) return - if(istype(M, /mob/living/carbon)) - if(exilecheck(M)) + if(!stationgate || QDELETED(stationgate)) + return + if(isliving(AM)) + if(exilecheck(AM)) return - if(istype(M, /obj)) - if(M.can_buckle && M.has_buckled_mobs()) - if(exilecheck(M.buckled_mob)) + else + for(var/mob/living/L in AM.contents) + if(exilecheck(L)) + atom_say("Rejecting [AM]: Exile implant detected in contained lifeform.") return - for(var/mob/living/carbon/F in M) - if(exilecheck(F)) + if(AM.has_buckled_mobs()) + for(var/mob/living/L in AM.buckled_mobs) + if(exilecheck(L)) + atom_say("Rejecting [AM]: Exile implant detected in close proximity lifeform.") return - M.forceMove(get_step(stationgate.loc, SOUTH)) - M.dir = SOUTH + AM.forceMove(get_step(stationgate.loc, SOUTH)) + AM.setDir(SOUTH) + if(ismob(AM)) + var/mob/M = AM + if(M.client) + M.client.move_delay = max(world.time + 5, M.client.move_delay) /obj/machinery/gateway/centeraway/proc/exilecheck(var/mob/living/carbon/M) for(var/obj/item/implant/exile/E in M)//Checking that there is an exile implant in the contents diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 7fce23b9e4c..36c3a9de5c5 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -2050,7 +2050,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if("ghost_radio") toggles ^= CHAT_GHOSTRADIO - + if("ghost_pda") toggles ^= CHAT_GHOSTPDA @@ -2104,7 +2104,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts "High" = PARALLAX_HIGH, "Insane" = PARALLAX_INSANE ) - parallax = parallax_styles[input(user, "Pick a parallax style", "Parallax Style") as null|anything in parallax_styles] + parallax = parallax_styles[input(user, "Pick a parallax style", "Parallax Style") as null|anything in parallax_styles] if(parent && parent.mob && parent.mob.hud_used) parent.mob.hud_used.update_parallax_pref() @@ -2189,12 +2189,8 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/obj/item/organ/external/l_foot = character.get_organ("l_foot") var/obj/item/organ/external/r_foot = character.get_organ("r_foot") if(!l_foot && !r_foot) - var/obj/structure/chair/wheelchair/W = new /obj/structure/chair/wheelchair (character.loc) - character.buckled = W - character.update_canmove() - W.dir = character.dir - W.buckled_mob = character - W.add_fingerprint(character) + var/obj/structure/chair/wheelchair/W = new /obj/structure/chair/wheelchair(character.loc) + W.buckle_mob(character, TRUE) character.underwear = underwear character.undershirt = undershirt diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm index fdd871a3448..700c88008e0 100644 --- a/code/modules/clothing/spacesuits/chronosuit.dm +++ b/code/modules/clothing/spacesuits/chronosuit.dm @@ -80,9 +80,7 @@ phaseanim.layer = FLY_LAYER phaseanim.master = user user.ExtinguishMob() - if(user.buckled) - user.buckled.unbuckle_mob() - user.loc = holder + user.forceMove(holder) flick("chronophase", phaseanim) spawn(7) if(user) diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 1ab7fe58c2b..f654f052ab7 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -323,8 +323,6 @@ var/turf/picked = pick(turfs) if(!isturf(picked)) return - if(H.buckled) - H.buckled.unbuckle_mob() H.forceMove(picked) return 1 return 0 diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm index aaed5f5672c..0bd4060c831 100644 --- a/code/modules/crafting/craft.dm +++ b/code/modules/crafting/craft.dm @@ -268,7 +268,8 @@ /datum/personal_crafting/proc/close(mob/user) var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") - ui.close() + if(ui) + ui.close() /datum/personal_crafting/ui_data(mob/user) var/list/data = list() diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 58579a893e2..c7330151b00 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -455,8 +455,8 @@ master = null mutations.Cut() set_opacity(0) - if(buckled_mob) - unbuckle_mob() + if(has_buckled_mobs()) + unbuckle_all_mobs(force = TRUE) return ..() /obj/structure/spacevine/proc/add_mutation(datum/spacevine_mutation/mutation) @@ -639,7 +639,7 @@ SM.on_grow(src) /obj/structure/spacevine/proc/entangle_mob() - if(!buckled_mob && prob(25)) + if(!has_buckled_mobs() && prob(25)) for(var/mob/living/V in loc) entangle(V) if(has_buckled_mobs()) diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 156a426e202..c045b8a5b88 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -108,7 +108,7 @@ icon_state = "bonfire" density = FALSE anchored = TRUE - buckle_lying = 0 + buckle_lying = FALSE var/burning = 0 var/fire_stack_strength = 5 @@ -119,8 +119,8 @@ if(istype(W, /obj/item/stack/rods) && !can_buckle) var/obj/item/stack/rods/R = W R.use(1) - can_buckle = 1 - buckle_requires_restraints = 1 + can_buckle = TRUE + buckle_requires_restraints = TRUE to_chat(user, "You add a rod to [src].") var/image/U = image(icon='icons/obj/hydroponics/equipment.dmi',icon_state="bonfire_rod",pixel_y=16) underlays += U @@ -191,11 +191,10 @@ set_light(0) STOP_PROCESSING(SSobj, src) -/obj/structure/bonfire/buckle_mob(mob/living/M, force = 0) +/obj/structure/bonfire/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(..()) M.pixel_y += 13 -/obj/structure/bonfire/unbuckle_mob(force=0) - if(buckled_mob) - buckled_mob.pixel_y -= 13 - . = ..() +/obj/structure/bonfire/unbuckle_mob(mob/living/buckled_mob, force = FALSE) + if(..()) + buckled_mob.pixel_y -= 13 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5ca13a616c1..de52fe192da 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -398,12 +398,8 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, if(ventcrawler) ventcrawlerlocal = ventcrawler - if(!ventcrawler) - if(ishuman(src)) - var/mob/living/carbon/human/H = src - ventcrawlerlocal = H.dna.species.ventcrawler - - if(!ventcrawlerlocal) return + if(!ventcrawlerlocal) + return if(stat) to_chat(src, "You must be conscious to do this!") @@ -413,8 +409,11 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, to_chat(src, "You can't vent crawl while you're stunned!") return - if(buckled_mob) - to_chat(src, "You can't vent crawl with [buckled_mob] on you!") + if(has_buckled_mobs()) + to_chat(src, "You can't vent crawl with other creatures on you!") + return + if(buckled) + to_chat(src, "You can't vent crawl while buckled!") return if(ishuman(src)) var/mob/living/carbon/human/H = src @@ -450,6 +449,10 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, if(!do_after(src, 45, target = src)) return + if(has_buckled_mobs()) + to_chat(src, "You can't vent crawl with other creatures on you!") + return + if(buckled) to_chat(src, "You cannot crawl into a vent while buckled to something!") return @@ -626,7 +629,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, else if(I == handcuffed) handcuffed = null if(buckled && buckled.buckle_requires_restraints) - buckled.unbuckle_mob() + buckled.unbuckle_mob(src) update_handcuffed() else if(I == legcuffed) legcuffed = null @@ -934,7 +937,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, var/obj/item/W = handcuffed handcuffed = null if(buckled && buckled.buckle_requires_restraints) - buckled.unbuckle_mob() + buckled.unbuckle_mob(src) update_handcuffed() if(client) client.screen -= W diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm index 2964166e68f..4cc542ae1ad 100644 --- a/code/modules/mob/living/carbon/human/login.dm +++ b/code/modules/mob/living/carbon/human/login.dm @@ -3,7 +3,7 @@ overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow") ..() - if(dna.species && dna.species.ventcrawler) + if(ventcrawler) to_chat(src, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.") update_pipe_vision() return diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 10b23dcfc82..d3ce27a4704 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -61,7 +61,7 @@ var/punchstunthreshold = 9 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical var/list/default_genes = list() - var/ventcrawler = 0 //Determines if the mob can go through the vents. + var/ventcrawler = VENTCRAWLER_NONE //Determines if the mob can go through the vents. var/has_fine_manipulation = 1 // Can use small items. var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here. @@ -280,10 +280,12 @@ H.unEquip(thing) if(H.hud_used) H.hud_used.update_locked_slots() + H.ventcrawler = ventcrawler /datum/species/proc/on_species_loss(mob/living/carbon/human/H) if(H.butcher_results) //clear it out so we don't butcher a actual human. H.butcher_results = null + H.ventcrawler = initial(H.ventcrawler) /datum/species/proc/updatespeciescolor(mob/living/carbon/human/H) //Handles changing icobase for species that have multiple skin colors. return diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm index e8451d61cbb..4b816f7ab5d 100644 --- a/code/modules/mob/living/carbon/human/species/golem.dm +++ b/code/modules/mob/living/carbon/human/species/golem.dm @@ -404,18 +404,11 @@ name = "Plastic Golem" prefix = "Plastic" special_names = null + ventcrawler = VENTCRAWLER_NUDE golem_colour = rgb(255, 255, 255) skinned_type = /obj/item/stack/sheet/plastic info_text = "As a Plastic Golem, you are capable of ventcrawling if you're naked." -/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species) - . = ..() - C.ventcrawler = VENTCRAWLER_NUDE - -/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C) - . = ..() - C.ventcrawler = initial(C.ventcrawler) - //Immune to physical bullets and resistant to brute, but very vulnerable to burn damage. Dusts on death. /datum/species/golem/sand name = "Sand Golem" @@ -533,7 +526,7 @@ if(!isturf(picked)) return if(H.buckled) - H.buckled.unbuckle_mob() + H.buckled.unbuckle_mob(H, force = TRUE) do_teleport(H, picked) return TRUE @@ -617,7 +610,7 @@ if(!isturf(picked)) return if(H.buckled) - H.buckled.unbuckle_mob() + H.buckled.unbuckle_mob(H, force = TRUE) do_teleport(H, picked) last_teleport = world.time UpdateButtonIcon() //action icon looks unavailable diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm index 4bfad7b15c9..a0980256718 100644 --- a/code/modules/mob/living/carbon/human/species/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/monkey.dm @@ -17,7 +17,7 @@ can_craft = FALSE is_small = 1 has_fine_manipulation = 0 - ventcrawler = 1 + ventcrawler = VENTCRAWLER_NUDE show_ssd = 0 eyes = "blank_eyes" death_message = "lets out a faint chimper as it collapses and stops moving..." diff --git a/code/modules/mob/living/carbon/slime/slime.dm b/code/modules/mob/living/carbon/slime/slime.dm index 89e6393cd09..afd358ab99f 100644 --- a/code/modules/mob/living/carbon/slime/slime.dm +++ b/code/modules/mob/living/carbon/slime/slime.dm @@ -72,6 +72,16 @@ X.stored_slimes -= src return ..() +/mob/living/carbon/slime/can_unbuckle() + return FALSE + +/mob/living/carbon/slime/can_buckle() + return FALSE + +/mob/living/carbon/slime/get_mob_buckling_height(mob/seat) + if(..()) + return 3 + /mob/living/carbon/slime/regenerate_icons() icon_state = "[colour] [is_adult ? "adult" : "baby"] slime" overlays.len = 0 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index df222fadf47..f659b4198d1 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -446,12 +446,7 @@ on_fire = 0 suiciding = 0 if(buckled) //Unbuckle the mob and clear the alerts. - buckled.buckled_mob = null - buckled = null - anchored = initial(anchored) - update_canmove() - clear_alert("buckled") - post_buckle_mob(src) + buckled.unbuckle_mob(src, force = TRUE) if(iscarbon(src)) var/mob/living/carbon/C = src @@ -637,11 +632,14 @@ START RESIST PROCS */////////////////////// +/mob/living/can_resist() + return !((next_move > world.time) || incapacitated(ignore_restraints = TRUE, ignore_lying = TRUE)) + /mob/living/verb/resist() set name = "Resist" set category = "IC" - if(!isliving(src) || next_move > world.time || stat || weakened || stunned || paralysis) + if(!can_resist()) return changeNext_move(CLICK_CD_RESIST) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index f624b7ab33d..e9cfac7ae0a 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -216,6 +216,9 @@ fire_stacks += L.fire_stacks IgniteMob() +/mob/living/can_be_pulled(user, grab_state, force) + return ..() && !(buckled && buckled.buckle_prevents_pull) + /mob/living/water_act(volume, temperature, source, method = TOUCH) . = ..() adjust_fire_stacks(-(volume * 0.2)) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 023c03cd00a..9605ae186a7 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1173,6 +1173,9 @@ var/list/ai_verbs_default = list( to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") to_chat(user, "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") +/mob/living/silicon/ai/can_buckle() + return FALSE + // Pass lying down or getting up to our pet human, if we're in a rig. /mob/living/silicon/ai/lay_down() set name = "Rest" diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index d9f1aac2757..d2e52c39197 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -124,6 +124,11 @@ securityActive2 = null return ..() +/mob/living/silicon/pai/can_unbuckle() + return FALSE + +/mob/living/silicon/pai/can_buckle() + return FALSE /mob/living/silicon/pai/movement_delay() . = ..() diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 1db149418c7..ef087c29b6d 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -17,7 +17,7 @@ maxHealth = 50 damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) a_intent = INTENT_HARM //No swapping - buckle_lying = 0 + buckle_lying = FALSE mob_size = MOB_SIZE_LARGE radio_channel = "Supply" @@ -372,7 +372,7 @@ if(isobj(AM)) var/obj/O = AM - if(O.buckled_mob || (locate(/mob) in AM)) //can't load non crates objects with mobs buckled to it or inside it. + if(O.has_buckled_mobs() || (locate(/mob) in AM)) //can't load non crates objects with mobs buckled to it or inside it. buzz(SIGH) return @@ -398,19 +398,11 @@ return FALSE /mob/living/simple_animal/bot/mulebot/post_buckle_mob(mob/living/M) - if(M == buckled_mob) //post buckling - M.pixel_y = initial(M.pixel_y) + 9 - if(M.layer < layer) - M.layer = layer + 0.1 - - else //post unbuckling - reset_buckled_mob(M) + M.pixel_y = initial(M.pixel_y) + 9 + if(M.layer < layer) + M.layer = layer + 0.01 /mob/living/simple_animal/bot/mulebot/post_unbuckle_mob(mob/living/M) - . = ..() - reset_buckled_mob(M) - -/mob/living/simple_animal/bot/mulebot/proc/reset_buckled_mob(mob/living/M) load = null M.layer = initial(M.layer) M.pixel_y = initial(M.pixel_y) @@ -429,12 +421,13 @@ if(ismob(load)) var/mob/M = load M.reset_perspective(null) - unbuckle_mob() + unbuckle_all_mobs() if(load) load.forceMove(loc) load.pixel_y = initial(load.pixel_y) load.layer = initial(load.layer) + load.plane = initial(load.plane) if(dirn) var/turf/T = loc var/turf/newT = get_step(T,dirn) @@ -453,6 +446,7 @@ AM.forceMove(loc) AM.layer = initial(AM.layer) AM.pixel_y = initial(AM.pixel_y) + AM.plane = initial(AM.plane) if(ismob(AM)) var/mob/M = AM M.reset_perspective(null) diff --git a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm index 244edaeedec..c3939e41395 100644 --- a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm +++ b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm @@ -313,7 +313,7 @@ if(T.density) forceMove(H.loc) if(H.buckled) - H.buckled.unbuckle_mob() + H.buckled.unbuckle_mob(H, force = TRUE) manifested = TRUE Manifest() to_chat(H, "You feel the floor closing in on your feet!") diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index c2d16069146..4e8da45a155 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -17,7 +17,7 @@ qdel(tkgrabbed_objects[I]) tkgrabbed_objects = null if(buckled) - buckled.unbuckle_mob() + buckled.unbuckle_mob(src, force = TRUE) if(viewing_alternate_appearances) for(var/datum/alternate_appearance/AA in viewing_alternate_appearances) AA.viewers -= src @@ -1192,31 +1192,52 @@ var/list/slot_equipment_priority = list( \ /mob/proc/handle_ventcrawl() return // Only living mobs can ventcrawl -//You can buckle on mobs if you're next to them since most are dense -/mob/buckle_mob(mob/living/M, force = 0) +/** + * Buckle to another mob + * + * You can buckle on mobs if you're next to them since most are dense + * + * Turns you to face the other mob too + */ +/mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(M.buckled) return 0 var/turf/T = get_turf(src) if(M.loc != T) var/old_density = density - density = 0 + density = FALSE var/can_step = step_towards(M, T) density = old_density if(!can_step) return 0 return ..() -//Default buckling shift visual for mobs +///Call back post buckle to a mob to offset your visual height /mob/post_buckle_mob(mob/living/M) - if(M == buckled_mob) //post buckling - M.pixel_y = initial(M.pixel_y) + 9 - if(M.layer < layer) - M.layer = layer + 0.1 - else //post unbuckling - M.layer = initial(M.layer) - M.pixel_y = initial(M.pixel_y) + var/height = M.get_mob_buckling_height(src) + M.pixel_y = initial(M.pixel_y) + height + if(M.layer < layer) + M.layer = layer + 0.1 -/mob/proc/can_unbuckle(mob/user) +///Call back post unbuckle from a mob, (reset your visual height here) +/mob/post_unbuckle_mob(mob/living/M) + M.layer = initial(M.layer) + M.pixel_y = initial(M.pixel_y) + +///returns the height in pixel the mob should have when buckled to another mob. +/mob/proc/get_mob_buckling_height(mob/seat) + if(isliving(seat)) + var/mob/living/L = seat + if(L.mob_size <= MOB_SIZE_SMALL) //being on top of a small mob doesn't put you very high. + return 0 + return 9 + +///can the mob be buckled to something by default? +/mob/proc/can_buckle() + return 1 + +///can the mob be unbuckled from something by default? +/mob/proc/can_unbuckle() return 1 @@ -1307,6 +1328,10 @@ var/list/slot_equipment_priority = list( \ .["Gib"] = "?_src_=vars;gib=[UID()]" +///Can this mob resist (default FALSE) +/mob/proc/can_resist() + return FALSE //overridden in living.dm + /mob/proc/spin(spintime, speed) set waitfor = 0 var/D = dir diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index b378705becb..c4d4ef24ed6 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -74,7 +74,11 @@ var/a_intent = INTENT_HELP//Living var/m_intent = MOVE_INTENT_RUN//Living var/lastKnownIP = null + /// movable atoms buckled to this mob var/atom/movable/buckled = null//Living + /// movable atom we are buckled to + var/atom/movable/buckling + var/obj/item/l_hand = null//Living var/obj/item/r_hand = null//Living var/obj/item/back = null//Human/Monkey diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 7f78f58eb72..c45ff96df34 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -8,13 +8,13 @@ if(mover.checkpass(PASSMOB)) return 1 if(buckled == mover) - return 1 + return TRUE if(ismob(mover)) var/mob/moving_mob = mover if((other_mobs && moving_mob.other_mobs)) - return 1 - if(mover == buckled_mob) - return 1 + return TRUE + if(mover in buckled_mobs) + return TRUE return (!mover.density || !density || lying) @@ -362,10 +362,14 @@ /mob/proc/Move_Pulled(atom/A) if(!canmove || restrained() || !pulling) return - if(pulling.anchored) - return - if(!pulling.Adjacent(src)) + if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src)) + stop_pulling() return + if(isliving(pulling)) + var/mob/living/L = pulling + if(L.buckled && L.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it + stop_pulling() + return if(A == loc && pulling.density) return if(!Process_Spacemove(get_dir(pulling.loc, A))) diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 2889a68c75b..785c03b13a1 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -92,17 +92,17 @@ potion_action.target = src potion_action.Grant(user) actions += potion_action - + if(hotkey_help) hotkey_help.target = src hotkey_help.Grant(user) actions += hotkey_help - RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl) - RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt) - RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift) - RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift) - RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl) + RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl) + RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt) + RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift) + RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift) + RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl) RegisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL, .proc/XenoMonkeyClickCtrl) if(!connected_recycler) @@ -112,12 +112,12 @@ connected_recycler.connected += src /obj/machinery/computer/camera_advanced/xenobio/remove_eye_control(mob/living/user) - UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL) - UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT) - UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT) - UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT) - UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL) - UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL) + UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL) + UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT) + UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT) + UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT) + UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL) + UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL) ..() /obj/machinery/computer/camera_advanced/xenobio/attack_hand(mob/user) @@ -197,7 +197,7 @@ break if(!S.ckey) if(S.buckled) - S.buckled.unbuckle_mob() + S.buckled.unbuckle_mob(S, force = TRUE) S.Feedstop() S.visible_message("[S] vanishes in a flash of light!") S.forceMove(X) @@ -240,7 +240,7 @@ var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control var/obj/machinery/computer/camera_advanced/xenobio/X = target var/obj/machinery/monkey_recycler/recycler = X.connected_recycler - + if(!recycler) to_chat(owner, "There is no connected monkey recycler. Use a multitool to link one.") return @@ -335,8 +335,9 @@ ..() //Pick up monkey -/mob/living/carbon/monkey/CtrlClick(mob/user) - SEND_SIGNAL(user, COMSIG_XENO_MONKEY_CLICK_CTRL, src) +/mob/living/carbon/human/CtrlClick(mob/user) + if(issmall(src)) + SEND_SIGNAL(user, COMSIG_XENO_MONKEY_CLICK_CTRL, src) ..() // Scans slime @@ -379,7 +380,7 @@ return if(!S.ckey) if(S.buckled) - S.buckled.unbuckle_mob() + S.buckled.unbuckle_mob(S, force = TRUE) S.Feedstop() S.visible_message("[S] vanishes in a flash of light!") S.forceMove(X) @@ -419,7 +420,7 @@ to_chat(user, "[X] now has [X.monkeys] monkeys left.") //Pick up monkey -/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/monkey/M) +/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/human/M) if(!cameranet.checkTurfVis(M.loc)) to_chat(user, "Target is not near a camera. Cannot proceed.") return diff --git a/code/modules/ruins/lavalandruin_code/fountain_hall.dm b/code/modules/ruins/lavalandruin_code/fountain_hall.dm index 3de758ac0c9..75e2b8d9aa3 100644 --- a/code/modules/ruins/lavalandruin_code/fountain_hall.dm +++ b/code/modules/ruins/lavalandruin_code/fountain_hall.dm @@ -12,7 +12,7 @@ return if(!has_buckled_mobs()) return - var/mob/living/L = buckled_mob + var/mob/living/L = locate() in buckled_mobs if(!L) return to_chat(user, "You attempt to sacrifice [L] by invoking the sacrificial ritual.") diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 8c96837e9d5..783f8203857 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -594,7 +594,7 @@ if(ismob(AM)) var/mob/M = AM if(M.buckled) - M.buckled.unbuckle_mob(M, 1) + M.buckled.unbuckle_mob(M, force = TRUE) if(isliving(AM)) var/mob/living/L = AM L.stop_pulling() diff --git a/code/modules/vehicle/ambulance.dm b/code/modules/vehicle/ambulance.dm index 102b8895bf6..f10f9d9769c 100644 --- a/code/modules/vehicle/ambulance.dm +++ b/code/modules/vehicle/ambulance.dm @@ -58,8 +58,8 @@ AA.Remove(M) /obj/vehicle/ambulance/post_unbuckle_mob(mob/living/M) - . = ..() AA.Remove(M) + return ..() /obj/item/key/ambulance name = "ambulance key" @@ -69,20 +69,22 @@ /obj/vehicle/ambulance/handle_vehicle_offsets() ..() - if(buckled_mob) - switch(buckled_mob.dir) - if(SOUTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 7 - if(WEST) - buckled_mob.pixel_x = 13 - buckled_mob.pixel_y = 7 - if(NORTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 4 - if(EAST) - buckled_mob.pixel_x = -13 - buckled_mob.pixel_y = 7 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + switch(buckled_mob.dir) + if(SOUTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 7 + if(WEST) + buckled_mob.pixel_x = 13 + buckled_mob.pixel_y = 7 + if(NORTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 4 + if(EAST) + buckled_mob.pixel_x = -13 + buckled_mob.pixel_y = 7 /obj/vehicle/ambulance/Move(newloc, Dir) var/oldloc = loc @@ -92,8 +94,10 @@ if(bed && get_dist(oldloc, loc) <= 2) bed.Move(oldloc) bed.dir = Dir - if(bed.buckled_mob) - bed.buckled_mob.dir = Dir + if(bed.has_buckled_mobs()) + for(var/m in bed.buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(Dir) /obj/structure/bed/amb_trolley name = "ambulance train trolley" diff --git a/code/modules/vehicle/atv.dm b/code/modules/vehicle/atv.dm index a67310c8874..a78791fddea 100644 --- a/code/modules/vehicle/atv.dm +++ b/code/modules/vehicle/atv.dm @@ -16,10 +16,13 @@ atvcover.layer = MOB_LAYER + 0.1 /obj/vehicle/atv/post_buckle_mob(mob/living/M) - if(buckled_mob) - overlays += atvcover - else - overlays -= atvcover + add_overlay(atvcover) + return ..() + +/obj/vehicle/atv/post_unbuckle_mob(mob/living/M) + if(!has_buckled_mobs()) + cut_overlay(atvcover) + return ..() /obj/vehicle/atv/handle_vehicle_layer() if(dir == SOUTH) diff --git a/code/modules/vehicle/janicart.dm b/code/modules/vehicle/janicart.dm index 8ee2d71443a..0f4382c92d1 100644 --- a/code/modules/vehicle/janicart.dm +++ b/code/modules/vehicle/janicart.dm @@ -10,20 +10,22 @@ /obj/vehicle/janicart/handle_vehicle_offsets() ..() - if(buckled_mob) - switch(buckled_mob.dir) - if(NORTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 4 - if(EAST) - buckled_mob.pixel_x = -12 - buckled_mob.pixel_y = 7 - if(SOUTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 7 - if(WEST) - buckled_mob.pixel_x = 12 - buckled_mob.pixel_y = 7 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + switch(buckled_mob.dir) + if(NORTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 4 + if(EAST) + buckled_mob.pixel_x = -12 + buckled_mob.pixel_y = 7 + if(SOUTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 7 + if(WEST) + buckled_mob.pixel_x = 12 + buckled_mob.pixel_y = 7 /obj/item/key/janitor diff --git a/code/modules/vehicle/motorcycle.dm b/code/modules/vehicle/motorcycle.dm index 3bcf98f2164..a79f8e3fa12 100644 --- a/code/modules/vehicle/motorcycle.dm +++ b/code/modules/vehicle/motorcycle.dm @@ -16,11 +16,14 @@ bikecover.layer = MOB_LAYER + 0.1 -obj/vehicle/motorcycle/post_buckle_mob(mob/living/M) - if(buckled_mob) - overlays += bikecover - else - overlays -= bikecover +/obj/vehicle/motorcycle/post_buckle_mob(mob/living/M) + add_overlay(bikecover) + return ..() + +/obj/vehicle/motorcycle/post_unbuckle_mob(mob/living/M) + if(!has_buckled_mobs()) + cut_overlay(bikecover) + return ..() /obj/vehicle/motorcycle/handle_vehicle_layer() diff --git a/code/modules/vehicle/speedbike.dm b/code/modules/vehicle/speedbike.dm index ac57e65b2e6..e1efe63bcbd 100644 --- a/code/modules/vehicle/speedbike.dm +++ b/code/modules/vehicle/speedbike.dm @@ -15,7 +15,7 @@ overlays += overlay /obj/vehicle/space/speedbike/Move(newloc,move_dir) - if(buckled_mob) + if(has_buckled_mobs()) new /obj/effect/temp_visual/dir_setting/speedbike_trail(loc) . = ..() @@ -29,21 +29,23 @@ pixel_y = 0 /obj/vehicle/space/speedbike/handle_vehicle_offsets() - if(buckled_mob) - buckled_mob.dir = dir - switch(dir) - if(NORTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = -8 - if(SOUTH) - buckled_mob.pixel_x = 0 - buckled_mob.pixel_y = 4 - if(EAST) - buckled_mob.pixel_x = -10 - buckled_mob.pixel_y = 5 - if(WEST) - buckled_mob.pixel_x = 10 - buckled_mob.pixel_y = 5 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(dir) + switch(dir) + if(NORTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = -8 + if(SOUTH) + buckled_mob.pixel_x = 0 + buckled_mob.pixel_y = 4 + if(EAST) + buckled_mob.pixel_x = -10 + buckled_mob.pixel_y = 5 + if(WEST) + buckled_mob.pixel_x = 10 + buckled_mob.pixel_y = 5 /obj/vehicle/space/speedbike/red icon_state = "speedbike_red" diff --git a/code/modules/vehicle/sportscar.dm b/code/modules/vehicle/sportscar.dm index 04ba5bdd2f5..f52f4b77a92 100644 --- a/code/modules/vehicle/sportscar.dm +++ b/code/modules/vehicle/sportscar.dm @@ -15,29 +15,33 @@ carcover = image("icons/vehicles/sportscar.dmi", "sportscar_cover") carcover.layer = MOB_LAYER + 0.1 - /obj/vehicle/car/post_buckle_mob(mob/living/M) - if(buckled_mob) - overlays += carcover - else - overlays -= carcover + add_overlay(carcover) + return ..() + +/obj/vehicle/car/post_unbuckle_mob(mob/living/M) + if(!has_buckled_mobs()) + cut_overlay(carcover) + return ..() /obj/vehicle/car/handle_vehicle_offsets() ..() - if(buckled_mob) - switch(buckled_mob.dir) - if(NORTH) - buckled_mob.pixel_x = 2 - buckled_mob.pixel_y = 20 - if(EAST) - buckled_mob.pixel_x = 20 - buckled_mob.pixel_y = 23 - if(SOUTH) - buckled_mob.pixel_x = 20 - buckled_mob.pixel_y = 27 - if(WEST) - buckled_mob.pixel_x = 34 - buckled_mob.pixel_y = 10 + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + switch(buckled_mob.dir) + if(NORTH) + buckled_mob.pixel_x = 2 + buckled_mob.pixel_y = 20 + if(EAST) + buckled_mob.pixel_x = 20 + buckled_mob.pixel_y = 23 + if(SOUTH) + buckled_mob.pixel_x = 20 + buckled_mob.pixel_y = 27 + if(WEST) + buckled_mob.pixel_x = 34 + buckled_mob.pixel_y = 10 /obj/vehicle/car/handle_vehicle_layer() diff --git a/code/modules/vehicle/vehicle.dm b/code/modules/vehicle/vehicle.dm index fc2ea3b4600..9b3a747b7ff 100644 --- a/code/modules/vehicle/vehicle.dm +++ b/code/modules/vehicle/vehicle.dm @@ -6,14 +6,14 @@ icon_state = "scooter" density = 1 anchored = 0 - can_buckle = 1 - buckle_lying = 0 + can_buckle = TRUE + buckle_lying = FALSE armor = list("melee" = 30, "bullet" = 30, "laser" = 30, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0) var/keytype = null //item typepath, if non-null an item of this type is needed in your hands to drive this vehicle var/next_vehicle_move = 0 //used for move delays var/vehicle_move_delay = 2 //tick delay between movements, lower = faster, higher = slower var/auto_door_open = TRUE - var/needs_gravity = 0//To allow non-space vehicles to move in no gravity or not, mostly for adminbus + var/needs_gravity = 0 //To allow non-space vehicles to move in no gravity or not, mostly for adminbus //Pixels var/generic_pixel_x = 0 //All dirs show this pixel_x for the driver var/generic_pixel_y = 0 //All dirs shwo this pixel_y for the driver @@ -37,25 +37,26 @@ //if they differ between directions, otherwise use the //generic variables /obj/vehicle/proc/handle_vehicle_offsets() - if(buckled_mob) - buckled_mob.dir = dir - buckled_mob.pixel_x = generic_pixel_x - buckled_mob.pixel_y = generic_pixel_y + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.setDir(dir) + buckled_mob.pixel_x = generic_pixel_x + buckled_mob.pixel_y = generic_pixel_y /obj/vehicle/update_icon() return - //KEYS /obj/vehicle/proc/keycheck(mob/user) if(keytype) if(istype(user.l_hand, keytype) || istype(user.r_hand, keytype)) - return 1 + return TRUE else - return 1 - return 0 + return TRUE + return FALSE /obj/item/key name = "key" @@ -66,8 +67,8 @@ //BUCKLE HOOKS -/obj/vehicle/unbuckle_mob(force = 0) - if(buckled_mob) +/obj/vehicle/unbuckle_mob(mob/living/buckled_mob, force = FALSE) + if(istype(buckled_mob)) buckled_mob.pixel_x = 0 buckled_mob.pixel_y = 0 . = ..() @@ -80,38 +81,45 @@ if(A.density) if(A != src && A != M) return - M.loc = get_turf(src) + M.forceMove(get_turf(src)) ..() handle_vehicle_offsets() - /obj/vehicle/bullet_act(obj/item/projectile/Proj) - if(buckled_mob) - buckled_mob.bullet_act(Proj) + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.bullet_act(Proj) //MOVEMENT /obj/vehicle/relaymove(mob/user, direction) if(user.incapacitated()) - unbuckle_mob() + unbuckle_mob(user) + return + if(world.time < next_vehicle_move) + return + next_vehicle_move = world.time + vehicle_move_delay if(keycheck(user)) - if(!Process_Spacemove(direction) || world.time < next_vehicle_move || !isturf(loc)) return - next_vehicle_move = world.time + vehicle_move_delay - + if(!Process_Spacemove(direction) || !isturf(loc)) + return step(src, direction) - if(buckled_mob) - if(buckled_mob.loc != loc) - buckled_mob.buckled = null //Temporary, so Move() succeeds. - buckled_mob.buckled = src //Restoring + if(has_buckled_mobs()) + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + if(buckled_mob.loc != loc) + buckled_mob.buckled = null //Temporary, so Move() succeeds. + buckled_mob.buckled = src //Restoring - if(istype(src.loc, /turf/simulated)) - var/turf/simulated/T = src.loc + if(issimulatedturf(loc)) + var/turf/simulated/T = loc if(T.wet == TURF_WET_LUBE) //Lube! Fall off! playsound(src, 'sound/misc/slip.ogg', 50, 1, -3) - buckled_mob.Stun(7) - buckled_mob.Weaken(7) - unbuckle_mob() + for(var/m in buckled_mobs) + var/mob/living/buckled_mob = m + buckled_mob.Weaken(5) + unbuckle_all_mobs() step(src, dir) handle_vehicle_layer() @@ -121,7 +129,7 @@ /obj/vehicle/Move(NewLoc,Dir=0,step_x=0,step_y=0) - ..() + . = ..() handle_vehicle_layer() handle_vehicle_offsets() @@ -133,11 +141,12 @@ /obj/vehicle/Bump(atom/movable/M) if(!spaceworthy && isspaceturf(get_turf(src))) - return 0 + return FALSE . = ..() if(auto_door_open) - if(istype(M, /obj/machinery/door) && buckled_mob) - M.Bumped(buckled_mob) + if(istype(M, /obj/machinery/door) && has_buckled_mobs()) + for(var/m in buckled_mobs) + M.Bumped(m) /obj/vehicle/proc/RunOver(var/mob/living/carbon/human/H) return //write specifics for different vehicles @@ -145,19 +154,19 @@ /obj/vehicle/Process_Spacemove(direction) if(has_gravity(src)) - return 1 + return TRUE - if(pulledby && pulledby != buckled_mob) // no pulling the vehicle you're driving through space! - return 1 + if(pulledby && (pulledby.loc != loc)) + return TRUE if(needs_gravity) - return 1 + return TRUE - return 0 + return FALSE /obj/vehicle/space pressure_resistance = INFINITY spaceworthy = TRUE /obj/vehicle/space/Process_Spacemove(direction) - return 1 + return TRUE \ No newline at end of file diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 2fe2c7cd21c..367a42a6c79 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ