// For any mob that can be ridden /datum/component/riding/creature /// If TRUE, this creature's movements can be controlled by the rider while mounted (as opposed to riding cyborgs and humans, which is passive) var/can_be_driven = TRUE /// If TRUE, this creature's abilities can be triggered by the rider while mounted var/can_use_abilities = FALSE /// Shall we require riders to go through the riding minigame if they arent in our friends list var/require_minigame = FALSE /// Do we use vehicle_move_delay or default to mob's own movespeed? var/uses_native_speed = FALSE /// unsharable abilities that we will force to be shared anyway var/list/override_unsharable_abilities = list() /// abilities that are always blacklisted from sharing var/list/blacklist_abilities = list() /// flag that determine how our ai acts while ridden var/ai_behavior_while_ridden = RIDING_PAUSE_AI_PLANNING | RIDING_PAUSE_AI_MOVEMENT /datum/component/riding/creature/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE) if(!isliving(parent)) return COMPONENT_INCOMPATIBLE . = ..() var/mob/living/living_parent = parent living_parent.stop_pulling() // was only used on humans previously, may change some other behavior log_riding(living_parent, riding_mob) riding_mob.set_glide_size(living_parent.glide_size) update_parent_layer_and_offsets(living_parent.dir) if(can_use_abilities) setup_abilities(riding_mob) if(isanimal(parent)) var/mob/living/simple_animal/simple_parent = parent simple_parent.stop_automated_movement = TRUE /datum/component/riding/creature/Destroy(force) unequip_buckle_inhands(parent) if(isanimal(parent)) var/mob/living/simple_animal/simple_parent = parent simple_parent.stop_automated_movement = FALSE parent.remove_traits(list(TRAIT_AI_PAUSED, TRAIT_AI_MOVEMENT_HALTED), REF(src)) return ..() /datum/component/riding/creature/RegisterWithParent() . = ..() RegisterSignal(parent, COMSIG_MOB_EMOTE, PROC_REF(check_emote)) if(can_be_driven) RegisterSignal(parent, COMSIG_RIDDEN_DRIVER_MOVE, PROC_REF(driver_move)) // this isn't needed on riding humans or cyborgs since the rider can't control them /// Creatures need to be logged when being mounted /datum/component/riding/creature/proc/log_riding(mob/living/living_parent, mob/living/rider) if(!istype(living_parent) || !istype(rider)) return living_parent.log_message("is now being ridden by [rider].", LOG_GAME, color="pink") rider.log_message("started riding [living_parent].", LOG_GAME, color="pink") // this applies to humans and most creatures, but is replaced again for cyborgs /datum/component/riding/creature/ride_check(mob/living/rider, consequences = TRUE) . = TRUE var/mob/living/living_parent = parent if(living_parent.body_position != STANDING_UP) // if we move while on the ground, the rider falls off . = FALSE // for piggybacks and (redundant?) borg riding, check if the rider is stunned/restrained else if((ride_check_flags & RIDER_NEEDS_ARMS) && (HAS_TRAIT(rider, TRAIT_RESTRAINED) || INCAPACITATED_IGNORING(rider, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB))) . = FALSE // for fireman carries, check if the ridden is stunned/restrained else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || INCAPACITATED_IGNORING(living_parent, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB))) . = FALSE else if((ride_check_flags & JUST_FRIEND_RIDERS) && !(living_parent.faction.Find(REF(rider)))) . = FALSE if(. || !consequences) return rider.visible_message(span_warning("[rider] falls off of [living_parent]!"), \ span_warning("You fall off of [living_parent]!")) rider.Paralyze(1 SECONDS) rider.Knockdown(4 SECONDS) living_parent.unbuckle_mob(rider) /datum/component/riding/creature/vehicle_mob_buckle(mob/living/ridden, mob/living/rider, force = FALSE) // Ensure that the /mob/post_buckle_mob(mob/living/M) does not mess us up with layers // If we do not do this override we'll be stuck with the above proc (+ 0.1)-ing our rider's layer incorrectly rider.layer = initial(rider.layer) if(can_be_driven) //let the player take over if they should be controlling movement if(ai_behavior_while_ridden & RIDING_PAUSE_AI_PLANNING) ADD_TRAIT(ridden, TRAIT_AI_PAUSED, REF(src)) if(ai_behavior_while_ridden & RIDING_PAUSE_AI_MOVEMENT) ADD_TRAIT(ridden, TRAIT_AI_MOVEMENT_HALTED, REF(src)) return ..() /datum/component/riding/creature/vehicle_mob_unbuckle(mob/living/formerly_ridden, mob/living/former_rider, force = FALSE) if(istype(formerly_ridden) && istype(former_rider)) formerly_ridden.log_message("is no longer being ridden by [former_rider].", LOG_GAME, color="pink") former_rider.log_message("is no longer riding [formerly_ridden].", LOG_GAME, color="pink") remove_abilities(former_rider) if(!formerly_ridden.buckled_mobs.len) formerly_ridden.remove_traits(list(TRAIT_AI_PAUSED, TRAIT_AI_MOVEMENT_HALTED), REF(src)) // We gotta reset those layers at some point, don't we? former_rider.layer = MOB_LAYER formerly_ridden.layer = MOB_LAYER return ..() /datum/component/riding/creature/Process_Spacemove(direction, continuous_move) var/mob/living/living_parent = parent return override_allow_spacemove || living_parent.Process_Spacemove(direction, continuous_move) /datum/component/riding/creature/driver_move(atom/movable/movable_parent, mob/living/user, direction) if(!COOLDOWN_FINISHED(src, vehicle_move_cooldown) || !Process_Spacemove(direction)) return COMPONENT_DRIVER_BLOCK_MOVE if(!keycheck(user)) if(ispath(keytype, /obj/item)) var/obj/item/key = keytype to_chat(user, span_warning("You need a [initial(key.name)] to ride [movable_parent]!")) return COMPONENT_DRIVER_BLOCK_MOVE var/mob/living/living_parent = parent step(living_parent, direction) var/modified_move_delay = uses_native_speed ? living_parent.cached_multiplicative_slowdown : vehicle_move_delay if(HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW! switch(HAS_TRAIT(user, TRAIT_PRIMITIVE) ? SANITY_LEVEL_GREAT : user.mob_mood?.sanity_level) if(SANITY_LEVEL_GREAT) modified_move_delay *= 0.8 if(SANITY_LEVEL_NEUTRAL) modified_move_delay *= 0.9 if(SANITY_LEVEL_DISTURBED) modified_move_delay *= 1 if(SANITY_LEVEL_CRAZY) modified_move_delay *= 1.1 if(SANITY_LEVEL_INSANE) modified_move_delay *= 1.2 if(NSCOMPONENT(direction) && EWCOMPONENT(direction)) modified_move_delay = FLOOR(modified_move_delay * sqrt(2), world.tick_lag) COOLDOWN_START(src, vehicle_move_cooldown, modified_move_delay) return ..() /// Yeets the rider off, used for animals and cyborgs, redefined for humans who shove their piggyback rider off /datum/component/riding/creature/proc/force_dismount(mob/living/rider, throw_range = 8, throw_speed = 3, gentle = FALSE) var/atom/movable/movable_parent = parent movable_parent.unbuckle_mob(rider) rider.Knockdown(3 SECONDS) if(throw_range == 0) return if(!iscyborg(movable_parent) && !isanimal_or_basicmob(movable_parent)) return var/turf/target = get_edge_target_turf(movable_parent, movable_parent.dir) rider.visible_message(span_warning("[rider] is thrown clear of [movable_parent]!"), \ span_warning("You're thrown clear of [movable_parent]!")) rider.throw_at(target, throw_range, throw_speed, movable_parent, gentle = gentle) /// If we're a cyborg or animal and we spin, we yeet whoever's on us off us /datum/component/riding/creature/proc/check_emote(mob/living/user, datum/emote/emote) SIGNAL_HANDLER if((!iscyborg(user) && !isanimal_or_basicmob(user)) || !istype(emote, /datum/emote/spin)) return for(var/mob/yeet_mob in user.buckled_mobs) force_dismount(yeet_mob, gentle=!user.combat_mode) // gentle on help, byeeee if not /// If the ridden creature has abilities, and some var yet to be made is set to TRUE, the rider will be able to control those abilities /datum/component/riding/creature/proc/setup_abilities(mob/living/rider) if(!isliving(parent)) return var/mob/living/ridden_creature = parent for(var/datum/action/action as anything in ridden_creature.actions) if(is_type_in_list(action, blacklist_abilities)) continue if(!action.can_be_shared && !is_type_in_list(action, override_unsharable_abilities)) continue action.GiveAction(rider) /// Takes away the riding parent's abilities from the rider /datum/component/riding/creature/proc/remove_abilities(mob/living/rider) if(!isliving(parent)) return var/mob/living/ridden_creature = parent for(var/datum/action/action as anything in ridden_creature.actions) if(istype(action, /datum/action/cooldown) && rider.click_intercept == action) var/datum/action/cooldown/cooldown_action = action cooldown_action.unset_click_ability(rider, refund_cooldown = TRUE) action.HideFrom(rider) /datum/component/riding/creature/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 ///////Yes, I said humans. No, this won't end well...////////// /datum/component/riding/creature/human can_be_driven = FALSE /datum/component/riding/creature/human/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE) . = ..() var/mob/living/carbon/human/human_parent = parent human_parent.add_movespeed_modifier(/datum/movespeed_modifier/human_carry) if(ride_check_flags & RIDER_NEEDS_ARMS) // piggyback human_parent.buckle_lying = 0 // the riding mob is made nondense so they don't bump into any dense atoms the carrier is pulling, // since pulled movables are moved before buckled movables ADD_TRAIT(riding_mob, TRAIT_UNDENSE, VEHICLE_TRAIT) else if(ride_check_flags & CARRIER_NEEDS_ARM) // fireman human_parent.buckle_lying = 90 /datum/component/riding/creature/handle_buckle(mob/living/rider) . = ..() var/mob/living/ridden = parent if(!require_minigame || ridden.faction.Find(REF(rider))) return ridden.Shake(pixelshiftx = 1, pixelshifty = 0, duration = 1 SECONDS) ridden.spin(spintime = 1 SECONDS, speed = 1) ridden.balloon_alert(rider, "tries to shake you off!") new /datum/riding_minigame(ridden, rider) /datum/component/riding/creature/human/RegisterWithParent() . = ..() RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_host_unarmed_melee)) RegisterSignal(parent, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(check_carrier_fall_over)) /datum/component/riding/creature/human/log_riding(mob/living/living_parent, mob/living/rider) if(!istype(living_parent) || !istype(rider)) return if(ride_check_flags & RIDER_NEEDS_ARMS) // piggyback living_parent.log_message("started giving [rider] a piggyback ride.", LOG_GAME, color="pink") rider.log_message("started piggyback riding [living_parent].", LOG_GAME, color="pink") else if(ride_check_flags & CARRIER_NEEDS_ARM) // fireman living_parent.log_message("started fireman carrying [rider].", LOG_GAME, color="pink") rider.log_message("was fireman carried by [living_parent].", LOG_GAME, color="pink") /datum/component/riding/creature/human/vehicle_mob_unbuckle(datum/source, mob/living/former_rider, force = FALSE) unequip_buckle_inhands(parent) var/mob/living/carbon/human/H = parent H.remove_movespeed_modifier(/datum/movespeed_modifier/human_carry) REMOVE_TRAIT(former_rider, TRAIT_UNDENSE, VEHICLE_TRAIT) return ..() /// If the carrier shoves the person they're carrying, force the carried mob off /datum/component/riding/creature/human/proc/on_host_unarmed_melee(mob/living/source, atom/target, proximity, modifiers) SIGNAL_HANDLER if(LAZYACCESS(modifiers, RIGHT_CLICK) && (target in source.buckled_mobs)) force_dismount(target) return COMPONENT_CANCEL_ATTACK_CHAIN return NONE /// If the carrier gets knocked over, force the rider(s) off and see if someone got hurt /datum/component/riding/creature/human/proc/check_carrier_fall_over(mob/living/carbon/human/human_parent) SIGNAL_HANDLER for(var/mob/living/rider as anything in human_parent.buckled_mobs) human_parent.unbuckle_mob(rider) rider.Paralyze(1 SECONDS) rider.Knockdown(4 SECONDS) human_parent.visible_message( span_danger("[rider] topples off of [human_parent] as they both fall to the ground!"), span_warning("You fall to the ground, bringing [rider] with you!"), span_hear("You hear two consecutive thuds."), COMBAT_MESSAGE_RANGE, ignored_mobs = rider, visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, ) to_chat(rider, span_danger("[human_parent] falls to the ground, bringing you with [human_parent.p_them()]!")) /datum/component/riding/creature/human/get_rider_offsets_and_layers(pass_index, mob/offsetter) var/mob/living/carbon/human/seat = parent // fireman carry if(seat.buckle_lying) return list( TEXT_NORTH = list(0, 6, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 6, MOB_BELOW_PIGGYBACK_LAYER), TEXT_EAST = list(0, 6, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 6, MOB_BELOW_PIGGYBACK_LAYER), ) // piggyback return list( TEXT_NORTH = list( 0, 8, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_SOUTH = list( 0, 8, MOB_BELOW_PIGGYBACK_LAYER), TEXT_EAST = list(-6, 8, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list( 6, 8, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/human/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0), ) /datum/component/riding/creature/human/force_dismount(mob/living/rider, throw_range = 8, throw_speed = 3, gentle = FALSE) var/atom/movable/seat = parent seat.unbuckle_mob(rider) rider.Paralyze(1 SECONDS) rider.Knockdown(4 SECONDS) rider.visible_message( span_warning("[seat] pushes [rider] off of [seat.p_them()]!"), span_warning("[seat] pushes you off of [seat.p_them()]!"), ) //Now onto cyborg riding// /datum/component/riding/creature/cyborg can_be_driven = FALSE /datum/component/riding/creature/cyborg/ride_check(mob/living/user, consequences = TRUE) var/mob/living/silicon/robot/robot_parent = parent if(!iscarbon(user)) return TRUE . = user.usable_hands if(!. && consequences) Unbuckle(user) to_chat(user, span_warning("You can't grab onto [robot_parent] with no hands!")) /datum/component/riding/creature/cyborg/get_rider_offsets_and_layers(pass_index, mob/offsetter) var/mob/living/silicon/robot/robot_parent = parent return robot_parent.model?.ride_offsets || DEFAULT_ROBOT_RIDING_OFFSETS /datum/component/riding/creature/cyborg/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), ) //now onto every other ridable mob// /datum/component/riding/creature/mulebot /datum/component/riding/creature/mulebot/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(0, 12, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 12, MOB_BELOW_PIGGYBACK_LAYER), TEXT_EAST = list(0, 12, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 12, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/mulebot/get_parent_offsets_and_layers() return null /datum/component/riding/creature/cow /datum/component/riding/creature/cow/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list( 0, 8), TEXT_SOUTH = list( 0, 8), TEXT_EAST = list(-2, 8), TEXT_WEST = list( 2, 8), ) /datum/component/riding/creature/cow/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/pig /datum/component/riding/creature/pig/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list( 0, 8), TEXT_SOUTH = list( 0, 8), TEXT_EAST = list(-2, 8), TEXT_WEST = list( 2, 8), ) /datum/component/riding/creature/pig/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/pony vehicle_move_delay = 1.5 COOLDOWN_DECLARE(pony_trot_cooldown) /datum/component/riding/creature/pony/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list( 0, 9), TEXT_SOUTH = list( 0, 9), TEXT_EAST = list(-2, 9), TEXT_WEST = list( 2, 9), ) /datum/component/riding/creature/pony/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/pony/driver_move(atom/movable/movable_parent, mob/living/user, direction) . = ..() if (. == COMPONENT_DRIVER_BLOCK_MOVE || !COOLDOWN_FINISHED(src, pony_trot_cooldown)) return var/mob/living/carbon/human/human_user = user if(human_user && is_clown_job(human_user.mind?.assigned_role)) // there's a new sheriff in town playsound(movable_parent, 'sound/mobs/non-humanoids/pony/clown_gallup.ogg', 50) COOLDOWN_START(src, pony_trot_cooldown, 500 MILLISECONDS) /datum/component/riding/creature/bear vehicle_move_delay = 1.5 /datum/component/riding/creature/bear/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list( 1, 8), TEXT_SOUTH = list( 1, 8), TEXT_EAST = list(-3, 6), TEXT_WEST = list( 3, 6), ) /datum/component/riding/creature/bear/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/carp override_allow_spacemove = TRUE /datum/component/riding/creature/carp/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(0, 13), TEXT_SOUTH = list(0, 15), TEXT_EAST = list(-2, 12), TEXT_WEST = list( 2, 12), ) /datum/component/riding/creature/carp/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/megacarp override_allow_spacemove = TRUE /datum/component/riding/creature/megacarp/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(1, 8), TEXT_SOUTH = list(1, 8), TEXT_EAST = list(-3, 6), TEXT_WEST = list(3, 6), ) /datum/component/riding/creature/megacarp/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/vatbeast override_allow_spacemove = TRUE can_use_abilities = TRUE /datum/component/riding/creature/vatbeast/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(0, 15), TEXT_SOUTH = list(0, 15), TEXT_EAST = list(-10, 15), TEXT_WEST = list(10, 15), ) /datum/component/riding/creature/vatbeast/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/goliath keytype = /obj/item/key/lasso uses_native_speed = TRUE rider_traits = list(TRAIT_NO_FLOATING_ANIM, TRAIT_TENTACLE_IMMUNE) /datum/component/riding/creature/goliath/deathmatch keytype = null /datum/component/riding/creature/goliath/Initialize(mob/living/riding_mob, force, ride_check_flags) . = ..() var/mob/living/basic/mining/goliath/goliath = parent goliath.add_movespeed_modifier(/datum/movespeed_modifier/goliath_mount) /datum/component/riding/creature/goliath/Destroy(force) var/mob/living/basic/mining/goliath/goliath = parent goliath.remove_movespeed_modifier(/datum/movespeed_modifier/goliath_mount) return ..() /datum/component/riding/creature/goliath/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list( 0, 12), TEXT_SOUTH = list( 0, 12), TEXT_EAST = list(-4, 12), TEXT_WEST = list( 3, 12), ) /datum/component/riding/creature/goliath/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/glutton /datum/component/riding/creature/glutton/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list( 0, 24), TEXT_SOUTH = list( 0, 24), TEXT_EAST = list(-16, 24), TEXT_WEST = list( 16, 24), ) /datum/component/riding/creature/glutton/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), ) /datum/component/riding/creature/guardian can_be_driven = FALSE /datum/component/riding/creature/guardian/get_rider_offsets_and_layers(pass_index, mob/offsetter) 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/creature/guardian/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), ) /datum/component/riding/creature/guardian/ride_check(mob/living/user, consequences = TRUE) var/mob/living/basic/guardian/charger = parent if(!istype(charger)) return ..() return charger.summoner == user /datum/component/riding/creature/goldgrub uses_native_speed = TRUE /datum/component/riding/creature/goldgrub/Initialize(mob/living/riding_mob, force, ride_check_flags) . = ..() var/mob/living/basic/mining/goldgrub/goldgrub = parent goldgrub.add_movespeed_modifier(/datum/movespeed_modifier/goldgrub_mount) /datum/component/riding/creature/goldgrub/Destroy(force) var/mob/living/basic/mining/goldgrub/goldgrub = parent goldgrub.remove_movespeed_modifier(/datum/movespeed_modifier/goldgrub_mount) return ..() /datum/component/riding/creature/goldgrub/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(0, 3), TEXT_SOUTH = list(1, 7), TEXT_EAST = list(-3, 3), TEXT_WEST = list(3, 3), ) /datum/component/riding/creature/goldgrub/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/leaper can_force_unbuckle = FALSE can_use_abilities = TRUE ride_check_flags = JUST_FRIEND_RIDERS /datum/component/riding/creature/leaper/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(0, 46), TEXT_SOUTH = list(0, 51), TEXT_EAST = list(-6, 46), TEXT_WEST = list( 6, 46), ) /datum/component/riding/creature/leaper/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), ) /datum/component/riding/creature/leaper/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE) . = ..() RegisterSignal(riding_mob, COMSIG_MOVABLE_POINTED, PROC_REF(attack_pointed)) /datum/component/riding/creature/leaper/proc/attack_pointed(mob/living/rider, atom/pointed, obj/effect/temp_visual/point/point) SIGNAL_HANDLER if(!isclosedturf(pointed)) return var/mob/living/basic/basic_parent = parent if(!pointed.IsReachableBy(basic_parent)) return basic_parent.melee_attack(pointed) /datum/component/riding/leaper/handle_unbuckle(mob/living/rider) . = ..() UnregisterSignal(rider, COMSIG_MOVABLE_POINTED) /datum/component/riding/creature/raptor require_minigame = TRUE uses_native_speed = TRUE ride_check_flags = RIDER_NEEDS_ARM | UNBUCKLE_DISABLED_RIDER /datum/component/riding/creature/raptor/Initialize(mob/living/riding_mob, force, ride_check_flags) . = ..() RegisterSignal(parent, COMSIG_PROJECTILE_PREHIT, PROC_REF(on_bullet_hit)) RegisterSignal(parent, COMSIG_MOB_AFTER_APPLY_DAMAGE, PROC_REF(on_attacked)) /datum/component/riding/creature/raptor/proc/on_bullet_hit(atom/target, obj/projectile/hit_projectile) SIGNAL_HANDLER if(hit_projectile.armor_flag == ENERGY) freak_out() /datum/component/riding/creature/raptor/proc/on_attacked(mob/living/source, damage_dealt, damagetype, def_zone, blocked, wound_bonus, exposed_wound_bonus, sharpness, attack_direction, obj/item/attacking_item) SIGNAL_HANDLER if(damagetype == STAMINA) freak_out() /datum/component/riding/creature/raptor/proc/freak_out() var/mob/living/living_parent = parent if(lavaland_equipment_pressure_check(get_turf(living_parent)) || !length(living_parent.buckled_mobs)) return living_parent.balloon_alert_to_viewers("freaks out!") living_parent.spin(spintime = 2 SECONDS, speed = 1) for(var/mob/living/buckled_mob in living_parent.buckled_mobs) force_dismount(buckled_mob, throw_range = 2, gentle = TRUE) /datum/component/riding/creature/raptor/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(-1, 7), TEXT_SOUTH = list(2, 10), TEXT_EAST = list(0, 7), TEXT_WEST = list(0, 7), ) /datum/component/riding/creature/raptor/get_parent_offsets_and_layers() return list( TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), ) /datum/component/riding/creature/raptor/update_parent_layer_and_offsets(dir, animate) . = ..() var/mob/living/basic/raptor/raptor = parent if (istype(raptor)) raptor.adjust_offsets(dir) /datum/component/riding/creature/raptor/combat ai_behavior_while_ridden = RIDING_PAUSE_AI_MOVEMENT /datum/component/riding/creature/raptor/healer/vehicle_mob_buckle(mob/living/ridden, mob/living/rider, force) RegisterSignal(rider, COMSIG_MOB_STATCHANGE, PROC_REF(on_buckled_stat_change)) return ..() /datum/component/riding/creature/raptor/healer/vehicle_mob_unbuckle(mob/living/formerly_ridden, mob/living/former_rider, force) UnregisterSignal(former_rider, COMSIG_MOB_STATCHANGE) return ..() /datum/component/riding/creature/raptor/healer/proc/on_buckled_stat_change(mob/living/source, new_stat, old_stat) SIGNAL_HANDLER var/mob/living/basic/raptor/raptor = source.buckled if (!istype(raptor)) // what UnregisterSignal(source, COMSIG_MOB_STATCHANGE) return // Heal the owner and flee whatever might've attacked them if (new_stat == CONSCIOUS || new_stat == DEAD || old_stat != CONSCIOUS || !raptor.ai_controller) ADD_TRAIT(raptor, TRAIT_AI_PAUSED, REF(src)) return REMOVE_TRAIT(raptor, TRAIT_AI_PAUSED, REF(src)) // Rip bozo, but you're not our friend if (source in raptor.ai_controller.blackboard[BB_FRIENDS_LIST]) raptor.ai_controller.set_blackboard_key(BB_INJURED_RAPTOR, source) for (var/mob/living/possible_hostile in view(5, raptor)) if (possible_hostile.stat || possible_hostile.invisibility > raptor.see_invisible || source.faction_check_atom(possible_hostile)) continue raptor.ai_controller.set_blackboard_key(BB_BASIC_MOB_FLEE_TARGET, possible_hostile) break /datum/component/riding/creature/raptor/small/get_rider_offsets_and_layers(pass_index, mob/offsetter) return list( TEXT_NORTH = list(-1, 5), TEXT_SOUTH = list(2, 8), TEXT_EAST = list(0, 5), TEXT_WEST = list(0, 5), )