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"