mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-08-24 13:46:53 +01:00
Merge pull request #9294 from MistakeNot4892/xenofauna
Xenofauna Tech equipment update.
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
var/entries_decay_at // Set in rounds. This controls when item messages start getting scrambled.
|
||||
var/entry_decay_weight = 0.5
|
||||
var/has_admin_data
|
||||
var/area_restricted = TRUE
|
||||
var/station_restricted = TRUE
|
||||
|
||||
/datum/persistent/New()
|
||||
SetFilename()
|
||||
@@ -71,14 +73,15 @@
|
||||
/datum/persistent/proc/IsValidEntry(var/atom/entry)
|
||||
if(!istype(entry))
|
||||
return FALSE
|
||||
if(GetEntryAge(entry) >= entries_expire_at)
|
||||
if(!isnull(entries_expire_at) && GetEntryAge(entry) >= entries_expire_at)
|
||||
return FALSE
|
||||
var/turf/T = get_turf(entry)
|
||||
if(!T || !(T.z in using_map.station_levels) )
|
||||
return FALSE
|
||||
var/area/A = get_area(T)
|
||||
if(!A || (A.area_flags & AREA_FLAG_IS_NOT_PERSISTENT))
|
||||
if(station_restricted && (!T || !(T.z in using_map.station_levels) ))
|
||||
return FALSE
|
||||
if(area_restricted)
|
||||
var/area/A = get_area(T)
|
||||
if(!A || (A.area_flags & AREA_FLAG_IS_NOT_PERSISTENT))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/persistent/proc/GetEntryAge(var/atom/entry)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Currently unticked pending full implementation of the required data structures
|
||||
// and tracking/load logic. Needs to account for DMMS load, critters spawning in POIs,
|
||||
// critters spawning on station, etc. Fair bit of design work to consider.
|
||||
/datum/persistent/specimen
|
||||
name = "specimen"
|
||||
entries_expire_at = 10
|
||||
area_restricted = FALSE
|
||||
station_restricted = FALSE
|
||||
|
||||
/datum/persistent/specimen/CreateEntryInstance(var/turf/creating, var/list/token)
|
||||
new /obj/item/gps/specimen_tag(
|
||||
creating,
|
||||
token["age"]+1,
|
||||
token["implanted_by"],
|
||||
token["specimen_id"],
|
||||
token["specimen_gender"],
|
||||
token["physical_info"],
|
||||
token["behavior_info"],
|
||||
text2path(token["specimen_type"])
|
||||
)
|
||||
|
||||
/datum/persistent/specimen/GetEntryAge(var/atom/entry)
|
||||
var/obj/item/gps/specimen_tag/save_specimen = entry
|
||||
if(!istype(save_specimen))
|
||||
return 0
|
||||
return save_specimen.age
|
||||
|
||||
/datum/persistent/specimen/IsValidEntry(atom/entry)
|
||||
. = ..()
|
||||
var/obj/item/gps/specimen_tag/save_specimen = entry
|
||||
return istype(save_specimen) && save_specimen.has_been_implanted() && save_specimen.implanted_in.stat != DEAD
|
||||
|
||||
/datum/persistent/specimen/CompileEntry(var/atom/entry, var/write_file)
|
||||
. = ..()
|
||||
var/obj/item/gps/specimen_tag/save_specimen = entry
|
||||
if(!istype(save_specimen))
|
||||
return
|
||||
save_specimen.update_from_animal()
|
||||
LAZYADDASSOC(., "implanted_by", save_specimen.implanted_by)
|
||||
LAZYADDASSOC(., "specimen_id", save_specimen.gps_tag)
|
||||
LAZYADDASSOC(., "specimen_type", save_specimen.implanted_in.type)
|
||||
LAZYADDASSOC(., "specimen_gender", save_specimen.gender)
|
||||
LAZYADDASSOC(., "physical_info", save_specimen.physical_info)
|
||||
LAZYADDASSOC(., "behavior_info", save_specimen.behavioral_info)
|
||||
@@ -0,0 +1,292 @@
|
||||
// Device used to implant, remove or read specimen tags.
|
||||
|
||||
/* Notes on specimen tagger and expected flow:
|
||||
* - Xenofauna player uses tagger (/obj/item/specimen_tagger) on appropriate critter (appropriate type, has cataloguer info).
|
||||
* - Tag (/obj/item/gps/specimen_tag) is created and registered in the critter.
|
||||
* - Xenofauna players can then track the tag via GPS to scan, remove, etc.
|
||||
* - When persistent specimens are committed, tags will be loaded and assigned to mobs at world init.
|
||||
*/
|
||||
|
||||
/obj/item/specimen_tagger
|
||||
name = "specimen tagger"
|
||||
desc = "A handheld device used to implant, remove and read xenofauna tracking tags from local specimens. Not for use on crewmembers."
|
||||
icon = 'icons/obj/specimen_tagger.dmi'
|
||||
icon_state = "tagger"
|
||||
force = 0
|
||||
item_flags = NOBLUDGEON
|
||||
var/tag_id = "FAUNA0"
|
||||
var/static/list/unsuitable_tag_types = list(
|
||||
// Do not specimen tag your crewmates
|
||||
/mob/living/carbon,
|
||||
/mob/living/simple_mob/animal/sif/grafadreka/trained,
|
||||
// Do not specimen tag pre-mapped critters
|
||||
/mob/living/simple_mob/animal/passive/opossum/poppy,
|
||||
/mob/living/simple_mob/animal/passive/dog/corgi/Ian,
|
||||
/mob/living/simple_mob/animal/passive/cat/runtime
|
||||
)
|
||||
|
||||
/obj/item/specimen_tagger/attack_self(mob/user)
|
||||
var/new_tag = input("Please enter desired tag.", name, tag_id) as text
|
||||
if(QDELETED(src) || QDELETED(user) || user.incapacitated() || loc != user)
|
||||
return TRUE
|
||||
new_tag = uppertext(copytext(sanitize(new_tag), 1, 11))
|
||||
if(!length(new_tag))
|
||||
return TRUE
|
||||
tag_id = new_tag
|
||||
to_chat(usr, "You set the tracker tag to '[tag_id]'.")
|
||||
return TRUE
|
||||
|
||||
/obj/item/specimen_tagger/examine(mob/user)
|
||||
. = ..()
|
||||
. += "Use this on a living animal on help intent to read an existing tracker, grab intent to tag an animal with a tracker, and any other intent to remove an existing tracker."
|
||||
|
||||
/obj/item/specimen_tagger/attack(mob/living/M, mob/living/user, target_zone, attack_modifier)
|
||||
switch(user.a_intent)
|
||||
if(I_HELP)
|
||||
try_read_tag(user, M)
|
||||
if(I_GRAB)
|
||||
try_implant_tag(user, M)
|
||||
else
|
||||
try_remove_tag(user, M)
|
||||
return TRUE
|
||||
|
||||
/obj/item/specimen_tagger/proc/try_read_tag(var/mob/user, var/mob/living/target)
|
||||
var/obj/item/gps/specimen_tag/xenotag = locate() in target
|
||||
if(!istype(xenotag) || !xenotag.has_been_implanted())
|
||||
to_chat(user, SPAN_WARNING("\The [target] has not been tagged."))
|
||||
return FALSE
|
||||
to_chat(user, "<b>Specimen data for [xenotag.gps_tag]:</b>")
|
||||
to_chat(user, "<b>Species:</b> [target.real_name]")
|
||||
to_chat(user, "<b>Tag duration:</b> [xenotag.age] shift\s")
|
||||
to_chat(user, "<b>Tagged by:</b> [xenotag.implanted_by]")
|
||||
to_chat(user, "<b>Physical notes:</b> [xenotag.physical_info]")
|
||||
to_chat(user, "<b>Behavioral notes:</b> [xenotag.behavioral_info]")
|
||||
return TRUE
|
||||
|
||||
/obj/item/specimen_tagger/proc/check_can_tag(var/mob/user, var/mob/living/target)
|
||||
if(QDELETED(target) || !istype(target) || target.stat == DEAD || target.isSynthetic())
|
||||
to_chat(user, SPAN_WARNING("Xenofauna specimens need to be living organic creatures."))
|
||||
return FALSE
|
||||
if(!LAZYLEN(target.get_catalogue_data()))
|
||||
to_chat(user, SPAN_WARNING("There's no scientific reason to tag \the [target]."))
|
||||
return FALSE
|
||||
if(target.key || target.client || is_type_in_list(target, unsuitable_tag_types))
|
||||
to_chat(user, SPAN_WARNING("\The [target] is not suitable for tagging."))
|
||||
return FALSE
|
||||
var/obj/item/gps/specimen_tag/xenotag = locate(/obj/item/gps/specimen_tag) in target
|
||||
if(istype(xenotag) && xenotag.has_been_implanted())
|
||||
to_chat(user, SPAN_WARNING("\The [target] has already been tagged."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/specimen_tagger/proc/try_implant_tag(var/mob/user, var/mob/living/target)
|
||||
if(!check_can_tag(user, target))
|
||||
return FALSE
|
||||
user.visible_message(SPAN_NOTICE("\The [user] begins tagging \the [target] with \the [src]..."))
|
||||
if(!do_after(user, 3 SECONDS, target) || !check_can_tag(user, target))
|
||||
return FALSE
|
||||
var/obj/item/gps/specimen_tag/xenotag = new
|
||||
xenotag.SetTag(tag_id)
|
||||
xenotag.implanted_by = user.real_name
|
||||
if(user.mind)
|
||||
var/user_title = user.mind.assigned_role || user.mind.role_alt_title
|
||||
if(user_title)
|
||||
xenotag.implanted_by = "[xenotag.implanted_by], [user_title]"
|
||||
|
||||
xenotag.implant(target)
|
||||
user.visible_message(SPAN_NOTICE("\The [user] tags \the [target] with \a [xenotag]!"))
|
||||
return TRUE
|
||||
|
||||
/obj/item/specimen_tagger/proc/can_remove_tag(var/mob/user, var/mob/living/target)
|
||||
if(!istype(target))
|
||||
to_chat(user, SPAN_WARNING("\The [target] is not a xenofauna specimen."))
|
||||
return FALSE
|
||||
var/obj/item/gps/specimen_tag/xenotag = locate() in target
|
||||
if(!istype(xenotag) || !xenotag.has_been_implanted())
|
||||
to_chat(user, SPAN_WARNING("\The [target] has not been tagged."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/specimen_tagger/proc/try_remove_tag(var/mob/user, var/mob/living/target)
|
||||
if(!can_remove_tag(user, target))
|
||||
return FALSE
|
||||
var/obj/item/gps/specimen_tag/xenotag = locate() in target
|
||||
if(!istype(xenotag))
|
||||
return FALSE
|
||||
user.visible_message(SPAN_NOTICE("\The [user] starts removing \the [xenotag] from \the [target] with \the [src]..."))
|
||||
if(!do_after(user, 3 SECONDS, target) || !can_remove_tag(user, target))
|
||||
return FALSE
|
||||
if(!istype(xenotag))
|
||||
return FALSE
|
||||
qdel(xenotag)
|
||||
user.visible_message(SPAN_NOTICE("\The [user] removes \the [xenotag] from \the [target]!"))
|
||||
return TRUE
|
||||
|
||||
// Specimen tag itself.
|
||||
/obj/item/gps/specimen_tag
|
||||
name = "xenofauna tracker"
|
||||
gps_tag = "FAUNA0"
|
||||
icon = 'icons/obj/specimen_tag.dmi'
|
||||
icon_state = "gps-tag"
|
||||
w_class = ITEMSIZE_TINY
|
||||
tag_category = "XENOFAUNA"
|
||||
|
||||
var/age = 0
|
||||
var/mob/living/implanted_in
|
||||
var/implanted_by
|
||||
var/physical_info = "No notes recorded."
|
||||
var/behavioral_info = "No notes recorded."
|
||||
|
||||
/obj/item/gps/specimen_tag/Initialize(mapload, _age, _implanted_by, _specimen_id, _specimen_gender, _physical_info, _behavioral_info, _specimen_type)
|
||||
// If we have a specimen, set up our data.
|
||||
if(_specimen_type)
|
||||
var/mob/living/critter = new _specimen_type(get_turf(src))
|
||||
implant(critter, TRUE)
|
||||
if(_specimen_gender)
|
||||
critter.gender = _specimen_gender
|
||||
if(_age)
|
||||
age = _age
|
||||
if(_specimen_id)
|
||||
gps_tag = _specimen_id
|
||||
if(_physical_info)
|
||||
physical_info = _physical_info
|
||||
if(_behavioral_info)
|
||||
behavioral_info = _behavioral_info
|
||||
if(_implanted_by)
|
||||
implanted_by = _implanted_by
|
||||
. = ..()
|
||||
if(!tracking)
|
||||
toggletracking()
|
||||
|
||||
/obj/item/gps/specimen_tag/Destroy()
|
||||
clear_implanted()
|
||||
// TODO: persistent tags
|
||||
// SSpersistence.forget_value(src, /datum/persistent/specimen)
|
||||
. = ..()
|
||||
|
||||
/obj/item/gps/specimen_tag/Move()
|
||||
. = ..()
|
||||
if(implanted_in && loc != implanted_in)
|
||||
clear_implanted()
|
||||
|
||||
// Specimen tags are just for tracking, they don't work as held GPS.
|
||||
/obj/item/gps/specimen_tag/attack_hand(mob/living/user)
|
||||
toggletracking(user)
|
||||
return TRUE
|
||||
/obj/item/gps/specimen_tag/check_visible_to_holder()
|
||||
return FALSE
|
||||
/obj/item/gps/specimen_tag/create_compass()
|
||||
return
|
||||
/obj/item/gps/specimen_tag/display_list()
|
||||
return list()
|
||||
|
||||
/obj/item/gps/specimen_tag/proc/has_been_implanted()
|
||||
return !QDELETED(implanted_in) && istype(implanted_in) && loc == implanted_in
|
||||
|
||||
/obj/item/gps/specimen_tag/proc/implant(var/mob/target, var/implanted_in_init = FALSE)
|
||||
forceMove(target)
|
||||
implanted_in = target
|
||||
GLOB.destroyed_event.register(implanted_in, src, /obj/item/gps/specimen_tag/proc/clear_implanted)
|
||||
// TODO: persistent tags
|
||||
// SSpersistence.track_value(src, /datum/persistent/specimen)
|
||||
if(!implanted_in_init)
|
||||
generate_critter_info()
|
||||
|
||||
/obj/item/gps/specimen_tag/proc/generate_critter_info()
|
||||
|
||||
var/list/possible_physical_info
|
||||
var/list/possible_behavioral_info
|
||||
var/list/catalogue_data = implanted_in.get_catalogue_data()
|
||||
for(var/catalogue_data_type in catalogue_data)
|
||||
if(ispath(catalogue_data_type, /datum/category_item/catalogue/fauna))
|
||||
var/datum/category_item/catalogue/fauna/fauna_data = GLOB.catalogue_data.resolve_item(catalogue_data_type)
|
||||
var/notes = fauna_data.get_fauna_physical_notes()
|
||||
if(!isnull(notes))
|
||||
LAZYDISTINCTADD(possible_physical_info, notes)
|
||||
notes = fauna_data.get_fauna_behavior_notes()
|
||||
if(!isnull(notes))
|
||||
LAZYDISTINCTADD(possible_behavioral_info, notes)
|
||||
|
||||
if(LAZYLEN(possible_physical_info))
|
||||
physical_info = pick(possible_physical_info)
|
||||
else
|
||||
physical_info = "No notes recorded."
|
||||
|
||||
if(LAZYLEN(possible_behavioral_info))
|
||||
behavioral_info = pick(possible_behavioral_info)
|
||||
else
|
||||
behavioral_info = "No notes recorded."
|
||||
|
||||
/obj/item/gps/specimen_tag/proc/clear_implanted()
|
||||
if(implanted_in)
|
||||
GLOB.destroyed_event.unregister(implanted_in, src)
|
||||
implanted_in = null
|
||||
|
||||
/obj/item/gps/specimen_tag/proc/update_from_animal()
|
||||
return
|
||||
|
||||
// Mob helpers/overrides.
|
||||
/mob/living/examine(mob/user, infix, suffix)
|
||||
. = ..()
|
||||
var/obj/item/gps/specimen_tag/xenotag = locate() in src
|
||||
if(istype(xenotag) && xenotag.has_been_implanted())
|
||||
. += "\The [src] has been tagged with \a [xenotag]."
|
||||
|
||||
// Lists of strings used by the specimen tracking system to add flavour to
|
||||
// specimens. Static lists in procs to allow overriding while also not putting
|
||||
// a massive string list on every single cataloguer fauna entry.
|
||||
/datum/category_item/catalogue/fauna/proc/get_fauna_physical_notes()
|
||||
var/static/list/fauna_physical_notes = list(
|
||||
"Perpetually smells like mold no matter what we do about it.",
|
||||
"Perpetually smells like mildew no matter what we do about it.",
|
||||
"Perpetually smells like sifsap no matter what we do about it.",
|
||||
"Seems to always have an itch in the spot it can't reach.",
|
||||
"Vocalizations are notably harsh and loud for the species.",
|
||||
"Vocalizations are notably soft and quiet for the species.",
|
||||
"Has a notch in its left ear.",
|
||||
"Has a notch in its right ear.",
|
||||
"Is missing its left ear.",
|
||||
"Is missing its right ear.",
|
||||
"Is missing its left eye.",
|
||||
"Is missing its right eye.",
|
||||
"Has had the very tip of its tail chewed off.",
|
||||
"Might have trouble with its hearing.",
|
||||
"Is more scar tissue than animal at this point.",
|
||||
"Walks with a limp.",
|
||||
"Has two differently colored eyes.",
|
||||
"Might have a cold...",
|
||||
"Is allergic to nuts.",
|
||||
"Is allergic to berries.",
|
||||
"Is allergic to dairy."
|
||||
)
|
||||
return fauna_physical_notes
|
||||
|
||||
/datum/category_item/catalogue/fauna/proc/get_fauna_behavior_notes()
|
||||
var/static/list/fauna_behavior_notes = list(
|
||||
"Likes rolling around in the moss with reckless abandon.",
|
||||
"Enjoys munching on frostbelles the most, as a treat.",
|
||||
"Enjoys munching on wabback the most, as a treat.",
|
||||
"Enjoys munching on eyebulbs the most, as a treat.",
|
||||
"Constantly sniffs around at everything new.",
|
||||
"Seems super friendly! Probably won't bite. Probably.",
|
||||
"Seems rather stand-offish. Mind the personal bubble.",
|
||||
"Loves a good back scritch.",
|
||||
"Loves a good head scritch.",
|
||||
"Loves a good behind the ear scritch.",
|
||||
"Seems to hate the world and everything in it.",
|
||||
"Just tolerates being pet, but certainly doesn't enjoy it.",
|
||||
"Often sticks its head into snowbanks to contemplate the state of things.",
|
||||
"Enjoys singing along to songs only it can hear. Mostly just sounds like an animal wailing.",
|
||||
"Would rather be fishing.",
|
||||
"Partakes in many siestas.",
|
||||
"Struggles with object permanence.",
|
||||
"Is very picky about food; maybe it's a texture thing.",
|
||||
"Is a sentient garbage disposal for anything even remotely edible.",
|
||||
"Loves swimming and splashing around in water.",
|
||||
"Sinks like a rock the moment it enters water.",
|
||||
"Gets lost easily.",
|
||||
"Enjoys soft things. It'd have a bed of plushies if it knew what a bed was.",
|
||||
"Never seems to be in a rush to go anywhere...",
|
||||
"Has gotta go fast at all times."
|
||||
)
|
||||
return fauna_behavior_notes
|
||||
Reference in New Issue
Block a user