From 02b9445b9bf6d4615e3ffbeb3611101ebb72ca2f Mon Sep 17 00:00:00 2001 From: Fox McCloud Date: Sun, 21 Feb 2021 16:25:19 -0500 Subject: [PATCH] Refactors DNA Mutations; Refactors Mutations to use Traits (#15483) * Refactors Mutations * traits * more work * styling fix * yet even more work * oh hush * almost there * it continues yet further * and that's genetics done * and that's it folks * last bit and golem fixup * oof * oops * tweaks and fixes * styling --- code/__DEFINES/combat.dm | 18 +- code/__DEFINES/flags.dm | 4 - code/__DEFINES/genetics.dm | 81 +- code/__DEFINES/is_helpers.dm | 2 + code/__DEFINES/reagents.dm | 5 + code/__HELPERS/traits.dm | 122 +- code/_globalvars/traits.dm | 54 +- code/_onclick/other_mobs.dm | 6 +- code/_onclick/telekinesis.dm | 6 +- code/controllers/subsystem/jobs.dm | 2 +- code/datums/components/caltrop.dm | 2 +- code/datums/diseases/_MobProcs.dm | 7 +- .../diseases/advance/symptoms/deafness.dm | 14 +- .../diseases/advance/symptoms/vision.dm | 5 +- code/datums/diseases/critical.dm | 2 +- code/datums/dog_fashion.dm | 2 +- code/datums/elements/earhealing.dm | 36 + code/datums/mind.dm | 2 +- code/datums/outfits/outfit_admin.dm | 2 +- code/datums/spells/banana_touch.dm | 4 +- code/datums/spells/cluwne.dm | 18 +- code/datums/spells/genetic.dm | 53 +- code/datums/spells/mime_malaise.dm | 2 +- code/datums/spells/wizard.dm | 15 +- code/datums/status_effects/buffs.dm | 8 +- .../weather/weather_types/radiation_storm.dm | 4 +- code/datums/wires/wires.dm | 2 +- code/game/atoms.dm | 2 +- code/game/data_huds.dm | 6 +- code/game/dna/dna2.dm | 12 +- code/game/dna/dna2_domutcheck.dm | 53 +- code/game/dna/dna2_helpers.dm | 2 +- code/game/dna/dna_modifier.dm | 18 +- code/game/dna/genes/disabilities.dm | 261 ---- code/game/dna/genes/gene.dm | 126 -- code/game/dna/genes/goon_disabilities.dm | 292 ---- code/game/dna/genes/goon_powers.dm | 620 --------- code/game/dna/genes/powers.dm | 200 --- code/game/dna/genes/vg_disabilities.dm | 42 - code/game/dna/genes/vg_powers.dm | 408 ------ code/game/dna/mutations/_mutations.dm | 74 ++ code/game/dna/mutations/disabilities.dm | 549 ++++++++ code/game/dna/{genes => mutations}/monkey.dm | 10 +- code/game/dna/mutations/powers.dm | 1181 +++++++++++++++++ code/game/gamemodes/changeling/changeling.dm | 12 +- .../gamemodes/changeling/changeling_power.dm | 2 +- .../gamemodes/changeling/evolution_menu.dm | 2 +- .../changeling/powers/augmented_eyesight.dm | 2 +- .../changeling/powers/chameleon_skin.dm | 6 +- .../gamemodes/changeling/powers/fakedeath.dm | 4 +- .../gamemodes/changeling/powers/humanform.dm | 4 +- .../gamemodes/changeling/powers/revive.dm | 6 +- .../gamemodes/changeling/powers/shriek.dm | 2 +- .../changeling/powers/strained_muscles.dm | 6 +- .../gamemodes/changeling/powers/swap_form.dm | 4 +- .../gamemodes/changeling/powers/tiny_prick.dm | 6 +- code/game/gamemodes/cult/cult.dm | 6 +- code/game/gamemodes/cult/cult_actions.dm | 2 +- code/game/gamemodes/cult/cult_items.dm | 6 +- code/game/gamemodes/cult/cult_structures.dm | 2 +- code/game/gamemodes/devil/game_mode.dm | 3 +- .../gamemodes/miniantags/abduction/gland.dm | 4 +- .../miniantags/guardian/types/lightning.dm | 7 +- code/game/gamemodes/objective.dm | 4 +- code/game/gamemodes/revolution/revolution.dm | 3 +- code/game/gamemodes/setupgame.dm | 22 +- code/game/gamemodes/shadowling/shadowling.dm | 3 +- code/game/gamemodes/vampire/vampire.dm | 3 +- code/game/gamemodes/vampire/vampire_powers.dm | 2 +- code/game/gamemodes/wizard/artefact.dm | 35 +- code/game/gamemodes/wizard/spellbook.dm | 10 - code/game/jobs/job/security.dm | 3 +- code/game/jobs/job/support.dm | 12 +- code/game/machinery/adv_med.dm | 12 +- code/game/machinery/cloning.dm | 2 +- code/game/machinery/computer/Operating.dm | 2 +- code/game/machinery/computer/cloning.dm | 6 +- code/game/machinery/mass_driver.dm | 2 +- code/game/machinery/poolcontroller.dm | 4 +- code/game/machinery/transformer.dm | 6 +- code/game/mecha/equipment/weapons/weapons.dm | 2 +- code/game/mecha/mecha.dm | 2 +- code/game/objects/effects/mines.dm | 12 +- code/game/objects/items/devices/flash.dm | 2 +- code/game/objects/items/devices/flashlight.dm | 6 +- .../objects/items/devices/laserpointer.dm | 8 +- code/game/objects/items/devices/megaphone.dm | 2 +- code/game/objects/items/devices/scanners.dm | 14 +- code/game/objects/items/tools/screwdriver.dm | 2 +- code/game/objects/items/weapons/batons.dm | 2 +- code/game/objects/items/weapons/defib.dm | 4 +- .../objects/items/weapons/dna_injector.dm | 11 +- .../objects/items/weapons/dnascrambler.dm | 8 +- .../items/weapons/grenades/flashbang.dm | 3 +- .../objects/items/weapons/grenades/grenade.dm | 2 +- code/game/objects/items/weapons/handcuffs.dm | 2 +- code/game/objects/items/weapons/kitchen.dm | 2 +- .../objects/items/weapons/melee/energy.dm | 4 +- .../objects/items/weapons/pneumaticCannon.dm | 2 +- code/game/objects/items/weapons/shards.dm | 2 +- code/game/objects/items/weapons/shields.dm | 2 +- .../objects/items/weapons/storage/bible.dm | 2 +- .../items/weapons/storage/briefcase.dm | 2 +- code/game/objects/items/weapons/stunbaton.dm | 2 +- code/game/objects/items/weapons/teleprod.dm | 2 +- code/game/objects/items/weapons/twohanded.dm | 6 +- .../crates_lockers/closets/statue.dm | 4 +- code/game/objects/structures/mirror.dm | 4 +- code/game/verbs/suicide.dm | 2 +- code/modules/admin/admin.dm | 2 +- code/modules/admin/topic.dm | 14 +- code/modules/admin/verbs/debug.dm | 8 +- code/modules/admin/verbs/honksquad.dm | 3 +- .../antagonists/traitor/datum_mindslave.dm | 6 +- .../antagonists/traitor/datum_traitor.dm | 6 +- .../antagonists/wishgranter/wishgranter.dm | 36 +- code/modules/assembly/mousetrap.dm | 8 +- code/modules/awaymissions/corpse.dm | 4 +- .../awaymissions/mission_code/wildwest.dm | 8 +- code/modules/client/preference/preferences.dm | 4 +- code/modules/clothing/clothing.dm | 2 +- code/modules/clothing/ears/ears.dm | 14 +- code/modules/clothing/glasses/glasses.dm | 26 +- .../clothing/under/accessories/accessory.dm | 2 +- code/modules/events/mass_hallucination.dm | 2 +- .../drinks/drinks/shotglass.dm | 6 +- code/modules/hydroponics/grown/nettle.dm | 2 +- code/modules/hydroponics/grown/replicapod.dm | 2 +- code/modules/martial_arts/martial.dm | 2 +- .../mining/lavaland/loot/colossus_loot.dm | 6 +- code/modules/mob/living/carbon/alien/alien.dm | 2 +- .../living/carbon/alien/special/facehugger.dm | 43 +- code/modules/mob/living/carbon/carbon.dm | 16 +- code/modules/mob/living/carbon/human/death.dm | 70 +- code/modules/mob/living/carbon/human/emote.dm | 4 +- .../mob/living/carbon/human/examine.dm | 6 +- code/modules/mob/living/carbon/human/human.dm | 40 +- .../mob/living/carbon/human/human_damage.dm | 11 +- .../mob/living/carbon/human/human_defense.dm | 4 +- .../mob/living/carbon/human/human_organs.dm | 8 +- code/modules/mob/living/carbon/human/life.dm | 44 +- code/modules/mob/living/carbon/human/say.dm | 18 +- .../living/carbon/human/species/_species.dm | 57 +- .../living/carbon/human/species/abductor.dm | 3 +- .../mob/living/carbon/human/species/diona.dm | 23 +- .../mob/living/carbon/human/species/golem.dm | 32 +- .../mob/living/carbon/human/species/grey.dm | 13 +- .../living/carbon/human/species/machine.dm | 3 +- .../mob/living/carbon/human/species/monkey.dm | 13 +- .../living/carbon/human/species/nucleation.dm | 3 +- .../living/carbon/human/species/plasmaman.dm | 34 +- .../mob/living/carbon/human/species/shadow.dm | 3 +- .../living/carbon/human/species/shadowling.dm | 10 +- .../living/carbon/human/species/skeleton.dm | 18 +- .../mob/living/carbon/human/species/skrell.dm | 11 +- .../mob/living/carbon/human/species/slime.dm | 11 +- .../mob/living/carbon/human/species/unathi.dm | 2 +- .../mob/living/carbon/human/species/vox.dm | 17 +- .../mob/living/carbon/human/species/wryn.dm | 3 +- .../mob/living/carbon/human/status_procs.dm | 6 - .../mob/living/carbon/human/update_icons.dm | 32 +- .../mob/living/carbon/human/update_stat.dm | 2 +- code/modules/mob/living/carbon/superheroes.dm | 13 +- .../mob/living/carbon/update_status.dm | 4 +- code/modules/mob/living/damage_procs.dm | 7 +- code/modules/mob/living/life.dm | 2 +- code/modules/mob/living/living.dm | 10 +- code/modules/mob/living/living_defense.dm | 13 +- code/modules/mob/living/say.dm | 2 +- .../mob/living/silicon/robot/component.dm | 2 +- .../mob/living/simple_animal/bot/honkbot.dm | 2 +- .../mob/living/simple_animal/bot/medbot.dm | 2 +- .../mob/living/simple_animal/friendly/cat.dm | 5 +- .../mob/living/simple_animal/friendly/dog.dm | 2 +- .../mob/living/simple_animal/friendly/fox.dm | 5 +- .../living/simple_animal/friendly/mouse.dm | 6 +- .../simple_animal/hostile/floorcluwne.dm | 4 +- .../living/simple_animal/hostile/headslug.dm | 2 +- .../living/simple_animal/hostile/hellhound.dm | 2 +- .../simple_animal/hostile/mining/hivelord.dm | 7 +- .../mob/living/simple_animal/simple_animal.dm | 2 +- code/modules/mob/living/status_procs.dm | 121 +- code/modules/mob/living/update_status.dm | 10 +- code/modules/mob/mob_defines.dm | 5 +- code/modules/mob/status_procs.dm | 4 - code/modules/mob/transform_procs.dm | 2 +- code/modules/mob/typing_indicator.dm | 2 +- code/modules/paperwork/contract.dm | 6 +- code/modules/paperwork/paper.dm | 6 +- code/modules/paperwork/paperplane.dm | 2 +- code/modules/paperwork/ticketmachine.dm | 2 +- code/modules/power/lighting.dm | 4 +- code/modules/projectiles/gun.dm | 2 +- code/modules/projectiles/projectile/energy.dm | 2 +- .../modules/projectiles/projectile/special.dm | 37 - code/modules/reagents/chemistry/reagents.dm | 8 +- .../reagents/chemistry/reagents/admin.dm | 4 +- .../reagents/chemistry/reagents/drink_cold.dm | 4 +- .../reagents/chemistry/reagents/drinks.dm | 10 +- .../reagents/chemistry/reagents/drugs.dm | 10 +- .../reagents/chemistry/reagents/food.dm | 2 +- .../reagents/chemistry/reagents/medicine.dm | 19 +- .../reagents/chemistry/reagents/misc.dm | 4 +- .../reagents/chemistry/reagents/toxins.dm | 22 +- code/modules/recycling/disposal.dm | 2 +- .../ruins/lavalandruin_code/sin_ruins.dm | 2 +- code/modules/station_goals/dna_vault.dm | 12 +- code/modules/surgery/helpers.dm | 2 +- .../surgery/organs/augments_internal.dm | 8 + code/modules/surgery/organs/blood.dm | 8 +- code/modules/surgery/organs/body_egg.dm | 12 +- code/modules/surgery/organs/ears.dm | 52 +- code/modules/surgery/organs/eyes.dm | 24 +- code/modules/surgery/organs/lungs.dm | 11 +- code/modules/surgery/organs/organ.dm | 2 +- code/modules/surgery/organs/organ_external.dm | 2 +- code/modules/surgery/organs/organ_internal.dm | 23 +- code/modules/surgery/organs/pain.dm | 4 +- code/modules/surgery/organs/subtypes/xenos.dm | 2 + code/modules/surgery/surgery.dm | 2 +- code/modules/tgui/states.dm | 2 +- paradise.dme | 13 +- sound/weapons/flash_ring.ogg | Bin 0 -> 24325 bytes 223 files changed, 2908 insertions(+), 3049 deletions(-) create mode 100644 code/datums/elements/earhealing.dm delete mode 100644 code/game/dna/genes/disabilities.dm delete mode 100644 code/game/dna/genes/gene.dm delete mode 100644 code/game/dna/genes/goon_disabilities.dm delete mode 100644 code/game/dna/genes/goon_powers.dm delete mode 100644 code/game/dna/genes/powers.dm delete mode 100644 code/game/dna/genes/vg_disabilities.dm delete mode 100644 code/game/dna/genes/vg_powers.dm create mode 100644 code/game/dna/mutations/_mutations.dm create mode 100644 code/game/dna/mutations/disabilities.dm rename code/game/dna/{genes => mutations}/monkey.dm (86%) create mode 100644 code/game/dna/mutations/powers.dm create mode 100644 sound/weapons/flash_ring.ogg diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index b526047237b..5bda7374fba 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -32,18 +32,12 @@ #define OBLITERATION 32 //Bitflags defining which status effects could be or are inflicted on a mob -#define CANSTUN 1 -#define CANWEAKEN 2 -#define CANPARALYSE 4 -#define CANPUSH 8 -#define PASSEMOTES 16 //Mob has a cortical borer or holders inside of it that need to see emotes. -#define GOTTAGOFAST 32 -#define IGNORESLOWDOWN 128 -#define IGNORE_SPEED_CHANGES 256 -#define GOTTAGONOTSOFAST 512 //This is used for nukacola, mormal meth is a "1" speed up, nuka is 0.5 and they don't stack, feel free to use this one somewhere else -#define GODMODE 4096 -#define FAKEDEATH 8192 //Replaces stuff like changeling.changeling_fakedeath -#define XENO_HOST 16384 //Tracks whether we're gonna be a baby alien's mummy. +#define CANSTUN 1 +#define CANWEAKEN 2 +#define CANPARALYSE 4 +#define CANPUSH 8 +#define PASSEMOTES 16 //Mob has a cortical borer or holders inside of it that need to see emotes. +#define GODMODE 32 //Health Defines #define HEALTH_THRESHOLD_CRIT 0 diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 0abd008556d..e77c140e78f 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -35,10 +35,6 @@ #define INFORM_ADMINS_ON_RELOCATE_2 32 #define BANG_PROTECT_2 64 -// An item worn in the ear slot with HEALS_EARS will heal your ears each -// Life() tick, even if normally your ears would be too damaged to heal. -#define HEALS_EARS_2 128 - // A mob with OMNITONGUE has no restriction in the ability to speak // languages that they know. So even if they wouldn't normally be able to // through mob or tongue restrictions, this flag allows them to ignore diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index c982420ff2a..6f5aaaf2b93 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -25,60 +25,7 @@ // MUTATIONS /////////////////////////////////////// -// Generic mutations: -#define TK "telekenesis" -#define COLDRES "cold_resistance" -#define XRAY "xray" -#define HULK "hulk" -#define CLUMSY "clumsy" -#define FAT "fat" -#define HUSK "husk" -#define NOCLONE "noclone" -#define LASER "eyelaser" // harm intent - click anywhere to shoot lasers from eyes -#define WINGDINGS "wingdings" // Ayy lmao -#define SKELETON "skeleton" -#define BREATHLESS "breathless" // no breathing -#define REMOTE_VIEW "remove_view" // remote viewing -#define REGEN "regeneration" // health regen -#define RUN "increased_run" // no slowdown -#define REMOTE_TALK "remote_talk" // remote talking -#define MORPH "morph" // changing appearance -#define HEATRES "heat_resistance" // heat resistance -#define HALLUCINATE "hallucinate" // hallucinations -#define FINGERPRINTS "no_prints" // no fingerprints -#define NO_SHOCK "no_shock" // insulated hands -#define DWARF "dwarf" // table climbing -#define OBESITY "obesity" // Decreased metabolism -#define STRONG "strong" // (Nothing) -#define SOBER "sober" // Increased alcohol metabolism -#define PSY_RESIST "psy_resist" // Block remoteview -#define EMPATH "empathy" //Read minds -#define COMIC "comic_sans" //Comic Sans -#define LOUD "loudness" // CAUSES INTENSE YELLING -#define DIZZY "dizzy" // Trippy. -#define LISP "lisp" -#define RADIOACTIVE "radioactive" -#define CHAV "chav" -#define SWEDISH "swedish" -#define SCRAMBLED "scrambled" -#define HORNS "horns" -#define IMMOLATE "immolate" -#define CLOAK "cloak" -#define CHAMELEON "chameleon" -#define CRYO "cryokinesis" -#define EATER "matter_eater" -#define JUMPY "jumpy" -#define POLYMORPH "polymorph" -//disabilities -#define NEARSIGHTED "nearsighted" -#define EPILEPSY "epilepsy" -#define COUGHING "coughing" -#define TOURETTES "tourettes" -#define NERVOUS "nervous" -#define BLINDNESS "blind" -#define COLOURBLIND "colorblind" -#define MUTE "mute" -#define DEAF "deaf" + //Nutrition levels for humans. No idea where else to put it #define NUTRITION_LEVEL_FAT 600 @@ -126,28 +73,12 @@ #define CLONER_MATURE_CLONE "mature" //Species traits. - +#define NO_BLOOD "no_blood" +#define NOTRANSSTING "no_trans_sting" #define IS_WHITELISTED "whitelisted" #define LIPS "lips" -#define NO_BLOOD "no_blood" -#define NO_BREATHE "no_breathe" -#define NO_DNA "no_dna" -#define NO_SCAN "no_scan" -#define NO_PAIN "no_pain" -#define IS_PLANT "is_plant" +#define EXOTIC_COLOR "exotic_blood_color" #define NO_INTORGANS "no_internal_organs" -#define RADIMMUNE "rad_immunity" -#define NOGUNS "no_guns" -#define NOTRANSSTING "no_trans_sting" -#define VIRUSIMMUNE "virus_immunity" -#define NOCRITDAMAGE "no_crit" -#define RESISTHOT "resist_heat" -#define RESISTCOLD "resist_cold" -#define NO_EXAMINE "no_examine" #define CAN_WINGDINGS "can_wingdings" -#define NO_GERMS "no_germs" -#define NO_DECAY "no_decay" -#define PIERCEIMMUNE "pierce_immunity" -#define NO_HUNGER "no_hunger" -#define EXOTIC_COLOR "exotic_blood_colour" -#define NO_OBESITY "no_obesity" +#define NO_CLONESCAN "no_clone_scan" +#define IS_PLANT "is_plant" // Convert this to a biotype TODO diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 5ce2a107a08..a7f14a0ffe1 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -24,6 +24,8 @@ #define is_cleanable(A) (istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/rune)) //if something is cleanable +#define isclothing(A) (istype(A, /obj/item/clothing)) + #define is_pen(W) (istype(W, /obj/item/pen)) GLOBAL_LIST_INIT(pointed_types, typecacheof(list( diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index 564247455e3..eade54a1f05 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -19,3 +19,8 @@ #define REAGENT_TOUCH 1 #define REAGENT_INGEST 2 + +///Health threshold for synthflesh and rezadone to unhusk someone +#define UNHUSK_DAMAGE_THRESHOLD 50 +///Amount of synthflesh required to unhusk someone +#define SYNTHFLESH_UNHUSK_AMOUNT 100 diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm index 4cd02401b43..ef22a8101a2 100644 --- a/code/__HELPERS/traits.dm +++ b/code/__HELPERS/traits.dm @@ -1,3 +1,6 @@ +#define SIGNAL_ADDTRAIT(trait_ref) "addtrait [trait_ref]" +#define SIGNAL_REMOVETRAIT(trait_ref) "removetrait [trait_ref]" + // trait accessor defines #define ADD_TRAIT(target, trait, source) \ do { \ @@ -6,12 +9,14 @@ target.status_traits = list(); \ _L = target.status_traits; \ _L[trait] = list(source); \ + SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \ } else { \ _L = target.status_traits; \ if (_L[trait]) { \ _L[trait] |= list(source); \ } else { \ _L[trait] = list(source); \ + SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \ } \ } \ } while (0) @@ -31,7 +36,8 @@ } \ };\ if (!length(_L[trait])) { \ - _L -= trait \ + _L -= trait; \ + SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \ }; \ if (!length(_L)) { \ target.status_traits = null \ @@ -46,31 +52,131 @@ for (var/_T in _L) { \ _L[_T] &= _S;\ if (!length(_L[_T])) { \ - _L -= _T } \ - };\ - if (!length(_L)) { \ - target.status_traits = null\ + _L -= _T; \ + SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T), _T); \ + }; \ };\ + if (!length(_L)) { \ + target.status_traits = null\ + };\ }\ } while (0) + +#define REMOVE_TRAITS_IN(target, sources) \ + do { \ + var/list/_L = target.status_traits; \ + var/list/_S = sources; \ + if (sources && !islist(sources)) { \ + _S = list(sources); \ + } else { \ + _S = sources\ + }; \ + if (_L) { \ + for (var/_T in _L) { \ + _L[_T] -= _S;\ + if (!length(_L[_T])) { \ + _L -= _T; \ + SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T)); \ + }; \ + };\ + if (!length(_L)) { \ + target.status_traits = null\ + };\ + }\ + } while (0) + #define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE) #define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE) +#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\ + target.status_traits ?\ + (target.status_traits[trait] ?\ + ((source in target.status_traits[trait]) && (length(target.status_traits) == 1))\ + : FALSE)\ + : FALSE) +#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE) /* Remember to update _globalvars/traits.dm if you're adding/removing/renaming traits. */ //mob traits +#define TRAIT_BLIND "blind" +#define TRAIT_MUTE "mute" +#define TRAIT_DEAF "deaf" +#define TRAIT_NEARSIGHT "nearsighted" +#define TRAIT_FAT "fat" +#define TRAIT_HUSK "husk" +#define TRAIT_BADDNA "baddna" +#define TRAIT_SKELETONIZED "skeletonized" +#define TRAIT_CLUMSY "clumsy" +#define TRAIT_CHUNKYFINGERS "chunkyfingers" //means that you can't use weapons with normal trigger guards. #define TRAIT_PACIFISM "pacifism" -#define TRAIT_WATERBREATH "waterbreathing" +#define TRAIT_IGNORESLOWDOWN "ignoreslow" +#define TRAIT_IGNOREDAMAGESLOWDOWN "ignoredamageslowdown" +#define TRAIT_GOTTAGOFAST "gottagofast" +#define TRAIT_GOTTAGONOTSOFAST "gottagonotsofast" +#define TRAIT_FAKEDEATH "fakedeath" //Makes the owner appear as dead to most forms of medical examination +#define TRAIT_XENO_HOST "xeno_host" //Tracks whether we're gonna be a baby alien's mummy. +#define TRAIT_SHOCKIMMUNE "shock_immunity" +#define TRAIT_TESLA_SHOCKIMMUNE "tesla_shock_immunity" +#define TRAIT_RESISTHEAT "resist_heat" +#define TRAIT_RESISTHEATHANDS "resist_heat_handsonly" //For when you want to be able to touch hot things, but still want fire to be an issue. +#define TRAIT_RESISTCOLD "resist_cold" +#define TRAIT_RESISTHIGHPRESSURE "resist_high_pressure" +#define TRAIT_RESISTLOWPRESSURE "resist_low_pressure" +#define TRAIT_RADIMMUNE "rad_immunity" +#define TRAIT_GENELESS "geneless" +#define TRAIT_VIRUSIMMUNE "virus_immunity" +#define TRAIT_PIERCEIMMUNE "pierce_immunity" +#define TRAIT_NOFIRE "nonflammable" +#define TRAIT_NOHUNGER "no_hunger" +#define TRAIT_NOBREATH "no_breath" +#define TRAIT_NOCRITDAMAGE "no_crit" +#define TRAIT_XRAY_VISION "xray_vision" +#define TRAIT_THERMAL_VISION "thermal_vision" +#define TRAIT_XENO_IMMUNE "xeno_immune" //prevents xeno huggies implanting skeletons #define TRAIT_BLOODCRAWL "bloodcrawl" #define TRAIT_BLOODCRAWL_EAT "bloodcrawl_eat" -#define TRAIT_JESTER "jester" -#define TRAIT_TESLA_SHOCKIMMUNE "tesla_shock_immunity" +#define TRAIT_DWARF "dwarf" + +#define TRAIT_COMIC_SANS "comic_sans" +#define TRAIT_NOFINGERPRINTS "no_fingerprints" +#define TRAIT_SLOWDIGESTION "slow_digestion" +#define TRAIT_COLORBLIND "colorblind" +#define TRAIT_WINGDINGS "wingdings" +#define TRAIT_WATERBREATH "waterbreathing" +#define TRAIT_NOFAT "no_fatness" +#define TRAIT_NOGERMS "no_germs" +#define TRAIT_NODECAY "no_decay" +#define TRAIT_NOEXAMINE "no_examine" +#define TRAIT_NOPAIN "no_pain" + // // common trait sources +#define TRAIT_GENERIC "generic" +#define EYE_DAMAGE "eye_damage" +#define EAR_DAMAGE "ear_damage" +#define GENETIC_MUTATION "genetic" +#define OBESITY "obesity" +#define MAGIC_TRAIT "magic" +#define SPECIES_TRAIT "species" #define ROUNDSTART_TRAIT "roundstart" //cannot be removed without admin intervention +#define CLOTHING_TRAIT "clothing" #define CULT_TRAIT "cult" +#define INNATE_TRAIT "innate" // unique trait sources +#define STATUE_MUTE "statue" +#define CHANGELING_DRAIN "drain" +#define TRAIT_HULK "hulk" +#define STASIS_MUTE "stasis" +#define SCRYING_ORB "scrying-orb" #define CULT_EYES "cult_eyes" +#define DOGGO_SPACESUIT "doggo_spacesuit" +#define FLOORCLUWNE "floorcluwne" + +//quirk traits +#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" + +//traits that should be properly converted to genetic mutations one day +#define TRAIT_LASEREYES "laser_eyes" diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 820d65f1970..e91ea9b8e70 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -5,11 +5,57 @@ */ GLOBAL_LIST_INIT(traits_by_type, list( /mob = list( + "TRAIT_BLIND" = TRAIT_BLIND, + "TRAIT_MUTE" = TRAIT_MUTE, + "TRAIT_DEAF" = TRAIT_DEAF, + "TRAIT_NEARSIGHT" = TRAIT_NEARSIGHT, + "TRAIT_FAT" = TRAIT_FAT, + "TRAIT_HUSK" = TRAIT_HUSK, + "TRAIT_BADDNA" = TRAIT_BADDNA, + "TRAIT_SKELETONIZED" = TRAIT_SKELETONIZED, + "TRAIT_CLUMSY" = TRAIT_CLUMSY, + "TRAIT_CHUNKYFINGERS" = TRAIT_CHUNKYFINGERS, "TRAIT_PACIFISM" = TRAIT_PACIFISM, - "TRAIT_WATERBREATH" = TRAIT_WATERBREATH, - "BLOODCRAWL" = TRAIT_BLOODCRAWL, - "BLOODCRAWL_EAT" = TRAIT_BLOODCRAWL_EAT, - "TRAIT_TESLA_SHOCKIMMUNE" = TRAIT_TESLA_SHOCKIMMUNE))) + "TRAIT_IGNORESLOWDOWN" = TRAIT_IGNORESLOWDOWN, + "TRAIT_IGNOREDAMAGESLOWDOWN" = TRAIT_IGNOREDAMAGESLOWDOWN, + "TRAIT_GOTTAGOFAST" = TRAIT_GOTTAGOFAST, + "TRAIT_GOTTAGONOTSOFAST" = TRAIT_GOTTAGONOTSOFAST, + "TRAIT_FAKEDEATH" = TRAIT_FAKEDEATH, + "TRAIT_XENO_HOST" = TRAIT_XENO_HOST, + "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, + "TRAIT_TESLA_SHOCKIMMUNE" = TRAIT_TESLA_SHOCKIMMUNE, + "TRAIT_RESISTHEAT" = TRAIT_RESISTHEAT, + "TRAIT_RESISTHEATHANDS" = TRAIT_RESISTHEATHANDS, + "TRAIT_RESISTCOLD" = TRAIT_RESISTCOLD, + "TRAIT_RESISTHIGHPRESSURE" = TRAIT_RESISTHIGHPRESSURE, + "TRAIT_RESISTLOWPRESSURE" = TRAIT_RESISTLOWPRESSURE, + "TRAIT_RADIMMUNE" = TRAIT_RADIMMUNE, + "TRAIT_GENELESS" = TRAIT_GENELESS, + "TRAIT_VIRUSIMMUNE" = TRAIT_VIRUSIMMUNE, + "TRAIT_PIERCEIMMUNE" = TRAIT_PIERCEIMMUNE, + "TRAIT_NOFIRE" = TRAIT_NOFIRE, + "TRAIT_NOHUNGER" = TRAIT_NOHUNGER, + "TRAIT_NOBREATH" = TRAIT_NOBREATH, + "TRAIT_NOCRITDAMAGE" = TRAIT_NOCRITDAMAGE, + "TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION, + "TRAIT_THERMAL_VISION" = TRAIT_THERMAL_VISION, + "TRAIT_XENO_IMMUNE" = TRAIT_XENO_IMMUNE, + "TRAIT_BLOODCRAWL" = TRAIT_BLOODCRAWL, + "TRAIT_BLOODCRAWL_EAT" = TRAIT_BLOODCRAWL_EAT, + "TRAIT_DWARF" = TRAIT_DWARF, + "TRAIT_ALCOHOL_TOLERANCE" = TRAIT_ALCOHOL_TOLERANCE, + + "TRAIT_COMIC_SANS" = TRAIT_COMIC_SANS, + "TRAIT_NOFINGERPRINTS" = TRAIT_NOFINGERPRINTS, + "TRAIT_SLOWDIGESTION" = TRAIT_SLOWDIGESTION, + "TRAIT_COLORBLIND" = TRAIT_COLORBLIND, + "TRAIT_WINGDINGS" = TRAIT_WINGDINGS, + "TRAIT_WATERBREATH" = TRAIT_WATERBREATH, + "TRAIT_NOFAT" = TRAIT_NOFAT, + "TRAIT_NOGERMS" = TRAIT_NOGERMS, + "TRAIT_NODECAY" = TRAIT_NODECAY, + "TRAIT_NOEXAMINE" = TRAIT_NOEXAMINE, + "TRAIT_NOPAIN" = TRAIT_NOPAIN))) /// value -> trait name, generated on use from trait_by_type global GLOBAL_LIST(trait_name_map) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 4497f170a2d..3720f9bdb2e 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -12,7 +12,7 @@ if(proximity && istype(G) && G.Touch(A, 1)) return - if(HULK in mutations) + if(HAS_TRAIT(src, TRAIT_HULK)) if(proximity) //no telekinetic hulk attack if(A.attack_hulk(src)) return @@ -42,10 +42,10 @@ if(istype(G) && G.Touch(A, 0)) // for magic gloves return - if((LASER in mutations) && a_intent == INTENT_HARM) + if(HAS_TRAIT(src, TRAIT_LASEREYES) && a_intent == INTENT_HARM) LaserEyes(A) - if(TK in mutations) + if(dna.GetSEState(GLOB.teleblock)) A.attack_tk(src) if(isturf(A) && get_dist(src, A) <= 1) diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index e684707d460..df9c8ea1fae 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -39,11 +39,11 @@ /obj/item/attack_tk(mob/user) if(user.stat || !isturf(loc)) return - if((TK in user.mutations) && !user.get_active_hand()) // both should already be true to get here + if(user.dna?.GetSEState(GLOB.teleblock) && !user.get_active_hand()) // both should already be true to get here var/obj/item/tk_grab/O = new(src) O.form_grab(user, src) else - warning("Strange attack_tk(): TK([TK in user.mutations]) empty hand([!user.get_active_hand()])") + warning("Strange attack_tk(): TK([user.dna?.GetSEState(GLOB.teleblock)]) empty hand([!user.get_active_hand()])") /mob/attack_tk(mob/user) @@ -109,7 +109,7 @@ if(!host || host != user) qdel(src) return - if(!(TK in host.mutations)) + if(!host.dna?.GetSEState(GLOB.teleblock)) qdel(src) return if(isobj(target) && !isturf(target.loc)) diff --git a/code/controllers/subsystem/jobs.dm b/code/controllers/subsystem/jobs.dm index f82964ad4e0..504f263247b 100644 --- a/code/controllers/subsystem/jobs.dm +++ b/code/controllers/subsystem/jobs.dm @@ -500,7 +500,7 @@ SUBSYSTEM_DEF(jobs) job.after_spawn(H) //Gives glasses to the vision impaired - if(NEARSIGHTED in H.mutations) + if(HAS_TRAIT(H, TRAIT_NEARSIGHT)) var/equipped = H.equip_to_slot_or_del(new /obj/item/clothing/glasses/regular(H), slot_glasses) if(equipped != 1) var/obj/item/clothing/glasses/G = H.glasses diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm index fc781b288a9..7d6848e6b5a 100644 --- a/code/datums/components/caltrop.dm +++ b/code/datums/components/caltrop.dm @@ -24,7 +24,7 @@ if(ishuman(AM)) var/mob/living/carbon/human/H = AM - if(PIERCEIMMUNE in H.dna.species.species_traits) + if(HAS_TRAIT(H, TRAIT_PIERCEIMMUNE)) return if((flags & CALTROP_IGNORE_WALKERS) && H.m_intent == MOVE_INTENT_WALK) diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index 81312cdfcc4..1d8596482b3 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -142,11 +142,12 @@ /mob/living/carbon/human/CanContractDisease(datum/disease/D) - if((VIRUSIMMUNE in dna.species.species_traits) && !D.bypasses_immunity) - return 0 + if(HAS_TRAIT(src, TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity) + return FALSE + for(var/thing in D.required_organs) if(!((locate(thing) in bodyparts) || (locate(thing) in internal_organs))) - return 0 + return FALSE return ..() /mob/living/carbon/human/monkey/CanContractDisease(datum/disease/D) diff --git a/code/datums/diseases/advance/symptoms/deafness.dm b/code/datums/diseases/advance/symptoms/deafness.dm index a3111478b26..1346b6afc26 100644 --- a/code/datums/diseases/advance/symptoms/deafness.dm +++ b/code/datums/diseases/advance/symptoms/deafness.dm @@ -16,7 +16,6 @@ Bonus */ /datum/symptom/deafness - name = "Deafness" stealth = -1 resistance = -2 @@ -29,15 +28,12 @@ Bonus ..() if(prob(SYMPTOM_ACTIVATION_PROB)) var/mob/living/M = A.affected_mob + var/obj/item/organ/internal/ears/ears = M.get_organ_slot("ears") + if(!ears) + return //cutting off your ears to cure the deafness: the ultimate own switch(A.stage) if(3, 4) to_chat(M, "[pick("You hear a ringing in your ear.", "Your ears pop.")]") if(5) - if(!(DEAF in M.mutations)) - to_chat(M, "Your ears pop and begin ringing loudly!") - M.BecomeDeaf() - spawn(200) - if(M) - to_chat(M, "The ringing in your ears fades...") - M.CureDeaf() - return + to_chat(M, "Your ears pop and begin ringing loudly!") + ears.deaf = min(20, ears.deaf + 15) diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm index 252eaf16ecc..4c854953745 100644 --- a/code/datums/diseases/advance/symptoms/vision.dm +++ b/code/datums/diseases/advance/symptoms/vision.dm @@ -44,7 +44,8 @@ Bonus M.EyeBlurry(30) eyes.receive_damage(5) if(eyes.damage >= 10) - M.BecomeNearsighted() + M.become_nearsighted(EYE_DAMAGE) if(prob(eyes.damage - 10 + 1)) - if(M.BecomeBlind()) + if(!M.eye_blind) to_chat(M, "You go blind!") + eyes.receive_damage(eyes.max_damage) diff --git a/code/datums/diseases/critical.dm b/code/datums/diseases/critical.dm index 436a4248076..575059e2150 100644 --- a/code/datums/diseases/critical.dm +++ b/code/datums/diseases/critical.dm @@ -157,7 +157,7 @@ /datum/disease/critical/hypoglycemia/has_cure() if(ishuman(affected_mob)) var/mob/living/carbon/human/H = affected_mob - if(NO_HUNGER in H.dna.species.species_traits) + if(HAS_TRAIT(H, TRAIT_NOHUNGER)) return TRUE if(ismachineperson(H)) return TRUE diff --git a/code/datums/dog_fashion.dm b/code/datums/dog_fashion.dm index 14705ae7375..ef3b76652ea 100644 --- a/code/datums/dog_fashion.dm +++ b/code/datums/dog_fashion.dm @@ -201,7 +201,7 @@ /datum/dog_fashion/back/hardsuit/apply(mob/living/simple_animal/pet/dog/D) ..() - D.mutations.Add(BREATHLESS) + ADD_TRAIT(D, TRAIT_NOBREATH, DOGGO_SPACESUIT) D.atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) D.minbodytemp = 0 diff --git a/code/datums/elements/earhealing.dm b/code/datums/elements/earhealing.dm new file mode 100644 index 00000000000..ee33cd9ee34 --- /dev/null +++ b/code/datums/elements/earhealing.dm @@ -0,0 +1,36 @@ +/datum/element/earhealing + element_flags = ELEMENT_DETACH + var/list/user_by_item = list() + +/datum/element/earhealing/New() + START_PROCESSING(SSdcs, src) + +/datum/element/earhealing/Attach(datum/target) + . = ..() + if(!isitem(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED), .proc/equippedChanged) + +/datum/element/earhealing/Detach(datum/target) + . = ..() + UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED)) + user_by_item -= target + +/datum/element/earhealing/proc/equippedChanged(datum/source, mob/living/carbon/user, slot) + SIGNAL_HANDLER + + if(((slot == slot_l_ear) || (slot == slot_r_ear)) && istype(user)) + user_by_item[source] = user + else + user_by_item -= source + +/datum/element/earhealing/process() + for(var/i in user_by_item) + var/mob/living/carbon/user = user_by_item[i] + var/obj/item/organ/internal/ears/ears = user.get_int_organ(/obj/item/organ/internal/ears) + if(!ears || HAS_TRAIT_NOT_FROM(user, TRAIT_DEAF, EAR_DAMAGE)) + continue + ears.deaf = max(ears.deaf - 0.25, (ears.ear_damage < 100 ? 0 : 1)) // Do not clear deafness if our ears are too damaged + ears.ear_damage = max(ears.ear_damage - 0.025, 0) + CHECK_TICK diff --git a/code/datums/mind.dm b/code/datums/mind.dm index ed4a9707952..a1f136daec6 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -976,7 +976,7 @@ current.dna = changeling.absorbed_dna[1] current.real_name = current.dna.real_name current.UpdateAppearance() - domutcheck(current, null) + domutcheck(current) log_admin("[key_name(usr)] has reset [key_name(current)]'s DNA") message_admins("[key_name_admin(usr)] has reset [key_name_admin(current)]'s DNA") diff --git a/code/datums/outfits/outfit_admin.dm b/code/datums/outfits/outfit_admin.dm index aca1ab9bcf3..f40d29df78c 100644 --- a/code/datums/outfits/outfit_admin.dm +++ b/code/datums/outfits/outfit_admin.dm @@ -1052,7 +1052,7 @@ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/raise_vampires) to_chat(H, "You have gained the ability to Raise Vampires. This extremely powerful AOE ability affects all humans near you. Vampires/thralls are healed. Corpses are raised as vampires. Others are stunned, then brain damaged, then killed.") H.dna.SetSEState(GLOB.jumpblock, 1) - genemutcheck(H, GLOB.jumpblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.jumpblock, MUTCHK_FORCED) H.update_mutations() H.gene_stability = 100 diff --git a/code/datums/spells/banana_touch.dm b/code/datums/spells/banana_touch.dm index e8b7f27b0da..ae2d1d69161 100644 --- a/code/datums/spells/banana_touch.dm +++ b/code/datums/spells/banana_touch.dm @@ -57,8 +57,8 @@ equip_to_slot_if_possible(new /obj/item/clothing/mask/gas/clown_hat/nodrop, slot_wear_mask, TRUE, TRUE) dna.SetSEState(GLOB.clumsyblock, TRUE, TRUE) dna.SetSEState(GLOB.comicblock, TRUE, TRUE) - genemutcheck(src, GLOB.clumsyblock, null, MUTCHK_FORCED) - genemutcheck(src, GLOB.comicblock, null, MUTCHK_FORCED) + singlemutcheck(src, GLOB.clumsyblock, MUTCHK_FORCED) + singlemutcheck(src, GLOB.comicblock, MUTCHK_FORCED) if(!(iswizard(src) || (mind && mind.special_role == SPECIAL_ROLE_WIZARD_APPRENTICE))) //Mutations are permanent on non-wizards. Can still be removed by genetics fuckery but not mutadone. dna.default_blocks.Add(GLOB.clumsyblock) dna.default_blocks.Add(GLOB.comicblock) diff --git a/code/datums/spells/cluwne.dm b/code/datums/spells/cluwne.dm index 19a12055fef..5a3b7b5da58 100644 --- a/code/datums/spells/cluwne.dm +++ b/code/datums/spells/cluwne.dm @@ -26,9 +26,8 @@ var/obj/item/organ/internal/honktumor/cursed/tumor = new tumor.insert(src) - mutations.Add(NERVOUS) dna.SetSEState(GLOB.nervousblock, 1, 1) - genemutcheck(src, GLOB.nervousblock, null, MUTCHK_FORCED) + singlemutcheck(src, GLOB.nervousblock, MUTCHK_FORCED) rename_character(real_name, "cluwne") unEquip(w_uniform, 1) @@ -55,15 +54,12 @@ if(tumor) tumor.remove(src) else - mutations.Remove(CLUMSY) - mutations.Remove(GLOB.comicblock) - dna.SetSEState(GLOB.clumsyblock,0) - dna.SetSEState(GLOB.comicblock,0) - genemutcheck(src, GLOB.clumsyblock, null, MUTCHK_FORCED) - genemutcheck(src, GLOB.comicblock, null, MUTCHK_FORCED) - mutations.Remove(NERVOUS) - dna.SetSEState(GLOB.nervousblock, 0) - genemutcheck(src, GLOB.nervousblock, null, MUTCHK_FORCED) + dna.SetSEState(GLOB.clumsyblock, FALSE) + dna.SetSEState(GLOB.comicblock, FALSE) + singlemutcheck(src, GLOB.clumsyblock, MUTCHK_FORCED) + singlemutcheck(src, GLOB.comicblock, MUTCHK_FORCED) + dna.SetSEState(GLOB.nervousblock, FALSE) + singlemutcheck(src, GLOB.nervousblock, MUTCHK_FORCED) var/obj/item/clothing/under/U = w_uniform unEquip(w_uniform, 1) diff --git a/code/datums/spells/genetic.dm b/code/datums/spells/genetic.dm index d95c6212486..dce6966512a 100644 --- a/code/datums/spells/genetic.dm +++ b/code/datums/spells/genetic.dm @@ -2,31 +2,36 @@ name = "Genetic" desc = "This spell inflicts a set of mutations and disabilities upon the target." - var/list/mutations = list() //mutation strings - var/duration = 100 //deciseconds - /* - Disabilities - 1st bit - ? - 2nd bit - ? - 3rd bit - ? - 4th bit - ? - 5th bit - ? - 6th bit - ? - */ + var/list/active_on = list() + var/list/traits = list() // traits + var/list/mutations = list() // mutation defines. Set these in Initialize. Refactor this nonsense one day + var/duration = 100 // deciseconds /obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets, mob/user = usr) - for(var/mob/living/target in targets) - for(var/x in mutations) - target.mutations.Add(x) - target.update_mutations() //update target's mutation overlays - var/mob/living/carbon/human/H = target - if(ishuman(target)) - H.update_body() - spawn(duration) - target.mutations.Remove(mutations) - target.update_mutations() - if(ishuman(target)) - H.update_body() + if(!target.dna) + continue + for(var/A in mutations) + target.dna.SetSEState(A, TRUE) + singlemutcheck(target, A, MUTCHK_FORCED) + for(var/A in traits) + ADD_TRAIT(target, A, MAGIC_TRAIT) + active_on += target + target.regenerate_icons() + if(duration < charge_max) + addtimer(CALLBACK(src, .proc/remove, target), duration, TIMER_OVERRIDE|TIMER_UNIQUE) - return +/obj/effect/proc_holder/spell/targeted/genetic/Destroy() + for(var/V in active_on) + remove(V) + return ..() + +/obj/effect/proc_holder/spell/targeted/genetic/proc/remove(mob/living/carbon/target) + active_on -= target + if(!QDELETED(target)) + for(var/A in mutations) + target.dna.SetSEState(A, FALSE) + singlemutcheck(target, A, MUTCHK_FORCED) + for(var/A in traits) + REMOVE_TRAIT(target, A, MAGIC_TRAIT) + target.regenerate_icons() diff --git a/code/datums/spells/mime_malaise.dm b/code/datums/spells/mime_malaise.dm index 1765b2f5741..03d5c07fb0f 100644 --- a/code/datums/spells/mime_malaise.dm +++ b/code/datums/spells/mime_malaise.dm @@ -50,5 +50,5 @@ equip_to_slot_if_possible(new /obj/item/clothing/under/mime/nodrop, slot_w_uniform, TRUE, TRUE) equip_to_slot_if_possible(new /obj/item/clothing/suit/suspenders/nodrop, slot_wear_suit, TRUE, TRUE) dna.SetSEState(GLOB.muteblock , TRUE, TRUE) - genemutcheck(src, GLOB.muteblock , null, MUTCHK_FORCED) + singlemutcheck(src, GLOB.muteblock, MUTCHK_FORCED) dna.default_blocks.Add(GLOB.muteblock) diff --git a/code/datums/spells/wizard.dm b/code/datums/spells/wizard.dm index a99655222a4..a954f72cb13 100644 --- a/code/datums/spells/wizard.dm +++ b/code/datums/spells/wizard.dm @@ -88,21 +88,16 @@ include_user = 1 centcom_cancast = 0 - mutations = list(LASER, HULK) + traits = list(TRAIT_LASEREYES) duration = 300 cooldown_min = 300 //25 deciseconds reduction per rank action_icon_state = "mutate" sound = 'sound/magic/mutate.ogg' -/obj/effect/proc_holder/spell/targeted/genetic/mutate/cast(list/targets, mob/user = usr) - for(var/mob/living/target in targets) - target.dna.SetSEState(GLOB.hulkblock, 1) - genemutcheck(target, GLOB.hulkblock, null, MUTCHK_FORCED) - spawn(duration) - target.dna.SetSEState(GLOB.hulkblock, 0) - genemutcheck(target, GLOB.hulkblock, null, MUTCHK_FORCED) - ..() +/obj/effect/proc_holder/spell/targeted/genetic/mutate/Initialize(mapload) + . = ..() + mutations = list(GLOB.hulkblock) /obj/effect/proc_holder/spell/targeted/smoke name = "Smoke" @@ -304,7 +299,7 @@ sound = 'sound/magic/blind.ogg' /obj/effect/proc_holder/spell/targeted/genetic/blind - mutations = list(BLINDNESS) + traits = list(TRAIT_BLIND) duration = 300 sound = 'sound/magic/blind.ogg' diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index e6b2e8d2008..b35140c14e4 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -54,8 +54,8 @@ /datum/status_effect/blooddrunk/on_apply() . = ..() if(.) + ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "blooddrunk") if(ishuman(owner)) - owner.status_flags |= IGNORESLOWDOWN var/mob/living/carbon/human/H = owner for(var/X in H.bodyparts) var/obj/item/organ/external/BP = X @@ -81,7 +81,7 @@ H.dna.species.clone_mod *= 10 H.dna.species.stamina_mod *= 10 add_attack_logs(owner, owner, "lost blood-drunk stun immunity", ATKLOG_ALL) - owner.status_flags &= ~IGNORESLOWDOWN + REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "blooddrunk") if(islist(owner.stun_absorption) && owner.stun_absorption["blooddrunk"]) owner.stun_absorption -= "blooddrunk" @@ -215,7 +215,7 @@ alert_type = /obj/screen/alert/status_effect/regenerative_core /datum/status_effect/regenerative_core/on_apply() - owner.status_flags |= IGNORE_SPEED_CHANGES + ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, id) owner.adjustBruteLoss(-25) owner.adjustFireLoss(-25) owner.remove_CC() @@ -231,4 +231,4 @@ return TRUE /datum/status_effect/regenerative_core/on_remove() - owner.status_flags &= ~IGNORE_SPEED_CHANGES + REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, id) diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index 09d6f67323e..8eff5e412c7 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -36,7 +36,7 @@ if(prob(40)) if(ishuman(L)) var/mob/living/carbon/human/H = L - if(!(RADIMMUNE in H.dna.species.species_traits)) + if(!HAS_TRAIT(H, TRAIT_RADIMMUNE)) if(prob(max(0, 100 - resist))) randmuti(H) // Applies bad mutation if(prob(50)) @@ -44,7 +44,7 @@ randmutb(H) else randmutg(H) - domutcheck(H, null, 1) + domutcheck(H, MUTCHK_FORCED) L.rad_act(20) diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index 5707c0aa9a1..691018cd6fa 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -105,7 +105,7 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes) - if(eyes && (COLOURBLIND in H.mutations)) // Check if the human has colorblindness. + if(eyes && HAS_TRAIT(H, TRAIT_COLORBLIND)) // Check if the human has colorblindness. replace_colors = eyes.replace_colours // Get the colorblind replacement colors list. var/list/wires_list = list() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 67675b24449..66df3d4a76c 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -575,7 +575,7 @@ add_fibers(M) //He has no prints! - if(FINGERPRINTS in M.mutations) + if(HAS_TRAIT(M, TRAIT_NOFINGERPRINTS)) if(fingerprintslast != M.key) fingerprintshidden += "(Has no fingerprints) Real name: [M.real_name], Key: [M.key]" fingerprintslast = M.key diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 121838ee304..3692f725361 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -96,7 +96,7 @@ //helper for getting the appropriate health status /proc/RoundHealth(mob/living/M) - if(M.stat == DEAD || (M.status_flags & FAKEDEATH)) + if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_FAKEDEATH))) return "health-100-dead" //what's our health? it doesn't matter, we're dead, or faking var/maxi_health = M.maxHealth @@ -178,7 +178,7 @@ /mob/living/carbon/med_hud_set_status() var/image/holder = hud_list[STATUS_HUD] var/mob/living/simple_animal/borer/B = has_brain_worms() - var/dead = stat == DEAD || (status_flags & FAKEDEATH) + var/dead = stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH) // To the right of health bar if(dead) var/revivable = timeofdeath && (round(world.time - timeofdeath) < DEFIB_TIME_LIMIT) @@ -186,7 +186,7 @@ holder.icon_state = "hudflatline" else holder.icon_state = "huddead" - else if(status_flags & XENO_HOST) + else if(HAS_TRAIT(src, TRAIT_XENO_HOST)) holder.icon_state = "hudxeno" else if(B && B.controlling) holder.icon_state = "hudbrainworm" diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index a9a91ebf17f..b0323825c70 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -9,12 +9,12 @@ // and to tell our new DNA datum which values to set in order to turn something // on or off. GLOBAL_LIST_INIT(dna_activity_bounds, new(DNA_SE_LENGTH)) -GLOBAL_LIST_INIT(assigned_gene_blocks, new(DNA_SE_LENGTH)) +GLOBAL_LIST_INIT(assigned_mutation_blocks, new(DNA_SE_LENGTH)) // Used to determine what each block means (admin hax and species stuff on /vg/, mostly) GLOBAL_LIST_INIT(assigned_blocks, new(DNA_SE_LENGTH)) -GLOBAL_LIST_EMPTY(dna_genes) +GLOBAL_LIST_EMPTY(dna_mutations) GLOBAL_LIST_EMPTY(good_blocks) GLOBAL_LIST_EMPTY(bad_blocks) @@ -173,7 +173,7 @@ GLOBAL_LIST_EMPTY(bad_blocks) var/value = GetUIValue(block) return round(1 + (value / 4096) * maxvalue) -// Is the UI gene "on" or "off"? +// Is the UI mutation "on" or "off"? // For UI, this is simply a check of if the value is > 2050. /datum/dna/proc/GetUIState(block) if(block <= 0) @@ -181,7 +181,7 @@ GLOBAL_LIST_EMPTY(bad_blocks) return UI[block] > 2050 -// Set UI gene "on" (1) or "off" (0) +// Set UI mutation "on" (1) or "off" (0) /datum/dna/proc/SetUIState(block, on, defer = FALSE) if(block <= 0) return @@ -299,7 +299,7 @@ GLOBAL_LIST_EMPTY(bad_blocks) var/value = GetSEValue(block) return round(1 + (value / 4096) * maxvalue) -// Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.) +// Is the block "on" (1) or "off" (0)? (Un-assigned mutations are always off.) /datum/dna/proc/GetSEState(block) if(block <= 0) return FALSE @@ -443,4 +443,4 @@ GLOBAL_LIST_EMPTY(bad_blocks) destination.dna.species.handle_dna(destination) // Handle DNA has to be re-called as the DNA was changed. destination.UpdateAppearance() - domutcheck(destination, null, MUTCHK_FORCED) + domutcheck(destination, MUTCHK_FORCED) diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm index 16eee549bf2..d82e652dbb7 100644 --- a/code/game/dna/dna2_domutcheck.dm +++ b/code/game/dna/dna2_domutcheck.dm @@ -1,67 +1,56 @@ // (Re-)Apply mutations. // TODO: Turn into a /mob proc, change inj to a bitflag for various forms of differing behavior. // M: Mob to mess with -// connected: Machine we're in, type unchecked so I doubt it's used beyond monkeying // flags: See below, bitfield. -/proc/domutcheck(mob/living/M, connected = null, flags = 0) - for(var/datum/dna/gene/gene in GLOB.dna_genes) +/proc/domutcheck(mob/living/M, flags = 0) + for(var/datum/mutation/mutation in GLOB.dna_mutations) if(!M || !M.dna) return - if(!gene.block) + if(!mutation.block) continue - domutation(gene, M, connected, flags) + domutation(mutation, M, flags) -// Use this to force a mut check on a single gene! -/proc/genemutcheck(mob/living/M, block, connected = null, flags = 0) - if(ishuman(M)) // Would've done this via species instead of type, but the basic mob doesn't have a species, go figure. - var/mob/living/carbon/human/H = M - if(NO_DNA in H.dna.species.species_traits) - return +// Use this to force a mut check on a single mutation! +/proc/singlemutcheck(mob/living/M, block, flags = 0) if(!M) return + if(HAS_TRAIT(M, TRAIT_GENELESS)) + return if(block < 0) return - var/datum/dna/gene/gene = GLOB.assigned_gene_blocks[block] - domutation(gene, M, connected, flags) + var/datum/mutation/mutation = GLOB.assigned_mutation_blocks[block] + domutation(mutation, M, flags) -/proc/domutation(datum/dna/gene/gene, mob/living/M, connected = null, flags = 0) - if(!gene || !istype(gene)) +/proc/domutation(datum/mutation/mutation, mob/living/M, flags = 0) + if(!mutation || !istype(mutation)) return FALSE // Current state - var/gene_active = M.dna.GetSEState(gene.block) + var/mutation_active = M.dna.GetSEState(mutation.block) // Sanity checks, don't skip. - if(!gene.can_activate(M,flags) && gene_active) + if(!mutation.can_activate(M, flags) && mutation_active) //testing("[M] - Failed to activate [gene.name] (can_activate fail).") return FALSE - var/defaultgenes // Do not mutate inherent species abilities - if(ishuman(M)) - var/mob/living/carbon/human/H = M - defaultgenes = H.dna.species.default_genes - - if((gene in defaultgenes) && gene_active) - return - // Prior state - var/gene_prior_status = (gene.type in M.active_genes) - var/changed = gene_active != gene_prior_status + var/mutation_prior_status = (mutation.type in M.active_mutations) + var/changed = mutation_active != mutation_prior_status // If gene state has changed: if(changed) // Gene active (or ALWAYS ACTIVATE) - if(gene_active) + if(mutation_active) //testing("[gene.name] activated!") - gene.activate(M,connected,flags) + mutation.activate(M) if(M) - M.active_genes |= gene.type + M.active_mutations |= mutation.type // If Gene is NOT active: else //testing("[gene.name] deactivated!") - gene.deactivate(M,connected,flags) + mutation.deactivate(M) if(M) - M.active_genes -= gene.type + M.active_mutations -= mutation.type diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index 7ded549f29b..ac521fd90d1 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -60,7 +60,7 @@ if(prob(prob)) M.dna.SetSEValue(i, rand(1, 4095), 1) M.dna.UpdateSE() - domutcheck(M, null) + domutcheck(M) // I haven't yet figured out what the fuck this is supposed to do. /proc/miniscramble(input, rs, rd) diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 1b3fb461f39..11aa0cce55a 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -312,10 +312,8 @@ if(!occupant) return TRUE - if(ishuman(occupant)) - var/mob/living/carbon/human/H = occupant - if(NO_DNA in H.dna.species.species_traits) - return TRUE + if(HAS_TRAIT(occupant, TRAIT_GENELESS)) + return TRUE var/radiation_protection = occupant.run_armor_check(null, "rad") if(radiation_protection > NEGATE_MUTATION_THRESHOLD) @@ -473,7 +471,7 @@ occupantData["name"] = connected.occupant.dna.real_name occupantData["stat"] = connected.occupant.stat occupantData["isViableSubject"] = 1 - if((NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna || (NO_DNA in connected.occupant.dna.species.species_traits)) + if((HAS_TRAIT(connected.occupant, TRAIT_BADDNA) && connected.scan_level < 3) || !connected.occupant.dna || HAS_TRAIT(connected.occupant, TRAIT_GENELESS)) occupantData["isViableSubject"] = 0 occupantData["health"] = connected.occupant.health occupantData["maxHealth"] = connected.occupant.maxHealth @@ -604,7 +602,7 @@ if(prob(20 + radiation_intensity)) randmutb(connected.occupant) - domutcheck(connected.occupant, connected) + domutcheck(connected.occupant) else randmuti(connected.occupant) connected.occupant.UpdateAppearance() @@ -659,7 +657,7 @@ //testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!") connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block) - domutcheck(connected.occupant, connected) + domutcheck(connected.occupant) else var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff) connected.occupant.apply_effect(radiation, IRRADIATE) @@ -670,7 +668,7 @@ if(prob(80 - radiation_duration)) //testing("Random bad mut!") randmutb(connected.occupant) - domutcheck(connected.occupant, connected) + domutcheck(connected.occupant) else randmuti(connected.occupant) //testing("Random identity mut!") @@ -723,7 +721,7 @@ if("changeLabel") ui_modal_input(src, "changeBufferLabel", "Please enter the new buffer label:", null, list("id" = bufferId), buffer.name, UI_MODAL_INPUT_MAX_LENGTH_NAME) if("transfer") - if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna) + if(!connected.occupant || (HAS_TRAIT(connected.occupant, TRAIT_BADDNA) && connected.scan_level < 3) || !connected.occupant.dna) return irradiating = 2 @@ -752,7 +750,7 @@ else if(buf.types & DNA2_BUF_SE) connected.occupant.dna.SE = buf.dna.SE.Copy() connected.occupant.dna.UpdateSE() - domutcheck(connected.occupant, connected) + domutcheck(connected.occupant) if("createInjector") if(!injector_ready) return diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm deleted file mode 100644 index 8970a115f5e..00000000000 --- a/code/game/dna/genes/disabilities.dm +++ /dev/null @@ -1,261 +0,0 @@ -///////////////////// -// DISABILITY GENES -// -// These activate either a mutation, disability -// -// Gene is always activated. -///////////////////// - -/datum/dna/gene/disability - name = "DISABILITY" - - // Mutation to give (or 0) - var/mutation = 0 - - // Activation message - var/activation_message = "" - - // Yay, you're no longer growing 3 arms - var/deactivation_message = "" - -/datum/dna/gene/disability/can_activate(mob/M, flags) - return TRUE // Always set! - -/datum/dna/gene/disability/activate(mob/living/M, connected, flags) - ..() - M.mutations |= mutation - if(activation_message) - to_chat(M, "[activation_message]") - else - testing("[name] has no activation message.") - -/datum/dna/gene/disability/deactivate(mob/living/M, connected, flags) - ..() - M.mutations.Remove(mutation) - if(deactivation_message) - to_chat(M, "[deactivation_message]") - else - testing("[name] has no deactivation message.") - -/datum/dna/gene/disability/hallucinate - name = "Hallucinate" - activation_message = "Your mind says 'Hello'." - deactivation_message = "Sanity returns. Or does it?" - instability = -GENE_INSTABILITY_MODERATE - mutation = HALLUCINATE - -/datum/dna/gene/disability/hallucinate/New() - ..() - block = GLOB.hallucinationblock - -/datum/dna/gene/disability/hallucinate/OnMobLife(mob/living/carbon/human/H) - if(prob(1)) - H.AdjustHallucinate(45) - -/datum/dna/gene/disability/epilepsy - name = "Epilepsy" - activation_message = "You get a headache." - deactivation_message = "Your headache is gone, at last." - instability = -GENE_INSTABILITY_MODERATE - mutation = EPILEPSY - -/datum/dna/gene/disability/epilepsy/New() - ..() - block = GLOB.epilepsyblock - -/datum/dna/gene/disability/epilepsy/OnMobLife(mob/living/carbon/human/H) - if((prob(1) && H.paralysis < 1)) - H.visible_message("[H] starts having a seizure!","You have a seizure!") - H.Paralyse(10) - H.Jitter(1000) - -/datum/dna/gene/disability/cough - name = "Coughing" - activation_message = "You start coughing." - deactivation_message = "Your throat stops aching." - instability = -GENE_INSTABILITY_MINOR - mutation = COUGHING - -/datum/dna/gene/disability/cough/New() - ..() - block = GLOB.coughblock - -/datum/dna/gene/disability/cough/OnMobLife(mob/living/carbon/human/H) - if((prob(5) && H.paralysis <= 1)) - H.drop_item() - H.emote("cough") - -/datum/dna/gene/disability/clumsy - name = "Clumsiness" - activation_message = "You feel lightheaded." - deactivation_message = "You regain some control of your movements" - instability = -GENE_INSTABILITY_MINOR - mutation = CLUMSY - -/datum/dna/gene/disability/clumsy/New() - ..() - block = GLOB.clumsyblock - -/datum/dna/gene/disability/tourettes - name = "Tourettes" - activation_message = "You twitch." - deactivation_message = "Your mouth tastes like soap." - instability = -GENE_INSTABILITY_MODERATE - mutation = TOURETTES - -/datum/dna/gene/disability/tourettes/New() - ..() - block = GLOB.twitchblock - -/datum/dna/gene/disability/tourettes/OnMobLife(mob/living/carbon/human/H) - if((prob(10) && H.paralysis <= 1)) - H.Stun(10) - switch(rand(1, 3)) - if(1) - H.emote("twitch") - if(2 to 3) - H.say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]") - var/x_offset_old = H.pixel_x - var/y_offset_old = H.pixel_y - var/x_offset = H.pixel_x + rand(-2, 2) - var/y_offset = H.pixel_y + rand(-1, 1) - animate(H, pixel_x = x_offset, pixel_y = y_offset, time = 1) - animate(H, pixel_x = x_offset_old, pixel_y = y_offset_old, time = 1) - -/datum/dna/gene/disability/nervousness - name = "Nervousness" - activation_message="You feel nervous." - deactivation_message ="You feel much calmer." - mutation = NERVOUS - -/datum/dna/gene/disability/nervousness/New() - ..() - block = GLOB.nervousblock - -/datum/dna/gene/disability/nervousness/OnMobLife(mob/living/carbon/human/H) - if(prob(10)) - H.Stuttering(10) - -/datum/dna/gene/disability/blindness - name = "Blindness" - activation_message = "You can't seem to see anything." - deactivation_message = "You can see now, in case you didn't notice..." - instability = -GENE_INSTABILITY_MAJOR - mutation = BLINDNESS - -/datum/dna/gene/disability/blindness/New() - ..() - block = GLOB.blindblock - -/datum/dna/gene/disability/blindness/activate(mob/M, connected, flags) - ..() - M.update_blind_effects() - -/datum/dna/gene/disability/blindness/deactivate(mob/M, connected, flags) - ..() - M.update_blind_effects() - - -/datum/dna/gene/disability/colourblindness - name = "Colourblindness" - activation_message = "You feel a peculiar prickling in your eyes while your perception of colour changes." - deactivation_message ="Your eyes tingle unsettlingly, though everything seems to become alot more colourful." - instability = -GENE_INSTABILITY_MODERATE - mutation = COLOURBLIND - -/datum/dna/gene/disability/colourblindness/New() - ..() - block = GLOB.colourblindblock - -/datum/dna/gene/disability/colourblindness/activate(mob/M, connected, flags) - ..() - M.update_client_colour() //Handle the activation of the colourblindness on the mob. - M.update_icons() //Apply eyeshine as needed. - -/datum/dna/gene/disability/colourblindness/deactivate(mob/M, connected, flags) - ..() - M.update_client_colour() //Handle the deactivation of the colourblindness on the mob. - M.update_icons() //Remove eyeshine as needed. - -/datum/dna/gene/disability/deaf - name = "Deafness" - activation_message="It's kinda quiet." - deactivation_message ="You can hear again!" - instability = -GENE_INSTABILITY_MAJOR - mutation = DEAF - -/datum/dna/gene/disability/deaf/New() - ..() - block = GLOB.deafblock - -/datum/dna/gene/disability/deaf/activate(mob/M, connected, flags) - ..() - M.MinimumDeafTicks(1) - -/datum/dna/gene/disability/nearsighted - name = "Nearsightedness" - activation_message="Your eyes feel weird..." - deactivation_message ="You can see clearly now" - instability = -GENE_INSTABILITY_MODERATE - mutation = NEARSIGHTED - -/datum/dna/gene/disability/nearsighted/New() - ..() - block = GLOB.glassesblock - -/datum/dna/gene/disability/nearsighted/activate(mob/living/M, connected, flags) - ..() - M.update_nearsighted_effects() - -/datum/dna/gene/disability/nearsighted/deactivate(mob/living/M, connected, flags) - ..() - M.update_nearsighted_effects() - -/datum/dna/gene/disability/lisp - name = "Lisp" - desc = "I wonder wath thith doeth." - activation_message = "Thomething doethn't feel right." - deactivation_message = "You now feel able to pronounce consonants." - mutation = LISP - -/datum/dna/gene/disability/lisp/New() - ..() - block = GLOB.lispblock - -/datum/dna/gene/disability/lisp/OnSay(mob/M, message) - return replacetext(message,"s","th") - -/datum/dna/gene/disability/comic - name = "Comic" - desc = "This will only bring death and destruction." - activation_message = "Uh oh!" - deactivation_message = "Well thank god that's over with." - mutation = COMIC - -/datum/dna/gene/disability/comic/New() - ..() - block = GLOB.comicblock - -/datum/dna/gene/disability/wingdings - name = "Alien Voice" - desc = "Garbles the subject's voice into an incomprehensible speech." - activation_message = "Your vocal cords feel alien." - deactivation_message = "Your vocal cords no longer feel alien." - instability = -GENE_INSTABILITY_MINOR - mutation = WINGDINGS - -/datum/dna/gene/disability/wingdings/New() - ..() - block = GLOB.wingdingsblock - -/datum/dna/gene/disability/wingdings/OnSay(mob/M, message) - var/garbled_message = "" - for(var/i in 1 to length(message)) - if(message[i] in GLOB.alphabet_uppercase) - garbled_message += pick(GLOB.alphabet_uppercase) - else if(message[i] in GLOB.alphabet) - garbled_message += pick(GLOB.alphabet) - else - garbled_message += message[i] - message = garbled_message - return message diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm deleted file mode 100644 index 1509cd098a4..00000000000 --- a/code/game/dna/genes/gene.dm +++ /dev/null @@ -1,126 +0,0 @@ -/** -* Gene Datum -* -* domutcheck was getting pretty hairy. This is the solution. -* -* All genes are stored in a global variable to cut down on memory -* usage. -* -* @author N3X15 -*/ - -/datum/dna/gene - // Display name - var/name = "BASE GENE" - - // Probably won't get used but why the fuck not - var/desc="Oh god who knows what this does." - - // Set in initialize()! - // What gene activates this? - var/block = 0 - - // Any of a number of GENE_ flags. - var/flags = 0 - - // Chance of the gene to cause adverse effects when active - var/instability = 0 - -/* -* Is the gene active in this mob's DNA? -*/ -/datum/dna/gene/proc/is_active(mob/M) - return M.active_genes && (type in M.active_genes) - -// Return 1 if we can activate. -// HANDLE MUTCHK_FORCED HERE! -/datum/dna/gene/proc/can_activate(mob/M, flags) - return FALSE - -// Called when the gene activates. Do your magic here. -/datum/dna/gene/proc/activate(mob/living/M, connected, flags) - M.gene_stability -= instability - -/** -* Called when the gene deactivates. Undo your magic here. -* Only called when the block is deactivated. -*/ -/datum/dna/gene/proc/deactivate(mob/living/M, connected, flags) - M.gene_stability += instability - -// This section inspired by goone's bioEffects. - -/** -* Called in each life() tick. -*/ -/datum/dna/gene/proc/OnMobLife(mob/M) - return - -/** -* Called when the mob dies -*/ -/datum/dna/gene/proc/OnMobDeath(mob/M) - return - -/** -* Called when the mob says shit -*/ -/datum/dna/gene/proc/OnSay(mob/M, message) - return message - -/** -* Called after the mob runs update_icons. -* -* @params M The subject. -* @params g Gender (m or f) -*/ -/datum/dna/gene/proc/OnDrawUnderlays(mob/M, g) - return FALSE - - -///////////////////// -// BASIC GENES -// -// These just chuck in a mutation and display a message. -// -// Gene is activated: -// 1. If mutation already exists in mob -// 2. If the probability roll succeeds -// 3. Activation is forced (done in domutcheck) -///////////////////// - - -/datum/dna/gene/basic - name = "BASIC GENE" - - // Mutation to give - var/mutation = 0 - - // Activation probability - var/activation_prob = 100 - - // Possible activation messages - var/list/activation_messages = list() - - // Possible deactivation messages - var/list/deactivation_messages = list() - -/datum/dna/gene/basic/can_activate(mob/M, flags) - if(flags & MUTCHK_FORCED) - return TRUE - // Probability check - return prob(activation_prob) - -/datum/dna/gene/basic/activate(mob/M, connected, flags) - ..() - M.mutations.Add(mutation) - if(activation_messages.len) - var/msg = pick(activation_messages) - to_chat(M, "[msg]") - -/datum/dna/gene/basic/deactivate(mob/living/M, connected, flags) - ..() - M.mutations.Remove(mutation) - if(deactivation_messages.len) - var/msg = pick(deactivation_messages) - to_chat(M, "[msg]") diff --git a/code/game/dna/genes/goon_disabilities.dm b/code/game/dna/genes/goon_disabilities.dm deleted file mode 100644 index 362271b8504..00000000000 --- a/code/game/dna/genes/goon_disabilities.dm +++ /dev/null @@ -1,292 +0,0 @@ -////////////////// -// DISABILITIES // -////////////////// - -//////////////////////////////////////// -// Totally Crippling -//////////////////////////////////////// - -// WAS: /datum/bioEffect/mute -/datum/dna/gene/disability/mute - name = "Mute" - desc = "Completely shuts down the speech center of the subject's brain." - activation_message = "You feel unable to express yourself at all." - deactivation_message = "You feel able to speak freely again." - instability = -GENE_INSTABILITY_MODERATE - mutation = MUTE - -/datum/dna/gene/disability/mute/New() - ..() - block = GLOB.muteblock - -/datum/dna/gene/disability/mute/OnSay(mob/M, message) - return "" - -//////////////////////////////////////// -// Harmful to others as well as self -//////////////////////////////////////// - -/datum/dna/gene/disability/radioactive - name = "Radioactive" - desc = "The subject suffers from constant radiation sickness and causes the same on nearby organics." - activation_message = "You feel a strange sickness permeate your whole body." - deactivation_message = "You no longer feel awful and sick all over." - instability = -GENE_INSTABILITY_MAJOR - mutation = RADIOACTIVE - -/datum/dna/gene/disability/radioactive/New() - ..() - block = GLOB.radblock - - -/datum/dna/gene/disability/radioactive/can_activate(mob/M, flags) - if(!..()) - return FALSE - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if((RADIMMUNE in H.dna.species.species_traits) && !(flags & MUTCHK_FORCED)) - return FALSE - return TRUE - -/datum/dna/gene/disability/radioactive/OnMobLife(mob/living/carbon/human/H) - radiation_pulse(H, 20) - -/datum/dna/gene/disability/radioactive/OnDrawUnderlays(mob/M, g) - return "rads_s" - -//////////////////////////////////////// -// Other disabilities -//////////////////////////////////////// - -// WAS: /datum/bioEffect/fat -/datum/dna/gene/disability/fat - name = "Obesity" - desc = "Greatly slows the subject's metabolism, enabling greater buildup of lipid tissue." - activation_message = "You feel blubbery and lethargic!" - deactivation_message = "You feel fit!" - instability = -GENE_INSTABILITY_MINOR - mutation = OBESITY - -/datum/dna/gene/disability/fat/New() - ..() - block = GLOB.fatblock - -// WAS: /datum/bioEffect/chav -/datum/dna/gene/disability/speech/chav - name = "Chav" - desc = "Forces the language center of the subject's brain to construct sentences in a more rudimentary manner." - activation_message = "Ye feel like a rite prat like, innit?" - deactivation_message = "You no longer feel like being rude and sassy." - mutation = CHAV - //List of swappable words. Normal word first, chav word second. - var/static/list/chavlinks = list( - "arrest" = "nick", - "arrested" = "nicked", - "ass" = "arse", - "bad" = "pants", - "bar" = "spoons", - "brain" = "noggin", - "break" = "smash", - "broke" = "smashed", - "broken" = "gone kaput", - "comdom" = "knob'ed", - "cool" = "ace", - "crazy" = "well mad", - "cup of tea" = "cuppa", - "destroyed" = "rekt", - "dick" = "prat", - "disappointed" = "gutted", - "disgusting" = "minging", - "disposals" = "bins", - "drink" = "bevvy", - "engineer" = "sparky", - "excited" = "jacked", - "fight" = "scuffle", - "food" = "nosh", - "friend" = "blud", - "fuck" = "fook", - "get" = "giz", - "girl" = "bird", - "go away" = "jog on", - "good" = "mint", - "great" = "bangin'", - "happy" = "chuffed", - "hello" = "orite", - "hi" = "sup", - "idiot" = "twit", - "isn't it" = "innit", - "kill" = "bang", - "killed" = "banged", - "man" = "bloke", - "mess" = "shambles", - "mistake" = "cock-up", - "murder" = "hench", - "murdered" = "henched", - "no" = "naw", - "really" = "propa", - "robust" = "'ard", - "run" = "leg it", - "sec" = "cops", - "security" = "coppers", - "silly" = "daft", - "steal" = "nick", - "stole" = "nicked", - "surprised" = "gobsmacked", - "suspicious" = "dodgy", - "tired" = "knackered", - "wet" = "moist", - "what" = "wot", - "window" = "windy", - "windows" = "windies", - "yes" = "ye", - "yikes" = "blimey", - "your" = "yur" - ) - -/datum/dna/gene/disability/speech/chav/New() - ..() - block = GLOB.chavblock - -/datum/dna/gene/disability/speech/chav/OnSay(mob/M, message) - var/static/regex/R = regex("\\b([chavlinks.Join("|")])\\b", "g") - message = R.Replace(message, /datum/dna/gene/disability/speech/chav/proc/replace_speech) - return message -/datum/dna/gene/disability/speech/chav/proc/replace_speech(matched) - return chavlinks[matched] - -// WAS: /datum/bioEffect/swedish -/datum/dna/gene/disability/speech/swedish - name = "Swedish" - desc = "Forces the language center of the subject's brain to construct sentences in a vaguely norse manner." - activation_message = "You feel Swedish, however that works." - deactivation_message = "The feeling of Swedishness passes." - mutation = SWEDISH - -/datum/dna/gene/disability/speech/swedish/New() - ..() - block = GLOB.swedeblock - -/datum/dna/gene/disability/speech/swedish/OnSay(mob/M, message) - // svedish - message = replacetextEx(message,"W","V") - message = replacetextEx(message,"w","v") - message = replacetextEx(message,"J","Y") - message = replacetextEx(message,"j","y") - message = replacetextEx(message,"A",pick("Å","Ä","Æ","A")) - message = replacetextEx(message,"a",pick("å","ä","æ","a")) - message = replacetextEx(message,"BO","BJO") - message = replacetextEx(message,"Bo","Bjo") - message = replacetextEx(message,"bo","bjo") - message = replacetextEx(message,"O",pick("Ö","Ø","O")) - message = replacetextEx(message,"o",pick("ö","ø","o")) - if(prob(30) && !M.is_muzzled()) - message += " Bork[pick("",", bork",", bork, bork")]!" - return message - -// WAS: /datum/bioEffect/unintelligable -/datum/dna/gene/disability/unintelligable - name = "Unintelligable" - desc = "Heavily corrupts the part of the brain responsible for forming spoken sentences." - activation_message = "You can't seem to form any coherent thoughts!" - deactivation_message = "Your mind feels more clear." - instability = -GENE_INSTABILITY_MINOR - mutation = SCRAMBLED - -/datum/dna/gene/disability/unintelligable/New() - ..() - block = GLOB.scrambleblock - -/datum/dna/gene/disability/unintelligable/OnSay(mob/M, message) - var/prefix = copytext(message,1,2) - if(prefix == ";") - message = copytext(message,2) - else if(prefix in list(":","#")) - prefix += copytext(message,2,3) - message = copytext(message,3) - else - prefix="" - - var/list/words = splittext(message," ") - var/list/rearranged = list() - for(var/i=1;i<=words.len;i++) - var/cword = pick(words) - words.Remove(cword) - var/suffix = copytext(cword,length(cword)-1,length(cword)) - while(length(cword)>0 && (suffix in list(".",",",";","!",":","?"))) - cword = copytext(cword,1 ,length(cword)-1) - suffix = copytext(cword,length(cword)-1,length(cword) ) - if(length(cword)) - rearranged += cword - return "[prefix][uppertext(jointext(rearranged," "))]!!" - -////////////////// -// USELESS SHIT // -////////////////// - -// WAS: /datum/bioEffect/strong -/datum/dna/gene/disability/strong - // pretty sure this doesn't do jack shit, putting it here until it does - name = "Strong" - desc = "Enhances the subject's ability to build and retain heavy muscles." - activation_message = "You feel buff!" - deactivation_message = "You feel wimpy and weak." - mutation = STRONG - -/datum/dna/gene/disability/strong/New() - ..() - block = GLOB.strongblock - -// WAS: /datum/bioEffect/horns -/datum/dna/gene/disability/horns - name = "Horns" - desc = "Enables the growth of a compacted keratin formation on the subject's head." - activation_message = "A pair of horns erupt from your head." - deactivation_message = "Your horns crumble away into nothing." - mutation = HORNS - -/datum/dna/gene/disability/horns/New() - ..() - block = GLOB.hornsblock - -/datum/dna/gene/disability/horns/OnDrawUnderlays(mob/M, g) - return "horns_s" - -//////////////////////////////////////////////////////////////////////// -// WAS: /datum/bioEffect/immolate -/datum/dna/gene/basic/grant_spell/immolate - name = "Incendiary Mitochondria" - desc = "The subject becomes able to convert excess cellular energy into thermal energy." - activation_messages = list("You suddenly feel rather hot.") - deactivation_messages = list("You no longer feel uncomfortably hot.") - mutation = IMMOLATE - - spelltype = /obj/effect/proc_holder/spell/targeted/immolate - -/datum/dna/gene/basic/grant_spell/immolate/New() - ..() - block = GLOB.immolateblock - -/obj/effect/proc_holder/spell/targeted/immolate - name = "Incendiary Mitochondria" - desc = "The subject becomes able to convert excess cellular energy into thermal energy." - panel = "Abilities" - - charge_type = "recharge" - charge_max = 600 - - clothes_req = 0 - stat_allowed = 0 - invocation_type = "none" - range = -1 - selection_type = "range" - var/list/compatible_mobs = list(/mob/living/carbon/human) - include_user = 1 - - action_icon_state = "genetic_incendiary" - -/obj/effect/proc_holder/spell/targeted/immolate/cast(list/targets, mob/living/user = usr) - var/mob/living/carbon/L = user - L.adjust_fire_stacks(0.5) - L.visible_message("[L.name] suddenly bursts into flames!") - L.IgniteMob() - playsound(L.loc, 'sound/effects/bamf.ogg', 50, 0) diff --git a/code/game/dna/genes/goon_powers.dm b/code/game/dna/genes/goon_powers.dm deleted file mode 100644 index a43d1bd97ac..00000000000 --- a/code/game/dna/genes/goon_powers.dm +++ /dev/null @@ -1,620 +0,0 @@ -#define EAT_MOB_DELAY 300 // 30s - -// WAS: /datum/bioEffect/alcres -/datum/dna/gene/basic/sober - name = "Sober" - activation_messages = list("You feel unusually sober.") - deactivation_messages = list("You feel like you could use a stiff drink.") - - mutation = SOBER - -/datum/dna/gene/basic/sober/New() - ..() - block = GLOB.soberblock - -//WAS: /datum/bioEffect/psychic_resist -/datum/dna/gene/basic/psychic_resist - name = "Psy-Resist" - desc = "Boosts efficiency in sectors of the brain commonly associated with meta-mental energies." - activation_messages = list("Your mind feels closed.") - deactivation_messages = list("You feel oddly exposed.") - - mutation = PSY_RESIST - -/datum/dna/gene/basic/psychic_resist/New() - ..() - block = GLOB.psyresistblock - -///////////////////////// -// Stealth Enhancers -///////////////////////// - -/datum/dna/gene/basic/stealth - instability = GENE_INSTABILITY_MODERATE - -/datum/dna/gene/basic/stealth/can_activate(mob/M, flags) - // Can only activate one of these at a time. - if(is_type_in_list(/datum/dna/gene/basic/stealth,M.active_genes)) - testing("Cannot activate [type]: /datum/dna/gene/basic/stealth in M.active_genes.") - return FALSE - return ..() - -/datum/dna/gene/basic/stealth/deactivate(mob/living/M, connected, flags) - ..() - M.alpha = 255 - -// WAS: /datum/bioEffect/darkcloak -/datum/dna/gene/basic/stealth/darkcloak - name = "Cloak of Darkness" - desc = "Enables the subject to bend low levels of light around themselves, creating a cloaking effect." - activation_messages = list("You begin to fade into the shadows.") - deactivation_messages = list("You become fully visible.") - activation_prob = 25 - mutation = CLOAK - -/datum/dna/gene/basic/stealth/darkcloak/New() - ..() - block = GLOB.shadowblock - -/datum/dna/gene/basic/stealth/darkcloak/OnMobLife(mob/M) - var/turf/simulated/T = get_turf(M) - if(!istype(T)) - return - var/light_available = T.get_lumcount() * 10 - if(light_available <= 2) - M.alpha = round(M.alpha * 0.8) - else - M.alpha = 255 - -//WAS: /datum/bioEffect/chameleon -/datum/dna/gene/basic/stealth/chameleon - name = "Chameleon" - desc = "The subject becomes able to subtly alter light patterns to become invisible, as long as they remain still." - activation_messages = list("You feel one with your surroundings.") - deactivation_messages = list("You feel oddly visible.") - activation_prob = 25 - mutation = CHAMELEON - -/datum/dna/gene/basic/stealth/chameleon/New() - ..() - block = GLOB.chameleonblock - -/datum/dna/gene/basic/stealth/chameleon/OnMobLife(mob/M) - if((world.time - M.last_movement) >= 30 && !M.stat && M.canmove && !M.restrained()) - M.alpha -= 25 - else - M.alpha = round(255 * 0.80) - -///////////////////////////////////////////////////////////////////////////////////////// - -/datum/dna/gene/basic/grant_spell - var/obj/effect/proc_holder/spell/spelltype - -/datum/dna/gene/basic/grant_spell/activate(mob/M, connected, flags) - M.AddSpell(new spelltype(null)) - ..() - return TRUE - -/datum/dna/gene/basic/grant_spell/deactivate(mob/M, connected, flags) - for(var/obj/effect/proc_holder/spell/S in M.mob_spell_list) - if(istype(S, spelltype)) - M.RemoveSpell(S) - ..() - return TRUE - -/datum/dna/gene/basic/grant_verb - var/verbtype - -/datum/dna/gene/basic/grant_verb/activate(mob/M, connected, flags) - ..() - M.verbs += verbtype - return TRUE - -/datum/dna/gene/basic/grant_verb/deactivate(mob/M, connected, flags) - ..() - M.verbs -= verbtype - -// WAS: /datum/bioEffect/cryokinesis -/datum/dna/gene/basic/grant_spell/cryo - name = "Cryokinesis" - desc = "Allows the subject to lower the body temperature of others." - activation_messages = list("You notice a strange cold tingle in your fingertips.") - deactivation_messages = list("Your fingers feel warmer.") - instability = GENE_INSTABILITY_MODERATE - mutation = CRYO - - spelltype = /obj/effect/proc_holder/spell/targeted/click/cryokinesis - -/datum/dna/gene/basic/grant_spell/cryo/New() - ..() - block = GLOB.cryoblock - -/obj/effect/proc_holder/spell/targeted/click/cryokinesis - name = "Cryokinesis" - desc = "Drops the bodytemperature of another person." - panel = "Abilities" - - charge_type = "recharge" - charge_max = 1200 - - clothes_req = FALSE - stat_allowed = FALSE - - click_radius = 0 - auto_target_single = FALSE // Give the clueless geneticists a way out and to have them not target themselves - selection_activated_message = "Your mind grow cold. Click on a target to cast the spell." - selection_deactivated_message = "Your mind returns to normal." - allowed_type = /mob/living/carbon - invocation_type = "none" - range = 7 - selection_type = "range" - include_user = TRUE - var/list/compatible_mobs = list(/mob/living/carbon/human) - - action_icon_state = "genetic_cryo" - -/obj/effect/proc_holder/spell/targeted/click/cryokinesis/cast(list/targets, mob/user = usr) - - var/mob/living/carbon/C = targets[1] - - if(COLDRES in C.mutations) - C.visible_message("A cloud of fine ice crystals engulfs [C.name], but disappears almost instantly!") - return - var/handle_suit = FALSE - if(ishuman(C)) - var/mob/living/carbon/human/H = C - if(istype(H.head, /obj/item/clothing/head/helmet/space)) - if(istype(H.wear_suit, /obj/item/clothing/suit/space)) - handle_suit = TRUE - if(H.internal) - H.visible_message("[user] sprays a cloud of fine ice crystals, engulfing [H]!", - "[user] sprays a cloud of fine ice crystals over your [H.head]'s visor.") - else - H.visible_message("[user] sprays a cloud of fine ice crystals engulfing, [H]!", - "[user] sprays a cloud of fine ice crystals cover your [H.head]'s visor and make it into your air vents!.") - - H.bodytemperature = max(0, H.bodytemperature - 100) - add_attack_logs(user, C, "Cryokinesis") - if(!handle_suit) - C.bodytemperature = max(0, C.bodytemperature - 200) - C.ExtinguishMob() - - C.visible_message("[user] sprays a cloud of fine ice crystals, engulfing [C]!") - add_attack_logs(user, C, "Cryokinesis- NO SUIT/INTERNALS") - - //playsound(user.loc, 'bamf.ogg', 50, 0) - - new/obj/effect/self_deleting(C.loc, icon('icons/effects/genetics.dmi', "cryokinesis")) - -/obj/effect/self_deleting - density = 0 - opacity = 0 - anchored = 1 - icon = null - desc = "" - //layer = 15 - -/obj/effect/self_deleting/New(atom/location, icon/I, duration = 20, oname = "something") - . = ..() - name = oname - loc=location - icon = I - QDEL_IN(src, duration) - -/////////////////////////////////////////////////////////////////////////////////////////// - -// WAS: /datum/bioEffect/mattereater -/datum/dna/gene/basic/grant_spell/mattereater - name = "Matter Eater" - desc = "Allows the subject to eat just about anything without harm." - activation_messages = list("You feel hungry.") - deactivation_messages = list("You don't feel quite so hungry anymore.") - instability = GENE_INSTABILITY_MINOR - mutation = EATER - - spelltype=/obj/effect/proc_holder/spell/targeted/eat - -/datum/dna/gene/basic/grant_spell/mattereater/New() - ..() - block = GLOB.eatblock - -/obj/effect/proc_holder/spell/targeted/eat - name = "Eat" - desc = "Eat just about anything!" - panel = "Abilities" - - charge_type = "recharge" - charge_max = 300 - - clothes_req = 0 - stat_allowed = 0 - invocation_type = "none" - range = 1 - selection_type = "view" - - action_icon_state = "genetic_eat" - - var/list/types_allowed = list( - /obj/item, - /mob/living/simple_animal/pet, - /mob/living/simple_animal/hostile, - /mob/living/simple_animal/parrot, - /mob/living/simple_animal/crab, - /mob/living/simple_animal/mouse, - /mob/living/carbon/human, - /mob/living/simple_animal/slime, - /mob/living/carbon/alien/larva, - /mob/living/simple_animal/slime, - /mob/living/simple_animal/chick, - /mob/living/simple_animal/chicken, - /mob/living/simple_animal/lizard, - /mob/living/simple_animal/cow, - /mob/living/simple_animal/spiderbot - ) - var/list/own_blacklist = list( - /obj/item/organ, - /obj/item/implant - ) - -/obj/effect/proc_holder/spell/targeted/eat/proc/doHeal(mob/user) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - for(var/name in H.bodyparts_by_name) - var/obj/item/organ/external/affecting = null - if(!H.bodyparts_by_name[name]) - continue - affecting = H.bodyparts_by_name[name] - if(!istype(affecting, /obj/item/organ/external)) - continue - affecting.heal_damage(4, 0, updating_health = FALSE) - H.UpdateDamageIcon() - H.updatehealth() - -/obj/effect/proc_holder/spell/targeted/eat/choose_targets(mob/user = usr) - var/list/targets = new /list() - var/list/possible_targets = new /list() - - if(!check_mouth(user)) - revert_cast(user) - return - - for(var/atom/movable/O in view_or_range(range, user, selection_type)) - if((O in user) && is_type_in_list(O,own_blacklist)) - continue - if(is_type_in_list(O,types_allowed)) - if(isanimal(O)) - var/mob/living/simple_animal/SA = O - if(!SA.gold_core_spawnable) - continue - possible_targets += O - - targets += input("Choose the target of your hunger.", "Targeting") as null|anything in possible_targets - - if(!targets.len || !targets[1]) //doesn't waste the spell - revert_cast(user) - return - - if(!check_mouth(user)) - revert_cast(user) - return - - perform(targets, user = user) - -/obj/effect/proc_holder/spell/targeted/eat/proc/check_mouth(mob/user = usr) - var/can_eat = TRUE - if(iscarbon(user)) - var/mob/living/carbon/C = user - if((C.head && (C.head.flags_cover & HEADCOVERSMOUTH)) || (C.wear_mask && (C.wear_mask.flags_cover & MASKCOVERSMOUTH) && !C.wear_mask.mask_adjusted)) - to_chat(C, "Your mouth is covered, preventing you from eating!") - can_eat = FALSE - return can_eat - -/obj/effect/proc_holder/spell/targeted/eat/cast(list/targets, mob/user = usr) - if(!targets.len) - to_chat(user, "No target found in range.") - return - - var/atom/movable/the_item = targets[1] - if(ishuman(the_item)) - var/mob/living/carbon/human/H = the_item - var/obj/item/organ/external/limb = H.get_organ(user.zone_selected) - if(!istype(limb)) - to_chat(user, "You can't eat this part of them!") - revert_cast() - return FALSE - if(istype(limb,/obj/item/organ/external/head)) - // Bullshit, but prevents being unable to clone someone. - to_chat(user, "You try to put \the [limb] in your mouth, but [the_item.p_their()] ears tickle your throat!") - revert_cast() - return FALSE - if(istype(limb,/obj/item/organ/external/chest)) - // Bullshit, but prevents being able to instagib someone. - to_chat(user, "You try to put [the_item.p_their()] [limb] in your mouth, but it's too big to fit!") - revert_cast() - return FALSE - user.visible_message("[user] begins stuffing [the_item]'s [limb.name] into [user.p_their()] gaping maw!") - var/oldloc = H.loc - if(!do_mob(user,H,EAT_MOB_DELAY)) - to_chat(user, "You were interrupted before you could eat [the_item]!") - else - if(!limb || !H) - return - if(H.loc != oldloc) - to_chat(user, "\The [limb] moved away from your mouth!") - return - user.visible_message("[user] [pick("chomps","bites")] off [the_item]'s [limb]!") - playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0) - limb.droplimb(0, DROPLIMB_SHARP) - doHeal(user) - else - user.visible_message("[user] eats \the [the_item].") - playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0) - qdel(the_item) - doHeal(user) - -//////////////////////////////////////////////////////////////////////// - -//WAS: /datum/bioEffect/jumpy -/datum/dna/gene/basic/grant_spell/jumpy - name = "Jumpy" - desc = "Allows the subject to leap great distances." - //cooldown = 30 - activation_messages = list("Your leg muscles feel taut and strong.") - deactivation_messages = list("Your leg muscles shrink back to normal.") - instability = GENE_INSTABILITY_MINOR - mutation = JUMPY - - spelltype =/obj/effect/proc_holder/spell/targeted/leap - -/datum/dna/gene/basic/grant_spell/jumpy/New() - ..() - block = GLOB.jumpblock - -/obj/effect/proc_holder/spell/targeted/leap - name = "Jump" - desc = "Leap great distances!" - panel = "Abilities" - range = -1 - include_user = 1 - - charge_type = "recharge" - charge_max = 60 - - clothes_req = 0 - stat_allowed = 0 - invocation_type = "none" - - action_icon_state = "genetic_jump" - -/obj/effect/proc_holder/spell/targeted/leap/cast(list/targets, mob/user = usr) - var/failure = FALSE - if(istype(user.loc,/mob/) || user.lying || user.stunned || user.buckled || user.stat) - to_chat(user, "You can't jump right now!") - return - - if(istype(user.loc,/turf/)) - if(user.restrained())//Why being pulled while cuffed prevents you from moving - for(var/mob/M in range(user, 1)) - if(M.pulling == user) - if(!M.restrained() && M.stat == 0 && M.canmove && user.Adjacent(M)) - failure = TRUE - else - M.stop_pulling() - - user.visible_message("[user.name] takes a huge leap!") - playsound(user.loc, 'sound/weapons/thudswoosh.ogg', 50, 1) - if(failure) - user.Weaken(5) - user.Stun(5) - user.visible_message("[user] attempts to leap away but is slammed back down to the ground!", - "You attempt to leap away but are suddenly slammed back down to the ground!", - "You hear the flexing of powerful muscles and suddenly a crash as a body hits the floor.") - return FALSE - var/prevLayer = user.layer - var/prevFlying = user.flying - user.layer = 9 - - user.flying = TRUE - for(var/i=0, i<10, i++) - step(user, user.dir) - if(i < 5) user.pixel_y += 8 - else user.pixel_y -= 8 - sleep(1) - user.flying = prevFlying - - if(FAT in user.mutations && prob(66)) - user.visible_message("[user.name] crashes due to [user.p_their()] heavy weight!") - //playsound(user.loc, 'zhit.wav', 50, 1) - user.AdjustWeakened(10) - user.AdjustStunned(5) - - user.layer = prevLayer - - if(istype(user.loc,/obj/)) - var/obj/container = user.loc - to_chat(user, "You leap and slam your head against the inside of [container]! Ouch!") - user.AdjustParalysis(3) - user.AdjustWeakened(5) - container.visible_message("[user.loc] emits a loud thump and rattles a bit.") - playsound(user.loc, 'sound/effects/bang.ogg', 50, 1) - var/wiggle = 6 - while(wiggle > 0) - wiggle-- - container.pixel_x = rand(-3,3) - container.pixel_y = rand(-3,3) - sleep(1) - container.pixel_x = 0 - container.pixel_y = 0 - -//////////////////////////////////////////////////////////////////////// - -// WAS: /datum/bioEffect/polymorphism - -/datum/dna/gene/basic/grant_spell/polymorph - name = "Polymorphism" - desc = "Enables the subject to reconfigure their appearance to mimic that of others." - - spelltype =/obj/effect/proc_holder/spell/targeted/click/polymorph - //cooldown = 1800 - activation_messages = list("You don't feel entirely like yourself somehow.") - deactivation_messages = list("You feel secure in your identity.") - instability = GENE_INSTABILITY_MODERATE - mutation = POLYMORPH - -/datum/dna/gene/basic/grant_spell/polymorph/New() - ..() - block = GLOB.polymorphblock - -/obj/effect/proc_holder/spell/targeted/click/polymorph - name = "Polymorph" - desc = "Mimic the appearance of others!" - panel = "Abilities" - charge_max = 1800 - - clothes_req = FALSE - stat_allowed = FALSE - - click_radius = -1 // Precision required - auto_target_single = FALSE // Safety to not turn into monkey (420) - selection_activated_message = "You body becomes unstable. Click on a target to cast transform into them." - selection_deactivated_message = "Your body calms down again." - allowed_type = /mob/living/carbon/human - - invocation_type = "none" - range = 1 - selection_type = "range" - - action_icon_state = "genetic_poly" - -/obj/effect/proc_holder/spell/targeted/click/polymorph/cast(list/targets, mob/user = usr) - var/mob/living/carbon/human/target = targets[1] - - user.visible_message("[user]'s body shifts and contorts.") - - spawn(10) - if(target && user) - playsound(user.loc, 'sound/goonstation/effects/gib.ogg', 50, 1) - var/mob/living/carbon/human/H = user - H.UpdateAppearance(target.dna.UI) - H.real_name = target.real_name - H.name = target.name - -//////////////////////////////////////////////////////////////////////// - -// WAS: /datum/bioEffect/empath -/datum/dna/gene/basic/grant_spell/empath - name = "Empathic Thought" - desc = "The subject becomes able to read the minds of others for certain information." - - spelltype = /obj/effect/proc_holder/spell/targeted/empath - activation_messages = list("You suddenly notice more about others than you did before.") - deactivation_messages = list("You no longer feel able to sense intentions.") - instability = GENE_INSTABILITY_MINOR - mutation = EMPATH - -/datum/dna/gene/basic/grant_spell/empath/New() - ..() - block = GLOB.empathblock - -/obj/effect/proc_holder/spell/targeted/empath - name = "Read Mind" - desc = "Read the minds of others for information." - charge_max = 180 - clothes_req = FALSE - human_req = TRUE - stat_allowed = CONSCIOUS - invocation_type = "none" - range = -2 - selection_type = "range" - - action_icon_state = "genetic_empath" - -/obj/effect/proc_holder/spell/targeted/empath/choose_targets(mob/user = usr) - var/list/possible_targets = list() - for(var/mob/living/carbon/C in range(7, user)) - possible_targets += C - var/target = input("Choose the target to spy on.", "Targeting") as null|mob in possible_targets - - if(!target) //doesn't waste the spell - revert_cast(user) - return - - perform(list(target), user = user) - -/obj/effect/proc_holder/spell/targeted/empath/cast(list/targets, mob/user = usr) - for(var/mob/living/carbon/M in targets) - if(!iscarbon(M)) - to_chat(user, "You may only use this on other organic beings.") - return - - if(PSY_RESIST in M.mutations) - to_chat(user, "You can't see into [M.name]'s mind at all!") - return - - if(M.stat == 2) - to_chat(user, "[M.name] is dead and cannot have [M.p_their()] mind read.") - return - if(M.health < 0) - to_chat(user, "[M.name] is dying, and [M.p_their()] thoughts are too scrambled to read.") - return - - to_chat(user, "Mind Reading of [M.name]:") - - var/pain_condition = M.health / M.maxHealth - // lower health means more pain - var/list/randomthoughts = list("what to have for lunch","the future","the past","money", - "[M.p_their()] hair","what to do next","[M.p_their()] job","space","amusing things","sad things", - "annoying things","happy things","something incoherent","something [M.p_they()] did wrong") - var/thoughts = "thinking about [pick(randomthoughts)]" - - if(M.fire_stacks) - pain_condition -= 0.5 - thoughts = "preoccupied with the fire" - - if(M.radiation) - pain_condition -= 0.25 - - switch(pain_condition) - if(0.81 to INFINITY) - to_chat(user, "Condition: [M.name] feels good.") - if(0.61 to 0.8) - to_chat(user, "Condition: [M.name] is suffering mild pain.") - if(0.41 to 0.6) - to_chat(user, "Condition: [M.name] is suffering significant pain.") - if(0.21 to 0.4) - to_chat(user, "Condition: [M.name] is suffering severe pain.") - else - to_chat(user, "Condition: [M.name] is suffering excruciating pain.") - thoughts = "haunted by [M.p_their()] own mortality" - - switch(M.a_intent) - if(INTENT_HELP) - to_chat(user, "Mood: You sense benevolent thoughts from [M.name].") - if(INTENT_DISARM) - to_chat(user, "Mood: You sense cautious thoughts from [M.name].") - if(INTENT_GRAB) - to_chat(user, "Mood: You sense hostile thoughts from [M.name].") - if(INTENT_HARM) - to_chat(user, "Mood: You sense cruel thoughts from [M.name].") - for(var/mob/living/L in view(7,M)) - if(L == M) - continue - thoughts = "thinking about punching [L.name]" - break - else - to_chat(user, "Mood: You sense strange thoughts from [M.name].") - - if(istype(M,/mob/living/carbon/human)) - var/numbers[0] - var/mob/living/carbon/human/H = M - if(H.mind && H.mind.initial_account) - numbers += H.mind.initial_account.account_number - numbers += H.mind.initial_account.remote_access_pin - if(numbers.len>0) - to_chat(user, "Numbers: You sense the number[numbers.len>1?"s":""] [english_list(numbers)] [numbers.len>1?"are":"is"] important to [M.name].") - to_chat(user, "Thoughts: [M.name] is currently [thoughts].") - - if(EMPATH in M.mutations) - to_chat(M, "You sense [user.name] reading your mind.") - else if(prob(5) || M.mind.assigned_role=="Chaplain") - to_chat(M, "You sense someone intruding upon your thoughts...") diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm deleted file mode 100644 index d893c64565c..00000000000 --- a/code/game/dna/genes/powers.dm +++ /dev/null @@ -1,200 +0,0 @@ -/////////////////////////////////// -// POWERS -/////////////////////////////////// - -/datum/dna/gene/basic/nobreath - name = "No Breathing" - activation_messages = list("You feel no need to breathe.") - deactivation_messages = list("You feel the need to breathe, once more.") - instability = GENE_INSTABILITY_MODERATE - mutation = BREATHLESS - activation_prob = 25 - -/datum/dna/gene/basic/nobreath/New() - ..() - block = GLOB.breathlessblock - - -/datum/dna/gene/basic/regenerate - name = "Regenerate" - activation_messages = list("Your wounds start healing.") - deactivation_messages = list("Your regenerative powers feel like they've vanished.") - instability = GENE_INSTABILITY_MINOR - mutation = REGEN - -/datum/dna/gene/basic/regenerate/New() - ..() - block = GLOB.regenerateblock - -/datum/dna/gene/basic/regenerate/OnMobLife(mob/living/carbon/human/H) - H.adjustBruteLoss(-0.1, FALSE) - H.adjustFireLoss(-0.1) - -/datum/dna/gene/basic/increaserun - name = "Super Speed" - activation_messages = list("You feel swift and unencumbered.") - deactivation_messages = list("You feel slow.") - instability = GENE_INSTABILITY_MINOR - mutation = RUN - -/datum/dna/gene/basic/increaserun/New() - ..() - block = GLOB.increaserunblock - -/datum/dna/gene/basic/increaserun/can_activate(mob/M, flags) - if(!..()) - return FALSE - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.dna.species && H.dna.species.speed_mod && !(flags & MUTCHK_FORCED)) - return FALSE - return TRUE - -/datum/dna/gene/basic/heat_resist - name = "Heat Resistance" - activation_messages = list("Your skin is icy to the touch.") - deactivation_messages = list("Your skin no longer feels icy to the touch.") - instability = GENE_INSTABILITY_MODERATE - mutation = HEATRES - -/datum/dna/gene/basic/heat_resist/New() - ..() - block = GLOB.coldblock - -/datum/dna/gene/basic/heat_resist/OnDrawUnderlays(mob/M, g) - return "cold_s" - -/datum/dna/gene/basic/cold_resist - name = "Cold Resistance" - activation_messages = list("Your body is filled with warmth.") - deactivation_messages = list("Your body is no longer filled with warmth.") - instability = GENE_INSTABILITY_MODERATE - mutation = COLDRES - -/datum/dna/gene/basic/cold_resist/New() - ..() - block = GLOB.fireblock - -/datum/dna/gene/basic/cold_resist/OnDrawUnderlays(mob/M, g) - return "fire_s" - -/datum/dna/gene/basic/noprints - name = "No Prints" - activation_messages = list("Your fingers feel numb.") - deactivation_messages = list("your fingers no longer feel numb.") - instability = GENE_INSTABILITY_MINOR - mutation = FINGERPRINTS - -/datum/dna/gene/basic/noprints/New() - ..() - block = GLOB.noprintsblock - -/datum/dna/gene/basic/noshock - name = "Shock Immunity" - activation_messages = list("Your skin feels dry and unreactive.") - deactivation_messages = list("Your skin no longer feels dry and unreactive.") - instability = GENE_INSTABILITY_MODERATE - mutation = NO_SHOCK - -/datum/dna/gene/basic/noshock/New() - ..() - block = GLOB.shockimmunityblock - -/datum/dna/gene/basic/midget - name = "Midget" - activation_messages = list("Everything around you seems bigger now...") - deactivation_messages = list("Everything around you seems to shrink...") - instability = GENE_INSTABILITY_MINOR - mutation = DWARF - -/datum/dna/gene/basic/midget/New() - ..() - block = GLOB.smallsizeblock - -/datum/dna/gene/basic/midget/activate(mob/M, connected, flags) - ..() - M.pass_flags |= PASSTABLE - M.resize = 0.8 - M.update_transform() - -/datum/dna/gene/basic/midget/deactivate(mob/M, connected, flags) - ..() - M.pass_flags &= ~PASSTABLE - M.resize = 1.25 - M.update_transform() - -// OLD HULK BEHAVIOR -/datum/dna/gene/basic/hulk - name = "Hulk" - activation_messages = list("Your muscles hurt.") - deactivation_messages = list("Your muscles shrink.") - instability = GENE_INSTABILITY_MAJOR - mutation = HULK - activation_prob = 15 - -/datum/dna/gene/basic/hulk/New() - ..() - block = GLOB.hulkblock - -/datum/dna/gene/basic/hulk/activate(mob/M, connected, flags) - ..() - var/status = CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH - M.status_flags &= ~status - -/datum/dna/gene/basic/hulk/deactivate(mob/M, connected, flags) - ..() - M.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH - -/datum/dna/gene/basic/hulk/OnDrawUnderlays(mob/M, g) - if(HULK in M.mutations) - return "hulk_[g]_s" - return FALSE - -/datum/dna/gene/basic/hulk/OnMobLife(mob/living/carbon/human/M) - if(!istype(M)) - return - if((HULK in M.mutations) && M.health <= 0) - M.mutations.Remove(HULK) - M.dna.SetSEState(GLOB.hulkblock,0) - genemutcheck(M, GLOB.hulkblock,null,MUTCHK_FORCED) - M.update_mutations() //update our mutation overlays - M.update_body() - M.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH //temporary fix until the problem can be solved. - to_chat(M, "You suddenly feel very weak.") - -/datum/dna/gene/basic/xray - name = "X-Ray Vision" - activation_messages = list("The walls suddenly disappear.") - deactivation_messages = list("the walls around you re-appear.") - instability = GENE_INSTABILITY_MAJOR - mutation = XRAY - activation_prob = 15 - -/datum/dna/gene/basic/xray/New() - ..() - block = GLOB.xrayblock - -/datum/dna/gene/basic/xray/activate(mob/living/M, connected, flags) - ..() - M.update_sight() - M.update_icons() //Apply eyeshine as needed. - -/datum/dna/gene/basic/xray/deactivate(mob/living/M, connected, flags) - ..() - M.update_sight() - M.update_icons() //Remove eyeshine as needed. - -/datum/dna/gene/basic/tk - name = "Telekenesis" - activation_messages = list("You feel smarter.") - deactivation_messages = list("You feel dumber.") - instability = GENE_INSTABILITY_MAJOR - mutation = TK - activation_prob = 15 - -/datum/dna/gene/basic/tk/New() - ..() - block = GLOB.teleblock - -/datum/dna/gene/basic/tk/OnDrawUnderlays(mob/M, g) - return "telekinesishead_s" diff --git a/code/game/dna/genes/vg_disabilities.dm b/code/game/dna/genes/vg_disabilities.dm deleted file mode 100644 index c2ad1559b6a..00000000000 --- a/code/game/dna/genes/vg_disabilities.dm +++ /dev/null @@ -1,42 +0,0 @@ - -/datum/dna/gene/disability/speech/loud - name = "Loud" - desc = "Forces the speaking centre of the subjects brain to yell every sentence." - activation_message = "YOU FEEL LIKE YELLING!" - deactivation_message = "You feel like being quiet.." - mutation = LOUD - -/datum/dna/gene/disability/speech/loud/New() - ..() - block = GLOB.loudblock - - - -/datum/dna/gene/disability/speech/loud/OnSay(mob/M, message) - message = replacetext(message,".","!") - message = replacetext(message,"?","?!") - message = replacetext(message,"!","!!") - return uppertext(message) - -/datum/dna/gene/disability/dizzy - name = "Dizzy" - desc = "Causes the cerebellum to shut down in some places." - activation_message = "You feel very dizzy..." - deactivation_message = "You regain your balance." - instability = -GENE_INSTABILITY_MINOR - mutation = DIZZY - -/datum/dna/gene/disability/dizzy/New() - ..() - block = GLOB.dizzyblock - - -/datum/dna/gene/disability/dizzy/OnMobLife(mob/living/carbon/human/M) - if(!istype(M)) - return - if(DIZZY in M.mutations) - M.Dizzy(300) - -/datum/dna/gene/disability/dizzy/deactivate(mob/living/M, connected, flags) - ..() - M.SetDizzy(0) diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm deleted file mode 100644 index 482842fb6be..00000000000 --- a/code/game/dna/genes/vg_powers.dm +++ /dev/null @@ -1,408 +0,0 @@ -///////////////////Vanilla Morph//////////////////////////////////// - -/datum/dna/gene/basic/grant_spell/morph - name = "Morphism" - desc = "Enables the subject to reconfigure their appearance to that of any human." - spelltype =/obj/effect/proc_holder/spell/targeted/morph - activation_messages = list("Your body feels if can alter its appearance.") - deactivation_messages = list("Your body doesn't feel capable of altering its appearance.") - instability = GENE_INSTABILITY_MINOR - mutation = MORPH - -/datum/dna/gene/basic/grant_spell/morph/New() - ..() - block = GLOB.morphblock - -/obj/effect/proc_holder/spell/targeted/morph - name = "Morph" - desc = "Mimic the appearance of your choice!" - panel = "Abilities" - charge_max = 1800 - - clothes_req = 0 - stat_allowed = 0 - invocation_type = "none" - range = -1 - include_user = 1 - selection_type = "range" - - action_icon_state = "genetic_morph" - -/obj/effect/proc_holder/spell/targeted/morph/cast(list/targets, mob/user = usr) - if(!ishuman(user)) - return - - if(istype(user.loc,/mob/)) - to_chat(user, "You can't change your appearance right now!") - return - var/mob/living/carbon/human/M = user - var/obj/item/organ/external/head/head_organ = M.get_organ("head") - var/obj/item/organ/internal/eyes/eyes_organ = M.get_int_organ(/obj/item/organ/internal/eyes) - - var/new_gender = alert(user, "Please select gender.", "Character Generation", "Male", "Female") - if(new_gender) - if(new_gender == "Male") - M.change_gender(MALE) - else - M.change_gender(FEMALE) - - var/new_eyes = input("Please select eye color.", "Character Generation", eyes_organ.eye_colour) as null|color - if(new_eyes) - M.change_eye_color(new_eyes) - - //Alt heads. - if(head_organ.dna.species.bodyflags & HAS_ALT_HEADS) - var/list/valid_alt_heads = M.generate_valid_alt_heads() - var/new_alt_head = input("Please select alternate head", "Character Generation", head_organ.alt_head) as null|anything in valid_alt_heads - if(new_alt_head) - M.change_alt_head(new_alt_head) - - // hair - var/list/valid_hairstyles = M.generate_valid_hairstyles() - var/new_style = input("Please select hair style", "Character Generation", head_organ.h_style) as null|anything in valid_hairstyles - - // if new style selected (not cancel) - if(new_style) - M.change_hair(new_style) - - var/new_hair = input("Please select hair color.", "Character Generation", head_organ.hair_colour) as null|color - if(new_hair) - M.change_hair_color(new_hair) - - var/datum/sprite_accessory/hair_style = GLOB.hair_styles_public_list[head_organ.h_style] - if(hair_style.secondary_theme && !hair_style.no_sec_colour) - new_hair = input("Please select secondary hair color.", "Character Generation", head_organ.sec_hair_colour) as null|color - if(new_hair) - M.change_hair_color(new_hair, 1) - - // facial hair - var/list/valid_facial_hairstyles = M.generate_valid_facial_hairstyles() - new_style = input("Please select facial style", "Character Generation", head_organ.f_style) as null|anything in valid_facial_hairstyles - - if(new_style) - M.change_facial_hair(new_style) - - var/new_facial = input("Please select facial hair color.", "Character Generation", head_organ.facial_colour) as null|color - if(new_facial) - M.change_facial_hair_color(new_facial) - - var/datum/sprite_accessory/facial_hair_style = GLOB.facial_hair_styles_list[head_organ.f_style] - if(facial_hair_style.secondary_theme && !facial_hair_style.no_sec_colour) - new_facial = input("Please select secondary facial hair color.", "Character Generation", head_organ.sec_facial_colour) as null|color - if(new_facial) - M.change_facial_hair_color(new_facial, 1) - - //Head accessory. - if(head_organ.dna.species.bodyflags & HAS_HEAD_ACCESSORY) - var/list/valid_head_accessories = M.generate_valid_head_accessories() - var/new_head_accessory = input("Please select head accessory style", "Character Generation", head_organ.ha_style) as null|anything in valid_head_accessories - if(new_head_accessory) - M.change_head_accessory(new_head_accessory) - - var/new_head_accessory_colour = input("Please select head accessory colour.", "Character Generation", head_organ.headacc_colour) as null|color - if(new_head_accessory_colour) - M.change_head_accessory_color(new_head_accessory_colour) - - //Body accessory. - if(M.dna.species.tail && M.dna.species.bodyflags & HAS_TAIL) - var/list/valid_body_accessories = M.generate_valid_body_accessories() - if(valid_body_accessories.len > 1) //By default valid_body_accessories will always have at the very least a 'none' entry populating the list, even if the user's species is not present in any of the list items. - var/new_body_accessory = input("Please select body accessory style", "Character Generation", M.body_accessory) as null|anything in valid_body_accessories - if(new_body_accessory) - M.change_body_accessory(new_body_accessory) - - //Head markings. - if(M.dna.species.bodyflags & HAS_HEAD_MARKINGS) - var/list/valid_head_markings = M.generate_valid_markings("head") - var/new_marking = input("Please select head marking style", "Character Generation", M.m_styles["head"]) as null|anything in valid_head_markings - if(new_marking) - M.change_markings(new_marking, "head") - - var/new_marking_colour = input("Please select head marking colour.", "Character Generation", M.m_colours["head"]) as null|color - if(new_marking_colour) - M.change_marking_color(new_marking_colour, "head") - //Body markings. - if(M.dna.species.bodyflags & HAS_BODY_MARKINGS) - var/list/valid_body_markings = M.generate_valid_markings("body") - var/new_marking = input("Please select body marking style", "Character Generation", M.m_styles["body"]) as null|anything in valid_body_markings - if(new_marking) - M.change_markings(new_marking, "body") - - var/new_marking_colour = input("Please select body marking colour.", "Character Generation", M.m_colours["body"]) as null|color - if(new_marking_colour) - M.change_marking_color(new_marking_colour, "body") - //Tail markings. - if(M.dna.species.bodyflags & HAS_TAIL_MARKINGS) - var/list/valid_tail_markings = M.generate_valid_markings("tail") - var/new_marking = input("Please select tail marking style", "Character Generation", M.m_styles["tail"]) as null|anything in valid_tail_markings - if(new_marking) - M.change_markings(new_marking, "tail") - - var/new_marking_colour = input("Please select tail marking colour.", "Character Generation", M.m_colours["tail"]) as null|color - if(new_marking_colour) - M.change_marking_color(new_marking_colour, "tail") - - //Skin tone. - if(M.dna.species.bodyflags & HAS_SKIN_TONE) - var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", M.s_tone) as null|text - if(!new_tone) - new_tone = 35 - else - new_tone = 35 - max(min(round(text2num(new_tone)), 220), 1) - M.change_skin_tone(new_tone) - - if(M.dna.species.bodyflags & HAS_ICON_SKIN_TONE) - var/prompt = "Please select skin tone: 1-[M.dna.species.icon_skin_tones.len] (" - for(var/i = 1 to M.dna.species.icon_skin_tones.len) - prompt += "[i] = [M.dna.species.icon_skin_tones[i]]" - if(i != M.dna.species.icon_skin_tones.len) - prompt += ", " - prompt += ")" - - var/new_tone = input(prompt, "Character Generation", M.s_tone) as null|text - if(!new_tone) - new_tone = 0 - else - new_tone = max(min(round(text2num(new_tone)), M.dna.species.icon_skin_tones.len), 1) - M.change_skin_tone(new_tone) - - //Skin colour. - if(M.dna.species.bodyflags & HAS_SKIN_COLOR) - var/new_body_colour = input("Please select body colour.", "Character Generation", M.skin_colour) as null|color - if(new_body_colour) - M.change_skin_color(new_body_colour) - - M.update_dna() - - M.visible_message("[M] morphs and changes [M.p_their()] appearance!", "You change your appearance!", "Oh, god! What the hell was that? It sounded like flesh getting squished and bone ground into a different shape!") - -/datum/dna/gene/basic/grant_spell/remotetalk - name = "Telepathy" - activation_messages = list("You feel you can project your thoughts.") - deactivation_messages = list("You no longer feel you can project your thoughts.") - instability = GENE_INSTABILITY_MINOR - mutation = REMOTE_TALK - - spelltype =/obj/effect/proc_holder/spell/targeted/remotetalk - -/datum/dna/gene/basic/grant_spell/remotetalk/New() - ..() - block = GLOB.remotetalkblock - -/datum/dna/gene/basic/grant_spell/remotetalk/activate(mob/living/M, connected, flags) - ..() - M.AddSpell(new /obj/effect/proc_holder/spell/targeted/mindscan(null)) - -/datum/dna/gene/basic/grant_spell/remotetalk/deactivate(mob/user) - ..() - for(var/obj/effect/proc_holder/spell/S in user.mob_spell_list) - if(istype(S, /obj/effect/proc_holder/spell/targeted/mindscan)) - user.RemoveSpell(S) - -/obj/effect/proc_holder/spell/targeted/remotetalk - name = "Project Mind" - desc = "Make people understand your thoughts!" - charge_max = 0 - - clothes_req = 0 - stat_allowed = 0 - invocation_type = "none" - range = -2 - selection_type = "range" - - action_icon_state = "genetic_project" - -/obj/effect/proc_holder/spell/targeted/remotetalk/choose_targets(mob/user = usr) - var/list/targets = new /list() - var/list/validtargets = user.get_telepathic_targets() - - if(!length(validtargets)) - to_chat(user, "There are no valid targets!") - start_recharge() - return - - var/target_name = input("Choose the target to talk to.", "Targeting") as null|anything in validtargets - - var/mob/living/target - if(!target_name || !(target = validtargets[target_name])) - revert_cast(user) - return - - targets += target - perform(targets, user = user) - -/obj/effect/proc_holder/spell/targeted/remotetalk/cast(list/targets, mob/user = usr) - if(!ishuman(user)) return - var/say = input("What do you wish to say") as text|null - if(!say || usr.stat) - return - say = strip_html(say) - say = pencode_to_html(say, usr, format = 0, fields = 0) - - for(var/mob/living/target in targets) - log_say("(TPATH to [key_name(target)]) [say]", user) - user.create_log(SAY_LOG, "Telepathically said '[say]' using [src]", target) - if(REMOTE_TALK in target.mutations) - target.show_message("You hear [user.real_name]'s voice: [say]") - else - target.show_message("You hear a voice that seems to echo around the room: [say]") - user.show_message("You project your mind into [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"]: [say]") - for(var/mob/dead/observer/G in GLOB.player_list) - G.show_message("Telepathic message from [user] ([ghost_follow_link(user, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]") - -/obj/effect/proc_holder/spell/targeted/mindscan - name = "Scan Mind" - desc = "Offer people a chance to share their thoughts!" - charge_max = 0 - clothes_req = 0 - stat_allowed = 0 - invocation_type = "none" - range = -2 - selection_type = "range" - action_icon_state = "genetic_mindscan" - var/list/available_targets = list() - -/obj/effect/proc_holder/spell/targeted/mindscan/choose_targets(mob/user = usr) - var/list/targets = list() - var/list/validtargets = user.get_telepathic_targets() - - if(!length(validtargets)) - to_chat(user, "There are no valid targets!") - start_recharge() - return - - var/target_name = input("Choose the target to listen to.", "Targeting") as null|anything in validtargets - - var/mob/living/target - if(!target_name || !(target = validtargets[target_name])) - revert_cast(user) - return - - targets += target - perform(targets, user = user) - -/obj/effect/proc_holder/spell/targeted/mindscan/cast(list/targets, mob/user = usr) - if(!ishuman(user)) - return - for(var/mob/living/target in targets) - var/message = "You feel your mind expand briefly... (Click to send a message.)" - if(REMOTE_TALK in target.mutations) - message = "You feel [user.real_name] request a response from you... (Click here to project mind.)" - user.show_message("You offer your mind to [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"].") - target.show_message("[message]") - available_targets += target - addtimer(CALLBACK(src, .proc/removeAvailability, target), 100) - -/obj/effect/proc_holder/spell/targeted/mindscan/proc/removeAvailability(mob/living/target) - if(target in available_targets) - available_targets -= target - if(!(target in available_targets)) - target.show_message("You feel the sensation fade...") - -/obj/effect/proc_holder/spell/targeted/mindscan/Topic(href, href_list) - var/mob/living/user - if(href_list["user"]) - user = locateUID(href_list["user"]) - if(href_list["target"]) - if(!user) - return - var/mob/living/target = locateUID(href_list["target"]) - if(!(target in available_targets)) - return - available_targets -= target - var/say = input("What do you wish to say") as text|null - if(!say) - return - say = strip_html(say) - say = pencode_to_html(say, target, format = 0, fields = 0) - user.create_log(SAY_LOG, "Telepathically responded '[say]' using [src]", target) - log_say("(TPATH to [key_name(target)]) [say]", user) - if(REMOTE_TALK in target.mutations) - target.show_message("You project your mind into [user.name]: [say]") - else - target.show_message("You fill the space in your thoughts: [say]") - user.show_message("You hear [target.name]'s voice: [say]") - for(var/mob/dead/observer/G in GLOB.player_list) - G.show_message("Telepathic response from [target] ([ghost_follow_link(target, ghost=G)]) to [user] ([ghost_follow_link(user, ghost=G)]): [say]") - -/obj/effect/proc_holder/spell/targeted/mindscan/Destroy() - available_targets.Cut() - return ..() - -/datum/dna/gene/basic/grant_spell/remoteview - name = "Remote Viewing" - activation_messages = list("Your mind can see things from afar.") - deactivation_messages = list("Your mind can no longer can see things from afar.") - instability = GENE_INSTABILITY_MINOR - mutation = REMOTE_VIEW - - spelltype =/obj/effect/proc_holder/spell/targeted/remoteview - -/datum/dna/gene/basic/grant_spell/remoteview/New() - ..() - block = GLOB.remoteviewblock - - -/obj/effect/proc_holder/spell/targeted/remoteview - name = "Remote View" - desc = "Spy on people from any range!" - charge_max = 100 - - clothes_req = 0 - stat_allowed = 0 - invocation_type = "none" - range = -2 - selection_type = "range" - - action_icon_state = "genetic_view" - -/obj/effect/proc_holder/spell/targeted/remoteview/choose_targets(mob/user = usr) - var/list/targets = list() - var/list/remoteviewers = list() - for(var/mob/M in GLOB.alive_mob_list) - if(M == user) - continue - if(PSY_RESIST in M.mutations) - continue - if(REMOTE_VIEW in M.mutations) - remoteviewers += M - if(!LAZYLEN(remoteviewers)) - to_chat(user, "No valid targets with remote view were found!") - start_recharge() - return - targets += input("Choose the target to spy on.", "Targeting") as null|anything in remoteviewers - if(!targets) - to_chat(user, "You decide against remote viewing.") - start_recharge() - return - perform(targets, user = user) - -/obj/effect/proc_holder/spell/targeted/remoteview/cast(list/targets, mob/user = usr) - var/mob/living/carbon/human/H - if(ishuman(user)) - H = user - else - return - - var/mob/target - - if(istype(H.l_hand, /obj/item/tk_grab) || istype(H.r_hand, /obj/item/tk_grab)) - to_chat(H, "Your mind is too busy with that telekinetic grab.") - H.remoteview_target = null - H.reset_perspective() - return - - if(H.client.eye != user.client.mob) - H.remoteview_target = null - H.reset_perspective() - return - - for(var/mob/living/L in targets) - target = L - - if(target) - H.remoteview_target = target - H.reset_perspective(target) - else - H.remoteview_target = null - H.reset_perspective() diff --git a/code/game/dna/mutations/_mutations.dm b/code/game/dna/mutations/_mutations.dm new file mode 100644 index 00000000000..a9718394066 --- /dev/null +++ b/code/game/dna/mutations/_mutations.dm @@ -0,0 +1,74 @@ +/datum/mutation + /// Display name + var/name = "mutation" + /// Description of the gene + var/desc = "A mutation." + /// What gene activates this? Set in initialize()! + var/block = 0 + /// Chance of the gene to cause adverse effects when active + var/instability = 0 + /// Trait to give, if any + var/traits_to_add = list() + /// Activation probability + var/activation_prob = 100 + /// Possible activation messages + var/list/activation_messages = list() + /// Possible deactivation messages + var/list/deactivation_messages = list() + + +// Is the gene active in this mob's DNA? +/datum/mutation/proc/is_active(mob/M) + return M.active_mutations && (type in M.active_mutations) + +// Return TRUE if we can activate. +// HANDLE MUTCHK_FORCED HERE! +/datum/mutation/proc/can_activate(mob/M, flags) + if(flags & MUTCHK_FORCED) + return TRUE + // Probability check + return prob(activation_prob) + +// Called when the gene activates. Do your magic here. +/datum/mutation/proc/activate(mob/living/M) + M.gene_stability -= instability + for(var/thing in traits_to_add) + ADD_TRAIT(M, thing, GENETIC_MUTATION) + if(length(activation_messages)) + var/msg = pick(activation_messages) + to_chat(M, "[msg]") + + +// Called when the gene deactivates. Undo your magic here. +// Only called when the block is deactivated. +/datum/mutation/proc/deactivate(mob/living/M) + M.gene_stability += instability + for(var/thing in traits_to_add) + REMOVE_TRAIT(M, thing, GENETIC_MUTATION) + if(length(deactivation_messages)) + var/msg = pick(deactivation_messages) + to_chat(M, "[msg]") + +// This section inspired by goone's bioEffects. + + +// Called in each life() tick. +/datum/mutation/proc/on_life(mob/M) + return + + +// Called when the mob dies +/datum/mutation/proc/on_death(mob/M) + return + + +// Called when the mob says shit +/datum/mutation/proc/on_say(mob/M, message) + return message + + +// Called after the mob runs update_icons. +// @params M The subject. +// @params g Gender (m or f) +/datum/mutation/proc/on_draw_underlays(mob/M, g) + return FALSE diff --git a/code/game/dna/mutations/disabilities.dm b/code/game/dna/mutations/disabilities.dm new file mode 100644 index 00000000000..bcb11eb1631 --- /dev/null +++ b/code/game/dna/mutations/disabilities.dm @@ -0,0 +1,549 @@ +///////////////////// +// DISABILITY MUTATIONS +// +// +// +// Mutation is always activated. +///////////////////// + +/datum/mutation/disability + name = "DISABILITY" + +/datum/mutation/disability/can_activate(mob/M, flags) + return TRUE // Always set! + +/datum/mutation/disability/hallucinate + name = "Hallucinate" + activation_messages = list("Your mind says 'Hello'.") + deactivation_messages = list("Sanity returns. Or does it?") + instability = -GENE_INSTABILITY_MODERATE + +/datum/mutation/disability/hallucinate/New() + ..() + block = GLOB.hallucinationblock + +/datum/mutation/disability/hallucinate/on_life(mob/living/carbon/human/H) + if(prob(1)) + H.AdjustHallucinate(45) + +/datum/mutation/disability/epilepsy + name = "Epilepsy" + activation_messages = list("You get a headache.") + deactivation_messages = list("Your headache is gone, at last.") + instability = -GENE_INSTABILITY_MODERATE + +/datum/mutation/disability/epilepsy/New() + ..() + block = GLOB.epilepsyblock + +/datum/mutation/disability/epilepsy/on_life(mob/living/carbon/human/H) + if((prob(1) && H.paralysis < 1)) + H.visible_message("[H] starts having a seizure!","You have a seizure!") + H.Paralyse(10) + H.Jitter(1000) + +/datum/mutation/disability/cough + name = "Coughing" + activation_messages = list("You start coughing.") + deactivation_messages = list("Your throat stops aching.") + instability = -GENE_INSTABILITY_MINOR + +/datum/mutation/disability/cough/New() + ..() + block = GLOB.coughblock + +/datum/mutation/disability/cough/on_life(mob/living/carbon/human/H) + if((prob(5) && H.paralysis <= 1)) + H.drop_item() + H.emote("cough") + +/datum/mutation/disability/clumsy + name = "Clumsiness" + activation_messages = list("You feel lightheaded.") + deactivation_messages = list("You regain some control of your movements") + instability = -GENE_INSTABILITY_MINOR + traits_to_add = list(TRAIT_CLUMSY) + +/datum/mutation/disability/clumsy/New() + ..() + block = GLOB.clumsyblock + +/datum/mutation/disability/tourettes + name = "Tourettes" + activation_messages = list("You twitch.") + deactivation_messages = list("Your mouth tastes like soap.") + instability = -GENE_INSTABILITY_MODERATE + +/datum/mutation/disability/tourettes/New() + ..() + block = GLOB.twitchblock + +/datum/mutation/disability/tourettes/on_life(mob/living/carbon/human/H) + if((prob(10) && H.paralysis <= 1)) + H.Stun(10) + switch(rand(1, 3)) + if(1) + H.emote("twitch") + if(2 to 3) + H.say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]") + var/x_offset_old = H.pixel_x + var/y_offset_old = H.pixel_y + var/x_offset = H.pixel_x + rand(-2, 2) + var/y_offset = H.pixel_y + rand(-1, 1) + animate(H, pixel_x = x_offset, pixel_y = y_offset, time = 1) + animate(H, pixel_x = x_offset_old, pixel_y = y_offset_old, time = 1) + +/datum/mutation/disability/nervousness + name = "Nervousness" + activation_messages = list("You feel nervous.") + deactivation_messages = list("You feel much calmer.") + +/datum/mutation/disability/nervousness/New() + ..() + block = GLOB.nervousblock + +/datum/mutation/disability/nervousness/on_life(mob/living/carbon/human/H) + if(prob(10)) + H.Stuttering(10) + +/datum/mutation/disability/blindness + name = "Blindness" + activation_messages = list("You can't seem to see anything.") + deactivation_messages = list("You can see now, in case you didn't notice...") + instability = -GENE_INSTABILITY_MAJOR + traits_to_add = list(TRAIT_BLIND) + +/datum/mutation/disability/blindness/New() + ..() + block = GLOB.blindblock + +/datum/mutation/disability/blindness/activate(mob/M) + ..() + M.update_blind_effects() + +/datum/mutation/disability/blindness/deactivate(mob/M) + ..() + M.update_blind_effects() + + +/datum/mutation/disability/colourblindness + name = "Colourblindness" + activation_messages = list("You feel a peculiar prickling in your eyes while your perception of colour changes.") + deactivation_messages = list("Your eyes tingle unsettlingly, though everything seems to become alot more colourful.") + instability = -GENE_INSTABILITY_MODERATE + traits_to_add = list(TRAIT_COLORBLIND) + +/datum/mutation/disability/colourblindness/New() + ..() + block = GLOB.colourblindblock + +/datum/mutation/disability/colourblindness/activate(mob/M) + ..() + M.update_client_colour() //Handle the activation of the colourblindness on the mob. + M.update_icons() //Apply eyeshine as needed. + +/datum/mutation/disability/colourblindness/deactivate(mob/M) + ..() + M.update_client_colour() //Handle the deactivation of the colourblindness on the mob. + M.update_icons() //Remove eyeshine as needed. + +/datum/mutation/disability/deaf + name = "Deafness" + activation_messages = list("It's kinda quiet.") + deactivation_messages = list("You can hear again!") + instability = -GENE_INSTABILITY_MAJOR + traits_to_add = list(TRAIT_DEAF) + +/datum/mutation/disability/deaf/New() + ..() + block = GLOB.deafblock + +/datum/mutation/disability/nearsighted + name = "Nearsightedness" + activation_messages = list("Your eyes feel weird...") + deactivation_messages = list("You can see clearly now") + instability = -GENE_INSTABILITY_MODERATE + traits_to_add = list(TRAIT_NEARSIGHT) + +/datum/mutation/disability/nearsighted/New() + ..() + block = GLOB.glassesblock + +/datum/mutation/disability/nearsighted/activate(mob/living/M) + ..() + M.update_nearsighted_effects() + +/datum/mutation/disability/nearsighted/deactivate(mob/living/M) + ..() + M.update_nearsighted_effects() + +/datum/mutation/disability/lisp + name = "Lisp" + desc = "I wonder wath thith doeth." + activation_messages = list("Thomething doethn't feel right.") + deactivation_messages = list("You now feel able to pronounce consonants.") + +/datum/mutation/disability/lisp/New() + ..() + block = GLOB.lispblock + +/datum/mutation/disability/lisp/on_say(mob/M, message) + return replacetext(message,"s","th") + +/datum/mutation/disability/comic + name = "Comic" + desc = "This will only bring death and destruction." + activation_messages = list("Uh oh!") + deactivation_messages = list("Well thank god that's over with.") + traits_to_add = list(TRAIT_COMIC_SANS) + +/datum/mutation/disability/comic/New() + ..() + block = GLOB.comicblock + +/datum/mutation/disability/wingdings + name = "Alien Voice" + desc = "Garbles the subject's voice into an incomprehensible speech." + activation_messages = list("Your vocal cords feel alien.") + deactivation_messages = list("Your vocal cords no longer feel alien.") + instability = -GENE_INSTABILITY_MINOR + traits_to_add = list(TRAIT_WINGDINGS) + +/datum/mutation/disability/wingdings/New() + ..() + block = GLOB.wingdingsblock + +/datum/mutation/disability/wingdings/on_say(mob/M, message) + var/garbled_message = "" + for(var/i in 1 to length(message)) + if(message[i] in GLOB.alphabet_uppercase) + garbled_message += pick(GLOB.alphabet_uppercase) + else if(message[i] in GLOB.alphabet) + garbled_message += pick(GLOB.alphabet) + else + garbled_message += message[i] + message = garbled_message + return message + +////////////////// +// DISABILITIES // +////////////////// + +//////////////////////////////////////// +// Totally Crippling +//////////////////////////////////////// + +// WAS: /datum/bioEffect/mute +/datum/mutation/disability/mute + name = "Mute" + desc = "Completely shuts down the speech center of the subject's brain." + activation_messages = list("You feel unable to express yourself at all.") + deactivation_messages = list("You feel able to speak freely again.") + instability = -GENE_INSTABILITY_MODERATE + traits_to_add = list(TRAIT_MUTE) + +/datum/mutation/disability/mute/New() + ..() + block = GLOB.muteblock + +/datum/mutation/disability/mute/on_say(mob/M, message) + return "" + +//////////////////////////////////////// +// Harmful to others as well as self +//////////////////////////////////////// + +/datum/mutation/disability/radioactive + name = "Radioactive" + desc = "The subject suffers from constant radiation sickness and causes the same on nearby organics." + activation_messages = list("You feel a strange sickness permeate your whole body.") + deactivation_messages = list("You no longer feel awful and sick all over.") + instability = -GENE_INSTABILITY_MAJOR + +/datum/mutation/disability/radioactive/New() + ..() + block = GLOB.radblock + + +/datum/mutation/disability/radioactive/can_activate(mob/M, flags) + if(!..()) + return FALSE + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(HAS_TRAIT(H, TRAIT_RADIMMUNE) && !(flags & MUTCHK_FORCED)) + return FALSE + return TRUE + +/datum/mutation/disability/radioactive/on_life(mob/living/carbon/human/H) + radiation_pulse(H, 20) + +/datum/mutation/disability/radioactive/on_draw_underlays(mob/M, g) + return "rads_s" + +//////////////////////////////////////// +// Other disabilities +//////////////////////////////////////// + +// WAS: /datum/bioEffect/fat +/datum/mutation/disability/fat + name = "Obesity" + desc = "Greatly slows the subject's metabolism, enabling greater buildup of lipid tissue." + activation_messages = list("You feel blubbery and lethargic!") + deactivation_messages = list("You feel fit!") + instability = -GENE_INSTABILITY_MINOR + traits_to_add = list(TRAIT_SLOWDIGESTION) + +/datum/mutation/disability/fat/New() + ..() + block = GLOB.fatblock + +// WAS: /datum/bioEffect/chav +/datum/mutation/disability/speech/chav + name = "Chav" + desc = "Forces the language center of the subject's brain to construct sentences in a more rudimentary manner." + activation_messages = list("Ye feel like a rite prat like, innit?") + deactivation_messages = list("You no longer feel like being rude and sassy.") + //List of swappable words. Normal word first, chav word second. + var/static/list/chavlinks = list( + "arrest" = "nick", + "arrested" = "nicked", + "ass" = "arse", + "bad" = "pants", + "bar" = "spoons", + "brain" = "noggin", + "break" = "smash", + "broke" = "smashed", + "broken" = "gone kaput", + "comdom" = "knob'ed", + "cool" = "ace", + "crazy" = "well mad", + "cup of tea" = "cuppa", + "destroyed" = "rekt", + "dick" = "prat", + "disappointed" = "gutted", + "disgusting" = "minging", + "disposals" = "bins", + "drink" = "bevvy", + "engineer" = "sparky", + "excited" = "jacked", + "fight" = "scuffle", + "food" = "nosh", + "friend" = "blud", + "fuck" = "fook", + "get" = "giz", + "girl" = "bird", + "go away" = "jog on", + "good" = "mint", + "great" = "bangin'", + "happy" = "chuffed", + "hello" = "orite", + "hi" = "sup", + "idiot" = "twit", + "isn't it" = "innit", + "kill" = "bang", + "killed" = "banged", + "man" = "bloke", + "mess" = "shambles", + "mistake" = "cock-up", + "murder" = "hench", + "murdered" = "henched", + "no" = "naw", + "really" = "propa", + "robust" = "'ard", + "run" = "leg it", + "sec" = "cops", + "security" = "coppers", + "silly" = "daft", + "steal" = "nick", + "stole" = "nicked", + "surprised" = "gobsmacked", + "suspicious" = "dodgy", + "tired" = "knackered", + "wet" = "moist", + "what" = "wot", + "window" = "windy", + "windows" = "windies", + "yes" = "ye", + "yikes" = "blimey", + "your" = "yur" + ) + +/datum/mutation/disability/speech/chav/New() + ..() + block = GLOB.chavblock + +/datum/mutation/disability/speech/chav/on_say(mob/M, message) + var/static/regex/R = regex("\\b([chavlinks.Join("|")])\\b", "g") + message = R.Replace(message, /datum/mutation/disability/speech/chav/proc/replace_speech) + return message + +/datum/mutation/disability/speech/chav/proc/replace_speech(matched) + return chavlinks[matched] + +// WAS: /datum/bioEffect/swedish +/datum/mutation/disability/speech/swedish + name = "Swedish" + desc = "Forces the language center of the subject's brain to construct sentences in a vaguely norse manner." + activation_messages = list("You feel Swedish, however that works.") + deactivation_messages = list("The feeling of Swedishness passes.") + +/datum/mutation/disability/speech/swedish/New() + ..() + block = GLOB.swedeblock + +/datum/mutation/disability/speech/swedish/on_say(mob/M, message) + // svedish + message = replacetextEx(message,"W","V") + message = replacetextEx(message,"w","v") + message = replacetextEx(message,"J","Y") + message = replacetextEx(message,"j","y") + message = replacetextEx(message,"A",pick("Å","Ä","Æ","A")) + message = replacetextEx(message,"a",pick("å","ä","æ","a")) + message = replacetextEx(message,"BO","BJO") + message = replacetextEx(message,"Bo","Bjo") + message = replacetextEx(message,"bo","bjo") + message = replacetextEx(message,"O",pick("Ö","Ø","O")) + message = replacetextEx(message,"o",pick("ö","ø","o")) + if(prob(30) && !M.is_muzzled()) + message += " Bork[pick("",", bork",", bork, bork")]!" + return message + +// WAS: /datum/bioEffect/unintelligable +/datum/mutation/disability/unintelligable + name = "Unintelligable" + desc = "Heavily corrupts the part of the brain responsible for forming spoken sentences." + activation_messages = list("You can't seem to form any coherent thoughts!") + deactivation_messages = list("Your mind feels more clear.") + instability = -GENE_INSTABILITY_MINOR + +/datum/mutation/disability/unintelligable/New() + ..() + block = GLOB.scrambleblock + +/datum/mutation/disability/unintelligable/on_say(mob/M, message) + var/prefix = copytext(message,1,2) + if(prefix == ";") + message = copytext(message,2) + else if(prefix in list(":","#")) + prefix += copytext(message,2,3) + message = copytext(message,3) + else + prefix="" + + var/list/words = splittext(message," ") + var/list/rearranged = list() + for(var/i=1;i<=words.len;i++) + var/cword = pick(words) + words.Remove(cword) + var/suffix = copytext(cword,length(cword)-1,length(cword)) + while(length(cword)>0 && (suffix in list(".",",",";","!",":","?"))) + cword = copytext(cword,1 ,length(cword)-1) + suffix = copytext(cword,length(cword)-1,length(cword) ) + if(length(cword)) + rearranged += cword + return "[prefix][uppertext(jointext(rearranged," "))]!!" + +////////////////// +// USELESS SHIT // +////////////////// + +// WAS: /datum/bioEffect/strong +/datum/mutation/disability/strong + // pretty sure this doesn't do jack shit, putting it here until it does + name = "Strong" + desc = "Enhances the subject's ability to build and retain heavy muscles." + activation_messages = list("You feel buff!") + deactivation_messages = list("You feel wimpy and weak.") + +/datum/mutation/disability/strong/New() + ..() + block = GLOB.strongblock + +// WAS: /datum/bioEffect/horns +/datum/mutation/disability/horns + name = "Horns" + desc = "Enables the growth of a compacted keratin formation on the subject's head." + activation_messages = list("A pair of horns erupt from your head.") + deactivation_messages = list("Your horns crumble away into nothing.") + +/datum/mutation/disability/horns/New() + ..() + block = GLOB.hornsblock + +/datum/mutation/disability/horns/on_draw_underlays(mob/M, g) + return "horns_s" + +/datum/mutation/grant_spell/immolate + name = "Incendiary Mitochondria" + desc = "The subject becomes able to convert excess cellular energy into thermal energy." + activation_messages = list("You suddenly feel rather hot.") + deactivation_messages = list("You no longer feel uncomfortably hot.") + spelltype = /obj/effect/proc_holder/spell/targeted/immolate + +/datum/mutation/grant_spell/immolate/New() + ..() + block = GLOB.immolateblock + +/obj/effect/proc_holder/spell/targeted/immolate + name = "Incendiary Mitochondria" + desc = "The subject becomes able to convert excess cellular energy into thermal energy." + panel = "Abilities" + + charge_type = "recharge" + charge_max = 600 + + clothes_req = 0 + stat_allowed = 0 + invocation_type = "none" + range = -1 + selection_type = "range" + var/list/compatible_mobs = list(/mob/living/carbon/human) + include_user = 1 + + action_icon_state = "genetic_incendiary" + +/obj/effect/proc_holder/spell/targeted/immolate/cast(list/targets, mob/living/user = usr) + var/mob/living/carbon/L = user + L.adjust_fire_stacks(0.5) + L.visible_message("[L.name] suddenly bursts into flames!") + L.IgniteMob() + playsound(L.loc, 'sound/effects/bamf.ogg', 50, 0) + +/datum/mutation/disability/speech/loud + name = "Loud" + desc = "Forces the speaking centre of the subjects brain to yell every sentence." + activation_messages = list("YOU FEEL LIKE YELLING!") + deactivation_messages = list("You feel like being quiet..") + +/datum/mutation/disability/speech/loud/New() + ..() + block = GLOB.loudblock + + + +/datum/mutation/disability/speech/loud/on_say(mob/M, message) + message = replacetext(message,".","!") + message = replacetext(message,"?","?!") + message = replacetext(message,"!","!!") + return uppertext(message) + +/datum/mutation/disability/dizzy + name = "Dizzy" + desc = "Causes the cerebellum to shut down in some places." + activation_messages = list("You feel very dizzy...") + deactivation_messages = list("You regain your balance.") + instability = -GENE_INSTABILITY_MINOR + +/datum/mutation/disability/dizzy/New() + ..() + block = GLOB.dizzyblock + + +/datum/mutation/disability/dizzy/on_life(mob/living/carbon/human/M) + if(!istype(M)) + return + M.Dizzy(300) + +/datum/mutation/disability/dizzy/deactivate(mob/living/M) + ..() + M.SetDizzy(0) diff --git a/code/game/dna/genes/monkey.dm b/code/game/dna/mutations/monkey.dm similarity index 86% rename from code/game/dna/genes/monkey.dm rename to code/game/dna/mutations/monkey.dm index 583b2c75836..8939ee31e00 100644 --- a/code/game/dna/genes/monkey.dm +++ b/code/game/dna/mutations/monkey.dm @@ -1,14 +1,14 @@ -/datum/dna/gene/monkey +/datum/mutation/monkey name = "Monkey" -/datum/dna/gene/monkey/New() +/datum/mutation/monkey/New() ..() block = GLOB.monkeyblock -/datum/dna/gene/monkey/can_activate(mob/M, flags) +/datum/mutation/monkey/can_activate(mob/M, flags) return ishuman(M) -/datum/dna/gene/monkey/activate(mob/living/carbon/human/H, connected, flags) +/datum/mutation/monkey/activate(mob/living/carbon/human/H) if(!istype(H)) return if(issmall(H)) @@ -43,7 +43,7 @@ return H -/datum/dna/gene/monkey/deactivate(mob/living/carbon/human/H, connected, flags) +/datum/mutation/monkey/deactivate(mob/living/carbon/human/H) if(!istype(H)) return if(!issmall(H)) diff --git a/code/game/dna/mutations/powers.dm b/code/game/dna/mutations/powers.dm new file mode 100644 index 00000000000..c2590fd227d --- /dev/null +++ b/code/game/dna/mutations/powers.dm @@ -0,0 +1,1181 @@ +/////////////////////////////////// +// POWERS +/////////////////////////////////// + +/datum/mutation/nobreath + name = "No Breathing" + activation_messages = list("You feel no need to breathe.") + deactivation_messages = list("You feel the need to breathe, once more.") + instability = GENE_INSTABILITY_MODERATE + traits_to_add = list(TRAIT_NOBREATH) + activation_prob = 25 + +/datum/mutation/nobreath/New() + ..() + block = GLOB.breathlessblock + + +/datum/mutation/regenerate + name = "Regenerate" + activation_messages = list("Your wounds start healing.") + deactivation_messages = list("Your regenerative powers feel like they've vanished.") + instability = GENE_INSTABILITY_MINOR + +/datum/mutation/regenerate/New() + ..() + block = GLOB.regenerateblock + +/datum/mutation/regenerate/on_life(mob/living/carbon/human/H) + H.adjustBruteLoss(-0.1, FALSE) + H.adjustFireLoss(-0.1) + +/datum/mutation/increaserun + name = "Super Speed" + activation_messages = list("You feel swift and unencumbered.") + deactivation_messages = list("You feel slow.") + instability = GENE_INSTABILITY_MINOR + traits_to_add = list(TRAIT_IGNORESLOWDOWN) + +/datum/mutation/increaserun/New() + ..() + block = GLOB.increaserunblock + +/datum/mutation/increaserun/can_activate(mob/M, flags) + if(!..()) + return FALSE + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.dna.species && H.dna.species.speed_mod && !(flags & MUTCHK_FORCED)) + return FALSE + return TRUE + +/datum/mutation/heat_resist + name = "Heat Resistance" + activation_messages = list("Your skin is icy to the touch.") + deactivation_messages = list("Your skin no longer feels icy to the touch.") + instability = GENE_INSTABILITY_MODERATE + traits_to_add = list(TRAIT_RESISTHEAT, TRAIT_RESISTHIGHPRESSURE) + +/datum/mutation/heat_resist/New() + ..() + block = GLOB.coldblock + +/datum/mutation/heat_resist/on_draw_underlays(mob/M, g) + return "cold_s" + +/datum/mutation/cold_resist + name = "Cold Resistance" + activation_messages = list("Your body is filled with warmth.") + deactivation_messages = list("Your body is no longer filled with warmth.") + instability = GENE_INSTABILITY_MODERATE + traits_to_add = list(TRAIT_RESISTCOLD, TRAIT_RESISTLOWPRESSURE) + +/datum/mutation/cold_resist/New() + ..() + block = GLOB.fireblock + +/datum/mutation/cold_resist/on_draw_underlays(mob/M, g) + return "fire_s" + +/datum/mutation/noprints + name = "No Prints" + activation_messages = list("Your fingers feel numb.") + deactivation_messages = list("your fingers no longer feel numb.") + instability = GENE_INSTABILITY_MINOR + traits_to_add = list(TRAIT_NOFINGERPRINTS) + +/datum/mutation/noprints/New() + ..() + block = GLOB.noprintsblock + +/datum/mutation/noshock + name = "Shock Immunity" + activation_messages = list("Your skin feels dry and unreactive.") + deactivation_messages = list("Your skin no longer feels dry and unreactive.") + instability = GENE_INSTABILITY_MODERATE + traits_to_add = list(TRAIT_SHOCKIMMUNE) + +/datum/mutation/noshock/New() + ..() + block = GLOB.shockimmunityblock + +/datum/mutation/midget + name = "Midget" + activation_messages = list("Everything around you seems bigger now...") + deactivation_messages = list("Everything around you seems to shrink...") + instability = GENE_INSTABILITY_MINOR + traits_to_add = list(TRAIT_DWARF) + +/datum/mutation/midget/New() + ..() + block = GLOB.smallsizeblock + +/datum/mutation/midget/activate(mob/M) + ..() + M.pass_flags |= PASSTABLE + M.resize = 0.8 + M.update_transform() + +/datum/mutation/midget/deactivate(mob/M) + ..() + M.pass_flags &= ~PASSTABLE + M.resize = 1.25 + M.update_transform() + +// OLD HULK BEHAVIOR +/datum/mutation/hulk + name = "Hulk" + activation_messages = list("Your muscles hurt.") + deactivation_messages = list("Your muscles shrink.") + instability = GENE_INSTABILITY_MAJOR + traits_to_add = list(TRAIT_HULK, TRAIT_CHUNKYFINGERS) + activation_prob = 15 + +/datum/mutation/hulk/New() + ..() + block = GLOB.hulkblock + +/datum/mutation/hulk/activate(mob/M) + ..() + var/status = CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH + M.status_flags &= ~status + +/datum/mutation/hulk/deactivate(mob/M) + ..() + M.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH + +/datum/mutation/hulk/on_draw_underlays(mob/M, g) + return "hulk_[g]_s" + +/datum/mutation/hulk/on_life(mob/living/carbon/human/M) + if(!istype(M)) + return + if(M.health <= 0) + M.dna.SetSEState(GLOB.hulkblock, 0) + singlemutcheck(M, GLOB.hulkblock, MUTCHK_FORCED) + M.update_mutations() //update our mutation overlays + M.update_body() + M.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH //temporary fix until the problem can be solved. + to_chat(M, "You suddenly feel very weak.") + +/datum/mutation/xray + name = "X-Ray Vision" + activation_messages = list("The walls suddenly disappear.") + deactivation_messages = list("the walls around you re-appear.") + instability = GENE_INSTABILITY_MAJOR + traits_to_add = list(TRAIT_XRAY_VISION) + activation_prob = 15 + +/datum/mutation/xray/New() + ..() + block = GLOB.xrayblock + +/datum/mutation/xray/activate(mob/living/M) + ..() + M.update_sight() + M.update_icons() //Apply eyeshine as needed. + +/datum/mutation/xray/deactivate(mob/living/M) + ..() + M.update_sight() + M.update_icons() //Remove eyeshine as needed. + +/datum/mutation/tk + name = "Telekenesis" + activation_messages = list("You feel smarter.") + deactivation_messages = list("You feel dumber.") + instability = GENE_INSTABILITY_MAJOR + activation_prob = 15 + +/datum/mutation/tk/New() + ..() + block = GLOB.teleblock + +/datum/mutation/tk/on_draw_underlays(mob/M, g) + return "telekinesishead_s" + +#define EAT_MOB_DELAY 300 // 30s + +// WAS: /datum/bioEffect/alcres +/datum/mutation/sober + name = "Sober" + activation_messages = list("You feel unusually sober.") + deactivation_messages = list("You feel like you could use a stiff drink.") + + traits_to_add = list(TRAIT_ALCOHOL_TOLERANCE) + +/datum/mutation/sober/New() + ..() + block = GLOB.soberblock + +//WAS: /datum/bioEffect/psychic_resist +/datum/mutation/psychic_resist + name = "Psy-Resist" + desc = "Boosts efficiency in sectors of the brain commonly associated with meta-mental energies." + activation_messages = list("Your mind feels closed.") + deactivation_messages = list("You feel oddly exposed.") + +/datum/mutation/psychic_resist/New() + ..() + block = GLOB.psyresistblock + +///////////////////////// +// Stealth Enhancers +///////////////////////// + +/datum/mutation/stealth + instability = GENE_INSTABILITY_MODERATE + +/datum/mutation/stealth/can_activate(mob/M, flags) + // Can only activate one of these at a time. + if(is_type_in_list(/datum/mutation/stealth, M.active_mutations)) + testing("Cannot activate [type]: /datum/mutation/stealth in M.active_mutations.") + return FALSE + return ..() + +/datum/mutation/stealth/deactivate(mob/living/M) + ..() + M.alpha = 255 + +// WAS: /datum/bioEffect/darkcloak +/datum/mutation/stealth/darkcloak + name = "Cloak of Darkness" + desc = "Enables the subject to bend low levels of light around themselves, creating a cloaking effect." + activation_messages = list("You begin to fade into the shadows.") + deactivation_messages = list("You become fully visible.") + activation_prob = 25 + +/datum/mutation/stealth/darkcloak/New() + ..() + block = GLOB.shadowblock + +/datum/mutation/stealth/darkcloak/on_life(mob/M) + var/turf/simulated/T = get_turf(M) + if(!istype(T)) + return + var/light_available = T.get_lumcount() * 10 + if(light_available <= 2) + M.alpha = round(M.alpha * 0.8) + else + M.alpha = 255 + +//WAS: /datum/bioEffect/chameleon +/datum/mutation/stealth/chameleon + name = "Chameleon" + desc = "The subject becomes able to subtly alter light patterns to become invisible, as long as they remain still." + activation_messages = list("You feel one with your surroundings.") + deactivation_messages = list("You feel oddly visible.") + activation_prob = 25 + +/datum/mutation/stealth/chameleon/New() + ..() + block = GLOB.chameleonblock + +/datum/mutation/stealth/chameleon/on_life(mob/M) + if((world.time - M.last_movement) >= 30 && !M.stat && M.canmove && !M.restrained()) + M.alpha -= 25 + else + M.alpha = round(255 * 0.80) + +///////////////////////////////////////////////////////////////////////////////////////// + +/datum/mutation/grant_spell + var/obj/effect/proc_holder/spell/spelltype + +/datum/mutation/grant_spell/activate(mob/M) + M.AddSpell(new spelltype(null)) + ..() + return TRUE + +/datum/mutation/grant_spell/deactivate(mob/M) + for(var/obj/effect/proc_holder/spell/S in M.mob_spell_list) + if(istype(S, spelltype)) + M.RemoveSpell(S) + ..() + return TRUE + +// WAS: /datum/bioEffect/cryokinesis +/datum/mutation/grant_spell/cryo + name = "Cryokinesis" + desc = "Allows the subject to lower the body temperature of others." + activation_messages = list("You notice a strange cold tingle in your fingertips.") + deactivation_messages = list("Your fingers feel warmer.") + instability = GENE_INSTABILITY_MODERATE + spelltype = /obj/effect/proc_holder/spell/targeted/click/cryokinesis + +/datum/mutation/grant_spell/cryo/New() + ..() + block = GLOB.cryoblock + +/obj/effect/proc_holder/spell/targeted/click/cryokinesis + name = "Cryokinesis" + desc = "Drops the bodytemperature of another person." + panel = "Abilities" + + charge_type = "recharge" + charge_max = 1200 + + clothes_req = FALSE + stat_allowed = FALSE + + click_radius = 0 + auto_target_single = FALSE // Give the clueless geneticists a way out and to have them not target themselves + selection_activated_message = "Your mind grow cold. Click on a target to cast the spell." + selection_deactivated_message = "Your mind returns to normal." + allowed_type = /mob/living/carbon + invocation_type = "none" + range = 7 + selection_type = "range" + include_user = TRUE + var/list/compatible_mobs = list(/mob/living/carbon/human) + + action_icon_state = "genetic_cryo" + +/obj/effect/proc_holder/spell/targeted/click/cryokinesis/cast(list/targets, mob/user = usr) + + var/mob/living/carbon/C = targets[1] + + if(HAS_TRAIT(C, TRAIT_RESISTCOLD)) + C.visible_message("A cloud of fine ice crystals engulfs [C.name], but disappears almost instantly!") + return + var/handle_suit = FALSE + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(istype(H.head, /obj/item/clothing/head/helmet/space)) + if(istype(H.wear_suit, /obj/item/clothing/suit/space)) + handle_suit = TRUE + if(H.internal) + H.visible_message("[user] sprays a cloud of fine ice crystals, engulfing [H]!", + "[user] sprays a cloud of fine ice crystals over your [H.head]'s visor.") + else + H.visible_message("[user] sprays a cloud of fine ice crystals engulfing, [H]!", + "[user] sprays a cloud of fine ice crystals cover your [H.head]'s visor and make it into your air vents!.") + + H.bodytemperature = max(0, H.bodytemperature - 100) + add_attack_logs(user, C, "Cryokinesis") + if(!handle_suit) + C.bodytemperature = max(0, C.bodytemperature - 200) + C.ExtinguishMob() + + C.visible_message("[user] sprays a cloud of fine ice crystals, engulfing [C]!") + add_attack_logs(user, C, "Cryokinesis- NO SUIT/INTERNALS") + +/////////////////////////////////////////////////////////////////////////////////////////// + +// WAS: /datum/bioEffect/mattereater +/datum/mutation/grant_spell/mattereater + name = "Matter Eater" + desc = "Allows the subject to eat just about anything without harm." + activation_messages = list("You feel hungry.") + deactivation_messages = list("You don't feel quite so hungry anymore.") + instability = GENE_INSTABILITY_MINOR + + spelltype=/obj/effect/proc_holder/spell/targeted/eat + +/datum/mutation/grant_spell/mattereater/New() + ..() + block = GLOB.eatblock + +/obj/effect/proc_holder/spell/targeted/eat + name = "Eat" + desc = "Eat just about anything!" + panel = "Abilities" + + charge_type = "recharge" + charge_max = 300 + + clothes_req = 0 + stat_allowed = 0 + invocation_type = "none" + range = 1 + selection_type = "view" + + action_icon_state = "genetic_eat" + + var/list/types_allowed = list( + /obj/item, + /mob/living/simple_animal/pet, + /mob/living/simple_animal/hostile, + /mob/living/simple_animal/parrot, + /mob/living/simple_animal/crab, + /mob/living/simple_animal/mouse, + /mob/living/carbon/human, + /mob/living/simple_animal/slime, + /mob/living/carbon/alien/larva, + /mob/living/simple_animal/slime, + /mob/living/simple_animal/chick, + /mob/living/simple_animal/chicken, + /mob/living/simple_animal/lizard, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/spiderbot + ) + var/list/own_blacklist = list( + /obj/item/organ, + /obj/item/implant + ) + +/obj/effect/proc_holder/spell/targeted/eat/proc/doHeal(mob/user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + for(var/name in H.bodyparts_by_name) + var/obj/item/organ/external/affecting = null + if(!H.bodyparts_by_name[name]) + continue + affecting = H.bodyparts_by_name[name] + if(!istype(affecting, /obj/item/organ/external)) + continue + affecting.heal_damage(4, 0, updating_health = FALSE) + H.UpdateDamageIcon() + H.updatehealth() + +/obj/effect/proc_holder/spell/targeted/eat/choose_targets(mob/user = usr) + var/list/targets = new /list() + var/list/possible_targets = new /list() + + if(!check_mouth(user)) + revert_cast(user) + return + + for(var/atom/movable/O in view_or_range(range, user, selection_type)) + if((O in user) && is_type_in_list(O,own_blacklist)) + continue + if(is_type_in_list(O,types_allowed)) + if(isanimal(O)) + var/mob/living/simple_animal/SA = O + if(!SA.gold_core_spawnable) + continue + possible_targets += O + + targets += input("Choose the target of your hunger.", "Targeting") as null|anything in possible_targets + + if(!targets.len || !targets[1]) //doesn't waste the spell + revert_cast(user) + return + + if(!check_mouth(user)) + revert_cast(user) + return + + perform(targets, user = user) + +/obj/effect/proc_holder/spell/targeted/eat/proc/check_mouth(mob/user = usr) + var/can_eat = TRUE + if(iscarbon(user)) + var/mob/living/carbon/C = user + if((C.head && (C.head.flags_cover & HEADCOVERSMOUTH)) || (C.wear_mask && (C.wear_mask.flags_cover & MASKCOVERSMOUTH) && !C.wear_mask.mask_adjusted)) + to_chat(C, "Your mouth is covered, preventing you from eating!") + can_eat = FALSE + return can_eat + +/obj/effect/proc_holder/spell/targeted/eat/cast(list/targets, mob/user = usr) + if(!targets.len) + to_chat(user, "No target found in range.") + return + + var/atom/movable/the_item = targets[1] + if(ishuman(the_item)) + var/mob/living/carbon/human/H = the_item + var/obj/item/organ/external/limb = H.get_organ(user.zone_selected) + if(!istype(limb)) + to_chat(user, "You can't eat this part of them!") + revert_cast() + return FALSE + if(istype(limb,/obj/item/organ/external/head)) + // Bullshit, but prevents being unable to clone someone. + to_chat(user, "You try to put \the [limb] in your mouth, but [the_item.p_their()] ears tickle your throat!") + revert_cast() + return FALSE + if(istype(limb,/obj/item/organ/external/chest)) + // Bullshit, but prevents being able to instagib someone. + to_chat(user, "You try to put [the_item.p_their()] [limb] in your mouth, but it's too big to fit!") + revert_cast() + return FALSE + user.visible_message("[user] begins stuffing [the_item]'s [limb.name] into [user.p_their()] gaping maw!") + var/oldloc = H.loc + if(!do_mob(user,H,EAT_MOB_DELAY)) + to_chat(user, "You were interrupted before you could eat [the_item]!") + else + if(!limb || !H) + return + if(H.loc != oldloc) + to_chat(user, "\The [limb] moved away from your mouth!") + return + user.visible_message("[user] [pick("chomps","bites")] off [the_item]'s [limb]!") + playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0) + limb.droplimb(0, DROPLIMB_SHARP) + doHeal(user) + else + user.visible_message("[user] eats \the [the_item].") + playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0) + qdel(the_item) + doHeal(user) + +//////////////////////////////////////////////////////////////////////// + +//WAS: /datum/bioEffect/jumpy +/datum/mutation/grant_spell/jumpy + name = "Jumpy" + desc = "Allows the subject to leap great distances." + //cooldown = 30 + activation_messages = list("Your leg muscles feel taut and strong.") + deactivation_messages = list("Your leg muscles shrink back to normal.") + instability = GENE_INSTABILITY_MINOR + + spelltype =/obj/effect/proc_holder/spell/targeted/leap + +/datum/mutation/grant_spell/jumpy/New() + ..() + block = GLOB.jumpblock + +/obj/effect/proc_holder/spell/targeted/leap + name = "Jump" + desc = "Leap great distances!" + panel = "Abilities" + range = -1 + include_user = 1 + + charge_type = "recharge" + charge_max = 60 + + clothes_req = 0 + stat_allowed = 0 + invocation_type = "none" + + action_icon_state = "genetic_jump" + +/obj/effect/proc_holder/spell/targeted/leap/cast(list/targets, mob/user = usr) + var/failure = FALSE + if(istype(user.loc,/mob/) || user.lying || user.stunned || user.buckled || user.stat) + to_chat(user, "You can't jump right now!") + return + + if(istype(user.loc,/turf/)) + if(user.restrained())//Why being pulled while cuffed prevents you from moving + for(var/mob/M in range(user, 1)) + if(M.pulling == user) + if(!M.restrained() && M.stat == 0 && M.canmove && user.Adjacent(M)) + failure = TRUE + else + M.stop_pulling() + + user.visible_message("[user.name] takes a huge leap!") + playsound(user.loc, 'sound/weapons/thudswoosh.ogg', 50, 1) + if(failure) + user.Weaken(5) + user.Stun(5) + user.visible_message("[user] attempts to leap away but is slammed back down to the ground!", + "You attempt to leap away but are suddenly slammed back down to the ground!", + "You hear the flexing of powerful muscles and suddenly a crash as a body hits the floor.") + return FALSE + var/prevLayer = user.layer + var/prevFlying = user.flying + user.layer = 9 + + user.flying = TRUE + for(var/i=0, i<10, i++) + step(user, user.dir) + if(i < 5) user.pixel_y += 8 + else user.pixel_y -= 8 + sleep(1) + user.flying = prevFlying + + if(HAS_TRAIT(user, TRAIT_FAT) && prob(66)) + user.visible_message("[user.name] crashes due to [user.p_their()] heavy weight!") + //playsound(user.loc, 'zhit.wav', 50, 1) + user.AdjustWeakened(10) + user.AdjustStunned(5) + + user.layer = prevLayer + + if(istype(user.loc,/obj/)) + var/obj/container = user.loc + to_chat(user, "You leap and slam your head against the inside of [container]! Ouch!") + user.AdjustParalysis(3) + user.AdjustWeakened(5) + container.visible_message("[user.loc] emits a loud thump and rattles a bit.") + playsound(user.loc, 'sound/effects/bang.ogg', 50, 1) + var/wiggle = 6 + while(wiggle > 0) + wiggle-- + container.pixel_x = rand(-3,3) + container.pixel_y = rand(-3,3) + sleep(1) + container.pixel_x = 0 + container.pixel_y = 0 + +//////////////////////////////////////////////////////////////////////// + +// WAS: /datum/bioEffect/polymorphism + +/datum/mutation/grant_spell/polymorph + name = "Polymorphism" + desc = "Enables the subject to reconfigure their appearance to mimic that of others." + + spelltype =/obj/effect/proc_holder/spell/targeted/click/polymorph + //cooldown = 1800 + activation_messages = list("You don't feel entirely like yourself somehow.") + deactivation_messages = list("You feel secure in your identity.") + instability = GENE_INSTABILITY_MODERATE + +/datum/mutation/grant_spell/polymorph/New() + ..() + block = GLOB.polymorphblock + +/obj/effect/proc_holder/spell/targeted/click/polymorph + name = "Polymorph" + desc = "Mimic the appearance of others!" + panel = "Abilities" + charge_max = 1800 + + clothes_req = FALSE + stat_allowed = FALSE + + click_radius = -1 // Precision required + auto_target_single = FALSE // Safety to not turn into monkey (420) + selection_activated_message = "You body becomes unstable. Click on a target to cast transform into them." + selection_deactivated_message = "Your body calms down again." + allowed_type = /mob/living/carbon/human + + invocation_type = "none" + range = 1 + selection_type = "range" + + action_icon_state = "genetic_poly" + +/obj/effect/proc_holder/spell/targeted/click/polymorph/cast(list/targets, mob/user = usr) + var/mob/living/carbon/human/target = targets[1] + + user.visible_message("[user]'s body shifts and contorts.") + + spawn(10) + if(target && user) + playsound(user.loc, 'sound/goonstation/effects/gib.ogg', 50, 1) + var/mob/living/carbon/human/H = user + H.UpdateAppearance(target.dna.UI) + H.real_name = target.real_name + H.name = target.name + +//////////////////////////////////////////////////////////////////////// + +// WAS: /datum/bioEffect/empath +/datum/mutation/grant_spell/empath + name = "Empathic Thought" + desc = "The subject becomes able to read the minds of others for certain information." + + spelltype = /obj/effect/proc_holder/spell/targeted/empath + activation_messages = list("You suddenly notice more about others than you did before.") + deactivation_messages = list("You no longer feel able to sense intentions.") + instability = GENE_INSTABILITY_MINOR + +/datum/mutation/grant_spell/empath/New() + ..() + block = GLOB.empathblock + +/obj/effect/proc_holder/spell/targeted/empath + name = "Read Mind" + desc = "Read the minds of others for information." + charge_max = 180 + clothes_req = FALSE + human_req = TRUE + stat_allowed = CONSCIOUS + invocation_type = "none" + range = -2 + selection_type = "range" + + action_icon_state = "genetic_empath" + +/obj/effect/proc_holder/spell/targeted/empath/choose_targets(mob/user = usr) + var/list/possible_targets = list() + for(var/mob/living/carbon/C in range(7, user)) + possible_targets += C + var/target = input("Choose the target to spy on.", "Targeting") as null|mob in possible_targets + + if(!target) //doesn't waste the spell + revert_cast(user) + return + + perform(list(target), user = user) + +/obj/effect/proc_holder/spell/targeted/empath/cast(list/targets, mob/user = usr) + for(var/mob/living/carbon/M in targets) + if(!iscarbon(M)) + to_chat(user, "You may only use this on other organic beings.") + return + + if(M.dna?.GetSEState(GLOB.psyresistblock)) + to_chat(user, "You can't see into [M.name]'s mind at all!") + return + + if(M.stat == 2) + to_chat(user, "[M.name] is dead and cannot have [M.p_their()] mind read.") + return + if(M.health < 0) + to_chat(user, "[M.name] is dying, and [M.p_their()] thoughts are too scrambled to read.") + return + + to_chat(user, "Mind Reading of [M.name]:") + + var/pain_condition = M.health / M.maxHealth + // lower health means more pain + var/list/randomthoughts = list("what to have for lunch","the future","the past","money", + "[M.p_their()] hair","what to do next","[M.p_their()] job","space","amusing things","sad things", + "annoying things","happy things","something incoherent","something [M.p_they()] did wrong") + var/thoughts = "thinking about [pick(randomthoughts)]" + + if(M.fire_stacks) + pain_condition -= 0.5 + thoughts = "preoccupied with the fire" + + if(M.radiation) + pain_condition -= 0.25 + + switch(pain_condition) + if(0.81 to INFINITY) + to_chat(user, "Condition: [M.name] feels good.") + if(0.61 to 0.8) + to_chat(user, "Condition: [M.name] is suffering mild pain.") + if(0.41 to 0.6) + to_chat(user, "Condition: [M.name] is suffering significant pain.") + if(0.21 to 0.4) + to_chat(user, "Condition: [M.name] is suffering severe pain.") + else + to_chat(user, "Condition: [M.name] is suffering excruciating pain.") + thoughts = "haunted by [M.p_their()] own mortality" + + switch(M.a_intent) + if(INTENT_HELP) + to_chat(user, "Mood: You sense benevolent thoughts from [M.name].") + if(INTENT_DISARM) + to_chat(user, "Mood: You sense cautious thoughts from [M.name].") + if(INTENT_GRAB) + to_chat(user, "Mood: You sense hostile thoughts from [M.name].") + if(INTENT_HARM) + to_chat(user, "Mood: You sense cruel thoughts from [M.name].") + for(var/mob/living/L in view(7,M)) + if(L == M) + continue + thoughts = "thinking about punching [L.name]" + break + else + to_chat(user, "Mood: You sense strange thoughts from [M.name].") + + if(istype(M,/mob/living/carbon/human)) + var/numbers[0] + var/mob/living/carbon/human/H = M + if(H.mind && H.mind.initial_account) + numbers += H.mind.initial_account.account_number + numbers += H.mind.initial_account.remote_access_pin + if(numbers.len>0) + to_chat(user, "Numbers: You sense the number[numbers.len>1?"s":""] [english_list(numbers)] [numbers.len>1?"are":"is"] important to [M.name].") + to_chat(user, "Thoughts: [M.name] is currently [thoughts].") + + if(M.dna?.GetSEState(GLOB.empathblock)) + to_chat(M, "You sense [user.name] reading your mind.") + else if(prob(5) || M.mind.assigned_role=="Chaplain") + to_chat(M, "You sense someone intruding upon your thoughts...") + +///////////////////Vanilla Morph//////////////////////////////////// + +/datum/mutation/grant_spell/morph + name = "Morphism" + desc = "Enables the subject to reconfigure their appearance to that of any human." + spelltype =/obj/effect/proc_holder/spell/targeted/morph + activation_messages = list("Your body feels if can alter its appearance.") + deactivation_messages = list("Your body doesn't feel capable of altering its appearance.") + instability = GENE_INSTABILITY_MINOR + +/datum/mutation/grant_spell/morph/New() + ..() + block = GLOB.morphblock + +/obj/effect/proc_holder/spell/targeted/morph + name = "Morph" + desc = "Mimic the appearance of your choice!" + panel = "Abilities" + charge_max = 1800 + + clothes_req = 0 + stat_allowed = 0 + invocation_type = "none" + range = -1 + include_user = 1 + selection_type = "range" + + action_icon_state = "genetic_morph" + +/obj/effect/proc_holder/spell/targeted/morph/cast(list/targets, mob/user = usr) + if(!ishuman(user)) + return + + if(istype(user.loc,/mob/)) + to_chat(user, "You can't change your appearance right now!") + return + var/mob/living/carbon/human/M = user + var/obj/item/organ/external/head/head_organ = M.get_organ("head") + var/obj/item/organ/internal/eyes/eyes_organ = M.get_int_organ(/obj/item/organ/internal/eyes) + + var/new_gender = alert(user, "Please select gender.", "Character Generation", "Male", "Female") + if(new_gender) + if(new_gender == "Male") + M.change_gender(MALE) + else + M.change_gender(FEMALE) + + var/new_eyes = input("Please select eye color.", "Character Generation", eyes_organ.eye_colour) as null|color + if(new_eyes) + M.change_eye_color(new_eyes) + + //Alt heads. + if(head_organ.dna.species.bodyflags & HAS_ALT_HEADS) + var/list/valid_alt_heads = M.generate_valid_alt_heads() + var/new_alt_head = input("Please select alternate head", "Character Generation", head_organ.alt_head) as null|anything in valid_alt_heads + if(new_alt_head) + M.change_alt_head(new_alt_head) + + // hair + var/list/valid_hairstyles = M.generate_valid_hairstyles() + var/new_style = input("Please select hair style", "Character Generation", head_organ.h_style) as null|anything in valid_hairstyles + + // if new style selected (not cancel) + if(new_style) + M.change_hair(new_style) + + var/new_hair = input("Please select hair color.", "Character Generation", head_organ.hair_colour) as null|color + if(new_hair) + M.change_hair_color(new_hair) + + var/datum/sprite_accessory/hair_style = GLOB.hair_styles_public_list[head_organ.h_style] + if(hair_style.secondary_theme && !hair_style.no_sec_colour) + new_hair = input("Please select secondary hair color.", "Character Generation", head_organ.sec_hair_colour) as null|color + if(new_hair) + M.change_hair_color(new_hair, 1) + + // facial hair + var/list/valid_facial_hairstyles = M.generate_valid_facial_hairstyles() + new_style = input("Please select facial style", "Character Generation", head_organ.f_style) as null|anything in valid_facial_hairstyles + + if(new_style) + M.change_facial_hair(new_style) + + var/new_facial = input("Please select facial hair color.", "Character Generation", head_organ.facial_colour) as null|color + if(new_facial) + M.change_facial_hair_color(new_facial) + + var/datum/sprite_accessory/facial_hair_style = GLOB.facial_hair_styles_list[head_organ.f_style] + if(facial_hair_style.secondary_theme && !facial_hair_style.no_sec_colour) + new_facial = input("Please select secondary facial hair color.", "Character Generation", head_organ.sec_facial_colour) as null|color + if(new_facial) + M.change_facial_hair_color(new_facial, 1) + + //Head accessory. + if(head_organ.dna.species.bodyflags & HAS_HEAD_ACCESSORY) + var/list/valid_head_accessories = M.generate_valid_head_accessories() + var/new_head_accessory = input("Please select head accessory style", "Character Generation", head_organ.ha_style) as null|anything in valid_head_accessories + if(new_head_accessory) + M.change_head_accessory(new_head_accessory) + + var/new_head_accessory_colour = input("Please select head accessory colour.", "Character Generation", head_organ.headacc_colour) as null|color + if(new_head_accessory_colour) + M.change_head_accessory_color(new_head_accessory_colour) + + //Body accessory. + if(M.dna.species.tail && M.dna.species.bodyflags & HAS_TAIL) + var/list/valid_body_accessories = M.generate_valid_body_accessories() + if(valid_body_accessories.len > 1) //By default valid_body_accessories will always have at the very least a 'none' entry populating the list, even if the user's species is not present in any of the list items. + var/new_body_accessory = input("Please select body accessory style", "Character Generation", M.body_accessory) as null|anything in valid_body_accessories + if(new_body_accessory) + M.change_body_accessory(new_body_accessory) + + //Head markings. + if(M.dna.species.bodyflags & HAS_HEAD_MARKINGS) + var/list/valid_head_markings = M.generate_valid_markings("head") + var/new_marking = input("Please select head marking style", "Character Generation", M.m_styles["head"]) as null|anything in valid_head_markings + if(new_marking) + M.change_markings(new_marking, "head") + + var/new_marking_colour = input("Please select head marking colour.", "Character Generation", M.m_colours["head"]) as null|color + if(new_marking_colour) + M.change_marking_color(new_marking_colour, "head") + //Body markings. + if(M.dna.species.bodyflags & HAS_BODY_MARKINGS) + var/list/valid_body_markings = M.generate_valid_markings("body") + var/new_marking = input("Please select body marking style", "Character Generation", M.m_styles["body"]) as null|anything in valid_body_markings + if(new_marking) + M.change_markings(new_marking, "body") + + var/new_marking_colour = input("Please select body marking colour.", "Character Generation", M.m_colours["body"]) as null|color + if(new_marking_colour) + M.change_marking_color(new_marking_colour, "body") + //Tail markings. + if(M.dna.species.bodyflags & HAS_TAIL_MARKINGS) + var/list/valid_tail_markings = M.generate_valid_markings("tail") + var/new_marking = input("Please select tail marking style", "Character Generation", M.m_styles["tail"]) as null|anything in valid_tail_markings + if(new_marking) + M.change_markings(new_marking, "tail") + + var/new_marking_colour = input("Please select tail marking colour.", "Character Generation", M.m_colours["tail"]) as null|color + if(new_marking_colour) + M.change_marking_color(new_marking_colour, "tail") + + //Skin tone. + if(M.dna.species.bodyflags & HAS_SKIN_TONE) + var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", M.s_tone) as null|text + if(!new_tone) + new_tone = 35 + else + new_tone = 35 - max(min(round(text2num(new_tone)), 220), 1) + M.change_skin_tone(new_tone) + + if(M.dna.species.bodyflags & HAS_ICON_SKIN_TONE) + var/prompt = "Please select skin tone: 1-[M.dna.species.icon_skin_tones.len] (" + for(var/i = 1 to M.dna.species.icon_skin_tones.len) + prompt += "[i] = [M.dna.species.icon_skin_tones[i]]" + if(i != M.dna.species.icon_skin_tones.len) + prompt += ", " + prompt += ")" + + var/new_tone = input(prompt, "Character Generation", M.s_tone) as null|text + if(!new_tone) + new_tone = 0 + else + new_tone = max(min(round(text2num(new_tone)), M.dna.species.icon_skin_tones.len), 1) + M.change_skin_tone(new_tone) + + //Skin colour. + if(M.dna.species.bodyflags & HAS_SKIN_COLOR) + var/new_body_colour = input("Please select body colour.", "Character Generation", M.skin_colour) as null|color + if(new_body_colour) + M.change_skin_color(new_body_colour) + + M.update_dna() + + M.visible_message("[M] morphs and changes [M.p_their()] appearance!", "You change your appearance!", "Oh, god! What the hell was that? It sounded like flesh getting squished and bone ground into a different shape!") + +/datum/mutation/grant_spell/remotetalk + name = "Telepathy" + activation_messages = list("You feel you can project your thoughts.") + deactivation_messages = list("You no longer feel you can project your thoughts.") + instability = GENE_INSTABILITY_MINOR + + spelltype =/obj/effect/proc_holder/spell/targeted/remotetalk + +/datum/mutation/grant_spell/remotetalk/New() + ..() + block = GLOB.remotetalkblock + +/datum/mutation/grant_spell/remotetalk/activate(mob/living/M) + ..() + M.AddSpell(new /obj/effect/proc_holder/spell/targeted/mindscan(null)) + +/datum/mutation/grant_spell/remotetalk/deactivate(mob/user) + ..() + for(var/obj/effect/proc_holder/spell/S in user.mob_spell_list) + if(istype(S, /obj/effect/proc_holder/spell/targeted/mindscan)) + user.RemoveSpell(S) + +/obj/effect/proc_holder/spell/targeted/remotetalk + name = "Project Mind" + desc = "Make people understand your thoughts!" + charge_max = 0 + + clothes_req = 0 + stat_allowed = 0 + invocation_type = "none" + range = -2 + selection_type = "range" + + action_icon_state = "genetic_project" + +/obj/effect/proc_holder/spell/targeted/remotetalk/choose_targets(mob/user = usr) + var/list/targets = new /list() + var/list/validtargets = user.get_telepathic_targets() + + if(!length(validtargets)) + to_chat(user, "There are no valid targets!") + start_recharge() + return + + var/target_name = input("Choose the target to talk to.", "Targeting") as null|anything in validtargets + + var/mob/living/target + if(!target_name || !(target = validtargets[target_name])) + revert_cast(user) + return + + targets += target + perform(targets, user = user) + +/obj/effect/proc_holder/spell/targeted/remotetalk/cast(list/targets, mob/user = usr) + if(!ishuman(user)) return + var/say = input("What do you wish to say") as text|null + if(!say || usr.stat) + return + say = strip_html(say) + say = pencode_to_html(say, usr, format = 0, fields = 0) + + for(var/mob/living/target in targets) + log_say("(TPATH to [key_name(target)]) [say]", user) + user.create_log(SAY_LOG, "Telepathically said '[say]' using [src]", target) + if(target.dna?.GetSEState(GLOB.remotetalkblock)) + target.show_message("You hear [user.real_name]'s voice: [say]") + else + target.show_message("You hear a voice that seems to echo around the room: [say]") + user.show_message("You project your mind into [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"]: [say]") + for(var/mob/dead/observer/G in GLOB.player_list) + G.show_message("Telepathic message from [user] ([ghost_follow_link(user, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]") + +/obj/effect/proc_holder/spell/targeted/mindscan + name = "Scan Mind" + desc = "Offer people a chance to share their thoughts!" + charge_max = 0 + clothes_req = 0 + stat_allowed = 0 + invocation_type = "none" + range = -2 + selection_type = "range" + action_icon_state = "genetic_mindscan" + var/list/available_targets = list() + +/obj/effect/proc_holder/spell/targeted/mindscan/choose_targets(mob/user = usr) + var/list/targets = list() + var/list/validtargets = user.get_telepathic_targets() + + if(!length(validtargets)) + to_chat(user, "There are no valid targets!") + start_recharge() + return + + var/target_name = input("Choose the target to listen to.", "Targeting") as null|anything in validtargets + + var/mob/living/target + if(!target_name || !(target = validtargets[target_name])) + revert_cast(user) + return + + targets += target + perform(targets, user = user) + +/obj/effect/proc_holder/spell/targeted/mindscan/cast(list/targets, mob/user = usr) + if(!ishuman(user)) + return + for(var/mob/living/target in targets) + var/message = "You feel your mind expand briefly... (Click to send a message.)" + if(target.dna?.GetSEState(GLOB.remotetalkblock)) + message = "You feel [user.real_name] request a response from you... (Click here to project mind.)" + user.show_message("You offer your mind to [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"].") + target.show_message("[message]") + available_targets += target + addtimer(CALLBACK(src, .proc/removeAvailability, target), 100) + +/obj/effect/proc_holder/spell/targeted/mindscan/proc/removeAvailability(mob/living/target) + if(target in available_targets) + available_targets -= target + if(!(target in available_targets)) + target.show_message("You feel the sensation fade...") + +/obj/effect/proc_holder/spell/targeted/mindscan/Topic(href, href_list) + var/mob/living/user + if(href_list["user"]) + user = locateUID(href_list["user"]) + if(href_list["target"]) + if(!user) + return + var/mob/living/target = locateUID(href_list["target"]) + if(!(target in available_targets)) + return + available_targets -= target + var/say = input("What do you wish to say") as text|null + if(!say) + return + say = strip_html(say) + say = pencode_to_html(say, target, format = 0, fields = 0) + user.create_log(SAY_LOG, "Telepathically responded '[say]' using [src]", target) + log_say("(TPATH to [key_name(target)]) [say]", user) + if(target.dna?.GetSEState(GLOB.remotetalkblock)) + target.show_message("You project your mind into [user.name]: [say]") + else + target.show_message("You fill the space in your thoughts: [say]") + user.show_message("You hear [target.name]'s voice: [say]") + for(var/mob/dead/observer/G in GLOB.player_list) + G.show_message("Telepathic response from [target] ([ghost_follow_link(target, ghost=G)]) to [user] ([ghost_follow_link(user, ghost=G)]): [say]") + +/obj/effect/proc_holder/spell/targeted/mindscan/Destroy() + available_targets.Cut() + return ..() + +/datum/mutation/grant_spell/remoteview + name = "Remote Viewing" + activation_messages = list("Your mind can see things from afar.") + deactivation_messages = list("Your mind can no longer can see things from afar.") + instability = GENE_INSTABILITY_MINOR + + spelltype =/obj/effect/proc_holder/spell/targeted/remoteview + +/datum/mutation/grant_spell/remoteview/New() + ..() + block = GLOB.remoteviewblock + + +/obj/effect/proc_holder/spell/targeted/remoteview + name = "Remote View" + desc = "Spy on people from any range!" + charge_max = 100 + + clothes_req = 0 + stat_allowed = 0 + invocation_type = "none" + range = -2 + selection_type = "range" + + action_icon_state = "genetic_view" + +/obj/effect/proc_holder/spell/targeted/remoteview/choose_targets(mob/user = usr) + var/list/targets = list() + var/list/remoteviewers = list() + for(var/mob/M in GLOB.alive_mob_list) + if(M == user) + continue + if(M.dna?.GetSEState(GLOB.psyresistblock)) + continue + if(M.dna?.GetSEState(GLOB.remoteviewblock)) + remoteviewers += M + if(!LAZYLEN(remoteviewers)) + to_chat(user, "No valid targets with remote view were found!") + start_recharge() + return + targets += input("Choose the target to spy on.", "Targeting") as null|anything in remoteviewers + if(!targets) + to_chat(user, "You decide against remote viewing.") + start_recharge() + return + perform(targets, user = user) + +/obj/effect/proc_holder/spell/targeted/remoteview/cast(list/targets, mob/user = usr) + var/mob/living/carbon/human/H + if(ishuman(user)) + H = user + else + return + + var/mob/target + + if(istype(H.l_hand, /obj/item/tk_grab) || istype(H.r_hand, /obj/item/tk_grab)) + to_chat(H, "Your mind is too busy with that telekinetic grab.") + H.remoteview_target = null + H.reset_perspective() + return + + if(H.client.eye != user.client.mob) + H.remoteview_target = null + H.reset_perspective() + return + + for(var/mob/living/L in targets) + target = L + + if(target) + H.remoteview_target = target + H.reset_perspective(target) + else + H.remoteview_target = null + H.reset_perspective() diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index cf02a711d6f..7cdaa6c3017 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -112,7 +112,7 @@ GLOBAL_LIST_INIT(possible_changeling_IDs, list("Alpha","Beta","Gamma","Delta","E if(identity_theft.target && identity_theft.target.current) identity_theft.target_real_name = kill_objective.target.current.real_name //Whoops, forgot this. var/mob/living/carbon/human/H = identity_theft.target.current - if(can_absorb_species(H.dna.species)) // For species that can't be absorbed - should default to an escape objective + if(!HAS_TRAIT(H, TRAIT_GENELESS)) // For species that can't be absorbed - should default to an escape objective identity_theft.explanation_text = "Escape on the shuttle or an escape pod with the identity of [identity_theft.target_real_name], the [identity_theft.target.assigned_role] while wearing [identity_theft.target.p_their()] identification card." changeling.objectives += identity_theft else @@ -139,7 +139,8 @@ GLOBAL_LIST_INIT(possible_changeling_IDs, list("Alpha","Beta","Gamma","Delta","E if(changeling.current.mind) if(changeling.current.mind.assigned_role == "Clown") to_chat(changeling.current, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.") - changeling.current.mutations.Remove(CLUMSY) + changeling.current.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(changeling.current, GLOB.clumsyblock, MUTCHK_FORCED) var/datum/action/innate/toggle_clumsy/A = new A.Grant(changeling.current) var/obj_count = 1 @@ -315,11 +316,11 @@ GLOBAL_LIST_INIT(possible_changeling_IDs, list("Alpha","Beta","Gamma","Delta","E to_chat(user, "[T] is not compatible with our biology.") return - if((NOCLONE || SKELETON || HUSK) in T.mutations) + if(HAS_TRAIT(T, TRAIT_BADDNA) || HAS_TRAIT(T, TRAIT_HUSK) || HAS_TRAIT(T, TRAIT_SKELETONIZED)) to_chat(user, "DNA of [target] is ruined beyond usability!") return - if(NO_DNA in T.dna.species.species_traits) + if(HAS_TRAIT(T, TRAIT_GENELESS)) to_chat(user, "This creature does not have DNA!") return @@ -327,6 +328,3 @@ GLOBAL_LIST_INIT(possible_changeling_IDs, list("Alpha","Beta","Gamma","Delta","E to_chat(user, "We already have this DNA in storage!") return 1 - -/proc/can_absorb_species(datum/species/S) - return !(NO_DNA in S.species_traits) diff --git a/code/game/gamemodes/changeling/changeling_power.dm b/code/game/gamemodes/changeling/changeling_power.dm index 40daa5735c3..dc5c0f9f90c 100644 --- a/code/game/gamemodes/changeling/changeling_power.dm +++ b/code/game/gamemodes/changeling/changeling_power.dm @@ -73,7 +73,7 @@ the same goes for Remove(). if you override Remove(), call parent or else your p if(req_stat < user.stat) to_chat(user, "We are incapacitated.") return 0 - if((user.status_flags & FAKEDEATH) && name!="Regenerate") + if(HAS_TRAIT(user, TRAIT_FAKEDEATH) && name != "Regenerate") to_chat(user, "We are incapacitated.") return 0 if(c.geneticdamage > max_genetic_damage) diff --git a/code/game/gamemodes/changeling/evolution_menu.dm b/code/game/gamemodes/changeling/evolution_menu.dm index 83453f09b2a..8485f8f0540 100644 --- a/code/game/gamemodes/changeling/evolution_menu.dm +++ b/code/game/gamemodes/changeling/evolution_menu.dm @@ -112,7 +112,7 @@ to_chat(user, "We have reached our capacity for abilities.") return FALSE - if(user.status_flags & FAKEDEATH)//To avoid potential exploits by buying new powers while in stasis, which clears your verblist. + if(HAS_TRAIT(user, TRAIT_FAKEDEATH)) //To avoid potential exploits by buying new powers while in stasis, which clears your verblist. to_chat(user, "We lack the energy to evolve new abilities right now.") return FALSE diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm index 28afcaa9c36..3e7d72cfd42 100644 --- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm +++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm @@ -49,7 +49,7 @@ /obj/item/organ/internal/cyberimp/eyes/shield/ling/on_life() ..() var/obj/item/organ/internal/eyes/E = owner.get_int_organ(/obj/item/organ/internal/eyes) - if(owner.eye_blind || owner.eye_blurry || (BLINDNESS in owner.mutations) || (NEARSIGHTED in owner.mutations) || (E && E.damage > 0)) + if(owner.eye_blind || owner.eye_blurry || HAS_TRAIT(owner, TRAIT_BLIND) || HAS_TRAIT(owner, TRAIT_NEARSIGHT) || (E && E.damage > 0)) owner.reagents.add_reagent("oculine", 1) /obj/item/organ/internal/cyberimp/eyes/shield/ling/prepare_eat() diff --git a/code/game/gamemodes/changeling/powers/chameleon_skin.dm b/code/game/gamemodes/changeling/powers/chameleon_skin.dm index d71758a9c8f..48d9b8e4d6e 100644 --- a/code/game/gamemodes/changeling/powers/chameleon_skin.dm +++ b/code/game/gamemodes/changeling/powers/chameleon_skin.dm @@ -13,10 +13,10 @@ return if(H.dna.GetSEState(GLOB.chameleonblock)) H.dna.SetSEState(GLOB.chameleonblock, 0) - genemutcheck(H, GLOB.chameleonblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.chameleonblock, MUTCHK_FORCED) else H.dna.SetSEState(GLOB.chameleonblock, 1) - genemutcheck(H, GLOB.chameleonblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.chameleonblock, MUTCHK_FORCED) SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]")) return TRUE @@ -25,5 +25,5 @@ var/mob/living/carbon/C = user if(C.dna.GetSEState(GLOB.chameleonblock)) C.dna.SetSEState(GLOB.chameleonblock, 0) - genemutcheck(C, GLOB.chameleonblock, null, MUTCHK_FORCED) + singlemutcheck(C, GLOB.chameleonblock, MUTCHK_FORCED) ..() diff --git a/code/game/gamemodes/changeling/powers/fakedeath.dm b/code/game/gamemodes/changeling/powers/fakedeath.dm index 89586d9672c..343a8e1e1c7 100644 --- a/code/game/gamemodes/changeling/powers/fakedeath.dm +++ b/code/game/gamemodes/changeling/powers/fakedeath.dm @@ -15,7 +15,7 @@ if(user.stat != DEAD) user.emote("deathgasp") user.timeofdeath = world.time - user.status_flags |= FAKEDEATH //play dead + ADD_TRAIT(user, TRAIT_FAKEDEATH, "changeling") //play dead user.updatehealth("fakedeath sting") user.update_canmove() user.mind.changeling.regenerating = TRUE @@ -31,7 +31,7 @@ R.Grant(user) /datum/action/changeling/fakedeath/can_sting(var/mob/user) - if(user.status_flags & FAKEDEATH) + if(HAS_TRAIT(user, TRAIT_FAKEDEATH)) to_chat(user, "We are already regenerating.") return if(!user.stat)//Confirmation for living changelings if they want to fake their death diff --git a/code/game/gamemodes/changeling/powers/humanform.dm b/code/game/gamemodes/changeling/powers/humanform.dm index 90031d4d542..fd00afab30a 100644 --- a/code/game/gamemodes/changeling/powers/humanform.dm +++ b/code/game/gamemodes/changeling/powers/humanform.dm @@ -25,12 +25,12 @@ return 0 to_chat(user, "We transform our appearance.") user.dna.SetSEState(GLOB.monkeyblock,0,1) - genemutcheck(user,GLOB.monkeyblock,null,MUTCHK_FORCED) + singlemutcheck(user,GLOB.monkeyblock, MUTCHK_FORCED) if(istype(user)) user.set_species(chosen_dna.species.type) user.dna = chosen_dna.Clone() user.real_name = chosen_dna.real_name - domutcheck(user,null,MUTCHK_FORCED) + domutcheck(user, MUTCHK_FORCED) user.flavor_text = "" user.dna.UpdateSE() user.dna.UpdateUI() diff --git a/code/game/gamemodes/changeling/powers/revive.dm b/code/game/gamemodes/changeling/powers/revive.dm index b8747ba1162..13b3877b9bb 100644 --- a/code/game/gamemodes/changeling/powers/revive.dm +++ b/code/game/gamemodes/changeling/powers/revive.dm @@ -19,9 +19,9 @@ user.SetEyeBlurry(0, FALSE) user.RestoreEars() user.heal_overall_damage(user.getBruteLoss(), user.getFireLoss(), updating_health = FALSE) - user.CureBlind(FALSE) + user.cure_blind(null, FALSE) user.CureDeaf() - user.CureNearsighted(FALSE) + user.cure_nearsighted(null, FALSE) user.reagents.clear_reagents() user.germ_level = 0 user.timeofdeath = 0 @@ -52,7 +52,7 @@ H.remove_all_embedded_objects() for(var/datum/disease/critical/C in user.viruses) C.cure() - user.status_flags &= ~(FAKEDEATH) + REMOVE_TRAIT(user, TRAIT_FAKEDEATH, "changeling") user.updatehealth("revive sting") user.update_blind_effects() user.update_blurry_effects() diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm index 229122f5291..a049aa0f2d9 100644 --- a/code/game/gamemodes/changeling/powers/shriek.dm +++ b/code/game/gamemodes/changeling/powers/shriek.dm @@ -16,7 +16,7 @@ if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL) continue if(!M.mind || !M.mind.changeling) - M.MinimumDeafTicks(30) + M.AdjustEarDamage(0, 30) M.AdjustConfused(20) M.Jitter(50) else diff --git a/code/game/gamemodes/changeling/powers/strained_muscles.dm b/code/game/gamemodes/changeling/powers/strained_muscles.dm index c05c37fdcf0..038cf76331c 100644 --- a/code/game/gamemodes/changeling/powers/strained_muscles.dm +++ b/code/game/gamemodes/changeling/powers/strained_muscles.dm @@ -17,7 +17,7 @@ if(enabled) to_chat(user, "Our muscles tense and strengthen.") else - user.status_flags &= ~GOTTAGOFAST + REMOVE_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling") to_chat(user, "Our muscles relax.") if(stacks >= 10) to_chat(user, "We collapse in exhaustion.") @@ -25,11 +25,11 @@ user.emote("gasp") while(enabled) - user.status_flags |= GOTTAGOFAST + ADD_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling") if(user.stat || user.staminaloss >= 90) enabled = 0 //Let's use something exact instead of !enabled where we can. to_chat(user, "Our muscles relax without the energy to strengthen them.") - user.status_flags &= ~GOTTAGOFAST + REMOVE_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling") user.Weaken(2) user.emote("gasp") break diff --git a/code/game/gamemodes/changeling/powers/swap_form.dm b/code/game/gamemodes/changeling/powers/swap_form.dm index e392974648c..4c44b97f47e 100644 --- a/code/game/gamemodes/changeling/powers/swap_form.dm +++ b/code/game/gamemodes/changeling/powers/swap_form.dm @@ -15,10 +15,10 @@ to_chat(user, "We must have an aggressive grab on creature in our active hand to do this!") return var/mob/living/carbon/human/target = G.affecting - if((NOCLONE || SKELETON || HUSK) in target.mutations) + if(HAS_TRAIT(target, TRAIT_BADDNA) || HAS_TRAIT(target, TRAIT_HUSK) || HAS_TRAIT(target, TRAIT_SKELETONIZED)) to_chat(user, "DNA of [target] is ruined beyond usability!") return - if(!istype(target) || !target.mind || issmall(target) || (NO_DNA in target.dna.species.species_traits)) + if(!istype(target) || !target.mind || issmall(target) || HAS_TRAIT(target, TRAIT_GENELESS)) to_chat(user, "[target] is not compatible with this ability.") return if(target.mind.changeling) diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index 97fc24c0938..95432db9424 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -94,12 +94,12 @@ /datum/action/changeling/sting/transformation/can_sting(var/mob/user, var/mob/target) if(!..()) return - if((HUSK in target.mutations) || (!ishuman(target))) + if(HAS_TRAIT(target, TRAIT_HUSK) || (!ishuman(target))) to_chat(user, "Our sting appears ineffective against its DNA.") return FALSE if(ishuman(target)) var/mob/living/carbon/human/H = target - if(NO_DNA in H.dna.species.species_traits) + if(HAS_TRAIT(H, TRAIT_GENELESS)) to_chat(user, "This won't work on a creature without DNA.") return FALSE return TRUE @@ -167,7 +167,7 @@ /datum/action/changeling/sting/blind/sting_action(var/mob/living/user, var/mob/living/target) add_attack_logs(user, target, "Blind sting (changeling)") to_chat(target, "Your eyes burn horrifically!") - target.BecomeNearsighted() + target.become_nearsighted(EYE_DAMAGE) target.EyeBlind(20) target.EyeBlurry(40) SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]")) diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index e4d94ecb69f..82f919e1e0c 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -88,7 +88,8 @@ GLOBAL_LIST_EMPTY(all_cults) if(cult_mind.assigned_role == "Clown") to_chat(cult_mind.current, "A dark power has allowed you to overcome your clownish nature, letting you wield weapons without harming yourself.") - cult_mind.current.mutations.Remove(CLUMSY) + cult_mind.current.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(cult_mind.current, GLOB.clumsyblock, MUTCHK_FORCED) var/datum/action/innate/toggle_clumsy/A = new A.Grant(cult_mind.current) @@ -182,7 +183,8 @@ GLOBAL_LIST_EMPTY(all_cults) if(cult_mind.assigned_role == "Clown") to_chat(cult_mind.current, "A dark power has allowed you to overcome your clownish nature, letting you wield weapons without harming yourself.") - cult_mind.current.mutations.Remove(CLUMSY) + cult_mind.current.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(cult_mind.current, GLOB.clumsyblock, MUTCHK_FORCED) var/datum/action/innate/toggle_clumsy/A = new A.Grant(cult_mind.current) SEND_SOUND(cult_mind.current, 'sound/ambience/antag/bloodcult.ogg') diff --git a/code/game/gamemodes/cult/cult_actions.dm b/code/game/gamemodes/cult/cult_actions.dm index c5dd101c3b4..ab81f253a32 100644 --- a/code/game/gamemodes/cult/cult_actions.dm +++ b/code/game/gamemodes/cult/cult_actions.dm @@ -31,7 +31,7 @@ to_chat(user, "You can't speak!") return - if((MUTE in user.mutations) || user.mind.miming) //Under vow of silence/mute? + if(HAS_TRAIT(user, TRAIT_MUTE) || user.mind.miming) //Under vow of silence/mute? user.visible_message("[user] appears to whisper to themselves.", "You begin to whisper to yourself.") //Make them do *something* abnormal. sleep(10) diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm index 51abf843c93..01238df31ec 100644 --- a/code/game/gamemodes/cult/cult_items.dm +++ b/code/game/gamemodes/cult/cult_items.dm @@ -53,7 +53,7 @@ user.Confused(10) user.Jitter(6) - if(HULK in user.mutations) + if(HAS_TRAIT(user, TRAIT_HULK)) to_chat(user, "You can't seem to hold the blade properly!") return FALSE @@ -200,12 +200,12 @@ user.Confused(10) user.Weaken(5) else if(slot == slot_wear_suit) - user.status_flags |= GOTTAGOFAST + ADD_TRAIT(user, TRAIT_GOTTAGOFAST, "cultrobes") /obj/item/clothing/suit/hooded/cultrobes/flagellant_robe/dropped(mob/user) . = ..() if(user) - user.status_flags &= ~GOTTAGOFAST + REMOVE_TRAIT(user, TRAIT_GOTTAGOFAST, "cultrobes") /obj/item/clothing/head/hooded/flagellant_hood name = "flagellant's robes" diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index 8ca90a4210b..b2b4dfa534e 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -74,7 +74,7 @@ if(invisibility) to_chat(user, "The magic in [src] is being channeled into Redspace, reveal the structure first!") return - if(HULK in user.mutations) + if(HAS_TRAIT(user, TRAIT_HULK)) to_chat(user, "You cannot seem to manipulate this structure with your bulky hands!") return if(!anchored) diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm index 74ff27468cc..7e9f054faea 100644 --- a/code/game/gamemodes/devil/game_mode.dm +++ b/code/game/gamemodes/devil/game_mode.dm @@ -38,7 +38,8 @@ devil_mind.devilinfo.link_with_mob(devil_mind.current) if(devil_mind.assigned_role == "Clown") to_chat(devil_mind.current, "Your infernal nature allows you to wield weapons without harming yourself.") - devil_mind.current.mutations.Remove(CLUMSY) + devil_mind.current.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(devil_mind.current, GLOB.clumsyblock, MUTCHK_FORCED) var/datum/action/innate/toggle_clumsy/A = new A.Grant(devil_mind.current) spawn(10) diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm index 2096eb0d162..e9a218b240b 100644 --- a/code/game/gamemodes/miniantags/abduction/gland.dm +++ b/code/game/gamemodes/miniantags/abduction/gland.dm @@ -281,13 +281,13 @@ if(ishuman(owner)) owner.gene_stability += GENE_INSTABILITY_MODERATE // give them this gene for free owner.dna.SetSEState(GLOB.shockimmunityblock, TRUE) - genemutcheck(owner, GLOB.shockimmunityblock, null, MUTCHK_FORCED) + singlemutcheck(owner, GLOB.shockimmunityblock, MUTCHK_FORCED) /obj/item/organ/internal/heart/gland/electric/remove(mob/living/carbon/M, special = 0) if(ishuman(owner)) owner.gene_stability -= GENE_INSTABILITY_MODERATE // but return it to normal once it's removed owner.dna.SetSEState(GLOB.shockimmunityblock, FALSE) - genemutcheck(owner, GLOB.shockimmunityblock, null, MUTCHK_FORCED) + singlemutcheck(owner, GLOB.shockimmunityblock, MUTCHK_FORCED) return ..() /obj/item/organ/internal/heart/gland/electric/activate() diff --git a/code/game/gamemodes/miniantags/guardian/types/lightning.dm b/code/game/gamemodes/miniantags/guardian/types/lightning.dm index 901ba9162d0..e1874ea5c56 100644 --- a/code/game/gamemodes/miniantags/guardian/types/lightning.dm +++ b/code/game/gamemodes/miniantags/guardian/types/lightning.dm @@ -22,8 +22,7 @@ . = ..() if(!summoner) return - if(!(NO_SHOCK in summoner.mutations)) - summoner.mutations.Add(NO_SHOCK) + ADD_TRAIT(summoner, TRAIT_SHOCKIMMUNE, "guardian") /mob/living/simple_animal/hostile/guardian/beam/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) return FALSE //You are lightning, you should not be hurt by such things. @@ -118,6 +117,6 @@ . = 1 /mob/living/simple_animal/hostile/guardian/beam/death(gibbed) - if(summoner && (NO_SHOCK in summoner.mutations)) - summoner.mutations.Remove(NO_SHOCK) + if(summoner) + REMOVE_TRAIT(summoner, TRAIT_SHOCKIMMUNE, "guardian") return ..() diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index d1622aabd3c..b572890ab6b 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -317,7 +317,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective) for(var/datum/mind/possible_target in SSticker.minds) if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && possible_target.current.client) var/mob/living/carbon/human/H = possible_target.current - if(!(NO_DNA in H.dna.species.species_traits)) + if(!HAS_TRAIT(H, TRAIT_GENELESS)) possible_targets += possible_target if(possible_targets.len > 0) target = pick(possible_targets) @@ -489,7 +489,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective) n_p++ else if(SSticker.current_state == GAME_STATE_PLAYING) for(var/mob/living/carbon/human/P in GLOB.player_list) - if(NO_DNA in P.dna.species.species_traits) + if(HAS_TRAIT(P, TRAIT_GENELESS)) continue if(P.client && !(P.mind in SSticker.mode.changelings) && P.mind!=owner) n_p++ diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 1f9e3e4359e..c8a9d39e555 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -121,7 +121,8 @@ if(mob.mind) if(mob.mind.assigned_role == "Clown") to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - mob.mutations.Remove(CLUMSY) + mob.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(mob, GLOB.clumsyblock, MUTCHK_FORCED) var/datum/action/innate/toggle_clumsy/A = new A.Grant(mob) diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm index f6ba6504381..75825a12259 100644 --- a/code/game/gamemodes/setupgame.dm +++ b/code/game/gamemodes/setupgame.dm @@ -107,14 +107,14 @@ // Monkeyblock is always last. GLOB.monkeyblock = DNA_SE_LENGTH - // And the genes that actually do the work. (domutcheck improvements) + // And the mutations that actually do the work. (domutcheck improvements) var/list/blocks_assigned[DNA_SE_LENGTH] - for(var/gene_type in typesof(/datum/dna/gene)) - var/datum/dna/gene/G = new gene_type + for(var/mutation_type in typesof(/datum/mutation)) + var/datum/mutation/G = new mutation_type if(G.block) if(G.block in blocks_assigned) warning("DNA2: Gene [G.name] trying to use already-assigned block [G.block] (used by [english_list(blocks_assigned[G.block])])") - GLOB.dna_genes.Add(G) + GLOB.dna_mutations.Add(G) var/list/assignedToBlock[0] if(blocks_assigned[G.block]) assignedToBlock=blocks_assigned[G.block] @@ -122,14 +122,14 @@ blocks_assigned[G.block]=assignedToBlock //testing("DNA2: Gene [G.name] assigned to block [G.block].") - // I WILL HAVE A LIST OF GENES THAT MATCHES THE RANDOMIZED BLOCKS GODDAMNIT! - for(var/block=1;block<=DNA_SE_LENGTH;block++) + // I WILL HAVE A LIST OF MUTATIONS THAT MATCHES THE RANDOMIZED BLOCKS GODDAMNIT! + for(var/block in 1 to DNA_SE_LENGTH) var/name = GLOB.assigned_blocks[block] - for(var/datum/dna/gene/gene in GLOB.dna_genes) - if(gene.name == name || gene.block == block) - if(gene.block in GLOB.assigned_gene_blocks) - warning("DNA2: Gene [gene.name] trying to add to already assigned gene block list (used by [english_list(GLOB.assigned_gene_blocks[block])])") - GLOB.assigned_gene_blocks[block] = gene + for(var/datum/mutation/mutation in GLOB.dna_mutations) + if(mutation.name == name || mutation.block == block) + if(mutation.block in GLOB.assigned_mutation_blocks) + warning("DNA2: Mutation [mutation.name] trying to add to already assigned gene block list (used by [english_list(GLOB.assigned_mutation_blocks[block])])") + GLOB.assigned_mutation_blocks[block] = mutation //testing("DNA2: [numsToAssign.len] blocks are unused: [english_list(numsToAssign)]") diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm index 8eb5c2af838..37045d44d10 100644 --- a/code/game/gamemodes/shadowling/shadowling.dm +++ b/code/game/gamemodes/shadowling/shadowling.dm @@ -148,7 +148,8 @@ Made by Xhuis update_shadow_icons_added(shadow_mind) if(shadow_mind.assigned_role == "Clown") to_chat(S, "Your alien nature has allowed you to overcome your clownishness.") - S.mutations.Remove(CLUMSY) + S.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(S, GLOB.clumsyblock, MUTCHK_FORCED) /datum/game_mode/proc/add_thrall(datum/mind/new_thrall_mind) if(!istype(new_thrall_mind)) diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm index 141ce7a1ef9..d1699850260 100644 --- a/code/game/gamemodes/vampire/vampire.dm +++ b/code/game/gamemodes/vampire/vampire.dm @@ -185,7 +185,8 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha if(vampire.current.mind) if(vampire.current.mind.assigned_role == "Clown") to_chat(vampire.current, "Your lust for blood has allowed you to overcome your clumsy nature allowing you to wield weapons without harming yourself.") - vampire.current.mutations.Remove(CLUMSY) + vampire.current.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(vampire.current, GLOB.clumsyblock, MUTCHK_FORCED) var/datum/action/innate/toggle_clumsy/A = new A.Grant(vampire.current) var/obj_count = 1 diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 0ff7192a7e6..db245cd0d25 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -270,7 +270,7 @@ continue to_chat(C, "You hear a ear piercing shriek and your senses dull!") C.Weaken(4) - C.MinimumDeafTicks(20) + C.AdjustEarDamage(0, 20) C.Stuttering(20) C.Stun(4) C.Jitter(150) diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index cb0c277b1e6..1307dc8424d 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -220,6 +220,37 @@ damtype = BURN force = 15 hitsound = 'sound/items/welder2.ogg' + var/mob/current_owner + +/obj/item/scrying/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + +/obj/item/scrying/Destroy() + STOP_PROCESSING(SSobj, src) + current_owner = null + return ..() + +/obj/item/scrying/process() + var/mob/holder = get(loc, /mob) + if(current_owner && current_owner != holder) + + to_chat(current_owner, "Your otherworldly vision fades...") + + REMOVE_TRAIT(current_owner, TRAIT_XRAY_VISION, SCRYING_ORB) + current_owner.update_sight() + current_owner.update_icons() + + current_owner = null + + if(!current_owner && holder) + current_owner = holder + + to_chat(current_owner, "You can see...everything!") + + ADD_TRAIT(current_owner, TRAIT_XRAY_VISION, SCRYING_ORB) + current_owner.update_sight() + current_owner.update_icons() /obj/item/scrying/attack_self(mob/user as mob) to_chat(user, " You can see...everything!") @@ -342,7 +373,7 @@ GLOBAL_LIST_EMPTY(multiverse) if(duplicate_self) M.dna = user.dna.Clone() M.UpdateAppearance() - domutcheck(M, null) + domutcheck(M) M.update_body() M.update_hair() M.update_fhair() @@ -796,7 +827,7 @@ GLOBAL_LIST_EMPTY(multiverse) else if(istype(I,/obj/item/bikehorn)) to_chat(target, "HONK") target << 'sound/items/airhorn.ogg' - target.MinimumDeafTicks(3) + target.AdjustEarDamage(0, 3) GiveHint(target) cooldown = world.time +cooldown_time return diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 0038200497e..88ee4cc393d 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -386,16 +386,6 @@ log_name = "SO" category = "Artefacts" -/datum/spellbook_entry/item/scryingorb/Buy(mob/living/carbon/human/user, obj/item/spellbook/book) - if(..()) - if(!(XRAY in user.mutations)) - user.mutations.Add(XRAY) - user.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS) - user.see_in_dark = 8 - user.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE - to_chat(user, "The walls suddenly disappear.") - return TRUE - /datum/spellbook_entry/item/soulstones name = "Six Soul Stone Shards and the spell Artificer" desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot." diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index 3bf9ccc50eb..a7a8b69edba 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -149,8 +149,7 @@ if(visualsOnly) return - H.dna.SetSEState(GLOB.soberblock,1) - H.mutations += SOBER + H.dna.SetSEState(GLOB.soberblock, TRUE) H.check_mutations = 1 /datum/job/officer diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index b4af01cd417..8a90da80dfa 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -34,7 +34,7 @@ return H.dna.SetSEState(GLOB.soberblock,1) - genemutcheck(H, GLOB.soberblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.soberblock, MUTCHK_FORCED) H.dna.default_blocks.Add(GLOB.soberblock) H.check_mutations = 1 @@ -292,11 +292,11 @@ implant.insert(H) H.dna.SetSEState(GLOB.clumsyblock, TRUE) - genemutcheck(H, GLOB.clumsyblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.clumsyblock, MUTCHK_FORCED) H.dna.default_blocks.Add(GLOB.clumsyblock) if(!ismachineperson(H)) H.dna.SetSEState(GLOB.comicblock, TRUE) - genemutcheck(H, GLOB.comicblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.comicblock, MUTCHK_FORCED) H.dna.default_blocks.Add(GLOB.comicblock) H.check_mutations = TRUE H.add_language("Clownish") @@ -308,7 +308,8 @@ /datum/action/innate/toggle_clumsy/Activate() var/mob/living/carbon/human/H = owner - H.mutations.Add(CLUMSY) + H.dna.SetSEState(GLOB.clumsyblock, TRUE) + singlemutcheck(H, GLOB.clumsyblock, MUTCHK_FORCED) active = TRUE background_icon_state = "bg_spell" UpdateButtonIcon() @@ -316,7 +317,8 @@ /datum/action/innate/toggle_clumsy/Deactivate() var/mob/living/carbon/human/H = owner - H.mutations.Remove(CLUMSY) + H.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(H, GLOB.clumsyblock, MUTCHK_FORCED) active = FALSE background_icon_state = "bg_default" UpdateButtonIcon() diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 4978db6efce..670e58247d4 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -321,9 +321,9 @@ occupantData["intOrgan"] = intOrganData - occupantData["blind"] = (BLINDNESS in occupant.mutations) - occupantData["colourblind"] = (COLOURBLIND in occupant.mutations) - occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations) + occupantData["blind"] = HAS_TRAIT(occupant, TRAIT_BLIND) + occupantData["colourblind"] = HAS_TRAIT(occupant, TRAIT_COLORBLIND) + occupantData["nearsighted"] = HAS_TRAIT(occupant, TRAIT_NEARSIGHT) data["occupant"] = occupantData return data @@ -511,11 +511,11 @@ dat += "[i.name]N/A[i.damage][infection]:[mech][dead]" dat += "" dat += "" - if(BLINDNESS in occupant.mutations) + if(HAS_TRAIT(occupant, TRAIT_BLIND)) dat += "Cataracts detected.
" - if(COLOURBLIND in occupant.mutations) + if(HAS_TRAIT(occupant, TRAIT_COLORBLIND)) dat += "Photoreceptor abnormalities detected.
" - if(NEARSIGHTED in occupant.mutations) + if(HAS_TRAIT(occupant, TRAIT_NEARSIGHT)) dat += "Retinal misalignment detected.
" else dat += "[src] is empty." diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index f00dc6311e9..a350a820c0a 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -274,7 +274,7 @@ GLOBAL_LIST_INIT(cloner_biomass_items, list(\ for(var/datum/language/L in R.languages) H.add_language(L.name) - domutcheck(H, null, MUTCHK_FORCED) //Ensures species that get powers by the species proc handle_dna keep them + domutcheck(H, MUTCHK_FORCED) //Ensures species that get powers by the species proc handle_dna keep them if(efficiency > 2 && efficiency < 5 && prob(25)) randmutb(H) diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 9d98bf6105d..c875b094058 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -185,7 +185,7 @@ var/patientStatus // Tell the computer what to say based on the status of the patient on the table. var/isNewPatient = (table.patient != currentPatient) //Is this a new Patient? - if(table.patient.stat == DEAD || table.patient.status_flags & FAKEDEATH) + if(table.patient.stat == DEAD || HAS_TRAIT(table.patient, TRAIT_FAKEDEATH)) patientStatus = "Dead" else if(table.patient.stat == CONSCIOUS) patientStatus = "Awake" diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 73722f5e6a3..fc8321d1f6a 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -392,7 +392,7 @@ if(subject.get_int_organ(/obj/item/organ/internal/brain)) var/obj/item/organ/internal/brain/Brn = subject.get_int_organ(/obj/item/organ/internal/brain) if(istype(Brn)) - if(NO_SCAN in Brn.dna.species.species_traits) + if(NO_CLONESCAN in Brn.dna.species.species_traits) set_scan_temp("[Brn.dna.species.name_plural] are not scannable.", "bad") SStgui.update_uis(src) return @@ -408,7 +408,7 @@ set_scan_temp("Subject's brain is not responding. Further attempts after a short delay may succeed.", "bad") SStgui.update_uis(src) return - if((NOCLONE in subject.mutations) && src.scanner.scan_level < 2) + if(HAS_TRAIT(subject, TRAIT_BADDNA) && src.scanner.scan_level < 2) set_scan_temp("Subject has incompatible genetic mutations.", "bad") SStgui.update_uis(src) return @@ -432,7 +432,7 @@ var/obj/item/organ/B = subject.get_int_organ(/obj/item/organ/internal/brain) B.dna.check_integrity() R.dna=B.dna.Clone() - if(NO_SCAN in R.dna.species.species_traits) + if(NO_CLONESCAN in R.dna.species.species_traits) extra_info = "Proper genetic interface not found, defaulting to genetic data of the body." R.dna.species = new subject.dna.species.type R.id= copytext(md5(B.dna.real_name), 2, 6) diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm index 8c960774b63..49457c96ec7 100644 --- a/code/game/machinery/mass_driver.dm +++ b/code/game/machinery/mass_driver.dm @@ -204,7 +204,7 @@ set name = "Rotate Frame" set src in view(1) - if( usr.stat || usr.restrained() || (usr.status_flags & FAKEDEATH)) + if( usr.stat || usr.restrained() || HAS_TRAIT(usr, TRAIT_FAKEDEATH)) return src.dir = turn(src.dir, -90) diff --git a/code/game/machinery/poolcontroller.dm b/code/game/machinery/poolcontroller.dm index 8f4aec27ff7..d2ade6bf0ea 100644 --- a/code/game/machinery/poolcontroller.dm +++ b/code/game/machinery/poolcontroller.dm @@ -115,9 +115,9 @@ if(drownee && ((drownee.lying && !drownee.player_logged) || deep_water)) //Mob lying down and not SSD or water is deep (determined by controller) if(drownee.internal) return //Has internals, no drowning - if((NO_BREATHE in drownee.dna.species.species_traits) || (BREATHLESS in drownee.mutations)) + if(HAS_TRAIT(drownee, TRAIT_NOBREATH)) return //doesn't breathe, no drowning - if(HAS_TRAIT(drownee,TRAIT_WATERBREATH)) + if(HAS_TRAIT(drownee, TRAIT_WATERBREATH)) return //fish things don't drown if(drownee.stat == DEAD) //Dead spacemen don't drown more diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index 3b26877e4b2..04822a8014f 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -205,10 +205,10 @@ if(prob(5)) if(prob(75)) randmutb(H) // Applies bad mutation - domutcheck(H,null,1) + domutcheck(H, MUTCHK_FORCED) else randmutg(H) // Applies good mutation - domutcheck(H,null,1) + domutcheck(H, MUTCHK_FORCED) /obj/machinery/transformer/xray/proc/scan(obj/item/I) @@ -309,7 +309,7 @@ H.real_name = template.real_name H.sync_organ_dna(assimilate = 0, old_ue = prev_ue) H.UpdateAppearance() - domutcheck(H, null, MUTCHK_FORCED) + domutcheck(H, MUTCHK_FORCED) H.update_mutations() /obj/machinery/transformer/gene_applier/attackby(obj/item/I, mob/living/user, params) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index e8db08bf37c..48fb17565eb 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -212,7 +212,7 @@ to_chat(M, "HONK") M.SetSleeping(0) M.Stuttering(20) - M.MinimumDeafTicks(30) + M.AdjustEarDamage(0, 30) M.Weaken(3) if(prob(30)) M.Stun(10) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 594b318750c..001ef8cc06b 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -887,7 +887,7 @@ else examine(user) if(occupant) - user << "This exosuit has a pilot and cannot be controlled." + to_chat(user, "This exosuit has a pilot and cannot be controlled.") return var/can_control_mech = FALSE for(var/obj/item/mecha_parts/mecha_tracking/ai_control/A in trackers) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index f1c3ae63c1f..44f99e2edac 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -68,12 +68,10 @@ /obj/effect/mine/dnascramble/mineEffect(mob/living/victim) victim.rad_act(radiation_amount) - if(ishuman(victim)) - var/mob/living/carbon/human/V = victim - if(NO_DNA in V.dna.species.species_traits) - return + if(!victim.dna || HAS_TRAIT(victim, TRAIT_GENELESS)) + return randmutb(victim) - domutcheck(victim ,null) + domutcheck(victim) /obj/effect/mine/gas name = "oxygen mine" @@ -179,7 +177,7 @@ if(!victim.client || !istype(victim)) return to_chat(victim, "You feel fast!") - victim.status_flags |= GOTTAGOFAST + ADD_TRAIT(victim, TRAIT_GOTTAGOFAST, "mine") spawn(duration) - victim.status_flags &= ~GOTTAGOFAST + REMOVE_TRAIT(victim, TRAIT_GOTTAGOFAST, "mine") to_chat(victim, "You slow down.") diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 8bfbf22f05d..2edd1c01a26 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -21,7 +21,7 @@ var/use_sound = 'sound/weapons/flash.ogg' /obj/item/flash/proc/clown_check(mob/user) - if(user && (CLUMSY in user.mutations) && prob(50)) + if(user && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) flash_carbon(user, user, 15, 0) return 0 return 1 diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 307964ca25c..aadd814c0f2 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -48,7 +48,7 @@ add_fingerprint(user) if(on && user.zone_selected == "eyes") - if(((CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) //too dumb to use flashlight properly + if((HAS_TRAIT(user, TRAIT_CLUMSY) || user.getBrainLoss() >= 60) && prob(50)) //too dumb to use flashlight properly return ..() //just hit them in the head if(!(istype(user, /mob/living/carbon/human) || SSticker) && SSticker.mode.name != "monkey") //don't have dexterity @@ -74,9 +74,9 @@ if(istype(H)) //robots and aliens are unaffected var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes) - if(M.stat == DEAD || !eyes || (BLINDNESS in M.mutations)) //mob is dead or fully blind + if(M.stat == DEAD || !eyes || HAS_TRAIT(M, TRAIT_BLIND)) //mob is dead or fully blind to_chat(user, "[M]'s pupils are unresponsive to the light!") - else if((XRAY in M.mutations) || eyes.see_in_dark >= 8) //The mob's either got the X-RAY vision or has a tapetum lucidum (extreme nightvision, i.e. Vulp/Tajara with COLOURBLIND & their monkey forms). + else if(HAS_TRAIT(M, TRAIT_XRAY_VISION) || eyes.see_in_dark >= 8) //The mob's either got the X-RAY vision or has a tapetum lucidum (extreme nightvision, i.e. Vulp/Tajara with COLOURBLIND & their monkey forms). to_chat(user, "[M]'s pupils glow eerily!") else //they're okay! if(M.flash_eyes(visual = 1)) diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index cfaea9f32f9..fe7d0cb3fe6 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -79,11 +79,9 @@ if(!user.IsAdvancedToolUser()) to_chat(user, "You don't have the dexterity to do this!") return - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if((HULK in H.mutations) || (NOGUNS in H.dna.species.species_traits)) - user << "Your fingers can't press the button!" - return + if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS)) + to_chat(user, "Your fingers can't press the button!") + return add_fingerprint(user) diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm index 9e2e8a085f7..ce8c6ca7191 100644 --- a/code/game/objects/items/devices/megaphone.dm +++ b/code/game/objects/items/devices/megaphone.dm @@ -32,7 +32,7 @@ if(H && H.mind && H.mind.miming) to_chat(user, "Your vow of silence prevents you from speaking.") return - if((COMIC in H.mutations) || H.get_int_organ(/obj/item/organ/internal/cyberimp/brain/clown_voice)) + if(HAS_TRAIT(H, TRAIT_COMIC_SANS)) span = "sans" if(spamcheck) to_chat(user, "\The [src] needs to recharge!") diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 7872120b96c..5e82e651e23 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -98,7 +98,7 @@ REAGENT SCANNER var/advanced = FALSE /obj/item/healthanalyzer/attack(mob/living/M, mob/living/user) - if(((CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) + if((HAS_TRAIT(user, TRAIT_CLUMSY) || user.getBrainLoss() >= 60) && prob(50)) user.visible_message("[user] analyzes the floor's vitals!", "You stupidly try to analyze the floor's vitals!") to_chat(user, "Analyzing results for The floor:\n\tOverall status: Healthy") to_chat(user, "Key: Suffocation/Toxin/Burn/Brute") @@ -130,7 +130,7 @@ REAGENT SCANNER var/TX = H.getToxLoss() > 50 ? "[H.getToxLoss()]" : H.getToxLoss() var/BU = H.getFireLoss() > 50 ? "[H.getFireLoss()]" : H.getFireLoss() var/BR = H.getBruteLoss() > 50 ? "[H.getBruteLoss()]" : H.getBruteLoss() - if(H.status_flags & FAKEDEATH) + if(HAS_TRAIT(H, TRAIT_FAKEDEATH)) OX = fake_oxy > 50 ? "[fake_oxy]" : fake_oxy to_chat(user, "Analyzing Results for [H]:\n\t Overall Status: dead") else @@ -138,7 +138,7 @@ REAGENT SCANNER to_chat(user, "\t Key: Suffocation/Toxin/Burns/Brute") to_chat(user, "\t Damage Specifics: [OX] - [TX] - [BU] - [BR]") to_chat(user, "Body Temperature: [H.bodytemperature-T0C]°C ([H.bodytemperature*1.8-459.67]°F)") - if(H.timeofdeath && (H.stat == DEAD || (H.status_flags & FAKEDEATH))) + if(H.timeofdeath && (H.stat == DEAD || (HAS_TRAIT(H, TRAIT_FAKEDEATH)))) to_chat(user, "Time of Death: [station_time_timestamp("hh:mm:ss", H.timeofdeath)]") var/tdelta = round(world.time - H.timeofdeath) if(tdelta < DEFIB_TIME_LIMIT) @@ -155,7 +155,7 @@ REAGENT SCANNER TX = H.getToxLoss() > 50 ? "Dangerous amount of toxins detected" : "Subject bloodstream toxin level minimal" BU = H.getFireLoss() > 50 ? "Severe burn damage detected" : "Subject burn injury status O.K" BR = H.getBruteLoss() > 50 ? "Severe anatomical damage detected" : "Subject brute-force injury status O.K" - if(H.status_flags & FAKEDEATH) + if(HAS_TRAIT(H, TRAIT_FAKEDEATH)) OX = fake_oxy > 50 ? "Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal" to_chat(user, "[OX] | [TX] | [BU] | [BR]") @@ -837,11 +837,11 @@ REAGENT SCANNER dat += "[i.name]N/A[i.damage][infection]:[mech]" dat += "" dat += "" - if(BLINDNESS in target.mutations) + if(HAS_TRAIT(target, TRAIT_BLIND)) dat += "Cataracts detected.
" - if(COLOURBLIND in target.mutations) + if(HAS_TRAIT(target, TRAIT_COLORBLIND)) dat += "Photoreceptor abnormalities detected.
" - if(NEARSIGHTED in target.mutations) + if(HAS_TRAIT(target, TRAIT_NEARSIGHT)) dat += "Retinal misalignment detected.
" return dat diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index 17169ce8970..dcebcacf954 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -45,7 +45,7 @@ return ..() if(user.zone_selected != "eyes" && user.zone_selected != "head") return ..() - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) M = user return eyestab(M,user) diff --git a/code/game/objects/items/weapons/batons.dm b/code/game/objects/items/weapons/batons.dm index 1da9e2bddde..47ec7da88e9 100644 --- a/code/game/objects/items/weapons/batons.dm +++ b/code/game/objects/items/weapons/batons.dm @@ -35,7 +35,7 @@ return ..() add_fingerprint(user) - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) user.visible_message("[user] accidentally clubs [user.p_them()]self with [src]!", \ "You accidentally club yourself with [src]!") user.Weaken(force * 3) diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index 2aecdf536ec..0dcce288a1a 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -419,7 +419,7 @@ for(var/obj/item/organ/external/O in H.bodyparts) total_brute += O.brute_dam total_burn += O.burn_dam - if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !(NOCLONE in H.mutations) && (H.mind && H.mind.is_revivable()) && (H.get_int_organ(/obj/item/organ/internal/heart) || H.get_int_organ(/obj/item/organ/internal/brain/slime))) + if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !HAS_TRAIT(H, TRAIT_HUSK) && !HAS_TRAIT(H, TRAIT_BADDNA) && (H.mind && H.mind.is_revivable()) && (H.get_int_organ(/obj/item/organ/internal/heart) || H.get_int_organ(/obj/item/organ/internal/brain/slime))) tobehealed = min(health + threshold, 0) // It's HILARIOUS without this min statement, let me tell you tobehealed -= 5 //They get 5 of each type of damage healed so excessive combined damage will not immediately kill them after they get revived H.adjustOxyLoss(tobehealed) @@ -538,7 +538,7 @@ for(var/obj/item/organ/external/O in H.bodyparts) total_brute += O.brute_dam total_burn += O.burn_dam - if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !(NOCLONE in H.mutations) && (H.mind && H.mind.is_revivable())) + if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !HAS_TRAIT(H, TRAIT_HUSK) && (H.mind && H.mind.is_revivable())) tobehealed = min(health + threshold, 0) // It's HILARIOUS without this min statement, let me tell you tobehealed -= 5 //They get 5 of each type of damage healed so excessive combined damage will not immediately kill them after they get revived H.adjustOxyLoss(tobehealed) diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index 5f635b1eb73..46d347e0db7 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -80,7 +80,7 @@ return spawn(0) //Some mutations have sleeps in them, like monkey - if(!(NOCLONE in M.mutations) && !(H && (NO_DNA in H.dna.species.species_traits))) // prevents drained people from having their DNA changed + if(!HAS_TRAIT(M, TRAIT_BADDNA) && !HAS_TRAIT(M, TRAIT_GENELESS)) // prevents drained people from having their DNA changed var/prev_ue = M.dna.unique_enzymes // UI in syringe. if(buf.types & DNA2_BUF_UI) @@ -103,7 +103,7 @@ M.dna.UpdateSE() else M.dna.SetSEValue(block,src.GetValue()) - domutcheck(M, null, forcedmutation ? MUTCHK_FORCED : 0) + domutcheck(M, forcedmutation ? MUTCHK_FORCED : FALSE) M.update_mutations() if(H) H.sync_organ_dna(assimilate = 0, old_ue = prev_ue) @@ -112,14 +112,9 @@ if(used) to_chat(user, "This injector is used up!") return - if(!M.dna) //You know what would be nice? If the mob you're injecting has DNA, and so doesn't cause runtimes. + if(!M.dna || HAS_TRAIT(M, TRAIT_GENELESS) || HAS_TRAIT(M, TRAIT_BADDNA)) //You know what would be nice? If the mob you're injecting has DNA, and so doesn't cause runtimes. return FALSE - if(ishuman(M)) // Would've done this via species instead of type, but the basic mob doesn't have a species, go figure. - var/mob/living/carbon/human/H = M - if(NO_DNA in H.dna.species.species_traits) - return FALSE - if(!user.IsAdvancedToolUser()) return FALSE diff --git a/code/game/objects/items/weapons/dnascrambler.dm b/code/game/objects/items/weapons/dnascrambler.dm index 1dcc4a942c2..f0a1a208906 100644 --- a/code/game/objects/items/weapons/dnascrambler.dm +++ b/code/game/objects/items/weapons/dnascrambler.dm @@ -22,11 +22,9 @@ if(used) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(NO_DNA in H.dna.species.species_traits) - to_chat(user, "You failed to inject [M], as [M.p_they()] [M.p_have()] no DNA to scramble, nor flesh to inject.") - return + if(HAS_TRAIT(M, TRAIT_GENELESS)) + to_chat(user, "You failed to inject [M], as [M.p_they()] [M.p_have()] no DNA to scramble, nor flesh to inject.") + return if(M == user) user.visible_message("[user] injects [user.p_them()]self with [src]!") diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 06ec9cded0c..6606b7cc703 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -74,7 +74,7 @@ if(!ear_safety) M.Stun(stun_amount) M.Weaken(stun_amount) - M.AdjustEarDamage(rand(0, 5), 15) + M.AdjustEarDamage(5, 15) if(iscarbon(M)) var/mob/living/carbon/C = M var/obj/item/organ/internal/ears/ears = C.get_int_organ(/obj/item/organ/internal/ears) @@ -83,6 +83,5 @@ to_chat(M, "Your ears start to ring badly!") if(prob(ears.ear_damage - 5)) to_chat(M, "You can't hear anything!") - M.BecomeDeaf() else if(ears.ear_damage >= 5) to_chat(M, "Your ears start to ring!") diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm index da546836dc6..43e6b9e4692 100644 --- a/code/game/objects/items/weapons/grenades/grenade.dm +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -22,7 +22,7 @@ qdel(src) /obj/item/grenade/proc/clown_check(var/mob/living/user) - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) to_chat(user, "Huh? How does this thing work?") active = 1 icon_state = initial(icon_state) + "_active" diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index ee562c0b35c..a9e4765560a 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -29,7 +29,7 @@ to_chat(user, "[src] is stuck to your hand!") return - if((CLUMSY in user.mutations) && prob(50) && (!ignoresClumsy)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50) && (!ignoresClumsy)) to_chat(user, "Uh... how do those things work?!") apply_cuffs(user, user) return diff --git a/code/game/objects/items/weapons/kitchen.dm b/code/game/objects/items/weapons/kitchen.dm index bc8c4bc65df..a9fa08b9271 100644 --- a/code/game/objects/items/weapons/kitchen.dm +++ b/code/game/objects/items/weapons/kitchen.dm @@ -48,7 +48,7 @@ if(user.a_intent != INTENT_HELP) if(user.zone_selected == "head" || user.zone_selected == "eyes") - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) C = user return eyestab(C, user) else diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index f6fb213b353..82592abb8b1 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -37,7 +37,7 @@ return BRUTELOSS|FIRELOSS /obj/item/melee/energy/attack_self(mob/living/carbon/user) - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) to_chat(user, "You accidentally cut yourself with [src], like a doofus!") user.take_organ_damage(5,5) active = !active @@ -291,7 +291,7 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user - if((CLUMSY in H.mutations) && prob(50)) + if(HAS_TRAIT(H, TRAIT_CLUMSY) && prob(50)) to_chat(H, "You accidentally cut yourself with [src], like a doofus!") H.take_organ_damage(10,10) active = !active diff --git a/code/game/objects/items/weapons/pneumaticCannon.dm b/code/game/objects/items/weapons/pneumaticCannon.dm index 93f5afea391..e26607b8fb7 100644 --- a/code/game/objects/items/weapons/pneumaticCannon.dm +++ b/code/game/objects/items/weapons/pneumaticCannon.dm @@ -101,7 +101,7 @@ if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting)) to_chat(user, "\The [src] lets out a weak hiss and doesn't react!") return - if(user && (CLUMSY in user.mutations) && prob(75)) + if(user && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(75)) user.visible_message("[user] loses [user.p_their()] grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!") user.drop_item() if(prob(10)) diff --git a/code/game/objects/items/weapons/shards.dm b/code/game/objects/items/weapons/shards.dm index f987f047f11..234685f3fe9 100644 --- a/code/game/objects/items/weapons/shards.dm +++ b/code/game/objects/items/weapons/shards.dm @@ -51,7 +51,7 @@ return if(ishuman(user)) var/mob/living/carbon/human/H = user - if(!H.gloves && !(PIERCEIMMUNE in H.dna.species.species_traits)) + if(!H.gloves && !HAS_TRAIT(H, TRAIT_PIERCEIMMUNE)) var/obj/item/organ/external/affecting = H.get_organ("[user.hand ? "l" : "r" ]_hand") if(affecting.is_robotic()) return diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index 19e56e161e3..86789ca3791 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -76,7 +76,7 @@ return (active) /obj/item/shield/energy/attack_self(mob/living/carbon/human/user) - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) to_chat(user, "You beat yourself in the head with [src].") user.take_organ_damage(5) active = !active diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm index 2479c408043..a954369e933 100644 --- a/code/game/objects/items/weapons/storage/bible.dm +++ b/code/game/objects/items/weapons/storage/bible.dm @@ -82,7 +82,7 @@ user.take_organ_damage(0, 10) return - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) to_chat(user, "The [src] slips out of your hand and hits your head.") user.take_organ_damage(10) user.Paralyse(20) diff --git a/code/game/objects/items/weapons/storage/briefcase.dm b/code/game/objects/items/weapons/storage/briefcase.dm index acbf16ce202..55911d4ddc5 100644 --- a/code/game/objects/items/weapons/storage/briefcase.dm +++ b/code/game/objects/items/weapons/storage/briefcase.dm @@ -56,7 +56,7 @@ to_chat(user, "The [I] is too big to fit in the false bottom!") return if(!user.drop_item(I)) - user << "The [I] is stuck to your hands!" + to_chat(user, "The [I] is stuck to your hands!") return stored_item = I diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index ec7d4b6989f..b1c4419e869 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -135,7 +135,7 @@ add_fingerprint(user) /obj/item/melee/baton/attack(mob/M, mob/living/user) - if(status && (CLUMSY in user.mutations) && prob(50)) + if(status && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", \ "You accidentally hit yourself with [src]!") user.Weaken(stunforce*3) diff --git a/code/game/objects/items/weapons/teleprod.dm b/code/game/objects/items/weapons/teleprod.dm index 1fe31f8a4f7..023d55609fa 100644 --- a/code/game/objects/items/weapons/teleprod.dm +++ b/code/game/objects/items/weapons/teleprod.dm @@ -9,7 +9,7 @@ /obj/item/melee/baton/cattleprod/teleprod/attack(mob/living/carbon/M, mob/living/carbon/user)//handles making things teleport when hit ..() if(status) - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", \ "You accidentally hit yourself with [src]!") user.Weaken(stunforce*3) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 95dfb79dfdc..10f69e15b69 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -300,12 +300,12 @@ ..() /obj/item/twohanded/dualsaber/attack(mob/target, mob/living/user) - if(HULK in user.mutations) + if(HAS_TRAIT(user, TRAIT_HULK)) to_chat(user, "You grip the blade too hard and accidentally close it!") unwield() return ..() - if((CLUMSY in user.mutations) && (wielded) && prob(40)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && (wielded) && prob(40)) to_chat(user, "You twirl around a bit before losing your balance and impaling yourself on the [src].") user.take_organ_damage(20, 25) return @@ -353,7 +353,7 @@ return TRUE /obj/item/twohanded/dualsaber/wield(mob/living/carbon/M) //Specific wield () hulk checks due to reflection chance for balance issues and switches hitsounds. - if(HULK in M.mutations) + if(HAS_TRAIT(M, TRAIT_HULK)) to_chat(M, "You lack the grace to wield this!") return . = ..() diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index b0a8101e4a7..54b9b8a1c56 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -19,7 +19,7 @@ L.buckled = 0 L.anchored = 0 L.forceMove(src) - L.mutations |= MUTE + ADD_TRAIT(L, TRAIT_MUTE, STATUE_MUTE) max_integrity = L.health + 100 //stoning damaged mobs will result in easier to shatter statues intialTox = L.getToxLoss() intialFire = L.getFireLoss() @@ -68,7 +68,7 @@ for(var/mob/living/M in src) M.forceMove(loc) - M.mutations -= MUTE + REMOVE_TRAIT(M, TRAIT_MUTE, STATUE_MUTE) M.take_overall_damage((M.health - obj_integrity - 100),0) //any new damage the statue incurred is transfered to the mob ..() diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 6bf97d581e2..c56f4cb2603 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -147,10 +147,10 @@ if(voice_mutation) if(H.dna.GetSEState(voice_mutation)) H.dna.SetSEState(voice_mutation, FALSE) - genemutcheck(H, voice_mutation, null, MUTCHK_FORCED) + singlemutcheck(H, voice_mutation, MUTCHK_FORCED) else H.dna.SetSEState(voice_mutation, TRUE) - genemutcheck(H, voice_mutation, null, MUTCHK_FORCED) + singlemutcheck(H, voice_mutation, MUTCHK_FORCED) if(voice_choice) curse(user) diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index 7ce784539ad..401e0870d22 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -37,7 +37,7 @@ // Failing that... if(!(damagetype & BRUTELOSS) && !(damagetype & FIRELOSS) && !(damagetype & TOXLOSS) && !(damagetype & OXYLOSS)) - if(NO_BREATHE in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_NOBREATH)) // the ultimate fallback take_overall_damage(max(dmgamt - getToxLoss() - getFireLoss() - getBruteLoss() - getOxyLoss(), 0), 0, updating_health = FALSE) else diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 64ad4bf7c4a..daf195af8f8 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -222,7 +222,7 @@ GLOBAL_VAR_INIT(nologevent, 0) body += "

" body += "DNA Blocks:
" var/bname - for(var/block=1;block<=DNA_SE_LENGTH;block++) + for(var/block in 1 to DNA_SE_LENGTH) if(((block-1)%5)==0) body += "" bname = GLOB.assigned_blocks[block] diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index faaf2fa9ed9..8bc4e3f2657 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2087,15 +2087,15 @@ logmsg = "a heal over time." if("Permanent Regeneration") H.dna.SetSEState(GLOB.regenerateblock, 1) - genemutcheck(H, GLOB.regenerateblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.regenerateblock, MUTCHK_FORCED) H.update_mutations() H.gene_stability = 100 logmsg = "permanent regeneration." if("Super Powers") - var/list/default_genes = list(GLOB.regenerateblock, GLOB.breathlessblock, GLOB.coldblock) - for(var/gene in default_genes) - H.dna.SetSEState(gene, 1) - genemutcheck(H, gene, null, MUTCHK_FORCED) + var/list/default_mutations = list(GLOB.regenerateblock, GLOB.breathlessblock, GLOB.coldblock) + for(var/mutation in default_mutations) + H.dna.SetSEState(mutation, 1) + singlemutcheck(H, mutation, MUTCHK_FORCED) H.update_mutations() H.gene_stability = 100 logmsg = "superpowers." @@ -2234,7 +2234,7 @@ logmsg = "starvation." if("Cluwne") H.makeCluwne() - H.mutations |= NOCLONE + ADD_TRAIT(H, TRAIT_BADDNA, "smiting") logmsg = "cluwned." if("Mutagen Cookie") var/obj/item/reagent_containers/food/snacks/cookie/evilcookie = new /obj/item/reagent_containers/food/snacks/cookie @@ -2255,7 +2255,7 @@ H.equip_to_slot_or_del(evilcookie, slot_l_hand) logmsg = "a hellwater cookie." if("Hunter") - H.mutations |= NOCLONE + ADD_TRAIT(H, TRAIT_BADDNA, "smiting") usr.client.create_eventmob_for(H, 1) logmsg = "hunter." if("Crew Traitor") diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 81a6854639e..c27f4502af2 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -852,12 +852,12 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) if(!SSticker) alert("Wait until the game starts") return - if(istype(M, /mob/living/carbon)) + if(ishuman(M)) M.dna.SetSEState(block,!M.dna.GetSEState(block)) - genemutcheck(M,block,null,MUTCHK_FORCED) + singlemutcheck(M, block, MUTCHK_FORCED) M.update_mutations() - var/state="[M.dna.GetSEState(block)?"on":"off"]" - var/blockname=GLOB.assigned_blocks[block] + var/state = "[M.dna.GetSEState(block) ? "on" : "off"]" + var/blockname = GLOB.assigned_blocks[block] message_admins("[key_name_admin(src)] has toggled [M.key]'s [blockname] block [state]!") log_admin("[key_name(src)] has toggled [M.key]'s [blockname] block [state]!") else diff --git a/code/modules/admin/verbs/honksquad.dm b/code/modules/admin/verbs/honksquad.dm index 5107ce7e22c..485f25ab757 100644 --- a/code/modules/admin/verbs/honksquad.dm +++ b/code/modules/admin/verbs/honksquad.dm @@ -126,7 +126,8 @@ GLOBAL_VAR_INIT(sent_honksquad, 0) equip_to_slot_or_del(new /obj/item/gun/energy/clown(src), slot_in_backpack) else equip_to_slot_or_del(new /obj/item/gun/throw/piecannon(src), slot_in_backpack) - src.mutations.Add(CLUMSY) + dna.SetSEState(GLOB.clumsyblock, TRUE) + singlemutcheck(src, GLOB.clumsyblock, MUTCHK_FORCED) diff --git a/code/modules/antagonists/traitor/datum_mindslave.dm b/code/modules/antagonists/traitor/datum_mindslave.dm index 6fcb4bac63a..68f174cc878 100644 --- a/code/modules/antagonists/traitor/datum_mindslave.dm +++ b/code/modules/antagonists/traitor/datum_mindslave.dm @@ -28,14 +28,16 @@ var/mob/living/carbon/human/slave_mob = owner.current if(slave_mob && istype(slave_mob)) to_chat(slave_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - slave_mob.mutations.Remove(CLUMSY) + slave_mob.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(slave_mob, GLOB.clumsyblock, MUTCHK_FORCED) /datum/antagonist/mindslave/remove_innate_effects() . = ..() if(owner.assigned_role == "Clown") var/mob/living/carbon/human/slave_mob = owner.current if(slave_mob && istype(slave_mob)) - slave_mob.mutations.Add(CLUMSY) + slave_mob.dna.SetSEState(GLOB.clumsyblock, TRUE) + singlemutcheck(slave_mob, GLOB.clumsyblock, MUTCHK_FORCED) /datum/antagonist/mindslave/proc/add_objective(datum/objective/O) owner.objectives += O diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 3e36a11fbe9..adffc39ee09 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -68,7 +68,8 @@ var/mob/living/carbon/human/traitor_mob = owner.current if(traitor_mob && istype(traitor_mob)) to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - traitor_mob.mutations.Remove(CLUMSY) + traitor_mob.dna.SetSEState(GLOB.clumsyblock, FALSE) + singlemutcheck(traitor_mob, GLOB.clumsyblock, MUTCHK_FORCED) var/datum/action/innate/toggle_clumsy/A = new A.Grant(traitor_mob) @@ -79,7 +80,8 @@ var/mob/living/carbon/human/traitor_mob = owner.current if(traitor_mob && istype(traitor_mob)) to_chat(traitor_mob, "You lose your syndicate training and return to your own clumsy, clownish self.") - traitor_mob.mutations.Add(CLUMSY) + traitor_mob.dna.SetSEState(GLOB.clumsyblock, TRUE) + singlemutcheck(traitor_mob, GLOB.clumsyblock, MUTCHK_FORCED) for(var/datum/action/innate/A in traitor_mob.actions) if(istype(A, /datum/action/innate/toggle_clumsy)) A.Remove(traitor_mob) diff --git a/code/modules/antagonists/wishgranter/wishgranter.dm b/code/modules/antagonists/wishgranter/wishgranter.dm index cb6fad39d34..92e6336d693 100644 --- a/code/modules/antagonists/wishgranter/wishgranter.dm +++ b/code/modules/antagonists/wishgranter/wishgranter.dm @@ -23,56 +23,56 @@ return H.ignore_gene_stability = TRUE H.dna.SetSEState(GLOB.hulkblock, TRUE) - genemutcheck(H, GLOB.hulkblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.hulkblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.xrayblock, TRUE) - genemutcheck(H, GLOB.xrayblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.xrayblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.fireblock, TRUE) - genemutcheck(H, GLOB.fireblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.fireblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.coldblock, TRUE) - genemutcheck(H, GLOB.coldblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.coldblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.teleblock, TRUE) - genemutcheck(H, GLOB.teleblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.teleblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.increaserunblock, TRUE) - genemutcheck(H, GLOB.increaserunblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.increaserunblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.breathlessblock, TRUE) - genemutcheck(H, GLOB.breathlessblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.breathlessblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.regenerateblock, TRUE) - genemutcheck(H, GLOB.regenerateblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.regenerateblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.shockimmunityblock, TRUE) - genemutcheck(H, GLOB.shockimmunityblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.shockimmunityblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.smallsizeblock, TRUE) - genemutcheck(H, GLOB.smallsizeblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.smallsizeblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.soberblock, TRUE) - genemutcheck(H, GLOB.soberblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.soberblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.psyresistblock, TRUE) - genemutcheck(H, GLOB.psyresistblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.psyresistblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.shadowblock, TRUE) - genemutcheck(H, GLOB.shadowblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.shadowblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.cryoblock, TRUE) - genemutcheck(H, GLOB.cryoblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.cryoblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.eatblock, TRUE) - genemutcheck(H, GLOB.eatblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.eatblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.jumpblock, TRUE) - genemutcheck(H, GLOB.jumpblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.jumpblock, MUTCHK_FORCED) H.dna.SetSEState(GLOB.immolateblock, TRUE) - genemutcheck(H, GLOB.immolateblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.immolateblock, MUTCHK_FORCED) - H.mutations.Add(LASER) + ADD_TRAIT(H, TRAIT_LASEREYES, "wishgranter") H.update_mutations() H.update_body() diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index a17649bb008..bb336672ba9 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -19,7 +19,7 @@ if(!armed) if(ishuman(usr)) var/mob/living/carbon/human/user = usr - if((user.getBrainLoss() >= 60 || (CLUMSY in user.mutations)) && prob(50)) + if((user.getBrainLoss() >= 60 || HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50)) to_chat(user, "Your hand slips, setting off the trigger.") pulse(0) update_icon() @@ -43,7 +43,7 @@ var/obj/item/organ/external/affecting = null if(ishuman(target)) var/mob/living/carbon/human/H = target - if(PIERCEIMMUNE in H.dna.species.species_traits) + if(HAS_TRAIT(H, TRAIT_PIERCEIMMUNE)) playsound(src, 'sound/effects/snap.ogg', 50, TRUE) armed = FALSE update_icon() @@ -75,7 +75,7 @@ if(!armed) to_chat(user, "You arm [src].") else - if((user.getBrainLoss() >= 60 || (CLUMSY in user.mutations)) && prob(50)) + if((user.getBrainLoss() >= 60 || HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50)) var/which_hand = "l_hand" if(!user.hand) which_hand = "r_hand" @@ -90,7 +90,7 @@ /obj/item/assembly/mousetrap/attack_hand(mob/living/user) if(armed) - if((user.getBrainLoss() >= 60 || (CLUMSY in user.mutations)) && prob(50)) + if((user.getBrainLoss() >= 60 || HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50)) var/which_hand = "l_hand" if(!user.hand) which_hand = "r_hand" diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 5d3d6494e48..c3a483c04d8 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -194,9 +194,9 @@ H.set_species(mob_species) if(husk) - H.ChangeToHusk() + H.Drain() else //Because for some reason I can't track down, things are getting turned into husks even if husk = false. It's in some damage proc somewhere. - H.mutations.Remove(HUSK) + H.cure_husk() H.underwear = "Nude" H.undershirt = "Nude" H.socks = "Nude" diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm index 30d1c213a56..94743390f30 100644 --- a/code/modules/awaymissions/mission_code/wildwest.dm +++ b/code/modules/awaymissions/mission_code/wildwest.dm @@ -76,9 +76,11 @@ if("Power") to_chat(user, "Your wish is granted, but at a terrible cost...") to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart.") - user.mutations.Add(LASER) - user.mutations.Add(COLDRES) - user.mutations.Add(XRAY) + ADD_TRAIT(user, TRAIT_LASEREYES, "ww_wishgranter") + user.dna.SetSEState(GLOB.fireblock, TRUE) + singlemutcheck(user, GLOB.fireblock, MUTCHK_FORCED) + user.dna.SetSEState(GLOB.xrayblock, TRUE) + singlemutcheck(user, GLOB.xrayblock, MUTCHK_FORCED) if(ishuman(user)) var/mob/living/carbon/human/human = user if(!isshadowperson(human)) diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 56184f1daf6..fd4f9d869f2 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -867,7 +867,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts HTML += ShowDisabilityState(user, DISABILITY_FLAG_BLIND, "Blind") HTML += ShowDisabilityState(user, DISABILITY_FLAG_DEAF, "Deaf") HTML += ShowDisabilityState(user, DISABILITY_FLAG_MUTE, "Mute") - if(!(NO_OBESITY in S.species_traits)) + if(!(TRAIT_NOFAT in S.inherent_traits)) HTML += ShowDisabilityState(user, DISABILITY_FLAG_FAT, "Obese") HTML += ShowDisabilityState(user, DISABILITY_FLAG_NERVOUS, "Stutter") HTML += ShowDisabilityState(user, DISABILITY_FLAG_SWEDISH, "Swedish accent") @@ -2291,7 +2291,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts if(character.dna.dirtySE) character.dna.UpdateSE() - domutcheck(character, null, MUTCHK_FORCED) //'Activates' all the above disabilities. + domutcheck(character, MUTCHK_FORCED) //'Activates' all the above disabilities. character.dna.ready_dna(character, flatten_SE = 0) character.sync_organ_dna(assimilate=1) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d4293bd92a8..6567a71642b 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -526,7 +526,7 @@ BLIND // can't see anything /obj/item/clothing/suit/proc/adjustsuit(var/mob/user) if(!ignore_suitadjust) if(!user.incapacitated()) - if(!(HULK in user.mutations)) + if(!HAS_TRAIT(user, TRAIT_HULK)) if(suit_adjusted) var/flavour = "close" icon_state = copytext(icon_state, 1, findtext(icon_state, "_open")) /*Trims the '_open' off the end of the icon state, thus avoiding a case where jackets that start open will diff --git a/code/modules/clothing/ears/ears.dm b/code/modules/clothing/ears/ears.dm index d00751e2cfb..01a74ae99ec 100644 --- a/code/modules/clothing/ears/ears.dm +++ b/code/modules/clothing/ears/ears.dm @@ -4,7 +4,19 @@ icon_state = "earmuffs" item_state = "earmuffs" flags = EARBANGPROTECT - flags_2 = HEALS_EARS_2 strip_delay = 15 put_on_delay = 25 resistance_flags = FLAMMABLE + +/obj/item/clothing/ears/earmuffs/ComponentInitialize() + . = ..() + AddElement(/datum/element/earhealing) + +/obj/item/clothing/ears/earmuffs/equipped(mob/user, slot) + . = ..() + if(ishuman(user) && ((slot == slot_l_ear) || (slot == slot_r_ear))) + ADD_TRAIT(user, TRAIT_DEAF, CLOTHING_TRAIT) + +/obj/item/clothing/ears/earmuffs/dropped(mob/user) + . = ..() + REMOVE_TRAIT(user, TRAIT_DEAF, CLOTHING_TRAIT) diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index cc63f0a6e40..ea030fb8905 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -45,6 +45,19 @@ user.update_sight() user.update_inv_glasses() +//called when thermal glasses are emped. +/obj/item/clothing/glasses/proc/thermal_overload() + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + var/obj/item/organ/internal/eyes/eyes = H.get_organ_slot("eyes") + if(!H.eye_blind && eyes) + if(H.glasses == src) + to_chat(H, "[src] overloads and blinds you!") + H.flash_eyes(visual = TRUE) + H.EyeBlind(3) + H.EyeBlurry(5) + eyes.receive_damage(5) + /obj/item/clothing/glasses/meson name = "Optical Meson Scanner" desc = "Used for seeing walls, floors, and stuff through anything." @@ -340,7 +353,7 @@ /obj/item/clothing/glasses/sunglasses/lasers/equipped(mob/user, slot) //grant them laser eyes upon equipping it. if(slot == slot_glasses) - user.mutations.Add(LASER) + ADD_TRAIT(user, TRAIT_LASEREYES, "admin_zapglasses") user.regenerate_icons() ..(user, slot) @@ -404,16 +417,7 @@ ) /obj/item/clothing/glasses/thermal/emp_act(severity) - if(istype(src.loc, /mob/living/carbon/human)) - var/mob/living/carbon/human/M = src.loc - to_chat(M, "The Optical Thermal Scanner overloads and blinds you!") - if(M.glasses == src) - M.EyeBlind(3) - M.EyeBlurry(5) - if(!(NEARSIGHTED in M.mutations)) - M.BecomeNearsighted() - spawn(100) - M.CureNearsighted() + thermal_overload() ..() /obj/item/clothing/glasses/thermal/monocle diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index a80289686ff..48710377615 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -141,7 +141,7 @@ user.visible_message("[user] places \the [src] against [M]'s chest and listens attentively.", "You place \the [src] against [M]'s chest...") var/obj/item/organ/internal/H = M.get_int_organ(/obj/item/organ/internal/heart) var/obj/item/organ/internal/L = M.get_int_organ(/obj/item/organ/internal/lungs) - if((H && M.pulse) || (L && !(BREATHLESS in M.mutations) && !(NO_BREATHE in M.dna.species.species_traits))) + if((H && M.pulse) || (L && !HAS_TRAIT(M, TRAIT_NOBREATH))) var/color = "notice" if(H) var/heart_sound diff --git a/code/modules/events/mass_hallucination.dm b/code/modules/events/mass_hallucination.dm index b8f45023a27..4fff53f1a8f 100644 --- a/code/modules/events/mass_hallucination.dm +++ b/code/modules/events/mass_hallucination.dm @@ -10,7 +10,7 @@ if(!is_station_level(T.z)) continue var/armor = H.getarmor(type = "rad") - if((RADIMMUNE in H.dna.species.species_traits) || armor >= 75) // Leave radiation-immune species/rad armored players completely unaffected + if(HAS_TRAIT(H, TRAIT_RADIMMUNE) || armor >= 75) // Leave radiation-immune species/rad armored players completely unaffected continue H.AdjustHallucinate(rand(50, 100)) diff --git a/code/modules/food_and_drinks/drinks/drinks/shotglass.dm b/code/modules/food_and_drinks/drinks/drinks/shotglass.dm index 7b3349e4c2d..144e280da40 100644 --- a/code/modules/food_and_drinks/drinks/drinks/shotglass.dm +++ b/code/modules/food_and_drinks/drinks/drinks/shotglass.dm @@ -72,7 +72,7 @@ return /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/attack(mob/living/carbon/human/user) - if((CLUMSY in user.mutations) && prob(50) && (resistance_flags & ON_FIRE)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50) && (resistance_flags & ON_FIRE)) clumsilyDrink(user) else ..() @@ -89,7 +89,7 @@ ..() if(!(resistance_flags & ON_FIRE)) return - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) clumsilyDrink(user) else user.visible_message("[user] places [user.p_their()] hand over [src] to put it out!", "You use your hand to extinguish [src]!") @@ -98,7 +98,7 @@ /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/MouseDrop(mob/living/carbon/human/user) if(!ishuman(user)) return - if((CLUMSY in user.mutations) && prob(50) && (resistance_flags & ON_FIRE)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50) && (resistance_flags & ON_FIRE)) clumsilyDrink(user) else ..() diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index 8dcada2f7e8..18cf9952e1d 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -54,7 +54,7 @@ var/mob/living/carbon/human/H = user if(H.gloves) return TRUE - if(PIERCEIMMUNE in H.dna.species.species_traits) + if(HAS_TRAIT(H, TRAIT_PIERCEIMMUNE)) return TRUE var/organ = ((H.hand ? "l_":"r_") + "arm") var/obj/item/organ/external/affecting = H.get_organ(organ) diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm index 0f2b54ab971..a0c3a86d3f0 100644 --- a/code/modules/hydroponics/grown/replicapod.dm +++ b/code/modules/hydroponics/grown/replicapod.dm @@ -30,7 +30,7 @@ if(!contains_sample) for(var/datum/reagent/blood/bloodSample in W.reagents.reagent_list) var/datum/dna/dna = bloodSample.data["dna"] - if(bloodSample.data["mind"] && bloodSample.data["cloneable"] && !(NO_SCAN in dna.species.species_traits)) + if(bloodSample.data["mind"] && bloodSample.data["cloneable"] && !(NO_CLONESCAN in dna.species.species_traits)) var/datum/mind/tempmind = bloodSample.data["mind"] if(tempmind.is_revivable()) mind = bloodSample.data["mind"] diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm index 7c2648b987e..b9a7138de99 100644 --- a/code/modules/martial_arts/martial.dm +++ b/code/modules/martial_arts/martial.dm @@ -307,7 +307,7 @@ /obj/item/twohanded/bostaff/attack(mob/target, mob/living/user) add_fingerprint(user) - if((CLUMSY in user.mutations) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) to_chat(user, "You club yourself over the head with [src].") user.Weaken(3) if(ishuman(user)) diff --git a/code/modules/mining/lavaland/loot/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm index f0c57fadfe6..07a633c6b2e 100644 --- a/code/modules/mining/lavaland/loot/colossus_loot.dm +++ b/code/modules/mining/lavaland/loot/colossus_loot.dm @@ -217,7 +217,7 @@ if(H.stat == DEAD) H.set_species(/datum/species/shadow) H.revive() - H.mutations |= NOCLONE //Free revives, but significantly limits your options for reviving except via the crystal + ADD_TRAIT(H, TRAIT_BADDNA, MAGIC_TRAIT) //Free revives, but significantly limits your options for reviving except via the crystal H.grab_ghost(force = TRUE) /obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans @@ -370,7 +370,7 @@ if(isliving(A) && holder_animal) var/mob/living/L = A L.notransform = 1 - L.mutations |= MUTE + ADD_TRAIT(L, TRAIT_MUTE, STASIS_MUTE) L.status_flags |= GODMODE L.mind.transfer_to(holder_animal) var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession @@ -380,7 +380,7 @@ /obj/structure/closet/stasis/dump_contents(var/kill = 1) STOP_PROCESSING(SSobj, src) for(var/mob/living/L in src) - L.mutations -=MUTE + REMOVE_TRAIT(L, TRAIT_MUTE, STASIS_MUTE) L.status_flags &= ~GODMODE L.notransform = 0 if(holder_animal && !QDELETED(holder_animal)) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 02f639f018a..130dbc39145 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -193,7 +193,7 @@ Des: Gives the client of the alien an image on each infected mob. /mob/living/carbon/alien/proc/AddInfectionImages() if(client) for(var/mob/living/C in GLOB.mob_list) - if(C.status_flags & XENO_HOST) + if(HAS_TRAIT(C, TRAIT_XENO_HOST)) var/obj/item/organ/internal/body_egg/alien_embryo/A = C.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo) if(A) var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]") diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index b3f6d73a163..c7c776f631d 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -104,24 +104,23 @@ /obj/item/clothing/mask/facehugger/proc/Attach(mob/living/M) if(!isliving(M)) - return 0 + return FALSE if((!iscorgi(M) && !iscarbon(M)) || isalien(M)) - return 0 + return FALSE if(attached) - return 0 + return FALSE else attached++ spawn(MAX_IMPREGNATION_TIME) attached = 0 - if(M.get_int_organ(/obj/item/organ/internal/xenos/hivenode)) - return 0 - if(M.get_int_organ(/obj/item/organ/internal/body_egg/alien_embryo)) - return 0 + if(HAS_TRAIT(M, TRAIT_XENO_IMMUNE)) + return FALSE if(loc == M) - return 0 + return FALSE if(stat != CONSCIOUS) - return 0 - if(!sterile) M.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage + return FALSE + if(!sterile) + M.take_organ_damage(strength, 0) //done here so that even borgs and humans in helmets take damage M.visible_message("[src] leaps at [M]'s face!", \ "[src] leaps at [M]'s face!") if(ishuman(M)) @@ -130,12 +129,12 @@ H.visible_message("[src] smashes against [H]'s [H.head]!", \ "[src] smashes against [H]'s [H.head]!") Die() - return 0 + return FALSE if(iscarbon(M)) var/mob/living/carbon/target = M if(target.wear_mask) if(prob(20)) - return 0 + return FALSE if(istype(target.wear_mask, /obj/item/clothing/mask/muzzle)) var/obj/item/clothing/mask/muzzle/S = target.wear_mask if(S.do_break()) @@ -143,7 +142,7 @@ "[src] spits acid onto [S] melting the lock!") var/obj/item/clothing/W = target.wear_mask if(W.flags & NODROP) - return 0 + return FALSE target.unEquip(W) target.visible_message("[src] tears [W] off of [target]'s face!", \ @@ -159,7 +158,7 @@ spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME)) Impregnate(M) - return 1 + return TRUE /obj/item/clothing/mask/facehugger/proc/Impregnate(mob/living/target as mob) if(!target || target.stat == DEAD || loc != target) //was taken off or something @@ -220,22 +219,22 @@ /proc/CanHug(mob/living/M) if(!istype(M)) - return 0 + return FALSE if(M.stat == DEAD) - return 0 - if(M.get_int_organ(/obj/item/organ/internal/xenos/hivenode)) - return 0 + return FALSE + if(HAS_TRAIT(M, TRAIT_XENO_IMMUNE)) + return FALSE if(iscorgi(M)) - return 1 + return TRUE var/mob/living/carbon/C = M if(ishuman(C)) var/mob/living/carbon/human/H = C if(H.head && H.head.flags_cover & HEADCOVERSMOUTH) - return 0 - return 1 - return 0 + return FALSE + return TRUE + return FALSE /obj/item/clothing/mask/facehugger/lamarr name = "Lamarr" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index e4a711546a4..81a0174a945 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -39,7 +39,7 @@ adjust_nutrition(-(hunger_drain * 0.1)) if(m_intent == MOVE_INTENT_RUN) adjust_nutrition(-(hunger_drain * 0.1)) - if((FAT in mutations) && m_intent == MOVE_INTENT_RUN && bodytemperature <= 360) + if(HAS_TRAIT(src, TRAIT_FAT) && m_intent == MOVE_INTENT_RUN && bodytemperature <= 360) bodytemperature += 2 // Moving around increases germ_level faster @@ -244,7 +244,7 @@ if(prob(30) && ishuman(M)) // 30% chance of burning your hands var/mob/living/carbon/human/H = M var/protected = FALSE // Protected from the fire - if((H.gloves?.max_heat_protection_temperature > 360) || (HEATRES in H.mutations)) + if((H.gloves?.max_heat_protection_temperature > 360) || HAS_TRAIT(H, TRAIT_RESISTHEAT) || HAS_TRAIT(H, TRAIT_RESISTHEATHANDS)) protected = TRUE var/obj/item/organ/external/active_hand = H.get_organ("[H.hand ? "l" : "r"]_hand") @@ -327,7 +327,7 @@ to_chat(src, "You're completely exhausted.") else to_chat(src, "You feel fatigued.") - if((SKELETON in H.mutations) && (!H.w_uniform) && (!H.wear_suit)) + if(HAS_TRAIT(H, TRAIT_SKELETONIZED) && (!H.w_uniform) && (!H.wear_suit)) H.play_xylophone() /mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0) @@ -1200,10 +1200,14 @@ so that different stomachs can handle things in different ways VB*/ if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates. return - if(XRAY in mutations) + if(HAS_TRAIT(src, TRAIT_THERMAL_VISION)) + sight |= (SEE_MOBS) + lighting_alpha = min(lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE) + + if(HAS_TRAIT(src, TRAIT_XRAY_VISION)) sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) - see_in_dark = 8 - lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + see_in_dark = max(see_in_dark, 8) + lighting_alpha = min(lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE) SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT) sync_lighting_plane_alpha() diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 5eb373a301d..1ec9bb19c3b 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -119,9 +119,9 @@ dna.species.update_sight(src) /mob/living/carbon/human/proc/makeSkeleton() - var/obj/item/organ/external/head/H = get_organ("head") - if(SKELETON in src.mutations) + if(HAS_TRAIT(src, TRAIT_SKELETONIZED)) return + var/obj/item/organ/external/head/H = get_organ("head") if(istype(H)) H.disfigured = TRUE @@ -140,45 +140,39 @@ update_head_accessory() update_markings() - mutations.Add(SKELETON) - mutations.Add(NOCLONE) + ADD_TRAIT(src, TRAIT_SKELETONIZED, "skeletonization") + ADD_TRAIT(src, TRAIT_BADDNA, "skeletonization") update_body() update_mutantrace() - return -/mob/living/carbon/human/proc/ChangeToHusk() - - // If the target has no DNA to begin with, its DNA can't be damaged beyond repair. - if(NO_DNA in dna.species.species_traits) - return - if(HUSK in mutations) - return - - var/obj/item/organ/external/head/H = bodyparts_by_name["head"] - if(istype(H)) - H.disfigured = TRUE //makes them unknown without fucking up other stuff like admintools - if(H.f_style) - H.f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE - if(H.h_style) - H.h_style = "Bald" - update_fhair() - update_hair() - - mutations.Add(HUSK) - update_body() - update_mutantrace() - return +/mob/living/carbon/human/proc/become_husk(source) + if(!HAS_TRAIT(src, TRAIT_HUSK)) + ADD_TRAIT(src, TRAIT_HUSK, source) + var/obj/item/organ/external/head/H = bodyparts_by_name["head"] + if(istype(H)) + H.disfigured = TRUE //makes them unknown without fucking up other stuff like admintools + if(H.f_style) + H.f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE + if(H.h_style) + H.h_style = "Bald" + update_fhair() + update_hair() + update_body() + update_mutantrace() + else + ADD_TRAIT(src, TRAIT_HUSK, source) /mob/living/carbon/human/proc/Drain() - ChangeToHusk() - mutations |= NOCLONE - return + become_husk(CHANGELING_DRAIN) + ADD_TRAIT(src, TRAIT_BADDNA, CHANGELING_DRAIN) + blood_volume = 0 -/mob/living/carbon/human/proc/cure_husk() - mutations.Remove(HUSK) - var/obj/item/organ/external/head/H = bodyparts_by_name["head"] - if(istype(H)) - H.disfigured = FALSE - update_body() - update_mutantrace() - UpdateAppearance() // reset hair from DNA +/mob/living/carbon/human/proc/cure_husk(source) + REMOVE_TRAIT(src, TRAIT_HUSK, source) + if(!HAS_TRAIT(src, TRAIT_HUSK)) + var/obj/item/organ/external/head/H = bodyparts_by_name["head"] + if(istype(H)) + H.disfigured = FALSE + update_body() + update_mutantrace() + UpdateAppearance() // reset hair from DNA diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index c434ecc2694..cec48e0a9ea 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -1,6 +1,6 @@ /mob/living/carbon/human/emote(act, m_type = 1, message = null, force) - if((stat == DEAD) || (status_flags & FAKEDEATH)) + if((stat == DEAD) || HAS_TRAIT(src, TRAIT_FAKEDEATH)) return // No screaming bodies var/param = null @@ -37,7 +37,7 @@ on_CD = handle_emote_CD() emote("gasp") return - + switch(act) //This switch adds cooldowns to some emotes if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no", "buzz2") var/found_machine_head = FALSE diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 2ec78381536..059fd4a4c2a 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -37,7 +37,7 @@ if(C == src.head || C == src.wear_suit || C == src.wear_mask || C == src.w_uniform || C == src.belt || C == src.back) if(C.species_disguise) displayed_species = C.species_disguise - if(skipjumpsuit && skipface || (NO_EXAMINE in dna.species.species_traits)) //either obscured or on the nospecies list + if(skipjumpsuit && skipface || HAS_TRAIT(src, TRAIT_NOEXAMINE)) //either obscured or on the nospecies list msg += "!\n" //omit the species when examining else if(displayed_species == "Slime People") //snowflakey because Slime People are defined as a plural msg += ", a slime person!\n" @@ -177,7 +177,7 @@ var/appears_dead = FALSE - if(stat == DEAD || (status_flags & FAKEDEATH)) + if(stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH)) appears_dead = TRUE if(suiciding) msg += "[p_they(TRUE)] appear[p_s()] to have committed suicide... there is no hope of recovery.\n" @@ -298,7 +298,7 @@ if(nutrition < NUTRITION_LEVEL_HYPOGLYCEMIA) msg += "[p_they(TRUE)] [p_are()] severely malnourished.\n" - if(FAT in mutations) + if(HAS_TRAIT(src, TRAIT_FAT)) msg += "[p_they(TRUE)] [p_are()] morbidly obese.\n" if(user.nutrition < NUTRITION_LEVEL_HYPOGLYCEMIA) msg += "[p_they(TRUE)] [p_are()] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 4e0069dcfae..29137d76f5b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -504,7 +504,7 @@ //Returns "Unknown" if facially disfigured and real_name if not. Useful for setting name when polyacided or when updating a human's name variable /mob/living/carbon/human/proc/get_face_name() var/obj/item/organ/external/head = get_organ("head") - if(!head || head.disfigured || cloneloss > 50 || !real_name || (HUSK in mutations)) //disfigured. use id-name if possible + if(!head || head.disfigured || cloneloss > 50 || !real_name || HAS_TRAIT(src, TRAIT_HUSK)) //disfigured. use id-name if possible return "Unknown" return real_name @@ -1007,7 +1007,7 @@ else target_zone = user.zone_selected - if(PIERCEIMMUNE in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_PIERCEIMMUNE)) . = FALSE var/obj/item/organ/external/affecting = get_organ(target_zone) @@ -1127,12 +1127,9 @@ check_and_regenerate_organs(src) //Regenerate limbs and organs only if they're really missing. surgeries.Cut() //End all surgeries. - if(!isskeleton(src) && (SKELETON in mutations)) - mutations.Remove(SKELETON) - if(NOCLONE in mutations) - mutations.Remove(NOCLONE) - if(HUSK in mutations) - mutations.Remove(HUSK) + REMOVE_TRAIT(src, TRAIT_SKELETONIZED, null) + REMOVE_TRAIT(src, TRAIT_BADDNA, null) + cure_husk() if(!client || !key) //Don't boot out anyone already in the mob. for(var/obj/item/organ/internal/brain/H in world) @@ -1161,7 +1158,7 @@ L.damage = L.min_bruised_damage /mob/living/carbon/human/cuff_resist(obj/item/I) - if(HULK in mutations) + if(HAS_TRAIT(src, TRAIT_HULK)) say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) if(..(I, cuff_break = 1)) unEquip(I) @@ -1221,7 +1218,7 @@ set_species(new_dna.species.type, retain_damage = TRUE) dna = new_dna.Clone() real_name = new_dna.real_name - domutcheck(src, null, MUTCHK_FORCED) //Ensures species that get powers by the species proc handle_dna keep them + domutcheck(src, MUTCHK_FORCED) //Ensures species that get powers by the species proc handle_dna keep them if(!keep_flavor_text) flavor_text = "" dna.UpdateSE() @@ -1247,8 +1244,7 @@ if(gender == PLURAL && oldspecies.has_gender) change_gender(pick(MALE, FEMALE)) - if(oldspecies.default_genes.len) - oldspecies.handle_dna(src, TRUE) // Remove any genes that belong to the old species + oldspecies.handle_dna(src, TRUE) // Remove any mutations that belong to the old species oldspecies.on_species_loss(src) @@ -1504,7 +1500,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X if(!get_location_accessible(src, "eyes")) return FALSE // Natural eyeshine, any implants, and XRAY - all give shiny appearance. - if((istype(eyes) && eyes.shine()) || istype(eye_implant) || (XRAY in mutations)) + if((istype(eyes) && eyes.shine()) || istype(eye_implant) || HAS_TRAIT(src, TRAIT_XRAY_VISION)) return TRUE return FALSE @@ -1607,16 +1603,11 @@ Eyes need to have significantly high darksight to shine unless the mob has the X return ..() -/mob/living/carbon/human/rad_act(amount) - if(RADIMMUNE in dna.species.species_traits) - return SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, amount) - . = ..() - /mob/living/carbon/human/proc/do_cpr(mob/living/carbon/human/H) if(H == src) to_chat(src, "You cannot perform CPR on yourself!") return - if(H.stat == DEAD || (H.status_flags & FAKEDEATH)) + if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_FAKEDEATH)) to_chat(src, "[H.name] is dead!") return if(!check_has_mouth()) @@ -1771,12 +1762,9 @@ Eyes need to have significantly high darksight to shine unless the mob has the X . = ..() if(G.trigger_guard == TRIGGER_GUARD_NORMAL) - if(HULK in mutations) + if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS)) to_chat(src, "Your meaty finger is much too large for the trigger guard!") return FALSE - if(NOGUNS in dna.species.species_traits) - to_chat(src, "Your fingers don't fit in the trigger guard!") - return FALSE if(mind && mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry to_chat(src, "[mind.martial_art.no_guns_message]") @@ -1901,12 +1889,12 @@ Eyes need to have significantly high darksight to shine unless the mob has the X . += "---" /mob/living/carbon/human/adjust_nutrition(change) - if(NO_HUNGER in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_NOHUNGER)) return FALSE return ..() /mob/living/carbon/human/set_nutrition(change) - if(NO_HUNGER in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_NOHUNGER)) return FALSE return ..() @@ -1961,7 +1949,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X /mob/living/carbon/human/proc/cleanSE() //remove all disabilities/powers for(var/block = 1; block <= DNA_SE_LENGTH; block++) dna.SetSEState(block, FALSE, TRUE) - genemutcheck(src, block, null, MUTCHK_FORCED) + singlemutcheck(src, block, MUTCHK_FORCED) dna.UpdateSE() /mob/living/carbon/human/get_spooked() diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 621d8330761..2073f8ca0be 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -14,9 +14,8 @@ health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute - //TODO: fix husking - if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD) - ChangeToHusk() + if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD * 2) && stat == DEAD) + become_husk(BURN) update_stat("updatehealth([reason])") med_hud_set_health() @@ -170,17 +169,11 @@ // Defined here solely to take species flags into account without having to recast at mob/living level. /mob/living/carbon/human/adjustOxyLoss(amount) - if(NO_BREATHE in dna.species.species_traits) - oxyloss = 0 - return FALSE if(dna.species && amount > 0) amount = amount * dna.species.oxy_mod . = ..() /mob/living/carbon/human/setOxyLoss(amount) - if(NO_BREATHE in dna.species.species_traits) - oxyloss = 0 - return FALSE if(dna.species && amount > 0) amount = amount * dna.species.oxy_mod . = ..() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 18cb61c4244..96226b8d697 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -37,7 +37,7 @@ emp_act return 2 if(mind?.martial_art?.deflection_chance) //Some martial arts users can deflect projectiles! - if(!lying && !(HULK in mutations) && prob(mind.martial_art.deflection_chance)) //But only if they're not lying down, and hulks can't do it + if(!lying && !HAS_TRAIT(src, TRAIT_HULK) && prob(mind.martial_art.deflection_chance)) //But only if they're not lying down, and hulks can't do it add_attack_logs(P.firer, src, "hit by [P.type] but got deflected by martial arts '[mind.martial_art]'") visible_message("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!", "You deflect the projectile!") return FALSE @@ -518,7 +518,7 @@ emp_act else if(I) if(((throwingdatum ? throwingdatum.speed : I.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || I.embedded_ignore_throwspeed_threshold) if(can_embed(I)) - if(prob(I.embed_chance) && !(PIERCEIMMUNE in dna.species.species_traits)) + if(prob(I.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE)) throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) var/obj/item/organ/external/L = pick(bodyparts) L.embedded_objects |= I diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index b4a65b110a9..6ea6398e9fd 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -65,7 +65,7 @@ // standing is poor if(stance_damage >= 8) if(!(lying || resting)) - if(!(NO_PAIN in dna.species.species_traits)) + if(!HAS_TRAIT(src, TRAIT_NOPAIN)) emote("scream") custom_emote(1, "collapses!") Weaken(5) //can't emote while weakened, apparently. @@ -93,7 +93,7 @@ continue var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ") - custom_emote(1, "[(NO_PAIN in dna.species.species_traits) ? "" : emote_scream ]drops what [p_they()] [p_were()] holding in [p_their()] [E.name]!") + custom_emote(1, "[HAS_TRAIT(src, TRAIT_NOPAIN) ? "" : emote_scream ]drops what [p_they()] [p_were()] holding in [p_their()] [E.name]!") else if(E.is_malfunctioning()) @@ -119,11 +119,11 @@ /mob/living/carbon/human/proc/becomeSlim() to_chat(src, "You feel fit again!") - mutations.Remove(FAT) + ADD_TRAIT(src, TRAIT_FAT, OBESITY) /mob/living/carbon/human/proc/becomeFat() to_chat(src, "You suddenly feel blubbery!") - mutations.Add(FAT) + REMOVE_TRAIT(src, TRAIT_FAT, OBESITY) //Handles chem traces /mob/living/carbon/human/proc/handle_trace_chems() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 1e1363bdec2..a943de4e79d 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -15,7 +15,7 @@ if(.) //not dead if(check_mutations) - domutcheck(src,null) + domutcheck(src) update_mutations() check_mutations = FALSE @@ -101,7 +101,7 @@ else //blindness - if(BLINDNESS in mutations) // Disabled-blind, doesn't get better on its own + if(HAS_TRAIT(src, TRAIT_BLIND)) // Disabled-blind, doesn't get better on its own else if(eye_blind) // Blindness, heals slowly over time AdjustEyeBlind(-1) @@ -170,11 +170,11 @@ emote("drool") /mob/living/carbon/human/handle_mutations_and_radiation() - for(var/datum/dna/gene/gene in GLOB.dna_genes) - if(!gene.block) + for(var/datum/mutation/mutation in GLOB.dna_mutations) + if(!mutation.block) continue - if(gene.is_active(src)) - gene.OnMobLife(src) + if(mutation.is_active(src)) + mutation.on_life(src) if(!ignore_gene_stability && gene_stability < GENETIC_DAMAGE_STAGE_1) var/instability = DEFAULT_GENE_STABILITY - gene_stability if(prob(instability * 0.1)) @@ -207,7 +207,7 @@ if(!L || L && (L.status & ORGAN_DEAD)) if(health >= HEALTH_THRESHOLD_CRIT) adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1) - else if(!(NOCRITDAMAGE in dna.species.species_traits)) + else if(!HAS_TRAIT(src, TRAIT_NOCRITDAMAGE)) adjustOxyLoss(HUMAN_MAX_OXYLOSS) if(dna.species) @@ -329,7 +329,7 @@ if(status_flags & GODMODE) return 1 //godmode if(adjusted_pressure >= dna.species.hazard_high_pressure) - if(!(HEATRES in mutations)) + if(!HAS_TRAIT(src, TRAIT_RESISTHIGHPRESSURE)) var/pressure_damage = min( ( (adjusted_pressure / dna.species.hazard_high_pressure) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) take_overall_damage(brute=pressure_damage, updating_health = TRUE, used_weapon = "High Pressure") throw_alert("pressure", /obj/screen/alert/highpressure, 2) @@ -342,7 +342,7 @@ else if(adjusted_pressure >= dna.species.hazard_low_pressure) throw_alert("pressure", /obj/screen/alert/lowpressure, 1) else - if(COLDRES in mutations) + if(HAS_TRAIT(src, TRAIT_RESISTLOWPRESSURE)) clear_alert("pressure") else take_overall_damage(brute=LOW_PRESSURE_DAMAGE, updating_health = TRUE, used_weapon = "Low Pressure") @@ -354,7 +354,7 @@ . = ..() if(!.) return - if(HEATRES in mutations) + if(HAS_TRAIT(src, TRAIT_NOFIRE)) return var/thermal_protection = get_thermal_protection() @@ -417,7 +417,7 @@ /mob/living/carbon/human/proc/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to. - if(HEATRES in mutations) + if(HAS_TRAIT(src, TRAIT_RESISTHEAT)) return 1 var/thermal_protection_flags = get_heat_protection_flags(temperature) @@ -478,7 +478,7 @@ /mob/living/carbon/human/proc/get_cold_protection(temperature) - if(COLDRES in mutations) + if(HAS_TRAIT(src, TRAIT_RESISTCOLD)) return 1 //Fully protected from the cold. temperature = max(temperature, TCMB) //There is an occasional bug where the temperature is miscalculated in areas with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. @@ -536,12 +536,12 @@ if(status_flags & GODMODE) return 0 //godmode - if(!(NO_HUNGER in dna.species.species_traits)) - if(FAT in mutations) + if(!HAS_TRAIT(src, TRAIT_NOHUNGER)) + if(HAS_TRAIT(src, TRAIT_FAT)) if(overeatduration < 100) becomeSlim() else - if(overeatduration > 500 && !(NO_OBESITY in dna.species.species_traits)) + if(overeatduration > 500 && !HAS_TRAIT(src, TRAIT_NOFAT)) becomeFat() // nutrition decrease @@ -564,8 +564,8 @@ else if(overeatduration > 1) - if(OBESITY in mutations) - overeatduration -= 1 // Those with obesity gene take twice as long to unfat + if(HAS_TRAIT(src, TRAIT_SLOWDIGESTION)) + overeatduration -= 1 // Those with slow digestion trait, it takes longer to lose weight else overeatduration -= 2 @@ -626,7 +626,7 @@ var/collapse_start = 75 var/braindamage_start = 120 var/alcohol_strength = drunk - var/sober_str =! (SOBER in mutations) ? 1 : 2 + var/sober_str = !HAS_TRAIT(src, TRAIT_ALCOHOL_TOLERANCE) ? 1 : 2 alcohol_strength /= sober_str @@ -800,7 +800,7 @@ healthdoll.cached_healthdoll_overlays = new_overlays /mob/living/carbon/human/proc/handle_nutrition_alerts() //This is a terrible abuse of the alert system; something like this should be a HUD element - if(NO_HUNGER in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_NOHUNGER)) return if(mind?.vampire && (mind in SSticker.mode.vampires)) //Vampires switch(nutrition) @@ -887,7 +887,7 @@ if(blood_volume <= BLOOD_VOLUME_BAD)//how much blood do we have temp = PULSE_THREADY //not enough :( - if(status_flags & FAKEDEATH) + if(HAS_TRAIT(src, TRAIT_FAKEDEATH)) temp = PULSE_NONE //pretend that we're dead. unlike actual death, can be inflienced by meds for(var/datum/reagent/R in reagents.reagent_list) @@ -912,7 +912,7 @@ /mob/living/carbon/human/proc/handle_decay() var/decaytime = world.time - timeofdeath - if(NO_DECAY in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_NODECAY)) return if(reagents.has_reagent("formaldehyde")) //embalming fluid stops decay @@ -943,7 +943,7 @@ var/obj/item/clothing/mask/M = H.wear_mask if(M && (M.flags_cover & MASKCOVERSMOUTH)) continue - if(NO_BREATHE in H.dna.species.species_traits) + if(HAS_TRAIT(H, TRAIT_NOBREATH)) continue //no puking if you can't smell! // Humans can lack a mind datum, y'know if(H.mind && (H.mind.assigned_role == "Detective" || H.mind.assigned_role == "Coroner")) diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 3a2b646e510..54882305fca 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -96,7 +96,7 @@ if(translator && translator.active) return TRUE // how do species that don't breathe talk? magic, that's what. - var/breathes = (!(NO_BREATHE in dna.species.species_traits)) + var/breathes = (!HAS_TRAIT(src, TRAIT_NOBREATH)) var/obj/item/organ/internal/L = get_organ_slot("lungs") if((breathes && !L) || breathes && L && (L.status & ORGAN_DEAD)) return FALSE @@ -129,12 +129,10 @@ S.message = "[S.message]" verb = translator.speech_verb return list("verb" = verb) - if((COMIC in mutations) \ - || (locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) \ - || HAS_TRAIT(src, TRAIT_JESTER)) + if(HAS_TRAIT(src, TRAIT_COMIC_SANS)) span = "sans" - if(WINGDINGS in mutations) + if(HAS_TRAIT(src, TRAIT_WINGDINGS)) span = "wingdings" var/list/parent = ..() @@ -144,7 +142,7 @@ if(S.speaking && S.speaking.flags & NO_STUTTER) continue - if(silent || (MUTE in mutations)) + if(silent || HAS_TRAIT(src, TRAIT_MUTE)) S.message = "" if(istype(wear_mask, /obj/item/clothing/mask/horsehead)) @@ -154,11 +152,11 @@ verb = pick("whinnies", "neighs", "says") if(dna) - for(var/datum/dna/gene/gene in GLOB.dna_genes) - if(!gene.block) + for(var/datum/mutation/mutation in GLOB.dna_mutations) + if(!mutation.block) continue - if(gene.is_active(src)) - S.message = gene.OnSay(src, S.message) + if(mutation.is_active(src)) + S.message = mutation.on_say(src, S.message) var/braindam = getBrainLoss() if(braindam >= 60) diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 17abcd9ba2c..ad919c080be 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -57,7 +57,6 @@ var/punchdamagelow = 0 //lowest possible punch damage var/punchdamagehigh = 9 //highest possible punch damage var/punchstunthreshold = 9 //damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical - var/list/default_genes = list() var/ventcrawler = VENTCRAWLER_NONE //Determines if the mob can go through the vents. var/has_fine_manipulation = 1 // Can use small items. @@ -65,6 +64,8 @@ var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here. var/list/species_traits = list() + ///Generic traits tied to having the species. + var/list/inherent_traits = list() var/breathid = "o2" @@ -212,7 +213,7 @@ ears = new mutantears(H) /datum/species/proc/breathe(mob/living/carbon/human/H) - if((NO_BREATHE in species_traits) || (BREATHLESS in H.mutations)) + if(HAS_TRAIT(H, TRAIT_NOBREATH)) return TRUE //////////////// @@ -222,17 +223,15 @@ /datum/species/proc/movement_delay(mob/living/carbon/human/H) . = 0 //We start at 0. - if(H.status_flags & IGNORE_SPEED_CHANGES) - return . if(has_gravity(H)) - if(H.status_flags & GOTTAGOFAST) + if(HAS_TRAIT(H, TRAIT_GOTTAGOFAST)) . -= 1 - else if(H.status_flags & GOTTAGONOTSOFAST) + else if(HAS_TRAIT(H, TRAIT_GOTTAGONOTSOFAST)) . -= 0.5 var/ignoreslow = FALSE - if((H.status_flags & IGNORESLOWDOWN) || (RUN in H.mutations)) + if(HAS_TRAIT(H, TRAIT_IGNORESLOWDOWN)) ignoreslow = TRUE var/flight = H.flying //Check for flight and flying items @@ -259,16 +258,17 @@ for(var/datum/reagent/R in H.reagents.reagent_list) if(R.shock_reduction) health_deficiency -= R.shock_reduction - if(health_deficiency >= 40) - if(flight) - . += (health_deficiency / 75) - else - . += (health_deficiency / 25) + if(!HAS_TRAIT(H, TRAIT_IGNOREDAMAGESLOWDOWN)) + if(health_deficiency >= 40) + if(flight) + . += (health_deficiency / 75) + else + . += (health_deficiency / 25) . += 2 * H.stance_damage //damaged/missing feet or legs is slow if((hungry >= 70) && !flight) . += hungry/50 - if(FAT in H.mutations) + if(HAS_TRAIT(H, TRAIT_FAT)) . += (1.5 - flight) if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) . += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR @@ -286,11 +286,22 @@ H.hud_used.update_locked_slots() H.ventcrawler = ventcrawler + for(var/X in inherent_traits) + ADD_TRAIT(H, X, SPECIES_TRAIT) + + if(TRAIT_VIRUSIMMUNE in inherent_traits) + for(var/datum/disease/A in H.viruses) + if(!A.bypasses_immunity) + A.cure(FALSE) + if(inherent_factions) for(var/i in inherent_factions) H.faction += i //Using +=/-= for this in case you also gain the faction from a different source. /datum/species/proc/on_species_loss(mob/living/carbon/human/H) + for(var/X in inherent_traits) + REMOVE_TRAIT(H, X, SPECIES_TRAIT) + if(H.butcher_results) //clear it out so we don't butcher a actual human. H.butcher_results = null H.ventcrawler = initial(H.ventcrawler) @@ -317,8 +328,8 @@ // For special snowflake species effects // (Slime People changing color based on the reagents they consume) /datum/species/proc/handle_life(mob/living/carbon/human/H) - if((NO_BREATHE in species_traits) || (BREATHLESS in H.mutations)) - var/takes_crit_damage = (!(NOCRITDAMAGE in species_traits)) + if(HAS_TRAIT(H, TRAIT_NOBREATH)) + var/takes_crit_damage = (!HAS_TRAIT(H, TRAIT_NOCRITDAMAGE)) if((H.health <= HEALTH_THRESHOLD_CRIT) && takes_crit_damage) H.adjustBruteLoss(1) return @@ -376,7 +387,7 @@ /datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(attacker_style && attacker_style.help_act(user, target) == TRUE)//adminfu only... return TRUE - if(target.health >= HEALTH_THRESHOLD_CRIT && !(target.status_flags & FAKEDEATH)) + if(target.health >= HEALTH_THRESHOLD_CRIT && !HAS_TRAIT(target, TRAIT_FAKEDEATH)) target.help_shake_act(user) return TRUE else @@ -404,7 +415,7 @@ if(target.mind && target.mind.vampire && (target.mind in SSticker.mode.vampires)) to_chat(user, "Your fangs fail to pierce [target.name]'s cold flesh") return - if(SKELETON in target.mutations) + if(HAS_TRAIT(target, TRAIT_SKELETONIZED)) to_chat(user, "There is no blood in a skeleton!") return //we're good to suck the blood, blaah @@ -750,7 +761,7 @@ return FALSE /datum/species/proc/handle_mutations_and_radiation(mob/living/carbon/human/H) - if(RADIMMUNE in species_traits) + if(HAS_TRAIT(H, TRAIT_RADIMMUNE)) H.radiation = 0 return TRUE @@ -771,7 +782,7 @@ to_chat(H, "You mutate!") randmutb(H) H.emote("gasp") - domutcheck(H, null) + domutcheck(H) if(radiation > RAD_MOB_HAIRLOSS) var/obj/item/organ/external/head/head_organ = H.get_organ("head") @@ -873,7 +884,11 @@ It'll return null if the organ doesn't correspond, so include null checks when u if(H.vision_type.light_sensitive) H.weakeyes = TRUE - if(XRAY in H.mutations) + if(HAS_TRAIT(src, TRAIT_THERMAL_VISION)) + H.sight |= (SEE_MOBS) + H.lighting_alpha = min(H.lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE) + + if(HAS_TRAIT(H, TRAIT_XRAY_VISION)) H.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) if(H.has_status_effect(STATUS_EFFECT_SUMMONEDGHOST)) @@ -906,7 +921,7 @@ It'll return null if the organ doesn't correspond, so include null checks when u /datum/species/proc/can_hear(mob/living/carbon/human/H) . = FALSE var/obj/item/organ/internal/ears/ears = H.get_int_organ(/obj/item/organ/internal/ears) - if(istype(ears) && !ears.deaf) + if(istype(ears) && !HAS_TRAIT(H, TRAIT_DEAF)) . = TRUE /** diff --git a/code/modules/mob/living/carbon/human/species/abductor.dm b/code/modules/mob/living/carbon/human/species/abductor.dm index d7220d3a3e9..4370501f557 100644 --- a/code/modules/mob/living/carbon/human/species/abductor.dm +++ b/code/modules/mob/living/carbon/human/species/abductor.dm @@ -14,7 +14,8 @@ "eyes" = /obj/item/organ/internal/eyes/abductor //3 darksight. ) - species_traits = list(NO_BLOOD, NO_BREATHE, VIRUSIMMUNE, NOGUNS, NO_HUNGER, NO_EXAMINE) + species_traits = list(NO_BLOOD) + inherent_traits = list(TRAIT_VIRUSIMMUNE, TRAIT_CHUNKYFINGERS, TRAIT_NOHUNGER, TRAIT_NOBREATH, TRAIT_NOEXAMINE) dies_at_threshold = TRUE taste_sensitivity = TASTE_SENSITIVITY_NO_TASTE diff --git a/code/modules/mob/living/carbon/human/species/diona.dm b/code/modules/mob/living/carbon/human/species/diona.dm index 133a334a998..736a8d577ef 100644 --- a/code/modules/mob/living/carbon/human/species/diona.dm +++ b/code/modules/mob/living/carbon/human/species/diona.dm @@ -21,7 +21,8 @@ even the simplest concepts of other minds. Their alien physiology allows them survive happily off a diet of nothing but light, \ water and other radiation." - species_traits = list(IS_PLANT, NO_GERMS, NO_DECAY) + species_traits = list(IS_PLANT) + inherent_traits = list(TRAIT_NOGERMS, TRAIT_NODECAY) clothing_flags = HAS_SOCKS default_hair_colour = "#000000" has_gender = FALSE @@ -112,6 +113,26 @@ H.adjustBruteLoss(2) ..() +/datum/species/diona/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H) + switch(P.type) + if(/obj/item/projectile/energy/floramut) + if(prob(15)) + H.rad_act(rand(30, 80)) + H.Weaken(5) + H.visible_message("[H] writhes in pain as [H.p_their()] vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.") + if(prob(80)) + randmutb(H) + domutcheck(H) + else + randmutg(H) + domutcheck(H) + else + H.adjustFireLoss(rand(5, 15)) + H.show_message("The radiation beam singes you!") + if(/obj/item/projectile/energy/florayield) + H.set_nutrition(min(H.nutrition + 30, NUTRITION_LEVEL_FULL)) + return TRUE + /datum/species/diona/pod //Same name and everything; we want the same limitations on them; we just want their regeneration to kick in at all times and them to have special factions pod = TRUE inherent_factions = list("plants", "vines") diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm index cde56de264b..4e0060f0e54 100644 --- a/code/modules/mob/living/carbon/human/species/golem.dm +++ b/code/modules/mob/living/carbon/human/species/golem.dm @@ -5,7 +5,8 @@ icobase = 'icons/mob/human_races/r_golem.dmi' deform = 'icons/mob/human_races/r_golem.dmi' - species_traits = list(NO_BREATHE, NO_BLOOD, NO_PAIN, RADIMMUNE, NOGUNS, PIERCEIMMUNE) + species_traits = list(NO_BLOOD) + inherent_traits = list(TRAIT_RESISTHEAT, TRAIT_NOBREATH, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_NOFIRE, TRAIT_CHUNKYFINGERS, TRAIT_RADIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_NOPAIN) dies_at_threshold = TRUE speed_mod = 2 brute_mod = 0.45 //55% damage reduction @@ -24,19 +25,6 @@ dietflags = DIET_OMNI //golems can eat anything because they are magic or something reagent_tag = PROCESS_ORG - warning_low_pressure = -INFINITY - hazard_low_pressure = -INFINITY - hazard_high_pressure = INFINITY - warning_high_pressure = INFINITY - - cold_level_1 = -INFINITY - cold_level_2 = -INFINITY - cold_level_3 = -INFINITY - - heat_level_1 = INFINITY - heat_level_2 = INFINITY - heat_level_3 = INFINITY - blood_color = "#515573" flesh_color = "#137E8F" skinned_type = /obj/item/stack/sheet/metal @@ -138,10 +126,9 @@ /datum/species/golem/plasma name = "Plasma Golem" skinned_type = /obj/item/stack/ore/plasma + //Can burn and takes damage from heat + inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_CHUNKYFINGERS, TRAIT_RADIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_NOPAIN) //no RESISTHEAT, NOFIRE golem_colour = rgb(170, 51, 221) - heat_level_1 = 360 - heat_level_2 = 400 - heat_level_3 = 460 info_text = "As a Plasma Golem, you burn easily. Be careful, if you get hot enough while burning, you'll blow up!" heatmod = 0 //fine until they blow up prefix = "Plasma" @@ -327,8 +314,9 @@ name = "Wood Golem" golem_colour = rgb(158, 112, 75) skinned_type = /obj/item/stack/sheet/wood - species_traits = list(NO_BREATHE, NO_BLOOD, NO_PAIN, RADIMMUNE, NOGUNS, PIERCEIMMUNE, IS_PLANT) + species_traits = list(NO_BLOOD, IS_PLANT) // Refactor into biotype //Can burn and take damage from heat + inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_CHUNKYFINGERS, TRAIT_RADIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_NOPAIN) brute_mod = 0.7 //30% damage reduction down from 55% burn_mod = 0.875 tox_mod = 0.7 @@ -336,11 +324,6 @@ brain_mod = 0.7 stamina_mod = 0.7 heatmod = 1.5 - - heat_level_1 = 300 - heat_level_2 = 340 - heat_level_3 = 400 - dietflags = DIET_HERB // Plants eat...plants? info_text = "As a Wooden Golem, you have plant-like traits: you take damage from extreme temperatures, can be set on fire, and have lower armor than a normal golem. You regenerate when in the light and wither in the darkness." @@ -616,7 +599,7 @@ prefix = "Bananium" special_names = null unarmed_type = /datum/unarmed_attack/golem/bananium - + inherent_traits = list(TRAIT_RESISTHEAT, TRAIT_NOBREATH, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_NOFIRE, TRAIT_CHUNKYFINGERS, TRAIT_CLUMSY, TRAIT_COMIC_SANS, TRAIT_RADIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_NOPAIN) var/last_honk = 0 var/honkooldown = 0 var/last_banana = 0 @@ -627,7 +610,6 @@ ..() last_banana = world.time last_honk = world.time - H.mutations.Add(COMIC) H.equip_to_slot_or_del(new /obj/item/reagent_containers/food/drinks/bottle/bottleofbanana(H), slot_r_store) H.equip_to_slot_or_del(new /obj/item/bikehorn(H), slot_l_store) H.AddElement(/datum/element/waddling) diff --git a/code/modules/mob/living/carbon/human/species/grey.dm b/code/modules/mob/living/carbon/human/species/grey.dm index 76acd899adb..7eab20e00f4 100644 --- a/code/modules/mob/living/carbon/human/species/grey.dm +++ b/code/modules/mob/living/carbon/human/species/grey.dm @@ -19,8 +19,6 @@ brute_mod = 1.25 //greys are fragile - default_genes = list(REMOTE_TALK) - species_traits = list(LIPS, IS_WHITELISTED, CAN_WINGDINGS) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS bodyflags = HAS_BODY_MARKINGS @@ -32,9 +30,12 @@ /datum/species/grey/handle_dna(mob/living/carbon/human/H, remove) ..() - H.dna.SetSEState(GLOB.remotetalkblock, !remove, 1) - genemutcheck(H, GLOB.remotetalkblock, null, MUTCHK_FORCED) - H.dna.default_blocks.Add(GLOB.remotetalkblock) + H.dna.SetSEState(GLOB.remotetalkblock, !remove, TRUE) + singlemutcheck(H, GLOB.remotetalkblock, MUTCHK_FORCED) + if(!remove) + H.dna.default_blocks.Add(GLOB.remotetalkblock) + else + H.dna.default_blocks.Remove(GLOB.remotetalkblock) /datum/species/grey/water_act(mob/living/carbon/human/H, volume, temperature, source, method = REAGENT_TOUCH) . = ..() @@ -68,7 +69,7 @@ /datum/species/grey/after_equip_job(datum/job/J, mob/living/carbon/human/H) var/translator_pref = H.client.prefs.speciesprefs - if(translator_pref || ((ismindshielded(H) || J.is_command || J.supervisors == "the captain") && (WINGDINGS in H.mutations))) + if(translator_pref || ((ismindshielded(H) || J.is_command || J.supervisors == "the captain") && HAS_TRAIT(H, TRAIT_WINGDINGS))) if(J.title == "Mime") return if(J.title == "Clown") diff --git a/code/modules/mob/living/carbon/human/species/machine.dm b/code/modules/mob/living/carbon/human/species/machine.dm index b54b02929f9..972abc9e08c 100644 --- a/code/modules/mob/living/carbon/human/species/machine.dm +++ b/code/modules/mob/living/carbon/human/species/machine.dm @@ -22,7 +22,8 @@ death_message = "gives a short series of shrill beeps, their chassis shuddering before falling limp, nonfunctional." death_sounds = list('sound/voice/borg_deathsound.ogg') //I've made this a list in the event we add more sounds for dead robots. - species_traits = list(IS_WHITELISTED, NO_BREATHE, NO_BLOOD, NO_SCAN, NO_INTORGANS, NO_PAIN, NO_DNA, RADIMMUNE, VIRUSIMMUNE, NO_GERMS, NO_DECAY, NOTRANSSTING) //Computers that don't decay? What a lie! + species_traits = list(IS_WHITELISTED, NO_BLOOD, NO_CLONESCAN, NO_INTORGANS, NOTRANSSTING) + inherent_traits = list(TRAIT_VIRUSIMMUNE, TRAIT_NOBREATH, TRAIT_RADIMMUNE, TRAIT_NOGERMS, TRAIT_NODECAY, TRAIT_NOPAIN, TRAIT_GENELESS) //Computers that don't decay? What a lie! clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS bodyflags = HAS_SKIN_COLOR | HAS_HEAD_MARKINGS | HAS_HEAD_ACCESSORY | ALL_RPARTS dietflags = 0 //IPCs can't eat, so no diet diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm index 9c5b51b743b..b8af1384d08 100644 --- a/code/modules/mob/living/carbon/human/species/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/monkey.dm @@ -10,7 +10,7 @@ blood_mask = 'icons/mob/human_races/masks/blood_monkey.dmi' language = null default_language = "Chimpanzee" - species_traits = list(NO_EXAMINE) + inherent_traits = list(TRAIT_NOEXAMINE) skinned_type = /obj/item/stack/sheet/animalhide/monkey greater_form = /datum/species/human no_equip = list(slot_belt, slot_wear_id, slot_l_ear, slot_r_ear, slot_glasses, slot_gloves, slot_shoes, slot_wear_suit, slot_w_uniform, slot_l_store, slot_r_store, slot_s_store, slot_wear_pda) @@ -59,7 +59,7 @@ ..() if(!remove) H.dna.SetSEState(GLOB.monkeyblock, TRUE) - genemutcheck(H, GLOB.monkeyblock, null, MUTCHK_FORCED) + singlemutcheck(H, GLOB.monkeyblock, MUTCHK_FORCED) /datum/species/monkey/tajaran name = "Farwa" @@ -123,6 +123,8 @@ reagent_tag = PROCESS_ORG tail = null + inherent_traits = list(TRAIT_NOEXAMINE, TRAIT_NOFAT, TRAIT_WATERBREATH) + has_organ = list( "heart" = /obj/item/organ/internal/heart/skrell, "lungs" = /obj/item/organ/internal/lungs/skrell, @@ -132,13 +134,6 @@ "appendix" = /obj/item/organ/internal/appendix, "eyes" = /obj/item/organ/internal/eyes/skrell //Tajara monkey-forms are uniquely colourblind and have excellent darksight, which is why they need a subtype of their greater-form's organ.. ) -/datum/species/monkey/skrell/on_species_gain(mob/living/carbon/human/H) - ..() - ADD_TRAIT(H, TRAIT_WATERBREATH, "species") - -/datum/species/monkey/skrell/on_species_loss(mob/living/carbon/human/H) - ..() - REMOVE_TRAIT(H, TRAIT_WATERBREATH, "species") /datum/species/monkey/unathi name = "Stok" diff --git a/code/modules/mob/living/carbon/human/species/nucleation.dm b/code/modules/mob/living/carbon/human/species/nucleation.dm index f82a6283066..f5fa663641c 100644 --- a/code/modules/mob/living/carbon/human/species/nucleation.dm +++ b/code/modules/mob/living/carbon/human/species/nucleation.dm @@ -13,7 +13,8 @@ language = "Sol Common" burn_mod = 4 // holy shite, poor guys wont survive half a second cooking smores brute_mod = 2 // damn, double wham, double dam - species_traits = list(LIPS, IS_WHITELISTED, NO_BREATHE, NO_BLOOD, NO_PAIN, NO_SCAN, RADIMMUNE) + species_traits = list(LIPS, IS_WHITELISTED, NO_BLOOD, NO_CLONESCAN) + inherent_traits = list(TRAIT_NOBREATH, TRAIT_RADIMMUNE, TRAIT_NOPAIN) dies_at_threshold = TRUE dietflags = DIET_OMNI //still human at their core, so they maintain their eating habits and diet diff --git a/code/modules/mob/living/carbon/human/species/plasmaman.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm index 408a7451c39..c60abb4a19a 100644 --- a/code/modules/mob/living/carbon/human/species/plasmaman.dm +++ b/code/modules/mob/living/carbon/human/species/plasmaman.dm @@ -6,7 +6,8 @@ dangerous_existence = TRUE //So so much //language = "Clatter" - species_traits = list(IS_WHITELISTED, RADIMMUNE, NO_BLOOD, NO_HUNGER, NOTRANSSTING) + species_traits = list(IS_WHITELISTED, NO_BLOOD, NOTRANSSTING) + inherent_traits = list(TRAIT_RADIMMUNE, TRAIT_NOHUNGER) forced_heartattack = TRUE // Plasmamen have no blood, but they should still get heart-attacks skinned_type = /obj/item/stack/sheet/mineral/plasma // We're low on plasma, R&D! *eyes plasmaman co-worker intently* dietflags = DIET_OMNI @@ -143,26 +144,21 @@ return FALSE /datum/species/plasmaman/handle_life(mob/living/carbon/human/H) - var/datum/gas_mixture/environment = H.loc.return_air() - var/atmos_sealed = FALSE - if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing)) - var/obj/item/clothing/CS = H.wear_suit - var/obj/item/clothing/CH = H.head - if (CS.flags & CH.flags & STOPSPRESSUREDMAGE) - atmos_sealed = TRUE - if((!istype(H.w_uniform, /obj/item/clothing/under/plasmaman) || !istype(H.head, /obj/item/clothing/head/helmet/space/plasmaman)) && !atmos_sealed) + var/atmos_sealed = !HAS_TRAIT(H, TRAIT_NOFIRE) && (isclothing(H.wear_suit) && H.wear_suit.flags & STOPSPRESSUREDMAGE) && (isclothing(H.head) && H.head.flags & STOPSPRESSUREDMAGE) + if(!atmos_sealed && (!istype(H.w_uniform, /obj/item/clothing/under/plasmaman) || !istype(H.head, /obj/item/clothing/head/helmet/space/plasmaman))) + var/datum/gas_mixture/environment = H.loc.return_air() if(environment) if(environment.total_moles()) - if(environment.oxygen && environment.oxygen >= OXYCONCEN_PLASMEN_IGNITION) //Same threshhold that extinguishes fire - H.adjust_fire_stacks(0.5) - if(!H.on_fire && H.fire_stacks > 0) - H.visible_message("[H]'s body reacts with the atmosphere and bursts into flames!","Your body reacts with the atmosphere and bursts into flame!") - H.IgniteMob() - else - if(H.fire_stacks) - var/obj/item/clothing/under/plasmaman/P = H.w_uniform - if(istype(P)) - P.Extinguish(H) + if(!HAS_TRAIT(H, TRAIT_NOFIRE)) + if(environment.oxygen && environment.oxygen >= OXYCONCEN_PLASMEN_IGNITION) //Same threshhold that extinguishes fire + H.adjust_fire_stacks(0.5) + if(!H.on_fire && H.fire_stacks > 0) + H.visible_message("[H]'s body reacts with the atmosphere and bursts into flames!","Your body reacts with the atmosphere and bursts into flame!") + H.IgniteMob() + else if(H.fire_stacks) + var/obj/item/clothing/under/plasmaman/P = H.w_uniform + if(istype(P)) + P.Extinguish(H) H.update_fire() ..() diff --git a/code/modules/mob/living/carbon/human/species/shadow.dm b/code/modules/mob/living/carbon/human/species/shadow.dm index be2a7f44229..8b1bdcb9388 100644 --- a/code/modules/mob/living/carbon/human/species/shadow.dm +++ b/code/modules/mob/living/carbon/human/species/shadow.dm @@ -16,7 +16,8 @@ "eyes" = /obj/item/organ/internal/eyes/shadow //8 darksight. ) - species_traits = list(NO_BREATHE, NO_BLOOD, RADIMMUNE, VIRUSIMMUNE) + species_traits = list(NO_BLOOD) + inherent_traits = list(TRAIT_VIRUSIMMUNE, TRAIT_NOBREATH, TRAIT_RADIMMUNE) dies_at_threshold = TRUE dietflags = DIET_OMNI //the mutation process allowed you to now digest all foods regardless of initial race diff --git a/code/modules/mob/living/carbon/human/species/shadowling.dm b/code/modules/mob/living/carbon/human/species/shadowling.dm index 4667a6b1019..32c67401a57 100644 --- a/code/modules/mob/living/carbon/human/species/shadowling.dm +++ b/code/modules/mob/living/carbon/human/species/shadowling.dm @@ -9,7 +9,8 @@ blood_color = "#555555" flesh_color = "#222222" - species_traits = list(NO_BLOOD, NO_BREATHE, RADIMMUNE, NOGUNS, NO_HUNGER, NO_EXAMINE) //Can't use guns due to muzzle flash + species_traits = list(NO_BLOOD) //Can't use guns due to muzzle flash + inherent_traits = list(TRAIT_CHUNKYFINGERS, TRAIT_NOHUNGER, TRAIT_NOBREATH, TRAIT_RADIMMUNE, TRAIT_NOEXAMINE) burn_mod = 1.5 //1.5x burn damage, 2x is excessive heatmod = 1.5 @@ -42,8 +43,8 @@ H.adjustToxLoss(-5) H.adjustBrainLoss(-25) //Shad O. Ling gibbers, "CAN U BE MY THRALL?!!" H.AdjustEyeBlurry(-1) - H.CureNearsighted() - H.CureBlind() + H.cure_nearsighted() + H.cure_blind() H.adjustCloneLoss(-1) H.SetWeakened(0) H.SetStunned(0) @@ -59,7 +60,8 @@ blood_color = "#CCCCCC" flesh_color = "#AAAAAA" - species_traits = list(NO_BLOOD, NO_BREATHE, RADIMMUNE, NO_HUNGER, NO_EXAMINE) + species_traits = list(NO_BLOOD) + inherent_traits = list(TRAIT_NOBREATH, TRAIT_RADIMMUNE, TRAIT_NOHUNGER, TRAIT_NOEXAMINE) burn_mod = 1.1 heatmod = 1.1 diff --git a/code/modules/mob/living/carbon/human/species/skeleton.dm b/code/modules/mob/living/carbon/human/species/skeleton.dm index f5085742ccb..c1f3e64d2d2 100644 --- a/code/modules/mob/living/carbon/human/species/skeleton.dm +++ b/code/modules/mob/living/carbon/human/species/skeleton.dm @@ -10,7 +10,10 @@ blood_color = "#FFFFFF" flesh_color = "#E6E6C6" - species_traits = list(NO_BREATHE, NO_BLOOD, RADIMMUNE, VIRUSIMMUNE, NO_HUNGER, PIERCEIMMUNE) + species_traits = list(NO_BLOOD) + inherent_traits = list(TRAIT_RESISTHEAT, TRAIT_NOBREATH, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_RADIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_NOHUNGER, TRAIT_XENO_IMMUNE) + tox_mod = 0 + clone_mod = 0 dies_at_threshold = TRUE skinned_type = /obj/item/stack/sheet/bone @@ -19,19 +22,6 @@ dietflags = DIET_OMNI reagent_tag = PROCESS_ORG - warning_low_pressure = -INFINITY - hazard_low_pressure = -INFINITY - hazard_high_pressure = INFINITY - warning_high_pressure = INFINITY - - cold_level_1 = -INFINITY - cold_level_2 = -INFINITY - cold_level_3 = -INFINITY - - heat_level_1 = INFINITY - heat_level_2 = INFINITY - heat_level_3 = INFINITY - suicide_messages = list( "is snapping their own bones!", "is collapsing into a pile!", diff --git a/code/modules/mob/living/carbon/human/species/skrell.dm b/code/modules/mob/living/carbon/human/species/skrell.dm index e65196ee2f8..899d9cb6b2f 100644 --- a/code/modules/mob/living/carbon/human/species/skrell.dm +++ b/code/modules/mob/living/carbon/human/species/skrell.dm @@ -13,7 +13,8 @@ the secrets of their empire to their allies." - species_traits = list(LIPS, NO_OBESITY) + species_traits = list(LIPS) + inherent_traits = list(TRAIT_NOFAT, TRAIT_WATERBREATH) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS bodyflags = HAS_SKIN_COLOR | HAS_BODY_MARKINGS dietflags = DIET_HERB @@ -45,11 +46,3 @@ "is twisting their own neck!", "makes like a fish and suffocates!", "is strangling themselves with their own tendrils!") - -/datum/species/skrell/on_species_gain(mob/living/carbon/human/H) - ..() - ADD_TRAIT(H, TRAIT_WATERBREATH, "species") - -/datum/species/skrell/on_species_loss(mob/living/carbon/human/H) - ..() - REMOVE_TRAIT(H, TRAIT_WATERBREATH, "species") diff --git a/code/modules/mob/living/carbon/human/species/slime.dm b/code/modules/mob/living/carbon/human/species/slime.dm index e22d767eeb0..7da9e49c5c0 100644 --- a/code/modules/mob/living/carbon/human/species/slime.dm +++ b/code/modules/mob/living/carbon/human/species/slime.dm @@ -26,7 +26,8 @@ male_cough_sounds = list('sound/effects/slime_squish.ogg') female_cough_sounds = list('sound/effects/slime_squish.ogg') - species_traits = list(LIPS, IS_WHITELISTED, NO_SCAN, EXOTIC_COLOR) + species_traits = list(LIPS, IS_WHITELISTED, NO_CLONESCAN, EXOTIC_COLOR) + inherent_traits = list(TRAIT_WATERBREATH) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS bodyflags = HAS_SKIN_COLOR | NO_EYES dietflags = DIET_CARN @@ -73,7 +74,6 @@ grow.Grant(H) recolor = new() recolor.Grant(H) - ADD_TRAIT(H, TRAIT_WATERBREATH, "species") RegisterSignal(H, COMSIG_HUMAN_UPDATE_DNA, /datum/species/slime/./proc/blend) blend(H) @@ -84,7 +84,6 @@ grow.Remove(H) if(recolor) recolor.Remove(H) - REMOVE_TRAIT(H, TRAIT_WATERBREATH, "species") UnregisterSignal(H, COMSIG_HUMAN_UPDATE_DNA) /datum/species/slime/proc/blend(mob/living/carbon/human/H) @@ -112,8 +111,10 @@ -/datum/species/slime/can_hear() // fucking snowflakes - . = TRUE +/datum/species/slime/can_hear(mob/living/carbon/human/H) // fucking snowflakes + . = FALSE + if(!HAS_TRAIT(H, TRAIT_DEAF)) + . = TRUE /datum/action/innate/slimecolor name = "Toggle Recolor" diff --git a/code/modules/mob/living/carbon/human/species/unathi.dm b/code/modules/mob/living/carbon/human/species/unathi.dm index d4e9b02cd9b..d5fd16084bf 100644 --- a/code/modules/mob/living/carbon/human/species/unathi.dm +++ b/code/modules/mob/living/carbon/human/species/unathi.dm @@ -117,4 +117,4 @@ default_language = "Sinta'unathi" speed_mod = -0.80 - species_traits = list(NO_BREATHE, NOGUNS) + inherent_traits = list(TRAIT_CHUNKYFINGERS, TRAIT_NOBREATH) diff --git a/code/modules/mob/living/carbon/human/species/vox.dm b/code/modules/mob/living/carbon/human/species/vox.dm index 37da7bc2698..8171a42955c 100644 --- a/code/modules/mob/living/carbon/human/species/vox.dm +++ b/code/modules/mob/living/carbon/human/species/vox.dm @@ -23,7 +23,8 @@ eyes = "vox_eyes_s" - species_traits = list(NO_SCAN, NO_GERMS, NO_DECAY, IS_WHITELISTED, NOTRANSSTING) + species_traits = list(NO_CLONESCAN, IS_WHITELISTED, NOTRANSSTING) + inherent_traits = list(TRAIT_NOGERMS, TRAIT_NODECAY) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS //Species-fitted 'em all. dietflags = DIET_OMNI bodyflags = HAS_ICON_SKIN_TONE | HAS_TAIL | TAIL_WAGGING | TAIL_OVERLAPPED | HAS_BODY_MARKINGS | HAS_TAIL_MARKINGS @@ -150,23 +151,13 @@ unarmed_type = /datum/unarmed_attack/claws/armalis blacklisted = TRUE - warning_low_pressure = 50 - hazard_low_pressure = 0 - - cold_level_1 = 80 - cold_level_2 = 50 - cold_level_3 = 0 - - heat_level_1 = 2000 - heat_level_2 = 3000 - heat_level_3 = 4000 - brute_mod = 0.2 burn_mod = 0.2 eyes = "blank_eyes" - species_traits = list(NO_SCAN, NO_GERMS, NO_DECAY, NO_BLOOD, NO_PAIN, IS_WHITELISTED) + species_traits = list(NO_CLONESCAN, NO_BLOOD, IS_WHITELISTED) + inherent_traits = list(TRAIT_RESISTHEAT, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_NOFIRE, TRAIT_NOPAIN, TRAIT_NOGERMS, TRAIT_NODECAY) clothing_flags = 0 //IDK if you've ever seen underwear on an Armalis, but it ain't pretty. bodyflags = HAS_TAIL dies_at_threshold = TRUE diff --git a/code/modules/mob/living/carbon/human/species/wryn.dm b/code/modules/mob/living/carbon/human/species/wryn.dm index e977022d0d3..95f9b859f1f 100644 --- a/code/modules/mob/living/carbon/human/species/wryn.dm +++ b/code/modules/mob/living/carbon/human/species/wryn.dm @@ -35,7 +35,8 @@ "antennae" = /obj/item/organ/internal/wryn/hivenode ) - species_traits = list(LIPS, IS_WHITELISTED, NO_BREATHE, NO_SCAN, HIVEMIND) + species_traits = list(LIPS, IS_WHITELISTED, NO_CLONESCAN, HIVEMIND) + inherent_traits = list(TRAIT_NOBREATH) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS bodyflags = HAS_SKIN_COLOR dietflags = DIET_HERB //bees feed off nectar, so bee people feed off plants too diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 818e15f26e8..0beb30088da 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -1,9 +1,3 @@ -/mob/living/carbon/human/SetLoseBreath(amount) - if(NO_BREATHE in dna.species.species_traits) - losebreath = 0 - return FALSE - . = ..() - /mob/living/carbon/human/SetStunned(amount, updating = 1, force = 0) if(dna.species.stun_mod) amount = amount * dna.species.stun_mod diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 204112546a0..5d9e8af255d 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -172,9 +172,9 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) var/husk_color_mod = rgb(96, 88, 80) var/hulk_color_mod = rgb(48, 224, 40) - var/husk = (HUSK in mutations) - var/hulk = (HULK in mutations) - var/skeleton = (SKELETON in mutations) + var/husk = HAS_TRAIT(src, TRAIT_HUSK) + var/hulk = HAS_TRAIT(src, TRAIT_HULK) + var/skeleton = HAS_TRAIT(src, TRAIT_SKELETONIZED) if(dna.species && dna.species.bodyflags & HAS_ICON_SKIN_TONE) dna.species.updatespeciescolor(src) @@ -450,20 +450,18 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) if(gender == FEMALE) g = "f" // DNA2 - Drawing underlays. - for(var/datum/dna/gene/gene in GLOB.dna_genes) - if(!gene.block) + for(var/datum/mutation/mutation in GLOB.dna_mutations) + if(!mutation.block) continue - if(gene.is_active(src)) - var/underlay = gene.OnDrawUnderlays(src, g) + if(mutation.is_active(src)) + var/underlay = mutation.on_draw_underlays(src, g) if(underlay) standing.underlays += underlay add_image = 1 - for(var/mut in mutations) - switch(mut) - if(LASER) - standing.overlays += "lasereyes_s" - add_image = 1 - if((COLDRES in mutations) && (HEATRES in mutations)) + if(HAS_TRAIT(src, TRAIT_LASEREYES)) + standing.overlays += "lasereyes_s" + add_image = 1 + if(dna.GetSEState(GLOB.fireblock) && dna.GetSEState(GLOB.coldblock)) standing.underlays -= "cold_s" standing.underlays -= "fire_s" standing.underlays += "coldfire_s" @@ -475,7 +473,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) /mob/living/carbon/human/proc/update_mutantrace() //BS12 EDIT - var/skel = (SKELETON in mutations) + var/skel = HAS_TRAIT(src, TRAIT_SKELETONIZED) if(skel) skeleton = 'icons/mob/human_races/r_skeleton.dmi' else @@ -1300,9 +1298,9 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) return out /mob/living/carbon/human/proc/generate_icon_render_key() - var/husk = (HUSK in mutations) - var/hulk = (HULK in mutations) - var/skeleton = (SKELETON in mutations) + var/husk = HAS_TRAIT(src, TRAIT_HUSK) + var/hulk = HAS_TRAIT(src, TRAIT_HULK) + var/skeleton = HAS_TRAIT(src, TRAIT_SKELETONIZED) var/g = dna.GetUITriState(DNA_UI_GENDER) if(g == DNA_GENDER_PLURAL) g = DNA_GENDER_FEMALE diff --git a/code/modules/mob/living/carbon/human/update_stat.dm b/code/modules/mob/living/carbon/human/update_stat.dm index d5d1801e1a7..52452cbc251 100644 --- a/code/modules/mob/living/carbon/human/update_stat.dm +++ b/code/modules/mob/living/carbon/human/update_stat.dm @@ -12,7 +12,7 @@ /mob/living/carbon/human/update_nearsighted_effects() var/obj/item/clothing/glasses/G = glasses - if((NEARSIGHTED in mutations) && (!istype(G) || !G.prescription)) + if(HAS_TRAIT(src, TRAIT_NEARSIGHT) && (!istype(G) || !G.prescription)) overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1) else clear_fullscreen("nearsighted") diff --git a/code/modules/mob/living/carbon/superheroes.dm b/code/modules/mob/living/carbon/superheroes.dm index 32a562b212c..93d412e56c2 100644 --- a/code/modules/mob/living/carbon/superheroes.dm +++ b/code/modules/mob/living/carbon/superheroes.dm @@ -7,12 +7,11 @@ var/name var/desc var/class - var/list/default_genes = list(REGEN, BREATHLESS, COLDRES) var/list/default_spells = list() var/activated = FALSE //for wishgranters to not give an option if someone already has it. /datum/superheroes/proc/create(var/mob/living/carbon/human/H) - assign_genes(H) + assign_mutations(H) assign_spells(H) equip(H) fixflags(H) @@ -29,11 +28,11 @@ for(var/obj/item/W in H.get_all_slots()) W.flags |= NODROP -/datum/superheroes/proc/assign_genes(var/mob/living/carbon/human/H) - if(default_genes.len) - for(var/gene in default_genes) - H.mutations |= gene - H.update_mutations() +/datum/superheroes/proc/assign_mutations(var/mob/living/carbon/human/H) + var/list/default_mutations = list(GLOB.regenerateblock, GLOB.breathlessblock, GLOB.coldblock) + for(var/mutation in default_mutations) + H.dna.SetSEState(mutation, 1) + singlemutcheck(H, mutation, MUTCHK_FORCED) /datum/superheroes/proc/assign_spells(var/mob/living/carbon/human/H) if(default_spells.len) diff --git a/code/modules/mob/living/carbon/update_status.dm b/code/modules/mob/living/carbon/update_status.dm index 918968800ce..88a04749368 100644 --- a/code/modules/mob/living/carbon/update_status.dm +++ b/code/modules/mob/living/carbon/update_status.dm @@ -6,7 +6,7 @@ death() create_debug_log("died of damage, trigger reason: [reason]") return - if(paralysis || sleeping || (check_death_method() && getOxyLoss() > 50) || (status_flags & FAKEDEATH) || health <= HEALTH_THRESHOLD_CRIT && check_death_method()) + if(paralysis || sleeping || (check_death_method() && getOxyLoss() > 50) || HAS_TRAIT(src, TRAIT_FAKEDEATH) || health <= HEALTH_THRESHOLD_CRIT && check_death_method()) if(stat == CONSCIOUS) KnockOut() create_debug_log("fell unconscious, trigger reason: [reason]") @@ -29,5 +29,5 @@ /mob/living/carbon/can_hear() . = FALSE var/obj/item/organ/internal/ears/ears = get_int_organ(/obj/item/organ/internal/ears) - if(istype(ears) && !ears.deaf) + if(istype(ears) && !HAS_TRAIT(src, TRAIT_DEAF)) . = TRUE diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index c0f667e9d31..e7be12930ce 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -84,7 +84,8 @@ if(PARALYZE) Paralyse(effect * blocked) if(IRRADIATE) - radiation += max(effect * blocked, 0) + if(!HAS_TRAIT(src, TRAIT_RADIMMUNE)) + radiation += max(effect * blocked, 0) if(SLUR) Slur(effect * blocked) if(STUTTER) @@ -148,7 +149,7 @@ if(status_flags & GODMODE) oxyloss = 0 return FALSE //godmode - if(BREATHLESS in mutations) + if(HAS_TRAIT(src, TRAIT_NOBREATH)) oxyloss = 0 return FALSE var/old_oxyloss = oxyloss @@ -165,7 +166,7 @@ if(status_flags & GODMODE) oxyloss = 0 return FALSE //godmode - if(BREATHLESS in mutations) + if(HAS_TRAIT(src, TRAIT_NOBREATH)) oxyloss = 0 return FALSE var/old_oxyloss = oxyloss diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index c0341f11b47..a325dddee26 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -155,7 +155,7 @@ /mob/living/proc/handle_disabilities() //Eyes - if((BLINDNESS in mutations) || stat) //blindness from disability or unconsciousness doesn't get better on its own + if(HAS_TRAIT(src, TRAIT_BLIND) || stat) //blindness from disability or unconsciousness doesn't get better on its own EyeBlind(1) else if(eye_blind) //blindness, heals slowly over time AdjustEyeBlind(-1) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 05b29d20545..92ca04aa5a8 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -242,7 +242,7 @@ /mob/living/pointed(atom/A as mob|obj|turf in view()) if(incapacitated(ignore_lying = TRUE)) return FALSE - if(status_flags & FAKEDEATH) + if(HAS_TRAIT(src, TRAIT_FAKEDEATH)) return FALSE if(!..()) return FALSE @@ -456,8 +456,8 @@ SetHallucinate(0) set_nutrition(NUTRITION_LEVEL_FED + 50) bodytemperature = 310 - CureBlind() - CureNearsighted() + cure_blind() + cure_nearsighted() CureMute() CureDeaf() CureTourettes() @@ -780,7 +780,7 @@ //called when the mob receives a bright flash /mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash) - if(check_eye_prot() < intensity && (override_blindness_check || !(BLINDNESS in mutations))) + if(check_eye_prot() < intensity && (override_blindness_check || !HAS_TRAIT(src, TRAIT_BLIND))) overlay_fullscreen("flash", type) addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25) return 1 @@ -1036,7 +1036,7 @@ /mob/living/rad_act(amount) . = ..() - if(!amount || (amount < RAD_MOB_SKIN_PROTECTION)) + if(!amount || (amount < RAD_MOB_SKIN_PROTECTION) || HAS_TRAIT(src, TRAIT_RADIMMUNE)) return amount -= RAD_BACKGROUND_RADIATION // This will always be at least 1 because of how skin protection is calculated diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index e2aeadf1963..d10208c00dc 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -62,7 +62,7 @@ return FALSE if((flags & SHOCK_TESLA) && HAS_TRAIT(src, TRAIT_TESLA_SHOCKIMMUNE)) return FALSE - if(NO_SHOCK in mutations) //shockproof + if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE)) return FALSE shock_damage *= siemens_coeff if(shock_damage < 1) @@ -166,15 +166,14 @@ //Mobs on Fire /mob/living/proc/IgniteMob() - if(fire_stacks > 0 && !on_fire) - on_fire = 1 - visible_message("[src] catches fire!", \ - "You're set on fire!") + if(fire_stacks > 0 && !on_fire && !HAS_TRAIT(src, TRAIT_NOFIRE)) + on_fire = TRUE + visible_message("[src] catches fire!", "You're set on fire!") set_light(light_range + 3,l_color = "#ED9200") throw_alert("fire", /obj/screen/alert/fire) update_fire() - return 1 - return 0 + return TRUE + return FALSE /mob/living/proc/ExtinguishMob() if(on_fire) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 9bba6784af5..4465cdeb9db 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -67,7 +67,7 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key) if(S.speaking && S.speaking.flags & NO_STUTTER) continue - if((HULK in mutations) && health >= 25) + if(HAS_TRAIT(src, TRAIT_HULK) && health >= 25) S.message = "[uppertext(S.message)]!!!" verb = pick("yells", "roars", "hollers") diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 6cb0cc53bd0..bf6119394f5 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -230,7 +230,7 @@ var/mode = 1 /obj/item/robotanalyzer/attack(mob/living/M as mob, mob/living/user as mob) - if(( (CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) + if((HAS_TRAIT(user, TRAIT_CLUMSY) || user.getBrainLoss() >= 60) && prob(50)) user.visible_message("[user] has analyzed the floor's vitals!", "You try to analyze the floor's vitals!") to_chat(user, "Analyzing Results for The floor:\n\t Overall Status: Healthy") to_chat(user, "\t Damage Specifics: [0]-[0]-[0]-[0]") diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index e0f58ee5764..036efc973ef 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -168,7 +168,7 @@ if(!spam_flag) if(ishuman(C)) C.stuttering = 20 //stammer - C.MinimumDeafTicks(0, 5) //far less damage than the H.O.N.K. + C.AdjustEarDamage(0, 5) //far less damage than the H.O.N.K. C.Jitter(50) C.Weaken(5) C.Stun(5) // Paralysis from tg ported as stun diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 5246a536d92..4f9002e7f11 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -458,7 +458,7 @@ soft_reset() return - if(C.stat == DEAD || (C.status_flags & FAKEDEATH)) + if(C.stat == DEAD || HAS_TRAIT(C, TRAIT_FAKEDEATH)) var/list/messagevoice = list("No! Stay with me!" = 'sound/voice/mno.ogg', "Live, damnit! LIVE!" = 'sound/voice/mlive.ogg', "I...I've never lost a patient before. Not today, I mean." = 'sound/voice/mlost.ogg') var/message = pick(messagevoice) speak(message) diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index 57cf403e33b..7f832b4e089 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -213,7 +213,6 @@ icon_resting = "Syndicat_rest" meow_sound = null //Need robo-meow. gender = FEMALE - mutations = list(BREATHLESS) faction = list("syndicate") gold_core_spawnable = NO_SPAWN eats_mice = 0 @@ -222,6 +221,10 @@ melee_damage_lower = 5 melee_damage_upper = 15 +/mob/living/simple_animal/pet/cat/Syndi/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_NOBREATH, SPECIES_TRAIT) + /mob/living/simple_animal/pet/cat/cak name = "Keeki" desc = "It's a cat made out of cake." diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 37667e6efad..578b3ac7e75 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -353,7 +353,7 @@ desc = initial(desc) set_light(0) atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) - mutations.Remove(BREATHLESS) + REMOVE_TRAIT(src, TRAIT_NOBREATH, DOGGO_SPACESUIT) minbodytemp = initial(minbodytemp) if(inventory_head && inventory_head.dog_fashion) diff --git a/code/modules/mob/living/simple_animal/friendly/fox.dm b/code/modules/mob/living/simple_animal/friendly/fox.dm index 9eccc473e6d..d1a3f430353 100644 --- a/code/modules/mob/living/simple_animal/friendly/fox.dm +++ b/code/modules/mob/living/simple_animal/friendly/fox.dm @@ -33,7 +33,6 @@ icon_living = "Syndifox" icon_dead = "Syndifox_dead" icon_resting = "Syndifox_rest" - mutations = list(BREATHLESS) faction = list("syndicate") unique_pet = TRUE gold_core_spawnable = NO_SPAWN @@ -41,3 +40,7 @@ minbodytemp = 0 melee_damage_lower = 10 melee_damage_upper = 20 + +/mob/living/simple_animal/pet/dog/fox/Syndifox/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_NOBREATH, SPECIES_TRAIT) diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 275eb133862..043d145ba64 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -46,7 +46,7 @@ if(istype(F) && !F.intact) var/obj/structure/cable/C = locate() in F if(C && prob(15)) - if(C.avail()) + if(C.avail() && !HAS_TRAIT(src, TRAIT_SHOCKIMMUNE)) visible_message("[src] chews through [C]. It's toast!") playsound(src, 'sound/effects/sparks2.ogg', 100, 1) toast() // mmmm toasty. @@ -169,6 +169,10 @@ unique_pet = TRUE gold_core_spawnable = NO_SPAWN +/mob/living/simple_animal/mouse/brown/Tom/Initialize(mapload) + . = ..() + // Tom fears no cable. + ADD_TRAIT(src, TRAIT_SHOCKIMMUNE, SPECIES_TRAIT) /mob/living/simple_animal/mouse/blobinfected maxHealth = 100 diff --git a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm index 196de37457c..23b9ceb2c6b 100644 --- a/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm +++ b/code/modules/mob/living/simple_animal/hostile/floorcluwne.dm @@ -346,7 +346,7 @@ visible_message("[src] begins dragging [H] under the floor!") if(do_after(src, 50, target = H) && eating) - H.BecomeBlind() + H.become_blind(FLOORCLUWNE) H.layer = GAME_PLANE H.invisibility = INVISIBILITY_MAXIMUM H.mouse_opacity = 0 @@ -388,7 +388,7 @@ O.droplimb() Reset_View(FALSE, old_color, H) - H.CureBlind() + H.cure_blind(FLOORCLUWNE) H.layer = initial(H.layer) H.invisibility = initial(H.invisibility) H.mouse_opacity = initial(H.mouse_opacity) diff --git a/code/modules/mob/living/simple_animal/hostile/headslug.dm b/code/modules/mob/living/simple_animal/hostile/headslug.dm index d53a5f033f6..dbc9380d451 100644 --- a/code/modules/mob/living/simple_animal/hostile/headslug.dm +++ b/code/modules/mob/living/simple_animal/hostile/headslug.dm @@ -50,7 +50,7 @@ // Changeling egg can survive in aliens! var/mob/living/carbon/C = target if(C.stat == DEAD) - if(C.status_flags & XENO_HOST) + if(HAS_TRAIT(C, TRAIT_XENO_HOST)) to_chat(src, "A foreign presence repels us from this body. Perhaps we should try to infest another?") return Infect(target) diff --git a/code/modules/mob/living/simple_animal/hostile/hellhound.dm b/code/modules/mob/living/simple_animal/hostile/hellhound.dm index 9107aa03457..2ae36d88db0 100644 --- a/code/modules/mob/living/simple_animal/hostile/hellhound.dm +++ b/code/modules/mob/living/simple_animal/hostile/hellhound.dm @@ -7,7 +7,6 @@ icon_living = "hellhound" icon_dead = "hellhound_dead" icon_resting = "hellhound_rest" - mutations = list(BREATHLESS) atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 maxbodytemp = INFINITY @@ -39,6 +38,7 @@ . = ..() whisper_action = new() whisper_action.Grant(src) + ADD_TRAIT(src, TRAIT_NOBREATH, SPECIES_TRAIT) /mob/living/simple_animal/hostile/hellhound/handle_automated_action() if(!..()) diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm index 7504f7d379e..f24e979a152 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm @@ -250,7 +250,7 @@ /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H) visible_message("[name] burrows into the flesh of [H]!") var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L - if((DWARF in H.mutations)) //dwarf legions aren't just fluff! + if(HAS_TRAIT(H, TRAIT_DWARF)) //dwarf legions aren't just fluff! L = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf(H.loc) else L = new(H.loc) @@ -328,9 +328,8 @@ /obj/effect/mob_spawn/human/corpse/damaged/legioninfested/dwarf/equip(mob/living/carbon/human/H) . = ..() - H.dna.SetSEState(GLOB.smallsizeblock, 1, 1) - H.mutations.Add(DWARF) - genemutcheck(H, GLOB.smallsizeblock, null, MUTCHK_FORCED) + H.dna.SetSEState(GLOB.smallsizeblock, TRUE, TRUE) + singlemutcheck(H, GLOB.smallsizeblock, MUTCHK_FORCED) H.update_mutations() /obj/effect/mob_spawn/human/corpse/damaged/legioninfested/Initialize(mapload) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 88930e224fa..8219c359109 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -239,7 +239,7 @@ var/areatemp = get_temperature(environment) - if(abs(areatemp - bodytemperature) > 5 && !(BREATHLESS in mutations)) + if(abs(areatemp - bodytemperature) > 5 && !HAS_TRAIT(src, TRAIT_NOBREATH)) var/diff = areatemp - bodytemperature diff = diff / 5 bodytemperature += diff diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 4afd47b839d..fe0800b952f 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -18,10 +18,6 @@ // BOOLEAN STATES /* - * EyesBlocked - Your eyes are covered somehow - * EarsBlocked - Your ears are covered somehow * Resting You are lying down of your own volition * Flying @@ -33,68 +29,46 @@ // All of these decrement over time - at a rate of 1 per life cycle unless otherwise noted // Status effects sorted alphabetically: /* - * Confused * + * Confused * Movement is scrambled - * Dizzy * + * Dizzy * The screen goes all warped - * Drowsy + * Drowsy You begin to yawn, and have a chance of incrementing "Paralysis" - * Druggy * + * Druggy * A trippy overlay appears. - * Drunk * + * Drunk * Essentially what your "BAC" is - the higher it is, the more alcohol you have in you - * EyeBlind * + * EyeBlind * You cannot see. Prevents EyeBlurry from healing naturally. - * EyeBlurry * + * EyeBlurry * A hazy overlay appears on your screen. - * Hallucination * + * Hallucination * Your character will imagine various effects happening to them, vividly. - * Jitter * + * Jitter * Your character will visibly twitch. Higher values amplify the effect. * LoseBreath * Your character is unable to breathe. - * Paralysis * + * Paralysis * Your character is knocked out. - * Silent * + * Silent * Your character is unable to speak. - * Sleeping * + * Sleeping * Your character is asleep. - * Slowed * + * Slowed * Your character moves slower. - * Slurring * + * Slurring * Your character cannot enunciate clearly. - * CultSlurring * + * CultSlurring * Your character cannot enunciate clearly while mumbling about elder codes. - * Stunned * + * Stunned * Your character is unable to move, and drops stuff in their hands. They keep standing, though. * Stuttering * Your character stutters parts of their messages. - * Weakened * + * Weakened * Your character collapses, but is still conscious. */ -// DISABILITIES -// These are more permanent than the above. -// Disabilities sorted alphabetically -/* - * Blind (32) - Can't see. EyeBlind does not heal when this is active. - * Coughing (4) - Cough occasionally, causing you to drop your items - * Deaf (128) - Can't hear. EarDeaf does not heal when this is active - * Epilepsy (2) - Occasionally go "Epileptic", causing you to become very twitchy, drop all items, and fall to the floor - * Mute (64) - Cannot talk. - * Nearsighted (1) - My glasses! I can't see without my glasses! (Nearsighted overlay when not wearing prescription eyewear) - * Nervous (16) - Occasionally begin to stutter. - * Tourettes (8) - SHIT (say bad words, and drop stuff occasionally) -*/ - /mob/living // Booleans @@ -281,7 +255,7 @@ SetLoseBreath(max(losebreath, amount)) /mob/living/SetLoseBreath(amount) - if(BREATHLESS in mutations) + if(HAS_TRAIT(src, TRAIT_NOBREATH)) losebreath = 0 return FALSE losebreath = max(amount, 0) @@ -455,96 +429,63 @@ // Blind -/mob/living/proc/BecomeBlind(updating = TRUE) - var/val_change = !(BLINDNESS in mutations) +/mob/living/proc/become_blind(source, updating = TRUE) + var/val_change = !HAS_TRAIT(src, TRAIT_BLIND) . = val_change ? STATUS_UPDATE_BLIND : STATUS_UPDATE_NONE - mutations |= BLINDNESS + ADD_TRAIT(src, TRAIT_BLIND, source) if(val_change && updating) update_blind_effects() -/mob/living/proc/CureBlind(updating = TRUE) - var/val_change = !!(BLINDNESS in mutations) +/mob/living/proc/cure_blind(source, updating = TRUE) + var/val_change = !!HAS_TRAIT(src, TRAIT_BLIND) . = val_change ? STATUS_UPDATE_BLIND : STATUS_UPDATE_NONE - mutations -= BLINDNESS + REMOVE_TRAIT(src, TRAIT_BLIND, source) if(val_change && updating) - CureIfHasDisability(GLOB.blindblock) update_blind_effects() // Coughing - -/mob/living/proc/BecomeCoughing() - mutations |= COUGHING - /mob/living/proc/CureCoughing() - mutations -= COUGHING CureIfHasDisability(GLOB.coughblock) // Deaf - -/mob/living/proc/BecomeDeaf() - mutations |= DEAF - /mob/living/proc/CureDeaf() - mutations -= DEAF CureIfHasDisability(GLOB.deafblock) // Epilepsy - -/mob/living/proc/BecomeEpilepsy() - mutations |= EPILEPSY - /mob/living/proc/CureEpilepsy() - mutations -= EPILEPSY CureIfHasDisability(GLOB.epilepsyblock) // Mute - -/mob/living/proc/BecomeMute() - mutations |= MUTE - /mob/living/proc/CureMute() - mutations -= MUTE CureIfHasDisability(GLOB.muteblock) // Nearsighted - -/mob/living/proc/BecomeNearsighted(updating = TRUE) - var/val_change = !(NEARSIGHTED in mutations) +/mob/living/proc/become_nearsighted(source, updating = TRUE) + var/val_change = !HAS_TRAIT(src, TRAIT_NEARSIGHT) . = val_change ? STATUS_UPDATE_NEARSIGHTED : STATUS_UPDATE_NONE - mutations |= NEARSIGHTED + ADD_TRAIT(src, TRAIT_NEARSIGHT, source) if(val_change && updating) update_nearsighted_effects() -/mob/living/proc/CureNearsighted(updating = TRUE) - var/val_change = !!(NEARSIGHTED in mutations) +/mob/living/proc/cure_nearsighted(source, updating = TRUE) + var/val_change = !!HAS_TRAIT(src, TRAIT_NEARSIGHT) . = val_change ? STATUS_UPDATE_NEARSIGHTED : STATUS_UPDATE_NONE - mutations -= NEARSIGHTED + REMOVE_TRAIT(src, TRAIT_NEARSIGHT, source) if(val_change && updating) - CureIfHasDisability(GLOB.glassesblock) update_nearsighted_effects() // Nervous - -/mob/living/proc/BecomeNervous() - mutations |= NERVOUS - /mob/living/proc/CureNervous() - mutations -= NERVOUS CureIfHasDisability(GLOB.nervousblock) // Tourettes - -/mob/living/proc/BecomeTourettes() - mutations |= TOURETTES - /mob/living/proc/CureTourettes() - mutations -= TOURETTES CureIfHasDisability(GLOB.twitchblock) /mob/living/proc/CureIfHasDisability(block) if(dna && dna.GetSEState(block)) dna.SetSEState(block, 0, 1) //Fix the gene - genemutcheck(src, block,null, MUTCHK_FORCED) + singlemutcheck(src, block, MUTCHK_FORCED) dna.UpdateSE() ///////////////////////////////// FROZEN ///////////////////////////////////// diff --git a/code/modules/mob/living/update_status.dm b/code/modules/mob/living/update_status.dm index 8ef178918b4..317d6068514 100644 --- a/code/modules/mob/living/update_status.dm +++ b/code/modules/mob/living/update_status.dm @@ -25,7 +25,7 @@ clear_alert("high") /mob/living/update_nearsighted_effects() - if(NEARSIGHTED in mutations) + if(HAS_TRAIT(src, TRAIT_NEARSIGHT)) overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1) else clear_fullscreen("nearsighted") @@ -41,17 +41,17 @@ // Whether the mob can hear things /mob/living/can_hear() - . = !(DEAF in mutations) + . = !HAS_TRAIT(src, TRAIT_DEAF) // Whether the mob is able to see // `information_only` is for stuff that's purely informational - like blindness overlays // This flag exists because certain things like angel statues expect this to be false for dead people /mob/living/has_vision(information_only = FALSE) - return (information_only && stat == DEAD) || !(eye_blind || (BLINDNESS in mutations) || stat) + return (information_only && stat == DEAD) || !(eye_blind || HAS_TRAIT(src, TRAIT_BLIND) || stat) // Whether the mob is capable of talking /mob/living/can_speak() - if(!(silent || (MUTE in mutations))) + if(!(silent || HAS_TRAIT(src, TRAIT_MUTE))) if(is_muzzled()) var/obj/item/clothing/mask/muzzle/M = wear_mask if(M.mute >= MUZZLE_MUTE_MUFFLE) @@ -62,7 +62,7 @@ // Whether the mob is capable of standing or not /mob/living/proc/can_stand() - return !(IsWeakened() || paralysis || stat || (status_flags & FAKEDEATH)) + return !(IsWeakened() || paralysis || stat || HAS_TRAIT(src, TRAIT_FAKEDEATH)) // Whether the mob is capable of actions or not /mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, ignore_lying = FALSE, list/extra_checks = list(), use_default_checks = TRUE) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 49fa60b5c95..3bfce8f3555 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -105,9 +105,6 @@ var/datum/dna/dna = null //Carbon var/radiation = 0 //Carbon - var/list/mutations = list() //Carbon -- Doohl - //see: setup.dm for list of mutations - var/voice_name = "unidentifiable voice" var/list/faction = list("neutral") //Used for checking whether hostile simple animals will attack you, possibly more stuff later @@ -179,7 +176,7 @@ var/stance_damage = 0 //Whether this mob's ability to stand has been affected - var/list/active_genes = list() + var/list/active_mutations = list() var/last_movement = -100 // Last world.time the mob actually moved of its own accord. diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm index 3a053e74e16..b2bf830f577 100644 --- a/code/modules/mob/status_procs.dm +++ b/code/modules/mob/status_procs.dm @@ -58,10 +58,6 @@ /mob/proc/AdjustEarDamage() return -/mob/proc/MinimumDeafTicks() - return - - /mob/proc/EyeBlind() return diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index a2eeeb8e2be..7cc864ebfa0 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -1,7 +1,7 @@ /mob/living/carbon/human/proc/monkeyize() var/mob/H = src H.dna.SetSEState(GLOB.monkeyblock,1) - genemutcheck(H,GLOB.monkeyblock,null,MUTCHK_FORCED) + singlemutcheck(H, GLOB.monkeyblock, MUTCHK_FORCED) /mob/new_player/AIize() spawning = 1 diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm index 0100170bdca..d773f11bb55 100644 --- a/code/modules/mob/typing_indicator.dm +++ b/code/modules/mob/typing_indicator.dm @@ -23,7 +23,7 @@ GLOBAL_LIST_EMPTY(typing_indicator) if(ishuman(src)) var/mob/living/carbon/human/H = src - if((MUTE in H.mutations) || H.silent) + if(HAS_TRAIT(H, TRAIT_MUTE) || H.silent) overlays -= GLOB.typing_indicator[bubble_icon] return diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm index d94e69133a7..14156ac0dc6 100644 --- a/code/modules/paperwork/contract.dm +++ b/code/modules/paperwork/contract.dm @@ -266,7 +266,7 @@ if(!user.dna) return -1 user.dna.SetSEState(GLOB.hulkblock,1) - genemutcheck(user, GLOB.hulkblock,null,MUTCHK_FORCED) + singlemutcheck(user, GLOB.hulkblock, MUTCHK_FORCED) // Demonic power gives you consequenceless hulk user.gene_stability += GENE_INSTABILITY_MAJOR if(ishuman(user)) @@ -321,7 +321,9 @@ /obj/item/paper/contract/infernal/knowledge/FulfillContract(mob/living/carbon/human/user = target.current, blood = 0) if(!istype(user) || !user.mind) return -1 - user.mutations.Add(XRAY) + ADD_TRAIT(user, TRAIT_XRAY_VISION, "devils_bargain") + user.update_sight() + user.update_icons() user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/view_range(null)) return ..() diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 8a28ae335f2..04f3abc299f 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -97,7 +97,7 @@ set category = "Object" set src in usr - if((CLUMSY in usr.mutations) && prob(50)) + if(HAS_TRAIT(usr, TRAIT_CLUMSY) && prob(50)) to_chat(usr, "You cut yourself on the paper.") return if(!usr.is_literate()) @@ -390,7 +390,7 @@ to_chat(user, "You stamp the paper with your rubber stamp.") if(is_hot(P)) - if((CLUMSY in user.mutations) && prob(10)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10)) user.visible_message("[user] accidentally ignites [user.p_them()]self!", \ "You miss the paper and accidentally light yourself on fire!") user.unEquip(P) @@ -686,7 +686,7 @@ target.adjustFireLoss(150) // hard crit, the burning takes care of the rest. else if(myeffect == "Total Brain Death") to_chat(target,"You see a message appear in front of you in bright red letters: YHWH-3 ACTIVATED. TERMINATION IN 3 SECONDS") - target.mutations.Add(NOCLONE) + ADD_TRAIT(target, TRAIT_BADDNA, "evil_fax") target.adjustBrainLoss(125) else if(myeffect == "Honk Tumor") if(!target.get_int_organ(/obj/item/organ/internal/honktumor)) diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm index aa2a033f130..fa2a4ae4239 100644 --- a/code/modules/paperwork/paperplane.dm +++ b/code/modules/paperwork/paperplane.dm @@ -72,7 +72,7 @@ update_icon() else if(is_hot(P)) - if((CLUMSY in user.mutations) && prob(10)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10)) user.visible_message("[user] accidentally ignites [user.p_them()]self!", \ "You miss [src] and accidentally light yourself on fire!") user.unEquip(P) diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm index c1fa280c5c0..c0d121c2177 100644 --- a/code/modules/paperwork/ticketmachine.dm +++ b/code/modules/paperwork/ticketmachine.dm @@ -215,7 +215,7 @@ /obj/item/ticket_machine_ticket/attackby(obj/item/P, mob/living/carbon/human/user, params) //Stolen from papercode ..() if(is_hot(P)) - if((CLUMSY in user.mutations) && prob(10)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(10)) user.visible_message("[user] accidentally ignites [user.p_them()]self!", \ "You miss the paper and accidentally light yourself on fire!") user.drop_item() diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index fb669390c6c..cf346126f4d 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -576,9 +576,9 @@ else prot = 1 - if(prot > 0 || (HEATRES in user.mutations)) + if(prot > 0 || HAS_TRAIT(user, TRAIT_RESISTHEAT) || HAS_TRAIT(user, TRAIT_RESISTHEATHANDS)) to_chat(user, "You remove the light [fitting]") - else if(TK in user.mutations) + else if(user.dna?.GetSEState(GLOB.teleblock)) to_chat(user, "You telekinetically remove the light [fitting].") else if(user.a_intent == INTENT_DISARM || user.a_intent == INTENT_GRAB) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 2ac85a760e8..503cefe2356 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -172,7 +172,7 @@ //Exclude lasertag guns from the CLUMSY check. if(clumsy_check) if(istype(user)) - if((CLUMSY in user.mutations) && prob(40)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(40)) to_chat(user, "You shoot yourself in the foot with \the [src]!") var/shot_leg = pick("l_foot", "r_foot") process_fire(user, user, 0, params, zone_override = shot_leg) diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index 2a2131cc308..61d2fe80e4d 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -25,7 +25,7 @@ do_sparks(1, 1, src) else if(iscarbon(target)) var/mob/living/carbon/C = target - if(HULK in C.mutations) + if(HAS_TRAIT(C, TRAIT_HULK)) C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) else if(C.status_flags & CANWEAKEN) spawn(5) diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 71258e4fc0b..4c89919e0f6 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -133,30 +133,6 @@ impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser flag = "energy" -/obj/item/projectile/energy/floramut/on_hit(var/atom/target, var/blocked = 0) - ..() - var/mob/living/M = target - if(ishuman(target)) - var/mob/living/carbon/human/H = M - if(IS_PLANT in H.dna.species.species_traits) - if(prob(15)) - H.rad_act(rand(30, 80)) - H.Weaken(5) - H.visible_message("[H] writhes in pain as [M.p_their()] vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.") - if(prob(80)) - randmutb(H) - domutcheck(H, null) - else - randmutg(H) - domutcheck(H, null) - else - H.adjustFireLoss(rand(5, 15)) - H.show_message("The radiation beam singes you!") - else if(iscarbon(target)) - M.show_message("The radiation beam dissipates harmlessly through your body.") - else - return 1 - /obj/item/projectile/energy/florayield name = "beta somatoray" icon_state = "energy2" @@ -165,19 +141,6 @@ nodamage = 1 flag = "energy" -/obj/item/projectile/energy/florayield/on_hit(var/atom/target, var/blocked = 0) - ..() - var/mob/M = target - if(ishuman(target)) //These rays make plantmen fat. - var/mob/living/carbon/human/H = M - if(IS_PLANT in H.dna.species.species_traits) - H.set_nutrition(min(H.nutrition+30, NUTRITION_LEVEL_FULL)) - else if(iscarbon(target)) - M.show_message("The radiation beam dissipates harmlessly through your body.") - else - return 1 - - /obj/item/projectile/beam/mindflayer name = "flayer ray" diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index fdde6c8abe6..a6830c15786 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -227,24 +227,24 @@ return update_flags /datum/reagent/proc/fakedeath(mob/living/M) - if(M.status_flags & FAKEDEATH) + if(HAS_TRAIT(M, TRAIT_FAKEDEATH)) return if(!(M.status_flags & CANPARALYSE)) return if(M.mind && M.mind.changeling && M.mind.changeling.regenerating) //no messing with changeling's fake death return M.emote("deathgasp") - M.status_flags |= FAKEDEATH + ADD_TRAIT(M, TRAIT_FAKEDEATH, id) M.updatehealth("fakedeath reagent") /datum/reagent/proc/fakerevive(mob/living/M) - if(!(M.status_flags & FAKEDEATH)) + if(!HAS_TRAIT(M, TRAIT_FAKEDEATH)) return if(M.mind && M.mind.changeling && M.mind.changeling.regenerating) return if(M.resting) M.StopResting() - M.status_flags &= ~(FAKEDEATH) + REMOVE_TRAIT(M, TRAIT_FAKEDEATH, id) if(M.healthdoll) M.healthdoll.cached_healthdoll_overlays.Cut() M.updatehealth("fakedeath reagent end") diff --git a/code/modules/reagents/chemistry/reagents/admin.dm b/code/modules/reagents/chemistry/reagents/admin.dm index 90e6cff3bf6..9ebad4be89f 100644 --- a/code/modules/reagents/chemistry/reagents/admin.dm +++ b/code/modules/reagents/chemistry/reagents/admin.dm @@ -25,8 +25,8 @@ E.mend_fracture() E.internal_bleeding = FALSE M.SetEyeBlind(0, FALSE) - M.CureNearsighted(FALSE) - M.CureBlind(FALSE) + M.cure_nearsighted(null, FALSE) + M.cure_blind(null, FALSE) M.CureMute() M.CureDeaf() M.CureEpilepsy() diff --git a/code/modules/reagents/chemistry/reagents/drink_cold.dm b/code/modules/reagents/chemistry/reagents/drink_cold.dm index fb40e7133ef..3d225263359 100644 --- a/code/modules/reagents/chemistry/reagents/drink_cold.dm +++ b/code/modules/reagents/chemistry/reagents/drink_cold.dm @@ -73,11 +73,11 @@ update_flags |= M.Druggy(30, FALSE) M.AdjustDizzy(5) M.SetDrowsy(0) - M.status_flags |= GOTTAGONOTSOFAST + ADD_TRAIT(M, TRAIT_GOTTAGONOTSOFAST, id) return ..() | update_flags /datum/reagent/consumable/drink/cold/nuka_cola/on_mob_delete(mob/living/M) - M.status_flags &= ~GOTTAGONOTSOFAST + REMOVE_TRAIT(M, TRAIT_GOTTAGONOTSOFAST, id) ..() /datum/reagent/consumable/drink/cold/spacemountainwind diff --git a/code/modules/reagents/chemistry/reagents/drinks.dm b/code/modules/reagents/chemistry/reagents/drinks.dm index 53187fc8c35..f1d0b61ca1d 100644 --- a/code/modules/reagents/chemistry/reagents/drinks.dm +++ b/code/modules/reagents/chemistry/reagents/drinks.dm @@ -74,8 +74,8 @@ if(1 to 20) //nothing if(21 to INFINITY) - if(prob(current_cycle-10)) - update_flags |= M.CureNearsighted(FALSE) + if(prob(current_cycle - 10)) + update_flags |= M.cure_nearsighted(EYE_DAMAGE, FALSE) return ..() | update_flags /datum/reagent/consumable/drink/doctor_delight @@ -178,7 +178,7 @@ /datum/reagent/consumable/drink/banana/on_mob_life(mob/living/M) var/update_flags = STATUS_UPDATE_NONE - if((ishuman(M) && (COMIC in M.mutations)) || issmall(M)) + if(HAS_TRAIT(M, TRAIT_COMIC_SANS) || issmall(M)) update_flags |= M.adjustBruteLoss(-1, FALSE) update_flags |= M.adjustFireLoss(-1, FALSE) return ..() | update_flags @@ -409,7 +409,7 @@ /datum/reagent/consumable/drink/bananahonk/on_mob_life(mob/living/M) var/update_flags = STATUS_UPDATE_NONE - if((ishuman(M) && (COMIC in M.mutations)) || issmall(M)) + if(HAS_TRAIT(M, TRAIT_COMIC_SANS) || issmall(M)) update_flags |= M.adjustBruteLoss(-1, FALSE) update_flags |= M.adjustFireLoss(-1, FALSE) return ..() | update_flags @@ -517,7 +517,7 @@ description = "Beloved of children and teetotalers." color = "#E6CDFF" taste_description = "grape soda" - + /datum/reagent/consumable/drink/coco/icecoco name = "Iced Cocoa" id = "icecoco" diff --git a/code/modules/reagents/chemistry/reagents/drugs.dm b/code/modules/reagents/chemistry/reagents/drugs.dm index 893d6c30837..db2c21bd9fa 100644 --- a/code/modules/reagents/chemistry/reagents/drugs.dm +++ b/code/modules/reagents/chemistry/reagents/drugs.dm @@ -290,7 +290,7 @@ H.visible_message("[M]'s skin is rotting away!") update_flags |= H.adjustBruteLoss(25, FALSE) H.emote("scream") - H.ChangeToHusk() + H.become_husk("krokodil_overdose") H.emote("faint") else if(effect <= 7) M.emote("shiver") @@ -322,13 +322,13 @@ update_flags |= M.AdjustWeakened(-2.5, FALSE) update_flags |= M.adjustStaminaLoss(-2, FALSE) update_flags |= M.SetSleeping(0, FALSE) - M.status_flags |= GOTTAGOFAST + ADD_TRAIT(M, TRAIT_GOTTAGOFAST, id) if(prob(50)) update_flags |= M.adjustBrainLoss(1, FALSE) return ..() | update_flags /datum/reagent/methamphetamine/on_mob_delete(mob/living/M) - M.status_flags &= ~GOTTAGOFAST + REMOVE_TRAIT(M, TRAIT_GOTTAGOFAST, id) ..() /datum/reagent/methamphetamine/overdose_process(mob/living/M, severity) @@ -684,7 +684,7 @@ update_flags |= M.AdjustStunned(-2, FALSE) update_flags |= M.AdjustWeakened(-2, FALSE) update_flags |= M.adjustStaminaLoss(-2, FALSE) - M.status_flags |= GOTTAGOFAST + ADD_TRAIT(M, TRAIT_GOTTAGOFAST, id) M.Jitter(3) update_flags |= M.adjustBrainLoss(0.5, FALSE) if(prob(5)) @@ -692,7 +692,7 @@ return ..() | update_flags /datum/reagent/lube/ultra/on_mob_delete(mob/living/M) - M.status_flags &= ~GOTTAGOFAST + REMOVE_TRAIT(M, TRAIT_GOTTAGOFAST, id) ..() /datum/reagent/lube/ultra/overdose_process(mob/living/M, severity) diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm index c517f0d4bd7..c77a3e11b49 100644 --- a/code/modules/reagents/chemistry/reagents/food.dm +++ b/code/modules/reagents/chemistry/reagents/food.dm @@ -809,7 +809,7 @@ H.Weaken(2, FALSE) H.update_canmove() to_chat(H, "Ugh! Eating that was a terrible idea!") - if(NO_HUNGER in H.dna.species.species_traits) //If you don't eat, then you can't get food poisoning + if(HAS_TRAIT(H, TRAIT_NOHUNGER)) //If you don't eat, then you can't get food poisoning return H.ForceContractDisease(new /datum/disease/food_poisoning(0)) diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm index 1f3acb41f5a..bdf1a084963 100644 --- a/code/modules/reagents/chemistry/reagents/medicine.dm +++ b/code/modules/reagents/chemistry/reagents/medicine.dm @@ -295,6 +295,11 @@ M.adjustFireLoss(-1.5*volume) if(show_message) to_chat(M, "The synthetic flesh integrates itself into your wounds, healing you.") + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(HAS_TRAIT_FROM(H, TRAIT_HUSK, BURN) && H.getFireLoss() < UNHUSK_DAMAGE_THRESHOLD && (H.reagents.get_reagent_amount("synthflesh") + volume >= SYNTHFLESH_UNHUSK_AMOUNT)) + H.cure_husk(BURN) + H.visible_message("The squishy liquid coats [H]'s burns. [H] looks a lot healthier!") //we're avoiding using the phrases "burnt flesh" and "burnt skin" here because humans could be a skeleton or a golem or something ..() /datum/reagent/medicine/synthflesh/reaction_turf(turf/T, volume) //let's make a mess! @@ -639,9 +644,9 @@ update_flags |= M.AdjustEyeBlurry(-1, FALSE) update_flags |= M.AdjustEarDamage(-1) if(prob(50)) - update_flags |= M.CureNearsighted(FALSE) + update_flags |= M.cure_nearsighted(EYE_DAMAGE, FALSE) if(prob(30)) - update_flags |= M.CureBlind(FALSE) + update_flags |= M.cure_blind(EYE_DAMAGE, FALSE) update_flags |= M.SetEyeBlind(0, FALSE) return ..() | update_flags @@ -769,7 +774,7 @@ if(M.getBruteLoss() + M.getFireLoss() + M.getCloneLoss() >= 150) M.delayed_gib() return - if(!M.suiciding && !(NOCLONE in M.mutations) && (!M.mind || M.mind && M.mind.is_revivable())) + if(!M.suiciding && !HAS_TRAIT(M, TRAIT_HUSK) && !HAS_TRAIT(M, TRAIT_BADDNA) && (!M.mind || M.mind && M.mind.is_revivable())) var/time_dead = world.time - M.timeofdeath M.visible_message("[M] seems to rise from the dead!") M.adjustCloneLoss(50) @@ -820,13 +825,13 @@ ..() return M.SetJitter(0) - var/needs_update = M.mutations.len > 0 + var/needs_update = length(M.active_mutations) if(needs_update) for(var/block = 1; block<=DNA_SE_LENGTH; block++) if(!(block in M.dna.default_blocks)) M.dna.SetSEState(block, FALSE, TRUE) - genemutcheck(M, block, null, MUTCHK_FORCED) + singlemutcheck(M, block, MUTCHK_FORCED) M.dna.UpdateSE() M.dna.struc_enzymes = M.dna.struc_enzymes_original @@ -902,7 +907,7 @@ /datum/reagent/medicine/stimulative_agent/on_mob_life(mob/living/M) var/update_flags = STATUS_UPDATE_NONE - M.status_flags |= GOTTAGOFAST + ADD_TRAIT(M, TRAIT_GOTTAGOFAST, id) if(M.health < 50 && M.health > 0) update_flags |= M.adjustOxyLoss(-1*REAGENTS_EFFECT_MULTIPLIER, FALSE) update_flags |= M.adjustToxLoss(-1*REAGENTS_EFFECT_MULTIPLIER, FALSE) @@ -915,7 +920,7 @@ return ..() | update_flags /datum/reagent/medicine/stimulative_agent/on_mob_delete(mob/living/M) - M.status_flags &= ~GOTTAGOFAST + REMOVE_TRAIT(M, TRAIT_GOTTAGOFAST, id) ..() /datum/reagent/medicine/stimulative_agent/overdose_process(mob/living/M, severity) diff --git a/code/modules/reagents/chemistry/reagents/misc.dm b/code/modules/reagents/chemistry/reagents/misc.dm index fba47ad52a3..524a30ce038 100644 --- a/code/modules/reagents/chemistry/reagents/misc.dm +++ b/code/modules/reagents/chemistry/reagents/misc.dm @@ -460,7 +460,7 @@ else to_chat(C, "Something doesn't feel right...") C.AdjustDizzy(volume) - ADD_TRAIT(C, TRAIT_JESTER, id) + ADD_TRAIT(C, TRAIT_COMIC_SANS, id) C.AddComponent(/datum/component/squeak, null, null, null, null, null, TRUE) C.AddElement(/datum/element/waddling) @@ -496,7 +496,7 @@ /datum/reagent/jestosterone/on_mob_delete(mob/living/M) ..() - REMOVE_TRAIT(M, TRAIT_JESTER, id) + REMOVE_TRAIT(M, TRAIT_COMIC_SANS, id) qdel(M.GetComponent(/datum/component/squeak)) M.RemoveElement(/datum/element/waddling) diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm index 73e393ea66a..fdfad83bee2 100644 --- a/code/modules/reagents/chemistry/reagents/toxins.dm +++ b/code/modules/reagents/chemistry/reagents/toxins.dm @@ -34,7 +34,7 @@ taste_description = "mint" /datum/reagent/minttoxin/on_mob_life(mob/living/M) - if(FAT in M.mutations) + if(HAS_TRAIT(M, TRAIT_FAT)) M.gib() return ..() @@ -180,11 +180,11 @@ /datum/reagent/mutagen/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume) if(!..()) return - if(!M.dna) + if(!M.dna || HAS_TRAIT(M, TRAIT_BADDNA) || HAS_TRAIT(M, TRAIT_GENELESS)) return //No robots, AIs, aliens, Ians or other mobs should be affected by this. if((method==REAGENT_TOUCH && prob(33)) || method==REAGENT_INGEST) randmutb(M) - domutcheck(M, null) + domutcheck(M) M.UpdateAppearance() /datum/reagent/mutagen/on_mob_life(mob/living/M) @@ -213,7 +213,7 @@ return ..() /datum/reagent/stable_mutagen/on_mob_life(mob/living/M) - if(!ishuman(M) || !M.dna) + if(!ishuman(M) || !M.dna || HAS_TRAIT(M, TRAIT_BADDNA) || HAS_TRAIT(M, TRAIT_GENELESS)) return M.apply_effect(2 * REAGENTS_EFFECT_MULTIPLIER, IRRADIATE) if(current_cycle == 10 && islist(data)) @@ -1113,12 +1113,12 @@ update_flags |= M.AdjustEyeBlurry(10, FALSE) if(70 to INFINITY) update_flags |= M.AdjustEyeBlurry(10, FALSE) - if(M.status_flags & FAKEDEATH) + if(HAS_TRAIT(M, TRAIT_FAKEDEATH)) fakerevive(M) return ..() | update_flags /datum/reagent/capulettium/on_mob_delete(mob/living/M) - if(M.status_flags & FAKEDEATH) + if(HAS_TRAIT(M, TRAIT_FAKEDEATH)) fakerevive(M) ..() @@ -1133,14 +1133,14 @@ /datum/reagent/capulettium_plus/on_mob_life(mob/living/M) M.Silence(2) - if((M.status_flags & FAKEDEATH) && !M.resting) + if((HAS_TRAIT(M, TRAIT_FAKEDEATH)) && !M.resting) fakerevive(M) - else if(!(M.status_flags & FAKEDEATH) && M.resting) + else if(!HAS_TRAIT(M, TRAIT_FAKEDEATH) && M.resting) fakedeath(M) return ..() /datum/reagent/capulettium_plus/on_mob_delete(mob/living/M) - if(M.status_flags & FAKEDEATH) + if(HAS_TRAIT(M, TRAIT_FAKEDEATH)) fakerevive(M) ..() @@ -1178,7 +1178,7 @@ return //No robots, AIs, aliens, Ians or other mobs should be affected by this. if((method==REAGENT_TOUCH && prob(50)) || method==REAGENT_INGEST) randmutb(M) - domutcheck(M, null) + domutcheck(M) M.UpdateAppearance() /datum/reagent/glowing_slurry/on_mob_life(mob/living/M) @@ -1193,7 +1193,7 @@ randmutg(M) did_mutation = TRUE if(did_mutation) - domutcheck(M, null) + domutcheck(M) M.UpdateAppearance() return ..() diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 7ca4ba37de4..47502d6ae71 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -553,7 +553,7 @@ SEND_SIGNAL(AM, COMSIG_MOVABLE_DISPOSING, src, D) if(istype(AM, /mob/living/carbon/human)) var/mob/living/carbon/human/H = AM - if(FAT in H.mutations) // is a human and fat? + if(HAS_TRAIT(H, TRAIT_FAT)) // is a human and fat? has_fat_guy = 1 // set flag on holder if(istype(AM, /obj/structure/bigDelivery) && !hasmob) var/obj/structure/bigDelivery/T = AM diff --git a/code/modules/ruins/lavalandruin_code/sin_ruins.dm b/code/modules/ruins/lavalandruin_code/sin_ruins.dm index 8e3876f7d2f..bb50d5e9746 100644 --- a/code/modules/ruins/lavalandruin_code/sin_ruins.dm +++ b/code/modules/ruins/lavalandruin_code/sin_ruins.dm @@ -90,7 +90,7 @@ /obj/effect/gluttony/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff. if(ishuman(mover)) var/mob/living/carbon/human/H = mover - if(H.nutrition >= NUTRITION_LEVEL_FAT || (FAT in H.mutations)) + if(H.nutrition >= NUTRITION_LEVEL_FAT || HAS_TRAIT(H, TRAIT_FAT)) H.visible_message("[H] pushes through [src]!", "You've seen and eaten worse than this.") return TRUE else diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm index ab5fadb5516..2139b54c62c 100644 --- a/code/modules/station_goals/dna_vault.dm +++ b/code/modules/station_goals/dna_vault.dm @@ -110,7 +110,7 @@ GLOBAL_LIST_INIT(non_simple_animals, typecacheof(list(/mob/living/carbon/human/m //humans if(ishuman(target)) var/mob/living/carbon/human/H = target - if(NO_DNA in H.dna.species.species_traits) + if(HAS_TRAIT(H, TRAIT_GENELESS)) to_chat(user, "This humanoid doesn't have DNA.") return if(dna[H.dna.uni_identity]) @@ -298,7 +298,7 @@ GLOBAL_LIST_INIT(non_simple_animals, typecacheof(list(/mob/living/carbon/human/m if(!completed) return var/datum/species/S = H.dna.species - if(NO_DNA in S.species_traits) + if(HAS_TRAIT(H, TRAIT_GENELESS)) to_chat(H, "Error, no DNA detected.") return switch(upgrade_type) @@ -308,14 +308,14 @@ GLOBAL_LIST_INIT(non_simple_animals, typecacheof(list(/mob/living/carbon/human/m if(L) L.tox_breath_dam_min = 0 L.tox_breath_dam_max = 0 - S.species_traits |= VIRUSIMMUNE + ADD_TRAIT(H, TRAIT_VIRUSIMMUNE, "dna_vault") if(VAULT_NOBREATH) to_chat(H, "Your lungs feel great.") - S.species_traits |= NO_BREATHE + ADD_TRAIT(H, TRAIT_NOBREATH, "dna_vault") if(VAULT_FIREPROOF) to_chat(H, "You feel fireproof.") S.burn_mod *= 0.5 - S.species_traits |= RESISTHOT + ADD_TRAIT(H, TRAIT_RESISTHEAT, "dna_vault") if(VAULT_STUNTIME) to_chat(H, "Nothing can keep you down for long.") S.stun_mod *= 0.5 @@ -328,7 +328,7 @@ GLOBAL_LIST_INIT(non_simple_animals, typecacheof(list(/mob/living/carbon/human/m S.clone_mod *= 0.7 S.brain_mod *= 0.7 S.stamina_mod *= 0.7 - S.species_traits |= PIERCEIMMUNE + ADD_TRAIT(H, TRAIT_PIERCEIMMUNE, "dna_vault") if(VAULT_SPEED) to_chat(H, "You feel very fast and agile.") S.speed_mod = -1 diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index 867e53579be..680f6768967 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -113,7 +113,7 @@ /proc/get_pain_modifier(mob/living/carbon/human/M) //returns modfier to make surgery harder if patient is conscious and feels pain if(M.stat) //stat=0 if CONSCIOUS, 1=UNCONSCIOUS and 2=DEAD. Operating on dead people is easy, too. Just sleeping won't work, though. return 1 - if(NO_PAIN in M.dna.species.species_traits)//if you don't feel pain, you can hold still + if(HAS_TRAIT(M, TRAIT_NOPAIN))//if you don't feel pain, you can hold still return 1 if(M.reagents.has_reagent("hydrocodone"))//really good pain killer return 0.99 diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index ba186aaa272..62e175ead18 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -215,6 +215,14 @@ slot = "brain_clownvoice" origin_tech = "materials=2;biotech=2" +/obj/item/organ/internal/cyberimp/brain/clown_voice/insert(mob/living/carbon/M, special = FALSE) + ..() + ADD_TRAIT(M, TRAIT_COMIC_SANS, "augment") + +/obj/item/organ/internal/cyberimp/brain/clown_voice/remove(mob/living/carbon/M, special = FALSE) + REMOVE_TRAIT(M, TRAIT_COMIC_SANS, "augment") + return ..() + /obj/item/organ/internal/cyberimp/brain/speech_translator //actual translating done in human/handle_speech_problems name = "Speech translator implant" desc = "While known as a translator, this implant actually generates speech based on the user's thoughts when activated, completely bypassing the need to speak." diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm index 06ab3db4f89..764028beab9 100644 --- a/code/modules/surgery/organs/blood.dm +++ b/code/modules/surgery/organs/blood.dm @@ -22,7 +22,7 @@ bleed_rate = 0 return - if(bodytemperature >= TCRYO && !(NOCLONE in mutations)) //cryosleep or husked people do not pump the blood. + if(bodytemperature >= TCRYO && !HAS_TRAIT(src, TRAIT_BADDNA)) //cryosleep or husked people do not pump the blood. if(blood_volume < BLOOD_VOLUME_NORMAL) blood_volume += 0.1 // regenerate blood VERY slowly @@ -74,10 +74,10 @@ var/additional_bleed = round(clamp((reagents.get_reagent_amount("heparin") / 10), 0, 2), 1) //Heparin worsens existing bleeding - if(internal_bleeding_rate && !(status_flags & FAKEDEATH)) + if(internal_bleeding_rate && !HAS_TRAIT(src, TRAIT_FAKEDEATH)) bleed_internal(internal_bleeding_rate + additional_bleed) - if(bleed_rate && !bleedsuppress && !(status_flags & FAKEDEATH)) + if(bleed_rate && !bleedsuppress && !HAS_TRAIT(src, TRAIT_FAKEDEATH)) bleed(bleed_rate + additional_bleed) //Makes a blood drop, leaking amt units of blood from the mob @@ -224,7 +224,7 @@ /mob/living/carbon/human/get_blood_id() if(dna.species.exotic_blood)//some races may bleed water..or kethcup.. return dna.species.exotic_blood - else if((NO_BLOOD in dna.species.species_traits) || (NOCLONE in mutations)) + else if((NO_BLOOD in dna.species.species_traits) || HAS_TRAIT(src, TRAIT_HUSK)) return return "blood" diff --git a/code/modules/surgery/organs/body_egg.dm b/code/modules/surgery/organs/body_egg.dm index a8ba9192ae4..db0397eec8c 100644 --- a/code/modules/surgery/organs/body_egg.dm +++ b/code/modules/surgery/organs/body_egg.dm @@ -12,19 +12,19 @@ /obj/item/organ/internal/body_egg/insert(var/mob/living/carbon/M, special = 0) ..() - owner.status_flags |= XENO_HOST + ADD_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) + ADD_TRAIT(owner, TRAIT_XENO_IMMUNE, "xeno immune") START_PROCESSING(SSobj, src) owner.med_hud_set_status() - spawn(0) - AddInfectionImages(owner) + INVOKE_ASYNC(src, .proc/AddInfectionImages, owner) /obj/item/organ/internal/body_egg/remove(var/mob/living/carbon/M, special = 0) STOP_PROCESSING(SSobj, src) if(owner) - owner.status_flags &= ~(XENO_HOST) + REMOVE_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) + REMOVE_TRAIT(owner, TRAIT_XENO_IMMUNE, "xeno immune") owner.med_hud_set_status() - spawn(0) - RemoveInfectionImages(owner) + INVOKE_ASYNC(src, .proc/RemoveInfectionImages, owner) . = ..() /obj/item/organ/internal/body_egg/process() diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm index bc57338dbbe..99c03ad1e57 100644 --- a/code/modules/surgery/organs/ears.dm +++ b/code/modules/surgery/organs/ears.dm @@ -13,39 +13,41 @@ // the person will not have either `deaf` or `ear_damage` decrease // without external aid (earmuffs, drugs) var/ear_damage = 0 + // Multiplier for both long term and short term ear damage + var/damage_multiplier = 1 /obj/item/organ/internal/ears/on_life() if(!iscarbon(owner)) return var/mob/living/carbon/C = owner - // genetic deafness prevents the body from using the ears, even if healthy - if(DEAF in C.mutations) - deaf = max(deaf, 1) + if(ear_damage < 100) + AdjustEarDamage(-0.1) + + // if we have non-damage related deafness like mutations, quirks or clothing (earmuffs), don't bother processing here. Ear healing from earmuffs or chems happen elsewhere + if(HAS_TRAIT_NOT_FROM(C, TRAIT_DEAF, EAR_DAMAGE)) + return + + if(ear_damage >= 100) + deaf = max(deaf, 1) // if we're failing we always have at least 1 deaf stack (and thus deafness) else - if(ishuman(C)) - var/mob/living/carbon/human/H = C - if((H.l_ear && H.l_ear.flags_2 & HEALS_EARS_2) || (H.r_ear && H.r_ear.flags_2 & HEALS_EARS_2)) - deaf = max(deaf - 1, 1) - ear_damage = max(ear_damage - 0.10, 0) - // if higher than UNHEALING_EAR_DAMAGE, no natural healing occurs. - if(ear_damage < UNHEALING_EAR_DAMAGE) - ear_damage = max(ear_damage - 0.05, 0) - deaf = max(deaf - 1, 0) + deaf = max(deaf - 1, 0) + if((ear_damage > 10) && prob(ear_damage / 30)) + AdjustEarDamage(0, 4) + SEND_SOUND(owner, sound('sound/weapons/flash_ring.ogg')) + + if(deaf) + ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE) + else + REMOVE_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE) + /obj/item/organ/internal/ears/proc/RestoreEars() deaf = 0 ear_damage = 0 - var/mob/living/carbon/C = owner - if(istype(C) && (DEAF in C.mutations)) - deaf = 1 - /obj/item/organ/internal/ears/proc/AdjustEarDamage(ddmg, ddeaf) - ear_damage = max(ear_damage + ddmg, 0) - deaf = max(deaf + ddeaf, 0) - -/obj/item/organ/internal/ears/proc/MinimumDeafTicks(value) - deaf = max(deaf, value) + ear_damage = clamp(ear_damage + (ddmg * damage_multiplier), 0, 100) + deaf = max(deaf + (ddeaf * damage_multiplier), 0) /obj/item/organ/internal/ears/surgeryize() RestoreEars() @@ -61,20 +63,16 @@ if(ears) ears.AdjustEarDamage(ddmg, ddeaf) -/mob/living/carbon/MinimumDeafTicks(value) - var/obj/item/organ/internal/ears/ears = get_int_organ(/obj/item/organ/internal/ears) - if(ears) - ears.MinimumDeafTicks(value) - /obj/item/organ/internal/ears/cybernetic name = "cybernetic ears" icon_state = "ears-c" desc = "a basic cybernetic designed to mimic the operation of ears." origin_tech = "biotech=4" status = ORGAN_ROBOT + damage_multiplier = 0.9 /obj/item/organ/internal/ears/cybernetic/emp_act(severity) if(emp_proof) return ..() - AdjustEarDamage(30, 120) + ear_damage += 40 / severity diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 59385ff85a3..085434b25f2 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -30,7 +30,7 @@ return eyes_icon /obj/item/organ/internal/eyes/proc/get_colourmatrix() //Returns a special colour matrix if the eyes are organic and the mob is colourblind, otherwise it uses the current one. - if(!is_robotic() && (COLOURBLIND in owner.mutations)) + if(!is_robotic() && HAS_TRAIT(owner, TRAIT_COLORBLIND)) return colourblind_matrix else return colourmatrix @@ -44,26 +44,26 @@ if(istype(M) && eye_colour) M.update_body() //Apply our eye colour to the target. - if(!(COLOURBLIND in M.mutations) && (COLOURBLIND in dependent_disabilities)) //If the eyes are colourblind and we're not, carry over the gene. - dependent_disabilities -= COLOURBLIND - M.dna.SetSEState(GLOB.colourblindblock,1) - genemutcheck(M,GLOB.colourblindblock,null,MUTCHK_FORCED) + if(!HAS_TRAIT(M, TRAIT_COLORBLIND) && (TRAIT_COLORBLIND in dependent_disabilities)) //If the eyes are colourblind and we're not, carry over the gene. + dependent_disabilities -= TRAIT_COLORBLIND + M.dna.SetSEState(GLOB.colourblindblock, TRUE) + singlemutcheck(M, GLOB.colourblindblock, MUTCHK_FORCED) else M.update_client_colour() //If we're here, that means the mob acquired the colourblindness gene while they didn't have eyes. Better handle it. /obj/item/organ/internal/eyes/remove(mob/living/carbon/human/M, special = 0) - if(!special && (COLOURBLIND in M.mutations)) //If special is set, that means these eyes are getting deleted (i.e. during set_species()) - if(!(COLOURBLIND in dependent_disabilities)) //We only want to change COLOURBLINDBLOCK and such it the eyes are being surgically removed. - dependent_disabilities |= COLOURBLIND - M.dna.SetSEState(GLOB.colourblindblock,0) - genemutcheck(M,GLOB.colourblindblock,null,MUTCHK_FORCED) + if(!special && HAS_TRAIT(M, TRAIT_COLORBLIND)) //If special is set, that means these eyes are getting deleted (i.e. during set_species()) + if(!(TRAIT_COLORBLIND in dependent_disabilities)) //We only want to change COLOURBLINDBLOCK and such it the eyes are being surgically removed. + dependent_disabilities |= TRAIT_COLORBLIND + M.dna.SetSEState(GLOB.colourblindblock, FALSE) + singlemutcheck(M, GLOB.colourblindblock, MUTCHK_FORCED) . = ..() /obj/item/organ/internal/eyes/surgeryize() if(!owner) return - owner.CureNearsighted() - owner.CureBlind() + owner.cure_nearsighted(EYE_DAMAGE) + owner.cure_blind(EYE_DAMAGE) owner.SetEyeBlurry(0) owner.SetEyeBlind(0) diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index cb399360f30..1f1529bd7b5 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -87,6 +87,9 @@ if((H.status_flags & GODMODE)) return + if(HAS_TRAIT(H, TRAIT_NOBREATH)) + return + if(!breath || (breath.total_moles() == 0)) if(isspaceturf(loc)) H.adjustOxyLoss(10) @@ -267,11 +270,7 @@ /obj/item/organ/internal/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/H) // called by human/life, handles temperatures var/breath_temperature = breath.temperature - var/species_traits = list() - if(H && H.dna.species && H.dna.species.species_traits) - species_traits = H.dna.species.species_traits - - if(!(COLDRES in H.mutations) && !(RESISTCOLD in species_traits)) // COLD DAMAGE + if(!HAS_TRAIT(H, TRAIT_RESISTCOLD)) // COLD DAMAGE var/CM = abs(H.dna.species.coldmod) var/TC = 0 if(breath_temperature < cold_level_3_threshold) @@ -287,7 +286,7 @@ if(prob(20)) to_chat(H, "You feel [cold_message] in your [name]!") - if(!(HEATRES in H.mutations) && !(RESISTHOT in species_traits)) // HEAT DAMAGE + if(!HAS_TRAIT(H, TRAIT_RESISTHEAT)) // HEAT DAMAGE var/HM = abs(H.dna.species.heatmod) var/TH = 0 if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index e85466740e8..f57eff0bc1e 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -100,7 +100,7 @@ return //Process infections - if(is_robotic() || sterile || (owner && (NO_GERMS in owner.dna.species.species_traits))) + if(is_robotic() || sterile || (owner && HAS_TRAIT(owner, TRAIT_NOGERMS))) germ_level = 0 return diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index 21ac34a16c6..5e6b58002b8 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -616,7 +616,7 @@ Note that amputating the affected organ does in fact remove the infection from t "Something feels like it shattered in your [name]!",\ "You hear a sickening crack.") playsound(owner, "bonebreak", 150, 1) - if(owner.dna.species && !(NO_PAIN in owner.dna.species.species_traits)) + if(!HAS_TRAIT(owner, TRAIT_NOPAIN)) owner.emote("scream") status |= ORGAN_BROKEN diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 78fa06122f5..a9665ec92e9 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -239,25 +239,20 @@ /obj/item/organ/internal/honktumor/insert(mob/living/carbon/M, special = 0) ..() - M.mutations.Add(CLUMSY) - M.mutations.Add(GLOB.comicblock) - M.dna.SetSEState(GLOB.clumsyblock,1,1) - M.dna.SetSEState(GLOB.comicblock,1,1) - genemutcheck(M,GLOB.clumsyblock,null,MUTCHK_FORCED) - genemutcheck(M,GLOB.comicblock,null,MUTCHK_FORCED) + M.dna.SetSEState(GLOB.clumsyblock, TRUE, TRUE) + M.dna.SetSEState(GLOB.comicblock, TRUE, TRUE) + singlemutcheck(M, GLOB.clumsyblock, MUTCHK_FORCED) + singlemutcheck(M, GLOB.comicblock, MUTCHK_FORCED) organhonked = world.time M.AddElement(/datum/element/waddling) squeak = M.AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg' = 1), 50) /obj/item/organ/internal/honktumor/remove(mob/living/carbon/M, special = 0) . = ..() - - M.mutations.Remove(CLUMSY) - M.mutations.Remove(GLOB.comicblock) - M.dna.SetSEState(GLOB.clumsyblock,0) - M.dna.SetSEState(GLOB.comicblock,0) - genemutcheck(M,GLOB.clumsyblock,null,MUTCHK_FORCED) - genemutcheck(M,GLOB.comicblock,null,MUTCHK_FORCED) + M.dna.SetSEState(GLOB.clumsyblock, FALSE) + M.dna.SetSEState(GLOB.comicblock, FALSE) + singlemutcheck(M, GLOB.clumsyblock, MUTCHK_FORCED) + singlemutcheck(M, GLOB.comicblock, MUTCHK_FORCED) M.RemoveElement(/datum/element/waddling) QDEL_NULL(squeak) qdel(src) @@ -268,7 +263,7 @@ to_chat(owner, "HONK") owner.SetSleeping(0) owner.Stuttering(20) - owner.MinimumDeafTicks(30) + owner.AdjustEarDamage(0, 30) owner.Weaken(3) owner << 'sound/items/airhorn.ogg' if(prob(30)) diff --git a/code/modules/surgery/organs/pain.dm b/code/modules/surgery/organs/pain.dm index 70f3ff43fa1..56d8b05d72a 100644 --- a/code/modules/surgery/organs/pain.dm +++ b/code/modules/surgery/organs/pain.dm @@ -34,7 +34,7 @@ if(stat >= UNCONSCIOUS) return - if(NO_PAIN in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_NOPAIN)) return if(reagents.has_reagent("morphine")) return @@ -54,7 +54,7 @@ if(stat >= UNCONSCIOUS) return - if(NO_PAIN in dna.species.species_traits) + if(HAS_TRAIT(src, TRAIT_NOPAIN)) return if(reagents.has_reagent("morphine")) return diff --git a/code/modules/surgery/organs/subtypes/xenos.dm b/code/modules/surgery/organs/subtypes/xenos.dm index bbe3f4387de..c38b7cc0c36 100644 --- a/code/modules/surgery/organs/subtypes/xenos.dm +++ b/code/modules/surgery/organs/subtypes/xenos.dm @@ -125,11 +125,13 @@ M.faction |= "alien" M.add_language("Hivemind") M.add_language("Xenomorph") + ADD_TRAIT(M, TRAIT_XENO_IMMUNE, "xeno immune") /obj/item/organ/internal/xenos/hivenode/remove(mob/living/carbon/M, special = 0) M.faction -= "alien" M.remove_language("Hivemind") M.remove_language("Xenomorph") + REMOVE_TRAIT(M, TRAIT_XENO_IMMUNE, "xeno immune") . = ..() /obj/item/organ/internal/xenos/neurotoxin diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 294e98d38d0..1acef049678 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -189,7 +189,7 @@ for(var/mob/living/carbon/human/H in view(2, E.loc))//germs from people if(AStar(E.loc, H.loc, /turf/proc/Distance, 2, simulated_only = 0)) - if(!((BREATHLESS in H.mutations) || (NO_BREATHE in H.dna.species.species_traits)) && !H.wear_mask) //wearing a mask helps preventing people from breathing cooties into open incisions + if(!HAS_TRAIT(H, TRAIT_NOBREATH) && !H.wear_mask) //wearing a mask helps preventing people from breathing cooties into open incisions germs += H.germ_level * 0.25 for(var/obj/effect/decal/cleanable/M in view(2, E.loc))//germs from messes diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index 196f2bc4ccb..383344317c1 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -113,6 +113,6 @@ return STATUS_CLOSE // Otherwise, we got nothing. /mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object) - if((TK in mutations) && (get_dist(src, src_object) <= 2)) + if(dna.GetSEState(GLOB.teleblock) && (get_dist(src, src_object) <= 2)) return STATUS_INTERACTIVE return ..() diff --git a/paradise.dme b/paradise.dme index 1c4b94cbb2e..0975721208a 100644 --- a/paradise.dme +++ b/paradise.dme @@ -359,6 +359,7 @@ #include "code\datums\diseases\advance\symptoms\weight.dm" #include "code\datums\diseases\advance\symptoms\youth.dm" #include "code\datums\elements\_element.dm" +#include "code\datums\elements\earhealing.dm" #include "code\datums\elements\rad_insulation.dm" #include "code\datums\elements\waddling.dm" #include "code\datums\helper_datums\construction_datum.dm" @@ -466,14 +467,10 @@ #include "code\game\dna\dna2_domutcheck.dm" #include "code\game\dna\dna2_helpers.dm" #include "code\game\dna\dna_modifier.dm" -#include "code\game\dna\genes\disabilities.dm" -#include "code\game\dna\genes\gene.dm" -#include "code\game\dna\genes\goon_disabilities.dm" -#include "code\game\dna\genes\goon_powers.dm" -#include "code\game\dna\genes\monkey.dm" -#include "code\game\dna\genes\powers.dm" -#include "code\game\dna\genes\vg_disabilities.dm" -#include "code\game\dna\genes\vg_powers.dm" +#include "code\game\dna\mutations\_mutations.dm" +#include "code\game\dna\mutations\disabilities.dm" +#include "code\game\dna\mutations\monkey.dm" +#include "code\game\dna\mutations\powers.dm" #include "code\game\gamemodes\game_mode.dm" #include "code\game\gamemodes\intercept_report.dm" #include "code\game\gamemodes\objective.dm" diff --git a/sound/weapons/flash_ring.ogg b/sound/weapons/flash_ring.ogg new file mode 100644 index 0000000000000000000000000000000000000000..006141ac0bc7652b0843dece91928941ad677e91 GIT binary patch literal 24325 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 LkCy)pE53gL?$`i$ literal 0 HcmV?d00001
 12345
[block-1]