/obj/vehicle/animal name = "animal" desc = "Base type of rideable animals - you shouldn't be seeing this!" load_item_visible = 1 mob_offset_y = 5 health = 100 maxhealth = 100 fire_dam_coeff = 0.6 brute_dam_coeff = 0.5 dir = SOUTH anchored = FALSE //so you can drag animals around ///The chance of blocking a projectile aimed at the user. Nothing by default. var/block_chance = 0 /// Speed on land. Higher is slower. /// If 0 it can't go on land turfs at all. var/land_speed = 5 /// Speed if walk intent is on. /// Should be slower, but does not crash into other bikes or people at this speed. /// If land speed is 0, still can't go on land turfs at all. var/land_speed_careful = 6 /// Same as land speed, but for space turfs. var/space_speed = 0 /// Same as land speed if walk intent is on, but for space turfs. var/space_speed_careful = 0 var/storage_type = /obj/item/storage/toolbox/bike_storage/saddle var/obj/item/storage/storage_compartment organic = TRUE on = TRUE var/list/armor_values = list( //some default values that seem about right for an average animal MELEE = ARMOR_MELEE_MEDIUM, BULLET = ARMOR_BALLISTIC_MINOR, BOMB = ARMOR_BOMB_MINOR ) /obj/vehicle/animal/mechanics_hints(mob/user, distance, is_adjacent) . += ..() . += "Click-drag yourself onto the animal to climb onto it." . += "Click-drag it onto yourself to access its mounted storage." /obj/vehicle/animal/Destroy() QDEL_NULL(storage_compartment) return ..() /obj/vehicle/animal/setup_vehicle() ..() on = TRUE set_light(0) AddOverlays(image(icon, "[icon_state]_overlay", MOB_LAYER + 1)) if(storage_type) storage_compartment = new storage_type(src) if(LAZYLEN(armor_values)) AddComponent(/datum/component/armor, armor_values) /obj/vehicle/animal/load(var/atom/movable/C) var/mob/living/M = C if(!istype(C)) return FALSE if(M.buckled_to || M.restrained() || !Adjacent(M) || !M.Adjacent(src)) return FALSE return ..(M) /obj/vehicle/animal/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params) if(use_check_and_message(user)) return if(user == over && ishuman(over)) var/mob/living/carbon/human/H = over storage_compartment.open(H) /obj/vehicle/animal/mouse_drop_receive(atom/dropped, mob/user, params) if(use_check_and_message(user)) return if(!load(dropped)) to_chat(user, SPAN_WARNING("You were unable to load \the [dropped] onto \the [src].")) return /obj/vehicle/animal/attack_hand(var/mob/user as mob) if(use_check_and_message(user)) return if(user == load) unload(load) to_chat(user, "You unbuckle yourself from \the [src]") if(user != load && load) user.visible_message ("[user] starts to unbuckle [load] from \the [src]!") if(do_after(user, 8 SECONDS, src)) unload(load) to_chat(user, "You unbuckle [load] from \the [src]") to_chat(load, "You were unbuckled from \the [src] by [user]") /obj/vehicle/animal/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit) var/datum/component/armor/armor_component = GetComponent(/datum/component/armor) if(buckled && prob((1 - armor_component.get_blocked(hitting_projectile.damage_type, hitting_projectile.damage_flags, hitting_projectile.armor_penetration))*100)) return buckled.bullet_act(arglist(args)) ..() /obj/vehicle/animal/relaymove(mob/living/user, direction) . = ..() if(user != load || user.incapacitated()) return return Move(get_step(src, direction)) /obj/vehicle/animal/proc/check_destination(var/turf/destination) var/static/list/types = typecacheof(list(/turf/space)) if(is_type_in_typecache(destination,types) || pulledby) return TRUE else return FALSE /obj/vehicle/animal/Move(var/turf/destination) var/mob/living/rider = buckled if(!istype(buckled)) return var/is_careful = (rider.m_intent != M_RUN) var/is_on_space = check_destination(destination) if(is_on_space) //IDK when we will ever need space-flying animals but may as well leave the possibility open if(!space_speed) return FALSE move_delay = (is_careful ? space_speed_careful : space_speed) else if(!land_speed) return FALSE move_delay = (is_careful ? land_speed_careful : land_speed) return ..() /obj/vehicle/animal/Collide(var/atom/movable/AM) . = ..() collide_act(AM) /obj/vehicle/animal/proc/collide_act(var/atom/movable/AM) var/mob/living/M if(!buckled) return if(istype(buckled, /mob/living)) M = buckled if(M.m_intent == M_RUN) if (istype(AM, /obj/vehicle)) M.setMoveCooldown(10) var/obj/vehicle/V = AM if(prob(50)) if(V.buckled) if(ishuman(V.buckled)) var/mob/living/carbon/human/I = V.buckled I.visible_message(SPAN_DANGER("\The [I] falls off from \the [V]")) V.unload(I) I.throw_at(get_edge_target_turf(V.loc, V.loc.dir), 5, 1) I.apply_effect(2, WEAKEN) if(prob(25)) if(ishuman(buckled)) var/mob/living/carbon/human/C = buckled C.visible_message(SPAN_DANGER ("\The [C] falls off from \the [src]!")) unload(C) C.throw_at(get_edge_target_turf(loc, loc.dir), 5, 1) C.apply_effect(2, WEAKEN) if(isliving(AM)) if(ishuman(AM)) var/mob/living/carbon/human/H = AM M.attack_log += "\[[time_stamp()]\] Was rammed by [src]" M.attack_log += "\[[time_stamp()]\] rammed[M.name] ([M.ckey]) rammed [H.name] ([H.ckey]) with the [src]." msg_admin_attack("[src] crashed into [key_name(H)] at (JMP)" ) src.visible_message(SPAN_DANGER("\The [src] smashes into \the [H]!")) playsound(src, SFX_SWING_HIT, 50, 1) H.apply_damage(20, DAMAGE_BRUTE) H.throw_at(get_edge_target_turf(loc, loc.dir), 5, 1) H.apply_effect(4, WEAKEN) M.setMoveCooldown(10) return TRUE else var/mob/living/L = AM src.visible_message(SPAN_DANGER("\The [src] smashes into \the [L]!")) playsound(src, SFX_SWING_HIT, 50, 1) L.throw_at(get_edge_target_turf(loc, loc.dir), 5, 1) L.apply_damage(20, DAMAGE_BRUTE) M.setMoveCooldown(10) return TRUE /obj/vehicle/animal/climber name = "climber" desc = "A rideable beast of burden, large enough for one adult rider only but perfectly adapted for the rough terrain on Adhomai. This one has a saddle mounted on it." icon = 'icons/mob/npc/adhomai_48.dmi' icon_state = "climber_s" pixel_x = -8 mob_offset_y = 8 land_speed = 2 land_speed_careful = 4 health = 100 storage_type = /obj/item/storage/toolbox/bike_storage/saddle corpse = /mob/living/simple_animal/climber/saddle /obj/item/storage/toolbox/bike_storage/saddle name = "saddle storage" /obj/item/saddle name = "saddle" desc = "A structure used to ride animals." icon = 'icons/obj/saddle.dmi' icon_state = "saddle" w_class = WEIGHT_CLASS_NORMAL /obj/vehicle/animal/threshbeast name = "threshbeast" desc = "Large herbivorous reptiles native to Moghes, the azkrazal or 'threshbeast' is commonly used as a mount, beast of burden, or convenient food source by Unathi. They are highly valued for their speed and strength, capable of running at 30-42 miles per hour at top speed. This one has been fitted with a saddle." icon = 'icons/mob/npc/moghes_64.dmi' icon_state = "threshbeast_s" pixel_x = -15 mob_offset_y = 10 land_speed = 2 land_speed_careful = 4 health = 100 organic = TRUE storage_type = /obj/item/storage/toolbox/bike_storage/saddle corpse = /mob/living/simple_animal/threshbeast/saddle /obj/vehicle/animal/hegeranzi name = "hegeranzi" desc = "A large species of herbivorous horned reptiles native to Moghes, the hegeranzi or 'warmount' is commonly used as mount or beast of war by the Unathi. They are highly valued for their speed, aggression, and fearsome horns. This one seems to have been fitted with a saddle." icon = 'icons/mob/npc/moghes_64.dmi' icon_state = "warmount_s" pixel_x = -14 mob_offset_y = 12 on = TRUE land_speed = 1 land_speed_careful = 4 health = 200 organic = TRUE storage_type = /obj/item/storage/toolbox/bike_storage/saddle corpse = /mob/living/simple_animal/hostile/retaliate/hegeranzi/saddle armor_values = list( //big tough war beast, has some more armor particularly against bullets and melee MELEE = ARMOR_MELEE_MAJOR, BULLET = ARMOR_BALLISTIC_MEDIUM, LASER = ARMOR_LASER_MINOR, BOMB = ARMOR_BOMB_MINOR ) /obj/vehicle/animal/warmount/RunOver(mob/living/carbon/human/H) var/mob/living/M if(!buckled) return if(istype(buckled, /mob/living)) M = buckled if(M.m_intent == M_RUN) M.attack_log += "\[[time_stamp()]\] Was rammed by [src]" M.attack_log += "\[[time_stamp()]\] rammed[M.name] ([M.ckey]) rammed [H.name] ([H.ckey]) with the [src]." msg_admin_attack("[src] crashed into [key_name(H)] at (JMP)" ) src.visible_message(SPAN_DANGER("\The [src] charges into \the [H]!")) playsound(src, 'sound/weapons/pierce.ogg', 50, 1) H.apply_damage(40, DAMAGE_BRUTE) if(H.species.mob_size < 16) playsound(M, 'sound/weapons/push_connect.ogg', 50, 1, -1) src.visible_message(SPAN_DANGER("\The [src] slams into \the [H], sending them flying!")) var/turf/target_turf = get_ranged_target_turf(H, M.dir, 4) H.throw_at(target_turf, 4, 1, src) H.apply_effect(4, WEAKEN) /obj/vehicle/animal/warmount/collide_act(atom/movable/AM) var/mob/living/M if(!buckled) return if(istype(buckled, /mob/living)) M = buckled if(M.m_intent == M_RUN) if (istype(AM, /obj/vehicle)) M.setMoveCooldown(10) var/obj/vehicle/V = AM if(prob(50)) if(V.buckled) if(ishuman(V.buckled)) var/mob/living/carbon/human/I = V.buckled I.visible_message(SPAN_DANGER("\The [I] falls off from \the [V]")) V.unload(I) I.throw_at(get_edge_target_turf(V.loc, V.loc.dir), 5, 1) I.apply_effect(2, WEAKEN) if(prob(25)) if(ishuman(buckled)) var/mob/living/carbon/human/C = buckled C.visible_message(SPAN_DANGER ("\The [C] falls off from \the [src]!")) unload(C) C.throw_at(get_edge_target_turf(loc, loc.dir), 5, 1) C.apply_effect(2, WEAKEN) if(isliving(AM)) if(ishuman(AM)) var/mob/living/carbon/human/H = AM M.attack_log += "\[[time_stamp()]\] Was rammed by [src]" M.attack_log += "\[[time_stamp()]\] rammed[M.name] ([M.ckey]) rammed [H.name] ([H.ckey]) with the [src]." msg_admin_attack("[src] crashed into [key_name(H)] at (JMP)" ) src.visible_message(SPAN_DANGER("\The [src] charges into \the [H]!")) playsound(src, 'sound/weapons/pierce.ogg', 50, 1) H.apply_damage(40, DAMAGE_BRUTE) if(H.species.mob_size < 16) playsound(M, 'sound/weapons/push_connect.ogg', 50, 1, -1) src.visible_message(SPAN_DANGER("\The [src] slams into \the [H], sending them flying!")) var/turf/target_turf = get_ranged_target_turf(H, M.dir, 4) H.throw_at(target_turf, 4, 1, src) H.apply_effect(4, WEAKEN) M.setMoveCooldown(10) return TRUE else var/mob/living/L = AM src.visible_message(SPAN_DANGER("\The [src] smashes into \the [L]!")) playsound(src, 'sound/weapons/pierce.ogg', 50, 1) L.throw_at(get_edge_target_turf(loc, loc.dir), 5, 1) L.apply_damage(40, DAMAGE_BRUTE) M.setMoveCooldown(10) return TRUE