From c87389a595299e784bc2dfb095e731b3b430e296 Mon Sep 17 00:00:00 2001 From: Fox McCloud Date: Sun, 22 Sep 2019 21:22:57 -0400 Subject: [PATCH] TG Buckle Update (#12375) --- code/ATMOSPHERICS/atmospherics.dm | 6 +- code/ATMOSPHERICS/pipes/pipe.dm | 4 +- .../pipes/simple/pipe_simple_he.dm | 8 +- code/_onclick/hud/alert.dm | 10 ++ code/datums/helper_datums/teleport.dm | 2 +- code/datums/spells/area_teleport.dm | 2 +- code/datums/spells/devil.dm | 8 -- .../weather/weather_types/floor_is_lava.dm | 4 +- code/game/atoms_movable.dm | 28 ++-- .../miniantags/slaughter/bloodcrawl.dm | 7 +- .../shadowling/shadowling_abilities.dm | 8 +- code/game/gamemodes/vampire/vampire_powers.dm | 8 -- code/game/machinery/OpTable.dm | 2 +- code/game/machinery/portable_turret.dm | 5 +- code/game/objects/buckling.dm | 132 ++++++++++-------- .../items/weapons/implants/implantchair.dm | 2 +- code/game/objects/items/weapons/scrolls.dm | 4 +- .../structures/crates_lockers/crates.dm | 4 +- code/game/objects/structures/electricchair.dm | 13 +- code/game/objects/structures/guillotine.dm | 32 +++-- code/game/objects/structures/kitchen_spike.dm | 100 +++++++------ code/game/objects/structures/plasticflaps.dm | 53 +++---- .../stool_bed_chair_nest/alien_nests.dm | 85 ++++++----- .../structures/stool_bed_chair_nest/bed.dm | 21 +-- .../structures/stool_bed_chair_nest/chairs.dm | 39 +++--- .../stool_bed_chair_nest/wheelchair.dm | 22 +-- code/game/turfs/simulated/floor/lava.dm | 21 +-- code/modules/awaymissions/gateway.dm | 29 ++-- code/modules/client/preference/preferences.dm | 12 +- .../modules/clothing/spacesuits/chronosuit.dm | 4 +- code/modules/clothing/suits/armor.dm | 2 - code/modules/crafting/craft.dm | 3 +- code/modules/events/spacevine.dm | 6 +- code/modules/hydroponics/grown/towercap.dm | 15 +- code/modules/mob/living/carbon/carbon.dm | 23 +-- code/modules/mob/living/carbon/human/login.dm | 2 +- .../living/carbon/human/species/_species.dm | 4 +- .../mob/living/carbon/human/species/golem.dm | 13 +- .../mob/living/carbon/human/species/monkey.dm | 2 +- code/modules/mob/living/carbon/slime/slime.dm | 10 ++ code/modules/mob/living/living.dm | 12 +- code/modules/mob/living/living_defense.dm | 3 + code/modules/mob/living/silicon/ai/ai.dm | 3 + code/modules/mob/living/silicon/pai/pai.dm | 5 + .../mob/living/simple_animal/bot/mulebot.dm | 22 ++- .../simple_animal/hostile/floorcluwne.dm | 2 +- code/modules/mob/mob.dm | 51 +++++-- code/modules/mob/mob_defines.dm | 4 + code/modules/mob/mob_movement.dm | 18 ++- .../research/xenobiology/xenobio_camera.dm | 37 ++--- .../ruins/lavalandruin_code/fountain_hall.dm | 2 +- code/modules/shuttle/shuttle.dm | 2 +- code/modules/vehicle/ambulance.dm | 38 ++--- code/modules/vehicle/atv.dm | 11 +- code/modules/vehicle/janicart.dm | 30 ++-- code/modules/vehicle/motorcycle.dm | 13 +- code/modules/vehicle/speedbike.dm | 34 ++--- code/modules/vehicle/sportscar.dm | 42 +++--- code/modules/vehicle/vehicle.dm | 89 ++++++------ icons/mob/screen_alert.dmi | Bin 50050 -> 51466 bytes 60 files changed, 640 insertions(+), 533 deletions(-) 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 2fe2c7cd21cb4000d3379cb959781975b8caa580..367a42a6c79208124bb824cb49ef5053683966ae 100644 GIT binary patch delta 12308 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 YaX{%JEf*VOLqZ%1A3n>~%9w=wAMU_oh5!Hn delta 10881 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