diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 743b23db0c..3293d6ef2b 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -61,7 +61,16 @@ HALOGEN COUNTER - Radcount on mobs
flick("[icon_state]-scan", src) //makes it so that it plays the scan animation on a succesful scan
user.visible_message("[user] has analyzed [M]'s vitals.","You have analyzed [M]'s vitals.")
- if (!ishuman(M) || M.isSynthetic())
+ if(isanimal(M))
+ //these sensors are designed for organic life
+ dat += "Analyzing Results for \the [M]:\n\tOverall Status: ERROR
"
+ dat += "\tKey: Suffocation/Toxin/Burns/Brute
"
+ dat += "\tDamage Specifics: [M.getOxyLoss()] - [M.getToxLoss()] - [M.getFireLoss()] - [M.getBruteLoss()]
"
+ dat += "Body temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)
"
+ user.show_message(dat, 1)
+ return
+
+ else if (!ishuman(M) || M.isSynthetic())
//these sensors are designed for organic life
dat += "Analyzing Results for ERROR:\n\tOverall Status: ERROR
"
dat += "\tKey: Suffocation/Toxin/Burns/Brute
"
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm
index e938c364fd..bd428590fd 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka.dm
@@ -230,6 +230,8 @@ var/global/list/last_drake_howl = list()
var/max_stored_sap = 60
var/attacked_by_human = FALSE
+ var/list/original_armor
+
/mob/living/simple_mob/animal/sif/grafadreka/proc/can_tend_wounds(var/mob/living/friend)
if(ishuman(friend))
var/mob/living/carbon/human/H = friend
@@ -257,6 +259,7 @@ var/global/list/last_drake_howl = list()
. = ..()
+ original_armor = armor
update_icon()
/mob/living/simple_mob/animal/sif/grafadreka/examine(var/mob/living/user)
@@ -303,7 +306,7 @@ var/global/list/last_drake_howl = list()
// Process food and sap chems.
if(reagents?.total_volume)
for(var/datum/reagent/chem in reagents.reagent_list)
- var/removed = min(chem.ingest_met, chem.volume)
+ var/removed = min(REM, min(chem.ingest_met, chem.volume))
chem.affect_animal(src, removed)
reagents.remove_reagent(chem.id, removed)
@@ -622,93 +625,3 @@ var/global/list/last_drake_howl = list()
projectiletype = /obj/item/projectile/drake_spit/weak
maxHealth = 60
health = 60
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained
- desc = "A large, sleek snow drake with heavy claws, powerful jaws and many pale spines along its body. This one is wearing some kind of vest with a pannier; maybe it belongs to someone."
- player_msg = "You are a large Sivian pack predator in symbiosis with the local bioluminescent bacteria. You can eat glowing \
- tree fruit to fuel your ranged spitting attack and poisonous bite (on harm intent), as well as healing saliva \
- (on help intent).
Unlike your wild kin, you are trained and work happily with your two-legged packmates."
- faction = "station"
- ai_holder_type = null // These guys should not exist without players.
- gender = PLURAL // Will take gender from prefs = set to non-NEUTER here to avoid randomizing in Initialize().
- var/obj/item/storage/internal/pannier = /obj/item/storage/internal/drake_pannier
-
-// It's just a backpack.
-/obj/item/storage/internal/drake_pannier
- color = COLOR_BEASTY_BROWN
- max_w_class = ITEMSIZE_LARGE
- max_storage_space = INVENTORY_STANDARD_SPACE
-
-/obj/item/storage/internal/drake_pannier/Initialize()
- . = ..() // Name is set lower in Initialize() so we set it again here.
- name = "drake's pannier"
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained/attackby(obj/item/O, mob/user)
-
- // bonk
- if(user.a_intent == I_HURT)
- return ..()
-
- // Pass some items down to heal or run injection etc.
- var/static/list/allow_type_to_pass = list(
- /obj/item/healthanalyzer,
- /obj/item/stack/medical,
- /obj/item/reagent_containers/syringe
- )
- if(user.a_intent == I_HELP)
- for(var/pass_type in allow_type_to_pass)
- if(istype(O, pass_type))
- return ..()
-
- // Open our storage, if we have it.
- if(pannier)
- return pannier.attackby(O, user)
-
- return ..()
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained/add_glow()
- . = ..()
- if(. && pannier)
- var/image/I = .
- I.icon_state = "[I.icon_state]-pannier"
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained/Logout()
- ..()
- if(stat != DEAD)
- lying = TRUE
- resting = TRUE
- sitting = FALSE
- Sleeping(2)
- update_icon()
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained/Login()
- ..()
- SetSleeping(0)
- update_icon()
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained/attack_hand(mob/living/L)
- // Permit headpats/smacks
- if(!pannier || L.a_intent == I_HURT || (L.a_intent == I_HELP && L.zone_sel?.selecting == BP_HEAD))
- return ..()
- return pannier.handle_attack_hand(L)
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained/Initialize()
- if(ispath(pannier))
- pannier = new pannier(src)
- . = ..()
-
-// universal_understand is buggy and produces double lines, so we'll just do this hack instead.
-/mob/living/simple_mob/animal/sif/grafadreka/trained/say_understands(var/mob/other, var/datum/language/speaking = null)
- if(!speaking || speaking.name == LANGUAGE_GALCOM)
- return TRUE
- return ..()
-
-/mob/living/simple_mob/animal/sif/grafadreka/trained/update_icon()
- . = ..()
- if(pannier)
- var/image/I = image(icon, "[current_icon_state]-pannier")
- I.color = pannier.color
- I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE|KEEP_APART)
- if(offset_compiled_icon)
- I.pixel_x = offset_compiled_icon
- add_overlay(I)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_harness.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_harness.dm
new file mode 100644
index 0000000000..9f446401f7
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_harness.dm
@@ -0,0 +1,129 @@
+// It's just a backpack.
+/obj/item/storage/internal/animal_harness
+ color = COLOR_BEASTY_BROWN
+ max_w_class = ITEMSIZE_LARGE
+ max_storage_space = INVENTORY_STANDARD_SPACE
+ var/obj/item/gps/attached_gps
+ var/obj/item/clothing/accessory/armor/attached_plate
+ var/obj/item/radio/attached_radio
+
+/obj/item/storage/internal/animal_harness/Initialize()
+
+ // Spawn some useful items. We can't use them, but anyone we find can.
+ new /obj/item/stack/medical/bruise_pack(src)
+ new /obj/item/stack/medical/ointment(src)
+ var/ration_type = pick(list(
+ /obj/item/storage/mre,
+ /obj/item/storage/mre/menu2,
+ /obj/item/storage/mre/menu3,
+ /obj/item/storage/mre/menu4,
+ /obj/item/storage/mre/menu5,
+ /obj/item/storage/mre/menu6,
+ /obj/item/storage/mre/menu7,
+ /obj/item/storage/mre/menu8,
+ /obj/item/storage/mre/menu9,
+ /obj/item/storage/mre/menu10
+ ))
+ new ration_type(src)
+
+ . = ..() // Name is set lower in Initialize() so we set it again here.
+ name = "animal harness"
+
+/obj/item/storage/internal/animal_harness/Destroy()
+ var/mob/living/simple_mob/animal/sif/grafadreka/trained/drake = loc
+ if(istype(drake) && drake.harness == src)
+ drake.harness = null
+ drake.armor = drake.original_armor
+ QDEL_NULL(attached_radio)
+ QDEL_NULL(attached_gps)
+ QDEL_NULL(attached_plate)
+ . = ..()
+
+/obj/item/storage/internal/animal_harness/attackby(obj/item/W, mob/user)
+
+ // Sanity check for some stuff below.
+ if(!istype(loc, /mob/living/simple_mob/animal/sif/grafadreka/trained))
+ return ..()
+
+ // Attach a tracker.
+ if(istype(W, /obj/item/gps))
+ if(attached_gps)
+ to_chat(user, SPAN_WARNING("There is already \a [attached_gps] attached to \the [loc]'s harness."))
+ else if(user.unEquip(W))
+ W.forceMove(loc)
+ user.visible_message(SPAN_NOTICE("\The [user] attaches \the [W] to \the [loc]'s harness."))
+ attached_gps = W
+ loc.verbs |= /mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_gps
+ return TRUE
+
+ // Attach an armor plate.
+ if(istype(W, /obj/item/clothing/accessory/armor))
+ if(attached_plate)
+ to_chat(user, SPAN_WARNING("There is already \a [attached_plate] inside \the [loc]'s harness."))
+ else if(user.unEquip(W))
+ W.forceMove(loc)
+ user.visible_message(SPAN_NOTICE("\The [user] secures \the [W] inside \the [loc]'s harness."))
+ attached_plate = W
+ var/mob/living/simple_mob/animal/sif/grafadreka/trained/drake = loc
+ drake.armor = attached_plate.armor
+ loc.verbs |= /mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_plate
+ return TRUE
+
+ // Attach a radio.
+ if(istype(W, /obj/item/radio))
+ if(attached_radio)
+ to_chat(user, SPAN_WARNING("There is already \a [attached_radio] attached to \the [loc]'s harness."))
+ else if(user.unEquip(W))
+ W.forceMove(loc)
+ user.visible_message(SPAN_NOTICE("\The [user] attaches \the [W] to \the [loc]'s harness."))
+ attached_radio = W
+ loc.verbs |= /mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_radio
+ return TRUE
+
+ . = ..()
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_plate()
+ set name = "Remove Attached Plate"
+ set category = "IC"
+ set src in view(1)
+ if(harness?.attached_plate)
+ harness.attached_plate.dropInto(get_turf(src))
+ if(usr == src)
+ var/datum/gender/G = gender_datums[get_visible_gender()]
+ visible_message("\The [src] awkwardly pulls \the [harness.attached_plate] out of [G.his] harness and drops it.")
+ else
+ visible_message("\The [usr] removes \the [harness.attached_plate] from \the [src]'s harness.")
+ usr.put_in_hands(harness.attached_plate)
+ harness.attached_plate = null
+ armor = original_armor
+ verbs -= /mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_plate
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_gps()
+ set name = "Remove Attached GPS"
+ set category = "IC"
+ set src in view(1)
+ if(harness?.attached_gps)
+ harness.attached_gps.dropInto(get_turf(src))
+ if(usr == src)
+ var/datum/gender/G = gender_datums[get_visible_gender()]
+ visible_message("\The [src] awkwardly pulls \the [harness.attached_gps] off [G.his] harness and drops it.")
+ else
+ visible_message("\The [usr] detaches \the [harness.attached_gps] from \the [src]'s harness.")
+ usr.put_in_hands(harness.attached_gps)
+ harness.attached_gps = null
+ verbs -= /mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_gps
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_radio()
+ set name = "Remove Attached Radio"
+ set category = "IC"
+ set src in view(1)
+ if(harness?.attached_radio)
+ harness.attached_radio.dropInto(get_turf(src))
+ if(usr == src)
+ var/datum/gender/G = gender_datums[get_visible_gender()]
+ visible_message("\The [src] awkwardly pulls \the [harness.attached_radio] off [G.his] harness and drops it.")
+ else
+ visible_message("\The [usr] detaches \the [harness.attached_radio] from \the [src]'s harness.")
+ usr.put_in_hands(harness.attached_radio)
+ harness.attached_radio = null
+ verbs -= /mob/living/simple_mob/animal/sif/grafadreka/trained/proc/remove_attached_radio
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_trained.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_trained.dm
new file mode 100644
index 0000000000..4885d04615
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/grafadreka_trained.dm
@@ -0,0 +1,92 @@
+/mob/living/simple_mob/animal/sif/grafadreka/trained
+ desc = "A large, sleek snow drake with heavy claws, powerful jaws and many pale spines along its body. This one is wearing some kind of harness; maybe it belongs to someone."
+ player_msg = "You are a large Sivian pack predator in symbiosis with the local bioluminescent bacteria. You can eat glowing \
+ tree fruit to fuel your ranged spitting attack and poisonous bite (on harm intent), as well as healing saliva \
+ (on help intent).
Unlike your wild kin, you are trained and work happily with your two-legged packmates."
+ faction = "station"
+ ai_holder_type = null // These guys should not exist without players.
+ gender = PLURAL // Will take gender from prefs = set to non-NEUTER here to avoid randomizing in Initialize().
+ var/obj/item/storage/internal/animal_harness/harness = /obj/item/storage/internal/animal_harness
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/Initialize()
+ if(ispath(harness))
+ harness = new harness(src)
+ harness.attached_radio = new /obj/item/radio(src)
+ . = ..()
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/Destroy()
+ if(istype(harness))
+ QDEL_NULL(harness)
+ return ..()
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/examine(mob/living/user)
+ . = ..()
+ if(harness)
+ . += "\The [src] is wearing \a [harness]."
+ for(var/obj/item/thing in list(harness.attached_gps, harness.attached_plate, harness.attached_radio))
+ . += "There is \a [thing] attached."
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/add_glow()
+ . = ..()
+ if(. && harness)
+ var/image/I = .
+ I.icon_state = "[I.icon_state]-pannier"
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/Logout()
+ ..()
+ if(stat != DEAD)
+ lying = TRUE
+ resting = TRUE
+ sitting = FALSE
+ Sleeping(2)
+ update_icon()
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/Login()
+ ..()
+ SetSleeping(0)
+ update_icon()
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/attack_hand(mob/living/L)
+ // Permit headpats/smacks
+ if(!harness || L.a_intent == I_HURT || (L.a_intent == I_HELP && L.zone_sel?.selecting == BP_HEAD))
+ return ..()
+ return harness.handle_attack_hand(L)
+
+// universal_understand is buggy and produces double lines, so we'll just do this hack instead.
+/mob/living/simple_mob/animal/sif/grafadreka/trained/say_understands(var/mob/other, var/datum/language/speaking = null)
+ if(!speaking || speaking.name == LANGUAGE_GALCOM)
+ return TRUE
+ return ..()
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/update_icon()
+ . = ..()
+ if(harness)
+ var/image/I = image(icon, "[current_icon_state]-pannier")
+ I.color = harness.color
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE|KEEP_APART)
+ if(offset_compiled_icon)
+ I.pixel_x = offset_compiled_icon
+ add_overlay(I)
+
+/mob/living/simple_mob/animal/sif/grafadreka/trained/attackby(obj/item/O, mob/user)
+
+ // bonk
+ if(user.a_intent == I_HURT)
+ return ..()
+
+ // Pass some items down to heal or run injection etc.
+ var/static/list/allow_type_to_pass = list(
+ /obj/item/healthanalyzer,
+ /obj/item/stack/medical,
+ /obj/item/reagent_containers/syringe
+ )
+ if(user.a_intent == I_HELP)
+ for(var/pass_type in allow_type_to_pass)
+ if(istype(O, pass_type))
+ return ..()
+
+ // Open our storage, if we have it.
+ if(harness)
+ return harness.attackby(O, user)
+
+ return ..()
diff --git a/maps/cynosure/cynosure_jobs.dm b/maps/cynosure/cynosure_jobs.dm
index 833f683f45..5693ee9eb0 100644
--- a/maps/cynosure/cynosure_jobs.dm
+++ b/maps/cynosure/cynosure_jobs.dm
@@ -1,5 +1,5 @@
#define CRASH_SURVIVOR_TITLE "Crash Survivor"
-#define DRAKE_SURVIVOR_TITLE "Working Drake"
+#define DRAKE_SURVIVOR_TITLE "Tamed Drake"
// Pilots
diff --git a/polaris.dme b/polaris.dme
index 21aba450cb..1b62dc655e 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -2481,6 +2481,8 @@
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\glitterfly.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\grafadreka.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\grafadreka_ai.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\grafadreka_harness.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\grafadreka_trained.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\hare.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\hooligan_crab.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\sif\kururak.dm"