mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 18:02:57 +00:00
327 lines
11 KiB
Plaintext
327 lines
11 KiB
Plaintext
/datum/component/riding
|
|
var/next_vehicle_move = 0 //used for move delays
|
|
var/vehicle_move_delay = 2 //tick delay between movements, lower = faster, higher = slower
|
|
var/keytype
|
|
|
|
var/slowed = FALSE
|
|
var/slowvalue = 1
|
|
|
|
var/list/riding_offsets = list() //position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
|
|
var/list/directional_vehicle_layers = list() //["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
|
|
var/list/directional_vehicle_offsets = list() //same as above but instead of layer you have a list(px, py)
|
|
var/list/allowed_turf_typecache
|
|
var/list/forbid_turf_typecache //allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
|
|
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
|
|
var/override_allow_spacemove = FALSE
|
|
var/drive_verb = "drive"
|
|
var/ride_check_rider_incapacitated = FALSE
|
|
var/ride_check_rider_restrained = FALSE
|
|
var/ride_check_ridden_incapacitated = FALSE
|
|
|
|
/datum/component/riding/Initialize()
|
|
if(!ismovableatom(parent))
|
|
. = COMPONENT_INCOMPATIBLE
|
|
CRASH("RIDING COMPONENT ASSIGNED TO NON ATOM MOVABLE!")
|
|
RegisterSignal(COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
|
|
RegisterSignal(COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle)
|
|
RegisterSignal(COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
|
|
|
|
/datum/component/riding/proc/vehicle_mob_unbuckle(mob/living/M, force = FALSE)
|
|
restore_position(M)
|
|
unequip_buckle_inhands(M)
|
|
|
|
/datum/component/riding/proc/vehicle_mob_buckle(mob/living/M, force = FALSE)
|
|
handle_vehicle_offsets()
|
|
|
|
/datum/component/riding/proc/handle_vehicle_layer()
|
|
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["[AM.dir]"]
|
|
if(directional_vehicle_layers["[AM.dir]"])
|
|
. = directional_vehicle_layers["[AM.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()
|
|
var/atom/movable/AM = parent
|
|
for(var/i in AM.buckled_mobs)
|
|
ride_check(i)
|
|
handle_vehicle_offsets()
|
|
handle_vehicle_layer()
|
|
|
|
/datum/component/riding/proc/ride_check(mob/living/M)
|
|
var/atom/movable/AM = parent
|
|
var/mob/AMM = AM
|
|
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 class='warning'>[M] falls off of [AM]!</span>")
|
|
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(buckled_mob)
|
|
buckled_mob.pixel_x = 0
|
|
buckled_mob.pixel_y = 0
|
|
if(buckled_mob.client)
|
|
buckled_mob.client.change_view(CONFIG_GET(string/default_view))
|
|
|
|
//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 < next_vehicle_move)
|
|
return
|
|
next_vehicle_move = world.time + vehicle_move_delay
|
|
|
|
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)
|
|
|
|
handle_vehicle_layer()
|
|
handle_vehicle_offsets()
|
|
else
|
|
to_chat(user, "<span class='notice'>You'll need the keys in one of your hands to [drive_verb] [AM].</span>")
|
|
|
|
/datum/component/riding/proc/Unbuckle(atom/movable/M)
|
|
addtimer(CALLBACK(parent, /atom/movable/.proc/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
|
|
|
|
/datum/component/riding/human/Initialize()
|
|
. = ..()
|
|
RegisterSignal(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
|
|
|
|
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
|
|
var/mob/living/carbon/human/AM = parent
|
|
if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs))
|
|
force_dismount(target)
|
|
|
|
/datum/component/riding/human/handle_vehicle_layer()
|
|
var/atom/movable/AM = parent
|
|
if(AM.buckled_mobs && AM.buckled_mobs.len)
|
|
if(AM.dir == SOUTH)
|
|
AM.layer = ABOVE_MOB_LAYER
|
|
else
|
|
AM.layer = OBJ_LAYER
|
|
else
|
|
AM.layer = MOB_LAYER
|
|
|
|
/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 class='warning'>[AM] pushes [user] off of them!</span>")
|
|
|
|
/datum/component/riding/cyborg
|
|
|
|
/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 class='userdanger'>You fall off of [AM]!</span>")
|
|
Unbuckle(user)
|
|
return
|
|
if(iscarbon(user))
|
|
var/mob/living/carbon/carbonuser = user
|
|
if(!carbonuser.get_num_arms())
|
|
Unbuckle(user)
|
|
to_chat(user, "<span class='userdanger'>You can't grab onto [AM] with no hands!</span>")
|
|
return
|
|
|
|
/datum/component/riding/cyborg/handle_vehicle_layer()
|
|
var/atom/movable/AM = parent
|
|
if(AM.buckled_mobs && AM.buckled_mobs.len)
|
|
if(AM.dir == SOUTH)
|
|
AM.layer = ABOVE_MOB_LAYER
|
|
else
|
|
AM.layer = OBJ_LAYER
|
|
else
|
|
AM.layer = MOB_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
|
|
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 class='warning'>[M] is thrown clear of [AM]!</span>")
|
|
M.throw_at(target, 14, 5, AM)
|
|
M.Knockdown(60)
|
|
|
|
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
|
|
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)
|
|
inhand.rider = user
|
|
inhand.parent = AM
|
|
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")
|
|
continue
|
|
if(O.selfdeleting)
|
|
continue
|
|
else
|
|
qdel(O)
|
|
return TRUE
|
|
|
|
/obj/item/riding_offhand
|
|
name = "offhand"
|
|
icon = 'icons/obj/items_and_weapons.dmi'
|
|
icon_state = "offhand"
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
flags_1 = ABSTRACT_1 | DROPDEL_1 | NOBLUDGEON_1
|
|
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)
|
|
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)
|
|
. = ..()
|