From 2aab5fa71c7826c430ef7061c4f35c14a2964944 Mon Sep 17 00:00:00 2001 From: CollenN Date: Thu, 19 Jun 2014 17:42:14 -0400 Subject: [PATCH 1/4] Finalizes Mutantrace Datum Update https://github.com/tgstation/-tg-station/pull/3609 Squashes the commits from the above pull request. Should hopefully be a lot less cluttered. --- code/__DEFINES/flags.dm | 17 +- code/__HELPERS/global_lists.dm | 9 + code/__HELPERS/mobs.dm | 6 +- code/__HELPERS/unsorted.dm | 24 +- code/controllers/configuration.dm | 3 + code/controllers/shuttle_controller.dm | 2 +- code/datums/datumvars.dm | 21 +- code/datums/diseases/transformation.dm | 9 +- code/datums/mind.dm | 15 +- code/datums/spell.dm | 6 + code/datums/spells/construct_spells.dm | 17 + code/game/atoms.dm | 6 +- code/game/atoms_movable.dm | 7 +- code/game/dna.dm | 29 +- .../gamemodes/changeling/powers/absorb.dm | 3 +- .../gamemodes/changeling/powers/tiny_prick.dm | 2 +- .../gamemodes/changeling/powers/transform.dm | 5 +- code/game/gamemodes/wizard/soulstone.dm | 69 +- code/game/jobs/job/captain.dm | 2 +- code/game/jobs/job/job.dm | 6 + code/game/machinery/bots/ed209bot.dm | 3 - code/game/machinery/bots/secbot.dm | 5 +- code/game/machinery/cloning.dm | 7 +- code/game/machinery/computer/cloning.dm | 11 +- .../game/machinery/computer/communications.dm | 4 +- code/game/machinery/doors/airlock.dm | 5 + code/game/machinery/status_display.dm | 2 +- code/game/machinery/teleporter.dm | 7 +- code/game/machinery/vending.dm | 2 +- code/game/objects/effects/effect_system.dm | 5 +- code/game/objects/items.dm | 2 + .../objects/items/devices/laserpointer.dm | 8 +- code/game/objects/items/devices/scanners.dm | 103 +- .../objects/items/weapons/cigs_lighters.dm | 95 +- .../objects/items/weapons/storage/boxes.dm | 28 +- .../objects/items/weapons/storage/fancy.dm | 25 + .../game/objects/items/weapons/tanks/tanks.dm | 8 +- code/game/objects/structures/door_assembly.dm | 57 +- code/modules/admin/admin.dm | 1 - code/modules/admin/topic.dm | 7 - .../awaymissions/mission_code/wildwest.dm | 16 +- code/modules/client/preferences.dm | 55 +- code/modules/client/preferences_savefile.dm | 16 +- code/modules/clothing/gloves/boxing.dm | 1 + code/modules/events/holiday/halloween.dm | 4 +- code/modules/hydroponics/hydroponics.dm | 2 +- .../living/carbon/alien/humanoid/humanoid.dm | 67 +- .../mob/living/carbon/alien/larva/larva.dm | 47 +- code/modules/mob/living/carbon/carbon.dm | 9 +- code/modules/mob/living/carbon/human/death.dm | 12 +- code/modules/mob/living/carbon/human/human.dm | 48 +- .../living/carbon/human/human_attackhand.dm | 158 +- .../mob/living/carbon/human/human_damage.dm | 58 +- .../mob/living/carbon/human/human_defense.dm | 138 +- .../mob/living/carbon/human/human_defines.dm | 2 +- .../mob/living/carbon/human/human_helpers.dm | 9 +- .../mob/living/carbon/human/human_movement.dm | 27 +- .../mob/living/carbon/human/inventory.dm | 296 ++-- code/modules/mob/living/carbon/human/life.dm | 599 +------- .../mob/living/carbon/human/mutantrace.dm | 22 + code/modules/mob/living/carbon/human/say.dm | 37 +- .../mob/living/carbon/human/species.dm | 1330 +++++++++++++++++ .../mob/living/carbon/human/species_types.dm | 177 +++ .../mob/living/carbon/human/update_icons.dm | 126 +- .../modules/mob/living/carbon/metroid/life.dm | 9 +- .../mob/living/carbon/metroid/metroid.dm | 116 +- .../mob/living/carbon/monkey/monkey.dm | 83 +- code/modules/mob/living/living.dm | 4 +- code/modules/mob/living/living_defense.dm | 2 + .../mob/living/simple_animal/constructs.dm | 92 +- .../living/simple_animal/hostile/hostile.dm | 5 + .../mob/living/simple_animal/simple_animal.dm | 48 +- code/modules/mob/mob_helpers.dm | 5 +- .../mob/new_player/preferences_setup.dm | 17 +- code/modules/mob/transform_procs.dm | 22 +- code/modules/power/gravitygenerator.dm | 10 +- code/modules/power/singularity/singularity.dm | 58 +- code/modules/projectiles/gun.dm | 4 +- code/modules/projectiles/guns/energy.dm | 18 +- code/modules/projectiles/projectile.dm | 1 + code/modules/projectiles/projectile/magic.dm | 8 +- .../modules/projectiles/projectile/special.dm | 39 +- code/modules/reagents/Chemistry-Holder.dm | 4 +- code/modules/reagents/Chemistry-Reagents.dm | 22 - code/modules/reagents/reagent_containers.dm | 6 +- .../reagents/reagent_containers/syringes.dm | 6 + config/game_options.txt | 8 +- icons/mob/human.dmi | Bin 66301 -> 65202 bytes icons/mob/human_face.dmi | Bin 30991 -> 31661 bytes icons/obj/cigarettes.dmi | Bin 2454 -> 4673 bytes sound/machines/airlockforced.ogg | Bin 0 -> 16204 bytes tgstation.dme | 2 + 92 files changed, 2638 insertions(+), 1850 deletions(-) create mode 100644 code/modules/mob/living/carbon/human/mutantrace.dm create mode 100644 code/modules/mob/living/carbon/human/species.dm create mode 100644 code/modules/mob/living/carbon/human/species_types.dm create mode 100644 sound/machines/airlockforced.ogg diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 3db6e30fa52..b86d5e613b5 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -46,4 +46,19 @@ #define PASSTABLE 1 #define PASSGLASS 2 #define PASSGRILLE 4 -#define PASSBLOB 8 \ No newline at end of file +#define PASSBLOB 8 + +//flags for species + +#define MUTCOLORS 1 +#define HAIR 2 +#define FACEHAIR 4 +#define EYECOLOR 8 +#define LIPS 16 +#define COLDRES 32 +#define HEATRES 64 +#define RADIMMUNE 128 +#define NOBREATH 256 +#define NOGUNS 512 +#define NOBLOOD 1024 +#define NOFIRE 2048 \ No newline at end of file diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 9ab0003633a..d7ecd960955 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -10,6 +10,15 @@ //underwear init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, underwear_all, underwear_m, underwear_f) + //Species + for(var/spath in typesof(/datum/species)) + if(spath == /datum/species) + continue + var/datum/species/S = new spath() + if(S.roundstart) + roundstart_species[S.name] = S.type + species_list[S.id] = S.type + //Surgeries for(var/path in typesof(/datum/surgery)) if(path == /datum/surgery) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index b382bb1e678..6b53dcaa221 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -56,10 +56,8 @@ var/list/skin_tones = list( "african2" ) -var/list/mutant_races = list( - "human", - "lizard", - ) +var/global/list/species_list[0] +var/global/list/roundstart_species[0] proc/age2agedescription(age) switch(age) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 5e8ceba95ba..979f8042173 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -252,6 +252,15 @@ Turf and target are seperate in case you want to teleport some distance from a t if(isAI(src)) var/mob/living/silicon/ai/AI = src if(oldname != real_name) + if(AI.eyeobj) + AI.eyeobj.name = "[newname] (AI Eye)" + + // Set ai pda name + if(AI.aiPDA) + AI.aiPDA.owner = newname + AI.aiPDA.name = newname + " (" + AI.aiPDA.ownjob + ")" + + // Notify Cyborgs for(var/mob/living/silicon/robot/Slave in AI.connected_robots) Slave.show_laws() @@ -330,22 +339,7 @@ Turf and target are seperate in case you want to teleport some distance from a t if(cmptext("ai",role)) if(isAI(src)) - var/mob/living/silicon/ai/A = src oldname = null//don't bother with the records update crap - //world << "[newname] is the AI!" - //world << sound('sound/AI/newAI.ogg') - // Set eyeobj name - if(A.eyeobj) - A.eyeobj.name = "[newname] (AI Eye)" - - // Set ai pda name - if(A.aiPDA) - A.aiPDA.owner = newname - A.aiPDA.name = newname + " (" + A.aiPDA.ownjob + ")" - - // Notify Cyborgs - for(var/mob/living/silicon/robot/Slave in A.connected_robots) - Slave.show_laws() if(cmptext("cyborg",role)) if(isrobot(src)) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index a4c1fac1f53..892e781fb5e 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -85,6 +85,7 @@ var/shuttle_refuel_delay = 12000 var/show_game_type_odds = 0 //if set this allows players to see the odds of each roundtype on the get revision screen var/mutant_races = 0 //players can choose their mutant race before joining the game + var/mutant_colors = 0 var/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." var/alert_desc_blue_upto = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted." @@ -385,6 +386,8 @@ config.default_laws = text2num(value) if("join_with_mutant_race") config.mutant_races = 1 + if("mutant_colors") + config.mutant_colors = 1 else diary << "Unknown setting in configuration: '[name]'" diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm index 0858a70f7f1..6e1c9a0a078 100644 --- a/code/controllers/shuttle_controller.dm +++ b/code/controllers/shuttle_controller.dm @@ -73,7 +73,7 @@ datum/shuttle_controller last_call_loc = null if(recall_count == 2) - priority_announce("The emergency shuttle has been recalled.\n\nExcessive number of emergency shuttle calls detected. We will attempt to trace any further signals to their source. Results may be viewed on any communications console.", null, 'sound/AI/shuttlerecalled.ogg') + priority_announce("The emergency shuttle has been recalled.\n\nExcessive number of emergency shuttle calls detected. We will attempt to trace all future calls and recalls to their source. Tracing results can be viewed on any communications console.", null, 'sound/AI/shuttlerecalled.ogg') else priority_announce("The emergency shuttle has been recalled.", null, 'sound/AI/shuttlerecalled.ogg', "Priority") setdirection(-1) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 4dba24ce357..831de1e8858 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -254,7 +254,7 @@ client body += "" if(ishuman(D)) body += "" - body += "" + body += "" body += "" body += "" body += "" @@ -786,25 +786,24 @@ client return holder.Topic(href, list("makeai"=href_list["makeai"])) - else if(href_list["setmutantrace"]) + else if(href_list["setspecies"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["setmutantrace"]) + var/mob/living/carbon/human/H = locate(href_list["setspecies"]) if(!istype(H)) usr << "This can only be done to instances of type /mob/living/carbon/human" return - var/new_mutantrace = input("Please choose a new mutantrace","Mutantrace",null) as null|anything in list("NONE","golem","lizard","slime","plant","shadow", "fly", "skeleton") - switch(new_mutantrace) - if(null) return - if("NONE") new_mutantrace = "" + var/result = input(usr, "Please choose a new species","Species") as null|anything in species_list + if(!H) usr << "Mob doesn't exist anymore" return - if(H.dna) - H.dna.mutantrace = new_mutantrace - H.update_body() - H.update_hair() + + if(result) + var/newtype = species_list[result] + H.dna.species = new newtype() + H.regenerate_icons() else if(href_list["adjustDamage"] && href_list["mobToDamage"]) if(!check_rights(0)) return diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index f1ee58534ec..8749abed60d 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -139,15 +139,14 @@ ..() switch(stage) if(1) - if(ishuman(affected_mob) && affected_mob.dna && affected_mob.dna.mutantrace == "slime") + if(ishuman(affected_mob) && affected_mob.dna && affected_mob.dna.species.id == "slime") stage = 5 if(3) if(ishuman(affected_mob)) var/mob/living/carbon/human/human = affected_mob - if(human.dna && !human.dna.mutantrace) - human.dna.mutantrace = "slime" - human.update_body() - + if(human.dna && human.dna.species.id != "slime") + human.dna.species = new /datum/species/slime() + human.update_icons() /datum/disease/transformation/corgi name = "The Barkening" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 9b004722c96..1e2f7d20e0e 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1172,19 +1172,8 @@ datum/mind ..() mind.assigned_role = "Shade" -/mob/living/simple_animal/construct/builder/mind_initialize() +/mob/living/simple_animal/construct/mind_initialize() ..() - mind.assigned_role = "Artificer" + mind.assigned_role = "[initial(name)]" mind.special_role = "Cultist" -/mob/living/simple_animal/construct/wraith/mind_initialize() - ..() - mind.assigned_role = "Wraith" - mind.special_role = "Cultist" - -/mob/living/simple_animal/construct/armoured/mind_initialize() - ..() - mind.assigned_role = "Juggernaut" - mind.special_role = "Cultist" - - diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 06bedadbd4d..c792d2845cc 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -8,6 +8,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin desc = "A wizard spell" panel = "Spells" anchored = 1 // Crap like fireball projectiles are proc_holders, this is needed so fireballs don't get blown back into your face via atmos etc. + pass_flags = PASSTABLE density = 0 opacity = 0 @@ -191,6 +192,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here smoke.start() + else if(smoke_spread == 3) + var/datum/effect/effect/system/sleep_smoke_spread/smoke = new /datum/effect/effect/system/sleep_smoke_spread() + smoke.set_up(smoke_amt, 0, location, smoke_amt == 1 ? 15 : 0) // same here + smoke.start() + /obj/effect/proc_holder/spell/proc/cast(list/targets) return diff --git a/code/datums/spells/construct_spells.dm b/code/datums/spells/construct_spells.dm index ed3248d776a..7e4221f9a03 100644 --- a/code/datums/spells/construct_spells.dm +++ b/code/datums/spells/construct_spells.dm @@ -110,3 +110,20 @@ invocation_type = "none" proj_lifespan = 10 max_targets = 6 + + +/obj/effect/proc_holder/spell/targeted/smoke/disable + name = "Paralysing Smoke" + desc = "This spell spawns a cloud of paralysing smoke." + + school = "conjuration" + charge_max = 200 + clothes_req = 0 + invocation = "none" + invocation_type = "none" + range = -1 + include_user = 1 + cooldown_min = 20 //25 deciseconds reduction per rank + + smoke_spread = 3 + smoke_amt = 10 diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 718fe4db854..d8b0638b193 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -250,6 +250,10 @@ var/list/blood_splatter_icons = list() //returns 1 if made bloody, returns 0 otherwise /atom/proc/add_blood(mob/living/carbon/M) + if(ishuman(M) && M.dna) + var/mob/living/carbon/human/H = M + if(NOBLOOD in H.dna.species.specflags) + return 0 if(rejects_blood()) return 0 if(!istype(M)) @@ -270,7 +274,7 @@ var/list/blood_splatter_icons = list() //try to find a pre-processed blood-splatter. otherwise, make a new one var/index = blood_splatter_index() var/icon/blood_splatter_icon = blood_splatter_icons[index] - if(!blood_splatter_icon ) + if(!blood_splatter_icon) blood_splatter_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent) blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 6d60e1c7835..22a06b41da6 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -127,7 +127,10 @@ //done throwing, either because it hit something or it finished moving src.throwing = 0 - if(isobj(src)) src.throw_impact(get_turf(src)) + if(isobj(src)) + src.throw_impact(get_turf(src)) + + return 1 //Overlays @@ -152,4 +155,4 @@ /atom/movable/overlay/attack_hand(a, b, c) if (src.master) return src.master.attack_hand(a, b, c) - return \ No newline at end of file + return diff --git a/code/game/dna.dm b/code/game/dna.dm index d969e6bc1a1..35314862a41 100644 --- a/code/game/dna.dm +++ b/code/game/dna.dm @@ -20,7 +20,8 @@ var/struc_enzymes var/uni_identity var/blood_type - var/mutantrace = null //The type of mutant race the player is if applicable (i.e. potato-man) + var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man) + var/mutant_color = "FFF" // What color you are if you have certain speciess var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings, /datum/dna/proc/generate_uni_identity(mob/living/carbon/character) @@ -30,6 +31,8 @@ L[DNA_GENDER_BLOCK] = construct_block((character.gender!=MALE)+1, 2) if(istype(character, /mob/living/carbon/human)) var/mob/living/carbon/human/H = character + if(!H.dna.species) + H.dna.species = new /datum/species/human() L[DNA_HAIR_STYLE_BLOCK] = construct_block(hair_styles_list.Find(H.hair_style), hair_styles_list.len) L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color) L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(facial_hair_styles_list.Find(H.facial_hair_style), facial_hair_styles_list.len) @@ -62,11 +65,17 @@ . += repeat_string(DNA_UNIQUE_ENZYMES_LEN, "0") return . -/proc/hardset_dna(mob/living/carbon/owner, ui, se, real_name, mutantrace, blood_type) +/proc/hardset_dna(mob/living/carbon/owner, ui, se, real_name, blood_type, datum/species/mrace, mcolor) if(!istype(owner, /mob/living/carbon/monkey) && !istype(owner, /mob/living/carbon/human)) return if(!owner.dna) - create_dna(owner) + create_dna(owner, mrace) + + if(mrace) + owner.dna.species = new mrace() + + if(mcolor) + owner.dna.mutant_color = mcolor if(real_name) owner.real_name = real_name @@ -79,18 +88,13 @@ owner.dna.uni_identity = ui updateappearance(owner) - var/update_mutantrace = (mutantrace != owner.dna.mutantrace) - owner.dna.mutantrace = mutantrace - if(update_mutantrace && istype(owner, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = owner - H.update_body() - H.update_hair() - if(se) owner.dna.struc_enzymes = se domutcheck(owner) check_dna_integrity(owner) + + owner.regenerate_icons() return /proc/check_dna_integrity(mob/living/carbon/character) @@ -122,8 +126,9 @@ character.dna.unique_enzymes = character.dna.generate_unique_enzymes(character) return character.dna -/proc/create_dna(mob/living/carbon/C) //don't use this unless you're about to use hardset_dna or ready_dna +/proc/create_dna(mob/living/carbon/C, datum/species/S) //don't use this unless you're about to use hardset_dna or ready_dna C.dna = new /datum/dna() + if(S) C.dna.species = new S() // do not remove; this is here to prevent runtimes /////////////////////////// DNA DATUM @@ -981,7 +986,7 @@ proc/deconstruct_block(value, values, blocksize=DNA_BLOCK_SIZE) /datum/dna/proc/is_same_as(var/datum/dna/D) if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name) - if(mutantrace == D.mutantrace && blood_type == D.blood_type) + if(species == D.species && mutant_color == D.mutant_color && blood_type == D.blood_type) return 1 return 0 diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index 946ca14f8c4..bd1b910f90e 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -90,7 +90,8 @@ new_dna.uni_identity = T.dna.uni_identity new_dna.struc_enzymes = T.dna.struc_enzymes new_dna.real_name = T.dna.real_name - new_dna.mutantrace = T.dna.mutantrace + new_dna.species = T.dna.species + new_dna.mutant_color = T.dna.mutant_color new_dna.blood_type = T.dna.blood_type absorbed_dna |= new_dna //And add the target DNA to our absorbed list. absorbedcount++ //all that done, let's increment the objective counter. \ No newline at end of file diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index 17aae0b9b84..da147e0d128 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -88,7 +88,7 @@ var/datum/dna/NewDNA = selected_dna if(ismonkey(target)) user << "We stealthily sting [target.name]." - hardset_dna(target, NewDNA.uni_identity, NewDNA.struc_enzymes, NewDNA.real_name, NewDNA.mutantrace, NewDNA.blood_type) + hardset_dna(target, NewDNA.uni_identity, NewDNA.struc_enzymes, NewDNA.real_name, NewDNA.blood_type, NewDNA.species, NewDNA.mutant_color) updateappearance(target) feedback_add_details("changeling_powers","TS") return 1 diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index 612d7871abc..b6954ccf79c 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -8,16 +8,17 @@ max_genetic_damage = 3 //Change our DNA to that of somebody we've absorbed. -/obj/effect/proc_holder/changeling/transform/sting_action(var/mob/living/carbon/user) +/obj/effect/proc_holder/changeling/transform/sting_action(var/mob/living/carbon/human/user) var/datum/changeling/changeling = user.mind.changeling var/datum/dna/chosen_dna = changeling.select_dna("Select the target DNA: ", "Target DNA") if(!chosen_dna) return - user.dna = chosen_dna user.real_name = chosen_dna.real_name + user.dna.species = new chosen_dna.species.type(user) + user.dna.mutant_color = chosen_dna.mutant_color updateappearance(user) domutcheck(user, null) diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index 2e7d0f8d0f2..3f40d34b6de 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -22,13 +22,6 @@ transfer_soul("VICTIM", M, user) return -/*/obj/item/device/soulstone/attack(mob/living/simple_animal/shade/M as mob, mob/user as mob)//APPARENTLY THEY NEED THEIR OWN SPECIAL SNOWFLAKE CODE IN THE LIVING ANIMAL DEFINES - if(!istype(M, /mob/living/simple_animal/shade))//If target is not a shade - return ..() - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])") - - transfer_soul("SHADE", M, user) - return*/ ///////////////////Options for using captured souls/////////////////////////////////////// /obj/item/device/soulstone/attack_self(mob/user) @@ -46,8 +39,6 @@ return - - /obj/item/device/soulstone/Topic(href, href_list) var/mob/U = usr if (!in_range(src, U)||U.machine!=src) @@ -160,53 +151,35 @@ var/construct_class = alert(U, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer") switch(construct_class) if("Juggernaut") - var/mob/living/simple_animal/construct/armoured/Z = new /mob/living/simple_animal/construct/armoured (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, create shield walls and even deflect energy weapons, and rip apart enemies and walls alike." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/armoured, T, U) if("Wraith") - var/mob/living/simple_animal/construct/wraith/Z = new /mob/living/simple_animal/construct/wraith (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/wraith, T, U) if("Artificer") - var/mob/living/simple_animal/construct/builder/Z = new /mob/living/simple_animal/construct/builder (get_turf(T.loc)) - Z.key = A.key - if(iscultist(U)) - if(ticker.mode.name == "cult") - ticker.mode:add_cultist(Z.mind) - else - ticker.mode.cult+=Z.mind - ticker.mode.update_cult_icons_added(Z.mind) - qdel(T) - Z << "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, use magic missile, repair allied constructs (by clicking on them), and most important of all create new constructs (Use your Artificer spell to summon a new construct shell and Summon Soulstone to create a new soulstone)." - Z << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." - Z.cancel_camera() - qdel(C) + makeNewConstruct(/mob/living/simple_animal/construct/builder, T, U) + + qdel(T) + qdel(C) else U << "Creation failed!: The soul stone is empty! Go kill someone!" return + +proc/makeNewConstruct(var/mob/living/simple_animal/construct/ctype, var/mob/target, var/mob/stoner = null, cultoverride = 0) + var/mob/living/simple_animal/construct/newstruct = new ctype(get_turf(target)) + newstruct.key = target.key + if(stoner && iscultist(stoner) || cultoverride) + if(ticker.mode.name == "cult") + ticker.mode:add_cultist(newstruct.mind) + else + ticker.mode.cult+=newstruct.mind + ticker.mode.update_cult_icons_added(newstruct.mind) + newstruct << newstruct.playstyle_string + newstruct << "You are still bound to serve your creator, follow their orders and help them complete their goals at all costs." + newstruct.cancel_camera() + + /obj/item/device/soulstone/proc/init_shade(var/obj/item/device/soulstone/C, var/mob/living/carbon/human/T, var/mob/U as mob, var/vic = 0) new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton T.invisibility = 101 diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index 62b93744f17..bfa0a915c94 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -43,7 +43,7 @@ Captain L.imp_in = H L.implanted = 1 - world << "[H.real_name] is the captain!" + world << "Captain [H.real_name] on deck!" /datum/job/captain/get_access() return get_all_accesses() diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 460b9fbeaa5..93c43bd653d 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -74,8 +74,14 @@ equip_backpack(H) //Equip the rest of the gear + if(H.dna) + H.dna.species.before_equip_job(src, H) + equip_items(H) + if(H.dna) + H.dna.species.after_equip_job(src, H) + //Equip ID var/obj/item/weapon/card/id/C = new default_id(H) C.access = get_access() diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 5cb9d67a849..9c18fef3d9a 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -698,9 +698,6 @@ Auto Patrol: []"}, if(istype(perp:wear_suit, /obj/item/clothing/suit/wizrobe)) threatcount += 2 - if(perp.dna && perp.dna.mutantrace && perp.dna.mutantrace != "none") - threatcount += 2 - //Agent cards lower threatlevel when normal idchecking is off. if((perp.wear_id && istype(perp:wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) && src.idcheck) threatcount -= 2 diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index e14f870ce67..7d1b29986d9 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -630,9 +630,6 @@ Auto Patrol: []"}, if(istype(humanperp.head, /obj/item/clothing/head/wizard) || istype(humanperp.head, /obj/item/clothing/head/helmet/space/rig/wizard)) threatcount += 2 - if(humanperp.dna && humanperp.dna.mutantrace && humanperp.dna.mutantrace != "none") - threatcount += 2 - //Agent cards lower threatlevel. if(humanperp.wear_id && istype(humanperp.wear_id.GetID(), /obj/item/weapon/card/id/syndicate)) threatcount -= 2 @@ -789,4 +786,4 @@ Auto Patrol: []"}, overlays -= "hs_arm" new /obj/item/robot_parts/l_arm(get_turf(src)) user << "You remove the robot arm from [src]." - build_step-- \ No newline at end of file + build_step-- diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 16437db55e0..ec9da16ba30 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -123,7 +123,7 @@ //Clonepod //Start growing a human clone in the pod! -/obj/machinery/clonepod/proc/growclone(var/ckey, var/clonename, var/ui, var/se, var/mindref, var/mrace) +/obj/machinery/clonepod/proc/growclone(var/ckey, var/clonename, var/ui, var/se, var/mindref, var/datum/species/mrace, var/mcolor) if(panel_open) return 0 if(mess || attempting) @@ -188,7 +188,8 @@ // -- End mode specific stuff - hardset_dna(H, ui, se, null, mrace) + hardset_dna(H, ui, se, null, null, mrace, mcolor) + if(efficiency > 2) for(var/A in bad_se_blocks) setblock(H.dna.struc_enzymes, A, construct_block(0,2)) @@ -203,6 +204,8 @@ H.facial_hair_style = "Shaved" H.hair_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") + H.regenerate_icons() + H.suiciding = 0 src.attempting = 0 return 1 diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 47f4870e719..f4e41af1fd2 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -34,7 +34,7 @@ if(!(pod1.occupant || pod1.mess) && (pod1.efficiency > 5)) for(var/datum/data/record/R in records) if(!(pod1.occupant || pod1.mess)) - if(pod1.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"])) + if(pod1.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["mcolor"])) records -= R /obj/machinery/computer/cloning/proc/updatemodules() @@ -328,7 +328,7 @@ temp = "Clonepod malfunction." else if(!config.revival_cloning) temp = "Unable to initiate cloning cycle." - else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"])) + else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["mcolor"])) temp = "[C.fields["name"]] => Cloning cycle in progress..." records.Remove(C) if(active_record == C) @@ -368,10 +368,10 @@ return var/datum/data/record/R = new() - if(subject.dna) - R.fields["mrace"] = subject.dna.mutantrace + if(subject.dna.species) + R.fields["mrace"] = subject.dna.species.type else - R.fields["mrace"] = null + R.fields["mrace"] = /datum/species/human R.fields["ckey"] = subject.ckey R.fields["name"] = subject.real_name R.fields["id"] = copytext(md5(subject.real_name), 2, 6) @@ -379,6 +379,7 @@ R.fields["UI"] = subject.dna.uni_identity R.fields["SE"] = subject.dna.struc_enzymes R.fields["blood_type"] = subject.dna.blood_type + R.fields["mcolor"] = subject.dna.mutant_color //Add an implant if needed var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 4c5148c3dc8..7ab878e4c54 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -355,9 +355,9 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12 if (src.authenticated) if(emergency_shuttle.recall_count > 1) if(emergency_shuttle.last_call_loc) - dat += "
Latest emergency signal trace attempt successful.
Last signal origin: [format_text(emergency_shuttle.last_call_loc.name)].
" + dat += "
Last emergency shuttle call/recall traced to: [format_text(emergency_shuttle.last_call_loc.name)].
" else - dat += "
Latest emergency signal trace attempt failed.
" + dat += "
Last emergency shuttle call/recall trace failed.
" dat += "Logged in as: [auth_id]" dat += "
\[ Log Out \]
" dat += "
General Functions" diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index fe8e972b78a..e8d184b4b88 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1024,6 +1024,8 @@ About the new airlock wires panel: playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1) if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) src.closeOther.close() + else + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) if(autoclose && normalspeed) spawn(150) @@ -1060,6 +1062,9 @@ About the new airlock wires panel: playsound(src.loc, 'sound/items/bikehorn.ogg', 30, 1) else playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1) + else + playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) + var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) if(killthis) killthis.ex_act(2)//Smashin windows diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 9f85aa337b6..ed0b5bf6e4a 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -109,7 +109,7 @@ index2 -= message2_len update_display(line1, line2) if(4) // supply shuttle timer - var/line1 = "SUPPLY" + var/line1 = "CARGO" var/line2 if(supply_shuttle.moving) line2 = get_supply_shuttle_timer() diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index b2386d2b4f4..df07d30f159 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -247,11 +247,10 @@ if(prob(30 - (accurate * 10))) //oh dear a problem if(ishuman(M))//don't remove people from the round randomly you jerks var/mob/living/carbon/human/human = M - if(human.dna && !human.dna.mutantrace) + if(human.dna && human.dna.species.id == "human") M << "You hear a buzzing in your ears." - human.dna.mutantrace = "fly" - human.update_body() - human.update_hair() + human.dna.species = new /datum/species/fly() + human.regenerate_icons() human.apply_effect((rand(120 - accurate * 40, 180 - accurate * 60)), IRRADIATE, 0) return diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index e02188a5fb3..50da8e4965b 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -646,7 +646,7 @@ product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." vend_delay = 34 icon_state = "cigs" - products = list(/obj/item/weapon/storage/fancy/cigarettes = 10,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/rollingpaperpack = 5) + products = list(/obj/item/weapon/storage/fancy/cigarettes = 10,/obj/item/weapon/storage/box/matches = 10,/obj/item/weapon/lighter/random = 4,/obj/item/weapon/storage/fancy/rollingpapers = 5) contraband = list(/obj/item/weapon/lighter/zippo = 4) premium = list(/obj/item/clothing/mask/cigarette/cigar/havana = 2) refill_canister = /obj/item/weapon/vending_refill/cigarette diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index b5b4b4f7f5a..8dd8ad4263b 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -582,6 +582,7 @@ steam.start() -- spawns the effect icon = 'icons/effects/96x96.dmi' pixel_x = -32 pixel_y = -32 + color = "#9C3636" /obj/effect/effect/sleep_smoke/New() ..() @@ -596,7 +597,7 @@ steam.start() -- spawns the effect // if (M.wear_suit, /obj/item/clothing/suit/wizrobe && (M.hat, /obj/item/clothing/head/wizard) && (M.shoes, /obj/item/clothing/shoes/sandal)) // I'll work on it later else M.drop_item() - M:sleeping += 1 + M:sleeping += 5 if (M.coughedtime != 1) M.coughedtime = 1 M.emote("cough") @@ -612,7 +613,7 @@ steam.start() -- spawns the effect return else M.drop_item() - M:sleeping += 1 + M:sleeping += 5 if (M.coughedtime != 1) M.coughedtime = 1 M.emote("cough") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index ff296e1dfec..cbf87e7b1c2 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -32,6 +32,8 @@ var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. var/reflect_chance = 0 //This var dictates what % of a time an object will reflect an energy based weapon's shot + var/list/species_exception = list() // even if a species cannot put items in a certain slot, if the species id is in the item's exception list, it will be able to wear that item + /obj/item/device icon = 'icons/obj/device.dmi' diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 3910f798064..4e0804e76cf 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -81,10 +81,10 @@ if(user.has_mutation(HULK)) user << "Your meaty finger is too large for the button!" return - if(iscarbon(user)) - var/mob/living/carbon/C = user - if(C.is_mutantrace("adamantine")) - user << "Your metal fingers can't press the button!" + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.dna && NOGUNS in H.dna.species.specflags) + user << "Your fingers can't press the button!" return add_fingerprint(user) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 996ce6ff0b1..8d25a62be7e 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -78,16 +78,16 @@ MASS SPECTROMETER // Clumsiness/brain damage check if ((CLUMSY in user.mutations || user.getBrainLoss() >= 60) && prob(50)) - user << text("You stupidly try to analyze the floor's vitals!") - user.visible_message(text("[user] has analyzed the floor's vitals!")) - user.show_message(text("Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) - user.show_message(text("\t Damage Specifics: 0-0-0-0"), 1) + user << "You stupidly try to analyze the floor's vitals!" + user.visible_message("[user] has analyzed the floor's vitals!") + user.show_message("Analyzing Results for The floor:\n\t Overall Status: Healthy", 1) + user.show_message("\t Damage Specifics: 0-0-0-0", 1) user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) user.show_message("Body Temperature: ???", 1) return - user.visible_message(text("[] has analyzed []'s vitals!", user, M)) + user.visible_message("[user] has analyzed [M]'s vitals.") healthscan(user, M, mode) @@ -102,21 +102,26 @@ MASS SPECTROMETER var/tox_loss = M.getToxLoss() var/fire_loss = M.getFireLoss() var/brute_loss = M.getBruteLoss() - var/mob_status = (M.stat > 1 ? "Deceased" : text("[]% healthy", M.health)) + var/mob_status = (M.stat > 1 ? "Deceased" : "[M.health]% healthy") if(M.status_flags & FAKEDEATH) mob_status = "Deceased" oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss user.show_message(text("Analyzing Results for []:\n\t Overall Status: []", M, mob_status), 1) - user.show_message(text("\t Damage Specifics: []-[]-[]-[]", oxy_loss, tox_loss, fire_loss, brute_loss), 1) - + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.dna)// Show target's species, if they have one + user.show_message("Species: [H.dna.species.name]", 1) + else // Otherwise we can assume that they are a regular human + user.show_message("Species: Human", 1) + user.show_message("\t Damage Specifics: [oxy_loss]-[tox_loss]-[fire_loss]-[brute_loss]", 1) user.show_message("Key: Suffocation/Toxin/Burn/Brute", 1) user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) // Time of death if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH))) - user.show_message("Time of Death: [M.tod]") + user.show_message("Time of Death: [M.tod]", 1) // Organ damage report if(istype(M, /mob/living/carbon/human) && mode == 1) @@ -131,26 +136,26 @@ MASS SPECTROMETER // Damage descriptions - user.show_message(text("[] | [] | [] | []", oxy_loss > 50 ? "\red Severe oxygen deprivation detected\blue" : "Subject bloodstream oxygen level normal", tox_loss > 50 ? "\red Dangerous amount of toxins detected\blue" : "Subject bloodstream toxin level minimal", fire_loss > 50 ? "\red Severe burn damage detected\blue" : "Subject burn injury status O.K", brute_loss > 50 ? "\red Severe anatomical damage detected\blue" : "Subject brute-force injury status O.K"), 1) + user.show_message(text("[] | [] | [] | []", oxy_loss > 50 ? " Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal", tox_loss > 50 ? " Dangerous amount of toxins detected" : "Subject bloodstream toxin level minimal", fire_loss > 50 ? " Severe burn damage detected" : "Subject burn injury status O.K", brute_loss > 50 ? " Severe anatomical damage detected" : "Subject brute-force injury status O.K"), 1) if(M.getStaminaLoss()) - user.show_message(text("Subject appears to be suffering from fatigue."), 1) + user.show_message("Subject appears to be suffering from fatigue.", 1) if (M.getCloneLoss()) - user.show_message(text("Subject appears to have been imperfectly cloned."), 1) + user.show_message("Subject appears to have been imperfectly cloned.", 1) for(var/datum/disease/D in M.viruses) if(!D.hidden[SCANNER]) - user.show_message(text("Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]")) + user.show_message("Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]", 1) if (M.reagents && M.reagents.get_reagent_amount("inaprovaline")) - user.show_message(text("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals."), 1) + user.show_message("Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals.", 1) if (M.getBrainLoss() >= 100 || !M.getorgan(/obj/item/organ/brain)) - user.show_message(text("Subject brain function is non-existant."), 1) + user.show_message("Subject brain function is non-existant.", 1) else if (M.getBrainLoss() >= 60) - user.show_message(text("Severe brain damage detected. Subject likely to have mental retardation."), 1) + user.show_message("Severe brain damage detected. Subject likely to have mental retardation.", 1) else if (M.getBrainLoss() >= 10) - user.show_message(text("Significant brain damage detected. Subject may have had a concussion."), 1) + user.show_message("Significant brain damage detected. Subject may have had a concussion.", 1) /obj/item/device/healthanalyzer/verb/toggle_mode() set name = "Switch Verbosity" @@ -193,11 +198,11 @@ MASS SPECTROMETER var/pressure = environment.return_pressure() var/total_moles = environment.total_moles() - user.show_message("\blue Results:", 1) + user.show_message(" Results:", 1) if(abs(pressure - ONE_ATMOSPHERE) < 10) - user.show_message("\blue Pressure: [round(pressure,0.1)] kPa", 1) + user.show_message(" Pressure: [round(pressure,0.1)] kPa", 1) else - user.show_message("\red Pressure: [round(pressure,0.1)] kPa", 1) + user.show_message(" Pressure: [round(pressure,0.1)] kPa", 1) if(total_moles) var/o2_concentration = environment.oxygen/total_moles var/n2_concentration = environment.nitrogen/total_moles @@ -206,27 +211,27 @@ MASS SPECTROMETER var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+plasma_concentration) if(abs(n2_concentration - N2STANDARD) < 20) - user.show_message("\blue Nitrogen: [round(n2_concentration*100)]%", 1) + user.show_message(" Nitrogen: [round(n2_concentration*100)]%", 1) else - user.show_message("\red Nitrogen: [round(n2_concentration*100)]%", 1) + user.show_message(" Nitrogen: [round(n2_concentration*100)]%", 1) if(abs(o2_concentration - O2STANDARD) < 2) - user.show_message("\blue Oxygen: [round(o2_concentration*100)]%", 1) + user.show_message(" Oxygen: [round(o2_concentration*100)]%", 1) else - user.show_message("\red Oxygen: [round(o2_concentration*100)]%", 1) + user.show_message(" Oxygen: [round(o2_concentration*100)]%", 1) if(co2_concentration > 0.01) - user.show_message("\red CO2: [round(co2_concentration*100)]%", 1) + user.show_message(" CO2: [round(co2_concentration*100)]%", 1) else - user.show_message("\blue CO2: [round(co2_concentration*100)]%", 1) + user.show_message(" CO2: [round(co2_concentration*100)]%", 1) if(plasma_concentration > 0.01) - user.show_message("\red Plasma: [round(plasma_concentration*100)]%", 1) + user.show_message(" Plasma: [round(plasma_concentration*100)]%", 1) if(unknown_concentration > 0.01) - user.show_message("\red Unknown: [round(unknown_concentration*100)]%", 1) + user.show_message(" Unknown: [round(unknown_concentration*100)]%", 1) - user.show_message("\blue Temperature: [round(environment.temperature-T0C)]°C", 1) + user.show_message(" Temperature: [round(environment.temperature-T0C)]°C", 1) src.add_fingerprint(user) return @@ -262,17 +267,17 @@ MASS SPECTROMETER if (user.stat) return if (crit_fail) - user << "\red This device has critically failed and is no longer functional!" + user << " This device has critically failed and is no longer functional!" return if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - user << "\red You don't have the dexterity to do this!" + user << " You don't have the dexterity to do this!" return if(reagents.total_volume) var/list/blood_traces = list() for(var/datum/reagent/R in reagents.reagent_list) if(R.id != "blood") reagents.clear_reagents() - user << "\red The sample was contaminated! Please insert another sample" + user.show_message(" The sample was contaminated! Please insert another sample.", 1) return else blood_traces = params2list(R.data["trace_chem"]) @@ -317,31 +322,31 @@ MASS SPECTROMETER /obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob) if (!isslime(M)) - user << "This device can only scan slimes!" + user.show_message("This device can only scan slimes!", 1) return var/mob/living/carbon/slime/T = M - user.show_message("Slime scan results:") - user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby")) - user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition())) + user.show_message("Slime scan results:", 1) + user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby"), 1) + user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition()), 1) if (T.nutrition < T.get_starve_nutrition()) - user.show_message("Warning: slime is starving!") + user.show_message("Warning: slime is starving!", 1) else if (T.nutrition < T.get_hunger_nutrition()) - user.show_message("Warning: slime is hungry") - user.show_message("Electric change strength: [T.powerlevel]") - user.show_message("Health: [T.health]") + user.show_message("Warning: slime is hungry", 1) + user.show_message("Electric change strength: [T.powerlevel]", 1) + user.show_message("Health: [T.health]", 1) if (T.slime_mutation[4] == T.colour) - user.show_message("This slime does not evolve any further") + user.show_message("This slime does not evolve any further.", 1) else if (T.slime_mutation[3] == T.slime_mutation[4]) if (T.slime_mutation[2] == T.slime_mutation[1]) - user.show_message(text("Possible mutation: []", T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting") + user.show_message("Possible mutation: [T.slime_mutation[3]]", 1) + user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting", 1) else - user.show_message(text("Possible mutations: [], [], [] (x2)", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)", 1) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1) else - user.show_message(text("Possible mutations: [], [], [], []", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3], T.slime_mutation[4])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") + user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]", 1) + user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1) if (T.cores > 1) - user.show_message("Anomalious slime core amount detected") - user.show_message("Growth progress: [T.amount_grown]/10") \ No newline at end of file + user.show_message("Anomalious slime core amount detected", 1) + user.show_message("Growth progress: [T.amount_grown]/10", 1) diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 35f0eadaa47..3b2c2381328 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -30,29 +30,44 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/turf/location = get_turf(src) smoketime-- if(smoketime < 1) + matchburnout() + return + if(location) + location.hotspot_expose(700, 5) + return + +/obj/item/weapon/match/fire_act() + matchignite() + +/obj/item/weapon/match/proc/matchignite() + if(lit == 0) + lit = 1 + icon_state = "match_lit" + damtype = "fire" + force = 3 + hitsound = 'sound/items/welder.ogg' + item_state = "cigon" + name = "lit match" + desc = "A match. This one is lit." + attack_verb = list("burnt","singed") + processing_objects.Add(src) + update_icon() + return + +/obj/item/weapon/match/proc/matchburnout() + if(lit == 1) lit = -1 damtype = "brute" - force = 0 + force = initial(force) icon_state = "match_burnt" item_state = "cigoff" name = "burnt match" desc = "A match. This one has seen better days." attack_verb = null processing_objects.Remove(src) - return - if(location) - location.hotspot_expose(700, 5) - return /obj/item/weapon/match/dropped(mob/user as mob) - if(lit == 1) - lit = -1 - damtype = "brute" - icon_state = "match_burnt" - item_state = "cigoff" - name = "burnt match" - desc = "A match. This one has seen better days." - attack_verb = null + matchburnout() return ..() ////////////////// @@ -78,7 +93,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/New() ..() flags |= NOREACT // so it doesn't react until you light it - create_reagents(chem_volume) // making the cigarrete a chemical holder with a maximum volume of 15 + create_reagents(chem_volume) // making the cigarette a chemical holder with a maximum volume of 15 /obj/item/clothing/mask/cigarette/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() @@ -120,7 +135,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM light("[user] lights their [name] with [W].") return - /obj/item/clothing/mask/cigarette/afterattack(obj/item/weapon/reagent_containers/glass/glass, mob/user as mob, proximity) if(!proximity) return if(istype(glass)) //you can dip cigarettes into beakers @@ -134,15 +148,14 @@ CIGARETTE PACKETS ARE IN FANCY.DM user << "[src] is full." -/obj/item/clothing/mask/cigarette/proc/light(var/flavor_text = "[usr] lights the [name].") +/obj/item/clothing/mask/cigarette/proc/light(var/flavor_text = null) if(!src.lit) src.lit = 1 name = "lit [name]" - if(!istype(src, /obj/item/clothing/mask/cigarette/pipe)) //can't burn people with pipes - attack_verb = list("burnt", "singed") - hitsound = 'sound/items/welder.ogg' - damtype = "fire" - force = 4 + attack_verb = list("burnt", "singed") + hitsound = 'sound/items/welder.ogg' + damtype = "fire" + force = 4 if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire var/datum/effect/effect/system/reagents_explosion/e = new() e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0) @@ -165,8 +178,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM reagents.handle_reactions() icon_state = icon_on item_state = icon_on - var/turf/T = get_turf(src) - T.visible_message(flavor_text) + if(flavor_text) + var/turf/T = get_turf(src) + T.visible_message(flavor_text) processing_objects.Add(src) //can't think of any other way to update the overlays :< @@ -176,6 +190,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM M.update_inv_l_hand(0) M.update_inv_r_hand(0) + /obj/item/clothing/mask/cigarette/proc/handle_reagents() if(iscarbon(loc)) var/mob/living/carbon/C = loc @@ -183,10 +198,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(prob(15)) // so it's not an instarape in case of acid reagents.reaction(C, INGEST) reagents.trans_to(C, REAGENTS_METABOLISM) - else - reagents.remove_any(REAGENTS_METABOLISM) - else - reagents.remove_any(REAGENTS_METABOLISM) + return + reagents.remove_any(REAGENTS_METABOLISM) + /obj/item/clothing/mask/cigarette/process() var/turf/location = get_turf(src) @@ -231,6 +245,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM else return ..() +/obj/item/clothing/mask/cigarette/fire_act() + light() + /obj/item/clothing/mask/cigarette/rollie name = "rollie" desc = "A roll of dried plant matter wrapped in thin paper." @@ -536,27 +553,3 @@ CIGARETTE PACKETS ARE IN FANCY.DM user << "You need to dry this first." else ..() - -/obj/item/weapon/rollingpaperpack - name = "rolling paper pack" - desc = "A pack of NanoTrasen brand rolling papers." - icon = 'icons/obj/cigarettes.dmi' - icon_state = "cig_paper_pack" - w_class = 1 - var/papers = 25 - -/obj/item/weapon/rollingpaperpack/attack_self(mob/user) - if(papers > 1) - var/obj/item/weapon/rollingpaper/P = new /obj/item/weapon/rollingpaper(user.loc) - user.put_in_inactive_hand(P) - user << "You take a paper out of the pack." - papers -- - else - var/obj/item/weapon/rollingpaper/P = new /obj/item/weapon/rollingpaper(user.loc) - user.put_in_inactive_hand(P) - user << "You take the last paper out of the pack, and throw the pack away." - qdel(src) - -/obj/item/weapon/rollingpaperpack/examine() - ..() - usr << "There are [src.papers] left" \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 521945ee7fd..010cb0420e5 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -470,25 +470,15 @@ w_class = 1 slot_flags = SLOT_BELT - New() - ..() - for(var/i=1; i <= storage_slots; i++) - new /obj/item/weapon/match(src) +/obj/item/weapon/storage/box/matches/New() + ..() + for(var/i=1; i <= storage_slots; i++) + new /obj/item/weapon/match(src) - attackby(obj/item/weapon/match/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/match) && W.lit == 0) - W.lit = 1 - W.icon_state = "match_lit" - W.damtype = "fire" - W.force = 3 - W.hitsound = 'sound/items/welder.ogg' - W.item_state = "cigon" - W.name = "lit match" - W.desc = "A match. This one is lit." - W.attack_verb = list("burnt","singed") - processing_objects.Add(W) - W.update_icon() - return +/obj/item/weapon/storage/box/matches/attackby(obj/item/weapon/match/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/match)) + W.matchignite() + return /obj/item/weapon/storage/box/lights name = "box of replacement bulbs" @@ -525,4 +515,4 @@ for(var/i = 0; i < 14; i++) new /obj/item/weapon/light/tube(src) for(var/i = 0; i < 7; i++) - new /obj/item/weapon/light/bulb(src) \ No newline at end of file + new /obj/item/weapon/light/bulb(src) diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm index b959c652871..303850c14dd 100644 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -192,3 +192,28 @@ desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"" icon_state = "Dpacket" item_state = "Dpacket" + + +/obj/item/weapon/storage/fancy/rollingpapers + name = "rolling paper pack" + desc = "A pack of NanoTrasen brand rolling papers." + w_class = 1 + icon = 'icons/obj/cigarettes.dmi' + icon_state = "cig_paper_pack" + storage_slots = 10 + icon_type = "rolling papers" + can_hold = list(/obj/item/weapon/rollingpaper) + +/obj/item/weapon/storage/fancy/rollingpapers/update_icon() + if(!contents.len) + icon_state = "[initial(icon_state)]0" + else + icon_state = initial(icon_state) + + desc = "There are [contents.len] papers\s left!" + return + +/obj/item/weapon/storage/fancy/rollingpapers/New() + ..() + for(var/i = 1 to storage_slots) + new /obj/item/weapon/rollingpaper(src) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 74393eafbe3..9c1e150c3e2 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -205,13 +205,15 @@ air_contents.react() pressure = air_contents.return_pressure() var/range = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE - range = min(range, MAX_EX_LIGHT_RANGE) var/turf/epicenter = get_turf(loc) //world << "\blue Exploding Pressure: [pressure] kPa, intensity: [range]" explosion(epicenter, round(range*0.25), round(range*0.5), round(range), round(range*1.5)) - qdel(src) + if(istype(src.loc,/obj/item/device/transfer_valve)) + qdel(src.loc) + else + qdel(src) else if(pressure > TANK_RUPTURE_PRESSURE) //world << "\blue[x],[y] tank is rupturing: [pressure] kPa, integrity [integrity]" @@ -237,4 +239,4 @@ integrity-- else if(integrity < 3) - integrity++ \ No newline at end of file + integrity++ diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 553122c43fb..e6518e44186 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -318,8 +318,10 @@ obj/structure/door_assembly /obj/structure/door_assembly/attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/pen)) var/t = copytext(stripped_input(user, "Enter the name for the door.", src.name, src.created_name),1,MAX_NAME_LEN) - if(!t) return - if(!in_range(src, usr) && src.loc != usr) return + if(!t) + return + if(!in_range(src, usr) && src.loc != usr) + return created_name = t return @@ -343,7 +345,8 @@ obj/structure/door_assembly icontype = input(user, "Please select a paintjob for this airlock.") in optionlist - if((!in_range(src, usr) && src.loc != usr) || !WT.use(user)) return + if((!in_range(src, usr) && src.loc != usr) || !WT.use(user)) + return var/has_solid = 0 var/has_glass = 0 switch(icontype) @@ -414,7 +417,7 @@ obj/structure/door_assembly if(mineral && mineral != "glass") mineral = null //I know this is stupid, but until we change glass to a boolean it's how this code works. - user << "\blue You change the paintjob on the airlock assembly." + user << " You change the paintjob on the airlock assembly." else if(istype(W, /obj/item/weapon/weldingtool) && !anchored ) var/obj/item/weapon/weldingtool/WT = W @@ -423,8 +426,9 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) if(do_after(user, 40)) - if(!src || !WT.isOn()) return - user << "\blue You've dissasembled the airlock assembly." + if( !WT.isOn() ) + return + user << " You've disassembled the airlock assembly." new /obj/item/stack/sheet/metal(get_turf(src), 4) if (mineral) if (mineral == "glass") @@ -435,7 +439,7 @@ obj/structure/door_assembly new M(get_turf(src)) qdel(src) else - user << "\blue You need more welding fuel to dissassemble the airlock assembly." + user << " You need more welding fuel to dissassemble the airlock assembly." return else if(istype(W, /obj/item/weapon/wrench) && !anchored ) @@ -443,8 +447,9 @@ obj/structure/door_assembly user.visible_message("[user] secures the airlock assembly to the floor.", "You start to secure the airlock assembly to the floor.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've secured the airlock assembly." + if( src.anchored ) + return + user << " You've secured the airlock assembly." src.name = "secured airlock assembly" src.anchored = 1 @@ -452,8 +457,9 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) user.visible_message("[user] unsecures the airlock assembly from the floor.", "You start to unsecure the airlock assembly from the floor.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've unsecured the airlock assembly." + if( !src.anchored ) + return + user << " You've unsecured the airlock assembly." src.name = "airlock assembly" src.anchored = 0 @@ -461,10 +467,9 @@ obj/structure/door_assembly var/obj/item/stack/cable_coil/coil = W user.visible_message("[user] wires the airlock assembly.", "You start to wire the airlock assembly.") if(do_after(user, 40)) - if(!src) return coil.use(1) src.state = 1 - user << "\blue You've wired the airlock assembly." + user << " You've wired the airlock assembly." src.name = "wired airlock assembly" else if(istype(W, /obj/item/weapon/wirecutters) && state == 1 ) @@ -472,8 +477,9 @@ obj/structure/door_assembly user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've cut the wires from the airlock assembly." + if( src.state != 1 ) + return + user << " You've cut the wires from the airlock assembly." new/obj/item/stack/cable_coil(get_turf(user), 1) src.state = 0 src.name = "secured airlock assembly" @@ -485,8 +491,9 @@ obj/structure/door_assembly W.loc = src if(do_after(user, 40)) - if(!src) return - user << "\blue You've installed the airlock electronics." + if( src.state != 1 ) + return + user << " You've installed the airlock electronics." src.state = 2 src.name = "near finished airlock assembly" src.electronics = W @@ -500,8 +507,9 @@ obj/structure/door_assembly user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove the electronics from the airlock assembly.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've removed the airlock electronics." + if( src.state != 2 ) + return + user << " You've removed the airlock electronics." src.state = 1 src.name = "wired airlock assembly" var/obj/item/weapon/airlock_electronics/ae @@ -519,7 +527,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - user << "\blue You've installed reinforced glass windows into the airlock assembly." + user << " You've installed reinforced glass windows into the airlock assembly." G.use(1) mineral = "glass" name = "near finished window airlock assembly" @@ -541,7 +549,7 @@ obj/structure/door_assembly playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] adds [G.name] to the airlock assembly.", "You start to install [G.name] into the airlock assembly.") if(do_after(user, 40)) - user << "\blue You've installed [M] plating into the airlock assembly." + user << " You've installed [M] plating into the airlock assembly." G.use(2) mineral = "[M]" name = "near finished [M] airlock assembly" @@ -552,11 +560,10 @@ obj/structure/door_assembly else if(istype(W, /obj/item/weapon/screwdriver) && state == 2 ) playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) - user << "\blue You start finishing the airlock." + user.visible_message("[user] finishes the airlock.", "You start finishing the airlock.") if(do_after(user, 40)) - if(!src) return - user << "\blue You've finished the airlock." + user << " You've finished the airlock." var/obj/machinery/door/airlock/door if(mineral == "glass") door = new src.glass_type( src.loc ) @@ -580,4 +587,4 @@ obj/structure/door_assembly icon_state = "[base_icon_state][state]" //This updates the icon_state. They are named as "door_as1_eng" where the 1 in that example //represents what state it's in. So the most generic algorithm for the correct updating of - //this is simply to change the number. \ No newline at end of file + //this is simply to change the number. diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index f08e6bffef1..7a7d7c45166 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -434,7 +434,6 @@ var/global/floorIsLava = 0 dat += {" 'Random' Events

- Trigger a gravity-failure event
Spawn a wave of meteors (aka lagocolyptic shower)
Spawn a vortex anomaly
Spawn a gravitational anomaly
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index f9fcfb99bf8..25510344edc 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1584,13 +1584,6 @@ usr.client.triple_ai() feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","TriAI") - if("gravity") - alert("WIP - event unavailable") -/* E = new /datum/round_event/weightless() - log_admin("[key_name(usr)] triggered a gravity-failure event.", 1) - message_admins("\blue [key_name_admin(usr)] triggered a gravity-failure event.", 1) - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","Grav") */ if("power") feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","P") diff --git a/code/modules/awaymissions/mission_code/wildwest.dm b/code/modules/awaymissions/mission_code/wildwest.dm index 9a2d6c758b4..1f0a894cd5a 100644 --- a/code/modules/awaymissions/mission_code/wildwest.dm +++ b/code/modules/awaymissions/mission_code/wildwest.dm @@ -89,20 +89,20 @@ user.see_in_dark = 8 user.see_invisible = SEE_INVISIBLE_LEVEL_TWO user << "\blue The walls suddenly disappear." - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("Wealth") user << "Your wish is granted, but at a terrible cost..." user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart." new /obj/structure/closet/syndicate/resources/everything(loc) - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("Immortality") user << "Your wish is granted, but at a terrible cost..." user << "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart." user.verbs += /mob/living/carbon/proc/immortality - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("To Kill") user << "Your wish is granted, but at a terrible cost..." user << "The Wish Granter punishes you for your wickedness, claiming your soul and warping your body to match the darkness in your heart." @@ -116,8 +116,8 @@ for(var/datum/objective/OBJ in user.mind.objectives) user << "Objective #[obj_count]: [OBJ.explanation_text]" obj_count++ - user.dna.mutantrace = "shadow" - user.update_body() + user.dna.species = new /datum/species/shadow() + user.regenerate_icons() if("Peace") user << "Whatever alien sentience that the Wish Granter possesses is satisfied with your wish. There is a distant wailing as the last of the Faithless begin to die, then silence." user << "You feel as if you just narrowly avoided a terrible fate..." diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7eaacc46d10..f3085e14e0f 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -53,7 +53,8 @@ datum/preferences var/facial_hair_color = "000" //Facial hair color var/skin_tone = "caucasian1" //Skin color var/eye_color = "000" //Eye color - var/mutant_race = "human" //Mutant race + var/datum/species/pref_species = new /datum/species/human() //Mutant race + var/mutant_color = "FFF" //Mutant race skin color //Mob preview var/icon/preview_icon_front = null @@ -165,16 +166,17 @@ datum/preferences dat += "
" if(config.mutant_races) - dat += "Mutant Race:
[mutant_race]
" + dat += "Species:
[pref_species.name]
" else - dat += "Mutant Race: Human
" + dat += "Species: Human
" + dat += "Blood Type: [blood_type]
" dat += "Skin Tone:
[skin_tone]
" dat += "Underwear:
[underwear]
" dat += "Backpack:
[backbaglist[backbag]]
" - dat += "
" + dat += "" dat += "

Hair Style

" @@ -182,7 +184,7 @@ datum/preferences dat += "    Change
" - dat += "
" + dat += "" dat += "

Facial Hair Style

" @@ -190,12 +192,17 @@ datum/preferences dat += "    Change
" - dat += "
" + dat += "" dat += "

Eye Color

" dat += "    Change
" + dat += "
" + + dat += "

Alien Color

" // even if choosing your mutantrace is off, this is here in case you gain one during a round + + dat += "    Change
" dat += "
" @@ -618,10 +625,27 @@ datum/preferences if(new_eyes) eye_color = sanitize_hexcolor(new_eyes) - if("mutant_race") - var/new_mutant_race = input(user, "Choose your character's mutant race:", "Character Preference") as null|anything in mutant_races - if(new_mutant_race) - mutant_race = new_mutant_race + if("species") + + var/result = input(user, "Select a species", "Species Selection") as null|anything in roundstart_species + + if(result) + var/newtype = roundstart_species[result] + pref_species = new newtype() + if(!config.mutant_colors) + mutant_color = pref_species.default_color + + if("mutant_color") + if(!config.mutant_colors) + user << "Alien colors are disabled." + return + var/new_mutantcolor = input(user, "Choose your character's alien skin color:", "Character Preference") as color|null + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) + if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright + mutant_color = sanitize_hexcolor(new_mutantcolor) + else + user << "Invalid color. Your color is not bright enough." if("s_tone") var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in skin_tones @@ -685,8 +709,10 @@ datum/preferences if("ghost_sight") toggles ^= CHAT_GHOSTSIGHT + if("pull_requests") toggles ^= CHAT_PULLR + if("save") save_preferences() save_character() @@ -722,10 +748,15 @@ datum/preferences character.real_name = real_name character.name = character.real_name + if(character.dna) character.dna.real_name = character.real_name - if(mutant_race != "human" && config.mutant_races) - character.dna.mutantrace = mutant_race + if(pref_species != /datum/species/human && config.mutant_races) + character.dna.species = new pref_species.type() + else + character.dna.species = new /datum/species/human() + character.dna.mutant_color = mutant_color + character.update_mutcolor() character.gender = gender character.age = age diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 1204bf5edee..93c33b755be 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -73,6 +73,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(11) underwear = "Ladies Kinky" if(12) underwear = "Tankini" if(13) underwear = "Nude" + if(!pref_species in species_list) + pref_species = new /datum/species/human() return /datum/preferences/proc/load_path(ckey,filename="preferences.sav") @@ -151,6 +153,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(needs_update == -2) //fatal, can't load any data return 0 + if(!S["species"] || !config.mutant_races) + S["species"] << new /datum/species/human() + //Character S["OOC_Notes"] >> metadata S["real_name"] >> real_name @@ -165,7 +170,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["facial_style_name"] >> facial_hair_style S["underwear"] >> underwear S["backbag"] >> backbag - S["mutant_race"] >> mutant_race + S["species"] >> pref_species + S["mutant_color"] >> mutant_color //Jobs S["userandomjob"] >> userandomjob @@ -186,6 +192,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Sanitize metadata = sanitize_text(metadata, initial(metadata)) real_name = reject_bad_name(real_name) + if(!pref_species in species_list) + pref_species = new /datum/species/human() + world << "[pref_species] is the species" if(!real_name) real_name = random_name(gender) be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) gender = sanitize_gender(gender) @@ -203,7 +212,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car eye_color = sanitize_hexcolor(eye_color, 3, 0) skin_tone = sanitize_inlist(skin_tone, skin_tones) backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag)) - mutant_race = sanitize_text(mutant_race, initial(mutant_race)) + mutant_color = sanitize_hexcolor(mutant_color, 3, 0) userandomjob = sanitize_integer(userandomjob, 0, 1, initial(userandomjob)) job_civilian_high = sanitize_integer(job_civilian_high, 0, 65535, initial(job_civilian_high)) @@ -240,7 +249,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["facial_style_name"] << facial_hair_style S["underwear"] << underwear S["backbag"] << backbag - S["mutant_race"] << mutant_race + S["species"] << pref_species + S["mutant_color"] << mutant_color //Jobs S["userandomjob"] << userandomjob diff --git a/code/modules/clothing/gloves/boxing.dm b/code/modules/clothing/gloves/boxing.dm index 0865c31e942..9467c63e34e 100644 --- a/code/modules/clothing/gloves/boxing.dm +++ b/code/modules/clothing/gloves/boxing.dm @@ -3,6 +3,7 @@ desc = "Because you really needed another excuse to punch your crewmates." icon_state = "boxing" item_state = "boxing" + species_exception = list(/datum/species/golem, /datum/species/golem/adamantine) // now you too can be a golem boxing champion /obj/item/clothing/gloves/boxing/green icon_state = "boxinggreen" diff --git a/code/modules/events/holiday/halloween.dm b/code/modules/events/holiday/halloween.dm index 67536e1dec7..9a7945d7719 100644 --- a/code/modules/events/holiday/halloween.dm +++ b/code/modules/events/holiday/halloween.dm @@ -9,9 +9,9 @@ /datum/round_event/spooky/start() for(var/mob/living/carbon/human/H in mob_list) if(H.dna) - hardset_dna(H, null, null, null, "skeleton") + hardset_dna(H, null, null, null, null, /datum/species/skeleton) for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list) Ian.place_on_head(new /obj/item/weapon/bedsheet(Ian)) /datum/round_event/spooky/announce() - priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE") \ No newline at end of file + priority_announce(pick("RATTLE ME BONES!","THE RIDE NEVER ENDS!", "A SKELETON POPS OUT!", "SPOOKY SCARY SKELETONS!", "CREWMEMBERS BEWARE, YOU'RE IN FOR A SCARE!") , "THE CALL IS COMING FROM INSIDE THE HOUSE") diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 80642e3957b..10f10353b41 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -909,7 +909,7 @@ obj/machinery/hydroponics/attackby(var/obj/item/O as obj, var/mob/user as mob) podman.gender = ghost.gender //dna stuff - hardset_dna(podman, ui, se, null, !prob(potency) ? "plant" : null) //makes sure podman has dna and sets the dna's ui/se/mutantrace/real_name etc variables + hardset_dna(podman, ui, se, null, null, null, !prob(potency) ? /datum/species/plant/pod : null, "#59CE00") //makes sure podman has dna and sets the dna's ui/se/mutantrace/real_name etc variables else //else, one packet of seeds. maybe two var/seed_count = 1 diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index ebe2a488d4f..b92d4c01cfd 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -94,7 +94,7 @@ if(shielded) damage /= 4 - show_message("\red The blob attacks!") + show_message("The blob attacks!") adjustFireLoss(damage) return @@ -120,9 +120,8 @@ return if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites [src]!"), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -137,10 +136,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) - + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) if(M.is_adult) @@ -167,9 +164,8 @@ if(M.powerlevel < 0) M.powerlevel = 0 - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] has shocked []!", src), 1) + visible_message("The [M.name] has shocked [src]!", \ + "The [M.name] has shocked [src]!") Weaken(power) if (stuttering < power) @@ -194,8 +190,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) updatehealth() @@ -229,9 +225,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if ("harm") var/damage = rand(1, 9) @@ -244,42 +238,35 @@ sleep(3) step_away(src,M,15) playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has punched []!", M, src), 1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") if ((stat != DEAD) && (damage > 9||prob(5)))//Regular humans have a very small chance of weakening an alien. Weaken(1,5) - for(var/mob/O in viewers(M, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has weakened []!", M, src), 1, "\red You hear someone fall.", 2) + visible_message("[M] has weakened [src]!", \ + "[M] has weakened [src]!", \ + "You hear someone fall.") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to punch []!", M, src), 1) + visible_message("[M] has attempted to punch [src]!") if ("disarm") if (!lying) if (prob(5))//Very small chance to push an alien down. Weaken(2) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has pushed down []!", M, src), 1) + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") else if (prob(50)) drop_item() playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has disarmed []!", M, src), 1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to disarm []!", M, src), 1) + visible_message("[M] has attempted to disarm [src]!") return /*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other. @@ -306,21 +293,19 @@ In all, this is a lot like the monkey code. /N AdjustParalysis(-3) AdjustStunned(-3) AdjustWeakened(-3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M.name] nuzzles [] trying to wake it up!", src), 1) + visible_message("[M.name] nuzzles [src] trying to wake it up!") else if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) var/damage = rand(1, 3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites []!", src), 1) + visible_message("[M.name] bites [src]!!", \ + "[M.name] bites [src]!!") + adjustBruteLoss(damage) updatehealth() else - M << "\green [name] is too injured for that." + M << "[name] is too injured for that." return diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 12b3713d6df..303f19e9b45 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -101,7 +101,7 @@ //paralysis += 1 - show_message("\red The blob attacks you!") + show_message("The blob attacks you!") adjustFireLoss(damage) @@ -117,8 +117,8 @@ if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) add_logs(M, src, "attacked", admin=0) @@ -146,9 +146,8 @@ return if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites [src]!"), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -163,9 +162,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -209,9 +207,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") else var/damage = rand(1, 9) @@ -224,21 +220,19 @@ sleep(3) step_away(src,M,15) playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has kicked []!", M, src), 1) + visible_message("[M] has kicked [src]!", \ + "[M] has kicked [src]!") if ((stat != DEAD) && (damage > 4.9)) Weaken(rand(5,10)) - for(var/mob/O in viewers(M, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has weakened []!", M, src), 1, "\red You hear someone fall.", 2) + visible_message("[M] has weakened [src]!", \ + "[M] has weakened [src]!", \ + "You hear someone fall.") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has attempted to kick []!", M, src), 1) + visible_message("[M] has attempted to kick [src]!", \ + "[M] has attempted to kick [src]!") return /mob/living/carbon/alien/larva/attack_alien(mob/living/carbon/alien/humanoid/M as mob) @@ -260,21 +254,18 @@ AdjustParalysis(-3) AdjustStunned(-3) AdjustWeakened(-3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M.name] nuzzles [] trying to wake it up!", src), 1) + visible_message("[M.name] nuzzles [src] trying to wake it up!") else if (health > 0) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) var/damage = rand(1, 3) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[M.name] bites []!", src), 1) + visible_message("[M.name] bites [src]!", \ + "[M.name] bites [src]!") adjustBruteLoss(damage) updatehealth() else - M << "\green [name] is too injured for that." + M << "[name] is too injured for that." return /mob/living/carbon/alien/larva/restrained() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5745bcea0e5..498fd4a2c5c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -205,7 +205,7 @@ src << "You're completely exhausted." else src << "You feel fatigued." - if(dna && (dna.mutantrace == "skeleton") && !H.w_uniform && !H.wear_suit) + if(dna && (dna.species == /datum/species/skeleton) && !H.w_uniform && !H.wear_suit) H.play_xylophone() else if(ishuman(src)) @@ -458,13 +458,6 @@ ..(message, bubble_type) -/mob/living/carbon/proc/is_mutantrace(var/mrace) - if(mrace) - if(src.dna && src.dna.mutantrace == mrace) - return 1 - else - return src.dna && src.dna.mutantrace ? 1 : 0 - /mob/living/carbon/getTrail() if(getBruteLoss() < 300) if(prob(50)) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 473707ff132..380d0de4cc3 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -8,7 +8,8 @@ ..() /mob/living/carbon/human/spawn_gibs() - hgibs(loc, viruses, dna) + if(dna) + hgibs(loc, viruses, dna) /mob/living/carbon/human/spawn_dust() new /obj/effect/decal/remains/human(loc) @@ -31,6 +32,9 @@ update_canmove() if(client) blind.layer = 0 + if(dna) + dna.species.spec_death(gibbed,src) + tod = worldtime2text() //weasellos time of death patch if(mind) mind.store_memory("Time of death: [tod]", 0) if(ticker && ticker.mode) @@ -40,11 +44,9 @@ return ..(gibbed) /mob/living/carbon/human/proc/makeSkeleton() - if(!check_dna_integrity(src) || (dna.mutantrace == "skeleton")) return - dna.mutantrace = "skeleton" + if(!check_dna_integrity(src)) return status_flags |= DISFIGURED - update_hair() - update_body() + dna.species = new /datum/species/skeleton(src) return 1 /mob/living/carbon/proc/ChangeToHusk() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 7030742e370..773c4bf2b23 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -51,12 +51,12 @@ for(var/mob/M in range(tmob, 1)) if( ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) ) if ( !(world.time % 5) ) - src << "\red [tmob] is restrained, you cannot push past" + src << "[tmob] is restrained, you cannot push past." now_pushing = 0 return if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) ) if ( !(world.time % 5) ) - src << "\red [tmob] is restraining [M], you cannot push past" + src << "[tmob] is restraining [M], you cannot push past." now_pushing = 0 return @@ -198,7 +198,7 @@ /mob/living/carbon/human/blob_act() if(stat == 2) return - show_message("\red The blob attacks you!") + show_message(" The blob attacks you!") var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") var/obj/item/organ/limb/affecting = get_organ(ran_zone(dam_zone)) apply_damage(rand(20,30), BRUTE, affecting, run_armor_check(affecting, "melee")) @@ -211,8 +211,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") @@ -227,9 +227,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -262,10 +261,8 @@ M.powerlevel -= 3 if(M.powerlevel < 0) M.powerlevel = 0 - - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red The [M.name] has shocked []!", src), 1) + visible_message("The [M.name] has shocked [src]!", \ + "The [M.name] has shocked [src]!") Weaken(power) if (stuttering < power) @@ -344,7 +341,7 @@ dat += "
Uniform: Obscured by [wear_suit]" else dat += "
Uniform: [(w_uniform && !(w_uniform.flags&ABSTRACT)) ? w_uniform : "Empty"]" - if(w_uniform) + if(w_uniform || dna.species.nojumpsuit) dat += "
[TAB]↳Belt: [(belt && !(belt.flags&ABSTRACT)) ? belt : "Empty"]" if(has_breathable_mask && istype(belt, /obj/item/weapon/tank)) dat += "
[TAB][TAB]↳[internal ? "Disable Internals" : "Set Internals"]" @@ -352,12 +349,31 @@ dat += " [(r_store && !(r_store.flags&ABSTRACT)) ? "Right (Full)" : "Right (Empty)"]" dat += "
[TAB]↳ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Empty"]" + if(dna) + if(dna.species.nojumpsuit) + dat += "
ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Nothing"]" + else if(w_uniform) + dat += "
ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Nothing"]" + else if(w_uniform) + dat += "
ID: [(wear_id && !(wear_id.flags&ABSTRACT)) ? wear_id : "Nothing"]" + dat += "
" if(handcuffed) dat += "
Handcuffed: Remove" if(legcuffed) - dat += "
Legcuffed: Remove" + dat += "
Legcuffed" + + if(dna) + if(dna.species.nojumpsuit) + dat += "

Left Pocket ([(l_store && !(l_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + dat += " - Right Pocket ([(r_store && !(r_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + else if(w_uniform) + dat += "

Left Pocket ([(l_store && !(l_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + dat += " - Right Pocket ([(r_store && !(r_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + else if(w_uniform) + dat += "

Left Pocket ([(l_store && !(l_store.flags&ABSTRACT)) ? "Full" : "Empty"])" + dat += " - Right Pocket ([(r_store && !(r_store.flags&ABSTRACT)) ? "Full" : "Empty"])" dat += {"
@@ -467,7 +483,7 @@ H.handle_regular_hud_updates() if(!modified) - usr << "\red Unable to locate a data core entry for this person." + usr << "Unable to locate a data core entry for this person." /mob/living/carbon/human/proc/play_xylophone() if(!src.xylophone) @@ -516,4 +532,4 @@ if(obscured.len > 0) return obscured else - return null + return null diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 0d1ef146670..d703a7ab610 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -2,163 +2,9 @@ if(..()) //to allow surgery to return properly. return - if((M != src) && check_shields(0, M.name)) - add_logs(M, src, "attempted to touch") - visible_message("[M] attempted to touch [src]!") - return 0 + if(dna) + dna.species.spec_attack_hand(M, src) - switch(M.a_intent) - if("help") - if(health >= 0) - help_shake_act(M) - if(src != M) - add_logs(M, src, "shaked") - return 1 - - //CPR - if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH))) - M << "Remove your mask!" - return 0 - if((head && (head.flags & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags & MASKCOVERSMOUTH))) - M << "Remove their mask!" - return 0 - - if(cpr_time < world.time + 30) - add_logs(src, M, "CPRed") - visible_message("[M] is trying to perform CPR on [src]!") - if(!do_mob(M, src)) - return 0 - if((health >= -99 && health <= 0)) - cpr_time = world.time - var/suff = min(getOxyLoss(), 7) - adjustOxyLoss(-suff) - updatehealth() - M.visible_message("[M] performs CPR on [src]!") - src << "You feel a breath of fresh air enter your lungs. It feels good." - - if("grab") - if(M == src || anchored) - return 0 - - add_logs(M, src, "grabbed", addition="passively") - - if(w_uniform) - w_uniform.add_fingerprint(M) - - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src) - if(buckled) - M << "You cannot grab [src], \he is buckled in!" - if(!G) //the grab will delete itself in New if affecting is anchored - return - M.put_in_active_hand(G) - G.synch() - LAssailant = M - - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message("[M] has grabbed [src] passively!") - return 1 - - if("harm") - add_logs(M, src, "punched") - - var/attack_verb = "punch" - if(lying) - attack_verb = "kick" - else if(M.dna) - switch(M.dna.mutantrace) - if("lizard") - attack_verb = "scratch" - if("plant") - attack_verb = "slash" - - var/damage = rand(0, 9) - if(!damage) - switch(attack_verb) - if("slash") - playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - - visible_message("[M] has attempted to [attack_verb] [src]!") - return 0 - - - var/obj/item/organ/limb/affecting = get_organ(ran_zone(M.zone_sel.selecting)) - var/armor_block = run_armor_check(affecting, "melee") - - if(HULK in M.mutations) - damage += 5 - - switch(attack_verb) - if("slash") - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - else - playsound(loc, "punch", 25, 1, -1) - - visible_message("[M] has [attack_verb]ed [src]!", \ - "[M] has [attack_verb]ed [src]!") - - apply_damage(damage, BRUTE, affecting, armor_block) - if((stat != DEAD) && damage >= 9) - visible_message("[M] has weakened [src]!", \ - "[M] has weakened [src]!") - apply_effect(4, WEAKEN, armor_block) - forcesay(hit_appends) - else if(lying) - forcesay(hit_appends) - - if("disarm") - add_logs(M, src, "disarmed") - - if(w_uniform) - w_uniform.add_fingerprint(M) - var/obj/item/organ/limb/affecting = get_organ(ran_zone(M.zone_sel.selecting)) - var/randn = rand(1, 100) - if(randn <= 25) - apply_effect(2, WEAKEN, run_armor_check(affecting, "melee")) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message("[M] has pushed [src]!", - "[M] has pushed [src]!") - forcesay(hit_appends) - return - - var/talked = 0 // BubbleWrap - - if(randn <= 60) - //BubbleWrap: Disarming breaks a pull - if(pulling) - visible_message("[M] has broken [src]'s grip on [pulling]!") - talked = 1 - stop_pulling() - - //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it? - if(istype(l_hand, /obj/item/weapon/grab)) - var/obj/item/weapon/grab/lgrab = l_hand - if(lgrab.affecting) - visible_message("[M] has broken [src]'s grip on [lgrab.affecting]!") - talked = 1 - spawn(1) - qdel(lgrab) - if(istype(r_hand, /obj/item/weapon/grab)) - var/obj/item/weapon/grab/rgrab = r_hand - if(rgrab.affecting) - visible_message("[M] has broken [src]'s grip on [rgrab.affecting]!") - talked = 1 - spawn(1) - qdel(rgrab) - //End BubbleWrap - - if(!talked) //BubbleWrap - if(drop_item()) - visible_message("[M] has disarmed [src]!", \ - "[M] has disarmed [src]!") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - return - - - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] attempted to disarm [src]!", \ - "[M] attemped to disarm [src]!") return /mob/living/carbon/human/proc/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, inrange, params) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index c1c1e7240f1..633e72059db 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -102,6 +102,7 @@ mob/living/carbon/human/proc/hat_fall_prob() var/obj/item/organ/limb/picked = pick(parts) if(picked.take_damage(brute,burn)) update_damage_overlays(0) + updatehealth() @@ -128,6 +129,7 @@ mob/living/carbon/human/proc/hat_fall_prob() // damage MANY external organs, in random order /mob/living/carbon/human/take_overall_damage(var/brute, var/burn) if(status_flags & GODMODE) return //godmode + var/list/obj/item/organ/limb/parts = get_damageable_organs() var/update = 0 while(parts.len && (brute>0 || burn>0) ) @@ -143,7 +145,9 @@ mob/living/carbon/human/proc/hat_fall_prob() burn -= (picked.burn_dam - burn_was) parts -= picked + updatehealth() + if(update) update_damage_overlays(0) @@ -159,34 +163,38 @@ mob/living/carbon/human/proc/hat_fall_prob() /mob/living/carbon/human/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0) - if((damagetype != BRUTE) && (damagetype != BURN)) - ..(damage, damagetype, def_zone, blocked) - return 1 - - blocked = (100-blocked)/100 - if(blocked <= 0) return 0 - - var/obj/item/organ/limb/organ = null - if(isorgan(def_zone)) - organ = def_zone + if(dna) // if you have a species, it will run the apply_damage code there instead + dna.species.apply_damage(damage, damagetype, def_zone, blocked, src) else - if(!def_zone) def_zone = ran_zone(def_zone) - organ = get_organ(check_zone(def_zone)) - if(!organ) return 0 + if((damagetype != BRUTE) && (damagetype != BURN)) + ..(damage, damagetype, def_zone, blocked) + return 1 - damage = (damage * blocked) + else + blocked = (100-blocked)/100 + if(blocked <= 0) return 0 - switch(damagetype) - if(BRUTE) - damageoverlaytemp = 20 - if(organ.take_damage(damage, 0)) - update_damage_overlays(0) - if(BURN) - damageoverlaytemp = 20 - if(organ.take_damage(0, damage)) - update_damage_overlays(0) + var/obj/item/organ/limb/organ = null + if(isorgan(def_zone)) + organ = def_zone + else + if(!def_zone) def_zone = ran_zone(def_zone) + organ = get_organ(check_zone(def_zone)) + if(!organ) return 0 - // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). + damage = (damage * blocked) - updatehealth() + switch(damagetype) + if(BRUTE) + damageoverlaytemp = 20 + if(organ.take_damage(damage, 0)) + update_damage_overlays(0) + if(BURN) + damageoverlaytemp = 20 + if(organ.take_damage(0, damage)) + update_damage_overlays(0) + + // Will set our damageoverlay icon to the next level, which will then be set back to the normal level the next mob.Life(). + + updatehealth() return 1 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 76ef3e5583d..4048c7e762c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -36,6 +36,11 @@ emp_act protection += C.armor[type] return protection +/mob/living/carbon/human/on_hit(proj_type) + if(dna) + dna.species.on_hit(proj_type, src) + return + /mob/living/carbon/human/bullet_act(var/obj/item/projectile/P, var/def_zone) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) if(check_reflect(def_zone)) // Checks if you've passed a reflection% check @@ -118,94 +123,93 @@ emp_act /mob/living/carbon/human/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone) if(!I || !user) return 0 + var/obj/item/organ/limb/target_limb = get_organ(user.zone_sel.selecting) var/obj/item/organ/limb/affecting = get_organ(ran_zone(user.zone_sel.selecting)) - var/hit_area = parse_zone(affecting.name) + var/target_area = parse_zone(target_limb.name) - if((user != src) && check_shields(I.force, "the [I.name]")) - return 0 + if(dna) // allows your species to affect the attacked_by code + return dna.species.spec_attacked_by(I,user,def_zone,affecting,hit_area,src.a_intent,target_limb,target_area,src) - if(I.attack_verb && I.attack_verb.len) - visible_message("[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!", \ - "[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!") - else if(I.force) - visible_message("[src] has been attacked in the [hit_area] with [I] by [user]!", \ - "[src] has been attacked in the [hit_area] with [I] by [user]!") else - return 0 + if((user != src) && check_shields(I.force, "the [I.name]")) + return 0 - var/armor = run_armor_check(affecting, "melee", "Your armour has protected your [hit_area].", "Your armour has softened a hit to your [hit_area].") - if(armor >= 100) return 0 - var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) + if(I.attack_verb && I.attack_verb.len) + visible_message("[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!", \ + "[src] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!") + else if(I.force) + visible_message("[src] has been attacked in the [hit_area] with [I] by [user]!", \ + "[src] has been attacked in the [hit_area] with [I] by [user]!") + else + return 0 - apply_damage(I.force, I.damtype, affecting, armor , I) + var/armor = run_armor_check(affecting, "melee", "Your armour has protected your [hit_area].", "Your armour has softened a hit to your [hit_area].") + if(armor >= 100) return 0 + var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) - var/bloody = 0 - if(((I.damtype == BRUTE) && prob(25 + (I.force * 2)))) - if(affecting.status == ORGAN_ORGANIC) - I.add_blood(src) //Make the weapon bloody, not the person. - if(prob(I.force * 2)) //blood spatter! - bloody = 1 - var/turf/location = loc - if(istype(location, /turf/simulated)) - location.add_blood(src) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood - if(H.wear_suit) - H.wear_suit.add_blood(src) - H.update_inv_wear_suit(0) //updates mob overlays to show the new blood (no refresh) - else if(H.w_uniform) - H.w_uniform.add_blood(src) - H.update_inv_w_uniform(0) //updates mob overlays to show the new blood (no refresh) - if (H.gloves) - var/obj/item/clothing/gloves/G = H.gloves - G.add_blood(H) - else - H.add_blood(H) - H.update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves + apply_damage(I.force, I.damtype, affecting, armor , I) + var/bloody = 0 + if(((I.damtype == BRUTE) && prob(25 + (I.force * 2)))) + if(affecting.status == ORGAN_ORGANIC) + I.add_blood(src) //Make the weapon bloody, not the person. + if(prob(I.force * 2)) //blood spatter! + bloody = 1 + var/turf/location = loc + if(istype(location, /turf/simulated)) + location.add_blood(src) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(get_dist(H, src) <= 1) //people with TK won't get smeared with blood + if(H.wear_suit) + H.wear_suit.add_blood(src) + H.update_inv_wear_suit(0) //updates mob overlays to show the new blood (no refresh) + else if(H.w_uniform) + H.w_uniform.add_blood(src) + H.update_inv_w_uniform(0) //updates mob overlays to show the new blood (no refresh) + if (H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + G.add_blood(H) + else + H.add_blood(H) + H.update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves - switch(hit_area) - if("head") //Harder to score a stun but if you do it lasts a bit longer - if(stat == CONSCIOUS && prob(I.force)) - if(Iforce >= 5) + switch(hit_area) + if("head") //Harder to score a stun but if you do it lasts a bit longer + if(stat == CONSCIOUS && prob(I.force)) visible_message("[src] has been knocked unconscious!", \ "[src] has been knocked unconscious!") apply_effect(20, PARALYZE, armor) if(src != user && I.damtype == BRUTE) ticker.mode.remove_revolutionary(mind) + if(bloody) //Apply blood + if(wear_mask) + wear_mask.add_blood(src) + update_inv_wear_mask(0) + if(head) + head.add_blood(src) + update_inv_head(0) + if(glasses && prob(33)) + glasses.add_blood(src) + update_inv_glasses(0) - if(bloody) //Apply blood - if(wear_mask) - wear_mask.add_blood(src) - update_inv_wear_mask(0) - if(head) - head.add_blood(src) - update_inv_head(0) - if(glasses && prob(33)) - glasses.add_blood(src) - update_inv_glasses(0) - - if("chest") //Easier to score a stun but lasts less time - if(stat == CONSCIOUS && prob(I.force + 10)) - if(Iforce >= 5) + if("chest") //Easier to score a stun but lasts less time + if(stat == CONSCIOUS && prob(I.force + 10)) visible_message("[src] has been knocked down!", \ "[src] has been knocked down!") apply_effect(5, WEAKEN, armor) - if(bloody) - if(wear_suit) - wear_suit.add_blood(src) - update_inv_wear_suit(0) - if(w_uniform) - w_uniform.add_blood(src) - update_inv_w_uniform(0) - - if(Iforce > 10 || Iforce >= 5 && prob(33)) - forcesay(hit_appends) //forcesay checks stat already. - + if(bloody) + if(wear_suit) + wear_suit.add_blood(src) + update_inv_wear_suit(0) + if(w_uniform) + w_uniform.add_blood(src) + update_inv_w_uniform(0) + if(Iforce > 10 || Iforce >= 5 && prob(33)) + forcesay(hit_appends) //forcesay checks stat already /mob/living/carbon/human/emp_act(severity) var/informed = 0 diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index ba27693b4c6..3fffa8a5958 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -34,7 +34,7 @@ var/obj/item/l_store = null var/obj/item/s_store = null - var/base_icon_state = "caucasian1_m" + var/icon/base_icon_state = "caucasian1_m" var/list/organs = list() //Gets filled up in the constructor (human.dm, New() proc, line 24. I'm sick and tired of missing comments. -Agouri diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 6b59a125648..3af3219a129 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -119,4 +119,11 @@ return 1//Humans can use guns and such /mob/living/carbon/human/InCritical() - return (health <= config.health_threshold_crit && stat == UNCONSCIOUS) \ No newline at end of file + return (health <= config.health_threshold_crit && stat == UNCONSCIOUS) + +/mob/living/carbon/human/reagent_check(datum/reagent/R) + if(dna) + var/bypass = dna.species.handle_chemicals(R,src) + return bypass // if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species. + else + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 905c9adaf4d..438fb8c650b 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -1,29 +1,6 @@ /mob/living/carbon/human/movement_delay() - if(!has_gravity(src)) - return -1 //It's hard to be slowed down in space by... anything - else if(status_flags & GOTTAGOFAST) - return -1 - - . = 0 - var/health_deficiency = (100 - health + staminaloss) - if(health_deficiency >= 40) - . += (health_deficiency / 25) - - var/hungry = (500 - nutrition) / 5 //So overeat would be 100 and default level would be 80 - if(hungry >= 70) - . += hungry / 50 - - if(wear_suit) - . += wear_suit.slowdown - if(shoes) - . += shoes.slowdown - if(back) - . += back.slowdown - - if(FAT in mutations) - . += 1.5 - if(bodytemperature < 283.222) - . += (283.222 - bodytemperature) / 10 * 1.75 + if(dna) + . += dna.species.movement_delay(src) . += ..() . += config.human_delay diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index ac1cddac276..9e99030ba8d 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -1,153 +1,156 @@ /mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = 0) - switch(slot) - if(slot_l_hand) - if(l_hand) - return 0 - return 1 - if(slot_r_hand) - if(r_hand) - return 0 - return 1 - if(slot_wear_mask) - if(wear_mask) - return 0 - if( !(I.slot_flags & SLOT_MASK) ) - return 0 - return 1 - if(slot_back) - if(back) - return 0 - if( !(I.slot_flags & SLOT_BACK) ) - return 0 - return 1 - if(slot_wear_suit) - if(wear_suit) - return 0 - if( !(I.slot_flags & SLOT_OCLOTHING) ) - return 0 - return 1 - if(slot_gloves) - if(gloves) - return 0 - if( !(I.slot_flags & SLOT_GLOVES) ) - return 0 - return 1 - if(slot_shoes) - if(shoes) - return 0 - if( !(I.slot_flags & SLOT_FEET) ) - return 0 - return 1 - if(slot_belt) - if(belt) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if( !(I.slot_flags & SLOT_BELT) ) - return - return 1 - if(slot_glasses) - if(glasses) - return 0 - if( !(I.slot_flags & SLOT_EYES) ) - return 0 - return 1 - if(slot_head) - if(head) - return 0 - if( !(I.slot_flags & SLOT_HEAD) ) - return 0 - return 1 - if(slot_ears) - if(ears) - return 0 - if( !(I.slot_flags & SLOT_EARS) ) - return 0 - return 1 - if(slot_w_uniform) - if(w_uniform) - return 0 - if( !(I.slot_flags & SLOT_ICLOTHING) ) - return 0 - return 1 - if(slot_wear_id) - if(wear_id) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if( !(I.slot_flags & SLOT_ID) ) - return 0 - return 1 - if(slot_l_store) - if(I.flags & NODROP) //Pockets aren't visible, so you can't move NODROP items into them. - return 0 - if(l_store) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if(I.slot_flags & SLOT_DENYPOCKET) - return - if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + if(dna) + return dna.species.can_equip(I, slot, disable_warning, src) + else + switch(slot) + if(slot_l_hand) + if(l_hand) + return 0 return 1 - if(slot_r_store) - if(I.flags & NODROP) - return 0 - if(r_store) - return 0 - if(!w_uniform) - if(!disable_warning) - src << "\red You need a jumpsuit before you can attach this [I.name]." - return 0 - if(I.slot_flags & SLOT_DENYPOCKET) - return 0 - if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + if(slot_r_hand) + if(r_hand) + return 0 return 1 - return 0 - if(slot_s_store) - if(I.flags & NODROP) //Suit storage NODROP items drop if you take a suit off, this is to prevent people exploiting this. - return 0 - if(s_store) - return 0 - if(!wear_suit) - if(!disable_warning) - src << "\red You need a suit before you can attach this [I.name]." - return 0 - if(!wear_suit.allowed) - if(!disable_warning) - usr << "You somehow have a suit with no defined allowed items for suit storage, stop that." //should be src? - return 0 - if(I.w_class > 4) - if(!disable_warning) - usr << "The [I.name] is too big to attach." //should be src? - return 0 - if( istype(I, /obj/item/device/pda) || istype(I, /obj/item/weapon/pen) || is_type_in_list(I, wear_suit.allowed) ) //ugly and un-polymorphic. + if(slot_wear_mask) + if(wear_mask) + return 0 + if( !(I.slot_flags & SLOT_MASK) ) + return 0 return 1 - return 0 - if(slot_handcuffed) - if(handcuffed) - return 0 - if(!istype(I, /obj/item/weapon/handcuffs)) - return 0 - return 1 - if(slot_legcuffed) - if(legcuffed) - return 0 - if(!istype(I, /obj/item/weapon/legcuffs)) - return 0 - return 1 - if(slot_in_backpack) - if (back && istype(back, /obj/item/weapon/storage/backpack)) - var/obj/item/weapon/storage/backpack/B = back - if(B.contents.len < B.storage_slots && I.w_class <= B.max_w_class) + if(slot_back) + if(back) + return 0 + if( !(I.slot_flags & SLOT_BACK) ) + return 0 + return 1 + if(slot_wear_suit) + if(wear_suit) + return 0 + if( !(I.slot_flags & SLOT_OCLOTHING) ) + return 0 + return 1 + if(slot_gloves) + if(gloves) + return 0 + if( !(I.slot_flags & SLOT_GLOVES) ) + return 0 + return 1 + if(slot_shoes) + if(shoes) + return 0 + if( !(I.slot_flags & SLOT_FEET) ) + return 0 + return 1 + if(slot_belt) + if(belt) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_BELT) ) + return + return 1 + if(slot_glasses) + if(glasses) + return 0 + if( !(I.slot_flags & SLOT_EYES) ) + return 0 + return 1 + if(slot_head) + if(head) + return 0 + if( !(I.slot_flags & SLOT_HEAD) ) + return 0 + return 1 + if(slot_ears) + if(ears) + return 0 + if( !(I.slot_flags & SLOT_EARS) ) + return 0 + return 1 + if(slot_w_uniform) + if(w_uniform) + return 0 + if( !(I.slot_flags & SLOT_ICLOTHING) ) + return 0 + return 1 + if(slot_wear_id) + if(wear_id) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_ID) ) + return 0 + return 1 + if(slot_l_store) + if(I.flags & NODROP) //Pockets aren't visible, so you can't move NODROP items into them. + return 0 + if(l_store) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) return 1 - return 0 - return 0 //Unsupported slot + if(slot_r_store) + if(I.flags & NODROP) + return 0 + if(r_store) + return 0 + if(!w_uniform) + if(!disable_warning) + src << "\red You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return 0 + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + return 1 + return 0 + if(slot_s_store) + if(I.flags & NODROP) //Suit storage NODROP items drop if you take a suit off, this is to prevent people exploiting this. + return 0 + if(s_store) + return 0 + if(!wear_suit) + if(!disable_warning) + src << "\red You need a suit before you can attach this [I.name]." + return 0 + if(!wear_suit.allowed) + if(!disable_warning) + usr << "You somehow have a suit with no defined allowed items for suit storage, stop that." //should be src? + return 0 + if(I.w_class > 4) + if(!disable_warning) + usr << "The [I.name] is too big to attach." //should be src? + return 0 + if( istype(I, /obj/item/device/pda) || istype(I, /obj/item/weapon/pen) || is_type_in_list(I, wear_suit.allowed) ) //ugly and un-polymorphic. + return 1 + return 0 + if(slot_handcuffed) + if(handcuffed) + return 0 + if(!istype(I, /obj/item/weapon/handcuffs)) + return 0 + return 1 + if(slot_legcuffed) + if(legcuffed) + return 0 + if(!istype(I, /obj/item/weapon/legcuffs)) + return 0 + return 1 + if(slot_in_backpack) + if (back && istype(back, /obj/item/weapon/storage/backpack)) + var/obj/item/weapon/storage/backpack/B = back + if(B.contents.len < B.storage_slots && I.w_class <= B.max_w_class) + return 1 + return 0 + return 0 //Unsupported slot @@ -383,5 +386,4 @@ return else src << "\red You are trying to equip this item to an unsupported inventory slot. Report this to a coder!" - return - + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 341bc28445e..65d0d00b9b0 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1,6 +1,11 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 //NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! + + +#define TINT_IMPAIR 2 //Threshold of tint level to apply weld mask overlay +#define TINT_BLIND 3 //Threshold of tint level to obscure vision fully + #define HUMAN_MAX_OXYLOSS 3 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it. #define HUMAN_CRIT_MAX_OXYLOSS ( (last_tick_duration) /3) //The amount of damage you'll get when in critical condition. We want this to be a 5 minute deal = 300s. There are 100HP to get through, so (1/3)*last_tick_duration per second. Breaths however only happen every 4 ticks. @@ -21,9 +26,6 @@ #define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point #define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point -#define TINT_IMPAIR 2 //Threshold of tint level to apply weld mask overlay -#define TINT_BLIND 3 //Threshold of tint level to obscure vision fully - /mob/living/carbon/human var/oxygen_alert = 0 var/toxins_alert = 0 @@ -51,7 +53,6 @@ fire_alert = 0 //Reset this here, because both breathe() and handle_environment() have a chance to set it. tinttotal = tintcheck() //here as both hud updates and status updates call it - //TODO: seperate this out var/datum/gas_mixture/environment = loc.return_air() @@ -98,6 +99,9 @@ handle_regular_hud_updates() + if(dna) + dna.species.spec_life(src) // for mutantraces + // Grabbing for(var/obj/item/weapon/grab/G in src) G.process() @@ -163,132 +167,14 @@ proc/handle_mutations_and_radiation() - if(getFireLoss()) - if((COLD_RESISTANCE in mutations) || (prob(1))) - heal_organ_damage(0,1) - - if ((HULK in mutations) && health <= 25) - mutations.Remove(HULK) - update_mutations() //update our mutation overlays - src << "\red You suddenly feel very weak." - Weaken(3) - emote("collapse") - - if (radiation) - if (radiation > 100) - radiation = 100 - Weaken(10) - src << "\red You feel weak." - emote("collapse") - - if (radiation < 0) - radiation = 0 - - else - switch(radiation) - if(1 to 49) - radiation-- - if(prob(25)) - adjustToxLoss(1) - updatehealth() - - if(50 to 74) - radiation -= 2 - adjustToxLoss(1) - if(prob(5)) - radiation -= 5 - Weaken(3) - src << "\red You feel weak." - emote("collapse") - if(prob(15)) - if(!( hair_style == "Shaved") || !(hair_style == "Bald")) - src << "Your hair starts to fall out in clumps..." - spawn(50) - facial_hair_style = "Shaved" - hair_style = "Bald" - update_hair() - updatehealth() - - if(75 to 100) - radiation -= 3 - adjustToxLoss(3) - if(prob(1)) - src << "\red You mutate!" - randmutb(src) - domutcheck(src,null) - emote("gasp") - updatehealth() - + if(dna) + dna.species.handle_mutations_and_radiation(src) proc/breathe() + if(dna) + dna.species.breathe(src) - if(reagents.has_reagent("lexorin")) return - if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) return - - var/datum/gas_mixture/environment = loc.return_air() - var/datum/gas_mixture/breath - // HACK NEED CHANGING LATER - if(health <= config.health_threshold_crit) - losebreath++ - - if(losebreath>0) //Suffocating so do not take a breath - losebreath-- - if (prob(10)) //Gasp per 10 ticks? Sounds about right. - spawn emote("gasp") - if(istype(loc, /obj/)) - var/obj/location_as_object = loc - location_as_object.handle_internal_lifeform(src, 0) - else - //First, check for air from internal atmosphere (using an air tank and mask generally) - breath = get_breath_from_internal(BREATH_VOLUME) // Super hacky -- TLE - //breath = get_breath_from_internal(0.5) // Manually setting to old BREATH_VOLUME amount -- TLE - - //No breath from internal atmosphere so get breath from location - if(!breath) - if(isobj(loc)) - var/obj/location_as_object = loc - breath = location_as_object.handle_internal_lifeform(src, BREATH_VOLUME) - else if(isturf(loc)) - var/breath_moles = 0 - /*if(environment.return_pressure() > ONE_ATMOSPHERE) - // Loads of air around (pressure effect will be handled elsewhere), so lets just take a enough to fill our lungs at normal atmos pressure (using n = Pv/RT) - breath_moles = (ONE_ATMOSPHERE*BREATH_VOLUME/R_IDEAL_GAS_EQUATION*environment.temperature) - else*/ - // Not enough air around, take a percentage of what's there to model this properly - breath_moles = environment.total_moles()*BREATH_PERCENTAGE - - breath = loc.remove_air(breath_moles) - // Handle chem smoke effect -- Doohl - var/block = 0 - if(wear_mask) - if(wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT) - block = 1 - if(glasses) - if(glasses.flags & BLOCK_GAS_SMOKE_EFFECT) - block = 1 - if(head) - if(head.flags & BLOCK_GAS_SMOKE_EFFECT) - block = 1 - - if(!block) - - for(var/obj/effect/effect/chem_smoke/smoke in view(1, src)) - if(smoke.reagents.total_volume) - smoke.reagents.reaction(src, INGEST) - spawn(5) - if(smoke) - smoke.reagents.copy_to(src, 10) // I dunno, maybe the reagents enter the blood stream through the lungs? - break // If they breathe in the nasty stuff once, no need to continue checking - - else //Still give containing object the chance to interact - if(istype(loc, /obj/)) - var/obj/location_as_object = loc - location_as_object.handle_internal_lifeform(src, 0) - - handle_breath(breath) - - if(breath) - loc.assume_air(breath) + return proc/get_breath_from_internal(volume_needed) @@ -304,229 +190,45 @@ return null - proc/handle_breath(datum/gas_mixture/breath) + /*proc/handle_breath(datum/gas_mixture/breath) if((status_flags & GODMODE)) return - if(!breath || (breath.total_moles() == 0) || suiciding) - if(reagents.has_reagent("inaprovaline")) - return - if(suiciding) - adjustOxyLoss(2)//If you are suiciding, you should die a little bit faster - failed_last_breath = 1 - oxygen_alert = max(oxygen_alert, 1) - return 0 - if(health >= config.health_threshold_crit) - adjustOxyLoss(HUMAN_MAX_OXYLOSS) - failed_last_breath = 1 - else - adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) - failed_last_breath = 1 + if(dna) + dna.species.handle_breath(breath) - oxygen_alert = max(oxygen_alert, 1) - - return 0 - - var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa - //var/safe_oxygen_max = 140 // Maximum safe partial pressure of O2, in kPa (Not used for now) - var/safe_co2_max = 10 // Yes it's an arbitrary value who cares? - var/safe_toxins_max = 0.005 - var/SA_para_min = 1 - var/SA_sleep_min = 5 - var/oxygen_used = 0 - var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME - - //Partial pressure of the O2 in our breath - var/O2_pp = (breath.oxygen/breath.total_moles())*breath_pressure - // Same, but for the toxins - var/Toxins_pp = (breath.toxins/breath.total_moles())*breath_pressure - // And CO2, lets say a PP of more than 10 will be bad (It's a little less really, but eh, being passed out all round aint no fun) - var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*breath_pressure // Tweaking to fit the hacky bullshit I've done with atmo -- TLE - //var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*0.5 // The default pressure value - - if(O2_pp < safe_oxygen_min) // Too little oxygen - if(prob(20)) - spawn(0) emote("gasp") - if(O2_pp > 0) - var/ratio = safe_oxygen_min/O2_pp - adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!) - failed_last_breath = 1 - oxygen_used = breath.oxygen*ratio/6 - else - adjustOxyLoss(HUMAN_MAX_OXYLOSS) - failed_last_breath = 1 - oxygen_alert = max(oxygen_alert, 1) - /*else if (O2_pp > safe_oxygen_max) // Too much oxygen (commented this out for now, I'll deal with pressure damage elsewhere I suppose) - spawn(0) emote("cough") - var/ratio = O2_pp/safe_oxygen_max - oxyloss += 5*ratio - oxygen_used = breath.oxygen*ratio/6 - oxygen_alert = max(oxygen_alert, 1)*/ - else // We're in safe limits - failed_last_breath = 0 - adjustOxyLoss(-5) - oxygen_used = breath.oxygen/6 - oxygen_alert = 0 - - breath.oxygen -= oxygen_used - breath.carbon_dioxide += oxygen_used - - //CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick. - if(CO2_pp > safe_co2_max) - if(!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. - co2overloadtime = world.time - else if(world.time - co2overloadtime > 120) - Paralyse(3) - adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business - if(world.time - co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good! - adjustOxyLoss(8) - if(prob(20)) // Lets give them some chance to know somethings not right though I guess. - spawn(0) emote("cough") - - else - co2overloadtime = 0 - - if(Toxins_pp > safe_toxins_max) // Too much toxins - var/ratio = (breath.toxins/safe_toxins_max) * 10 - //adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) //Limit amount of damage toxin exposure can do per second - if(reagents) - reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) - toxins_alert = max(toxins_alert, 1) - else - toxins_alert = 0 - - 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 > SA_para_min) // Enough to make us paralysed for a bit - Paralyse(3) // 3 gives them one second to wake up and run away a bit! - if(SA_pp > SA_sleep_min) // Enough to make us sleep as well - sleeping = max(sleeping+2, 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) emote(pick("giggle", "laugh")) - - if( (abs(310.15 - breath.temperature) > 50) && !(COLD_RESISTANCE in mutations)) // Hot air hurts :( - if(breath.temperature < 260.15) - if(prob(20)) - src << "\red You feel your face freezing and an icicle forming in your lungs!" - else if(breath.temperature > 360.15) - if(prob(20)) - src << "\red You feel your face burning and a searing heat in your lungs!" - - switch(breath.temperature) - if(-INFINITY to 120) - apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head") - fire_alert = max(fire_alert, 1) - if(120 to 200) - apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head") - fire_alert = max(fire_alert, 1) - if(200 to 260) - apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head") - fire_alert = max(fire_alert, 1) - if(360 to 400) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head") - fire_alert = max(fire_alert, 2) - if(400 to 1000) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head") - fire_alert = max(fire_alert, 2) - if(1000 to INFINITY) - apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head") - fire_alert = max(fire_alert, 2) - - //Temporary fixes to the alerts. - - return 1 + return 1*/ proc/handle_environment(datum/gas_mixture/environment) - if(!environment) - return - - var/loc_temp = get_temperature(environment) - //world << "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Thermal protection: [get_thermal_protection()] - Fire protection: [thermal_protection + add_fire_protection(loc_temp)] - Heat capacity: [environment_heat_capacity] - Location: [loc] - src: [src]" - - //Body temperature is adjusted in two steps. Firstly your body tries to stabilize itself a bit. - if(stat != 2) - stabilize_temperature_from_calories() - - //After then, it reacts to the surrounding atmosphere based on your thermal protection - if(!on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases - if(loc_temp < bodytemperature) - //Place is colder than we are - var/thermal_protection = get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. - if(thermal_protection < 1) - bodytemperature += min((1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_COLD_DIVISOR), BODYTEMP_COOLING_MAX) - else - //Place is hotter than we are - var/thermal_protection = get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. - if(thermal_protection < 1) - bodytemperature += min((1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR), BODYTEMP_HEATING_MAX) - - // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. - if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT) - //Body temperature is too hot. - fire_alert = max(fire_alert, 1) - switch(bodytemperature) - if(360 to 400) - apply_damage(HEAT_DAMAGE_LEVEL_1, BURN) - fire_alert = max(fire_alert, 2) - if(400 to 460) - apply_damage(HEAT_DAMAGE_LEVEL_2, BURN) - fire_alert = max(fire_alert, 2) - if(460 to INFINITY) - if(on_fire) - apply_damage(HEAT_DAMAGE_LEVEL_3, BURN) - fire_alert = max(fire_alert, 2) - else - apply_damage(HEAT_DAMAGE_LEVEL_2, BURN) - fire_alert = max(fire_alert, 2) - - else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) - fire_alert = max(fire_alert, 1) - if(!istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) - switch(bodytemperature) - if(200 to 260) - apply_damage(COLD_DAMAGE_LEVEL_1, BURN) - fire_alert = max(fire_alert, 1) - if(120 to 200) - apply_damage(COLD_DAMAGE_LEVEL_2, BURN) - fire_alert = max(fire_alert, 1) - if(-INFINITY to 120) - apply_damage(COLD_DAMAGE_LEVEL_3, BURN) - fire_alert = max(fire_alert, 1) - - // Account for massive pressure differences. Done by Polymorph - // Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense! - - var/pressure = environment.return_pressure() - var/adjusted_pressure = calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob. - switch(adjusted_pressure) - if(HAZARD_HIGH_PRESSURE to INFINITY) - adjustBruteLoss( min( ( (adjusted_pressure / HAZARD_HIGH_PRESSURE) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) ) - pressure_alert = 2 - if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) - pressure_alert = 1 - if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE) - pressure_alert = 0 - if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) - pressure_alert = -1 - else - if( !(COLD_RESISTANCE in mutations) ) - adjustBruteLoss( LOW_PRESSURE_DAMAGE ) - pressure_alert = -2 - else - pressure_alert = -1 + if(dna) + dna.species.handle_environment(environment, src) return ///FIRE CODE handle_fire() + if(dna) + dna.species.handle_fire(src) + if(..()) return var/thermal_protection = get_heat_protection(30000) //If you don't have fire suit level protection, you get a temperature increase if((1 - thermal_protection) > 0.0001) bodytemperature += BODYTEMP_HEATING_MAX return + + IgniteMob() + if(dna) + dna.species.IgniteMob(src) + else + ..() + + ExtinguishMob() + if(dna) + dna.species.ExtinguishMob(src) + else + ..() + //END FIRE CODE /* @@ -650,6 +352,9 @@ if(COLD_RESISTANCE in mutations) return 1 //Fully protected from the cold. + if(dna && COLDRES in dna.species.specflags) + return 1 + temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares 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. var/thermal_protection_flags = get_cold_protection_flags(temperature) @@ -739,82 +444,8 @@ */ proc/handle_chemicals_in_body() - if(reagents) reagents.metabolize(src) - - if(dna && dna.mutantrace == "plant") //couldn't think of a better place to place it, since it handles nutrition -- Urist - var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing - if(isturf(loc)) //else, there's considered to be no light - var/turf/T = loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 //hardcapped so it's not abused by having a ton of flashlights - else light_amount = 5 - nutrition += light_amount - if(nutrition > 500) - nutrition = 500 - if(light_amount > 2) //if there's enough light, heal - heal_overall_damage(1,1) - adjustToxLoss(-1) - adjustOxyLoss(-1) - if(dna && dna.mutantrace == "shadow") - var/light_amount = 0 - if(isturf(loc)) - var/turf/T = loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount - else light_amount = 10 - if(light_amount > 2) //if there's enough light, start dying - take_overall_damage(1,1) - else if (light_amount < 2) //heal in the dark - heal_overall_damage(1,1) - - //The fucking FAT mutation is the dumbest shit ever. It makes the code so difficult to work with - if(FAT in mutations) - if(overeatduration < 100) - src << "\blue You feel fit again!" - mutations -= FAT - update_inv_w_uniform(0) - update_inv_wear_suit() - else - if(overeatduration > 500) - src << "\red You suddenly feel blubbery!" - mutations |= FAT - update_inv_w_uniform(0) - update_inv_wear_suit() - - // nutrition decrease - if (nutrition > 0 && stat != 2) - nutrition = max (0, nutrition - HUNGER_FACTOR) - - if (nutrition > 450) - if(overeatduration < 600) //capped so people don't take forever to unfat - overeatduration++ - else - if(overeatduration > 1) - overeatduration -= 2 //doubled the unfat rate - - if(dna && dna.mutantrace == "plant") - if(nutrition < 200) - take_overall_damage(2,0) - - if (drowsyness) - drowsyness-- - eye_blurry = max(2, eye_blurry) - if (prob(5)) - sleeping += 1 - Paralyse(5) - - confused = max(0, confused - 1) - // decrement dizziness counter, clamped to 0 - if(resting) - dizziness = max(0, dizziness - 15) - jitteriness = max(0, jitteriness - 15) - else - dizziness = max(0, dizziness - 3) - jitteriness = max(0, jitteriness - 3) - - updatehealth() + if(dna) + dna.species.handle_chemicals_in_body(src) return //TODO: DEFERRED @@ -1048,155 +679,15 @@ damageoverlay.overlays += I damageoverlay.overlays += black - if( stat == DEAD ) - sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) - see_in_dark = 8 - if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO - if(healths) healths.icon_state = "health7" //DEAD healthmeter - else - sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) - var/see_temp = see_invisible - see_invisible = SEE_INVISIBLE_LIVING - if(dna) - switch(dna.mutantrace) - if("slime") - see_in_dark = 3 - see_invisible = SEE_INVISIBLE_LEVEL_ONE - if("shadow") - see_in_dark = 8 - else - see_in_dark = 2 - - if(XRAY in mutations) - sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_LEVEL_TWO - - if(seer) - see_invisible = SEE_INVISIBLE_OBSERVER - - if(mind && mind.changeling) - hud_used.lingchemdisplay.invisibility = 0 - hud_used.lingchemdisplay.maptext = "
[src.mind.changeling.chem_charges]
" - else - hud_used.lingchemdisplay.invisibility = 101 - - if(istype(wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja)) - var/obj/item/clothing/mask/gas/voice/space_ninja/O = wear_mask - switch(O.mode) - if(0) - var/target_list[] = list() - for(var/mob/living/target in oview(src)) - if( target.mind&&(target.mind.special_role||issilicon(target)) )//They need to have a mind. - target_list += target - if(target_list.len)//Everything else is handled by the ninja mask proc. - O.assess_targets(target_list, src) - see_invisible = SEE_INVISIBLE_LIVING - if(1) - see_in_dark = 5 - see_invisible = SEE_INVISIBLE_LIVING - if(2) - sight |= SEE_MOBS - see_invisible = SEE_INVISIBLE_LEVEL_TWO - if(3) - sight |= SEE_TURFS - see_invisible = SEE_INVISIBLE_LIVING - - if(glasses) - if(istype(glasses, /obj/item/clothing/glasses)) - var/obj/item/clothing/glasses/G = glasses - sight |= G.vision_flags - see_in_dark = G.darkness_view - see_invisible = G.invis_view - if(G.hud) - G.process_hud(src) - - if(druggy) //Override for druggy - see_invisible = see_temp - - if(see_override) //Override all - see_invisible = see_override - - if(healths) - switch(hal_screwyhud) - if(1) healths.icon_state = "health6" - if(2) healths.icon_state = "health7" - else - switch(health - staminaloss) - if(100 to INFINITY) healths.icon_state = "health0" - if(80 to 100) healths.icon_state = "health1" - if(60 to 80) healths.icon_state = "health2" - if(40 to 60) healths.icon_state = "health3" - if(20 to 40) healths.icon_state = "health4" - if(0 to 20) healths.icon_state = "health5" - else healths.icon_state = "health6" - - if(nutrition_icon) - switch(nutrition) - if(450 to INFINITY) nutrition_icon.icon_state = "nutrition0" - if(350 to 450) nutrition_icon.icon_state = "nutrition1" - if(250 to 350) nutrition_icon.icon_state = "nutrition2" - if(150 to 250) nutrition_icon.icon_state = "nutrition3" - else nutrition_icon.icon_state = "nutrition4" - - if(pressure) - pressure.icon_state = "pressure[pressure_alert]" - - if(pullin) - if(pulling) pullin.icon_state = "pull" - else pullin.icon_state = "pull0" -// if(rest) //Not used with new UI -// if(resting || lying || sleeping) rest.icon_state = "rest1" -// else rest.icon_state = "rest0" - if(toxin) - if(hal_screwyhud == 4 || toxins_alert) toxin.icon_state = "tox1" - else toxin.icon_state = "tox0" - if(oxygen) - if(hal_screwyhud == 3 || oxygen_alert) oxygen.icon_state = "oxy1" - else oxygen.icon_state = "oxy0" - if(fire) - if(fire_alert) fire.icon_state = "fire[fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat. - else fire.icon_state = "fire0" - - if(bodytemp) - switch(bodytemperature) //310.055 optimal body temp - if(370 to INFINITY) bodytemp.icon_state = "temp4" - if(350 to 370) bodytemp.icon_state = "temp3" - if(335 to 350) bodytemp.icon_state = "temp2" - if(320 to 335) bodytemp.icon_state = "temp1" - if(300 to 320) bodytemp.icon_state = "temp0" - if(295 to 300) bodytemp.icon_state = "temp-1" - if(280 to 295) bodytemp.icon_state = "temp-2" - if(260 to 280) bodytemp.icon_state = "temp-3" - else bodytemp.icon_state = "temp-4" - -// This checks how much the mob's eyewear impairs their vision - if(tinttotal >= TINT_IMPAIR) - if(tinted_weldhelh) - if(tinttotal >= TINT_BLIND) - blinded = 1 // You get the sudden urge to learn to play keyboard - client.screen += global_hud.darkMask - else - client.screen += global_hud.darkMask - - if(blind) - if(blinded) blind.layer = 18 - else blind.layer = 0 - - if( disabilities & NEARSIGHTED && !istype(glasses, /obj/item/clothing/glasses/regular) ) - client.screen += global_hud.vimpaired - if(eye_blurry) client.screen += global_hud.blurry - if(druggy) client.screen += global_hud.druggy - - - if(eye_stat > 20) - if(eye_stat > 30) client.screen += global_hud.darkMask - else client.screen += global_hud.vimpaired - if(machine) if(!machine.check_eye(src)) reset_view(null) else if(!client.adminobs) reset_view(null) + + if(dna) + dna.species.handle_vision(src) + dna.species.handle_hud_icons(src) + return 1 proc/handle_random_events() diff --git a/code/modules/mob/living/carbon/human/mutantrace.dm b/code/modules/mob/living/carbon/human/mutantrace.dm new file mode 100644 index 00000000000..30615bb624c --- /dev/null +++ b/code/modules/mob/living/carbon/human/mutantrace.dm @@ -0,0 +1,22 @@ +var/global/list/colored_mutraces = list( // these mutantraces are affected by mutant color + "lizard", + "plant", + "pod", + "slime", + "jelly", + "golem" +) + +var/global/list/mutants_with_eyes = list( // these mutantraces have eyes + "lizard", + "plant", + "pod", + "jelly", +) + +/mob/living/carbon/human/proc/check_mutrace(var/mutneeded = "mut1", var/mutneededalt = "mut2") + if(dna) + if(dna.mutantrace == mutneeded || dna.mutantrace == mutneededalt) + return 1 + + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index cdd8b0cc80a..be98cf67ed9 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -22,24 +22,8 @@ return if(dna) - if(dna.mutantrace == "lizard") - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "s", stutter("ss")) + message = dna.species.handle_speech(message,src) - if(dna.mutantrace == "fly") - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "z", stutter("zz")) - - /*if(dna.mutantrace == "slime" && prob(5)) - if(copytext(message, 1, 2) != "*") - if(copytext(message, 1, 2) == ";") - message = ";" - else - message = "" - message += "SKR" - var/imax = rand(5,20) - for(var/i = 0,i= 60) + return "gibbers, \"[text]\""; + if (ending == "?") + return "asks, \"[text]\""; + if (ending == "!") + return "exclaims, \"[text]\""; + + if(dna) + return "[dna.species.say_mod], \"[text]\""; + + return "says, \"[text]\""; /mob/living/carbon/human/proc/forcesay(list/append) if(stat == CONSCIOUS) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm new file mode 100644 index 00000000000..64fad2b5de4 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species.dm @@ -0,0 +1,1330 @@ +// This code handles different species in the game. + +#define SPECIES_LAYER 23 +#define BODY_LAYER 22 +#define HAIR_LAYER 8 + +#define TINT_IMPAIR 2 +#define TINT_BLIND 3 + +#define HUMAN_MAX_OXYLOSS 3 +#define HUMAN_CRIT_MAX_OXYLOSS ( (last_tick_duration) /3) + +#define HEAT_DAMAGE_LEVEL_1 2 +#define HEAT_DAMAGE_LEVEL_2 3 +#define HEAT_DAMAGE_LEVEL_3 8 + +#define COLD_DAMAGE_LEVEL_1 0.5 +#define COLD_DAMAGE_LEVEL_2 1.5 +#define COLD_DAMAGE_LEVEL_3 3 + +#define HEAT_GAS_DAMAGE_LEVEL_1 2 +#define HEAT_GAS_DAMAGE_LEVEL_2 4 +#define HEAT_GAS_DAMAGE_LEVEL_3 8 + +#define COLD_GAS_DAMAGE_LEVEL_1 0.5 +#define COLD_GAS_DAMAGE_LEVEL_2 1.5 +#define COLD_GAS_DAMAGE_LEVEL_3 3 + +/datum/species + var/id = null // if the game needs to manually check your race to do something not included in a proc here, it will use this + var/name = null // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever + var/roundstart = 0 // can this mob be chosen at roundstart? (assuming the config option is checked?) + var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race + + var/eyes = "eyes" // which eyes the race uses. at the moment, the only types of eyes are "eyes" (regular eyes) and "jelleyes" (three eyes) + var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows + var/hair_color = null // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color + var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent. + var/use_skintones = 0 // does it use skintones or not? (spoiler alert this is only used by humans) + + var/list/no_equip = list() // slots the race can't equip stuff to + var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids + + var/say_mod = "says" // affects the speech message + + var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster + var/armor = 0 // overall defense for the race... or less defense, if it's negative. + var/brutemod = 1 // multiplier for brute damage + var/burnmod = 1 // multiplier for burn damage + var/coldmod = 1 // multiplier for cold damage + var/heatmod = 1 // multiplier for heat damage + var/punchmod = 0 // adds to the punch damage + + var/invis_sight = SEE_INVISIBLE_LIVING + var/darksight = 2 + + // species flags. these can be found in flags.dm + var/list/specflags = list() + + var/attack_verb = "punch" // punch-specific attack verb + var/sound/attack_sound = 'sound/weapons/punch1.ogg' + var/sound/miss_sound = 'sound/weapons/punchmiss.ogg' + + var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species + + /////////// + // PROCS // + /////////// + + proc/update_base_icon_state(var/mob/living/carbon/human/H) + if(HUSK in H.mutations) + H.remove_overlay(SPECIES_LAYER) // races lose their color + return "husk" + else if(sexes) + if(use_skintones) + return "[H.skin_tone]_[(H.gender == FEMALE) ? "f" : "m"]" + else + return "[id]_[(H.gender == FEMALE) ? "f" : "m"]" + else + return "[id]" + + proc/update_color(var/mob/living/carbon/human/H) + H.remove_overlay(SPECIES_LAYER) + + var/image/standing + + var/g = (H.gender == FEMALE) ? "f" : "m" + + if(MUTCOLORS in specflags) + var/image/spec_base + if(sexes) + spec_base = image("icon" = 'icons/mob/human.dmi', "icon_state" = "[id]_[g]_s", "layer" = -SPECIES_LAYER) + else + spec_base = image("icon" = 'icons/mob/human.dmi', "icon_state" = "[id]_s", "layer" = -SPECIES_LAYER) + if(!config.mutant_colors) + H.dna.mutant_color = default_color + spec_base.color = "#[H.dna.mutant_color]" + standing = spec_base + + if(standing) + H.overlays_standing[SPECIES_LAYER] = standing + + H.apply_overlay(SPECIES_LAYER) + + proc/handle_hair(var/mob/living/carbon/human/H) + H.remove_overlay(HAIR_LAYER) + + var/datum/sprite_accessory/S + var/list/standing = list() + + if(H.facial_hair_style && FACEHAIR in specflags) + S = facial_hair_styles_list[H.facial_hair_style] + if(S) + var/image/img_facial_s + + img_facial_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + + if(hair_color) + if(hair_color == "mutcolor") + if(!config.mutant_colors) + img_facial_s.color = "#" + default_color + else + img_facial_s.color = "#" + H.dna.mutant_color + else + img_facial_s.color = "#" + hair_color + else + img_facial_s.color = "#" + H.facial_hair_color + img_facial_s.alpha = hair_alpha + + standing += img_facial_s + + //Applies the debrained overlay if there is no brain + if(!H.getorgan(/obj/item/organ/brain)) + standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER) + + else if(H.hair_style && HAIR in specflags) + S = hair_styles_list[H.hair_style] + if(S) + var/image/img_hair_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + + img_hair_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) + + if(hair_color) + if(hair_color == "mutcolor") + if(!config.mutant_colors) + img_hair_s.color = "#" + default_color + else + img_hair_s.color = "#" + H.dna.mutant_color + else + img_hair_s.color = "#" + hair_color + else + img_hair_s.color = "#" + H.hair_color + img_hair_s.alpha = hair_alpha + + standing += img_hair_s + + if(standing.len) + H.overlays_standing[HAIR_LAYER] = standing + + H.apply_overlay(HAIR_LAYER) + + return + + proc/handle_body(var/mob/living/carbon/human/H) + H.remove_overlay(BODY_LAYER) + + var/list/standing = list() + + // lipstick + if(H.lip_style && LIPS in specflags) + standing += image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[H.lip_style]_s", "layer" = -BODY_LAYER) + + // eyes + if(EYECOLOR in specflags) + var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[eyes]_s", "layer" = -BODY_LAYER) + img_eyes_s.color = "#" + H.eye_color + standing += img_eyes_s + + //Underwear + if(H.underwear) + var/datum/sprite_accessory/underwear/U = underwear_all[H.underwear] + if(U) + standing += image("icon"=U.icon, "icon_state"="[U.icon_state]_s", "layer"=-BODY_LAYER) + + if(standing.len) + H.overlays_standing[BODY_LAYER] = standing + + H.apply_overlay(BODY_LAYER) + + return + + proc/spec_life(var/mob/living/carbon/human/H) + return + + proc/spec_death(var/gibbed, var/mob/living/carbon/human/H) + return + + proc/auto_equip(var/mob/living/carbon/human/H) + // handles the equipping of species-specific gear + return + + proc/can_equip(var/obj/item/I, var/slot, var/disable_warning, var/mob/living/carbon/human/H) + if(slot in no_equip) + if(!(type in I.species_exception)) + return 0 + + switch(slot) + if(slot_l_hand) + if(H.l_hand) + return 0 + return 1 + if(slot_r_hand) + if(H.r_hand) + return 0 + return 1 + if(slot_wear_mask) + if(H.wear_mask) + return 0 + if( !(I.slot_flags & SLOT_MASK) ) + return 0 + return 1 + if(slot_back) + if(H.back) + return 0 + if( !(I.slot_flags & SLOT_BACK) ) + return 0 + return 1 + if(slot_wear_suit) + if(H.wear_suit) + return 0 + if( !(I.slot_flags & SLOT_OCLOTHING) ) + return 0 + return 1 + if(slot_gloves) + if(H.gloves) + return 0 + if( !(I.slot_flags & SLOT_GLOVES) ) + return 0 + return 1 + if(slot_shoes) + if(H.shoes) + return 0 + if( !(I.slot_flags & SLOT_FEET) ) + return 0 + return 1 + if(slot_belt) + if(H.belt) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_BELT) ) + return + return 1 + if(slot_glasses) + if(H.glasses) + return 0 + if( !(I.slot_flags & SLOT_EYES) ) + return 0 + return 1 + if(slot_head) + if(H.head) + return 0 + if( !(I.slot_flags & SLOT_HEAD) ) + return 0 + return 1 + if(slot_ears) + if(H.ears) + return 0 + if( !(I.slot_flags & SLOT_EARS) ) + return 0 + return 1 + if(slot_w_uniform) + if(H.w_uniform) + return 0 + if( !(I.slot_flags & SLOT_ICLOTHING) ) + return 0 + return 1 + if(slot_wear_id) + if(H.wear_id) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if( !(I.slot_flags & SLOT_ID) ) + return 0 + return 1 + if(slot_l_store) + if(I.flags & NODROP) //Pockets aren't visible, so you can't move NODROP items into them. + return 0 + if(H.l_store) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + return 1 + if(slot_r_store) + if(I.flags & NODROP) + return 0 + if(H.r_store) + return 0 + if(!H.w_uniform && !nojumpsuit) + if(!disable_warning) + H << "You need a jumpsuit before you can attach this [I.name]." + return 0 + if(I.slot_flags & SLOT_DENYPOCKET) + return 0 + if( I.w_class <= 2 || (I.slot_flags & SLOT_POCKET) ) + return 1 + return 0 + if(slot_s_store) + if(I.flags & NODROP) + return 0 + if(H.s_store) + return 0 + if(!H.wear_suit) + if(!disable_warning) + H << "You need a suit before you can attach this [I.name]." + return 0 + if(!H.wear_suit.allowed) + if(!disable_warning) + H << "You somehow have a suit with no defined allowed items for suit storage, stop that." + return 0 + if(I.w_class > 4) + if(!disable_warning) + H << "The [I.name] is too big to attach." //should be src? + return 0 + if( istype(I, /obj/item/device/pda) || istype(I, /obj/item/weapon/pen) || is_type_in_list(I, H.wear_suit.allowed) ) + return 1 + return 0 + if(slot_handcuffed) + if(H.handcuffed) + return 0 + if(!istype(I, /obj/item/weapon/handcuffs)) + return 0 + return 1 + if(slot_legcuffed) + if(H.legcuffed) + return 0 + if(!istype(I, /obj/item/weapon/legcuffs)) + return 0 + return 1 + if(slot_in_backpack) + if (H.back && istype(H.back, /obj/item/weapon/storage/backpack)) + var/obj/item/weapon/storage/backpack/B = H.back + if(B.contents.len < B.storage_slots && I.w_class <= B.max_w_class) + return 1 + return 0 + return 0 //Unsupported slot + + proc/before_equip_job(var/datum/job/J, var/mob/living/carbon/human/H) + return + + proc/after_equip_job(var/datum/job/J, var/mob/living/carbon/human/H) + return + + proc/handle_chemicals(var/datum/reagent/chem, var/mob/living/carbon/human/H) + return 0 + + proc/handle_speech(var/message, var/mob/living/carbon/human/H) + return message + + //////// + //LIFE// + //////// + + proc/handle_chemicals_in_body(var/mob/living/carbon/human/H) + if(H.reagents) H.reagents.metabolize(H) + + //The fucking FAT mutation is the dumbest shit ever. It makes the code so difficult to work with + if(FAT in H.mutations) + if(H.overeatduration < 100) + H << "You feel fit again!" + H.mutations -= FAT + H.update_inv_w_uniform(0) + H.update_inv_wear_suit() + else + if(H.overeatduration > 500) + H << "You suddenly feel blubbery!" + H.mutations |= FAT + H.update_inv_w_uniform(0) + H.update_inv_wear_suit() + + // nutrition decrease + if (H.nutrition > 0 && H.stat != 2) + H.nutrition = max (0, H.nutrition - HUNGER_FACTOR) + + if (H.nutrition > 450) + if(H.overeatduration < 600) //capped so people don't take forever to unfat + H.overeatduration++ + else + if(H.overeatduration > 1) + H.overeatduration -= 2 //doubled the unfat rate + + if (H.drowsyness) + H.drowsyness-- + H.eye_blurry = max(2, H.eye_blurry) + if (prob(5)) + H.sleeping += 1 + H.Paralyse(5) + + H.confused = max(0, H.confused - 1) + // decrement dizziness counter, clamped to 0 + if(H.resting) + H.dizziness = max(0, H.dizziness - 15) + H.jitteriness = max(0, H.jitteriness - 15) + else + H.dizziness = max(0, H.dizziness - 3) + H.jitteriness = max(0, H.jitteriness - 3) + + H.updatehealth() + + return + + proc/handle_vision(var/mob/living/carbon/human/H) + if( H.stat == DEAD ) + H.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) + H.see_in_dark = 8 + if(!H.druggy) H.see_invisible = SEE_INVISIBLE_LEVEL_TWO + else + H.sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) + var/see_temp = H.see_invisible + H.see_invisible = invis_sight + H.see_in_dark = darksight + + if(XRAY in H.mutations) + H.sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS + H.see_in_dark = 8 + H.see_invisible = SEE_INVISIBLE_LEVEL_TWO + + if(H.seer) + H.see_invisible = SEE_INVISIBLE_OBSERVER + + if(H.mind && H.mind.changeling) + H.hud_used.lingchemdisplay.invisibility = 0 + H.hud_used.lingchemdisplay.maptext = "
[H.mind.changeling.chem_charges]
" + else + H.hud_used.lingchemdisplay.invisibility = 101 + + if(istype(H.wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja)) + var/obj/item/clothing/mask/gas/voice/space_ninja/O = H.wear_mask + switch(O.mode) + if(0) + var/target_list[] = list() + for(var/mob/living/target in oview(H)) + if( target.mind&&(target.mind.special_role||issilicon(target)) )//They need to have a mind. + target_list += target + if(target_list.len)//Everything else is handled by the ninja mask proc. + O.assess_targets(target_list, H) + H.see_invisible = SEE_INVISIBLE_LIVING + if(1) + H.see_in_dark = 5 + H.see_invisible = SEE_INVISIBLE_LIVING + if(2) + H.sight |= SEE_MOBS + H.see_invisible = SEE_INVISIBLE_LEVEL_TWO + if(3) + H.sight |= SEE_TURFS + H.see_invisible = SEE_INVISIBLE_LIVING + + if(H.glasses) + if(istype(H.glasses, /obj/item/clothing/glasses)) + var/obj/item/clothing/glasses/G = H.glasses + H.sight |= G.vision_flags + H.see_in_dark = G.darkness_view + H.see_invisible = G.invis_view + if(G.hud) + G.process_hud(H) + + if(H.druggy) //Override for druggy + H.see_invisible = see_temp + + if(H.see_override) //Override all + H.see_invisible = H.see_override + + // This checks how much the mob's eyewear impairs their vision + if(H.tinttotal >= TINT_IMPAIR) + if(tinted_weldhelh) + if(H.tinttotal >= TINT_BLIND) + H.blinded = 1 // You get the sudden urge to learn to play keyboard + H.client.screen += global_hud.darkMask + else + H.client.screen += global_hud.darkMask + + if(H.blind) + if(H.blinded) H.blind.layer = 18 + else H.blind.layer = 0 + + if( H.disabilities & NEARSIGHTED && !istype(H.glasses, /obj/item/clothing/glasses/regular) ) + H.client.screen += global_hud.vimpaired + if(H.eye_blurry) H.client.screen += global_hud.blurry + if(H.druggy) H.client.screen += global_hud.druggy + + + if(H.eye_stat > 20) + if(H.eye_stat > 30) H.client.screen += global_hud.darkMask + else H.client.screen += global_hud.vimpaired + + return 1 + + proc/handle_hud_icons(var/mob/living/carbon/human/H) + 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" + else + switch(H.health - 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.nutrition_icon) + switch(H.nutrition) + if(450 to INFINITY) H.nutrition_icon.icon_state = "nutrition0" + if(350 to 450) H.nutrition_icon.icon_state = "nutrition1" + if(250 to 350) H.nutrition_icon.icon_state = "nutrition2" + if(150 to 250) H.nutrition_icon.icon_state = "nutrition3" + else H.nutrition_icon.icon_state = "nutrition4" + + if(H.pressure) + H.pressure.icon_state = "pressure[H.pressure_alert]" + + if(H.pullin) + if(H.pulling) H.pullin.icon_state = "pull" + else H.pullin.icon_state = "pull0" +// if(rest) //Not used with new UI +// if(resting || lying || sleeping) rest.icon_state = "rest1" +// else rest.icon_state = "rest0" + if(H.toxin) + if(H.hal_screwyhud == 4 || H.toxins_alert) H.toxin.icon_state = "tox1" + else H.toxin.icon_state = "tox0" + if(H.oxygen) + if(H.hal_screwyhud == 3 || H.oxygen_alert) H.oxygen.icon_state = "oxy1" + else H.oxygen.icon_state = "oxy0" + if(H.fire) + if(H.fire_alert) H.fire.icon_state = "fire[H.fire_alert]" //fire_alert is either 0 if no alert, 1 for cold and 2 for heat. + else H.fire.icon_state = "fire0" + + if(H.bodytemp) + if(!(HEATRES in specflags)) + switch(H.bodytemperature) //310.055 optimal body temp + if(370 to INFINITY) H.bodytemp.icon_state = "temp4" + if(350 to 370) H.bodytemp.icon_state = "temp3" + if(335 to 350) H.bodytemp.icon_state = "temp2" + switch(H.bodytemperature) + if(320 to 335) H.bodytemp.icon_state = "temp1" + if(300 to 320) H.bodytemp.icon_state = "temp0" + if(295 to 300) H.bodytemp.icon_state = "temp-1" + if(!(COLDRES in specflags)) + switch(H.bodytemperature) + if(280 to 295) H.bodytemp.icon_state = "temp-2" + if(260 to 280) H.bodytemp.icon_state = "temp-3" + if(-INFINITY to 260) H.bodytemp.icon_state = "temp-4" + + return 1 + + proc/handle_mutations_and_radiation(var/mob/living/carbon/human/H) + if(H.getFireLoss()) + if((COLD_RESISTANCE in H.mutations) || (prob(1))) + H.heal_organ_damage(0,1) + + if ((HULK in H.mutations) && H.health <= 25) + H.mutations.Remove(HULK) + H.update_mutations() //update our mutation overlays + H << "You suddenly feel very weak." + H.Weaken(3) + H.emote("collapse") + + if (H.radiation && !(RADIMMUNE in specflags)) + if (H.radiation > 100) + H.radiation = 100 + H.Weaken(10) + H << "You feel weak." + H.emote("collapse") + + if (H.radiation < 0) + H.radiation = 0 + + else + switch(H.radiation) + if(1 to 49) + H.radiation-- + if(prob(25)) + H.adjustToxLoss(1) + H.updatehealth() + + if(50 to 74) + H.radiation -= 2 + H.adjustToxLoss(1) + if(prob(5)) + H.radiation -= 5 + H.Weaken(3) + H << "You feel weak." + H.emote("collapse") + if(prob(15)) + if(!( H.hair_style == "Shaved") || !(H.hair_style == "Bald") || HAIR in specflags) + H << "Your hair starts to fall out in clumps..." + spawn(50) + H.facial_hair_style = "Shaved" + H.hair_style = "Bald" + H.update_hair() + H.updatehealth() + + if(75 to 100) + H.radiation -= 3 + H.adjustToxLoss(3) + if(prob(1)) + H << "You mutate!" + randmutb(H) + domutcheck(H,null) + H.emote("gasp") + H.updatehealth() + + //////////////// + // MOVE SPEED // + //////////////// + + proc/movement_delay(var/mob/living/carbon/human/H) + var/mspeed = 0 + + if(!has_gravity(H)) + return -1 //It's hard to be slowed down in space by... anything + else if(H.status_flags & GOTTAGOFAST) + return -1 + + mspeed = 0 + var/health_deficiency = (100 - H.health + H.staminaloss) + if(health_deficiency >= 40) + mspeed += (health_deficiency / 25) + + var/hungry = (500 - H.nutrition) / 5 //So overeat would be 100 and default level would be 80 + if(hungry >= 70) + mspeed += hungry / 50 + + if(H.wear_suit) + mspeed += H.wear_suit.slowdown + if(H.shoes) + mspeed += H.shoes.slowdown + if(H.back) + mspeed += H.back.slowdown + + if(FAT in H.mutations) + mspeed += 1.5 + if(H.bodytemperature < 283.222) + mspeed += (283.222 - H.bodytemperature) / 10 * 1.75 + + mspeed += speedmod + + return mspeed + + ////////////////// + // ATTACK PROCS // + ////////////////// + + proc/spec_attack_hand(var/mob/living/carbon/human/M, var/mob/living/carbon/human/H) + if((M != H) && H.check_shields(0, M.name)) + add_logs(M, H, "attempted to touch") + H.visible_message("[M] attempted to touch [H]!") + return 0 + + switch(M.a_intent) + if("help") + if(H.health >= 0) + H.help_shake_act(M) + if(H != M) + add_logs(M, H, "shaked") + return 1 + + //CPR + if((M.head && (M.head.flags & HEADCOVERSMOUTH)) || (M.wear_mask && (M.wear_mask.flags & MASKCOVERSMOUTH))) + M << "Remove your mask!" + return 0 + if((H.head && (H.head.flags & HEADCOVERSMOUTH)) || (H.wear_mask && (H.wear_mask.flags & MASKCOVERSMOUTH))) + M << "Remove their mask!" + return 0 + + if(H.cpr_time < world.time + 30) + add_logs(H, M, "CPRed") + H.visible_message("[M] is trying to perform CPR on [H]!") + if(!do_mob(M, H)) + return 0 + if((H.health >= -99 && H.health <= 0)) + H.cpr_time = world.time + var/suff = min(H.getOxyLoss(), 7) + H.adjustOxyLoss(-suff) + H.updatehealth() + M.visible_message("[M] performs CPR on [H]!") + H << "You feel a breath of fresh air enter your lungs. It feels good." + + if("grab") + if(M == H || H.anchored) + return 0 + + add_logs(M, H, "grabbed", addition="passively") + + if(H.w_uniform) + H.w_uniform.add_fingerprint(M) + + var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, H) + if(H.buckled) + M << "You cannot grab [H], \he is buckled in!" + if(!G) //the grab will delete itself in New if affecting is anchored + return + M.put_in_active_hand(G) + G.synch() + H.LAssailant = M + + playsound(H.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + H.visible_message("[M] has grabbed [H] passively!") + return 1 + + if("harm") + add_logs(M, H, "punched") + + var/atk_verb = "punch" + if(H.lying) + atk_verb = "kick" + else if(M.dna) + atk_verb = M.dna.species.attack_verb + + var/damage = rand(0, 9) + damage += punchmod + + if(!damage) + if(M.dna) + playsound(H.loc, M.dna.species.miss_sound, 25, 1, -1) + else + playsound(H.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + + H.visible_message("[M] has attempted to [atk_verb] [H]!") + return 0 + + + var/obj/item/organ/limb/affecting = H.get_organ(ran_zone(M.zone_sel.selecting)) + var/armor_block = H.run_armor_check(affecting, "melee") + + if(HULK in M.mutations) + damage += 5 + + if(M.dna) + playsound(H.loc, M.dna.species.attack_sound, 25, 1, -1) + else + playsound(H.loc, 'sound/weapons/punch1.ogg', 25, 1, -1) + + + H.visible_message("[M] has [atk_verb]ed [H]!", \ + "[M] has [atk_verb]ed [H]!") + + H.apply_damage(damage, BRUTE, affecting, armor_block) + if((H.stat != DEAD) && damage >= 9) + H.visible_message("[M] has weakened [H]!", \ + "[M] has weakened [H]!") + H.apply_effect(4, WEAKEN, armor_block) + H.forcesay(hit_appends) + else if(H.lying) + H.forcesay(hit_appends) + + if("disarm") + add_logs(M, H, "disarmed") + + if(H.w_uniform) + H.w_uniform.add_fingerprint(M) + var/obj/item/organ/limb/affecting = H.get_organ(ran_zone(M.zone_sel.selecting)) + var/randn = rand(1, 100) + if(randn <= 25) + H.apply_effect(2, WEAKEN, H.run_armor_check(affecting, "melee")) + playsound(H, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + H.visible_message("[M] has pushed [H]!", + "[M] has pushed [H]!") + H.forcesay(hit_appends) + return + + var/talked = 0 // BubbleWrap + + if(randn <= 60) + //BubbleWrap: Disarming breaks a pull + if(H.pulling) + H.visible_message("[M] has broken [H]'s grip on [H.pulling]!") + talked = 1 + H.stop_pulling() + + //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it? + if(istype(H.l_hand, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/lgrab = H.l_hand + if(lgrab.affecting) + H.visible_message("[M] has broken [H]'s grip on [lgrab.affecting]!") + talked = 1 + spawn(1) + qdel(lgrab) + if(istype(H.r_hand, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/rgrab = H.r_hand + if(rgrab.affecting) + H.visible_message("[M] has broken [H]'s grip on [rgrab.affecting]!") + talked = 1 + spawn(1) + qdel(rgrab) + //End BubbleWrap + + if(!talked) //BubbleWrap + if(H.drop_item()) + H.visible_message("[M] has disarmed [H]!", \ + "[M] has disarmed [H]!") + playsound(H, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + + playsound(H, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + H.visible_message("[M] attempted to disarm [H]!", \ + "[M] attemped to disarm [H]!") + return + + proc/spec_attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone, var/obj/item/organ/limb/affecting, var/hit_area, var/intent, var/obj/item/organ/limb/target_limb, target_area, var/mob/living/carbon/human/H) + // Allows you to put in item-specific reactions based on species + if((user != H) && H.check_shields(I.force, "the [I.name]")) + return 0 + + if(I.attack_verb && I.attack_verb.len) + H.visible_message("[H] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!", \ + "[H] has been [pick(I.attack_verb)] in the [hit_area] with [I] by [user]!") + else if(I.force) + H.visible_message("[H] has been attacked in the [hit_area] with [I] by [user]!", \ + "[H] has been attacked in the [hit_area] with [I] by [user]!") + else + return 0 + + var/armor = H.run_armor_check(affecting, "melee", "Your armour has protected your [hit_area].", "Your armour has softened a hit to your [hit_area].") + if(armor >= 100) return 0 + var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) + + apply_damage(I.force, I.damtype, affecting, armor, H) + + var/bloody = 0 + if(((I.damtype == BRUTE) && prob(25 + (I.force * 2)))) + if(affecting.status == ORGAN_ORGANIC) + I.add_blood(H) //Make the weapon bloody, not the person. + if(prob(I.force * 2)) //blood spatter! + bloody = 1 + var/turf/location = H.loc + if(istype(location, /turf/simulated)) + location.add_blood(H) + if(get_dist(H, H) <= 1) //people with TK won't get smeared with blood + if(H.wear_suit) + H.wear_suit.add_blood(H) + H.update_inv_wear_suit(0) //updates mob overlays to show the new blood (no refresh) + else if(H.w_uniform) + H.w_uniform.add_blood(H) + H.update_inv_w_uniform(0) //updates mob overlays to show the new blood (no refresh) + if (H.gloves) + var/obj/item/clothing/gloves/G = H.gloves + G.add_blood(H) + else + H.add_blood(H) + H.update_inv_gloves() //updates on-mob overlays for bloody hands and/or bloody gloves + + + switch(hit_area) + if("head") //Harder to score a stun but if you do it lasts a bit longer + if(H.stat == CONSCIOUS && prob(I.force) && armor < 50) + H.visible_message("[H] has been knocked unconscious!", \ + "[H] has been knocked unconscious!") + H.apply_effect(20, PARALYZE, armor) + if(H != user && I.damtype == BRUTE) + ticker.mode.remove_revolutionary(H.mind) + + if(bloody) //Apply blood + if(H.wear_mask) + H.wear_mask.add_blood(H) + H.update_inv_wear_mask(0) + if(H.head) + H.head.add_blood(H) + H.update_inv_head(0) + if(H.glasses && prob(33)) + H.glasses.add_blood(H) + H.update_inv_glasses(0) + + if("chest") //Easier to score a stun but lasts less time + if(H.stat == CONSCIOUS && prob(I.force + 10)) + H.visible_message("[H] has been knocked down!", \ + "[H] has been knocked down!") + H.apply_effect(5, WEAKEN, armor) + + if(bloody) + if(H.wear_suit) + H.wear_suit.add_blood(H) + H.update_inv_wear_suit(0) + if(H.w_uniform) + H.w_uniform.add_blood(H) + H.update_inv_w_uniform(0) + + if(Iforce > 10 || Iforce >= 5 && prob(33)) + H.forcesay(hit_appends) //forcesay checks stat already. + return + + proc/attacked_by(var/obj/item/I, var/mob/living/user, var/def_zone, var/mob/living/carbon/human/H) + H.apply_damage(I.force, I.damtype) + if(I.damtype == "brute") + if(prob(33) && I.force && !(NOBLOOD in specflags)) + var/turf/location = H.loc + if(istype(location, /turf/simulated)) + location.add_blood_floor(H) + + var/showname = "." + if(user) + showname = " by [user]!" + if(!(user in viewers(I, null))) + showname = "." + + if(I.attack_verb && I.attack_verb.len) + H.visible_message("[H] has been [pick(I.attack_verb)] with [I][showname]", + "[H] has been [pick(I.attack_verb)] with [I][showname]") + else if(I.force) + H.visible_message("[H] has been attacked with [I][showname]", + "[H] has been attacked with [I][showname]") + if(!showname && user) + if(user.client) + user << "You attack [H] with [I]. " + + return + + proc/apply_damage(var/damage, var/damagetype = BRUTE, var/def_zone = null, var/blocked, var/mob/living/carbon/human/H) + blocked = (100-(blocked+armor))/100 + if(blocked <= 0) return 0 + + var/obj/item/organ/limb/organ = null + if(isorgan(def_zone)) + organ = def_zone + else + if(!def_zone) def_zone = ran_zone(def_zone) + organ = H.get_organ(check_zone(def_zone)) + if(!organ) return 0 + + damage = (damage * blocked) + + switch(damagetype) + if(BRUTE) + H.damageoverlaytemp = 20 + if(organ.take_damage(damage*brutemod, 0)) + H.update_damage_overlays(0) + if(BURN) + H.damageoverlaytemp = 20 + if(organ.take_damage(0, damage*burnmod)) + H.update_damage_overlays(0) + if(TOX) + H.adjustToxLoss(damage * blocked) + if(OXY) + H.adjustOxyLoss(damage * blocked) + if(CLONE) + H.adjustCloneLoss(damage * blocked) + if(STAMINA) + H.adjustStaminaLoss(damage * blocked) + + proc/on_hit(var/obj/item/projectile/proj_type, var/mob/living/carbon/human/H) + // called when hit by a projectile + switch(proj_type) + if(/obj/item/projectile/energy/floramut) // overwritten by plants/pods + H.show_message("The radiation beam dissipates harmlessly through your body.") + if(/obj/item/projectile/energy/florayield) + H.show_message("The radiation beam dissipates harmlessly through your body.") + return + + ///////////// + //BREATHING// + ///////////// + + proc/breathe(var/mob/living/carbon/human/H) + if(H.reagents.has_reagent("lexorin")) return + if(istype(H.loc, /obj/machinery/atmospherics/unary/cryo_cell)) return + + var/datum/gas_mixture/environment = H.loc.return_air() + var/datum/gas_mixture/breath + // HACK NEED CHANGING LATER + if(H.health <= config.health_threshold_crit) + H.losebreath++ + + if(H.losebreath>0) //Suffocating so do not take a breath + H.losebreath-- + if (prob(10)) //Gasp per 10 ticks? Sounds about right. + spawn H.emote("gasp") + if(istype(H.loc, /obj/)) + var/obj/location_as_object = H.loc + location_as_object.handle_internal_lifeform(H, 0) + else + //First, check for air from internal atmosphere (using an air tank and mask generally) + breath = H.get_breath_from_internal(BREATH_VOLUME) // Super hacky -- TLE + //breath = get_breath_from_internal(0.5) // Manually setting to old BREATH_VOLUME amount -- TLE + + //No breath from internal atmosphere so get breath from location + if(!breath) + if(isobj(H.loc)) + var/obj/location_as_object = H.loc + breath = location_as_object.handle_internal_lifeform(H, BREATH_VOLUME) + else if(isturf(H.loc)) + var/breath_moles = 0 + /*if(environment.return_pressure() > ONE_ATMOSPHERE) + // Loads of air around (pressure effect will be handled elsewhere), so lets just take a enough to fill our lungs at normal atmos pressure (using n = Pv/RT) + breath_moles = (ONE_ATMOSPHERE*BREATH_VOLUME/R_IDEAL_GAS_EQUATION*environment.temperature) + else*/ + // Not enough air around, take a percentage of what's there to model this properly + breath_moles = environment.total_moles()*BREATH_PERCENTAGE + + breath = H.loc.remove_air(breath_moles) + // Handle chem smoke effect -- Doohl + var/block = 0 + if(H.wear_mask) + if(H.wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT) + block = 1 + if(H.glasses) + if(H.glasses.flags & BLOCK_GAS_SMOKE_EFFECT) + block = 1 + if(H.head) + if(H.head.flags & BLOCK_GAS_SMOKE_EFFECT) + block = 1 + + if(!block) + + for(var/obj/effect/effect/chem_smoke/smoke in view(1, H)) + if(smoke.reagents.total_volume) + smoke.reagents.reaction(H, INGEST) + spawn(5) + if(smoke) + smoke.reagents.copy_to(H, 10) // I dunno, maybe the reagents enter the blood stream through the lungs? + break // If they breathe in the nasty stuff once, no need to continue checking + + else //Still give containing object the chance to interact + if(istype(H.loc, /obj/)) + var/obj/location_as_object = H.loc + location_as_object.handle_internal_lifeform(H, 0) + + handle_breath(breath, H) + + if(breath) + H.loc.assume_air(breath) + + proc/handle_breath(datum/gas_mixture/breath, var/mob/living/carbon/human/H) + if((H.status_flags & GODMODE)) + return + + if(!breath || (breath.total_moles() == 0) || H.suiciding) + if(H.reagents.has_reagent("inaprovaline")) + return + if(H.suiciding) + H.adjustOxyLoss(2)//If you are suiciding, you should die a little bit faster + H.failed_last_breath = 1 + H.oxygen_alert = max(H.oxygen_alert, 1) + return 0 + if(H.health >= config.health_threshold_crit) + if(NOBREATH in specflags) return 1 + H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) + H.failed_last_breath = 1 + else + H.adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) + H.failed_last_breath = 1 + + H.oxygen_alert = max(H.oxygen_alert, 1) + + return 0 + + var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa + //var/safe_oxygen_max = 140 // Maximum safe partial pressure of O2, in kPa (Not used for now) + var/safe_co2_max = 10 // Yes it's an arbitrary value who cares? + var/safe_toxins_max = 0.005 + var/SA_para_min = 1 + var/SA_sleep_min = 5 + var/oxygen_used = 0 + var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME + + //Partial pressure of the O2 in our breath + var/O2_pp = (breath.oxygen/breath.total_moles())*breath_pressure + // Same, but for the toxins + var/Toxins_pp = (breath.toxins/breath.total_moles())*breath_pressure + // And CO2, lets say a PP of more than 10 will be bad (It's a little less really, but eh, being passed out all round aint no fun) + var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*breath_pressure // Tweaking to fit the hacky bullshit I've done with atmo -- TLE + //var/CO2_pp = (breath.carbon_dioxide/breath.total_moles())*0.5 // The default pressure value + + if(O2_pp < safe_oxygen_min) // Too little oxygen + if(!(NOBREATH in specflags) || (H.health <= config.health_threshold_crit)) + if(prob(20)) + spawn(0) H.emote("gasp") + if(O2_pp > 0) + var/ratio = safe_oxygen_min/O2_pp + H.adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!) + H.failed_last_breath = 1 + oxygen_used = breath.oxygen*ratio/6 + else + H.adjustOxyLoss(HUMAN_MAX_OXYLOSS) + H.failed_last_breath = 1 + H.oxygen_alert = max(H.oxygen_alert, 1) + /*else if (O2_pp > safe_oxygen_max) // Too much oxygen (commented this out for now, I'll deal with pressure damage elsewhere I suppose) + spawn(0) emote("cough") + var/ratio = O2_pp/safe_oxygen_max + oxyloss += 5*ratio + oxygen_used = breath.oxygen*ratio/6 + oxygen_alert = max(oxygen_alert, 1)*/ + else // We're in safe limits + H.failed_last_breath = 0 + H.adjustOxyLoss(-5) + oxygen_used = breath.oxygen/6 + H.oxygen_alert = 0 + + breath.oxygen -= oxygen_used + breath.carbon_dioxide += oxygen_used + + //CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick. + if(CO2_pp > safe_co2_max && !(NOBREATH in specflags)) + 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(3) + 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.co2overloadtime = 0 + + if(Toxins_pp > safe_toxins_max && !(NOBREATH in specflags)) // Too much toxins + var/ratio = (breath.toxins/safe_toxins_max) * 10 + //adjustToxLoss(Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) //Limit amount of damage toxin exposure can do per second + if(H.reagents) + H.reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE)) + H.toxins_alert = max(H.toxins_alert, 1) + else + H.toxins_alert = 0 + + if(breath.trace_gases.len && !(NOBREATH in specflags)) // 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 > SA_para_min) // 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 > SA_sleep_min) // Enough to make us sleep as well + H.sleeping = max(H.sleeping+2, 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) + + return 1 + + 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) && !(COLD_RESISTANCE in H.mutations) && !(COLDRES in specflags)) // Hot air hurts :( + if(breath.temperature < 260.15) + if(prob(20)) + H << "You feel your face freezing and an icicle forming in your lungs!" + else if(breath.temperature > 360.15 && !(HEATRES in specflags)) + if(prob(20)) + H << "You feel your face burning and a searing heat in your lungs!" + + if(!(COLDRES in specflags)) // COLD DAMAGE + switch(breath.temperature) + if(-INFINITY to 120) + H.apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head") + H.fire_alert = max(H.fire_alert, 1) + if(120 to 200) + H.apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head") + H.fire_alert = max(H.fire_alert, 1) + if(200 to 260) + H.apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head") + H.fire_alert = max(H.fire_alert, 1) + + if(!(HEATRES in specflags)) // HEAT DAMAGE + switch(breath.temperature) + if(360 to 400) + H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head") + H.fire_alert = max(H.fire_alert, 2) + if(400 to 1000) + H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head") + H.fire_alert = max(H.fire_alert, 2) + if(1000 to INFINITY) + H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head") + H.fire_alert = max(H.fire_alert, 2) + + return + + proc/handle_environment(datum/gas_mixture/environment, var/mob/living/carbon/human/H) + if(!environment) + return + + var/loc_temp = H.get_temperature(environment) + //world << "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Thermal protection: [get_thermal_protection()] - Fire protection: [thermal_protection + add_fire_protection(loc_temp)] - Heat capacity: [environment_heat_capacity] - Location: [loc] - src: [src]" + + //Body temperature is adjusted in two steps. Firstly your body tries to stabilize itself a bit. + if(H.stat != 2) + H.stabilize_temperature_from_calories() + + //After then, it reacts to the surrounding atmosphere based on your thermal protection + if(!H.on_fire) //If you're on fire, you do not heat up or cool down based on surrounding gases + if(loc_temp < H.bodytemperature) + //Place is colder than we are + var/thermal_protection = H.get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + H.bodytemperature += min((1-thermal_protection) * ((loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR), BODYTEMP_COOLING_MAX) + else + //Place is hotter than we are + var/thermal_protection = H.get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to. + if(thermal_protection < 1) + H.bodytemperature += min((1-thermal_protection) * ((loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR), BODYTEMP_HEATING_MAX) + + // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. + if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !(HEATRES in specflags)) + //Body temperature is too hot. + H.fire_alert = max(H.fire_alert, 1) + switch(H.bodytemperature) + if(360 to 400) + H.apply_damage(HEAT_DAMAGE_LEVEL_1*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + if(400 to 460) + H.apply_damage(HEAT_DAMAGE_LEVEL_2*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + if(460 to INFINITY) + if(H.on_fire) + H.apply_damage(HEAT_DAMAGE_LEVEL_3*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + else + H.apply_damage(HEAT_DAMAGE_LEVEL_2*heatmod, BURN) + H.fire_alert = max(H.fire_alert, 2) + + else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !(COLDRES in specflags)) + H.fire_alert = max(H.fire_alert, 1) + if(!istype(H.loc, /obj/machinery/atmospherics/unary/cryo_cell)) + switch(H.bodytemperature) + if(200 to 260) + H.apply_damage(COLD_DAMAGE_LEVEL_1*coldmod, BURN) + H.fire_alert = max(H.fire_alert, 1) + if(120 to 200) + H.apply_damage(COLD_DAMAGE_LEVEL_2*coldmod, BURN) + H.fire_alert = max(H.fire_alert, 1) + if(-INFINITY to 120) + H.apply_damage(COLD_DAMAGE_LEVEL_3*coldmod, BURN) + H.fire_alert = max(H.fire_alert, 1) + + // Account for massive pressure differences. Done by Polymorph + // Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense! + + var/pressure = environment.return_pressure() + var/adjusted_pressure = H.calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob. + switch(adjusted_pressure) + if(HAZARD_HIGH_PRESSURE to INFINITY) + if(!(HEATRES in specflags)) + H.adjustBruteLoss( min( ( (adjusted_pressure / HAZARD_HIGH_PRESSURE) -1 )*PRESSURE_DAMAGE_COEFFICIENT , MAX_HIGH_PRESSURE_DAMAGE) ) + H.pressure_alert = 2 + else + H.pressure_alert = 1 + if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) + H.pressure_alert = 1 + if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE) + H.pressure_alert = 0 + if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) + H.pressure_alert = -1 + else + if((COLD_RESISTANCE in H.mutations) || (COLDRES in specflags)) + H.pressure_alert = -1 + else + H.adjustBruteLoss( LOW_PRESSURE_DAMAGE ) + H.pressure_alert = -2 + + return + + ////////// + // FIRE // + ////////// + + proc/handle_fire(var/mob/living/carbon/human/H) + if(HEATRES in specflags || NOFIRE in specflags) + return + if(H.fire_stacks < 0) + H.fire_stacks++ //If we've doused ourselves in water to avoid fire, dry off slowly + H.fire_stacks = min(0, H.fire_stacks)//So we dry ourselves back to default, nonflammable. + if(!H.on_fire) + return + var/datum/gas_mixture/G = H.loc.return_air() // Check if we're standing in an oxygenless environment + if(G.oxygen < 1) + ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire + return + var/turf/location = get_turf(H) + location.hotspot_expose(700, 50, 1) + + proc/IgniteMob(var/mob/living/carbon/human/H) + if(H.fire_stacks > 0 && !H.on_fire && !(HEATRES in specflags) && !(NOFIRE in specflags)) + H.on_fire = 1 + H.AddLuminosity(3) + H.update_fire() + + proc/ExtinguishMob(var/mob/living/carbon/human/H) + if(H.on_fire) + H.on_fire = 0 + H.fire_stacks = 0 + H.AddLuminosity(-3) + H.update_fire() + +#undef SPECIES_LAYER +#undef BODY_LAYER +#undef HAIR_LAYER + +#undef HUMAN_MAX_OXYLOSS +#undef HUMAN_CRIT_MAX_OXYLOSS + +#undef HEAT_DAMAGE_LEVEL_1 +#undef HEAT_DAMAGE_LEVEL_2 +#undef HEAT_DAMAGE_LEVEL_3 + +#undef COLD_DAMAGE_LEVEL_1 +#undef COLD_DAMAGE_LEVEL_2 +#undef COLD_DAMAGE_LEVEL_3 + +#undef HEAT_GAS_DAMAGE_LEVEL_1 +#undef HEAT_GAS_DAMAGE_LEVEL_2 +#undef HEAT_GAS_DAMAGE_LEVEL_3 + +#undef COLD_GAS_DAMAGE_LEVEL_1 +#undef COLD_GAS_DAMAGE_LEVEL_2 +#undef COLD_GAS_DAMAGE_LEVEL_3 + +#undef TINT_IMPAIR +#undef TINT_BLIND \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm new file mode 100644 index 00000000000..1e2d538fad3 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -0,0 +1,177 @@ +/datum/species/human + name = "Human" + id = "human" + roundstart = 1 + specflags = list(EYECOLOR,HAIR,FACEHAIR,LIPS) + use_skintones = 1 + + handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "mutationtoxin") + H << "Your flesh rapidly mutates!" + H.dna.species = new /datum/species/slime() + H.regenerate_icons() + H.reagents.del_reagent(chem.type) + return 1 + +/datum/species/lizard + // Reptilian humanoids with scaled skin and tails. + name = "Lizardperson" + id = "lizard" + say_mod = "hisses" + default_color = "00FF00" + roundstart = 1 + specflags = list(MUTCOLORS,EYECOLOR,LIPS) + attack_verb = "slash" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + + handle_speech(message) + // jesus christ why + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "s", stutter("ss")) + + return message + +/datum/species/plant + // Creatures made of leaves and plant matter. + name = "Plant" + id = "plant" + default_color = "59CE00" + specflags = list(MUTCOLORS,EYECOLOR) + attack_verb = "slice" + attack_sound = 'sound/weapons/slice.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + burnmod = 1.25 + heatmod = 1.5 + + handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "plantbgone") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 + + on_hit(proj_type, mob/living/carbon/human/H) + switch(proj_type) + if(/obj/item/projectile/energy/floramut) + if(prob(15)) + H.apply_effect((rand(30,80)),IRRADIATE) + H.Weaken(5) + for (var/mob/V in viewers(H)) + V.show_message("[H] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) + 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!") + if(/obj/item/projectile/energy/florayield) + H.nutrition = min(H.nutrition+30, 500) + return + +/datum/species/plant/pod + // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. + name = "Podperson" + id = "pod" + + spec_life(mob/living/carbon/human/H) + var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing + if(isturf(H.loc)) //else, there's considered to be no light + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 + else light_amount = 5 + H.nutrition += light_amount + if(H.nutrition > 500) + H.nutrition = 500 + if(light_amount > 2) //if there's enough light, heal + H.heal_overall_damage(1,1) + H.adjustToxLoss(-1) + H.adjustOxyLoss(-1) + + if(H.nutrition < 200) + H.take_overall_damage(2,0) + +/datum/species/shadow + // Humans cursed to stay in the darkness, lest their life forces drain. They regain health in shadow and die in light. + name = "???" + id = "shadow" + darksight = 8 + sexes = 0 + ignored_by = list(/mob/living/simple_animal/hostile/faithless) + + spec_life(mob/living/carbon/human/H) + var/light_amount = 0 + if(isturf(H.loc)) + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount + else light_amount = 10 + if(light_amount > 2) //if there's enough light, start dying + H.take_overall_damage(1,1) + else if (light_amount < 2) //heal in the dark + H.heal_overall_damage(1,1) + +/datum/species/slime + // Humans mutated by slime mutagen, produced from green slimes. They are not targetted by slimes. + name = "Slimeperson" + id = "slime" + default_color = "00FFFF" + darksight = 3 + invis_sight = SEE_INVISIBLE_LEVEL_ONE + specflags = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR) + hair_color = "mutcolor" + hair_alpha = 150 + ignored_by = list(/mob/living/carbon/slime) + +/datum/species/jelly + // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them. + name = "Xenobiological Jelly Entity" + id = "jelly" + default_color = "00FF90" + say_mod = "chirps" + eyes = "jelleyes" + specflags = list(MUTCOLORS,EYECOLOR) + +/datum/species/golem + // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck. + name = "Golem" + id = "golem" + specflags = list(NOBREATH,HEATRES,COLDRES,NOGUNS,NOBLOOD,RADIMMUNE) + speedmod = 3 + armor = 55 + punchmod = 5 + no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_head, slot_w_uniform) + nojumpsuit = 1 + +/datum/species/golem/adamantine + name = "Adamantine Golem" + id = "adamantine" + +/datum/species/fly + // Humans turned into fly-like abominations in teleporter accidents. + name = "Human?" + id = "fly" + say_mod = "buzzes" + + handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "pestkiller") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 + + handle_speech(message) + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "z", stutter("zz")) + + return message + +/datum/species/skeleton + // 2spooky + name = "Spooky Scary Skeleton" + id = "skeleton" + sexes = 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index e09d39d53dd..c9edac17e1c 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -56,6 +56,7 @@ Please contact me on #coderbus IRC. ~Carnie x */ //Human Overlays Indexes///////// +#define SPECIES_LAYER 23 // mutantrace colors... these are on a seperate layer in order to prvent #define BODY_LAYER 22 //underwear, eyes, lips(makeup) #define MUTATIONS_LAYER 21 //Tk headglows etc. #define AUGMENTS_LAYER 20 @@ -78,28 +79,28 @@ Please contact me on #coderbus IRC. ~Carnie x #define L_HAND_LAYER 3 #define R_HAND_LAYER 2 //Having the two hands seperate seems rather silly, merge them together? It'll allow for code to be reused on mobs with arbitarily many hands #define FIRE_LAYER 1 //If you're on fire -#define TOTAL_LAYERS 22 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; +#define TOTAL_LAYERS 23 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; ////////////////////////////////// + /mob/living/carbon/human var/list/overlays_standing[TOTAL_LAYERS] /mob/living/carbon/human/proc/update_base_icon_state() - var/race = dna ? dna.mutantrace : null - switch(race) - if("lizard","golem","slime","shadow","adamantine","fly","plant") - base_icon_state = "[dna.mutantrace]_[(gender == FEMALE) ? "f" : "m"]" - if("skeleton") - base_icon_state = "skeleton" + //var/race = dna ? dna.mutantrace : null + if(dna) + base_icon_state = dna.species.update_base_icon_state(src) + else + if(HUSK in mutations) + base_icon_state = "husk" else - if(HUSK in mutations) - base_icon_state = "husk" - else - base_icon_state = "[skin_tone]_[(gender == FEMALE) ? "f" : "m"]" + base_icon_state = "[skin_tone]_[(gender == FEMALE) ? "f" : "m"]" + icon_state = "[base_icon_state]_s" /mob/living/carbon/human/proc/apply_overlay(cache_index) var/image/I = overlays_standing[cache_index] + if(I) overlays += I @@ -145,42 +146,11 @@ Please contact me on #coderbus IRC. ~Carnie x //Reset our hair remove_overlay(HAIR_LAYER) - //mutants don't have hair. masks and helmets can obscure our hair too. - if( (HUSK in mutations) || (dna && dna.mutantrace) || (head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR)) ) + if( (HUSK in mutations) || (head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR)) ) return - //base icons - var/datum/sprite_accessory/S - var/list/standing = list() - - if(facial_hair_style) - S = facial_hair_styles_list[facial_hair_style] - if(S) - var/image/img_facial_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) - - var/new_color = "#" + facial_hair_color - img_facial_s.color = new_color - - standing += img_facial_s - - //Applies the debrained overlay if there is no brain - if(!getorgan(/obj/item/organ/brain)) - standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER) - else if(hair_style) - S = hair_styles_list[hair_style] - if(S) - var/image/img_hair_s = image("icon" = S.icon, "icon_state" = "[S.icon_state]_s", "layer" = -HAIR_LAYER) - - var/new_color = "#" + hair_color - img_hair_s.color = new_color - - standing += img_hair_s - - if(standing.len) - overlays_standing[HAIR_LAYER] = standing - - apply_overlay(HAIR_LAYER) - + if(dna) + dna.species.handle_hair(src) /mob/living/carbon/human/update_mutations() remove_overlay(MUTATIONS_LAYER) @@ -188,6 +158,7 @@ Please contact me on #coderbus IRC. ~Carnie x var/list/standing = list() var/g = (gender == FEMALE) ? "f" : "m" + for(var/mut in mutations) switch(mut) if(HULK) @@ -203,41 +174,22 @@ Please contact me on #coderbus IRC. ~Carnie x apply_overlay(MUTATIONS_LAYER) +/mob/living/carbon/human/proc/update_mutcolor() + if(dna && !(HUSK in mutations)) + dna.species.update_color(src) /mob/living/carbon/human/proc/update_body() remove_overlay(BODY_LAYER) - update_base_icon_state() + if(dna) + base_icon_state = dna.species.update_base_icon_state(src) + else + update_base_icon_state() + icon_state = "[base_icon_state]_s" - var/list/standing = list() - - //Mouth (lipstick!) - if(lip_style) - standing += image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[lip_style]_s", "layer" = -BODY_LAYER) - - //Eyes - if(!dna || dna.mutantrace != "skeleton") - var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes_s", "layer" = -BODY_LAYER) - - var/new_color = "#" + eye_color - - img_eyes_s.color = new_color - - standing += img_eyes_s - - //Underwear - if(underwear) - var/datum/sprite_accessory/underwear/U = underwear_all[underwear] - if(U) - standing += image("icon"=U.icon, "icon_state"="[U.icon_state]_s", "layer"=-BODY_LAYER) - - - if(standing.len) - overlays_standing[BODY_LAYER] = standing - - apply_overlay(BODY_LAYER) - + if(dna) // didn't want to have a duplicate if(dna) here, but due to the ordering of the code this was the only way + dna.species.handle_body(src) /mob/living/carbon/human/update_fire() @@ -274,8 +226,6 @@ Please contact me on #coderbus IRC. ~Carnie x apply_overlay(AUGMENTS_LAYER) - - /* --------------------------------------- */ //For legacy support. /mob/living/carbon/human/regenerate_icons() @@ -305,6 +255,8 @@ Please contact me on #coderbus IRC. ~Carnie x update_transform() //Hud Stuff update_hud() + // Mutantrace colors + update_mutcolor() /* --------------------------------------- */ //vvvvvv UPDATE_INV PROCS vvvvvv @@ -322,16 +274,18 @@ Please contact me on #coderbus IRC. ~Carnie x var/t_color = w_uniform.item_color if(!t_color) t_color = icon_state var/image/standing = image("icon"='icons/mob/uniform.dmi', "icon_state"="[t_color]_s", "layer"=-UNIFORM_LAYER) + overlays_standing[UNIFORM_LAYER] = standing - var/G = (gender == FEMALE) ? "f" : "m" - if(G == "f" && U.fitted == 1) - var/index = "[t_color]_s" - var/icon/female_uniform_icon = female_uniform_icons[index] - if(!female_uniform_icon ) //Create standing/laying icons if they don't exist - generate_uniform(index,t_color) - standing = image("icon"=female_uniform_icons["[t_color]_s"], "layer"=-UNIFORM_LAYER) - overlays_standing[UNIFORM_LAYER] = standing + if(dna && dna.species.sexes) + var/G = (gender == FEMALE) ? "f" : "m" + if(G == "f" && U.fitted == 1) + var/index = "[t_color]_s" + var/icon/female_uniform_icon = female_uniform_icons[index] + if(!female_uniform_icon ) //Create standing/laying icons if they don't exist + generate_uniform(index,t_color) + standing = image("icon"=female_uniform_icons["[t_color]_s"], "layer"=-UNIFORM_LAYER) + overlays_standing[UNIFORM_LAYER] = standing if(w_uniform.blood_DNA) standing.overlays += image("icon"='icons/effects/blood.dmi', "icon_state"="uniformblood") @@ -375,6 +329,7 @@ Please contact me on #coderbus IRC. ~Carnie x if(gloves.blood_DNA) standing.overlays += image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands") + else if(blood_DNA) overlays_standing[GLOVES_LAYER] = image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands") @@ -532,7 +487,6 @@ Please contact me on #coderbus IRC. ~Carnie x if(wear_mask.blood_DNA && !istype(wear_mask, /obj/item/clothing/mask/cigarette)) standing.overlays += image("icon"='icons/effects/blood.dmi', "icon_state"="maskblood") - apply_overlay(FACEMASK_LAYER) @@ -628,7 +582,9 @@ Please contact me on #coderbus IRC. ~Carnie x apply_overlay(L_HAND_LAYER) + //Human Overlays Indexes///////// +#undef SPECIES_LAYER #undef BODY_LAYER #undef MUTATIONS_LAYER #undef DAMAGE_LAYER diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm index 3cfb35adffc..c045f843831 100644 --- a/code/modules/mob/living/carbon/metroid/life.dm +++ b/code/modules/mob/living/carbon/metroid/life.dm @@ -331,13 +331,10 @@ if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence targets += L // Possible target found! - if(isanimal(L) && (rabid || attacked || hungry >= 2)) //Simple_Animals only get retaliated against. - targets += L - - if(istype(L, /mob/living/carbon/human)) // Ignore slime(wo)men + if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men var/mob/living/carbon/human/H = L if(H.dna) - if(H.dna.mutantrace == "slime") + if(/mob/living/carbon/slime in H.dna.species.ignored_by) continue if(!L.canmove) // Only one slime can latch on at a time. @@ -568,4 +565,4 @@ if (hunger == 2 || rabid || attacked) return 1 if (Leader) return 0 if (holding_still) return 0 - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm index 3d1c6f8c70c..6f53f94d6de 100644 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ b/code/modules/mob/living/carbon/metroid/metroid.dm @@ -225,7 +225,7 @@ //paralysis += 1 - show_message(" The blob attacks you!") + show_message(" The blob attacks you!") adjustFireLoss(damage) @@ -237,7 +237,7 @@ return /mob/living/carbon/slime/attack_ui(slot) - return + return /mob/living/carbon/slime/attack_slime(mob/living/carbon/slime/M as mob) if (!ticker) @@ -248,10 +248,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" The [M.name] has glomped []!", src), 1) - + visible_message(" The [M.name] has glomped [src]!", \ + " The [M.name] has glomped [src]!") var/damage = rand(1, 3) attacked += 5 @@ -271,8 +269,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message(" [M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) attacked += 10 @@ -303,9 +301,8 @@ if (health > 0) attacked += 10 //playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [M.name] has attacked [src]!"), 1) + visible_message("[M.name] has attacked [src]!", \ + "[M.name] has attacked [src]!") adjustBruteLoss(rand(1, 3)) updatehealth() return @@ -325,15 +322,11 @@ if(Victim) if(Victim == M) if(prob(60)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] attempts to wrestle \the [name] off!", 1) + visible_message("[M] attempts to wrestle \the [name] off!") playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] manages to wrestle \the [name] off!", 1) + visible_message(" [M] manages to wrestle \the [name] off!") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if(prob(90) && !client) @@ -353,15 +346,11 @@ else if(prob(30)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] attempts to wrestle \the [name] off of [Victim]!", 1) + visible_message("[M] attempts to wrestle \the [name] off of [Victim]!") playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(" [M] manages to wrestle \the [name] off of [Victim]!", 1) + visible_message(" [M] manages to wrestle \the [name] off of [Victim]!") playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if(prob(80) && !client) @@ -400,9 +389,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") else @@ -426,17 +413,14 @@ playsound(loc, "punch", 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has punched []!", M, src), 1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attempted to punch []!", M, src), 1) + visible_message("[M] has attempted to punch [src]!") return @@ -452,9 +436,7 @@ switch(M.a_intent) if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message("[M] caresses [src] with its scythe like arm.") if ("harm") @@ -464,20 +446,17 @@ var/damage = rand(15, 30) if (damage >= 25) damage = rand(20, 40) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attacked [name]!", M), 1) + visible_message("[M] has attacked [name]!", \ + "[M] has attacked [name]!") else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has wounded [name]!", M), 1) + visible_message("[M] has wounded [name]!", \ + ")[M] has wounded [name]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has attempted to lunge at [name]!", M), 1) + visible_message("[M] has attempted to lunge at [name]!", \ + "[M] has attempted to lunge at [name]!") if ("grab") if (M == src || anchored) @@ -491,8 +470,7 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text(" [] has grabbed [name] passively!", M), 1) + visible_message(" [M] has grabbed [name] passively!") if ("disarm") playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) @@ -500,9 +478,8 @@ attacked += 10 if(prob(95)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has tackled [name]!", M), 1) + visible_message("[M] has tackled [name]!", \ + "[M] has tackled [name]!") if(Victim || Target) Victim = null @@ -527,9 +504,8 @@ else drop_item() - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text(" [] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [name]!", + "[M] has disarmed [name]!") adjustBruteLoss(damage) updatehealth() return @@ -538,7 +514,7 @@ if(W.force > 0) attacked += 10 if(prob(25)) - user << "\red [W] passes right through [src]!" + user << "[W] passes right through [src]!" return if(Discipline && prob(50)) // wow, buddy, why am I getting attacked?? Discipline = 0 @@ -847,6 +823,8 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 ////////Adamantine Golem stuff I dunno where else to put it +// This will eventually be removed. + /obj/item/clothing/under/golem name = "adamantine skin" desc = "a golem's skin" @@ -855,7 +833,6 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 item_color = "golem" flags = ABSTRACT | NODROP has_sensor = 0 - armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) /obj/item/clothing/suit/golem name = "adamantine shell" @@ -866,14 +843,8 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 gas_transfer_coefficient = 0.90 permeability_coefficient = 0.50 body_parts_covered = FULL_BODY - slowdown = 1.0 flags_inv = HIDEGLOVES | HIDESHOES | HIDEJUMPSUIT - flags = STOPSPRESSUREDMAGE | ABSTRACT | NODROP - heat_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS | HEAD - max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS | HEAD - min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - armor = list(melee = 80, bullet = 20, laser = 20, energy = 10, bomb = 0, bio = 0, rad = 0) + flags = ABSTRACT | NODROP /obj/item/clothing/shoes/golem name = "golem's feet" @@ -881,7 +852,6 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 icon_state = "golem" item_state = null flags = NOSLIP | ABSTRACT | NODROP - slowdown = SHOES_SLOWDOWN+1 /obj/item/clothing/mask/breath/golem @@ -891,7 +861,7 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 item_state = "golem" siemens_coefficient = 0 unacidable = 1 - flags = ABSTRACT | NODROP | MASKINTERNALS | MASKCOVERSMOUTH + flags = ABSTRACT | NODROP /obj/item/clothing/gloves/golem @@ -910,10 +880,7 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 name = "golem's head" desc = "a golem's head" unacidable = 1 - flags = STOPSPRESSUREDMAGE | ABSTRACT | NODROP - heat_protection = HEAD - max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT - armor = list(melee = 80, bullet = 20, laser = 20, energy = 10, bomb = 0, bio = 0, rad = 0) + flags = ABSTRACT | NODROP /obj/effect/golemrune anchored = 1 @@ -952,14 +919,9 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 return var/mob/living/carbon/human/G = new /mob/living/carbon/human if(prob(50)) G.gender = "female" - hardset_dna(G, null, null, null, "adamantine") + hardset_dna(G, null, null, null, null, /datum/species/golem/adamantine) G.real_name = text("Adamantine Golem ([rand(1, 1000)])") - G.equip_to_slot_or_del(new /obj/item/clothing/under/golem(G), slot_w_uniform) - G.equip_to_slot_or_del(new /obj/item/clothing/suit/golem(G), slot_wear_suit) - G.equip_to_slot_or_del(new /obj/item/clothing/shoes/golem(G), slot_shoes) - G.equip_to_slot_or_del(new /obj/item/clothing/mask/breath/golem(G), slot_wear_mask) - G.equip_to_slot_or_del(new /obj/item/clothing/gloves/golem(G), slot_gloves) - //G.equip_to_slot_or_del(new /obj/item/clothing/head/space/golem(G), slot_head) + G.dna.species.auto_equip(G) G.loc = src.loc G.key = ghost.key G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. Serve [user], and assist them in completing their goals at any cost." @@ -1047,9 +1009,9 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 /obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch() processing_objects.Remove(src) var/turf/T = get_turf(src) - src.visible_message("\blue The [name] pulsates and quivers!") + src.visible_message(" The [name] pulsates and quivers!") spawn(rand(50,100)) - src.visible_message("\blue The [name] bursts open!") + src.visible_message(" The [name] bursts open!") new/mob/living/carbon/slime(T) qdel(src) @@ -1065,4 +1027,4 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 return else ..() -*/ \ No newline at end of file +*/ diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index d1f94f76d29..e7492ba5f1c 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -77,8 +77,8 @@ if ((M.a_intent == "harm" && !( istype(wear_mask, /obj/item/clothing/mask/muzzle) ))) if ((prob(75) && health > 0)) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message("[M.name] bites [name]!", 1) + visible_message("[M.name] bites [name]!", \ + "[M.name] bites [name]!") var/damage = rand(1, 5) adjustBruteLoss(damage) health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() @@ -86,8 +86,8 @@ if(istype(D, /datum/disease/jungle_fever)) contract_disease(D,1,0) else - for(var/mob/O in viewers(src, null)) - O.show_message("[M.name] has attempted to bite [name]!", 1) + visible_message("[M.name] has attempted to bite [name]!", \ + "[M.name] has attempted to bite [name]!") return /mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M as mob) @@ -108,9 +108,8 @@ else if (M.a_intent == "harm") if (prob(75)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has punched [name]!", M), 1) + visible_message("[M] has punched [name]!", \ + "[M] has punched [name]!") playsound(loc, "punch", 25, 1, -1) var/damage = rand(5, 10) @@ -119,17 +118,15 @@ if ( (paralysis < 5) && (health > 0) ) Paralyse(rand(10, 15)) spawn( 0 ) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has knocked out [name]!", M), 1) + visible_message("[M] has knocked out [name]!", \ + "[M] has knocked out [name]!") return adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has attempted to punch [name]!", M), 1) + visible_message("[M] has attempted to punch [name]!", \ + "[M] has attempted to punch [name]!") else if (M.a_intent == "grab") if (M == src || anchored) @@ -144,22 +141,19 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has grabbed [name] passively!", M), 1) + visible_message("[M] has grabbed [name] passively!") else if (!( paralysis )) if (prob(25)) Paralyse(2) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has pushed down [name]!", M), 1) + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") else if(drop_item()) playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") return /mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M as mob) @@ -173,9 +167,7 @@ switch(M.a_intent) if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message(" [M] caresses [src] with its scythe like arm.") if ("harm") if ((prob(95) && health > 0)) @@ -185,20 +177,17 @@ damage = rand(20, 40) if (paralysis < 15) Paralyse(rand(10, 15)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has wounded [name]!", M), 1) + visible_message("[M] has wounded [name]!", \ + "[M] has wounded [name]!") else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has slashed [name]!", M), 1) + visible_message("[M] has slashed [name]!", \ + "[M] has slashed [name]!") adjustBruteLoss(damage) updatehealth() else playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has attempted to lunge at [name]!", M), 1) + visible_message("[M] has attempted to lunge at [name]!", \ + "[M] has attempted to lunge at [name]!") if ("grab") if (M == src || anchored) @@ -212,22 +201,19 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has grabbed [name] passively!", M), 1) + visible_message("[M] has grabbed [name] passively!") if ("disarm") playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) var/damage = 5 if(prob(95)) Weaken(10) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has tackled down [name]!", M), 1) + visible_message("[M] has tackled down [name]!", \ + "[M] has tackled down [name]!") else if(drop_item()) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("[] has disarmed [name]!", M), 1) + visible_message("[M] has disarmed [name]!", \ + "[M] has disarmed [name]!") adjustBruteLoss(damage) updatehealth() return @@ -238,8 +224,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("[M] [M.attacktext] [src]!", 1) + visible_message("[M] [M.attacktext] [src]!", \ + "[M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) @@ -255,9 +241,8 @@ if (health > -100) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("The [M.name] glomps []!", src), 1) + visible_message("The [M.name] glomps [src]!", \ + "The [M.name] glomps [src]!") var/damage = rand(1, 3) @@ -285,7 +270,8 @@ if(M.powerlevel < 0) M.powerlevel = 0 - visible_message("[M] shocked [src]!", "[M] shocked [src]!") + visible_message("[M] shocked [src]!", \ + "[M] shocked [src]!") Weaken(power) if (stuttering < power) @@ -343,6 +329,7 @@ /mob/living/carbon/monkey/blob_act() if (stat != 2) + show_message("The blob attacks you!") adjustFireLoss(60) health = 100 - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() if (prob(50)) @@ -360,4 +347,4 @@ return 0 /mob/living/carbon/monkey/canBeHandcuffed() - return 1 + return 1 diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 707e55f0602..d952a5be3f9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -431,11 +431,11 @@ qdel(I) if(C.handcuffed) - C.update_inv_handcuffed(0) C.handcuffed = null + C.update_inv_handcuffed(0) else - C.update_inv_legcuffed(0) C.legcuffed = null + C.update_inv_legcuffed(0) /mob/living/proc/cuff_resist(obj/item/I, mob/living/carbon/C) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index e492bb5d2fb..e903b7cef30 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -16,6 +16,8 @@ /mob/living/proc/getarmor(var/def_zone, var/type) return 0 +/mob/living/proc/on_hit(var/obj/item/projectile/proj_type) + return /mob/living/bullet_act(obj/item/projectile/P, def_zone) var/armor = run_armor_check(def_zone, P.flag) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 2ab4636438a..9506df68555 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -9,6 +9,7 @@ response_disarm = "flails at" response_harm = "punches" icon_dead = "shade_dead" + icon = 'icons/mob/mob.dmi' speed = 0 a_intent = "harm" stop_automated_movement = 1 @@ -25,6 +26,7 @@ minbodytemp = 0 faction = "cult" var/list/construct_spells = list() + var/playstyle_string = "You are a generic construct! Your job is to not exist." /mob/living/simple_animal/construct/New() ..() @@ -118,8 +120,7 @@ /mob/living/simple_animal/construct/armoured name = "Juggernaut" real_name = "Juggernaut" - desc = "A possessed suit of armour driven by the will of the restless dead" - icon = 'icons/mob/mob.dmi' + desc = "A possessed suit of armour driven by the will of the restless dead." icon_state = "behemoth" icon_living = "behemoth" maxHealth = 250 @@ -135,7 +136,8 @@ status_flags = 0 force_threshold = 11 construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) - + playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \ + create shield walls and even deflect energy weapons, and rip apart enemies and walls alike." /mob/living/simple_animal/construct/armoured/bullet_act(var/obj/item/projectile/P) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) @@ -174,7 +176,6 @@ name = "Wraith" real_name = "Wraith" desc = "A wicked bladed shell contraption piloted by a bound spirit" - icon = 'icons/mob/mob.dmi' icon_state = "floating" icon_living = "floating" maxHealth = 75 @@ -186,18 +187,16 @@ see_in_dark = 7 attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) + playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." /////////////////////////////Artificer///////////////////////// - - /mob/living/simple_animal/construct/builder name = "Artificer" real_name = "Artificer" desc = "A bulbous construct dedicated to building and maintaining The Cult of Nar-Sie's armies" - icon = 'icons/mob/mob.dmi' icon_state = "artificer" icon_living = "artificer" maxHealth = 50 @@ -215,60 +214,31 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/floor, /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, /obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser) + playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \ + use magic missile, repair allied constructs (by clicking on them), \ + and most important of all create new constructs \ + (Use your Artificer spell to summon a new construct shell and Summon Soulstone to create a new soulstone)." +/////////////////////////////Harvester///////////////////////// -/////////////////////////////Behemoth///////////////////////// +/mob/living/simple_animal/construct/harvester + name = "Harvester" + real_name = "Harvester" + desc = "A harbinger of Nar-Sie's enlightenment. It'll be all over soon." + icon_state = "harvester" + icon_living = "harvester" + maxHealth = 60 + health = 60 + melee_damage_lower = 1 + melee_damage_upper = 5 + attacktext = "prods" + speed = 0 + environment_smash = 1 + see_in_dark = 7 + attack_sound = 'sound/weapons/tap.ogg' + construct_spells = list(/obj/effect/proc_holder/spell/targeted/smoke/disable) + playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \ + Bring those who still cling to this world of illusion back to the Geometer so they may know Truth." - -/mob/living/simple_animal/construct/behemoth - name = "Behemoth" - real_name = "Behemoth" - desc = "The pinnacle of occult technology, Behemoths are the ultimate weapon in the Cult of Nar-Sie's arsenal." - icon = 'icons/mob/mob.dmi' - icon_state = "behemoth" - icon_living = "behemoth" - maxHealth = 750 - health = 750 - speak_emote = list("rumbles") - response_harm = "harmlessly punches" - harm_intent_damage = 0 - melee_damage_lower = 50 - melee_damage_upper = 50 - attacktext = "brutally crushes" - speed = 5 - environment_smash = 2 - attack_sound = 'sound/weapons/punch4.ogg' - force_threshold = 11 - var/energy = 0 - var/max_energy = 1000 - - -////////////////Powers////////////////// - - -/* -/client/proc/summon_cultist() - set category = "Behemoth" - set name = "Summon Cultist (300)" - set desc = "Teleport a cultist to your location" - if (istype(usr,/mob/living/simple_animal/constructbehemoth)) - - if(usr.energy<300) - usr << "\red You do not have enough power stored!" - return - - if(usr.stat) - return - - usr.energy -= 300 - var/list/mob/living/cultists = new - for(var/datum/mind/H in ticker.mode.cult) - if (istype(H.current,/mob/living)) - cultists+=H.current - var/mob/cultist = input("Choose the one who you want to summon", "Followers of Geometer") as null|anything in (cultists - usr) - if(!cultist) - return - if (cultist == usr) //just to be sure. - return - cultist.loc = usr.loc - usr.visible_message("/red [cultist] appears in a flash of red light as [usr] glows with power")*/ +/mob/living/simple_animal/construct/harvester/Process_Spacemove(var/check_drift = 0) + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 522122633b8..c65884dfc63 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -111,6 +111,11 @@ return 0 if(L in friends) return 0 + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.dna) + if(src.type in H.dna.species.ignored_by) + return 0 return 1 if(isobj(the_target)) if(the_target.type in wanted_objects) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index bf2a8a17afd..38916358259 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -245,8 +245,7 @@ return if(act) if(act == "scream") act = "makes a loud and pained whimper" //ugly hack to stop animals screaming when crushed :P - for (var/mob/O in viewers(src, null)) - O.show_message("[src] [act].") + visible_message("[src] [act].") /mob/living/simple_animal/attack_animal(mob/living/simple_animal/M as mob) @@ -255,8 +254,8 @@ else if(M.attack_sound) playsound(loc, M.attack_sound, 50, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("\red \The [M] [M.attacktext] [src]!", 1) + visible_message("\The [M] [M.attacktext] [src]!", \ + "\The [M] [M.attacktext] [src]!") add_logs(M, src, "attacked", admin=0) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) adjustBruteLoss(damage) @@ -276,9 +275,7 @@ if("help") if (health > 0) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\blue [M] [response_help] [src].") + visible_message(" [M] [response_help] [src].") if("grab") if (M == src || anchored) @@ -294,15 +291,11 @@ LAssailant = M - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if("harm", "disarm") adjustBruteLoss(harm_intent_damage) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\red [M] [response_harm] [src]!") + visible_message("[M] [response_harm] [src]!") return @@ -312,9 +305,7 @@ if ("help") - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1) + visible_message("[M] caresses [src] with its scythe like arm.") if ("grab") if(M == src || anchored) return @@ -329,13 +320,12 @@ LAssailant = M playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + visible_message("[M] has grabbed [src] passively!") if("harm", "disarm") var/damage = rand(15, 30) - visible_message("\red [M] has slashed at [src]!") + visible_message("[M] has slashed at [src]!", \ + "[M] has slashed at [src]!") adjustBruteLoss(damage) return @@ -344,13 +334,14 @@ switch(L.a_intent) if("help") - visible_message("\blue [L] rubs it's head against [src]") + visible_message("[L] rubs its head against [src].") else var/damage = rand(5, 10) - visible_message("\red [L] bites [src]!") + visible_message("[L] bites [src]!", \ + "[L] bites [src]!") if(stat != DEAD) L.amount_grown = min(L.amount_grown + damage, L.max_grown) @@ -364,7 +355,8 @@ if(M.Victim) return // can't attack while eating! - visible_message("\red [M.name] glomps [src]!") + visible_message("[M.name] glomps [src]!", \ + "[M.name] glomps [src]!") var/damage = rand(1, 3) @@ -391,18 +383,16 @@ MED.amount -= 1 if(MED.amount <= 0) qdel(MED) - for(var/mob/M in viewers(src, null)) - if ((M.client && !( M.blinded ))) - M.show_message("\blue [user] applies [MED] on [src]") + visible_message(" [user] applies [MED] on [src].") return else - user << "\blue [MED] won't help at all." + user << " [MED] won't help at all." return else - user << "\blue [src] is at full health." + user << " [src] is at full health." return else - user << "\blue [src] is dead, medical items won't bring it back to life." + user << " [src] is dead, medical items won't bring it back to life." return else if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead. if(istype(O, /obj/item/weapon/kitchenknife) || istype(O, /obj/item/weapon/butch)) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index e295e0b6553..25d81d559cb 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -420,6 +420,9 @@ proc/is_special_character(mob/M) // returns 1 for special characters and 2 for h var/list/hands = list(M.l_hand, M.r_hand) return hands +/mob/proc/reagent_check(var/datum/reagent/R) // utilized in the species code + return 1 + /proc/item_heal_robotic(var/mob/living/carbon/human/H, var/mob/user, var/brute, var/burn) var/obj/item/organ/limb/affecting = H.get_organ(check_zone(user.zone_sel.selecting)) @@ -442,4 +445,4 @@ proc/is_special_character(mob/M) // returns 1 for special characters and 2 for h user << "[H]'s [affecting.getDisplayName()] is already in good condition" return else - return \ No newline at end of file + return diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 6badea404f5..17df645d3aa 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -12,6 +12,7 @@ datum/preferences hair_color = random_short_color() facial_hair_color = hair_color eye_color = random_eye_color() + pref_species = new /datum/species/human() backbag = 2 age = rand(AGE_MIN,AGE_MAX) @@ -23,7 +24,11 @@ datum/preferences var/g = "m" if(gender == FEMALE) g = "f" - preview_icon = new /icon('icons/mob/human.dmi', "[skin_tone]_[g]_s") + if(pref_species.id == "human" || !config.mutant_races) + preview_icon = new /icon('icons/mob/human.dmi', "[skin_tone]_[g]_s") + else + preview_icon = new /icon('icons/mob/human.dmi', "[pref_species.id]_[g]_s") + preview_icon.Blend("#[mutant_color]", ICON_MULTIPLY) var/datum/sprite_accessory/S if(underwear) @@ -31,17 +36,19 @@ datum/preferences if(S) preview_icon.Blend(new /icon(S.icon, "[S.icon_state]_s"), ICON_OVERLAY) - var/icon/eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes_s") - eyes_s.Blend("#[eye_color]", ICON_MULTIPLY) + var/icon/eyes_s = new/icon() + if(EYECOLOR in pref_species.specflags) + eyes_s = new/icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[pref_species.eyes]_s") + eyes_s.Blend("#[eye_color]", ICON_MULTIPLY) S = hair_styles_list[hair_style] - if(S) + if(S && (HAIR in pref_species.specflags)) var/icon/hair_s = new/icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s") hair_s.Blend("#[hair_color]", ICON_MULTIPLY) eyes_s.Blend(hair_s, ICON_OVERLAY) S = facial_hair_styles_list[facial_hair_style] - if(S) + if(S && (FACEHAIR in pref_species.specflags)) var/icon/facial_s = new/icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s") facial_s.Blend("#[facial_hair_color]", ICON_MULTIPLY) eyes_s.Blend(facial_s, ICON_OVERLAY) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 03fb40fb3a9..dae51d0cc97 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -131,6 +131,12 @@ O.gender = (deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE O.dna = dna + + if(!dna.species) + O.dna.species = new /datum/species/human() + else + O.dna.species = new dna.species.type() + dna = null if (newname) //if there's a name as an argument, always take that one over the current name O.real_name = newname @@ -473,20 +479,8 @@ if(!MP) return 0 //Sanity, this should never happen. -// if(ispath(MP, /mob/living/simple_animal/space_worm)) //Goodbye Space Worms 2014 -// return 0 //Unfinished. Very buggy, they seem to just spawn additional space worms everywhere and eating your own tail results in new worms spawning. - - if(ispath(MP, /mob/living/simple_animal/construct/behemoth)) - return 0 //I think this may have been an unfinished WiP or something. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/armoured)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/wraith)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype - - if(ispath(MP, /mob/living/simple_animal/construct/builder)) - return 0 //Verbs do not appear for players. These constructs should really have their own class simple_animal/construct/subtype + if(ispath(MP, /mob/living/simple_animal/construct)) + return 0 //Verbs do not appear for players. //Good mobs! if(ispath(MP, /mob/living/simple_animal/cat)) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 95bb4dec398..e49459293f1 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -350,11 +350,13 @@ var/const/GRAV_NEEDS_WRENCH = 3 // Shake everyone on the z level to let them know that gravity was enagaged/disenagaged. /obj/machinery/gravity_generator/main/proc/shake_everyone() var/turf/our_turf = get_turf(src) - for(var/mob/M in player_list) + for(var/mob/M in mob_list) var/turf/their_turf = get_turf(M) - if(M.client && their_turf.z == our_turf.z) - shake_camera(M, 15, 1) - M.playsound_local(our_turf, 'sound/effects/alert.ogg', 100, 1, 0.5) + if(their_turf.z == our_turf.z) + M.update_gravity(M.mob_has_gravity()) + if(M.client) + shake_camera(M, 15, 1) + M.playsound_local(our_turf, 'sound/effects/alert.ogg', 100, 1, 0.5) /obj/machinery/gravity_generator/main/proc/gravity_in_level() var/turf/T = get_turf(src) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index a0725f79ee5..3d2c161a28f 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -1,10 +1,5 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 -var/global/list/uneatable = list( - /turf/space, - /obj/effect/overlay - ) - /obj/machinery/singularity name = "gravitational singularity" desc = "A gravitational singularity." @@ -32,6 +27,7 @@ var/global/list/uneatable = list( var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/teleport_del = 0 var/last_warning + var/list/uneatable = list(/turf/space, /obj/effect/overlay) /obj/machinery/singularity/New(loc, var/starting_energy = 50, var/temp = 0) //CARN: admin-alert for chuckle-fuckery. @@ -477,6 +473,7 @@ var/global/list/uneatable = list( move_self = 1 //Do we move on our own? grav_pull = 5 //How many tiles out do we pull? consume_range = 6 //How many tiles out do we eat + uneatable = list(/turf/space, /obj/effect/overlay, /mob/living/simple_animal/construct) /obj/machinery/singularity/narsie/large name = "Nar-Sie" @@ -496,6 +493,12 @@ var/global/list/uneatable = list( if(emergency_shuttle) emergency_shuttle.incall(0.3) // Cannot recall + +/obj/machinery/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) + makeNewConstruct(/mob/living/simple_animal/construct/harvester, user, null, 1) + new /obj/effect/effect/sleep_smoke(user.loc) + + /obj/machinery/singularity/narsie/process() eat() if(!target || prob(5)) @@ -538,8 +541,11 @@ var/global/list/uneatable = list( if(istype(A,/mob/living/)) var/mob/living/C = A + if(C.client) + makeNewConstruct(/mob/living/simple_animal/construct/harvester, C, null, 1) C.spawn_dust() C.gib() + return if(isturf(A)) var/turf/T = A @@ -550,35 +556,33 @@ var/global/list/uneatable = list( if(prob(20)) T.ChangeTurf(/turf/simulated/wall/cult) return + /obj/machinery/singularity/narsie/ex_act() //No throwing bombs at it either. --NEO return + /obj/machinery/singularity/narsie/proc/pickcultist() //Narsie rewards his cultists with being devoured first, then picks a ghost to follow. --NEO var/list/cultists = list() - for(var/datum/mind/cult_nh_mind in ticker.mode.cult) - if(!cult_nh_mind.current) - continue - if(cult_nh_mind.current.stat) - continue - var/turf/pos = get_turf(cult_nh_mind.current) - if(pos.z != src.z) - continue - cultists += cult_nh_mind.current - if(cultists.len) - acquire(pick(cultists)) - return - //If there was living cultists, it picks one to follow. - for(var/mob/living/carbon/human/food in living_mob_list) - if(food.stat) - continue + var/list/noncultists = list() + for(var/mob/living/carbon/food in living_mob_list) //we don't care about constructs or cult-Ians or whatever. cult-monkeys are fair game i guess var/turf/pos = get_turf(food) if(pos.z != src.z) continue - cultists += food - if(cultists.len) - acquire(pick(cultists)) - return - //no living cultists, pick a living human instead. + + if(iscultist(food)) + cultists += food + else + noncultists += food + + if(cultists.len) //cultists get higher priority + acquire(pick(cultists)) + return + + if(noncultists.len) + acquire(pick(noncultists)) + return + + //no living humans, follow a ghost instead. for(var/mob/dead/observer/ghost in player_list) if(!ghost.client) continue @@ -589,7 +593,7 @@ var/global/list/uneatable = list( if(cultists.len) acquire(pick(cultists)) return - //no living humans, follow a ghost instead. + /obj/machinery/singularity/narsie/proc/acquire(var/mob/food) target << "\blue NAR-SIE HAS LOST INTEREST IN YOU" diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 7d79eaeb7de..ea2a9a8c73e 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -80,8 +80,8 @@ return if(ishuman(user)) var/mob/living/carbon/human/H = user - if(H.dna && H.dna.mutantrace == "adamantine") - user << "Your metal fingers don't fit in the trigger guard!" + if(H.dna && NOGUNS in H.dna.species.specflags) + user << "Your fingers don't fit in the trigger guard!" return add_fingerprint(user) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 988d947a13e..f1ee2f12a74 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -33,20 +33,24 @@ /obj/item/weapon/gun/energy/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, params) - newshot() + newshot() //prepare a new shot ..() /obj/item/weapon/gun/energy/proc/newshot() - if (!ammo_type || !power_supply) return + if (!ammo_type || !power_supply) + return var/obj/item/ammo_casing/energy/shot = ammo_type[select] - if (!power_supply.use(shot.e_cost)) return - chambered = shot - chambered.newshot() + if(power_supply.charge >= shot.e_cost) //if there's enough power in the power_supply cell... + chambered = shot //...prepare a new shot based on the current ammo type selected + chambered.newshot() return /obj/item/weapon/gun/energy/process_chamber() - chambered = null + if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... + var/obj/item/ammo_casing/energy/shot = chambered + power_supply.use(shot.e_cost)//... drain the power_supply cell + chambered = null //either way, released the prepared shot return /obj/item/weapon/gun/energy/proc/select_fire(mob/living/user as mob) @@ -56,7 +60,7 @@ var/obj/item/ammo_casing/energy/shot = ammo_type[select] fire_sound = shot.fire_sound if (shot.select_name) - user << "\red [src] is now set to [shot.select_name]." + user << "[src] is now set to [shot.select_name]." update_icon() return diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 6fc8094d59f..afd7bf263ab 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -58,6 +58,7 @@ if(!isliving(target)) return 0 if(isanimal(target)) return 0 var/mob/living/L = target + L.on_hit(type) return L.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, blocked) proc/vol_by_damage() diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index e65431d7ad7..2efdbab093b 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -199,8 +199,12 @@ proc/wabbajack(mob/living/M) var/mob/living/carbon/human/H = new_mob ready_dna(H) if(H.dna) - H.dna.mutantrace = pick("lizard","golem","slime","plant","fly","shadow","adamantine","skeleton",8;"") - H.update_body() + var/list/randspecies = list() + for(var/t in typesof(/datum/species)) // returns a bunch of types + var/datum/species/temp = new t() + randspecies += "[temp.type]" + var/datum/species/new_species = pick(randspecies) + H.dna.species = new new_species() else return diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index afe46c110e3..e067b00b949 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -82,32 +82,8 @@ flag = "energy" on_hit(var/atom/target, var/blocked = 0) - if(iscarbon(target)) - var/mob/living/carbon/M = target - if(check_dna_integrity(M) && M.dna.mutantrace == "plant") //Plantmen possibly get mutated and damaged by the rays. - if(prob(15)) - M.apply_effect((rand(30,80)),IRRADIATE) - M.Weaken(5) - for (var/mob/V in viewers(src)) - V.show_message("\red [M] writhes in pain as \his vacuoles boil.", 3, "\red You hear the crunching of leaves.", 2) - if(prob(35)) - // for (var/mob/V in viewers(src)) //Public messages commented out to prevent possible metaish genetics experimentation and stuff. - Cheridan - // V.show_message("\red [M] is mutated by the radiation beam.", 3, "\red You hear the snapping of twigs.", 2) - if(prob(80)) - randmutb(M) - domutcheck(M,null) - else - randmutg(M) - domutcheck(M,null) - else - M.adjustFireLoss(rand(5,15)) - M.show_message("\red The radiation beam singes you!") - // for (var/mob/V in viewers(src)) - // V.show_message("\red [M] is singed by the radiation beam.", 3, "\red You hear the crackle of burning leaves.", 2) - else - // for (var/mob/V in viewers(src)) - // V.show_message("The radiation beam dissipates harmlessly through [M]", 3) - M.show_message("\blue The radiation beam dissipates harmlessly through your body.") + ..() + return /obj/item/projectile/energy/florayield name = "beta somatoray" @@ -117,14 +93,9 @@ nodamage = 1 flag = "energy" - on_hit(mob/living/carbon/target, var/blocked = 0) - if(iscarbon(target)) - if(ishuman(target) && target.dna && target.dna.mutantrace == "plant") //These rays make plantmen fat. - target.nutrition = min(target.nutrition+30, 500) - else - target.show_message("\blue The radiation beam dissipates harmlessly through your body.") - else - return 1 + on_hit(mob/living/carbon/human/target, var/blocked = 0) + ..() + return /obj/item/projectile/beam/mindflayer diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index a675580369a..4eec5cad53a 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -200,7 +200,9 @@ datum for(var/A in reagent_list) var/datum/reagent/R = A if(M && R) - R.on_mob_life(M) + if(M.reagent_check(R) != 1) + R.on_mob_life(M) + update_total() conditional_update_move(var/atom/A, var/Running = 0) diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index e7a8c57b042..ef9f736fa34 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -342,18 +342,6 @@ datum reagent_state = LIQUID color = "#13BC5E" // rgb: 19, 188, 94 - on_mob_life(var/mob/living/M as mob) - if(!M) M = holder.my_atom - if(ishuman(M)) - var/mob/living/carbon/human/human = M - if(human.dna && !human.dna.mutantrace) - M << "Your flesh rapidly mutates!" - human.dna.mutantrace = "slime" - human.update_body() - human.update_hair() - ..() - return - aslimetoxin name = "Advanced Mutation Toxin" id = "amutationtoxin" @@ -1507,11 +1495,6 @@ datum var/mob/living/carbon/C = M if(!C.wear_mask) // If not wearing a mask C.adjustToxLoss(2) // 4 toxic damage per application, doubled for some reason - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.dna) - if(H.dna.mutantrace == "plant") //plantmen take a LOT of damage - H.adjustToxLoss(10) toxin/plantbgone/weedkiller name = "Weed Killer" @@ -1534,11 +1517,6 @@ datum var/mob/living/carbon/C = M if(!C.wear_mask) // If not wearing a mask C.adjustToxLoss(2) // 4 toxic damage per application, doubled for some reason - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.dna) - if(H.dna.mutantrace == "fly") //Botanists can now genocide plant and fly people alike. - H.adjustToxLoss(10) toxin/stoxin name = "Sleep Toxin" diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index e23270bafc3..0f630190c1a 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -62,9 +62,9 @@ var/who = (isnull(user) || eater == user) ? "your" : "their" if(istype(cover, /obj/item/clothing/mask/)) - user << "You have to remove [who] mask first!" + user << "You have to remove [who] mask first!" else - user << "You have to remove [who] helmet first!" + user << "You have to remove [who] helmet first!" return 0 - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 7d8ae71c443..697a96fc5bd 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -59,6 +59,12 @@ return if(ismob(target)) //Blood! + if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.dna) + if(NOBLOOD in H.dna.species.specflags) + user << "You are unable to locate any blood." + return if(reagents.has_reagent("blood")) user << "There is already a blood sample in this syringe." return diff --git a/config/game_options.txt b/config/game_options.txt index b9ca7e763ca..9ba5daa2914 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -187,5 +187,9 @@ SEC_START_BRIG ## Set to 2 for "random", silicons will start with a random lawset picked from (at the time of writing): P.A.L.A.D.I.N., Corporate, Asimov. More can be added by changing the law datum paths in ai_laws.dm. DEFAULT_LAWS 1 -## Uncoment to give players the choice of their mutantrace before they join the game -#JOIN_WITH_MUTANT_RACE \ No newline at end of file +## Uncoment to give players the choice of their species before they join the game +#JOIN_WITH_MUTANT_RACE + +## Uncomment to allow certain species to have custom colors + +#MUTANT_COLORS \ No newline at end of file diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index efbb59c0fd7c78ed5e5b5e9a7cb1a2c69d4d7fe5..8b586b4fab90982346399e6671a1c806d2086a5d 100644 GIT binary patch delta 43932 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 Rq=15dMyJg5%5?0){~y=o4`=`Y delta 45042 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 diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 9e2059cafbe1e3326a8b203ad8548c3843d775fd..7b9629e0de8b0ac4c926a794315b4e6e108127a5 100644 GIT binary patch literal 31661 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 L^LBxf$*cbb`l+}) literal 30991 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 z zG6@hJUEMQw-lX1pPOeEw;$f(g?lF(kG`8#4RSOLE=uh+tmiy!Fi3aHvqwQ_xca^Yf z0-<1_-?5)%edq>tyj#t+I%!wI*{y0$R6C4AHcQVegS!@q>zQjBo0EI8L|#b#wbPFn zv6ba0k4rXK)uQ^)F;)*h?E8*Jc8LTBFst5dt2T~wNqjo3Cfo1dpTohRmt;8Tot=?V z?u`gc}uRqI%DD#*o=?ox->PW@&SzXYacRHD*^^+l~PNt(@zQ2F)Si^^@AvCPgND168=K zuPPP6CkqtK8TU7PMI``p!xap1Ezj`@BguJenie_B7kcXOMPl-)Cw62E7VR6U`t`}H zXD$|D+Mh2SBah8QKmi284R2WS`w$L^btYH^&bK={UJ|GO-R)(e+ZFld^FaENN_;4G zx0|aG#B(6&wYj+oZiJ=zAvgCXX6C2I8U}M*AJ*POaw4YG-lp1eX=W=5@uy-qBDj2I z-%mGUa%H(diWRZpla_r+OpB|NwkQgeZepMv@tP@cU-7E@; zx&u#q*s)AMSSViJ@W-F|-X;(C-kgz-XOX%B4+jY~S1HNq%dy3bv`tTHC-;EnL#-^VGS^wT+N}lWUBg~2wnrY!*>nY8ccp#g7CTfPp7{J{ml%5bT7(o0! zGble$9T5%zRMvZ?w?mVL4Zxn?#SXqyrWB_o`|zLN|L~T}Z;boiyYJome(d$_HOF4xH@>~+nq%(u_=d?yqed?-nhDcl=9S^ak?39gyW(~hJn!ijo9JX-x;r2}G)=OC5t2Uq0w=eC^imwWs z(VQh{OzjzZw-YTp&Jsk&VkLolAA|J^@0SPaC*Cjj*Y~_%j?=$>e3W&*no1RSP!BVX zLn4K*AAx!6-K%9fpn(8z5^AWYeKX+YYId+MawNO0QLfa5*7O3Z6K(D+QP=X#+j=S1j-}@nXB|HY$>qn- zG@+R8l5Ol||7jD9`1(n^^x4JbyWNvoE-H%c+9esw{WQ%5ib3YH?fM3K=z`{ak5BZO zt55JE+X?Np0CO`E4ZQJe2cnBb!JIX*2n>bqAAsSE9o{Wqz^u3BLHNz{Tn2<~XKgv? zZ$L9}=f-HL;Dw&Di!o;t=tu)Cm7QF4Q%~Z098LuAs=N0thi9XsFmA*DThlN^;Eq99e_2Ufn=#qqg=$K4{Pyi*R2zGH<;w`*fw4R0C!9gs{L+33ITqb->t9ggI z$1_y@EX>l9*A{l6YH7ktacFtQCbVK%^kqZ0D=`r^TL=>+wPIspVpfDRJxV6%WoMWB zr^Z>YIuLT~UhnSu?XC-6EuNrT*~@y}zFs zT@@dU%h!$WpL?l$$%^#e=@C5_z~4_<*BRSBH2l5D2`oP)n!=8sFj1KO9J8gr$K!91 zPzk{DvhTf5k^=A%0~+nNGS0r!zk2he!kER5eh#MW>se*ol`@}pYpx3trvLB|V%%yk z@n4jblTN;( zz<~F|n>X5<6(SiZRF@ZfxY$ZdYvNl|s_e;6AQmyyo4LM!!IS?(oc{;FL#0$LRcBfa zJuC(_0z0|jE&!W3q4o~>LF5hc$Q}Q}RFsWWJD_(nnrZrIW=F-m!r*3_-me}Gtqe(3 z%g&`o2LeYr?8h(uoISZVK+p#kfau;++$aXyYf0wn zdsB_f)ACN+2cPPkylnQd0$2J(>cD+9cO=hC-}7d^??g(ozDamubh#X#rwNoxSHq9T zrlZ&%()7PXIZhqSNbp}-(6<3?!0~by^G*ZbHT^{iV;|PccYTVlc~dWHn9T20eZ&q+ z&#iME)Xaq6{bhP${+LY3xApf3s{Wcd93oXUj)Von<~-I1DX@sM_pYtgTvv{RG6N zLOQV;l*Cw*t_->LufjCeoKAMT+qX~o9WF-+zmYZ$*Cz`Cnk6sUmU*FPa$`$ye&3{?P>M=bR4eiD#3MQIi)fo|06vN9y_ zQRUc-HajwF4bkD`LpQ}F^2Xp$d$0fg8}Utx5X(@OmVBfHSxBHok9UdlOLE_LJF$9Q zU8BV;G?J<rp7R%0ALjk+`_6Nh+04R%xVu&a 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 literal 2454 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 XVF?PtovKnk{IriDQ$d6LN$r0D?V@a) literal 0 HcmV?d00001 diff --git a/tgstation.dme b/tgstation.dme index 86fb4497c89..c01bdc15e3a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -963,6 +963,8 @@ #include "code\modules\mob\living\carbon\human\life.dm" #include "code\modules\mob\living\carbon\human\login.dm" #include "code\modules\mob\living\carbon\human\say.dm" +#include "code\modules\mob\living\carbon\human\species.dm" +#include "code\modules\mob\living\carbon\human\species_types.dm" #include "code\modules\mob\living\carbon\human\update_icons.dm" #include "code\modules\mob\living\carbon\human\whisper.dm" #include "code\modules\mob\living\carbon\metroid\death.dm" From 9d1659219efcee44b64b8d16a862c8ec89b13b7f Mon Sep 17 00:00:00 2001 From: CollenN Date: Fri, 20 Jun 2014 06:52:58 -0400 Subject: [PATCH 2/4] Encapsulates if() statement Profakos pointed this out --- code/modules/client/preferences_savefile.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 93c33b755be..33768cb04c7 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -73,7 +73,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(11) underwear = "Ladies Kinky" if(12) underwear = "Tankini" if(13) underwear = "Nude" - if(!pref_species in species_list) + if(!(pref_species in species_list)) pref_species = new /datum/species/human() return @@ -192,9 +192,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Sanitize metadata = sanitize_text(metadata, initial(metadata)) real_name = reject_bad_name(real_name) - if(!pref_species in species_list) + if(!(pref_species in species_list)) pref_species = new /datum/species/human() - world << "[pref_species] is the species" if(!real_name) real_name = random_name(gender) be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) gender = sanitize_gender(gender) From 0a173f10ddc73a55d30c605dc2537bdfa3d174be Mon Sep 17 00:00:00 2001 From: CollenN Date: Fri, 20 Jun 2014 17:19:00 -0400 Subject: [PATCH 3/4] Aaaaaaaaaaaaaaarghhhhh IN MY DEFENSE, you can't actually be set on fire in the first place if you have HEATRES or NOFIRE in your specflags, so it was easy for me to overlook this one. This is really more of an issue with BYOND than anything else. --- code/modules/mob/living/carbon/human/species.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 64fad2b5de4..97143b147b1 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1276,7 +1276,7 @@ ////////// proc/handle_fire(var/mob/living/carbon/human/H) - if(HEATRES in specflags || NOFIRE in specflags) + if((HEATRES in specflags) || (NOFIRE in specflags)) return if(H.fire_stacks < 0) H.fire_stacks++ //If we've doused ourselves in water to avoid fire, dry off slowly From 56eb50938b9615c192f9e08671f190b47c1aaf1b Mon Sep 17 00:00:00 2001 From: CollenN Date: Fri, 20 Jun 2014 21:35:48 -0400 Subject: [PATCH 4/4] Added some of Cheridan's suggestions *Removed 'Make 2spooky' admin command *You can still gib even if you don't have DNA *species_types now uses absolute pathing (probably not gonna do the same for species.dm, mainly because with such a large file it strikes me as practical to keep the paths relative) --- code/datums/datumvars.dm | 12 -- code/modules/mob/living/carbon/human/death.dm | 2 + .../mob/living/carbon/human/species_types.dm | 192 +++++++++++------- 3 files changed, 120 insertions(+), 86 deletions(-) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 831de1e8858..7477a1bea43 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -249,7 +249,6 @@ client body += "" body += "" body += "" - body += "" body += "" body += "" if(ishuman(D)) @@ -581,17 +580,6 @@ client if(usr.client) usr.client.cmd_assume_direct_control(M) - else if(href_list["make_skeleton"]) - if(!check_rights(R_FUN)) return - - var/mob/living/carbon/human/H = locate(href_list["make_skeleton"]) - if(!istype(H)) - usr << "This can only be used on instances of type /mob/living/carbon/human" - return - - H.makeSkeleton() - href_list["datumrefresh"] = href_list["make_skeleton"] - else if(href_list["delall"]) if(!check_rights(R_DEBUG|R_SERVER)) return diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 380d0de4cc3..045ca305efa 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -10,6 +10,8 @@ /mob/living/carbon/human/spawn_gibs() if(dna) hgibs(loc, viruses, dna) + else + hgibs(loc, viruses, null) /mob/living/carbon/human/spawn_dust() new /obj/effect/decal/remains/human(loc) diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index 1e2d538fad3..7d159238fc5 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -1,3 +1,7 @@ +/* + HUMANS +*/ + /datum/species/human name = "Human" id = "human" @@ -5,13 +9,17 @@ specflags = list(EYECOLOR,HAIR,FACEHAIR,LIPS) use_skintones = 1 - handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - if(chem.id == "mutationtoxin") - H << "Your flesh rapidly mutates!" - H.dna.species = new /datum/species/slime() - H.regenerate_icons() - H.reagents.del_reagent(chem.type) - return 1 +/datum/species/human/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "mutationtoxin") + H << "Your flesh rapidly mutates!" + H.dna.species = new /datum/species/slime() + H.regenerate_icons() + H.reagents.del_reagent(chem.type) + return 1 + +/* + LIZARDPEOPLE +*/ /datum/species/lizard // Reptilian humanoids with scaled skin and tails. @@ -25,12 +33,16 @@ attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' - handle_speech(message) - // jesus christ why - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "s", stutter("ss")) +/datum/species/lizard/handle_speech(message) + // jesus christ why + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "s", stutter("ss")) - return message + return message + +/* + PLANTPEOPLE +*/ /datum/species/plant // Creatures made of leaves and plant matter. @@ -44,56 +56,64 @@ burnmod = 1.25 heatmod = 1.5 - handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - if(chem.id == "plantbgone") - H.adjustToxLoss(3) - H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) - return 1 +/datum/species/plant/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "plantbgone") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 - on_hit(proj_type, mob/living/carbon/human/H) - switch(proj_type) - if(/obj/item/projectile/energy/floramut) - if(prob(15)) - H.apply_effect((rand(30,80)),IRRADIATE) - H.Weaken(5) - for (var/mob/V in viewers(H)) - V.show_message("[H] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) - if(prob(80)) - randmutb(H) - domutcheck(H,null) - else - randmutg(H) - domutcheck(H,null) +/datum/species/plant/on_hit(proj_type, mob/living/carbon/human/H) + switch(proj_type) + if(/obj/item/projectile/energy/floramut) + if(prob(15)) + H.apply_effect((rand(30,80)),IRRADIATE) + H.Weaken(5) + for (var/mob/V in viewers(H)) + V.show_message("[H] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) + if(prob(80)) + randmutb(H) + domutcheck(H,null) else - H.adjustFireLoss(rand(5,15)) - H.show_message("The radiation beam singes you!") - if(/obj/item/projectile/energy/florayield) - H.nutrition = min(H.nutrition+30, 500) - return + randmutg(H) + domutcheck(H,null) + else + H.adjustFireLoss(rand(5,15)) + H.show_message("The radiation beam singes you!") + if(/obj/item/projectile/energy/florayield) + H.nutrition = min(H.nutrition+30, 500) + return + +/* + PODPEOPLE +*/ /datum/species/plant/pod // A mutation caused by a human being ressurected in a revival pod. These regain health in light, and begin to wither in darkness. name = "Podperson" id = "pod" - spec_life(mob/living/carbon/human/H) - var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing - if(isturf(H.loc)) //else, there's considered to be no light - var/turf/T = H.loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 - else light_amount = 5 - H.nutrition += light_amount - if(H.nutrition > 500) - H.nutrition = 500 - if(light_amount > 2) //if there's enough light, heal - H.heal_overall_damage(1,1) - H.adjustToxLoss(-1) - H.adjustOxyLoss(-1) +/datum/species/plant/pod/spec_life(mob/living/carbon/human/H) + var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing + if(isturf(H.loc)) //else, there's considered to be no light + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = min(10,T.lighting_lumcount) - 5 + else light_amount = 5 + H.nutrition += light_amount + if(H.nutrition > 500) + H.nutrition = 500 + if(light_amount > 2) //if there's enough light, heal + H.heal_overall_damage(1,1) + H.adjustToxLoss(-1) + H.adjustOxyLoss(-1) - if(H.nutrition < 200) - H.take_overall_damage(2,0) + if(H.nutrition < 200) + H.take_overall_damage(2,0) + +/* + SHADOWPEOPLE +*/ /datum/species/shadow // Humans cursed to stay in the darkness, lest their life forces drain. They regain health in shadow and die in light. @@ -103,18 +123,22 @@ sexes = 0 ignored_by = list(/mob/living/simple_animal/hostile/faithless) - spec_life(mob/living/carbon/human/H) - var/light_amount = 0 - if(isturf(H.loc)) - var/turf/T = H.loc - var/area/A = T.loc - if(A) - if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount - else light_amount = 10 - if(light_amount > 2) //if there's enough light, start dying - H.take_overall_damage(1,1) - else if (light_amount < 2) //heal in the dark - H.heal_overall_damage(1,1) +/datum/species/shadow/spec_life(mob/living/carbon/human/H) + var/light_amount = 0 + if(isturf(H.loc)) + var/turf/T = H.loc + var/area/A = T.loc + if(A) + if(A.lighting_use_dynamic) light_amount = T.lighting_lumcount + else light_amount = 10 + if(light_amount > 2) //if there's enough light, start dying + H.take_overall_damage(1,1) + else if (light_amount < 2) //heal in the dark + H.heal_overall_damage(1,1) + +/* + SLIMEPEOPLE +*/ /datum/species/slime // Humans mutated by slime mutagen, produced from green slimes. They are not targetted by slimes. @@ -128,6 +152,10 @@ hair_alpha = 150 ignored_by = list(/mob/living/carbon/slime) +/* + JELLYPEOPLE +*/ + /datum/species/jelly // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them. name = "Xenobiological Jelly Entity" @@ -137,6 +165,10 @@ eyes = "jelleyes" specflags = list(MUTCOLORS,EYECOLOR) +/* + GOLEMS +*/ + /datum/species/golem // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck. name = "Golem" @@ -148,27 +180,39 @@ no_equip = list(slot_wear_mask, slot_wear_suit, slot_gloves, slot_shoes, slot_head, slot_w_uniform) nojumpsuit = 1 +/* + ADAMANTINE GOLEMS +*/ + /datum/species/golem/adamantine name = "Adamantine Golem" id = "adamantine" +/* + FLIES +*/ + /datum/species/fly // Humans turned into fly-like abominations in teleporter accidents. name = "Human?" id = "fly" say_mod = "buzzes" - handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) - if(chem.id == "pestkiller") - H.adjustToxLoss(3) - H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) - return 1 +/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + if(chem.id == "pestkiller") + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM) + return 1 - handle_speech(message) - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "z", stutter("zz")) +/datum/species/fly/handle_speech(message) + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "z", stutter("zz")) - return message + return message + +/* + SKELETONS +*/ /datum/species/skeleton // 2spooky