-
- |
- /* |
-
-
- |
- Datum-based species. Should make for much cleaner and easier to maintain mutantrace code. |
-
-
- |
- */ |
-
-
- |
-
- |
-
-
- |
- /datum/species |
-
-
- |
- var/name // Species name. |
-
-
- |
- var/name_plural // Pluralized name (since "[name]s" is not always valid) |
-
-
- |
- var/path // Species path |
-
-
- |
- var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. |
-
-
- |
- var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. |
-
-
- |
-
- |
-
-
- |
- // Damage overlay and masks. |
-
-
- |
- var/damage_overlays = 'icons/mob/human_races/masks/dam_human.dmi' |
-
-
- |
- var/damage_mask = 'icons/mob/human_races/masks/dam_mask_human.dmi' |
-
-
- |
- var/blood_mask = 'icons/mob/human_races/masks/blood_human.dmi' |
-
-
- |
-
- |
-
-
- |
- var/eyes = "eyes_s" // Icon for eyes. |
-
-
- |
- var/blurb = "A completely nondescript species." // A brief lore summary for use in the chargen screen. |
-
-
- |
- var/butt_sprite = "human" |
-
-
- |
-
- |
-
-
- |
- var/primitive_form // Lesser form, if any (ie. monkey for humans) |
-
-
- |
- var/greater_form // Greater form, if any, ie. human for monkeys. |
-
-
- |
- var/tail // Name of tail image in species effects icon file. |
-
-
- |
- var/unarmed //For empty hand harm-intent attack |
-
-
- |
- var/unarmed_type = /datum/unarmed_attack |
-
-
- |
- var/slowdown = 0 // Passive movement speed malus (or boost, if negative) |
-
-
- |
- var/silent_steps = 0 // Stops step noises |
-
-
- |
-
- |
-
-
- |
- var/breath_type = "oxygen" // Non-oxygen gas breathed, if any. |
-
-
- |
- var/poison_type = "plasma" // Poisonous air. |
-
-
- |
- var/exhale_type = "carbon_dioxide" // Exhaled gas type. |
-
-
- |
-
- |
-
-
- |
- var/cold_level_1 = 260 // Cold damage level 1 below this point. |
-
-
- |
- var/cold_level_2 = 200 // Cold damage level 2 below this point. |
-
-
- |
- var/cold_level_3 = 120 // Cold damage level 3 below this point. |
-
-
- |
- var/cold_env_multiplier = 1 // Damage multiplier for being in a cold environment |
-
-
- |
-
- |
-
-
- |
- var/heat_level_1 = 360 // Heat damage level 1 above this point. |
-
-
- |
- var/heat_level_2 = 400 // Heat damage level 2 above this point. |
-
-
- |
- var/heat_level_3 = 460 // Heat damage level 3 above this point; used for body temperature |
-
-
- |
- var/hot_env_multiplier = 1 // Damage multiplier for being in a hot environment |
-
-
- |
- var/heat_level_3_breathe = 1000 // Heat damage level 3 above this point; used for breathed air temperature |
-
-
- |
-
- |
-
-
- |
- var/body_temperature = 310.15 //non-IS_SYNTHETIC species will try to stabilize at this temperature. (also affects temperature processing) |
-
-
- |
- var/reagent_tag //Used for metabolizing reagents. |
-
-
- |
-
- |
-
-
- |
- var/siemens_coeff = 1 //base electrocution coefficient |
-
-
- |
-
- |
-
-
- |
- var/invis_sight = SEE_INVISIBLE_LIVING |
-
-
- |
- var/darksight = 2 |
-
-
- |
- var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. |
-
-
- |
- var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. |
-
-
- |
- var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning. |
-
-
- |
- var/hazard_low_pressure = HAZARD_LOW_PRESSURE // Dangerously low pressure. |
-
-
- |
-
- |
-
-
- |
- var/list/atmos_requirements = list( |
-
-
- |
- "min_oxy" = 16, |
-
-
- |
- "max_oxy" = 0, |
-
-
- |
- "min_nitro" = 0, |
-
-
- |
- "max_nitro" = 0, |
-
-
- |
- "min_tox" = 0, |
-
-
- |
- "max_tox" = 0.005, |
-
-
- |
- "min_co2" = 0, |
-
-
- |
- "max_co2" = 10, |
-
-
- |
- "sa_para" = 1, |
-
-
- |
- "sa_sleep" = 5 |
-
-
- |
- ) |
-
-
- |
-
- |
-
-
- |
- var/brute_mod = null // Physical damage reduction/malus. |
-
-
- |
- var/burn_mod = null // Burn damage reduction/malus. |
-
-
- |
-
- |
-
-
- |
- var/total_health = 100 |
-
-
- |
- 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 = 0 //Determines if the mob can go through the vents. |
-
-
- |
- var/has_fine_manipulation = 1 // Can use small items. |
-
-
- |
-
- |
-
-
- |
- var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here. |
-
-
- |
-
- |
-
-
- |
- var/flags = 0 // Various specific features. |
-
-
- |
- var/clothing_flags = 0 // Underwear and socks. |
-
-
- |
- var/exotic_blood |
-
-
- |
- var/bodyflags = 0 |
-
-
- |
- var/dietflags = 0 // Make sure you set this, otherwise it won't be able to digest a lot of foods |
-
-
- |
-
- |
-
-
- |
- var/list/abilities = list() // For species-derived or admin-given powers |
-
-
- |
-
- |
-
-
- |
- var/blood_color = "#A10808" //Red. |
-
-
- |
- var/flesh_color = "#FFC896" //Pink. |
-
-
- |
- var/single_gib_type = /obj/effect/decal/cleanable/blood/gibs |
-
-
- |
- var/remains_type = /obj/effect/decal/remains/human //What sort of remains is left behind when the species dusts |
-
-
- |
- var/base_color //Used when setting species. |
-
-
- |
-
- |
-
-
- |
- //Used in icon caching. |
-
-
- |
- var/race_key = 0 |
-
-
- |
- var/icon/icon_template |
-
-
- |
- var/is_small |
-
-
- |
- var/show_ssd = 1 |
-
-
- |
- var/virus_immune |
-
-
- |
- var/can_revive_by_healing // Determines whether or not this species can be revived by simply healing them |
-
-
- |
-
- |
-
-
- |
- //Death vars. |
-
-
- |
- var/death_message = "seizes up and falls limp, their eyes dead and lifeless..." |
-
-
- |
- var/list/suicide_messages = list( |
-
-
- |
- "is attempting to bite their tongue off!", |
-
-
- |
- "is jamming their thumbs into their eye sockets!", |
-
-
- |
- "is twisting their own neck!", |
-
-
- |
- "is holding their breath!") |
-
-
- |
-
- |
-
-
- |
- // Language/culture vars. |
-
-
- |
- var/default_language = "Galactic Common" // Default language is used when 'say' is used without modifiers. |
-
-
- |
- var/language = "Galactic Common" // Default racial language, if any. |
-
-
- |
- var/secondary_langs = list() // The names of secondary languages that are available to this species. |
-
-
- |
- var/list/speech_sounds // A list of sounds to potentially play when speaking. |
-
-
- |
- var/list/speech_chance // The likelihood of a speech sound playing. |
-
-
- |
- var/scream_verb = "screams" |
-
-
- |
- var/male_scream_sound = 'sound/goonstation/voice/male_scream.ogg' |
-
-
- |
- var/female_scream_sound = 'sound/goonstation/voice/female_scream.ogg' |
-
-
- |
-
- |
-
-
- |
- //Default hair/headacc style vars. |
-
-
- |
- var/default_hair //Default hair style for newly created humans unless otherwise set. |
-
-
- |
- var/default_hair_colour |
-
-
- |
- var/default_fhair //Default facial hair style for newly created humans unless otherwise set. |
-
-
- |
- var/default_fhair_colour |
-
-
- |
- var/default_headacc //Default head accessory style for newly created humans unless otherwise set. |
-
-
- |
- var/default_headacc_colour |
-
-
- |
-
- |
-
-
- |
- //Defining lists of icon skin tones for species that have them. |
-
-
- |
- var/list/icon_skin_tones = list() |
-
-
- |
-
- |
-
-
- |
- // Determines the organs that the species spawns with and |
-
-
- |
- var/list/has_organ = list( // which required-organ checks are conducted. |
-
-
- |
- "heart" = /obj/item/organ/internal/heart, |
-
-
- |
- "lungs" = /obj/item/organ/internal/lungs, |
-
-
- |
- "liver" = /obj/item/organ/internal/liver, |
-
-
- |
- "kidneys" = /obj/item/organ/internal/kidneys, |
-
-
- |
- "brain" = /obj/item/organ/internal/brain, |
-
-
- |
- "appendix" = /obj/item/organ/internal/appendix, |
-
-
- |
- "eyes" = /obj/item/organ/internal/eyes |
-
-
- |
- ) |
-
-
- |
- var/vision_organ // If set, this organ is required for vision. Defaults to "eyes" if the species has them. |
-
-
- |
- var/list/has_limbs = list( |
-
-
- |
- "chest" = list("path" = /obj/item/organ/external/chest), |
-
-
- |
- "groin" = list("path" = /obj/item/organ/external/groin), |
-
-
- |
- "head" = list("path" = /obj/item/organ/external/head), |
-
-
- |
- "l_arm" = list("path" = /obj/item/organ/external/arm), |
-
-
- |
- "r_arm" = list("path" = /obj/item/organ/external/arm/right), |
-
-
- |
- "l_leg" = list("path" = /obj/item/organ/external/leg), |
-
-
- |
- "r_leg" = list("path" = /obj/item/organ/external/leg/right), |
-
-
- |
- "l_hand" = list("path" = /obj/item/organ/external/hand), |
-
-
- |
- "r_hand" = list("path" = /obj/item/organ/external/hand/right), |
-
-
- |
- "l_foot" = list("path" = /obj/item/organ/external/foot), |
-
-
- |
- "r_foot" = list("path" = /obj/item/organ/external/foot/right) |
-
-
- |
- ) |
-
-
- |
- var/cyborg_type = "Cyborg" |
-
-
- |
- var/list/proc/species_abilities = list() |
-
-
- |
-
- |
-
-
- |
- /datum/species/New() |
-
-
- |
- //If the species has eyes, they are the default vision organ |
-
-
- |
- if(!vision_organ && has_organ["eyes"]) |
-
-
- |
- vision_organ = /obj/item/organ/internal/eyes |
-
-
- |
-
- |
-
-
- |
- unarmed = new unarmed_type() |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/get_random_name(var/gender) |
-
-
- |
- var/datum/language/species_language = all_languages[language] |
-
-
- |
- return species_language.get_random_name(gender) |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. |
-
-
- |
-
- |
-
-
- |
- for(var/obj/item/organ/internal/iorgan in H.internal_organs) |
-
-
- |
- if(iorgan in H.internal_organs) |
-
-
- |
- qdel(iorgan) |
-
-
- |
-
- |
-
-
- |
- for(var/obj/item/organ/organ in H.contents) |
-
-
- |
- if(organ in H.organs) |
-
-
- |
- qdel(organ) |
-
-
- |
-
- |
-
-
- |
- if(H.organs) H.organs.Cut() |
-
-
- |
- if(H.organs_by_name) H.organs_by_name.Cut() |
-
-
- |
-
- |
-
-
- |
- H.organs = list() |
-
-
- |
- H.internal_organs = list() |
-
-
- |
- H.organs_by_name = list() |
-
-
- |
-
- |
-
-
- |
- for(var/limb_type in has_limbs) |
-
-
- |
- var/list/organ_data = has_limbs[limb_type] |
-
-
- |
- var/limb_path = organ_data["path"] |
-
-
- |
- var/obj/item/organ/O = new limb_path(H) |
-
-
- |
- organ_data["descriptor"] = O.name |
-
-
- |
-
- |
-
-
- |
- for(var/index in has_organ) |
-
-
- |
- var/organ = has_organ[index] |
-
-
- |
- // organ new code calls `insert` on its own |
-
-
- |
- new organ(H) |
-
-
- |
-
- |
-
-
- |
- for(var/name in H.organs_by_name) |
-
-
- |
- H.organs |= H.organs_by_name[name] |
-
-
- |
-
- |
-
-
- |
- for(var/obj/item/organ/external/O in H.organs) |
-
-
- |
- O.owner = H |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_breath(var/datum/gas_mixture/breath, var/mob/living/carbon/human/H) |
-
-
- |
- var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME |
-
-
- |
-
- |
-
-
- |
- var/O2_used = 0 |
-
-
- |
- var/N2_used = 0 |
-
-
- |
- var/Tox_used = 0 |
-
-
- |
- var/CO2_used = 0 |
-
-
- |
-
- |
-
-
- |
- //Partial pressure of the O2 in our breath |
-
-
- |
- var/O2_pp = (breath.oxygen/breath.total_moles()) * breath_pressure |
-
-
- |
- // Partial pressure of Nitrogen |
-
-
- |
- var/N2_pp = (breath.nitrogen/breath.total_moles()) * breath_pressure |
-
-
- |
- // Partial pressure of plasma |
-
-
- |
- var/Tox_pp = (breath.toxins/breath.total_moles()) * breath_pressure |
-
-
- |
- // Partial pressure of CO2 |
-
-
- |
- var/CO2_pp = (breath.carbon_dioxide/breath.total_moles()) * breath_pressure |
-
-
- |
-
- |
-
-
- |
- if(O2_pp < atmos_requirements["min_oxy"]) |
-
-
- |
- if(prob(20)) |
-
-
- |
- spawn(0) |
-
-
- |
- H.emote("gasp") |
-
-
- |
-
- |
-
-
- |
- H.failed_last_breath = 1 |
-
-
- |
- if(O2_pp > 0) |
-
-
- |
- var/ratio = atmos_requirements["min_oxy"] / O2_pp |
-
-
- |
- H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) |
-
-
- |
- else |
-
-
- |
- H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) |
-
-
- |
- H.throw_alert("oxy", /obj/screen/alert/oxy) |
-
-
- |
- else if(atmos_requirements["max_oxy"] && O2_pp > atmos_requirements["max_oxy"]) |
-
-
- |
- var/ratio = (breath.oxygen / atmos_requirements["max_oxy"]) * 1000 |
-
-
- |
- H.adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) |
-
-
- |
- H.throw_alert("oxy", /obj/screen/alert/too_much_oxy) |
-
-
- |
- else |
-
-
- |
- H.clear_alert("oxy") |
-
-
- |
- if(atmos_requirements["min_oxy"]) //species breathes this gas, so, they got their air |
-
-
- |
- H.failed_last_breath = 0 |
-
-
- |
- H.adjustOxyLoss(-5) |
-
-
- |
- O2_used = breath.oxygen / 6 |
-
-
- |
-
- |
-
-
- |
- if(N2_pp < atmos_requirements["min_nitro"]) |
-
-
- |
- if(prob(20)) |
-
-
- |
- spawn(0) |
-
-
- |
- H.emote("gasp") |
-
-
- |
-
- |
-
-
- |
- H.failed_last_breath = 1 |
-
-
- |
- if(N2_pp > 0) |
-
-
- |
- var/ratio = atmos_requirements["min_nitro"] / N2_pp |
-
-
- |
- H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) |
-
-
- |
- else |
-
-
- |
- H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) |
-
-
- |
- H.throw_alert("nitro", /obj/screen/alert/nitro) |
-
-
- |
- else if(atmos_requirements["max_nitro"] && N2_pp > atmos_requirements["max_nitro"]) |
-
-
- |
- var/ratio = (breath.nitrogen / atmos_requirements["max_nitro"]) * 1000 |
-
-
- |
- H.adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) |
-
-
- |
- H.throw_alert("nitro", /obj/screen/alert/too_much_nitro) |
-
-
- |
- else |
-
-
- |
- H.clear_alert("nitro") |
-
-
- |
- if(atmos_requirements["min_nitro"]) //species breathes this gas, so they got their air |
-
-
- |
- H.failed_last_breath = 0 |
-
-
- |
- H.adjustOxyLoss(-5) |
-
-
- |
- N2_used = breath.nitrogen / 6 |
-
-
- |
-
- |
-
-
- |
- if(Tox_pp < atmos_requirements["min_tox"]) |
-
-
- |
- if(prob(20)) |
-
-
- |
- spawn(0) |
-
-
- |
- H.emote("gasp") |
-
-
- |
-
- |
-
-
- |
- H.failed_last_breath = 1 |
-
-
- |
- if(Tox_pp > 0) |
-
-
- |
- var/ratio = atmos_requirements["min_tox"] / Tox_pp |
-
-
- |
- H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) |
-
-
- |
- else |
-
-
- |
- H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) |
-
-
- |
- H.throw_alert("tox_in_air", /obj/screen/alert/not_enough_tox) |
-
-
- |
- else if(atmos_requirements["max_tox"] && Tox_pp > atmos_requirements["max_tox"]) |
-
-
- |
- var/ratio = (breath.toxins / atmos_requirements["max_tox"]) * 10 |
-
-
- |
- if(H.reagents) |
-
-
- |
- H.reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) |
-
-
- |
- H.throw_alert("tox_in_air", /obj/screen/alert/tox_in_air) |
-
-
- |
- else |
-
-
- |
- H.clear_alert("tox_in_air") |
-
-
- |
- if(atmos_requirements["min_tox"]) //species breathes this gas, so, they got their air |
-
-
- |
- H.failed_last_breath = 0 |
-
-
- |
- H.adjustOxyLoss(-5) |
-
-
- |
- Tox_used = breath.toxins / 6 |
-
-
- |
-
- |
-
-
- |
- if(CO2_pp < atmos_requirements["min_co2"]) |
-
-
- |
- if(prob(20)) |
-
-
- |
- spawn(0) |
-
-
- |
- H.emote("gasp") |
-
-
- |
-
- |
-
-
- |
- H.failed_last_breath = 1 |
-
-
- |
- if(CO2_pp) |
-
-
- |
- var/ratio = atmos_requirements["min_co2"] / CO2_pp |
-
-
- |
- H.adjustOxyLoss(min(5 * ratio, HUMAN_MAX_OXYLOSS)) |
-
-
- |
- else |
-
-
- |
- H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) |
-
-
- |
- H.throw_alert("co2", /obj/screen/alert/not_enough_co2) |
-
-
- |
- else if(atmos_requirements["max_co2"] && CO2_pp > atmos_requirements["max_co2"]) |
-
-
- |
- if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. |
-
-
- |
- H.co2overloadtime = world.time |
-
-
- |
- else if(world.time - H.co2overloadtime > 120) |
-
-
- |
- H.Paralyse(5) |
-
-
- |
- H.adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business |
-
-
- |
- if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good! |
-
-
- |
- H.adjustOxyLoss(8) |
-
-
- |
- if(prob(20)) // Lets give them some chance to know somethings not right though I guess. |
-
-
- |
- spawn(0) |
-
-
- |
- H.emote("cough") |
-
-
- |
- else |
-
-
- |
- H.clear_alert("co2") |
-
-
- |
- H.co2overloadtime = 0 |
-
-
- |
- if(atmos_requirements["min_co2"]) //species breathes this gas, so they got their air |
-
-
- |
- H.failed_last_breath = 0 |
-
-
- |
- H.adjustOxyLoss(-5) |
-
-
- |
- CO2_used = breath.carbon_dioxide / 6 |
-
-
- |
-
- |
-
-
- |
- breath.oxygen -= O2_used |
-
-
- |
- breath.nitrogen -= N2_used |
-
-
- |
- breath.toxins -= Tox_used |
-
-
- |
- breath.carbon_dioxide -= CO2_used |
-
-
- |
- breath.carbon_dioxide += O2_used |
-
-
- |
-
- |
-
-
- |
-
- |
-
-
- |
- if(breath.trace_gases.len) // If there's some other shit in the air lets deal with it here. |
-
-
- |
- for(var/datum/gas/sleeping_agent/SA in breath.trace_gases) |
-
-
- |
- var/SA_pp = (SA.moles / breath.total_moles()) * breath_pressure |
-
-
- |
- if(SA_pp > atmos_requirements["sa_para"]) // Enough to make us paralysed for a bit |
-
-
- |
- H.Paralyse(3) // 3 gives them one second to wake up and run away a bit! |
-
-
- |
- if(SA_pp > atmos_requirements["sa_sleep"]) // Enough to make us sleep as well |
-
-
- |
- // This value is large because breaths are taken only once every 4 life ticks. |
-
-
- |
- H.AdjustSleeping(8, bound_lower = 0, bound_upper = 10) |
-
-
- |
- else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning |
-
-
- |
- if(prob(20)) |
-
-
- |
- spawn(0) |
-
-
- |
- H.emote(pick("giggle", "laugh")) |
-
-
- |
-
- |
-
-
- |
- handle_temperature(breath, H) |
-
-
- |
- return 1 |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_temperature(datum/gas_mixture/breath, var/mob/living/carbon/human/H) // called by human/life, handles temperatures |
-
-
- |
- if(abs(310.15 - breath.temperature) > 50) // Hot air hurts :( |
-
-
- |
- if(H.status_flags & GODMODE) return 1 //godmode |
-
-
- |
- if(breath.temperature < cold_level_1) |
-
-
- |
- if(prob(20)) |
-
-
- |
- to_chat(H, "<span class='warning'>You feel your face freezing and an icicle forming in your lungs!</span>") |
-
-
- |
- else if(breath.temperature > heat_level_1) |
-
-
- |
- if(prob(20)) |
-
-
- |
- to_chat(H, "<span class='warning'>You feel your face burning and a searing heat in your lungs!</span>") |
-
-
- |
-
- |
-
-
- |
-
- |
-
-
- |
-
- |
-
-
- |
- switch(breath.temperature) |
-
-
- |
- if(-INFINITY to cold_level_3) |
-
-
- |
- H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Cold") |
-
-
- |
-
- |
-
-
- |
- if(cold_level_3 to cold_level_2) |
-
-
- |
- H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Cold") |
-
-
- |
-
- |
-
-
- |
- if(cold_level_2 to cold_level_1) |
-
-
- |
- H.apply_damage(cold_env_multiplier*COLD_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Cold") |
-
-
- |
-
- |
-
-
- |
- if(heat_level_1 to heat_level_2) |
-
-
- |
- H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head", used_weapon = "Excessive Heat") |
-
-
- |
-
- |
-
-
- |
- if(heat_level_2 to heat_level_3_breathe) |
-
-
- |
- H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Heat") |
-
-
- |
-
- |
-
-
- |
- if(heat_level_3_breathe to INFINITY) |
-
-
- |
- H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Heat") |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_post_spawn(var/mob/living/carbon/C) //Handles anything not already covered by basic species assignment. |
-
-
- |
- grant_abilities(C) |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/updatespeciescolor(var/mob/living/carbon/human/H) //Handles changing icobase for species that have multiple skin colors. |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/grant_abilities(var/mob/living/carbon/human/H) |
-
-
- |
- for(var/proc/ability in species_abilities) |
-
-
- |
- H.verbs += ability |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_pre_change(var/mob/living/carbon/human/H) |
-
-
- |
- if(H.butcher_results)//clear it out so we don't butcher a actual human. |
-
-
- |
- H.butcher_results = null |
-
-
- |
- remove_abilities(H) |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/remove_abilities(var/mob/living/carbon/human/H) |
-
-
- |
- for(var/proc/ability in species_abilities) |
-
-
- |
- H.verbs -= ability |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- // Do species-specific reagent handling here |
-
-
- |
- // Return 1 if it should do normal processing too |
-
-
- |
- // Return 0 if it shouldn't deplete and do its normal effect |
-
-
- |
- // Other return values will cause weird badness |
-
-
- |
- /datum/species/proc/handle_reagents(var/mob/living/carbon/human/H, var/datum/reagent/R) |
-
-
- |
- return 1 |
-
-
- |
-
- |
-
-
- |
- // For special snowflake species effects |
-
-
- |
- // (Slime People changing color based on the reagents they consume) |
-
-
- |
- /datum/species/proc/handle_life(var/mob/living/carbon/human/H) |
-
-
- |
- return 1 |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_dna(var/mob/living/carbon/C, var/remove) //Handles DNA mutations, as that doesn't work at init. Make sure you call genemutcheck on any blocks changed here |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- // Used for species-specific names (Vox, etc) |
-
-
- |
- /datum/species/proc/makeName(var/gender,var/mob/living/carbon/human/H=null) |
-
-
- |
- if(gender==FEMALE) return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names)) |
-
-
- |
- else return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns). |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_attack_hand(var/mob/living/carbon/human/H, var/mob/living/carbon/human/M) //Handles any species-specific attackhand events. |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/say_filter(mob/M, message, datum/language/speaking) |
-
-
- |
- return message |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/equip(var/mob/living/carbon/human/H) |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/can_understand(var/mob/other) |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- // Called in life() when the mob has no client. |
-
-
- |
- /datum/species/proc/handle_npc(var/mob/living/carbon/human/H) |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- //Species unarmed attacks |
-
-
- |
-
- |
-
-
- |
- /datum/unarmed_attack |
-
-
- |
- var/attack_verb = list("attack") // Empty hand hurt intent verb. |
-
-
- |
- var/damage = 0 // How much flat bonus damage an attack will do. This is a *bonus* guaranteed damage amount on top of the random damage attacks do. |
-
-
- |
- var/attack_sound = "punch" |
-
-
- |
- var/miss_sound = 'sound/weapons/punchmiss.ogg' |
-
-
- |
- var/sharp = 0 |
-
-
- |
- var/edge = 0 |
-
-
- |
-
- |
-
-
- |
- /datum/unarmed_attack/punch |
-
-
- |
- attack_verb = list("punch") |
-
-
- |
-
- |
-
-
- |
- /datum/unarmed_attack/punch/weak |
-
-
- |
- attack_verb = list("flail") |
-
-
- |
-
- |
-
-
- |
- /datum/unarmed_attack/diona |
-
-
- |
- attack_verb = list("lash", "bludgeon") |
-
-
- |
-
- |
-
-
- |
- /datum/unarmed_attack/claws |
-
-
- |
- attack_verb = list("scratch", "claw") |
-
-
- |
- attack_sound = 'sound/weapons/slice.ogg' |
-
-
- |
- miss_sound = 'sound/weapons/slashmiss.ogg' |
-
-
- |
- sharp = 1 |
-
-
- |
- edge = 1 |
-
-
- |
-
- |
-
-
- |
- /datum/unarmed_attack/claws/armalis |
-
-
- |
- attack_verb = list("slash", "claw") |
-
-
- |
- damage = 6 |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_can_equip(obj/item/I, slot, disable_warning = 0, mob/living/carbon/human/user) |
-
-
- |
- return 0 |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_vision(mob/living/carbon/human/H) |
-
-
- |
- // Right now this just handles blind, blurry, and similar states |
-
-
- |
- if(H.blinded || H.eye_blind) |
-
-
- |
- H.overlay_fullscreen("blind", /obj/screen/fullscreen/blind) |
-
-
- |
- H.throw_alert("blind", /obj/screen/alert/blind) |
-
-
- |
- else |
-
-
- |
- H.clear_fullscreen("blind") |
-
-
- |
- H.clear_alert("blind") |
-
-
- |
-
- |
-
-
- |
-
- |
-
-
- |
- if(H.disabilities & NEARSIGHTED) //this looks meh but saves a lot of memory by not requiring to add var/prescription |
-
-
- |
- if(H.glasses) //to every /obj/item |
-
-
- |
- var/obj/item/clothing/glasses/G = H.glasses |
-
-
- |
- if(G.prescription) |
-
-
- |
- H.clear_fullscreen("nearsighted") |
-
-
- |
- else |
-
-
- |
- H.overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1) |
-
-
- |
- else |
-
-
- |
- H.overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1) |
-
-
- |
- else |
-
-
- |
- H.clear_fullscreen("nearsighted") |
-
-
- |
-
- |
-
-
- |
- if(H.eye_blurry) |
-
-
- |
- H.overlay_fullscreen("blurry", /obj/screen/fullscreen/blurry) |
-
-
- |
- else |
-
-
- |
- H.clear_fullscreen("blurry") |
-
-
- |
-
- |
-
-
- |
- if(H.druggy) |
-
-
- |
- H.overlay_fullscreen("high", /obj/screen/fullscreen/high) |
-
-
- |
- H.throw_alert("high", /obj/screen/alert/high) |
-
-
- |
- else |
-
-
- |
- H.clear_fullscreen("high") |
-
-
- |
- H.clear_alert("high") |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/handle_hud_icons(mob/living/carbon/human/H) |
-
-
- |
- if(!H.client) |
-
-
- |
- return |
-
-
- |
- if(H.healths) |
-
-
- |
- if(H.stat == DEAD) |
-
-
- |
- H.healths.icon_state = "health7" |
-
-
- |
- else |
-
-
- |
- switch(H.hal_screwyhud) |
-
-
- |
- if(1) H.healths.icon_state = "health6" |
-
-
- |
- if(2) H.healths.icon_state = "health7" |
-
-
- |
- if(5) H.healths.icon_state = "health0" |
-
-
- |
- else |
-
-
- |
- switch(100 - ((flags & NO_PAIN) ? 0 : H.traumatic_shock) - H.staminaloss) |
-
-
- |
- if(100 to INFINITY) H.healths.icon_state = "health0" |
-
-
- |
- if(80 to 100) H.healths.icon_state = "health1" |
-
-
- |
- if(60 to 80) H.healths.icon_state = "health2" |
-
-
- |
- if(40 to 60) H.healths.icon_state = "health3" |
-
-
- |
- if(20 to 40) H.healths.icon_state = "health4" |
-
-
- |
- if(0 to 20) H.healths.icon_state = "health5" |
-
-
- |
- else H.healths.icon_state = "health6" |
-
-
- |
-
- |
-
-
- |
- if(H.healthdoll) |
-
-
- |
- if(H.stat == DEAD) |
-
-
- |
- H.healthdoll.icon_state = "healthdoll_DEAD" |
-
-
- |
- if(H.healthdoll.overlays.len) |
-
-
- |
- H.healthdoll.overlays.Cut() |
-
-
- |
- else |
-
-
- |
- var/list/new_overlays = list() |
-
-
- |
- var/list/cached_overlays = H.healthdoll.cached_healthdoll_overlays |
-
-
- |
- // Use the dead health doll as the base, since we have proper "healthy" overlays now |
-
-
- |
- H.healthdoll.icon_state = "healthdoll_DEAD" |
-
-
- |
- for(var/obj/item/organ/external/O in H.organs) |
-
-
- |
- var/damage = O.burn_dam + O.brute_dam |
-
-
- |
- var/comparison = (O.max_damage/5) |
-
-
- |
- var/icon_num = 0 |
-
-
- |
- if(damage) |
-
-
- |
- icon_num = 1 |
-
-
- |
- if(damage > (comparison)) |
-
-
- |
- icon_num = 2 |
-
-
- |
- if(damage > (comparison*2)) |
-
-
- |
- icon_num = 3 |
-
-
- |
- if(damage > (comparison*3)) |
-
-
- |
- icon_num = 4 |
-
-
- |
- if(damage > (comparison*4)) |
-
-
- |
- icon_num = 5 |
-
-
- |
- new_overlays += "[O.limb_name][icon_num]" |
-
-
- |
- H.healthdoll.overlays += (new_overlays - cached_overlays) |
-
-
- |
- H.healthdoll.overlays -= (cached_overlays - new_overlays) |
-
-
- |
- H.healthdoll.cached_healthdoll_overlays = new_overlays |
-
-
- |
-
- |
-
-
- |
- switch(H.nutrition) |
-
-
- |
- if(NUTRITION_LEVEL_FULL to INFINITY) |
-
-
- |
- H.throw_alert("nutrition", /obj/screen/alert/fat) |
-
-
- |
- if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL) |
-
-
- |
- H.clear_alert("nutrition") |
-
-
- |
- if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) |
-
-
- |
- H.throw_alert("nutrition", /obj/screen/alert/hungry) |
-
-
- |
- else |
-
-
- |
- H.throw_alert("nutrition", /obj/screen/alert/starving) |
-
-
- |
- return 1 |
-
-
- |
-
- |
-
-
- |
- /* |
-
-
- |
- Returns the path corresponding to the corresponding organ |
-
-
- |
- It'll return null if the organ doesn't correspond, so include null checks when using this! |
-
-
- |
- */ |
-
-
- |
- //Fethas Todo:Do i need to redo this? |
-
-
- |
- /datum/species/proc/return_organ(var/organ_slot) |
-
-
- |
- if(!(organ_slot in has_organ)) |
-
-
- |
- return null |
-
-
- |
- return has_organ[organ_slot] |
-
-
- |
-
- |
-
-
- |
-
- |
-
-
- |
- /datum/species/proc/update_sight(mob/living/carbon/human/H) |
-
-
- |
- H.sight = initial(H.sight) |
-
-
- |
- H.see_in_dark = darksight |
-
-
- |
- H.see_invisible = invis_sight |
-
-
- |
-
- |
-
-
- |
- if(H.client.eye != H) |
-
-
- |
- var/atom/A = H.client.eye |
-
-
- |
- if(A.update_remote_sight(H)) //returns 1 if we override all other sight updates. |
-
-
- |
- return |
-
-
- |
-
- |
-
-
- |
- if(H.mind && H.mind.vampire) |
-
-
- |
- if(H.mind.vampire.get_ability(/datum/vampire_passive/full)) |
-
-
- |
- H.sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS |
-
-
- |
- H.see_in_dark = 8 |
-
-
- |
- H.see_invisible = SEE_INVISIBLE_MINIMUM |
-
-
- |
- else if(H.mind.vampire.get_ability(/datum/vampire_passive/vision)) |
-
-
- |
- H.sight |= SEE_MOBS |
-
-
- |
-
- |
-
-
- |
- for(var/obj/item/organ/internal/cyberimp/eyes/E in H.internal_organs) |
-
-
- |
- H.sight |= E.vision_flags |
-
-
- |
- if(E.dark_view) |
-
-
- |
- H.see_in_dark = E.dark_view |
-
-
- |
- if(E.see_invisible) |
-
-
- |
- H.see_invisible = min(H.see_invisible, E.see_invisible) |
-
-
- |
-
- |
-
-
- |
-
- |
-
-
- |
- if(H.seer == 1) |
-
-
- |
- var/obj/effect/rune/R = locate() in H.loc |
-
-
- |
- if(R && R.word1 == cultwords["see"] && R.word2 == cultwords["hell"] && R.word3 == cultwords["join"]) |
-
-
- |
- H.see_invisible = SEE_INVISIBLE_OBSERVER |
-
-
- |
- else |
-
-
- |
- H.see_invisible = SEE_INVISIBLE_LIVING |
-
-
- |
- H.seer = 0 |
-
-
- |
-
- |
-
-
- |
- var/lesser_darkview_bonus = INFINITY |
-
-
- |
- // my glasses, I can't see without my glasses |
-
-
- |
- if(H.glasses) |
-
-
- |
- var/obj/item/clothing/glasses/G = H.glasses |
-
-
- |
- H.sight |= G.vision_flags |
-
-
- |
- lesser_darkview_bonus = G.darkness_view |
-
-
- |
- if(G.invis_override) |
-
-
- |
- H.see_invisible = G.invis_override |
-
-
- |
- else |
-
-
- |
- H.see_invisible = min(G.invis_view, H.see_invisible) |
-
-
- |
-
- |
-
-
- |
- // better living through hat trading |
-
-
- |
- if(H.head) |
-
-
- |
- if(istype(H.head, /obj/item/clothing/head)) |
-
-
- |
- var/obj/item/clothing/head/hat = H.head |
-
-
- |
- H.sight |= hat.vision_flags |
-
-
- |
-
- |
-
-
- |
- if(hat.darkness_view) // Pick the lowest of the two darkness_views between the glasses and helmet. |
-
-
- |
- lesser_darkview_bonus = min(hat.darkness_view,lesser_darkview_bonus) |
-
-
- |
-
- |
-
-
- |
- if(hat.helmet_goggles_invis_view) |
-
-
- |
- H.see_invisible = min(hat.helmet_goggles_invis_view, H.see_invisible) |
-
-
- |
-
- |
-
-
- |
- if(istype(H.back, /obj/item/weapon/rig)) ///aghhh so snowflakey |
-
-
- |
- var/obj/item/weapon/rig/rig = H.back |
-
-
- |
- if(rig.visor) |
-
-
- |
- if(!rig.helmet || (H.head && rig.helmet == H.head)) |
-
-
- |
- if(rig.visor && rig.visor.vision && rig.visor.active && rig.visor.vision.glasses) |
-
-
- |
- var/obj/item/clothing/glasses/G = rig.visor.vision.glasses |
-
-
- |
- if(istype(G)) |
-
-
- |
- H.see_in_dark = (G.darkness_view ? G.darkness_view : darksight) // Otherwise we keep our darkness view with togglable nightvision. |
-
-
- |
- if(G.vision_flags) // MESONS |
-
-
- |
- H.sight |= G.vision_flags |
-
-
- |
-
- |
-
-
- |
- H.see_invisible = min(G.invis_view, H.see_invisible) |
-
-
- |
-
- |
-
-
- |
- if(lesser_darkview_bonus != INFINITY) |
-
-
- |
- H.see_in_dark = max(lesser_darkview_bonus, H.see_in_dark) |
-
-
- |
-
- |
-
-
- |
- if(H.vision_type) |
-
-
- |
- H.see_in_dark = max(H.see_in_dark, H.vision_type.see_in_dark, darksight) |
-
-
- |
- H.see_invisible = H.vision_type.see_invisible |
-
-
- |
- if(H.vision_type.light_sensitive) |
-
-
- |
- H.weakeyes = 1 |
-
-
- |
- H.sight |= H.vision_type.sight_flags |
-
-
- |
-
- |
-
-
- |
- if(XRAY in H.mutations) |
-
-
- |
- H.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) |
-
-
- |
- H.see_in_dark = max(H.see_in_dark, 8) |
-
-
- |
- H.see_invisible = SEE_INVISIBLE_MINIMUM |
-
-
- |
-
- |
-
-
- |
- if(H.see_override) //Override all |
-
-
- |
- H.see_invisible = H.see_override |
-
-