Skip to content

Commit

Permalink
пересозданный МИРРОР 34500 (#2925)
Browse files Browse the repository at this point in the history
Co-authored-by: Builder13 <[email protected]>
Co-authored-by: Lexanx <[email protected]>
  • Loading branch information
3 people authored Dec 2, 2024
1 parent 355e356 commit f99ac23
Show file tree
Hide file tree
Showing 24 changed files with 520 additions and 27 deletions.
2 changes: 2 additions & 0 deletions baystation12.dme
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@
#include "code\datums\traits\general\nonpermeable_skin.dm"
#include "code\datums\traits\general\permeable_skin.dm"
#include "code\datums\traits\general\serpentid_adapted.dm"
#include "code\datums\traits\maluses\allergy.dm"
#include "code\datums\traits\maluses\animal_protein.dm"
#include "code\datums\traits\maluses\ethanol.dm"
#include "code\datums\traits\maluses\malus.dm"
Expand Down Expand Up @@ -2166,6 +2167,7 @@
#include "code\modules\mob\living\bot\mulebot.dm"
#include "code\modules\mob\living\bot\remotebot.dm"
#include "code\modules\mob\living\bot\secbot.dm"
#include "code\modules\mob\living\carbon\allergy.dm"
#include "code\modules\mob\living\carbon\breathe.dm"
#include "code\modules\mob\living\carbon\carbon.dm"
#include "code\modules\mob\living\carbon\carbon_defense.dm"
Expand Down
4 changes: 4 additions & 0 deletions code/__defines/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -496,3 +496,7 @@

/// Integer (~ticks * SSMobs/wait fire rate). The default maximum value a mob's confused var can be set to.
#define CONFUSED_MAX 15

///Flags assigned to carbon mobs trait_flags when they're actively having an allergy.
#define MILD_ALLERGY FLAG(0)
#define SEVERE_ALLERGY FLAG(1)
3 changes: 3 additions & 0 deletions code/datums/traits/_defines.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Helpers for shorter trait code
///Check if mob currently has a trait set; also works for traits with associated_list set.
#define HAS_TRAIT(MOB, TRAIT) MOB.HasTrait(TRAIT)
///Checks for minimum severity level with associated trait. Does not work for traits that have an metaoptions set.
#define HAS_TRAIT_LEVEL(MOB, TRAIT, LEVEL) (M.GetTraitLevel(TRAIT) >= LEVEL)
///Gets severity level with associated trait. Does not work for traits that have an metaoptions set.
#define GET_TRAIT_LEVEL(MOB, TRAIT) M.GetTraitLevel(TRAIT)
#define IS_METABOLICALLY_INERT(MOB) HAS_TRAIT(MOB, /singleton/trait/general/metabolically_inert) // This define exists only due to how common this check is
#define METABOLIC_INERTNESS(MOB) GET_TRAIT_LEVEL(MOB, /singleton/trait/general/metabolically_inert) // See above
38 changes: 38 additions & 0 deletions code/datums/traits/maluses/allergy.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/singleton/trait/malus/allergy
name = "Allergy"
levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MAJOR)
///Used to select which reagent mob is allergic to.
metaoptions = list(
/datum/reagent/antidexafen,
/datum/reagent/bicaridine,
/datum/reagent/citalopram,
/datum/reagent/dermaline,
/datum/reagent/drink/juice/apple,
/datum/reagent/drink/juice/berry,
/datum/reagent/drink/juice/garlic,
/datum/reagent/drink/juice/orange,
/datum/reagent/drink/kefir,
/datum/reagent/drink/thoom,
/datum/reagent/drugs/psilocybin,
/datum/reagent/drugs/three_eye,
/datum/reagent/ethanol/creme_de_menthe,
/datum/reagent/ethanol/gin,
/datum/reagent/ethanol/tequilla,
/datum/reagent/ethanol/vodka,
/datum/reagent/hyperzine,
/datum/reagent/kelotane,
/datum/reagent/nanoblood,
/datum/reagent/paracetamol,
/datum/reagent/paroxetine,
/datum/reagent/peridaxon,
/datum/reagent/spaceacillin,
/datum/reagent/tramadol,
/datum/reagent/tramadol/oxycodone,
/datum/reagent/tricordrazine,
/datum/reagent/toxin/amatoxin,
/datum/reagent/toxin/carpotoxin,
/datum/reagent/toxin/venom
)
addprompt = "Select reagent to make mob allergic to."
remprompt = "Select reagent to remove allergy to."
selectable = TRUE
2 changes: 1 addition & 1 deletion code/datums/traits/maluses/animal_protein.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/singleton/trait/malus/animal_protein
name = "Animal Protein Allergy"
name = "Animal Protein Intolerance"
levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MAJOR)
2 changes: 1 addition & 1 deletion code/datums/traits/maluses/ethanol.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/singleton/trait/malus/ethanol
name = "Ethanol Allergy"
name = "Ethanol Intolerance"
levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MODERATE, TRAIT_LEVEL_MAJOR)
2 changes: 1 addition & 1 deletion code/datums/traits/maluses/sugar.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/singleton/trait/malus/sugar
name = "Sugar Allergy"
name = "Sugar Intolerance"
levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MAJOR)
3 changes: 1 addition & 2 deletions code/datums/traits/maluses/water.dm
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/singleton/trait/malus/water
name = "Water Allergy"
description = "Also known as aquagenic urticaria."
name = "Water Intolerance"
levels = list(TRAIT_LEVEL_MINOR, TRAIT_LEVEL_MODERATE, TRAIT_LEVEL_MAJOR)
131 changes: 111 additions & 20 deletions code/datums/traits/traits.dm
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@

/mob/living/proc/HasTrait(trait_type)
SHOULD_NOT_OVERRIDE(TRUE)
SHOULD_NOT_SLEEP(TRUE)
return (trait_type in GetTraits())

/mob/living/proc/GetTraitLevel(trait_type)
/mob/living/proc/GetTraitLevel(trait_type, meta_option)
SHOULD_NOT_OVERRIDE(TRUE)
SHOULD_NOT_SLEEP(TRUE)
var/singleton/trait/trait = GET_SINGLETON(trait_type)
var/traits = GetTraits()
if(!traits)
return null
return traits[trait_type]

if (length(trait.metaoptions))
if (!meta_option)
return
var/list/interim = traits[trait_type]
return interim[meta_option]

else return traits[trait_type]

/mob/living/proc/GetTraits()
SHOULD_NOT_SLEEP(TRUE)
Expand All @@ -21,24 +30,44 @@
return traits
return species.traits

/mob/living/proc/SetTrait(trait_type, trait_level)
/mob/living/proc/GetMetaOptions(trait_type)
RETURN_TYPE(/list)
if (!HasTrait(trait_type))
return
var/singleton/trait/trait = GET_SINGLETON(trait_type)
if (!trait.metaoptions)
return

return traits[trait_type]

/mob/living/proc/SetTrait(trait_type, trait_level, meta_option)
SHOULD_NOT_SLEEP(TRUE)
var/singleton/trait/T = GET_SINGLETON(trait_type)
if(!T.Validate(trait_level))
var/singleton/trait/trait = GET_SINGLETON(trait_type)
if(!trait.Validate(trait_level, meta_option))
return FALSE

if (!LAZYISIN(traits, trait_type))
for (var/existing_trait_types in traits)
var/singleton/trait/ET = GET_SINGLETON(existing_trait_types)
if (trait_type in ET.incompatible_traits)
return FALSE

LAZYSET(traits, trait_type, trait_level)
for (var/existing_trait_types in traits)
var/singleton/trait/existing = GET_SINGLETON(existing_trait_types)
if (LAZYISIN(existing.incompatible_traits, trait_type) || LAZYISIN(trait.incompatible_traits, existing_trait_types))
return FALSE

if (length(trait.metaoptions))
var/list/interim = list()
if (!LAZYISIN(traits, trait_type))
LAZYSET(traits, trait_type, interim)

var/list/existing_meta_options = traits[trait_type]
if (existing_meta_options[meta_option] == trait_level)
return FALSE
LAZYSET(existing_meta_options, meta_option, trait_level)
LAZYSET(traits, trait_type, existing_meta_options)
else
LAZYSET(traits, trait_type, trait_level)
return TRUE

/mob/living/carbon/human/SetTrait(trait_type, trait_level)
/mob/living/carbon/human/SetTrait(trait_type, trait_level, additional_option)
var/singleton/trait/T = GET_SINGLETON(trait_type)
if(!T.Validate(trait_level))
if(!T.Validate(trait_level, additional_option))
return FALSE

if(!traits) // If traits haven't been setup before, check if we need to do so now
Expand All @@ -47,35 +76,97 @@
return TRUE
traits = species.traits.Copy() // The setup is to simply copy the species list of traits

return ..(trait_type, trait_level)
return ..(trait_type, trait_level, additional_option)

/mob/living/proc/RemoveTrait(trait_type)
/mob/living/proc/RemoveTrait(trait_type, additional_option)
if (additional_option)
var/list/interim = traits[trait_type]
LAZYREMOVE(interim, additional_option)
if (length(interim)) //If there remains other associations with the singleton, stop removing. Else; also remove the singleton.
return
LAZYREMOVE(traits, trait_type)

/mob/living/carbon/human/RemoveTrait(trait_type)
/mob/living/carbon/human/RemoveTrait(trait_type, additional_option)
// If traits haven't been setup, but we're trying to remove a trait that exists on the species then setup traits
if(!traits && (trait_type in species.traits))
traits = species.traits.Copy()

..(trait_type) // Could go through the trouble of nulling the traits list if it's again equal to the species list but eh
..(trait_type, additional_option) // Could go through the trouble of nulling the traits list if it's again equal to the species list but eh
traits = traits || list() // But we do ensure that humans don't null their traits list, to avoid copying from species again

/proc/LetterizeSeverity(severity)
switch (severity)
if (TRAIT_LEVEL_EXISTS)
severity = "Exists"
if (TRAIT_LEVEL_MINOR)
severity = "Minor"
if (TRAIT_LEVEL_MODERATE)
severity = "Moderate"
if (TRAIT_LEVEL_MAJOR)
severity = "Severe"
else
crash_with("Inappopriate arguments fed into proc.")
return severity

/proc/sanitize_trait_prefs(list/preferences)
RETURN_TYPE(/list)
var/list/final_preferences = list()
if (isnull(preferences))
return list()
if (!islist(preferences))
crash_with("Inappropriate argument fed into proc.")
return
if (!length(preferences))
return list()

for (var/trait in preferences)
var/trait_type = istext(trait) ? text2path(trait) : trait
var/singleton/trait/selected = GET_SINGLETON(trait_type)
var/severity
if (length(selected.metaoptions))
var/list/interim = preferences[trait]
var/list/final_interim = list()
for (var/metaoption in interim)
var/metaoption_type = istext(metaoption) ? text2path(metaoption) : metaoption
severity = interim[metaoption]
LAZYSET(final_interim, metaoption_type, severity)
LAZYSET(final_preferences, trait_type, final_interim)

else
severity = preferences[trait]
LAZYSET(final_preferences, trait_type, severity)
return final_preferences

/singleton/trait
var/name
var/description
/// Should either only contain TRAIT_LEVEL_EXISTS or a set of the other TRAIT_LEVEL_* levels
var/list/levels = list(TRAIT_LEVEL_EXISTS)
/// Additional list with unique paths to associate singleton with. if needed. Currently used for reagents in allergies only.
var/list/metaoptions = list()
///Prompts seen when adding/removing additional traits; only for traits with metaoptions set
var/addprompt = "Select a property to add."
var/remprompt = "Select a property to remove."

/// These trait types may not co-exist on the same mob/species
var/list/incompatible_traits
abstract_type = /singleton/trait

///List of species in which this trait is forbidden.
var/list/forbidden_species = list()
///Determines if trait can be selected in character setup
var/selectable = FALSE

/singleton/trait/New()
if(type == abstract_type)
CRASH("Invalid initialization")

/singleton/trait/proc/Validate(level)
/singleton/trait/proc/Validate(level, meta_option)
SHOULD_NOT_OVERRIDE(TRUE)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)

return (level in levels)
if (length(metaoptions))
return (level in levels) && (meta_option in metaoptions)
else
return (level in levels)
5 changes: 5 additions & 0 deletions code/game/objects/items/weapons/storage/med_pouch.dm
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,8 @@ Single Use Emergency Pouches
/obj/item/reagent_containers/hypospray/autoinjector/pouch_auto/adrenaline
name = "emergency adrenaline autoinjector"
starts_with = list(/datum/reagent/adrenaline = 5)

/obj/item/reagent_containers/hypospray/autoinjector/pouch_auto/allergy
name = "emergency allergy autoinjector"
desc = "The ingredient label reads 1.5 units of epinephrine and 3.5 units of inaprovaline."
starts_with = list(/datum/reagent/adrenaline = 1.5, /datum/reagent/inaprovaline = 3.5)
2 changes: 2 additions & 0 deletions code/modules/admin/view_variables/helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
<option value='?_src_=vars;addaura=\ref[src]'>Add Aura</option>
<option value='?_src_=vars;removeaura=\ref[src]'>Remove Aura</option>
<option value='?_src_=vars;debug_mob_ai=\ref[src]'>Toggle AI Debug Output</option>
<option value='?_src_=vars;settrait=\ref[src]'>Set Trait</option>
<option value='?_src_=vars;removetrait=\ref[src]'>Remove Trait</option>
"}

/mob/living/carbon/human/get_view_variables_options()
Expand Down
64 changes: 64 additions & 0 deletions code/modules/admin/view_variables/topic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,70 @@
var/mob/living/L = locate(href_list["debug_mob_ai"])
log_debug("AI Debugging toggled [L.ai_holder.debug() ? "ON" : "OFF"] for \the [L]")

else if (href_list["settrait"])
if (!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return
var/mob/living/target = locate(href_list["settrait"])
if (!istype(target))
to_chat(usr, SPAN_WARNING("This can only be done to instances of /mob/living."))
return

var/list/trait_list = GET_SINGLETON_SUBTYPE_LIST(/singleton/trait)
var/singleton/trait/selected = input("Select a trait to apply to \the [target].", "Add Trait") as null | anything in trait_list

if (!selected || !istype(selected) || QDELETED(target))
return

var/selected_level
if (length(selected.levels) > 1)
var/list/letterized_levels = list()
for (var/severity in selected.levels)
LAZYSET(letterized_levels, LetterizeSeverity(severity), severity)
var/letter_level = input("Select the trait's level to apply to \the [target].", "Select Level") as null | anything in letterized_levels
selected_level = letterized_levels[letter_level]
else
selected_level = selected.levels[1]

if (QDELETED(target))
return

var/additional_data
if (length(selected.metaoptions))
var/list/sanitized_metaoptions
for (var/atom/option as anything in selected.metaoptions)
var/named_option = initial(option.name)
LAZYSET(sanitized_metaoptions, named_option, option)
var/sanitized_additional = input("[selected.addprompt]", "Select Option") as null | anything in sanitized_metaoptions
additional_data = sanitized_metaoptions[sanitized_additional]

if (target.SetTrait(selected.type, selected_level, additional_data))
to_chat(usr, SPAN_NOTICE("Successfuly set \the [selected.name] in \the [target]."))
else
to_chat(usr, SPAN_WARNING("Failed to set \the [selected.name] in \the [target]."))
return

else if (href_list["removetrait"])
if (!check_rights(R_DEBUG|R_ADMIN|R_FUN)) return
var/mob/living/target = locate(href_list["removetrait"])
if (!istype(target))
to_chat(usr, SPAN_WARNING("This can only be done to instances of /mob/living."))
return
var/input = input("Select a trait to remove from \the [target].", "Remove Trait") as null | anything in target.traits
var/singleton/trait/selected = GET_SINGLETON(input)
if (!selected || !istype(selected) || QDELETED(target))
return

var/additional_option
if (length(selected.metaoptions))
var/list/interim = target.traits[selected.type]
additional_option = input("[selected.remprompt]", "Select Option") as null | anything in interim
if (!additional_option)
return

target.RemoveTrait(selected.type, additional_option)
to_chat(usr, SPAN_NOTICE("Successfuly removed \the [selected.name] in \the [target]."))
return


else if (href_list["addmovementhandler"])
if (!check_rights(R_DEBUG))
return
Expand Down
Loading

0 comments on commit f99ac23

Please sign in to comment.