/datum/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 = null var/atom/movable/ridden = null var/slowed = FALSE var/slowvalue = 1 /datum/riding/New(atom/movable/_ridden) ridden = _ridden /datum/riding/Destroy() ridden = null return ..() /datum/riding/proc/handle_vehicle_layer() if(ridden.dir != NORTH) ridden.layer = ABOVE_MOB_LAYER else ridden.layer = OBJ_LAYER /datum/riding/proc/on_vehicle_move() for(var/mob/living/M in ridden.buckled_mobs) ride_check(M) handle_vehicle_offsets() handle_vehicle_layer() /datum/riding/proc/ride_check(mob/living/M) return TRUE /datum/riding/proc/force_dismount(mob/living/M) ridden.unbuckle_mob(M) /datum/riding/proc/handle_vehicle_offsets() var/ridden_dir = "[ridden.dir]" var/passindex = 0 if(ridden.has_buckled_mobs()) for(var/m in ridden.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 == ridden_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 //Override this to set your vehicle's various pixel offsets /datum/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, 0), "[SOUTH]" = list(0, 0), "[EAST]" = list(0, 0), "[WEST]" = list(0, 0)) //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/riding/proc/get_rider_dir(pass_index) return ridden.dir //KEYS /datum/riding/proc/keycheck(mob/user) if(keytype) if(user.is_holding_item_of_type(keytype)) return TRUE else return TRUE return FALSE //BUCKLE HOOKS /datum/riding/proc/restore_position(mob/living/buckled_mob) if(istype(buckled_mob)) buckled_mob.pixel_x = 0 buckled_mob.pixel_y = 0 if(buckled_mob.client) buckled_mob.client.change_view(world.view) //MOVEMENT /datum/riding/proc/handle_ride(mob/user, direction) if(user.incapacitated()) Unbuckle(user) return if(world.time < next_vehicle_move) return next_vehicle_move = world.time + vehicle_move_delay if(keycheck(user)) if(!Process_Spacemove(direction) || !isturf(ridden.loc)) return step(ridden, direction) handle_vehicle_layer() handle_vehicle_offsets() else to_chat(user, "You'll need the keys in one of your hands to drive \the [ridden.name].") /datum/riding/proc/Unbuckle(atom/movable/M) addtimer(CALLBACK(ridden, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE) /datum/riding/proc/Process_Spacemove(direction) if(ridden.has_gravity()) return 1 return 0 /datum/riding/space/Process_Spacemove(direction) return 1 //atv /datum/riding/atv keytype = /obj/item/key vehicle_move_delay = 1 /datum/riding/atv/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, 4), "[SOUTH]" = list(0, 4), "[EAST]" = list(0, 4), "[WEST]" = list( 0, 4)) /datum/riding/atv/handle_vehicle_layer() if(ridden.dir == SOUTH) ridden.layer = ABOVE_MOB_LAYER else ridden.layer = OBJ_LAYER /datum/riding/atv/turret var/obj/machinery/porta_turret/syndicate/vehicle_turret/turret = null /datum/riding/atv/turret/handle_vehicle_layer() if(ridden.dir == SOUTH) ridden.layer = ABOVE_MOB_LAYER else ridden.layer = OBJ_LAYER if(turret) if(ridden.dir == NORTH) turret.layer = ABOVE_MOB_LAYER else turret.layer = OBJ_LAYER /datum/riding/atv/turret/handle_vehicle_offsets() ..() if(turret) turret.forceMove(get_turf(ridden)) switch(ridden.dir) if(NORTH) turret.pixel_x = 0 turret.pixel_y = 4 if(EAST) turret.pixel_x = -12 turret.pixel_y = 4 if(SOUTH) turret.pixel_x = 0 turret.pixel_y = 4 if(WEST) turret.pixel_x = 12 turret.pixel_y = 4 //pimpin ride /datum/riding/janicart keytype = /obj/item/key/janitor /datum/riding/janicart/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, 4), "[SOUTH]" = list(0, 7), "[EAST]" = list(-12, 7), "[WEST]" = list( 12, 7)) //scooter /datum/riding/scooter/handle_vehicle_layer() if(ridden.dir == SOUTH) ridden.layer = ABOVE_MOB_LAYER else ridden.layer = OBJ_LAYER /datum/riding/scooter/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0), "[SOUTH]" = list(-2), "[EAST]" = list(0), "[WEST]" = list( 2)) /datum/riding/scooter/handle_vehicle_offsets() ..() if(ridden.has_buckled_mobs()) for(var/m in ridden.buckled_mobs) var/mob/living/buckled_mob = m if(buckled_mob.get_num_legs() > 0) buckled_mob.pixel_y = 5 else buckled_mob.pixel_y = -4 /datum/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 /datum/riding/scooter/skateboard vehicle_move_delay = 0//fast //secway /datum/riding/secway keytype = /obj/item/key/security /datum/riding/secway/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, 4), "[SOUTH]" = list(0, 4), "[EAST]" = list(0, 4), "[WEST]" = list( 0, 4)) //i want to ride my /datum/riding/bicycle keytype = null vehicle_move_delay = 0 /datum/riding/bicycle/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, 4), "[SOUTH]" = list(0, 4), "[EAST]" = list(0, 4), "[WEST]" = list( 0, 4)) //speedbike /datum/riding/space/speedbike keytype = null vehicle_move_delay = 0 /datum/riding/space/speedbike/handle_vehicle_layer() switch(ridden.dir) if(NORTH,SOUTH) ridden.pixel_x = -16 ridden.pixel_y = -16 if(EAST,WEST) ridden.pixel_x = -18 ridden.pixel_y = 0 /datum/riding/space/speedbike/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, -8), "[SOUTH]" = list(0, 4), "[EAST]" = list(-10, 5), "[WEST]" = list( 10, 5)) //SPEEDUWAGON /datum/riding/space/speedwagon vehicle_move_delay = 0 /datum/riding/space/speedwagon/handle_vehicle_layer() ridden.layer = BELOW_MOB_LAYER /datum/riding/space/speedwagon/get_offsets(pass_index) // list(dir = x, y, layer) switch(pass_index) if(1) return list("[NORTH]" = list(-10, -4), "[SOUTH]" = list(16, 3), "[EAST]" = list(-4, 30), "[WEST]" = list(4, -3)) if(2) return list("[NORTH]" = list(19, -5, 4), "[SOUTH]" = list(-13, 3, 4), "[EAST]" = list(-4, -3, 4.1), "[WEST]" = list(4, 28, 3.9)) if(3) return list("[NORTH]" = list(-10, -18, 4.2), "[SOUTH]" = list(16, 25, 3.9), "[EAST]" = list(-22, 30), "[WEST]" = list(22, -3, 4.1)) if(4) return list("[NORTH]" = list(19, -18, 4.2), "[SOUTH]" = list(-13, 25, 3.9), "[EAST]" = list(-22, 3, 3.9), "[WEST]" = list(22, 28)) ///////////////BOATS//////////// /datum/riding/boat keytype = /obj/item/oar /datum/riding/boat/handle_ride(mob/user, direction) var/turf/next = get_step(ridden, direction) var/turf/current = get_turf(ridden) if(islava(next) || islava(current)) //We can move from land to lava, or lava to land, but not from land to land ..() else to_chat(user, "Boats don't go on land!") return 0 /datum/riding/boat/dragon keytype = null vehicle_move_delay = 1 /datum/riding/boat/dragon/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(1, 2), "[SOUTH]" = list(1, 2), "[EAST]" = list(1, 2), "[WEST]" = list( 1, 2)) ///////////////ANIMALS//////////// //general animals /datum/riding/animal keytype = null /datum/riding/animal/handle_ride(mob/user, direction) if(user.incapacitated()) Unbuckle(user) return if(world.time < next_vehicle_move) return next_vehicle_move = world.time + vehicle_move_delay if(keycheck(user)) if(!isturf(ridden.loc)) return step(ridden, direction) handle_vehicle_layer() handle_vehicle_offsets() else to_chat(user, "You'll need something to guide the [ridden.name].") ///////Humans. Yes, I said humans. No, this won't end well...////////// /datum/riding/human keytype = null /datum/riding/human/ride_check(mob/living/M) var/mob/living/carbon/human/H = ridden //IF this runtimes I'm blaming the admins. if(M.incapacitated(FALSE, TRUE) || H.incapacitated(FALSE, TRUE)) M.visible_message("[M] falls off [ridden]!") Unbuckle(M) return FALSE if(M.restrained(TRUE)) M.visible_message("[M] can't hang onto [ridden] with their hands cuffed!") //Honestly this should put the ridden mob in a chokehold. Unbuckle(M) return FALSE if(H.pulling == M) H.stop_pulling() /datum/riding/human/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, 6), "[SOUTH]" = list(0, 6), "[EAST]" = list(-6, 4), "[WEST]" = list( 6, 4)) /datum/riding/human/handle_vehicle_layer() if(ridden.buckled_mobs && ridden.buckled_mobs.len) if(ridden.dir == SOUTH) ridden.layer = ABOVE_MOB_LAYER else ridden.layer = OBJ_LAYER else ridden.layer = MOB_LAYER /datum/riding/human/force_dismount(mob/living/user) ridden.unbuckle_mob(user) user.Knockdown(60) user.visible_message("[ridden] pushes [user] off of them!") /datum/riding/cyborg keytype = null /datum/riding/cyborg/ride_check(mob/user) if(user.incapacitated()) var/kick = TRUE if(iscyborg(ridden)) var/mob/living/silicon/robot/R = ridden if(R.module && R.module.ride_allow_incapacitated) kick = FALSE if(kick) to_chat(user, "You fall off of [ridden]!") Unbuckle(user) return if(iscarbon(user)) var/mob/living/carbon/carbonuser = user if(!carbonuser.get_num_arms()) Unbuckle(user) to_chat(user, "You can't grab onto [ridden] with no hands!") return /datum/riding/cyborg/handle_vehicle_layer() if(ridden.buckled_mobs && ridden.buckled_mobs.len) if(ridden.dir == SOUTH) ridden.layer = ABOVE_MOB_LAYER else ridden.layer = OBJ_LAYER else ridden.layer = MOB_LAYER /datum/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer) return list("[NORTH]" = list(0, 4), "[SOUTH]" = list(0, 4), "[EAST]" = list(-6, 3), "[WEST]" = list( 6, 3)) /datum/riding/cyborg/handle_vehicle_offsets() if(ridden.has_buckled_mobs()) for(var/mob/living/M in ridden.buckled_mobs) M.setDir(ridden.dir) if(iscyborg(ridden)) var/mob/living/silicon/robot/R = ridden if(istype(R.module)) M.pixel_x = R.module.ride_offset_x[dir2text(ridden.dir)] M.pixel_y = R.module.ride_offset_y[dir2text(ridden.dir)] else ..() /datum/riding/cyborg/force_dismount(mob/living/M) ridden.unbuckle_mob(M) var/turf/target = get_edge_target_turf(ridden, ridden.dir) var/turf/targetm = get_step(get_turf(ridden), ridden.dir) M.Move(targetm) M.visible_message("[M] is thrown clear of [ridden]!") M.throw_at(target, 14, 5, ridden) M.Knockdown(60) /datum/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1) 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.ridden = ridden 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/riding/proc/unequip_buckle_inhands(mob/living/carbon/user) for(var/obj/item/riding_offhand/O in user.contents) if(O.ridden != ridden) 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/ridden 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() if(selfdeleting) if(rider in ridden.buckled_mobs) ridden.unbuckle_mob(rider) . = ..()