mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
* it begins * Update gun.dm * misc fixes * Update gun.dm * more fixes * Update lightning_flow.dm * i may be stupid * Update suicide.dm * fix mech strafing * Update mecha.dm * let there be qol * ghost stuff * Update screen_clockwork.dmi * does the stuff * stuff * Update worldbreaker.dm * moltial arts * Update worldbreaker.dm * CRITICAL FIX * mech stuff * Update tables_racks.dm * stuff * fix seismic arm * buster/seismic arm fix 2 * saber + lockers * stuff * hand tele and pre_attack_secondary * more right click acts * Update closets.dm * who did this * heck * Update mob.dm * Update items.dm * darkspawn fix * fixes wound healing * Update item_attack.dm * minor qol stuff * Update kinetic_crusher.dm * Update kinetic_crusher.dm * runtime fix * Update kinetic_crusher.dm * Update screen_plasmafire.dmi * stuff * syringes * i am very silly * death to /obj/item/toolset_handler * Update assembly.dm * surgery fix + hypo stuff * mantis fix * gas harpoon * atmos machines --------- Co-authored-by: Molti <gamingjoelouis@gmail.com>
486 lines
18 KiB
Plaintext
486 lines
18 KiB
Plaintext
/**
|
|
* This is the riding component, which is applied to a movable atom by the [ridable element][/datum/element/ridable] when a mob is successfully buckled to said movable.
|
|
*
|
|
* This component lives for as long as at least one mob is buckled to the parent. Once all mobs are unbuckled, the component is deleted, until another mob is buckled in
|
|
* and we make a new riding component, so on and so forth until the sun explodes.
|
|
*/
|
|
|
|
/datum/component/riding
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE
|
|
|
|
var/last_move_diagonal = FALSE
|
|
///tick delay between movements, lower = faster, higher = slower
|
|
var/vehicle_move_delay = 2
|
|
|
|
var/last_vehicle_move = 0 //used for move delays
|
|
|
|
|
|
/**
|
|
* If the driver needs a certain item in hand (or inserted, for vehicles) to drive this. For vehicles, this must be duplicated on the actual vehicle object in their
|
|
* [/obj/vehicle/var/key_type] variable because the vehicle objects still have a few special checks/functions of their own I'm not porting over to the riding component
|
|
* quite yet. Make sure if you define it on the vehicle, you define it here too.
|
|
*/
|
|
var/keytype
|
|
|
|
var/slowed = FALSE
|
|
var/slowvalue = 1
|
|
|
|
/// position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
|
|
var/list/riding_offsets = list()
|
|
/// ["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
|
|
var/list/directional_vehicle_layers = list()
|
|
/// same as above but instead of layer you have a list(px, py)
|
|
var/list/directional_vehicle_offsets = list()
|
|
/// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
|
|
var/list/allowed_turf_typecache
|
|
/// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
|
|
var/list/forbid_turf_typecache
|
|
/// We don't need roads where we're going if this is TRUE, allow normal movement in space tiles
|
|
var/override_allow_spacemove = FALSE
|
|
/// can anyone other than the rider unbuckle the rider?
|
|
var/can_force_unbuckle = TRUE
|
|
|
|
/**
|
|
* Ride check flags defined for the specific riding component types, so we know if we need arms, legs, or whatever.
|
|
* Takes additional flags from the ridable element and the buckle proc (buckle_mob_flags) for riding cyborgs/humans in case we need to reserve arms
|
|
*/
|
|
var/ride_check_flags = NONE
|
|
/// For telling someone they can't drive
|
|
COOLDOWN_DECLARE(message_cooldown)
|
|
/// For telling someone they can't drive
|
|
COOLDOWN_DECLARE(vehicle_move_cooldown)
|
|
|
|
|
|
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
|
|
var/drive_verb = "drive"
|
|
var/ride_check_rider_incapacitated = FALSE
|
|
var/ride_check_rider_restrained = FALSE
|
|
var/ride_check_ridden_incapacitated = FALSE
|
|
|
|
var/del_on_unbuckle_all = FALSE
|
|
|
|
/datum/component/riding/Initialize()
|
|
if(!ismovable(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, PROC_REF(vehicle_mob_buckle))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_UNBUCKLE, PROC_REF(vehicle_mob_unbuckle))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(vehicle_moved))
|
|
RegisterSignal(parent, COMSIG_BUCKLED_CAN_Z_MOVE, PROC_REF(riding_can_z_move))
|
|
|
|
/datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
|
|
var/atom/movable/AM = parent
|
|
restore_position(M)
|
|
unequip_buckle_inhands(M)
|
|
M.updating_glide_size = TRUE
|
|
if(AM.movement_type & FLYING)
|
|
M.movement_type &= ~FLYING
|
|
if(del_on_unbuckle_all && !AM.has_buckled_mobs())
|
|
qdel(src)
|
|
|
|
/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
|
|
var/atom/movable/AM = parent
|
|
M.set_glide_size(AM.glide_size)
|
|
M.updating_glide_size = FALSE
|
|
handle_vehicle_offsets()
|
|
if(AM.movement_type & FLYING)
|
|
M.movement_type |= FLYING
|
|
|
|
/// Some ridable atoms may want to only show on top of the rider in certain directions, like wheelchairs
|
|
/datum/component/riding/proc/handle_vehicle_layer(dir)
|
|
var/atom/movable/AM = parent
|
|
var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER)
|
|
. = defaults["[dir]"]
|
|
if(directional_vehicle_layers["[dir]"])
|
|
. = directional_vehicle_layers["[dir]"]
|
|
if(isnull(.)) //you can set it to null to not change it.
|
|
. = AM.layer
|
|
AM.layer = .
|
|
|
|
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
|
|
directional_vehicle_layers["[dir]"] = layer
|
|
|
|
/datum/component/riding/proc/vehicle_moved(datum/source, oldloc, dir, forced)
|
|
var/atom/movable/AM = parent
|
|
for(var/mob/M in AM.buckled_mobs)
|
|
ride_check(M)
|
|
handle_vehicle_offsets()
|
|
handle_vehicle_layer(dir)
|
|
|
|
/datum/component/riding/proc/ride_check(mob/living/M)
|
|
var/atom/movable/AM = parent
|
|
var/mob/AMM = AM
|
|
if(AM.movement_type & FLYING)
|
|
AMM.movement_type |= FLYING
|
|
else
|
|
AMM.movement_type &= ~FLYING
|
|
if((ride_check_rider_restrained && M.restrained(TRUE)) || (ride_check_rider_incapacitated && M.incapacitated(FALSE, TRUE)) || (ride_check_ridden_incapacitated && istype(AMM) && AMM.incapacitated(FALSE, TRUE)))
|
|
AM.visible_message(span_warning("[M] falls off of [AM]!"))
|
|
AM.unbuckle_mob(M)
|
|
return TRUE
|
|
|
|
/datum/component/riding/proc/force_dismount(mob/living/M)
|
|
var/atom/movable/AM = parent
|
|
AM.unbuckle_mob(M)
|
|
|
|
/datum/component/riding/proc/handle_vehicle_offsets()
|
|
var/atom/movable/AM = parent
|
|
var/AM_dir = "[AM.dir]"
|
|
var/passindex = 0
|
|
if(AM.has_buckled_mobs())
|
|
for(var/m in AM.buckled_mobs)
|
|
passindex++
|
|
var/mob/living/buckled_mob = m
|
|
var/list/offsets = get_offsets(passindex)
|
|
var/rider_dir = get_rider_dir(passindex)
|
|
buckled_mob.setDir(rider_dir)
|
|
dir_loop:
|
|
for(var/offsetdir in offsets)
|
|
if(offsetdir == AM_dir)
|
|
var/list/diroffsets = offsets[offsetdir]
|
|
buckled_mob.pixel_x = diroffsets[1]
|
|
if(diroffsets.len >= 2)
|
|
buckled_mob.pixel_y = diroffsets[2]
|
|
if(diroffsets.len == 3)
|
|
buckled_mob.layer = diroffsets[3]
|
|
break dir_loop
|
|
var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
|
|
var/px = default_vehicle_pixel_offsets[AM_dir]
|
|
var/py = default_vehicle_pixel_offsets[AM_dir]
|
|
if(directional_vehicle_offsets[AM_dir])
|
|
if(isnull(directional_vehicle_offsets[AM_dir]))
|
|
px = AM.pixel_x
|
|
py = AM.pixel_y
|
|
else
|
|
px = directional_vehicle_offsets[AM_dir][1]
|
|
py = directional_vehicle_offsets[AM_dir][2]
|
|
AM.pixel_x = px
|
|
AM.pixel_y = py
|
|
|
|
/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y)
|
|
directional_vehicle_offsets["[dir]"] = list(x, y)
|
|
|
|
//Override this to set your vehicle's various pixel offsets
|
|
/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
|
|
. = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
|
|
if(riding_offsets["[pass_index]"])
|
|
. = riding_offsets["[pass_index]"]
|
|
else if(riding_offsets["[RIDING_OFFSET_ALL]"])
|
|
. = riding_offsets["[RIDING_OFFSET_ALL]"]
|
|
|
|
/datum/component/riding/proc/set_riding_offsets(index, list/offsets)
|
|
if(!islist(offsets))
|
|
return FALSE
|
|
riding_offsets["[index]"] = offsets
|
|
|
|
//Override this to set the passengers/riders dir based on which passenger they are.
|
|
//ie: rider facing the vehicle's dir, but passenger 2 facing backwards, etc.
|
|
/datum/component/riding/proc/get_rider_dir(pass_index)
|
|
var/atom/movable/AM = parent
|
|
return AM.dir
|
|
|
|
//KEYS
|
|
/datum/component/riding/proc/keycheck(mob/user)
|
|
return !keytype || user.is_holding_item_of_type(keytype)
|
|
|
|
//BUCKLE HOOKS
|
|
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
|
|
if(isnull(buckled_mob))
|
|
return
|
|
buckled_mob.pixel_x = buckled_mob.base_pixel_x
|
|
buckled_mob.pixel_y = buckled_mob.base_pixel_y
|
|
var/atom/source = parent
|
|
SET_PLANE_EXPLICIT(buckled_mob, initial(buckled_mob.plane), source)
|
|
if(buckled_mob.client)
|
|
buckled_mob.client.view_size.resetToDefault()
|
|
|
|
//MOVEMENT
|
|
/datum/component/riding/proc/turf_check(turf/next, turf/current)
|
|
if(allowed_turf_typecache && !allowed_turf_typecache[next.type])
|
|
return (allow_one_away_from_valid_turf && allowed_turf_typecache[current.type])
|
|
else if(forbid_turf_typecache && forbid_turf_typecache[next.type])
|
|
return (allow_one_away_from_valid_turf && !forbid_turf_typecache[current.type])
|
|
return TRUE
|
|
|
|
/datum/component/riding/proc/handle_ride(mob/user, direction)
|
|
var/atom/movable/AM = parent
|
|
if(user.incapacitated())
|
|
Unbuckle(user)
|
|
return
|
|
|
|
if(world.time < last_vehicle_move + ((last_move_diagonal? 2 : 1) * vehicle_move_delay * CONFIG_GET(number/movedelay/run_delay))) //yogs - fixed this to work with movespeed
|
|
return
|
|
|
|
AM.set_glide_size((last_move_diagonal? 2 : 1) * DELAY_TO_GLIDE_SIZE(vehicle_move_delay) * CONFIG_GET(number/movedelay/run_delay))
|
|
for(var/mob/M in AM.buckled_mobs)
|
|
ride_check(M)
|
|
M.set_glide_size(AM.glide_size)
|
|
last_vehicle_move = world.time
|
|
|
|
if(keycheck(user))
|
|
var/turf/next = get_step(AM, direction)
|
|
var/turf/current = get_turf(AM)
|
|
if(!istype(next) || !istype(current))
|
|
return //not happening.
|
|
if(!turf_check(next, current))
|
|
to_chat(user, "Your \the [AM] can not go onto [next]!")
|
|
return
|
|
if(!Process_Spacemove(direction) || !isturf(AM.loc))
|
|
return
|
|
step(AM, direction)
|
|
|
|
if((direction & (direction - 1)) && (AM.loc == next)) //moved diagonally
|
|
last_move_diagonal = TRUE
|
|
else
|
|
last_move_diagonal = FALSE
|
|
AM.set_glide_size((last_move_diagonal? 2 : 1) * DELAY_TO_GLIDE_SIZE(vehicle_move_delay) * CONFIG_GET(number/movedelay/run_delay))
|
|
for(var/mob/M in AM.buckled_mobs)
|
|
ride_check(M)
|
|
M.set_glide_size(AM.glide_size)
|
|
|
|
handle_vehicle_layer(direction)
|
|
handle_vehicle_offsets()
|
|
else
|
|
to_chat(user, span_notice("You'll need the keys in one of your hands to [drive_verb] [AM]."))
|
|
|
|
/datum/component/riding/proc/Unbuckle(atom/movable/M)
|
|
addtimer(CALLBACK(parent, TYPE_PROC_REF(/atom/movable, unbuckle_mob), M), 0, TIMER_UNIQUE)
|
|
|
|
/datum/component/riding/proc/Process_Spacemove(direction)
|
|
var/atom/movable/AM = parent
|
|
return override_allow_spacemove || AM.has_gravity()
|
|
|
|
/datum/component/riding/proc/account_limbs(mob/living/M)
|
|
if(M.get_num_legs() < 2 && !slowed)
|
|
vehicle_move_delay = vehicle_move_delay + slowvalue
|
|
slowed = TRUE
|
|
else if(slowed)
|
|
vehicle_move_delay = vehicle_move_delay - slowvalue
|
|
slowed = FALSE
|
|
|
|
///////Yes, I said humans. No, this won't end well...//////////
|
|
/datum/component/riding/human
|
|
del_on_unbuckle_all = TRUE
|
|
|
|
/datum/component/riding/human/Initialize()
|
|
. = ..()
|
|
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, PROC_REF(on_host_unarmed_melee))
|
|
|
|
/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
|
|
unequip_buckle_inhands(parent)
|
|
var/mob/living/carbon/human/AM = parent
|
|
AM.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
|
|
. = ..()
|
|
|
|
/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
|
|
. = ..()
|
|
var/mob/living/carbon/human/AM = parent
|
|
var/slowdown = AM.dna.check_mutation(STRONG) ? 0 : HUMAN_CARRY_SLOWDOWN
|
|
AM.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = slowdown)
|
|
|
|
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target, modifiers)
|
|
var/mob/living/carbon/human/AM = parent
|
|
if(modifiers && modifiers[RIGHT_CLICK] && (target in AM.buckled_mobs))
|
|
force_dismount(target)
|
|
|
|
/datum/component/riding/human/handle_vehicle_layer(dir)
|
|
var/atom/movable/AM = parent
|
|
if(!AM.buckled_mobs || !AM.buckled_mobs.len)
|
|
AM.layer = MOB_LAYER
|
|
return
|
|
|
|
for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied
|
|
M.layer = MOB_LAYER
|
|
|
|
if(!AM.buckle_lying) // rider is vertical, must be piggybacking
|
|
if(dir == SOUTH)
|
|
AM.layer = MOB_ABOVE_PIGGYBACK_LAYER
|
|
else
|
|
AM.layer = MOB_BELOW_PIGGYBACK_LAYER
|
|
else // laying flat, we must be firemanning the rider
|
|
if(dir == NORTH)
|
|
AM.layer = MOB_BELOW_PIGGYBACK_LAYER
|
|
else
|
|
AM.layer = MOB_ABOVE_PIGGYBACK_LAYER
|
|
|
|
/datum/component/riding/human/get_offsets(pass_index)
|
|
var/mob/living/carbon/human/H = parent
|
|
if(H.buckle_lying)
|
|
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6))
|
|
else
|
|
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))
|
|
|
|
/datum/component/riding/human/force_dismount(mob/living/user)
|
|
var/atom/movable/AM = parent
|
|
AM.unbuckle_mob(user)
|
|
user.Knockdown(60)
|
|
user.visible_message(span_warning("[AM] pushes [user] off of [AM.p_them()]!"))
|
|
|
|
/datum/component/riding/human/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
|
|
if(!(z_move_flags & ZMOVE_CAN_FLY_CHECKS))
|
|
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
|
|
// if(!can_be_driven)
|
|
// if(z_move_flags & ZMOVE_FEEDBACK)
|
|
// to_chat(rider, span_warning("[movable_parent] cannot be driven around. Unbuckle from [movable_parent.p_them()] first."))
|
|
// return COMPONENT_RIDDEN_STOP_Z_MOVE
|
|
if(!ride_check(rider, FALSE))
|
|
if(z_move_flags & ZMOVE_FEEDBACK)
|
|
to_chat(rider, span_warning("You're unable to ride [movable_parent] right now!"))
|
|
return COMPONENT_RIDDEN_STOP_Z_MOVE
|
|
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
|
|
|
|
/datum/component/riding/cyborg
|
|
del_on_unbuckle_all = TRUE
|
|
|
|
/datum/component/riding/cyborg/ride_check(mob/user)
|
|
var/atom/movable/AM = parent
|
|
if(user.incapacitated())
|
|
var/kick = TRUE
|
|
if(iscyborg(AM))
|
|
var/mob/living/silicon/robot/R = AM
|
|
if(R.module && R.module.ride_allow_incapacitated)
|
|
kick = FALSE
|
|
if(kick)
|
|
to_chat(user, span_userdanger("You fall off of [AM]!"))
|
|
Unbuckle(user)
|
|
return
|
|
if(iscarbon(user))
|
|
var/mob/living/carbon/carbonuser = user
|
|
if(!carbonuser.get_num_arms())
|
|
Unbuckle(user)
|
|
to_chat(user, span_userdanger("You can't grab onto [AM] with no hands!"))
|
|
return
|
|
|
|
/datum/component/riding/cyborg/handle_vehicle_layer(dir)
|
|
var/atom/movable/robot_parent = parent
|
|
if(dir == SOUTH)
|
|
robot_parent.layer = MOB_ABOVE_PIGGYBACK_LAYER
|
|
else
|
|
robot_parent.layer = MOB_BELOW_PIGGYBACK_LAYER
|
|
|
|
/datum/component/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer)
|
|
return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3))
|
|
|
|
/datum/component/riding/cyborg/handle_vehicle_offsets()
|
|
var/atom/movable/AM = parent
|
|
if(AM.has_buckled_mobs())
|
|
for(var/mob/living/M in AM.buckled_mobs)
|
|
M.setDir(AM.dir)
|
|
if(iscyborg(AM))
|
|
var/mob/living/silicon/robot/R = AM
|
|
if(istype(R.module))
|
|
M.pixel_x = R.module.ride_offset_x[dir2text(AM.dir)]
|
|
M.pixel_y = R.module.ride_offset_y[dir2text(AM.dir)]
|
|
else
|
|
..()
|
|
|
|
/datum/component/riding/cyborg/force_dismount(mob/living/M)
|
|
var/atom/movable/AM = parent
|
|
var/mob/living/silicon/robot/S = AM
|
|
if(S.throwcooldown)
|
|
to_chat(S, "You have to wait for your motors to recharge")
|
|
return
|
|
M.visible_message(span_warning("[AM] queues their servos to fling [M]!"))
|
|
playsound(AM,'sound/misc/borg/fling_start.ogg',80,1,-1)
|
|
if(!do_after(AM, 1 SECONDS, M))
|
|
M.visible_message(span_boldwarning("[AM]'s servos disengage!"))
|
|
playsound(AM,'sound/misc/borg/fling_cancel.ogg',80,1,-1)
|
|
return
|
|
//sanity check after the timer to make sure they're still buckled
|
|
if(!S.has_buckled_mobs())
|
|
M.visible_message(span_boldwarning("[AM]'s servos pop!"))
|
|
playsound(AM,'sound/misc/borg/fling_pop.ogg',80,1,-1)
|
|
//consider adding some damage as a borg if you mess up your timing
|
|
return;
|
|
//if we're a borg with a person we're gonna wait until here to spin so it waits until after we charge up the servos
|
|
S.spin(20, 1)
|
|
playsound(AM,'sound/misc/borg/fling_throw.ogg',80,1,-1)
|
|
AM.unbuckle_mob(M)
|
|
var/turf/target = get_edge_target_turf(AM, AM.dir)
|
|
var/turf/targetm = get_step(get_turf(AM), AM.dir)
|
|
M.Move(targetm)
|
|
M.visible_message(span_warning("[M] is thrown clear of [AM]!"))
|
|
M.throw_at(target, 14, 5, AM)
|
|
M.Paralyze(60)
|
|
S.throwcooldown = TRUE
|
|
addtimer(VARSET_CALLBACK(S, throwcooldown, FALSE), 10 SECONDS)
|
|
|
|
/datum/component/riding/cyborg/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
|
|
if(!(z_move_flags & ZMOVE_CAN_FLY_CHECKS))
|
|
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
|
|
// if(!can_be_driven)
|
|
// if(z_move_flags & ZMOVE_FEEDBACK)
|
|
// to_chat(rider, span_warning("[movable_parent] cannot be driven around. Unbuckle from [movable_parent.p_them()] first."))
|
|
// return COMPONENT_RIDDEN_STOP_Z_MOVE
|
|
if(!ride_check(rider, FALSE))
|
|
if(z_move_flags & ZMOVE_FEEDBACK)
|
|
to_chat(rider, span_warning("You're unable to ride [movable_parent] right now!"))
|
|
return COMPONENT_RIDDEN_STOP_Z_MOVE
|
|
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
|
|
|
|
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1, riding_target_override = null)
|
|
var/atom/movable/AM = parent
|
|
var/amount_equipped = 0
|
|
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
|
|
var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user)
|
|
if(!riding_target_override)
|
|
inhand.rider = user
|
|
else
|
|
inhand.rider = riding_target_override
|
|
inhand.parent = AM
|
|
for(var/obj/item/I in user.held_items) // delete any hand items like slappers that could still totally be used to grab on
|
|
if((I.obj_flags & HAND_ITEM))
|
|
qdel(I)
|
|
if(user.put_in_hands(inhand, TRUE))
|
|
amount_equipped++
|
|
else
|
|
break
|
|
if(amount_equipped >= amount_required)
|
|
return TRUE
|
|
else
|
|
unequip_buckle_inhands(user)
|
|
return FALSE
|
|
|
|
/datum/component/riding/proc/unequip_buckle_inhands(mob/living/carbon/user)
|
|
var/atom/movable/AM = parent
|
|
for(var/obj/item/riding_offhand/O in user.contents)
|
|
if(O.parent != AM)
|
|
CRASH("RIDING OFFHAND ON WRONG MOB")
|
|
if(O.selfdeleting)
|
|
continue
|
|
else
|
|
qdel(O)
|
|
return TRUE
|
|
|
|
/// Extra checks before buckled.can_z_move can be called in mob/living/can_z_move()
|
|
/datum/component/riding/proc/riding_can_z_move(atom/movable/movable_parent, direction, turf/start, turf/destination, z_move_flags, mob/living/rider)
|
|
SIGNAL_HANDLER
|
|
return COMPONENT_RIDDEN_ALLOW_Z_MOVE
|
|
|
|
/obj/item/riding_offhand
|
|
name = "offhand"
|
|
icon = 'icons/obj/misc.dmi'
|
|
icon_state = "offhand"
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
item_flags = ABSTRACT | DROPDEL | NOBLUDGEON
|
|
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
|
var/mob/living/carbon/rider
|
|
var/mob/living/parent
|
|
var/selfdeleting = FALSE
|
|
|
|
/obj/item/riding_offhand/dropped()
|
|
selfdeleting = TRUE
|
|
. = ..()
|
|
|
|
/obj/item/riding_offhand/equipped()
|
|
if(loc != rider && loc != parent)
|
|
selfdeleting = TRUE
|
|
qdel(src)
|
|
. = ..()
|
|
|
|
/obj/item/riding_offhand/Destroy()
|
|
var/atom/movable/AM = parent
|
|
if(selfdeleting)
|
|
if(rider in AM.buckled_mobs)
|
|
AM.unbuckle_mob(rider)
|
|
. = ..()
|