From 9fcde12b4ff6ce5155919907ad85c3fcf3e6714d Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sun, 28 Sep 2014 01:21:36 +0930 Subject: [PATCH 01/16] Organ rewrite mapclean attempt. --- baystation12.dme | 9 +- code/ZAS/Phoron.dm | 16 +- code/controllers/hooks-defs.dm | 2 +- code/datums/diseases/appendicitis.dm | 3 +- code/datums/spells/inflict_handler.dm | 4 +- code/game/gamemodes/cult/runes.dm | 4 +- .../mutiny/directives/ipc_virus_directive.dm | 4 +- code/game/gamemodes/newobjective.dm | 2 +- code/game/machinery/bioprinter.dm | 71 +++ code/game/machinery/bots/mulebot.dm | 5 +- code/game/machinery/cloning.dm | 4 +- code/game/machinery/computer/cloning.dm | 2 +- code/game/machinery/flasher.dm | 2 +- code/game/objects/items.dm | 32 +- code/game/objects/items/devices/scanners.dm | 2 +- .../items/weapons/grenades/flashbang.dm | 4 +- .../objects/items/weapons/surgery_tools.dm | 2 +- code/game/objects/items/weapons/tools.dm | 2 + code/game/turfs/simulated.dm | 38 +- code/modules/food/recipes_microwave.dm | 4 +- code/modules/mob/living/carbon/alien/alien.dm | 3 + .../carbon/alien/humanoid/caste/drone.dm | 2 +- .../mob/living/carbon/alien/humanoid/life.dm | 2 +- .../mob/living/carbon/alien/larva/life.dm | 2 +- code/modules/mob/living/carbon/brain/MMI.dm | 5 +- .../mob/living/carbon/brain/brain_item.dm | 102 ++-- code/modules/mob/living/carbon/brain/death.dm | 2 +- .../mob/living/carbon/brain/posibrain.dm | 2 - .../mob/living/carbon/carbon_defines.dm | 1 - .../mob/living/carbon/human/examine.dm | 9 +- code/modules/mob/living/carbon/human/human.dm | 25 +- .../mob/living/carbon/human/human_damage.dm | 28 +- code/modules/mob/living/carbon/human/life.dm | 27 +- .../mob/living/carbon/metroid/metroid.dm | 5 + code/modules/mob/living/carbon/monkey/life.dm | 2 +- code/modules/mob/living/carbon/species.dm | 18 +- code/modules/mob/living/living.dm | 6 + code/modules/organs/blood.dm | 120 +++-- code/modules/organs/organ.dm | 16 + code/modules/organs/organ_external.dm | 11 +- code/modules/organs/organ_internal.dm | 84 ++- code/modules/organs/organ_objects.dm | 232 +++++++++ code/modules/reagents/Chemistry-Reagents.dm | 59 +-- .../reagent_containers/food/snacks.dm | 18 +- .../reagents/reagent_containers/syringes.dm | 2 +- code/modules/surgery/appendix.dm | 89 ---- code/modules/surgery/bones.dm | 8 +- code/modules/surgery/braincore.dm | 279 ---------- code/modules/surgery/brainrepair.dm | 68 +++ code/modules/surgery/encased.dm | 220 ++++++++ code/modules/surgery/eye.dm | 5 +- code/modules/surgery/generic.dm | 8 +- code/modules/surgery/implant.dm | 6 +- code/modules/surgery/organs_internal.dm | 493 ++++++++++++++++++ code/modules/surgery/other.dm | 34 +- code/modules/surgery/ribcage.dm | 335 ------------ code/modules/surgery/slimes.dm | 93 ++++ code/modules/surgery/surgery.dm | 7 +- code/modules/virus2/effect.dm | 2 +- icons/obj/surgery.dmi | Bin 10466 -> 14638 bytes maps/tgstation2.dmm | 4 +- 61 files changed, 1611 insertions(+), 1035 deletions(-) create mode 100644 code/game/machinery/bioprinter.dm create mode 100644 code/modules/organs/organ_objects.dm delete mode 100644 code/modules/surgery/appendix.dm delete mode 100644 code/modules/surgery/braincore.dm create mode 100644 code/modules/surgery/brainrepair.dm create mode 100644 code/modules/surgery/encased.dm create mode 100644 code/modules/surgery/organs_internal.dm delete mode 100644 code/modules/surgery/ribcage.dm create mode 100644 code/modules/surgery/slimes.dm diff --git a/baystation12.dme b/baystation12.dme index d09a530659b..1c200c9afc0 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -292,6 +292,7 @@ #include "code\game\machinery\Beacon.dm" #include "code\game\machinery\bees_apiary.dm" #include "code\game\machinery\bees_items.dm" +#include "code\game\machinery\bioprinter.dm" #include "code\game\machinery\buttons.dm" #include "code\game\machinery\cell_charger.dm" #include "code\game\machinery\cloning.dm" @@ -1110,6 +1111,7 @@ #include "code\modules\organs\organ.dm" #include "code\modules\organs\organ_external.dm" #include "code\modules\organs\organ_internal.dm" +#include "code\modules\organs\organ_objects.dm" #include "code\modules\organs\pain.dm" #include "code\modules\organs\wound.dm" #include "code\modules\paperwork\carbonpaper.dm" @@ -1345,17 +1347,18 @@ #include "code\modules\shuttles\shuttle_supply.dm" #include "code\modules\shuttles\shuttles_multi.dm" #include "code\modules\supermatter\supermatter.dm" -#include "code\modules\surgery\appendix.dm" #include "code\modules\surgery\bones.dm" -#include "code\modules\surgery\braincore.dm" +#include "code\modules\surgery\brainrepair.dm" +#include "code\modules\surgery\encased.dm" #include "code\modules\surgery\eye.dm" #include "code\modules\surgery\face.dm" #include "code\modules\surgery\generic.dm" #include "code\modules\surgery\headreattach.dm" #include "code\modules\surgery\implant.dm" +#include "code\modules\surgery\organs_internal.dm" #include "code\modules\surgery\other.dm" -#include "code\modules\surgery\ribcage.dm" #include "code\modules\surgery\robolimbs.dm" +#include "code\modules\surgery\slimes.dm" #include "code\modules\surgery\surgery.dm" #include "code\modules\vehicles\cargo_train.dm" #include "code\modules\vehicles\train.dm" diff --git a/code/ZAS/Phoron.dm b/code/ZAS/Phoron.dm index 98ab1278257..6cd983732ba 100644 --- a/code/ZAS/Phoron.dm +++ b/code/ZAS/Phoron.dm @@ -117,13 +117,17 @@ obj/var/contaminated = 0 /mob/living/carbon/human/proc/burn_eyes() //The proc that handles eye burning. - if(prob(20)) src << "\red Your eyes burn!" + if(!species.has_organ["eyes"]) + return + var/datum/organ/internal/eyes/E = internal_organs_by_name["eyes"] - E.damage += 2.5 - eye_blurry = min(eye_blurry+1.5,50) - if (prob(max(0,E.damage - 15) + 1) &&!eye_blind) - src << "\red You are blinded!" - eye_blind += 20 + if(E) + if(prob(20)) src << "\red Your eyes burn!" + E.damage += 2.5 + eye_blurry = min(eye_blurry+1.5,50) + if (prob(max(0,E.damage - 15) + 1) &&!eye_blind) + src << "\red You are blinded!" + eye_blind += 20 /mob/living/carbon/human/proc/pl_head_protected() //Checks if the head is adequately sealed. diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm index 1cd7c4aad8a..d36fc7a7c7f 100644 --- a/code/controllers/hooks-defs.dm +++ b/code/controllers/hooks-defs.dm @@ -33,7 +33,7 @@ /** * Debrained hook. * Called in brain_item.dm when someone gets debrained. - * Parameters: var/obj/item/brain + * Parameters: var/obj/item/organ/brain */ /hook/debrain diff --git a/code/datums/diseases/appendicitis.dm b/code/datums/diseases/appendicitis.dm index dba42d74d64..a9959ef0636 100644 --- a/code/datums/diseases/appendicitis.dm +++ b/code/datums/diseases/appendicitis.dm @@ -19,7 +19,8 @@ if(istype(affected_mob,/mob/living/carbon/human)) var/mob/living/carbon/human/H = affected_mob - if(H.species.name == "Diona" || H.species.name == "Machine" || H.species.name == "Vox") src.cure() + if(!H.internal_organs_by_name["appendix"]) + src.cure() if(stage == 1) if(affected_mob.op_stage.appendix == 2.0) diff --git a/code/datums/spells/inflict_handler.dm b/code/datums/spells/inflict_handler.dm index ac85b18ae3b..496eac91956 100644 --- a/code/datums/spells/inflict_handler.dm +++ b/code/datums/spells/inflict_handler.dm @@ -26,8 +26,8 @@ if("gib_brain") if(ishuman(target) || ismonkey(target)) var/mob/living/carbon/C = target - if(C.brain_op_stage != 4) // Their brain is already taken out - var/obj/item/brain/B = new(C.loc) + if(!C.has_brain()) // Their brain is already taken out + var/obj/item/organ/brain/B = new(C.loc) B.transfer_identity(C) target.gib() if("disintegrate") diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 6750f7c83eb..590df9cd07d 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -568,8 +568,8 @@ var/list/sacrificed = list() if(!(iscultist(V))) victims += V//Checks for cult status and mob type for(var/obj/item/I in src.loc)//Checks for MMIs/brains/Intellicards - if(istype(I,/obj/item/brain)) - var/obj/item/brain/B = I + if(istype(I,/obj/item/organ/brain)) + var/obj/item/organ/brain/B = I victims += B.brainmob else if(istype(I,/obj/item/device/mmi)) var/obj/item/device/mmi/B = I diff --git a/code/game/gamemodes/mutiny/directives/ipc_virus_directive.dm b/code/game/gamemodes/mutiny/directives/ipc_virus_directive.dm index 63c3f7d3c86..e035b665c9f 100644 --- a/code/game/gamemodes/mutiny/directives/ipc_virus_directive.dm +++ b/code/game/gamemodes/mutiny/directives/ipc_virus_directive.dm @@ -62,11 +62,11 @@ datum/directive/ipc_virus/get_remaining_orders() return text -/hook/debrain/proc/debrain_directive(obj/item/brain/B) +/hook/debrain/proc/debrain_directive(var/obj/item/organ/brain/B) var/datum/directive/ipc_virus/D = get_directive("ipc_virus") if (!D) return 1 - if(D.brains_to_enslave.Find(B.brainmob.mind)) + if(B && B.brainmob && B.brainmob.mind && D.brains_to_enslave.Find(B.brainmob.mind)) D.brains_to_enslave.Remove(B.brainmob.mind) return 1 diff --git a/code/game/gamemodes/newobjective.dm b/code/game/gamemodes/newobjective.dm index 70901add189..c2608cfa3d4 100644 --- a/code/game/gamemodes/newobjective.dm +++ b/code/game/gamemodes/newobjective.dm @@ -1376,7 +1376,7 @@ datum var/list/all_items = owner.current.get_contents() for(var/obj/item/device/mmi/mmi in all_items) if(mmi.brainmob&&mmi.brainmob.mind==target) return 1 - for(var/obj/item/brain/brain in all_items) + for(var/obj/item/organ/brain/brain in all_items) if(brain.brainmob&&brain.brainmob.mind==target) return 1 return 0 diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm new file mode 100644 index 00000000000..4ce50d404c5 --- /dev/null +++ b/code/game/machinery/bioprinter.dm @@ -0,0 +1,71 @@ +//These machines are mostly just here for debugging/spawning. Skeletons of the feature to come. + +/obj/machinery/bioprinter + name = "bioprinter" + desc = "It's a machine that grows replacement organs." + icon = 'icons/obj/surgery.dmi' + + icon_state = "bioprinter" + + var/prints_prosthetics + var/stored_matter = 200 + var/loaded_dna //Blood sample for DNA hashing. + var/list/products = list( + "heart" = list(/obj/item/organ/heart, 50), + "lungs" = list(/obj/item/organ/lungs, 40), + "kidneys" = list(/obj/item/organ/kidneys,20), + "eyes" = list(/obj/item/organ/eyes, 30), + "liver" = list(/obj/item/organ/liver, 50) + ) + +/obj/machinery/bioprinter/prosthetics + name = "prosthetics fabricator" + desc = "It's a machine that prints prosthetic organs." + prints_prosthetics = 1 + +/obj/machinery/bioprinter/attack_hand(mob/user) + + var/choice = input("What would you like to print?") as null|anything in products + if(!choice) + return + + if(stored_matter >= products[choice][2]) + + stored_matter -= products[choice][2] + var/new_organ = products[choice][1] + var/obj/item/organ/O = new new_organ(get_turf(src)) + + if(prints_prosthetics) + O.robotic = 2 + else if(loaded_dna) + visible_message("The printer would be using the DNA sample if it was coded.") + //TODO: Copy DNA hash or donor reference over to new organ. + + visible_message("The bioprinter spits out a new organ.") + + else + user << "There is not enough matter in the printer." + +/obj/machinery/bioprinter/attackby(obj/item/weapon/W, mob/user) + + // DNA sample from syringe. + if(!prints_prosthetics && istype(W,/obj/item/weapon/reagent_containers/syringe)) + user << "You inject the blood sample into the bioprinter, but it isn't coded yet." + return + // Meat for biomass. + else if(!prints_prosthetics && istype(W, /obj/item/weapon/reagent_containers/food/snacks/meat)) + user << "\blue \The [src] processes \the [W]." + stored_matter += 50 + user.drop_item() + del(W) + return + // Steel for matter. + else if(prints_prosthetics && istype(W, /obj/item/stack/sheet/metal)) + var/obj/item/stack/sheet/metal/M = W + user << "\blue \The [src] processes \the [W]." + stored_matter += M.amount * 10 + user.drop_item() + del(W) + return + else + return..() \ No newline at end of file diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm index 1762225088a..ce76680b0d9 100644 --- a/code/game/machinery/bots/mulebot.dm +++ b/code/game/machinery/bots/mulebot.dm @@ -803,10 +803,7 @@ H.apply_damage(0.5*damage, BRUTE, "l_arm") H.apply_damage(0.5*damage, BRUTE, "r_arm") - var/obj/effect/decal/cleanable/blood/B = new(src.loc) - B.blood_DNA = list() - B.blood_DNA[H.dna.unique_enzymes] = H.dna.b_type - + blood_splatter(src,H,1) bloodiness += 4 // player on mulebot attempted to move diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 5e1fbbe50da..04f5efa5185 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -72,12 +72,12 @@ return var/mob/selected = null - for(var/mob/M in player_list) + for(var/mob/living/M in player_list) //Dead people only thanks! if ((M.stat != 2) || (!M.client)) continue //They need a brain! - if ((istype(M, /mob/living/carbon/human)) && (M:brain_op_stage >= 4.0)) + if ((istype(M, /mob/living/carbon/human)) && (!M.has_brain())) continue if (M.ckey == find_key) diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 9ce8ccb4fc6..47eb7ca5583 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -337,7 +337,7 @@ if ((isnull(subject)) || (!(ishuman(subject))) || (!subject.dna)) scantemp = "Error: Unable to locate valid genetic data." return - if (subject.brain_op_stage == 4.0) + if (!subject.has_brain()) scantemp = "Error: No signs of intelligence detected." return if (subject.suiciding == 1) diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index cf05308e400..345d9f44d5d 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -81,7 +81,7 @@ if (istype(O, /mob/living/carbon/human)) var/mob/living/carbon/human/H = O var/datum/organ/internal/eyes/E = H.internal_organs_by_name["eyes"] - if ((E.damage > E.min_bruised_damage && prob(E.damage + 50))) + if (E && (E.damage > E.min_bruised_damage && prob(E.damage + 50))) flick("e_flash", O:flash) E.damage += rand(1, 5) else diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 6e1cc86633c..b4155d6fcae 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -53,7 +53,7 @@ Works similarly to worn sprite_sheets, except the alternate sprites are used when the clothing/refit_for_species() proc is called. */ var/list/sprite_sheets_obj = null - + /obj/item/device icon = 'icons/obj/device.dmi' @@ -516,8 +516,8 @@ user << "\red You're going to need to remove the eye covering first." return - if(istype(M, /mob/living/carbon/alien) || istype(M, /mob/living/carbon/slime))//Aliens don't have eyes./N slimes also don't have eyes! - user << "\red You cannot locate any eyes on this creature!" + if(!M.has_eyes()) + user << "\red You cannot locate any eyes on [M]!" return user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" @@ -533,20 +533,22 @@ M.weakened += 4 M.adjustBruteLoss(10) */ - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] has been stabbed in the eye with [src] by [user].", 1) - M << "\red [user] stabs you in the eye with [src]!" - user << "\red You stab [M] in the eye with [src]!" - else - user.visible_message( \ - "\red [user] has stabbed themself with [src]!", \ - "\red You stab yourself in the eyes with [src]!" \ - ) + if(istype(M, /mob/living/carbon/human)) + var/datum/organ/internal/eyes/eyes = H.internal_organs_by_name["eyes"] - if(!eyes) - return + + if(M != user) + for(var/mob/O in (viewers(M) - user - M)) + O.show_message("\red [M] has been stabbed in the eye with [src] by [user].", 1) + M << "\red [user] stabs you in the eye with [src]!" + user << "\red You stab [M] in the eye with [src]!" + else + user.visible_message( \ + "\red [user] has stabbed themself with [src]!", \ + "\red You stab yourself in the eyes with [src]!" \ + ) + eyes.damage += rand(3,4) if(eyes.damage >= eyes.min_bruised_damage) if(M.stat != 2) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index d3149ab90f8..aa7e260371b 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -173,7 +173,7 @@ REAGENT SCANNER // user.show_message("\blue Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals.") if (M.has_brain_worms()) user.show_message("\red Subject suffering from aberrant brain activity. Recommend further scanning.") - else if (M.getBrainLoss() >= 100 || istype(M, /mob/living/carbon/human) && M:brain_op_stage == 4.0) + else if (M.getBrainLoss() >= 100 || !M.has_brain()) user.show_message("\red Subject is brain dead.") else if (M.getBrainLoss() >= 60) user.show_message("\red Severe brain damage detected. Subject likely to have mental retardation.") diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index dd60f16645a..f5ad4fa9fde 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -20,7 +20,7 @@ var/damage = round(30/(get_dist(B,get_turf(src))+1)) B.health -= damage B.update_icon() - + new/obj/effect/effect/smoke/flashbang(src.loc) del(src) return @@ -84,7 +84,7 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M var/datum/organ/internal/eyes/E = H.internal_organs_by_name["eyes"] - if (E.damage >= E.min_bruised_damage) + if (E && E.damage >= E.min_bruised_damage) M << "\red Your eyes start to burn badly!" if(!banglet && !(istype(src , /obj/item/weapon/grenade/flashbang/clusterbang))) if (E.damage >= E.min_broken_damage) diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm index ddadcfddd8c..3080c05f09e 100644 --- a/code/game/objects/items/weapons/surgery_tools.dm +++ b/code/game/objects/items/weapons/surgery_tools.dm @@ -773,7 +773,7 @@ LOOK FOR SURGERY.DM*/ log_attack("[user.name] ([user.ckey]) debrained [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])") - var/obj/item/brain/B = new(M.loc) + var/obj/item/organ/brain/B = new(M.loc) B.transfer_identity(M) M:brain_op_stage = 4.0 diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index f4400132e80..fdb6a93b2e4 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -357,6 +357,8 @@ if(istype(user, /mob/living/carbon/human)) var/mob/living/carbon/human/H = user var/datum/organ/internal/eyes/E = H.internal_organs_by_name["eyes"] + if(!E) + return if(H.species.flags & IS_SYNTHETIC) return switch(safety) diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 19223c48f1c..42a63f26e58 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -153,50 +153,16 @@ B.virus2 = virus_copylist(M.virus2) return 1 //we bloodied the floor - - - //if there isn't a blood decal already, make one. - var/obj/effect/decal/cleanable/blood/newblood = new /obj/effect/decal/cleanable/blood(src) - - //Species-specific blood. - if(M.species) - newblood.basecolor = M.species.blood_color - else - newblood.basecolor = "#A10808" - - newblood.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - newblood.virus2 = virus_copylist(M.virus2) - newblood.update_icon() - + blood_splatter(src,M.get_blood(M.vessel),1) return 1 //we bloodied the floor // Only adds blood on the floor -- Skie /turf/simulated/proc/add_blood_floor(mob/living/carbon/M as mob) if(istype(M, /mob/living/carbon/monkey)) - - var/obj/effect/decal/cleanable/blood/this = new /obj/effect/decal/cleanable/blood(src) - this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - this.basecolor = "#A10808" - this.update_icon() - - else if(istype(M,/mob/living/carbon/human)) - - var/obj/effect/decal/cleanable/blood/this = new /obj/effect/decal/cleanable/blood(src) - var/mob/living/carbon/human/H = M - - //Species-specific blood. - if(H.species) - this.basecolor = H.species.blood_color - else - this.basecolor = "#A10808" - this.update_icon() - - this.blood_DNA[M.dna.unique_enzymes] = M.dna.b_type - + blood_splatter(src,M,1) else if( istype(M, /mob/living/carbon/alien )) var/obj/effect/decal/cleanable/blood/xeno/this = new /obj/effect/decal/cleanable/blood/xeno(src) this.blood_DNA["UNKNOWN BLOOD"] = "X*" - else if( istype(M, /mob/living/silicon/robot )) new /obj/effect/decal/cleanable/blood/oil(src) diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index 95183949160..fdd28f5bccb 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -135,7 +135,7 @@ I said no! /datum/recipe/brainburger items = list( /obj/item/weapon/reagent_containers/food/snacks/bun, - /obj/item/brain + /obj/item/organ/brain ) result = /obj/item/weapon/reagent_containers/food/snacks/brainburger @@ -1063,7 +1063,7 @@ I said no! /obj/item/weapon/reagent_containers/food/snacks/egg, /obj/item/weapon/reagent_containers/food/snacks/egg, /obj/item/weapon/reagent_containers/food/snacks/egg, - /obj/item/brain + /obj/item/organ/brain ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 23d5416fcae..214c091c3e8 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -202,6 +202,9 @@ Des: Removes all infected images from the alien. del(I) return +/mob/living/carbon/alien/has_eyes() + return 0 + #undef HEAT_DAMAGE_LEVEL_1 #undef HEAT_DAMAGE_LEVEL_2 #undef HEAT_DAMAGE_LEVEL_3 diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm index 2b084ce8b5c..6b7752f8137 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm @@ -27,7 +27,7 @@ // Queen check var/no_queen = 1 for(var/mob/living/carbon/alien/humanoid/queen/Q in living_mob_list) - if(!Q.key && Q.brain_op_stage != 4) + if(!Q.key && Q.has_brain()) continue no_queen = 0 diff --git a/code/modules/mob/living/carbon/alien/humanoid/life.dm b/code/modules/mob/living/carbon/alien/humanoid/life.dm index defcc968d13..f1910fcfe30 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/life.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/life.dm @@ -304,7 +304,7 @@ blinded = 1 silent = 0 else //ALIVE. LIGHTS ARE ON - if(health < config.health_threshold_dead || brain_op_stage == 4.0) + if(health < config.health_threshold_dead || !has_brain()) death() blinded = 1 stat = DEAD diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm index 9bb6ae43767..97abbdec382 100644 --- a/code/modules/mob/living/carbon/alien/larva/life.dm +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -222,7 +222,7 @@ FUCK YOU MORE FAT CODE -Hawk*/ blinded = 1 silent = 0 else //ALIVE. LIGHTS ARE ON - if(health < -25 || brain_op_stage == 4.0) + if(health < -25 || !has_brain()) death() blinded = 1 silent = 0 diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 6959828f9b5..ae2ed011925 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -22,7 +22,7 @@ var/obj/mecha = null//This does not appear to be used outside of reference in mecha.dm. attackby(var/obj/item/O as obj, var/mob/user as mob) - if(istype(O,/obj/item/brain) && !brainmob) //Time to stick a brain in it --NEO + if(istype(O,/obj/item/organ/brain) && !brainmob) //Time to stick a brain in it --NEO if(!O:brainmob) user << "\red You aren't sure where this brain came from, but you're pretty sure it's a useless brain." return @@ -61,6 +61,7 @@ return ..() + //TODO: ORGAN REMOVAL UPDATE. Make the brain remain in the MMI so it doesn't lose organ data. attack_self(mob/user as mob) if(!brainmob) user << "\red You upend the MMI, but there's nothing in it." @@ -68,7 +69,7 @@ user << "\red You upend the MMI, but the brain is clamped into place." else user << "\blue You upend the MMI, spilling the brain onto the floor." - var/obj/item/brain/brain = new(user.loc) + var/obj/item/organ/brain/brain = new(user.loc) brainmob.container = null//Reset brainmob mmi var. brainmob.loc = brain//Throw mob into brain. living_mob_list -= brainmob//Get outta here diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm index 27b9da88e88..d2ba4fbb949 100644 --- a/code/modules/mob/living/carbon/brain/brain_item.dm +++ b/code/modules/mob/living/carbon/brain/brain_item.dm @@ -1,7 +1,7 @@ -/obj/item/brain +/obj/item/organ/brain name = "brain" - desc = "A piece of juicy meat found in a persons head." - icon = 'icons/obj/surgery.dmi' + health = 400 //They need to live awhile longer than other organs. + desc = "A piece of juicy meat found in a person's head." icon_state = "brain2" flags = TABLEPASS force = 1.0 @@ -11,32 +11,32 @@ throw_range = 5 origin_tech = "biotech=3" attack_verb = list("attacked", "slapped", "whacked") + prosthetic_name = "cyberbrain" + prosthetic_icon = "brain-prosthetic" + organ_tag = "brain" var/mob/living/carbon/brain/brainmob = null - New() - ..() - //Shifting the brain "mob" over to the brain object so it's easier to keep track of. --NEO - //WASSSSSUUUPPPP /N - spawn(5) - if(brainmob && brainmob.client) - brainmob.client.screen.len = null //clear the hud +/obj/item/organ/brain/New() + ..() + spawn(5) + if(brainmob && brainmob.client) + brainmob.client.screen.len = null //clear the hud - proc - transfer_identity(var/mob/living/carbon/H) - name = "[H]'s brain" - brainmob = new(src) - brainmob.name = H.real_name - brainmob.real_name = H.real_name - brainmob.dna = H.dna.Clone() - brainmob.timeofhostdeath = H.timeofdeath - if(H.mind) - H.mind.transfer_to(brainmob) +/obj/item/organ/brain/proc/transfer_identity(var/mob/living/carbon/H) + name = "[H]'s brain" + brainmob = new(src) + brainmob.name = H.real_name + brainmob.real_name = H.real_name + brainmob.dna = H.dna.Clone() + brainmob.timeofhostdeath = H.timeofdeath + if(H.mind) + H.mind.transfer_to(brainmob) - brainmob << "\blue You feel slightly disoriented. That's normal when you're just a brain." - callHook("debrain", list(brainmob)) + brainmob << "\blue You feel slightly disoriented. That's normal when you're just a brain." + callHook("debrain", list(brainmob)) -/obj/item/brain/examine() // -- TLE +/obj/item/organ/brain/examine() // -- TLE set src in oview(12) if (!( usr )) return @@ -47,53 +47,27 @@ else usr << "This one seems particularly lifeless. Perhaps it will regain some of its luster later.." -/obj/item/brain/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M, /mob)) - return +/obj/item/organ/brain/removed(var/mob/living/target,var/mob/living/user) - add_fingerprint(user) + ..() - if(!(user.zone_sel.selecting == ("head")) || !istype(M, /mob/living/carbon/human)) - return ..() + var/mob/living/simple_animal/borer/borer = target.has_brain_worms() - if( !(locate(/obj/machinery/optable, M.loc) && M.resting) && ( !(locate(/obj/structure/table/, M.loc) && M.lying) && prob(50) ) ) - return ..() + if(borer) + borer.detatch() //Should remove borer if the brain is removed - RR - var/mob/living/carbon/human/H = M - if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES))) - // you can't stab someone in the eyes wearing a mask! - user << "\blue You're going to need to remove their head cover first." - return + var/mob/living/carbon/human/H = target + var/obj/item/organ/brain/B = src + if(istype(B) && istype(H)) + B.transfer_identity(target) -//since these people will be dead M != usr +/obj/item/organ/brain/replaced(var/mob/living/target) - if(M:brain_op_stage == 4.0) - for(var/mob/O in viewers(M, null)) - if(O == (user || M)) - continue - if(M == user) - O.show_message(text("\red [user] inserts [src] into his head!"), 1) - else - O.show_message(text("\red [M] has [src] inserted into his head by [user]."), 1) - - if(M != user) - M << "\red [user] inserts [src] into your head!" - user << "\red You insert [src] into [M]'s head!" - else - user << "\red You insert [src] into your head!" - - //this might actually be outdated since barring badminnery, a debrain'd body will have any client sucked out to the brain's internal mob. Leaving it anyway to be safe. --NEO - if(M.key)//Revised. /N - M.ghostize() + if(target.key) + target.ghostize() + if(brainmob) if(brainmob.mind) - brainmob.mind.transfer_to(M) + brainmob.mind.transfer_to(target) else - M.key = brainmob.key - - M:brain_op_stage = 3.0 - - del(src) - else - ..() - return + target.key = brainmob.key \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/carbon/brain/death.dm index 62916d818da..897b03c8a14 100644 --- a/code/modules/mob/living/carbon/brain/death.dm +++ b/code/modules/mob/living/carbon/brain/death.dm @@ -36,7 +36,7 @@ if(container && istype(container, /obj/item/device/mmi)) del(container)//Gets rid of the MMI if there is one if(loc) - if(istype(loc,/obj/item/brain)) + if(istype(loc,/obj/item/organ/brain)) del(loc)//Gets rid of the brain item spawn(15) if(animation) del(animation) diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index 6877ed4b854..5ee424bd8db 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -10,7 +10,6 @@ construction_time = 75 var/searching = 0 var/askDelay = 10 * 60 * 1 - mob/living/carbon/brain/brainmob = null req_access = list(access_robotics) locked = 0 mecha = null//This does not appear to be used outside of reference in mecha.dm. @@ -136,7 +135,6 @@ src.brainmob.robot_talk_understand = 1 src.brainmob.stat = 0 src.brainmob.silent = 0 - src.brainmob.brain_op_stage = 4.0 dead_mob_list -= src.brainmob ..() diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 0dff048d004..feed242bef0 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -1,7 +1,6 @@ /mob/living/carbon/ gender = MALE var/list/stomach_contents = list() - var/brain_op_stage = 0.0 var/list/datum/disease2/disease/virus2 = list() var/antibodies = 0 var/last_eating = 0 //Not sure what this does... I found it hidden in food.dm diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 2a9850171e7..c672950a18b 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -240,10 +240,11 @@ if(getBrainLoss() >= 60) msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n" - if(!key && brain_op_stage != 4 && stat != DEAD) - msg += "[t_He] [t_is] fast asleep. It doesn't look like they are waking up anytime soon.\n" - else if(!client && brain_op_stage != 4 && stat != DEAD) - msg += "[t_He] [t_has] suddenly fallen asleep.\n" + if(has_brain() && stat != DEAD) + if(!key) + msg += "[t_He] [t_is] fast asleep. It doesn't look like they are waking up anytime soon.\n" + else if(!client) + msg += "[t_He] [t_has] suddenly fallen asleep.\n" var/list/wound_flavor_text = list() var/list/is_destroyed = list() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b250884e9f7..3f7faeac8e6 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -535,13 +535,13 @@ //Now checks siemens_coefficient of the affected area by default /mob/living/carbon/human/electrocute_act(var/shock_damage, var/obj/source, var/base_siemens_coeff = 1.0, var/def_zone = null) if(status_flags & GODMODE) return 0 //godmode - + if (!def_zone) def_zone = pick("l_hand", "r_hand") - + var/datum/organ/external/affected_organ = get_organ(check_zone(def_zone)) var/siemens_coeff = base_siemens_coeff * get_siemens_coefficient_organ(affected_organ) - + return ..(shock_damage, source, siemens_coeff, def_zone) @@ -1135,12 +1135,12 @@ /mob/living/carbon/human/proc/is_lung_ruptured() var/datum/organ/internal/lungs/L = internal_organs_by_name["lungs"] - return L.is_bruised() + return L && L.is_bruised() /mob/living/carbon/human/proc/rupture_lung() var/datum/organ/internal/lungs/L = internal_organs_by_name["lungs"] - if(!L.is_bruised()) + if(L && !L.is_bruised()) src.custom_pain("You feel a stabbing pain in your chest!", 1) L.damage = L.min_bruised_damage @@ -1300,6 +1300,7 @@ spawn(0) update_icons() + fixblood() if(species) return 1 @@ -1567,3 +1568,17 @@ flavor_text += flavor_texts[T] flavor_text += "\n\n" return ..() + +/mob/living/carbon/human/has_brain() + if(internal_organs_by_name["brain"]) + var/datum/organ/internal/brain = internal_organs_by_name["brain"] + if(brain && istype(brain)) + return 1 + return 0 + +/mob/living/carbon/human/has_eyes() + if(internal_organs_by_name["eyes"]) + var/datum/organ/internal/eyes = internal_organs_by_name["eyes"] + if(eyes && istype(eyes) && !eyes.status & ORGAN_CUT_AWAY) + return 1 + return 0 diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 01caff57e5a..8b4e010d4b5 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -17,13 +17,19 @@ /mob/living/carbon/human/getBrainLoss() var/res = brainloss - var/datum/organ/internal/brain/sponge = internal_organs_by_name["brain"] - if (sponge.is_bruised()) - res += 20 - if (sponge.is_broken()) - res += 50 - res = min(res,maxHealth*2) - return res + if(species && species.has_organ["brain"]) + var/datum/organ/internal/brain/sponge = internal_organs_by_name["brain"] + if(!sponge) + res += 200 + else + if (sponge.is_bruised()) + res += 20 + if (sponge.is_broken()) + res += 50 + + res = min(res,maxHealth*2) + return res + return 0 //These procs fetch a cumulative total damage from all organs /mob/living/carbon/human/getBruteLoss() @@ -264,20 +270,20 @@ This function restores all organs. /mob/living/carbon/human/apply_damage(var/damage = 0, var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/sharp = 0, var/edge = 0, var/obj/used_weapon = null) //visible_message("Hit debug. [damage] | [damagetype] | [def_zone] | [blocked] | [sharp] | [used_weapon]") - + //Handle other types of damage if((damagetype != BRUTE) && (damagetype != BURN)) if(damagetype == HALLOSS) if ((damage > 25 && prob(20)) || (damage > 50 && prob(60))) emote("scream") - - + + ..(damage, damagetype, def_zone, blocked) return 1 //Handle BRUTE and BURN damage handle_suit_punctures(damagetype, damage) - + if(blocked >= 2) return 0 var/datum/organ/external/organ = null diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index c5fb663116a..dd02d3c17d7 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -95,6 +95,9 @@ //Disabilities handle_disabilities() + //Organ failure. + handle_organs() + //Random events (vomiting etc) handle_random_events() @@ -1081,7 +1084,7 @@ handle_organs() //Optimized. handle_blood() - if(health <= config.health_threshold_dead || brain_op_stage == 4.0) + if(health <= config.health_threshold_dead || !has_brain()) death() blinded = 1 silent = 0 @@ -1160,15 +1163,23 @@ //Eyes - if(sdisabilities & BLIND) //disabled-blind, doesn't get better on its own - blinded = 1 - else if(eye_blind) //blindness, heals slowly over time - eye_blind = max(eye_blind-1,0) - blinded = 1 + if(!species.has_organ["eyes"]) // Presumably if a species has no eyes, they see via something else. + eye_blind = 0 + blinded = 0 + eye_blurry = 0 + else if(!has_eyes()) // Eyes cut out? Permablind. + eye_blind = 1 + blinded = 1 + eye_blurry = 1 + else if(sdisabilities & BLIND) // Disabled-blind, doesn't get better on its own + blinded = 1 + else if(eye_blind) // Blindness, heals slowly over time + eye_blind = max(eye_blind-1,0) + blinded = 1 else if(istype(glasses, /obj/item/clothing/glasses/sunglasses/blindfold)) //resting your eyes with a blindfold heals blurry eyes faster eye_blurry = max(eye_blurry-3, 0) - blinded = 1 - else if(eye_blurry) //blurry eyes heal slowly + blinded = 1 + else if(eye_blurry) // Blurry eyes heal slowly eye_blurry = max(eye_blurry-1, 0) //Ears diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm index 67f0b904ed4..85fdb33a8da 100644 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ b/code/modules/mob/living/carbon/metroid/metroid.dm @@ -51,6 +51,8 @@ var/coretype = /obj/item/slime_extract/grey var/list/slime_mutation[4] + var/core_removal_stage = 0 //For removing cores. + /mob/living/carbon/slime/New() create_reagents(100) spawn (0) @@ -984,6 +986,9 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 if(A) G << "Golem rune created in [A.name]." +/mob/living/carbon/slime/has_eyes() + return 0 + //////////////////////////////Old shit from metroids/RoRos, and the old cores, would not take much work to re-add them//////////////////////// /* diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index ce681063582..44a7e7a2593 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -485,7 +485,7 @@ silent = 0 else //ALIVE. LIGHTS ARE ON updatehealth() - if(health < config.health_threshold_dead || brain_op_stage == 4.0) + if(health < config.health_threshold_dead || !has_brain()) death() blinded = 1 stat = DEAD diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 286bffb3a0f..d5e8a167614 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -54,6 +54,15 @@ var/race_key = 0 var/icon/icon_template + var/list/has_organ = list( + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "liver" = /datum/organ/internal/liver, + "kidneys" = /datum/organ/internal/kidney, + "brain" = /datum/organ/internal/brain, + "appendix" = /datum/organ/internal/appendix, + "eyes" = /datum/organ/internal/eyes + ) /datum/species/New() unarmed = new unarmed_type() @@ -73,12 +82,9 @@ H.organs_by_name["r_foot"] = new/datum/organ/external/r_foot(H.organs_by_name["r_leg"]) H.internal_organs = list() - H.internal_organs_by_name["heart"] = new/datum/organ/internal/heart(H) - H.internal_organs_by_name["lungs"] = new/datum/organ/internal/lungs(H) - H.internal_organs_by_name["liver"] = new/datum/organ/internal/liver(H) - H.internal_organs_by_name["kidney"] = new/datum/organ/internal/kidney(H) - H.internal_organs_by_name["brain"] = new/datum/organ/internal/brain(H) - H.internal_organs_by_name["eyes"] = new/datum/organ/internal/eyes(H) + for(var/organ in has_organ) + var/organ_type = has_organ[organ] + H.internal_organs_by_name[organ] = new organ_type(H) for(var/name in H.organs_by_name) H.organs += H.organs_by_name[name] diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index daf0e370049..a4e5e0586fd 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -784,3 +784,9 @@ var/area/new_area = get_area(loc) if(new_area) new_area.Entered(src) + +/mob/living/proc/has_brain() + return 1 + +/mob/living/proc/has_eyes() + return 1 \ No newline at end of file diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 3a691d9d353..38feee53e28 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -30,8 +30,9 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 /mob/living/carbon/human/proc/fixblood() for(var/datum/reagent/blood/B in vessel.reagent_list) if(B.id == "blood") - B.data = list( "donor"=src,"viruses"=null,"blood_DNA"=dna.unique_enzymes,"blood_type"=dna.b_type, \ + B.data = list( "donor"=src,"viruses"=null,"blood_DNA"=dna.unique_enzymes,"blood_colour"= species.blood_color,"blood_type"=dna.b_type, \ "resistances"=null,"trace_chem"=null, "virus2" = null, "antibodies" = null) + B.color = B.data["blood_color"] // Takes care blood loss and regeneration /mob/living/carbon/human/proc/handle_blood() @@ -63,14 +64,17 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 // Damaged heart virtually reduces the blood volume, as the blood isn't // being pumped properly anymore. - var/datum/organ/internal/heart/heart = internal_organs_by_name["heart"] + if(species && species.has_organ["heart"]) + var/datum/organ/internal/heart/heart = internal_organs_by_name["heart"] - if(heart.damage > 1 && heart.damage < heart.min_bruised_damage) - blood_volume *= 0.8 - else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage) - blood_volume *= 0.6 - else if(heart.damage >= heart.min_broken_damage && heart.damage < INFINITY) - blood_volume *= 0.3 + if(!heart) + blood_volume = 0 + else if(heart.damage > 1 && heart.damage < heart.min_bruised_damage) + blood_volume *= 0.8 + else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage) + blood_volume *= 0.6 + else if(heart.damage >= heart.min_broken_damage && heart.damage < INFINITY) + blood_volume *= 0.3 //Effects of bloodloss switch(blood_volume) @@ -141,31 +145,8 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 if(!amt) return - var/turf/T = get_turf(src) - var/list/obj/effect/decal/cleanable/blood/drip/nums = list() - var/list/iconL = list("1","2","3","4","5") - vessel.remove_reagent("blood",amt) - - for(var/obj/effect/decal/cleanable/blood/drip/G in T) - nums += G - iconL.Remove(G.icon_state) - - if (nums.len < 5) - var/obj/effect/decal/cleanable/blood/drip/this = new(T) - this.icon_state = pick(iconL) - this.blood_DNA = list() - this.blood_DNA[dna.unique_enzymes] = dna.b_type - for (var/ID in virus2) - var/datum/disease2/disease/V = virus2[ID] - this.virus2[ID] = V.getcopy() - if (species) this.basecolor = species.blood_color - this.update_icon() - - else - for(var/obj/effect/decal/cleanable/blood/drip/G in nums) - del G - T.add_blood(src) + blood_splatter(src,src) /**************************************************** BLOOD TRANSFERS @@ -193,6 +174,12 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 B.data["resistances"] = src.resistances.Copy() B.data["blood_type"] = copytext(src.dna.b_type,1,0) + // Putting this here due to return shenanigans. + if(istype(src,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = src + B.data["blood_colour"] = H.species.blood_color + B.color = B.data["blood_colour"] + var/list/temp_chem = list() for(var/datum/reagent/R in src.reagents.reagent_list) temp_chem += R.id @@ -279,4 +266,71 @@ proc/blood_incompatible(donor,receiver) if("O") if(donor_antigen != "O") return 1 //AB is a universal receiver. - return 0 \ No newline at end of file + return 0 + +proc/blood_splatter(var/target,var/datum/reagent/blood/source,var/large) + + var/obj/effect/decal/cleanable/blood/B + var/decal_type = /obj/effect/decal/cleanable/blood/splatter + var/turf/T = get_turf(target) + + if(istype(source,/mob/living/carbon/human)) + var/mob/living/carbon/human/M = source + source = M.get_blood(M.vessel) + else if(istype(source,/mob/living/carbon/monkey)) + var/mob/living/carbon/monkey/donor = source + if(donor.dna) + source = new() + source.data["blood_DNA"] = donor.dna.unique_enzymes + source.data["blood_type"] = donor.dna.b_type + + // Are we dripping or splattering? + if(!large) + + // Only a certain number of drips can be on a given turf. + var/list/drips = list() + var/list/drip_icons = list("1","2","3","4","5") + + for(var/obj/effect/decal/cleanable/blood/drip/drop in T) + drips += drop + drip_icons.Remove(drop.icon_state) + + // If we have too many drips, remove them and spawn a proper blood splatter. + if(drips.len >= 5) + //TODO: copy all virus data from drips to new splatter? + for(var/obj/effect/decal/cleanable/blood/drip/drop in drips) + del drop + else + decal_type = /obj/effect/decal/cleanable/blood/drip + + // Find a blood decal or create a new one. + B = locate(decal_type) in T + if(!B) + B = new decal_type(T) + + // If there's no data to copy, call it quits here. + if(!source) + return B + + // Update appearance. + if(source.data["blood_colour"]) + B.basecolor = source.data["blood_colour"] + B.update_icon() + + // Update blood information. + if(source.data["blood_DNA"]) + B.blood_DNA = list() + if(source.data["blood_type"]) + B.blood_DNA[source.data["blood_DNA"]] = source.data["blood_type"] + else + B.blood_DNA[source.data["blood_DNA"]] = "O+" + + // Update virus information. //Looks like this is out of date. + //for(var/datum/disease/D in source.data["viruses"]) + // var/datum/disease/new_virus = D.Copy(1) + // source.viruses += new_virus + // new_virus.holder = B + if(source.data["virus2"]) + B.virus2 = virus_copylist(source.data["virus2"]) + + return B \ No newline at end of file diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index f0c28d87c3b..12b180fd546 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -1,6 +1,8 @@ /datum/organ var/name = "organ" var/mob/living/carbon/human/owner = null + var/status = 0 + var/vital //Lose a vital limb, die immediately. var/list/datum/autopsy_data/autopsy_data = list() var/list/trace_chemicals = list() // traces of chemicals in the organ, @@ -56,6 +58,7 @@ // Takes care of organ related updates, such as broken and missing limbs /mob/living/carbon/human/proc/handle_organs() + number_wounds = 0 var/leg_tally = 2 var/force_process = 0 @@ -72,6 +75,19 @@ for(var/datum/organ/internal/I in internal_organs) I.process() + // Also handles some internal organ processing when the organs are missing completely. + // Only handles missing liver and kidneys for now. + // This is a bit harsh, but really if you're missing an entire bodily organ you're in deep shit. + if(species.has_organ["liver"]) + var/datum/organ/internal/liver = internal_organs_by_name["liver"] + if(!liver || liver.status & ORGAN_CUT_AWAY) + reagents.add_reagent("toxin", rand(1,3)) + + if(species.has_organ["kidneys"]) + var/datum/organ/internal/kidney = internal_organs_by_name["kidneys"] + if(!kidney || kidney.status & ORGAN_CUT_AWAY) + reagents.add_reagent("toxin", rand(1,3)) + if(!force_process && !bad_external_organs.len) return diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 79bbe771b30..c4df67cc870 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -32,12 +32,11 @@ var/damage_msg = "\red You feel an intense pain" var/broken_description - var/vital //Lose a vital limb, die immediately. - var/status = 0 var/open = 0 var/stage = 0 var/cavity = 0 - var/sabotaged = 0 //If a prosthetic limb is emagged, it will detonate when it fails. + var/sabotaged = 0 // If a prosthetic limb is emagged, it will detonate when it fails. + var/encased // Needs to be opened with a saw to access the organs. var/obj/item/hidden = null var/list/implants = list() @@ -855,6 +854,7 @@ Note that amputating the affected organ does in fact remove the infection from t min_broken_damage = 40 body_part = UPPER_TORSO vital = 1 + encased = "ribcage" /datum/organ/external/groin name = "groin" @@ -958,6 +958,7 @@ Note that amputating the affected organ does in fact remove the infection from t body_part = HEAD var/disfigured = 0 vital = 1 + encased = "skull" /datum/organ/external/head/get_icon(var/icon/race_icon, var/icon/deform_icon) if (!owner) @@ -1062,6 +1063,7 @@ obj/item/weapon/organ/r_hand obj/item/weapon/organ/r_leg name = "right leg" icon_state = "r_leg" + obj/item/weapon/organ/head name = "head" icon_state = "head_m" @@ -1158,11 +1160,12 @@ obj/item/weapon/organ/head/attackby(obj/item/weapon/W as obj, mob/user as mob) brainmob.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [W.name] (INTENT: [uppertext(user.a_intent)])" msg_admin_attack("[user] ([user.ckey]) debrained [brainmob] ([brainmob.ckey]) (INTENT: [uppertext(user.a_intent)]) (JMP)") + //TODO: ORGAN REMOVAL UPDATE. if(istype(src,/obj/item/weapon/organ/head/posi)) var/obj/item/device/mmi/posibrain/B = new(loc) B.transfer_identity(brainmob) else - var/obj/item/brain/B = new(loc) + var/obj/item/organ/brain/B = new(loc) B.transfer_identity(brainmob) brain_op_stage = 4.0 diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index 4ed10047564..e8c7acbfbf0 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -10,6 +10,9 @@ var/min_broken_damage = 30 var/parent_organ = "chest" var/robotic = 0 //For being a robot + var/removed_type //When removed, forms this object. + var/list/transplant_data // Blood DNA and colour of donor + var/rejecting // Is this organ already being rejected? /datum/organ/internal/proc/rejuvenate() damage=0 @@ -20,20 +23,19 @@ /datum/organ/internal/proc/is_broken() return damage >= min_broken_damage - - /datum/organ/internal/New(mob/living/carbon/human/H) ..() - var/datum/organ/external/E = H.organs_by_name[src.parent_organ] - if(E.internal_organs == null) - E.internal_organs = list() - E.internal_organs |= src - H.internal_organs |= src - src.owner = H + if(H) + var/datum/organ/external/E = H.organs_by_name[src.parent_organ] + if(E.internal_organs == null) + E.internal_organs = list() + E.internal_organs |= src + H.internal_organs |= src + src.owner = H /datum/organ/internal/process() - //Process infections + //Process infections if (robotic >= 2 || (owner.species && owner.species.flags & IS_PLANT)) //TODO make robotic internal and external organs separate types of organ instead of a flag germ_level = 0 return @@ -44,10 +46,10 @@ //** Handle the effects of infections var/antibiotics = owner.reagents.get_reagent_amount("spaceacillin") - + if (germ_level > 0 && germ_level < INFECTION_LEVEL_ONE/2 && prob(30)) germ_level-- - + if (germ_level >= INFECTION_LEVEL_ONE/2) //aiming for germ level to go from ambient to INFECTION_LEVEL_TWO in an average of 15 minutes if(antibiotics < 5 && prob(round(germ_level/6))) @@ -58,10 +60,33 @@ //spread germs if (antibiotics < 5 && parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30) )) parent.germ_level++ - + if (prob(3)) //about once every 30 seconds take_damage(1,silent=prob(30)) + // Process unsuitable transplants. TODO: consider some kind of + // immunosuppressant that changes transplant data to make it match. + if(transplant_data) + if(!rejecting) //Should this transplant reject? + if(owner.species != transplant_data["species"]) //Nope. + rejecting = 1 + else if(prob(20) && owner.dna && blood_incompatible(transplant_data["blood_type"],owner.dna.b_type)) + rejecting = 1 + else + rejecting++ //Rejection severity increases over time. + if(rejecting % 10 == 0) //Only fire every ten rejection ticks. + switch(rejecting) + if(1 to 50) + take_damage(rand(1,2)) + if(51 to 200) + take_damage(rand(2,3)) + if(201 to 500) + take_damage(rand(3,4)) + owner.reagents.add_reagent("toxin", 1) + if(501 to INFINITY) + take_damage(5) + owner.reagents.add_reagent("toxin", rand(3,5)) + /datum/organ/internal/proc/take_damage(amount, var/silent=0) if(src.robotic == 2) src.damage += (amount * 0.8) @@ -111,21 +136,22 @@ INTERNAL ORGANS DEFINES ****************************************************/ -/datum/organ/internal/heart +/datum/organ/internal/heart // This is not set to vital because death immediately occurs in blood.dm if it is removed. name = "heart" parent_organ = "chest" - + removed_type = /obj/item/organ/heart /datum/organ/internal/lungs name = "lungs" parent_organ = "chest" + removed_type = /obj/item/organ/lungs process() ..() if (germ_level > INFECTION_LEVEL_ONE) if(prob(5)) owner.emote("cough") //respitory tract infection - + if(is_bruised()) if(prob(2)) spawn owner.emote("me", 1, "coughs up blood!") @@ -138,6 +164,7 @@ name = "liver" parent_organ = "chest" var/process_accuracy = 10 + removed_type = /obj/item/organ/liver process() ..() @@ -147,7 +174,7 @@ if (germ_level > INFECTION_LEVEL_TWO) if(prob(1)) spawn owner.vomit() - + if(owner.life_tick % process_accuracy == 0) if(src.damage < 0) src.damage = 0 @@ -178,16 +205,20 @@ owner.adjustToxLoss(0.3 * process_accuracy) /datum/organ/internal/kidney - name = "kidney" - parent_organ = "chest" + name = "kidneys" + parent_organ = "groin" + removed_type = /obj/item/organ/kidneys /datum/organ/internal/brain name = "brain" parent_organ = "head" + removed_type = /obj/item/organ/brain + vital = 1 /datum/organ/internal/eyes name = "eyes" parent_organ = "head" + removed_type = /obj/item/organ/eyes process() //Eye damage replaces the old eye_stat var. ..() @@ -195,3 +226,20 @@ owner.eye_blurry = 20 if(is_broken()) owner.eye_blind = 20 + +/datum/organ/internal/appendix + name = "appendix" + parent_organ = "groin" + removed_type = /obj/item/organ/appendix + +/datum/organ/internal/proc/remove(var/mob/user) + + if(!removed_type) return 0 + + var/obj/item/organ/removed_organ = new removed_type(get_turf(user)) + + if(istype(removed_organ)) + removed_organ.organ_data = src + removed_organ.update() + + return removed_organ \ No newline at end of file diff --git a/code/modules/organs/organ_objects.dm b/code/modules/organs/organ_objects.dm new file mode 100644 index 00000000000..c48a9d4b541 --- /dev/null +++ b/code/modules/organs/organ_objects.dm @@ -0,0 +1,232 @@ +/obj/item/organ + name = "organ" + desc = "It looks like it probably just plopped out." + icon = 'icons/obj/surgery.dmi' + icon_state = "appendix" + + health = 100 // Process() ticks before death. + + var/fresh = 3 // Squirts of blood left in it. + var/dead_icon // Icon used when the organ dies. + var/robotic // Is the limb prosthetic? + var/organ_tag // What slot does it go in? + var/organ_type = /datum/organ/internal // Used to spawn the relevant organ data when produced via a machine or spawn(). + var/datum/organ/internal/organ_data // Stores info when removed. + var/prosthetic_name = "prosthetic organ" // Flavour string for robotic organ. + var/prosthetic_icon // Icon for robotic organ. + +/obj/item/organ/attack_self(mob/user as mob) + + // Convert it to an edible form, yum yum. + if(!robotic && user.a_intent == "help" && user.zone_sel.selecting == "mouth") + bitten(user) + return + +/obj/item/organ/New() + ..() + create_reagents(5) + if(!robotic) + processing_objects += src + spawn(1) + update() + +/obj/item/organ/Del() + if(!robotic) processing_objects -= src + ..() + +/obj/item/organ/process() + + if(robotic) + processing_objects -= src + return + + // Don't process if we're in a freezer, an MMI or a stasis bag. //TODO: ambient temperature? + if(istype(loc,/obj/item/device/mmi) || istype(loc,/obj/item/bodybag/cryobag) || istype(loc,/obj/structure/closet/crate/freezer)) + return + + if(fresh && prob(40)) + fresh-- + var/datum/reagent/blood = reagents.reagent_list["blood"] + blood_splatter(src,blood,1) + + health -= rand(1,3) + if(health <= 0) + die() + +/obj/item/organ/proc/die() + name = "dead [initial(name)]" + if(dead_icon) icon_state = dead_icon + health = 0 + processing_objects -= src + //TODO: Grey out the icon state. + //TODO: Inject an organ with peridaxon to make it alive again. + +/obj/item/organ/proc/roboticize() + + robotic = (organ_data && organ_data.robotic) ? organ_data.robotic : 1 + + if(prosthetic_name) + name = prosthetic_name + + if(prosthetic_icon) + icon_state = prosthetic_icon + else + //TODO: convert to greyscale. + +/obj/item/organ/proc/update() + + if(!organ_data) + organ_data = new /datum/organ/internal() + + if(robotic) + organ_data.robotic = robotic + + if(organ_data.robotic >= 2) + roboticize() + +// Brain is defined in brain_item.dm. +/obj/item/organ/heart + name = "heart" + icon_state = "heart-on" + prosthetic_name = "circulatory pump" + prosthetic_icon = "heart-prosthetic" + organ_tag = "heart" + fresh = 6 // Juicy. + dead_icon = "heart-off" + +/obj/item/organ/lungs + name = "lungs" + icon_state = "lungs" + prosthetic_name = "gas exchange system" + prosthetic_icon = "lungs-prosthetic" + organ_tag = "lungs" + +/obj/item/organ/kidneys + name = "kidneys" + icon_state = "kidneys" + prosthetic_name = "prosthetic kidneys" + prosthetic_icon = "kidneys-prosthetic" + organ_tag = "kidneys" + +/obj/item/organ/eyes + name = "eyeballs" + icon_state = "eyes" + prosthetic_name = "visual prosthesis" + prosthetic_icon = "eyes-prosthetic" + organ_tag = "eyes" + + var/eye_colour + +/obj/item/organ/liver + name = "liver" + icon_state = "liver" + prosthetic_name = "toxin filter" + prosthetic_icon = "liver-prosthetic" + organ_tag = "liver" + +/obj/item/organ/appendix + name = "appendix" + icon_state = "appendix" + organ_tag = "appendix" + +//These are here so they can be printed out via the fabricator. +/obj/item/organ/heart/prosthetic + robotic = 2 + +/obj/item/organ/lungs/prosthetic + robotic = 2 + +/obj/item/organ/kidneys/prosthetic + robotic = 2 + +/obj/item/organ/eyes/prosthetic + robotic = 2 + +/obj/item/organ/liver/prosthetic + robotic = 2 + +/obj/item/organ/appendix + name = "appendix" + +/obj/item/organ/proc/removed(var/mob/living/target,var/mob/living/user) + + if(!target || !user) + return + + if(organ_data.vital) + user.attack_log += "\[[time_stamp()]\] removed a vital organ ([src]) from [target.name] ([target.ckey]) (INTENT: [uppertext(user.a_intent)])" + target.attack_log += "\[[time_stamp()]\] had a vital organ ([src]) removed by [user.name] ([user.ckey]) (INTENT: [uppertext(user.a_intent)])" + msg_admin_attack("[user.name] ([user.ckey]) removed a vital organ ([src]) from [target.name] ([target.ckey]) (INTENT: [uppertext(user.a_intent)]) (JMP)") + target.death() + +/obj/item/organ/appendix/removed(var/mob/living/target,var/mob/living/user) + + ..() + + var/inflamed = 0 + for(var/datum/disease/appendicitis/appendicitis in target.viruses) + inflamed = 1 + appendicitis.cure() + target.resistances += appendicitis + + if(inflamed) + icon_state = "appendixinflamed" + name = "inflamed appendix" + +/obj/item/organ/eyes/removed(var/mob/living/target,var/mob/living/user) + + if(!eye_colour) + eye_colour = list(0,0,0) + + ..() //Make sure target is set so we can steal their eye colour for later. + var/mob/living/carbon/human/H = target + if(istype(H)) + eye_colour = list( + H.r_eyes ? H.r_eyes : 0, + H.g_eyes ? H.g_eyes : 0, + H.b_eyes ? H.b_eyes : 0 + ) + + // Leave bloody red pits behind! + H.r_eyes = 128 + H.g_eyes = 0 + H.b_eyes = 0 + H.update_body() + +/obj/item/organ/proc/replaced(var/mob/living/target) + return + +/obj/item/organ/eyes/replaced(var/mob/living/target) + + // Apply our eye colour to the target. + var/mob/living/carbon/human/H = target + if(istype(H) && eye_colour) + H.r_eyes = eye_colour[1] + H.g_eyes = eye_colour[2] + H.b_eyes = eye_colour[3] + H.update_body() + +/obj/item/organ/proc/bitten(mob/user) + + if(robotic) + return + + user << "\blue You take an experimental bite out of \the [src]." + var/datum/reagent/blood = reagents.reagent_list["blood"] + blood_splatter(src,blood,1) + + + user.drop_from_inventory(src) + var/obj/item/weapon/reagent_containers/food/snacks/organ/O = new(get_turf(src)) + O.name = name + O.icon_state = dead_icon ? dead_icon : icon_state + + // Pass over the blood. + reagents.trans_to(O, reagents.total_volume) + + if(fingerprints) O.fingerprints = fingerprints.Copy() + if(fingerprintshidden) O.fingerprintshidden = fingerprintshidden.Copy() + if(fingerprintslast) O.fingerprintslast = fingerprintslast + + user.put_in_active_hand(O) + del(src) \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index b1858cd6987..13962c71346 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -95,7 +95,7 @@ datum blood - data = new/list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null, "antibodies" = null) + data = new/list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"blood_colour"= "#A10808","resistances"=null,"trace_chem"=null, "antibodies" = null) name = "Blood" id = "blood" reagent_state = LIQUID @@ -128,49 +128,30 @@ datum var/mob/living/carbon/C = M C.antibodies |= self.data["antibodies"] + on_merge(var/data) + if(data["blood_colour"]) + color = data["blood_colour"] + return ..() - + on_update(var/atom/A) + if(data["blood_colour"]) + color = data["blood_colour"] + return ..() reaction_turf(var/turf/simulated/T, var/volume)//splash the blood all over the place if(!istype(T)) return var/datum/reagent/blood/self = src src = null if(!(volume >= 3)) return - //var/datum/disease/D = self.data["virus"] + if(!self.data["donor"] || istype(self.data["donor"], /mob/living/carbon/human)) - var/obj/effect/decal/cleanable/blood/blood_prop = locate() in T //find some blood here - if(!blood_prop) //first blood! - blood_prop = new(T) - blood_prop.blood_DNA[self.data["blood_DNA"]] = self.data["blood_type"] - - for(var/datum/disease/D in self.data["viruses"]) - var/datum/disease/newVirus = D.Copy(1) - blood_prop.viruses += newVirus - newVirus.holder = blood_prop - - if(self.data["virus2"]) - blood_prop.virus2 = virus_copylist(self.data["virus2"]) - - + blood_splatter(T,self,1) else if(istype(self.data["donor"], /mob/living/carbon/monkey)) - var/obj/effect/decal/cleanable/blood/blood_prop = locate() in T - if(!blood_prop) - blood_prop = new(T) - blood_prop.blood_DNA["Non-Human DNA"] = "A+" - for(var/datum/disease/D in self.data["viruses"]) - var/datum/disease/newVirus = D.Copy(1) - blood_prop.viruses += newVirus - newVirus.holder = blood_prop - + var/obj/effect/decal/cleanable/blood/B = blood_splatter(T,self,1) + if(B) B.blood_DNA["Non-Human DNA"] = "A+" else if(istype(self.data["donor"], /mob/living/carbon/alien)) - var/obj/effect/decal/cleanable/blood/xeno/blood_prop = locate() in T - if(!blood_prop) - blood_prop = new(T) - blood_prop.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" - for(var/datum/disease/D in self.data["viruses"]) - var/datum/disease/newVirus = D.Copy(1) - blood_prop.viruses += newVirus - newVirus.holder = blood_prop + var/obj/effect/decal/cleanable/blood/B = blood_splatter(T,self,1) + if(B) B.blood_DNA["UNKNOWN DNA STRUCTURE"] = "X*" return /* Must check the transfering of reagents and their data first. They all can point to one disease datum. @@ -1276,7 +1257,7 @@ datum if(ishuman(M)) var/mob/living/carbon/human/H = M var/datum/organ/internal/eyes/E = H.internal_organs_by_name["eyes"] - if(istype(E)) + if(E && istype(E)) if(E.damage > 0) E.damage = max(E.damage - 1, 0) ..() @@ -3024,7 +3005,9 @@ datum if(ishuman(M)) var/mob/living/carbon/human/H = M var/datum/organ/internal/liver/L = H.internal_organs_by_name["liver"] - if (istype(L)) + if (!L) + H.adjustToxLoss(5) + else if(istype(L)) L.take_damage(0.1, 1) H.adjustToxLoss(0.1) ..() @@ -3264,13 +3247,13 @@ datum if(prob(5)) if(ishuman(M)) var/mob/living/carbon/human/H = M var/datum/organ/internal/heart/L = H.internal_organs_by_name["heart"] - if (istype(L)) + if (L && istype(L)) L.take_damage(5, 0) if (300 to INFINITY) if(ishuman(M)) var/mob/living/carbon/human/H = M var/datum/organ/internal/heart/L = H.internal_organs_by_name["heart"] - if (istype(L)) + if (L && istype(L)) L.take_damage(100, 0) holder.remove_reagent(src.id, FOOD_METABOLISM) diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 29001d9723f..28e369f531f 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -590,25 +590,20 @@ ..() reagents.add_reagent("nutriment", 1) -/obj/item/weapon/reagent_containers/food/snacks/appendix -//yes, this is the same as meat. I might do something different in future - name = "appendix" - desc = "An appendix which looks perfectly healthy." +/obj/item/weapon/reagent_containers/food/snacks/organ + + name = "organ" + desc = "It's good for you." icon = 'icons/obj/surgery.dmi' icon_state = "appendix" filling_color = "#E00D34" New() ..() - reagents.add_reagent("nutriment", 3) + reagents.add_reagent("nutriment", rand(3,5)) + reagents.add_reagent("toxin", rand(1,3)) src.bitesize = 3 -/obj/item/weapon/reagent_containers/food/snacks/appendix/inflamed - name = "inflamed appendix" - desc = "An appendix which appears to be inflamed." - icon_state = "appendixinflamed" - filling_color = "#E00D7A" - /obj/item/weapon/reagent_containers/food/snacks/tofu name = "Tofu" icon_state = "tofu" @@ -1559,7 +1554,6 @@ On_Consume(var/mob/M) M << "Something inside of you suddently expands!" - if (istype(M, /mob/living/carbon/human)) //Do not try to understand. var/obj/item/weapon/surprise = new/obj/item/weapon(M) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 5e6277c8e7c..5617a3802e6 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -128,7 +128,7 @@ if(SYRINGE_INJECT) if(!reagents.total_volume) - user << "\red The Syringe is empty." + user << "\red The syringe is empty." return if(istype(target, /obj/item/weapon/implantcase/chem)) return diff --git a/code/modules/surgery/appendix.dm b/code/modules/surgery/appendix.dm deleted file mode 100644 index 91332eab06b..00000000000 --- a/code/modules/surgery/appendix.dm +++ /dev/null @@ -1,89 +0,0 @@ -//Procedures in this file: Appendectomy -////////////////////////////////////////////////////////////////// -// APPENDECTOMY // -////////////////////////////////////////////////////////////////// - -/datum/surgery_step/appendectomy/ - priority = 2 - can_infect = 1 - blood_level = 1 - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if (!hasorgans(target)) - return 0 - if (target_zone != "groin") - return 0 - var/datum/organ/external/groin = target.get_organ("groin") - if (!groin) - return 0 - if (groin.open < 2) - return 0 - return 1 - -/datum/surgery_step/appendectomy/cut_appendix - allowed_tools = list( - /obj/item/weapon/scalpel = 100, \ - /obj/item/weapon/kitchenknife = 75, \ - /obj/item/weapon/shard = 50, \ - ) - - min_duration = 70 - max_duration = 90 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.op_stage.appendix == 0 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts to separate [target]'s appendix from the abdominal wall with \the [tool].", \ - "You start to separate [target]'s appendix from the abdominal wall with \the [tool]." ) - target.custom_pain("The pain in your abdomen is living hell!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] has separated [target]'s appendix with \the [tool]." , \ - "\blue You have separated [target]'s appendix with \the [tool].") - target.op_stage.appendix = 1 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/datum/organ/external/groin = target.get_organ("groin") - user.visible_message("\red [user]'s hand slips, slicing an artery inside [target]'s abdomen with \the [tool]!", \ - "\red Your hand slips, slicing an artery inside [target]'s abdomen with \the [tool]!") - groin.createwound(CUT, 50, 1) - -/datum/surgery_step/appendectomy/remove_appendix - allowed_tools = list( - /obj/item/weapon/hemostat = 100, \ - /obj/item/weapon/wirecutters = 75, \ - /obj/item/weapon/kitchen/utensil/fork = 20 - ) - - min_duration = 60 - max_duration = 80 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.op_stage.appendix == 1 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts removing [target]'s appendix with \the [tool].", \ - "You start removing [target]'s appendix with \the [tool].") - target.custom_pain("Someone's ripping out your bowels!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] has removed [target]'s appendix with \the [tool].", \ - "\blue You have removed [target]'s appendix with \the [tool].") - var/app = 0 - for(var/datum/disease/appendicitis/appendicitis in target.viruses) - app = 1 - appendicitis.cure() - target.resistances += appendicitis - if (app) - new /obj/item/weapon/reagent_containers/food/snacks/appendix/inflamed(get_turf(target)) - else - new /obj/item/weapon/reagent_containers/food/snacks/appendix(get_turf(target)) - target.op_stage.appendix = 2 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/datum/organ/external/affected = target.get_organ(target_zone) - user.visible_message("\red [user]'s hand slips, nicking internal organs in [target]'s abdomen with \the [tool]!", \ - "\red Your hand slips, nicking internal organs in [target]'s abdomen with \the [tool]!") - affected.createwound(BRUISE, 20) diff --git a/code/modules/surgery/bones.dm b/code/modules/surgery/bones.dm index 0bc14075677..605b1503d56 100644 --- a/code/modules/surgery/bones.dm +++ b/code/modules/surgery/bones.dm @@ -18,7 +18,7 @@ if (!hasorgans(target)) return 0 var/datum/organ/external/affected = target.get_organ(target_zone) - return affected.open == 2 && affected.stage == 0 + return affected.open >= 2 && affected.stage == 0 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) @@ -52,7 +52,7 @@ if (!hasorgans(target)) return 0 var/datum/organ/external/affected = target.get_organ(target_zone) - return affected.name != "head" && affected.open == 2 && affected.stage == 1 + return affected.name != "head" && affected.open >= 2 && affected.stage == 1 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) @@ -91,7 +91,7 @@ if (!hasorgans(target)) return 0 var/datum/organ/external/affected = target.get_organ(target_zone) - return affected.name == "head" && affected.open == 2 && affected.stage == 1 + return affected.name == "head" && affected.open >= 2 && affected.stage == 1 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user] is beginning to piece together [target]'s skull with \the [tool]." , \ @@ -127,7 +127,7 @@ if (!hasorgans(target)) return 0 var/datum/organ/external/affected = target.get_organ(target_zone) - return affected.open == 2 && affected.stage == 2 + return affected.open >= 2 && affected.stage == 2 begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) diff --git a/code/modules/surgery/braincore.dm b/code/modules/surgery/braincore.dm deleted file mode 100644 index 4bc804eab5d..00000000000 --- a/code/modules/surgery/braincore.dm +++ /dev/null @@ -1,279 +0,0 @@ -//Procedures in this file: Brain extraction. Brain fixing. Slime Core extraction. -////////////////////////////////////////////////////////////////// -// BRAIN SURGERY // -////////////////////////////////////////////////////////////////// - -/datum/surgery_step/brain/ - priority = 2 - blood_level = 1 - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return target_zone == "head" && hasorgans(target) - -/datum/surgery_step/brain/saw_skull - allowed_tools = list( - /obj/item/weapon/circular_saw = 100, \ - /obj/item/weapon/hatchet = 75 - ) - - min_duration = 50 - max_duration = 70 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target_zone == "head" && target.brain_op_stage == 1 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] begins to cut through [target]'s skull with \the [tool].", \ - "You begin to cut through [target]'s skull with \the [tool].") - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] has cut [target]'s skull open with \the [tool].", \ - "\blue You have cut [target]'s skull open with \the [tool].") - target.brain_op_stage = 2 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, cracking [target]'s skull with \the [tool]!" , \ - "\red Your hand slips, cracking [target]'s skull with \the [tool]!" ) - target.apply_damage(max(10, tool.force), BRUTE, "head") - -/datum/surgery_step/brain/cut_brain - allowed_tools = list( - /obj/item/weapon/scalpel = 100, \ - /obj/item/weapon/kitchenknife = 75, \ - /obj/item/weapon/shard = 50, \ - ) - - min_duration = 80 - max_duration = 100 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.brain_op_stage == 2 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts separating connections to [target]'s brain with \the [tool].", \ - "You start separating connections to [target]'s brain with \the [tool].") - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] separates connections to [target]'s brain with \the [tool].", \ - "\blue You separate connections to [target]'s brain with \the [tool].") - target.brain_op_stage = 3 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, cutting a vein in [target]'s brain with \the [tool]!", \ - "\red Your hand slips, cutting a vein in [target]'s brain with \the [tool]!") - target.apply_damage(50, BRUTE, "head", 1, sharp=1) - -/datum/surgery_step/brain/saw_spine - allowed_tools = list( - /obj/item/weapon/circular_saw = 100, \ - /obj/item/weapon/hatchet = 75 - ) - - min_duration = 50 - max_duration = 70 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.brain_op_stage == 3 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts separating [target]'s brain from \his spine with \the [tool].", \ - "You start separating [target]'s brain from spine with \the [tool].") - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] separates [target]'s brain from \his spine with \the [tool].", \ - "\blue You separate [target]'s brain from spine with \the [tool].") - - var/mob/living/simple_animal/borer/borer = target.has_brain_worms() - - if(borer) - borer.detatch() //Should remove borer if the brain is removed - RR - - user.attack_log += "\[[time_stamp()]\] Debrained [target.name] ([target.ckey]) with [tool.name] (INTENT: [uppertext(user.a_intent)])" - target.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [tool.name] (INTENT: [uppertext(user.a_intent)])" - msg_admin_attack("[user.name] ([user.ckey]) debrained [target.name] ([target.ckey]) with [tool.name] (INTENT: [uppertext(user.a_intent)]) (JMP)") - - var/mob/living/carbon/human/H - if(istype(target,/mob/living/carbon/human)) - H = target - - var/obj/item/brain/B - if(H && H.species && H.species.flags & IS_SYNTHETIC) - var/obj/item/device/mmi/posibrain/P = new(target.loc) - P.transfer_identity(target) - else - B = new(target.loc) - B.transfer_identity(target) - - target.internal_organs -= B - target.internal_organs_by_name -= "brain" - - target:brain_op_stage = 4.0 - target.death()//You want them to die after the brain was transferred, so not to trigger client death() twice. - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, cutting a vein in [target]'s brain with \the [tool]!", \ - "\red Your hand slips, cutting a vein in [target]'s brain with \the [tool]!") - target.apply_damage(30, BRUTE, "head", 1, sharp=1) - if (ishuman(user)) - user:bloody_body(target) - user:bloody_hands(target, 0) - - -////////////////////////////////////////////////////////////////// -// BRAIN DAMAGE FIXING // -////////////////////////////////////////////////////////////////// - -/datum/surgery_step/brain/bone_chips - allowed_tools = list( - /obj/item/weapon/hemostat = 100, \ - /obj/item/weapon/wirecutters = 75, \ - /obj/item/weapon/kitchen/utensil/fork = 20 - ) - - min_duration = 80 - max_duration = 100 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.brain_op_stage == 2 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts taking bone chips out of [target]'s brain with \the [tool].", \ - "You start taking bone chips out of [target]'s brain with \the [tool].") - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] takes out all the bone chips in [target]'s brain with \the [tool].", \ - "\blue You take out all the bone chips in [target]'s brain with \the [tool].") - target.brain_op_stage = 3 - - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, jabbing \the [tool] in [target]'s brain!", \ - "\red Your hand slips, jabbing \the [tool] in [target]'s brain!") - target.apply_damage(30, BRUTE, "head", 1, sharp=1) - -/datum/surgery_step/brain/hematoma - allowed_tools = list( - /obj/item/weapon/FixOVein = 100, \ - /obj/item/stack/cable_coil = 75 - ) - - min_duration = 90 - max_duration = 110 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.brain_op_stage == 3 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] starts mending hematoma in [target]'s brain with \the [tool].", \ - "You start mending hematoma in [target]'s brain with \the [tool].") - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] mends hematoma in [target]'s brain with \the [tool].", \ - "\blue You mend hematoma in [target]'s brain with \the [tool].") - var/datum/organ/internal/brain/sponge = target.internal_organs_by_name["brain"] - if (sponge) - sponge.damage = 0 - - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, bruising [target]'s brain with \the [tool]!", \ - "\red Your hand slips, bruising [target]'s brain with \the [tool]!") - target.apply_damage(20, BRUTE, "head", 1, sharp=1) - -////////////////////////////////////////////////////////////////// -// SLIME CORE EXTRACTION // -////////////////////////////////////////////////////////////////// - -/datum/surgery_step/slime - is_valid_target(mob/living/carbon/slime/target) - return istype(target, /mob/living/carbon/slime/) - - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return target.stat == 2 - -/datum/surgery_step/slime/cut_flesh - allowed_tools = list( - /obj/item/weapon/scalpel = 100, \ - /obj/item/weapon/kitchenknife = 75, \ - /obj/item/weapon/shard = 50, \ - ) - - min_duration = 30 - max_duration = 50 - - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && target.brain_op_stage == 0 - - begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \ - "You start cutting through [target]'s flesh with \the [tool].") - - end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] cuts through [target]'s flesh with \the [tool].", \ - "\blue You cut through [target]'s flesh with \the [tool], revealing its silky innards.") - target.brain_op_stage = 1 - - fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \ - "\red Your hand slips, tearing [target]'s flesh with \the [tool]!") - -/datum/surgery_step/slime/cut_innards - allowed_tools = list( - /obj/item/weapon/scalpel = 100, \ - /obj/item/weapon/kitchenknife = 75, \ - /obj/item/weapon/shard = 50, \ - ) - - min_duration = 30 - max_duration = 50 - - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && target.brain_op_stage == 1 - - begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \ - "You start cutting [target]'s silky innards apart with \the [tool].") - - end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] cuts [target]'s innards apart with \the [tool], exposing the cores.", \ - "\blue You cut [target]'s innards apart with \the [tool], exposing the cores.") - target.brain_op_stage = 2 - - fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, tearing [target]'s innards with \the [tool]!", \ - "\red Your hand slips, tearing [target]'s innards with \the [tool]!") - -/datum/surgery_step/slime/saw_core - allowed_tools = list( - /obj/item/weapon/circular_saw = 100, \ - /obj/item/weapon/hatchet = 75 - ) - - min_duration = 50 - max_duration = 70 - - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && target.brain_op_stage == 2 && target.cores > 0 - - begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("[user] starts cutting out one of [target]'s cores with \the [tool].", \ - "You start cutting out one of [target]'s cores with \the [tool].") - - end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - target.cores-- - user.visible_message("\blue [user] cuts out one of [target]'s cores with \the [tool].",, \ - "\blue You cut out one of [target]'s cores with \the [tool]. [target.cores] cores left.") - - if(target.cores >= 0) - new target.coretype(target.loc) - if(target.cores <= 0) - target.icon_state = "[target.colour] baby slime dead-nocore" - - - fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, causing \him to miss the core!", \ - "\red Your hand slips, causing you to miss the core!") \ No newline at end of file diff --git a/code/modules/surgery/brainrepair.dm b/code/modules/surgery/brainrepair.dm new file mode 100644 index 00000000000..85b5dd8dd3e --- /dev/null +++ b/code/modules/surgery/brainrepair.dm @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////// +// BRAIN DAMAGE FIXING // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/brain/bone_chips + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/weapon/wirecutters = 75, \ + /obj/item/weapon/kitchen/utensil/fork = 20 + ) + + priority = 3 + min_duration = 80 + max_duration = 100 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/external/affected = target.get_organ(target_zone) + var/datum/organ/internal/brain/sponge = target.internal_organs_by_name["brain"] + return (sponge && sponge.damage > 0 && sponge.damage <= 20) && affected.open == 3 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts taking bone chips out of [target]'s brain with \the [tool].", \ + "You start taking bone chips out of [target]'s brain with \the [tool].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] takes out all the bone chips in [target]'s brain with \the [tool].", \ + "\blue You take out all the bone chips in [target]'s brain with \the [tool].") + var/datum/organ/internal/brain/sponge = target.internal_organs_by_name["brain"] + if (sponge) + sponge.damage = 0 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, jabbing \the [tool] in [target]'s brain!", \ + "\red Your hand slips, jabbing \the [tool] in [target]'s brain!") + target.apply_damage(30, BRUTE, "head", 1, sharp=1) + +/datum/surgery_step/brain/hematoma + allowed_tools = list( + /obj/item/weapon/FixOVein = 100, \ + /obj/item/stack/cable_coil = 75 + ) + + priority = 3 + min_duration = 90 + max_duration = 110 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/external/affected = target.get_organ(target_zone) + var/datum/organ/internal/brain/sponge = target.internal_organs_by_name["brain"] + return (sponge && sponge.damage > 20) && affected.open == 3 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts mending hematoma in [target]'s brain with \the [tool].", \ + "You start mending hematoma in [target]'s brain with \the [tool].") + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] mends hematoma in [target]'s brain with \the [tool].", \ + "\blue You mend hematoma in [target]'s brain with \the [tool].") + var/datum/organ/internal/brain/sponge = target.internal_organs_by_name["brain"] + if (sponge) + sponge.damage = 20 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, bruising [target]'s brain with \the [tool]!", \ + "\red Your hand slips, bruising [target]'s brain with \the [tool]!") + target.apply_damage(20, BRUTE, "head", 1, sharp=1) \ No newline at end of file diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm new file mode 100644 index 00000000000..dcd6cc4b318 --- /dev/null +++ b/code/modules/surgery/encased.dm @@ -0,0 +1,220 @@ +//Procedures in this file: Generic ribcage opening steps, Removing alien embryo, Fixing internal organs. +////////////////////////////////////////////////////////////////// +// GENERIC RIBCAGE SURGERY // +////////////////////////////////////////////////////////////////// +/datum/surgery_step/open_encased + priority = 2 + can_infect = 1 + blood_level = 1 + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return 0 + + var/datum/organ/external/affected = target.get_organ(target_zone) + return affected.encased && affected.open >= 2 + + +/datum/surgery_step/open_encased/saw + allowed_tools = list( + /obj/item/weapon/circular_saw = 100, \ + /obj/item/weapon/hatchet = 75 + ) + + min_duration = 50 + max_duration = 70 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + return ..() && affected.open == 2 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("[user] begins to cut through [target]'s [affected.encased] with \the [tool].", \ + "You begin to cut through [target]'s [affected.encased] with \the [tool].") + target.custom_pain("Something hurts horribly in your [affected.display_name]!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("\blue [user] has cut [target]'s [affected.encased] open with \the [tool].", \ + "\blue You have cut [target]'s [affected.encased] open with \the [tool].") + affected.open = 2.5 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("\red [user]'s hand slips, cracking [target]'s [affected.encased] with \the [tool]!" , \ + "\red Your hand slips, cracking [target]'s [affected.encased] with \the [tool]!" ) + + affected.createwound(CUT, 20) + affected.fracture() + + +/datum/surgery_step/open_encased/retract + allowed_tools = list( + /obj/item/weapon/retractor = 100, \ + /obj/item/weapon/crowbar = 75, \ + /obj/item/weapon/kitchen/utensil/fork = 20 + ) + + min_duration = 30 + max_duration = 40 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + return ..() && affected.open == 2.5 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "[user] starts to force open the [affected.encased] in [target]'s [affected.display_name] with \the [tool]." + var/self_msg = "You start to force open the [affected.encased] in [target]'s [affected.display_name] with \the [tool]." + user.visible_message(msg, self_msg) + target.custom_pain("Something hurts horribly in your [affected.display_name]!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "\blue [user] forces open [target]'s [affected.encased] with \the [tool]." + var/self_msg = "\blue You force open [target]'s [affected.encased] with \the [tool]." + user.visible_message(msg, self_msg) + + affected.open = 3 + + // Whoops! + if(prob(10)) + affected.fracture() + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "\red [user]'s hand slips, cracking [target]'s [affected.encased]!" + var/self_msg = "\red Your hand slips, cracking [target]'s [affected.encased]!" + user.visible_message(msg, self_msg) + + affected.createwound(BRUISE, 20) + affected.fracture() + +/datum/surgery_step/open_encased/close + allowed_tools = list( + /obj/item/weapon/retractor = 100, \ + /obj/item/weapon/crowbar = 75, \ + /obj/item/weapon/kitchen/utensil/fork = 20 + ) + + min_duration = 20 + max_duration = 40 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + return ..() && affected.open == 3 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "[user] starts bending [target]'s [affected.encased] back into place with \the [tool]." + var/self_msg = "You start bending [target]'s [affected.encased] back into place with \the [tool]." + user.visible_message(msg, self_msg) + target.custom_pain("Something hurts horribly in your [affected.display_name]!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "\blue [user] bends [target]'s [affected.encased] back into place with \the [tool]." + var/self_msg = "\blue You bend [target]'s [affected.encased] back into place with \the [tool]." + user.visible_message(msg, self_msg) + + affected.open = 2.5 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "\red [user]'s hand slips, bending [target]'s [affected.encased] the wrong way!" + var/self_msg = "\red Your hand slips, bending [target]'s [affected.encased] the wrong way!" + user.visible_message(msg, self_msg) + + affected.createwound(BRUISE, 20) + affected.fracture() + + /*if (prob(40)) //TODO: ORGAN REMOVAL UPDATE. + user.visible_message("\red A rib pierces the lung!") + target.rupture_lung()*/ + +/datum/surgery_step/open_encased/mend + allowed_tools = list( + /obj/item/weapon/bonegel = 100, \ + /obj/item/weapon/screwdriver = 75 + ) + + min_duration = 20 + max_duration = 40 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + return ..() && affected.open == 2.5 + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "[user] starts applying \the [tool] to [target]'s [affected.encased]." + var/self_msg = "You start applying \the [tool] to [target]'s [affected.encased]." + user.visible_message(msg, self_msg) + target.custom_pain("Something hurts horribly in your [affected.display_name]!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/msg = "\blue [user] applied \the [tool] to [target]'s [affected.encased]." + var/self_msg = "\blue You applied \the [tool] to [target]'s [affected.encased]." + user.visible_message(msg, self_msg) + + affected.open = 2 \ No newline at end of file diff --git a/code/modules/surgery/eye.dm b/code/modules/surgery/eye.dm index d142b8ef67c..0fa9f4863a1 100644 --- a/code/modules/surgery/eye.dm +++ b/code/modules/surgery/eye.dm @@ -12,7 +12,10 @@ var/datum/organ/external/affected = target.get_organ(target_zone) if (!affected) return 0 - return target_zone == "eyes" + + var/datum/organ/internal/eyes = target.internal_organs_by_name["eyes"] + + return target_zone == "eyes" && eyes /datum/surgery_step/eye/cut_open allowed_tools = list( diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index 94c7b2b861e..a05c6f120b2 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -56,8 +56,6 @@ affected.createwound(CUT, 1) affected.clamp() spread_germs_to_organ(affected, user) - if (target_zone == "head") - target.brain_op_stage = 1 fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) @@ -95,8 +93,6 @@ affected.createwound(CUT, 1) affected.clamp() affected.open = 2 - if (target_zone == "head") - target.brain_op_stage = 1 fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) @@ -134,8 +130,6 @@ affected.open = 1 affected.status |= ORGAN_BLEEDING affected.createwound(CUT, 1) - if (target_zone == "head") - target.brain_op_stage = 1 fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) @@ -191,7 +185,7 @@ can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) if(..()) var/datum/organ/external/affected = target.get_organ(target_zone) - return affected.open == 1 && !(affected.status & ORGAN_BLEEDING) + return affected.open == 1 //&& !(affected.status & ORGAN_BLEEDING) begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index 57df6a398c6..7e2fbc776e4 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -10,7 +10,7 @@ if(!hasorgans(target)) return 0 var/datum/organ/external/affected = target.get_organ(target_zone) - return affected.open == 2 && !(affected.status & ORGAN_BLEEDING) && (target_zone != "chest" || target.op_stage.ribcage == 2) + return affected.open == (affected.encased ? 3 : 2) && !(affected.status & ORGAN_BLEEDING) proc/get_max_wclass(datum/organ/external/affected) switch (affected.name) @@ -156,6 +156,10 @@ min_duration = 80 max_duration = 100 + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/internal/brain/sponge = target.internal_organs_by_name["brain"] + return ..() && (!sponge || !sponge.damage) + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts poking around inside the incision on [target]'s [affected.display_name] with \the [tool].", \ diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm new file mode 100644 index 00000000000..87675e906ef --- /dev/null +++ b/code/modules/surgery/organs_internal.dm @@ -0,0 +1,493 @@ +// Internal surgeries. +/datum/surgery_step/internal + priority = 2 + can_infect = 1 + blood_level = 1 + +/datum/surgery_step/internal/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return 0 + + var/datum/organ/external/affected = target.get_organ(target_zone) + return affected.open == (affected.encased ? 3 : 2) + +////////////////////////////////////////////////////////////////// +// ALIEN EMBRYO SURGERY // +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/remove_embryo + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/weapon/wirecutters = 75, \ + /obj/item/weapon/kitchen/utensil/fork = 20 + ) + blood_level = 2 + + min_duration = 80 + max_duration = 100 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/embryo = 0 + for(var/obj/item/alien_embryo/A in target) + embryo = 1 + break + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + return ..() && embryo && affected.open == 3 && target_zone == "chest" + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/msg = "[user] starts to pull something out from [target]'s ribcage with \the [tool]." + var/self_msg = "You start to pull something out from [target]'s ribcage with \the [tool]." + user.visible_message(msg, self_msg) + target.custom_pain("Something hurts horribly in your chest!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user] rips the larva out of [target]'s ribcage!", + "You rip the larva out of [target]'s ribcage!") + + for(var/obj/item/alien_embryo/A in target) + A.loc = A.loc.loc + + +////////////////////////////////////////////////////////////////// +// CHEST INTERNAL ORGAN SURGERY // +////////////////////////////////////////////////////////////////// +/datum/surgery_step/internal/fix_organ + allowed_tools = list( + /obj/item/stack/medical/advanced/bruise_pack= 100, \ + /obj/item/stack/medical/bruise_pack = 20, \ + /obj/item/stack/medical/bruise_pack/tajaran = 70, \ + ) + + min_duration = 70 + max_duration = 90 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/is_organ_damaged = 0 + for(var/datum/organ/internal/I in affected.internal_organs) + if(I.damage > 0) + is_organ_damaged = 1 + break + return ..() && is_organ_damaged + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/tool_name = "\the [tool]" + if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + tool_name = "regenerative membrane" + if (istype(tool, /obj/item/stack/medical/bruise_pack)) + if (istype(tool, /obj/item/stack/medical/bruise_pack/tajaran)) + tool_name = "the poultice" + else + tool_name = "the bandaid" + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + for(var/datum/organ/internal/I in affected.internal_organs) + if(I && I.damage > 0) + if(I.robotic < 2) + user.visible_message("[user] starts treating damage to [target]'s [I.name] with [tool_name].", \ + "You start treating damage to [target]'s [I.name] with [tool_name]." ) + + target.custom_pain("The pain in your [affected.display_name] is living hell!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/tool_name = "\the [tool]" + if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + tool_name = "regenerative membrane" + if (istype(tool, /obj/item/stack/medical/bruise_pack)) + if (istype(tool, /obj/item/stack/medical/bruise_pack/tajaran)) + tool_name = "the poultice" + else + tool_name = "the bandaid" + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + for(var/datum/organ/internal/I in affected.internal_organs) + if(I && I.damage > 0) + if(I.robotic < 2) + user.visible_message("\blue [user] treats damage to [target]'s [I.name] with [tool_name].", \ + "\blue You treat damage to [target]'s [I.name] with [tool_name]." ) + I.damage = 0 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("\red [user]'s hand slips, getting mess and tearing the inside of [target]'s [affected.display_name] with \the [tool]!", \ + "\red Your hand slips, getting mess and tearing the inside of [target]'s [affected.display_name] with \the [tool]!") + var/dam_amt = 2 + + if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) + target.adjustToxLoss(5) + + else if (istype(tool, /obj/item/stack/medical/bruise_pack)) + if (istype(tool, /obj/item/stack/medical/bruise_pack/tajaran)) + target.adjustToxLoss(7) + else + dam_amt = 5 + target.adjustToxLoss(10) + affected.createwound(CUT, 5) + + for(var/datum/organ/internal/I in affected.internal_organs) + if(I && I.damage > 0) + I.take_damage(dam_amt,0) + +/datum/surgery_step/internal/fix_organ_robotic //For artificial organs + allowed_tools = list( + /obj/item/stack/nanopaste = 100, \ + /obj/item/weapon/bonegel = 30, \ + /obj/item/weapon/screwdriver = 70, \ + ) + + min_duration = 70 + max_duration = 90 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/is_organ_damaged = 0 + for(var/datum/organ/internal/I in affected.internal_organs) + if(I.damage > 0 && I.robotic >= 2) + is_organ_damaged = 1 + break + return ..() && is_organ_damaged + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + for(var/datum/organ/internal/I in affected.internal_organs) + if(I && I.damage > 0) + if(I.robotic >= 2) + user.visible_message("[user] starts mending the damage to [target]'s [I.name]'s mechanisms.", \ + "You start mending the damage to [target]'s [I.name]'s mechanisms." ) + + target.custom_pain("The pain in your [affected.display_name] is living hell!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + for(var/datum/organ/internal/I in affected.internal_organs) + + if(I && I.damage > 0) + if(I.robotic >= 2) + user.visible_message("\blue [user] repairs [target]'s [I.name] with [tool].", \ + "\blue You repair [target]'s [I.name] with [tool]." ) + I.damage = 0 + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!hasorgans(target)) + return + var/datum/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("\red [user]'s hand slips, gumming up the mechanisms inside of [target]'s [affected.display_name] with \the [tool]!", \ + "\red Your hand slips, gumming up the mechanisms inside of [target]'s [affected.display_name] with \the [tool]!") + + target.adjustToxLoss(5) + affected.createwound(CUT, 5) + + for(var/datum/organ/internal/I in affected.internal_organs) + if(I) + I.take_damage(rand(3,5),0) + + +/datum/surgery_step/internal/detatch_organ + + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/kitchenknife = 75, \ + /obj/item/weapon/shard = 50, \ + ) + + min_duration = 90 + max_duration = 110 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!..()) + return 0 + + target.op_stage.current_organ = null + + var/list/attached_organs = list() + for(var/organ in target.internal_organs_by_name) + var/datum/organ/internal/I = target.internal_organs_by_name[organ] + if(!I.status && I.parent_organ == target_zone) + attached_organs |= organ + + var/organ_to_remove = input(user, "Which organ do you want to prepare for removal?") as null|anything in attached_organs + if(!organ_to_remove) + return 0 + + target.op_stage.current_organ = organ_to_remove + + return ..() && organ_to_remove + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + var/datum/organ/external/affected = target.get_organ(target_zone) + + user.visible_message("[user] starts to separate [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start to separate [target]'s [target.op_stage.current_organ] with \the [tool]." ) + target.custom_pain("The pain in your [affected.display_name] is living hell!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] has separated [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "\blue You have separated [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/datum/organ/internal/I = target.internal_organs_by_name[target.op_stage.current_organ] + if(I && istype(I)) + I.status |= ORGAN_CUT_AWAY + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s hand slips, slicing an artery inside [target]'s [affected.display_name] with \the [tool]!", \ + "\red Your hand slips, slicing an artery inside [target]'s [affected.display_name] with \the [tool]!") + affected.createwound(CUT, rand(30,50), 1) + +/datum/surgery_step/internal/remove_organ + + allowed_tools = list( + /obj/item/weapon/hemostat = 100, \ + /obj/item/weapon/wirecutters = 75, \ + /obj/item/weapon/kitchen/utensil/fork = 20 + ) + + min_duration = 60 + max_duration = 80 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!..()) + return 0 + + target.op_stage.current_organ = null + + var/list/removable_organs = list() + for(var/organ in target.internal_organs_by_name) + var/datum/organ/internal/I = target.internal_organs_by_name[organ] + if(I.status & ORGAN_CUT_AWAY && I.parent_organ == target_zone) + removable_organs |= organ + + var/organ_to_remove = input(user, "Which organ do you want to remove?") as null|anything in removable_organs + if(!organ_to_remove) + return 0 + + target.op_stage.current_organ = organ_to_remove + return ..() + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] starts removing [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start removing [target]'s [target.op_stage.current_organ] with \the [tool].") + target.custom_pain("Someone's ripping out your [target.op_stage.current_organ]!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] has removed [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "\blue You have removed [target]'s [target.op_stage.current_organ] with \the [tool].") + + // Extract the organ! + if(target.op_stage.current_organ) + + var/datum/organ/external/affected = target.get_organ(target_zone) + var/datum/organ/internal/I = target.internal_organs_by_name[target.op_stage.current_organ] + + var/obj/item/organ/O + if(I && istype(I)) + O = I.remove(user) + if(O && istype(O)) + + // Stop the organ from continuing to reject. + O.organ_data.rejecting = null + + // Transfer over some blood data, if the organ doesn't have data. + var/datum/reagent/blood/organ_blood = O.reagents.reagent_list["blood"] + if(!organ_blood || !organ_blood.data["blood_DNA"]) + target.vessel.trans_to(O, 5, 1, 1) + + // Kinda redundant, but I'm getting some buggy behavior. + target.internal_organs_by_name[target.op_stage.current_organ] = null + target.internal_organs_by_name -= target.op_stage.current_organ + target.internal_organs -= O.organ_data + affected.internal_organs -= O.organ_data + O.removed(target,user) + + target.op_stage.current_organ = null + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s hand slips, damaging the flesh in [target]'s [affected.display_name] with \the [tool]!", \ + "\red Your hand slips, damaging the flesh in [target]'s [affected.display_name] with \the [tool]!") + affected.createwound(BRUISE, 20) + +/datum/surgery_step/internal/replace_organ + allowed_tools = list( + /obj/item/organ = 100 + ) + + min_duration = 60 + max_duration = 80 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + var/obj/item/organ/O = tool + var/datum/organ/external/affected = target.get_organ(target_zone) + + var/organ_compatible + var/organ_missing + + if(!istype(O)) + return 0 + + if(target.species && target.species.has_organ[O.organ_tag]) + + if(!O.health) + user << "\red \The [O.organ_tag] is dead." + return 0 + + if(!target.internal_organs_by_name[O.organ_tag]) + organ_missing = 1 + else + user << "\red \The [target] already has a [O.organ_tag]." //TODO: grammar. + return 0 + + if(O.organ_data && affected.name == O.organ_data.parent_organ) + organ_compatible = 1 + else + user << "\red \The [O.organ_tag] doesn't normally go in \the [affected.display_name]." + return 0 + else + user << "\red \A [target.species.name] doesn't normally have a [O.organ_tag]." //TODO: grammar. + return 0 + + return ..() && organ_missing && organ_compatible + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/external/affected = target.get_organ(target_zone) + user.visible_message("[user] starts transplanting \the [tool] into [target]'s [affected.display_name].", \ + "You start transplanting \the [tool] into [target]'s [affected.display_name].") + target.custom_pain("Someone's rooting around in your [affected.display_name]!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\blue [user] has transplanted \the [tool] into [target]'s [affected.display_name].", \ + "\blue You have transplanted \the [tool] into [target]'s [affected.display_name].") + user.drop_item(tool) + var/obj/item/organ/O = tool + + if(istype(O)) + + if(!O.organ_data.transplant_data) + O.organ_data.transplant_data = list() + O.organ_data.transplant_data["species"] = target.species.name + O.organ_data.transplant_data["blood_type"] = target.dna.b_type + O.organ_data.transplant_data["blood_DNA"] = target.dna.unique_enzymes + + O.organ_data.owner = target + target.internal_organs |= O.organ_data + affected.internal_organs |= O.organ_data + target.internal_organs_by_name[O.organ_tag] = O.organ_data + O.organ_data.status |= ORGAN_CUT_AWAY + O.replaced(target) + + del(O) + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, damaging \the [tool]!", \ + "\red Your hand slips, damaging \the [tool]!") + var/obj/item/organ/I = tool + if(istype(I)) + I.organ_data.take_damage(rand(3,5),0) + +/datum/surgery_step/internal/attach_organ + allowed_tools = list( + /obj/item/weapon/FixOVein = 100, \ + /obj/item/stack/cable_coil = 75 + ) + + min_duration = 100 + max_duration = 120 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + + if (!..()) + return 0 + + target.op_stage.current_organ = null + + var/list/removable_organs = list() + for(var/organ in target.internal_organs_by_name) + var/datum/organ/internal/I = target.internal_organs_by_name[organ] + if(I.status & ORGAN_CUT_AWAY && I.parent_organ == target_zone) + removable_organs |= organ + + var/organ_to_replace = input(user, "Which organ do you want to reattach?") as null|anything in removable_organs + if(!organ_to_replace) + return 0 + + target.op_stage.current_organ = organ_to_replace + return ..() + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] begins reattaching [target]'s [target.op_stage.current_organ] with \the [tool].", \ + "You start reattaching [target]'s [target.op_stage.current_organ] with \the [tool].") + target.custom_pain("Someone's digging needles into your [target.op_stage.current_organ]!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] has reattached [target]'s [target.op_stage.current_organ] with \the [tool]." , \ + "\blue You have reattached [target]'s [target.op_stage.current_organ] with \the [tool].") + + var/datum/organ/internal/I = target.internal_organs_by_name[target.op_stage.current_organ] + if(I && istype(I)) + I.status &= ~ORGAN_CUT_AWAY + + fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/datum/organ/external/affected = target.get_organ(target_zone) + user.visible_message("\red [user]'s hand slips, damaging the flesh in [target]'s [affected.display_name] with \the [tool]!", \ + "\red Your hand slips, damaging the flesh in [target]'s [affected.display_name] with \the [tool]!") + affected.createwound(BRUISE, 20) + +////////////////////////////////////////////////////////////////// +// HEART SURGERY // +////////////////////////////////////////////////////////////////// +// To be finished after some tests. +// /datum/surgery_step/ribcage/heart/cut +// allowed_tools = list( +// /obj/item/weapon/scalpel = 100, \ +// /obj/item/weapon/kitchenknife = 75, \ +// /obj/item/weapon/shard = 50, \ +// ) + +// min_duration = 30 +// max_duration = 40 + +// can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) +// return ..() && target.op_stage.ribcage == 2 \ No newline at end of file diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm index 67f3cb82dec..ccd9d388e26 100644 --- a/code/modules/surgery/other.dm +++ b/code/modules/surgery/other.dm @@ -27,7 +27,7 @@ internal_bleeding = 1 break - return affected.open == 2 && internal_bleeding + return affected.open >= 2 && internal_bleeding begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) @@ -59,7 +59,7 @@ /obj/item/weapon/kitchenknife = 75, \ /obj/item/weapon/shard = 50, \ ) - + can_infect = 1 blood_level = 1 @@ -72,10 +72,10 @@ if (target_zone == "mouth" || target_zone == "eyes") return 0 - + var/datum/organ/external/affected = target.get_organ(target_zone) - return affected.open == 2 && (affected.status & ORGAN_DEAD) + return affected.open >= 2 && (affected.status & ORGAN_DEAD) begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) @@ -105,7 +105,7 @@ /obj/item/weapon/reagent_containers/spray = 50, /obj/item/weapon/reagent_containers/glass/bucket = 50, ) - + can_infect = 0 blood_level = 0 @@ -115,7 +115,7 @@ can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) if (!istype(tool, /obj/item/weapon/reagent_containers)) return 0 - + var/obj/item/weapon/reagent_containers/container = tool if(!container.reagents.has_reagent("peridaxon")) return 0 @@ -125,7 +125,7 @@ if (target_zone == "mouth" || target_zone == "eyes") return 0 - + var/datum/organ/external/affected = target.get_organ(target_zone) return affected.open == 3 && (affected.status & ORGAN_DEAD) @@ -138,34 +138,34 @@ end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) - + if (!istype(tool, /obj/item/weapon/reagent_containers)) return - + var/obj/item/weapon/reagent_containers/container = tool - + var/trans = container.reagents.trans_to(target, container.amount_per_transfer_from_this) if (trans > 0) container.reagents.reaction(target, INGEST) //technically it's contact, but the reagents are being applied to internal tissue - + if(container.reagents.has_reagent("peridaxon")) affected.status &= ~ORGAN_DEAD - + user.visible_message("\blue [user] applies [trans] units of the solution to affected tissue in [target]'s [affected.display_name]", \ "\blue You apply [trans] units of the solution to affected tissue in [target]'s [affected.display_name] with \the [tool].") fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/datum/organ/external/affected = target.get_organ(target_zone) - + if (!istype(tool, /obj/item/weapon/reagent_containers)) return - + var/obj/item/weapon/reagent_containers/container = tool - + var/trans = container.reagents.trans_to(target, container.amount_per_transfer_from_this) container.reagents.reaction(target, INGEST) //technically it's contact, but the reagents are being applied to internal tissue - + user.visible_message("\red [user]'s hand slips, applying [trans] units of the solution to the wrong place in [target]'s [affected.display_name] with the [tool]!" , \ "\red Your hand slips, applying [trans] units of the solution to the wrong place in [target]'s [affected.display_name] with the [tool]!") - + //no damage or anything, just wastes medicine diff --git a/code/modules/surgery/ribcage.dm b/code/modules/surgery/ribcage.dm deleted file mode 100644 index c14d065cd9b..00000000000 --- a/code/modules/surgery/ribcage.dm +++ /dev/null @@ -1,335 +0,0 @@ -//Procedures in this file: Generic ribcage opening steps, Removing alien embryo, Fixing internal organs. -////////////////////////////////////////////////////////////////// -// GENERIC RIBCAGE SURGERY // -////////////////////////////////////////////////////////////////// -/datum/surgery_step/ribcage - priority = 2 - can_infect = 1 - blood_level = 1 - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return target_zone == "chest" - -/datum/surgery_step/ribcage/saw_ribcage - allowed_tools = list( - /obj/item/weapon/circular_saw = 100, \ - /obj/item/weapon/hatchet = 75 - ) - - min_duration = 50 - max_duration = 70 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if (!hasorgans(target)) - return - var/datum/organ/external/affected = target.get_organ(target_zone) - return ..() && target.op_stage.ribcage == 0 && affected.open >= 2 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("[user] begins to cut through [target]'s ribcage with \the [tool].", \ - "You begin to cut through [target]'s ribcage with \the [tool].") - target.custom_pain("Something hurts horribly in your chest!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\blue [user] has cut [target]'s ribcage open with \the [tool].", \ - "\blue You have cut [target]'s ribcage open with \the [tool].") - target.op_stage.ribcage = 1 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user]'s hand slips, cracking [target]'s ribcage with \the [tool]!" , \ - "\red Your hand slips, cracking [target]'s ribcage with \the [tool]!" ) - var/datum/organ/external/affected = target.get_organ(target_zone) - affected.createwound(CUT, 20) - affected.fracture() - - -/datum/surgery_step/ribcage/retract_ribcage - allowed_tools = list( - /obj/item/weapon/retractor = 100, \ - /obj/item/weapon/crowbar = 75, \ - /obj/item/weapon/kitchen/utensil/fork = 20 - ) - - min_duration = 30 - max_duration = 40 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.op_stage.ribcage == 1 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "[user] starts to force open the ribcage in [target]'s torso with \the [tool]." - var/self_msg = "You start to force open the ribcage in [target]'s torso with \the [tool]." - user.visible_message(msg, self_msg) - target.custom_pain("Something hurts horribly in your chest!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "\blue [user] forces open [target]'s ribcage with \the [tool]." - var/self_msg = "\blue You force open [target]'s ribcage with \the [tool]." - user.visible_message(msg, self_msg) - target.op_stage.ribcage = 2 - - // Whoops! - if(prob(10)) - var/datum/organ/external/affected = target.get_organ(target_zone) - affected.fracture() - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "\red [user]'s hand slips, breaking [target]'s ribcage!" - var/self_msg = "\red Your hand slips, breaking [target]'s ribcage!" - user.visible_message(msg, self_msg) - var/datum/organ/external/affected = target.get_organ(target_zone) - affected.createwound(BRUISE, 20) - affected.fracture() - -/datum/surgery_step/ribcage/close_ribcage - allowed_tools = list( - /obj/item/weapon/retractor = 100, \ - /obj/item/weapon/crowbar = 75, \ - /obj/item/weapon/kitchen/utensil/fork = 20 - ) - - - min_duration = 20 - max_duration = 40 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.op_stage.ribcage == 2 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "[user] starts bending [target]'s ribcage back into place with \the [tool]." - var/self_msg = "You start bending [target]'s ribcage back into place with \the [tool]." - user.visible_message(msg, self_msg) - target.custom_pain("Something hurts horribly in your chest!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "\blue [user] bends [target]'s ribcage back into place with \the [tool]." - var/self_msg = "\blue You bend [target]'s ribcage back into place with \the [tool]." - user.visible_message(msg, self_msg) - - target.op_stage.ribcage = 1 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "\red [user]'s hand slips, bending [target]'s ribs the wrong way!" - var/self_msg = "\red Your hand slips, bending [target]'s ribs the wrong way!" - user.visible_message(msg, self_msg) - var/datum/organ/external/chest/affected = target.get_organ("chest") - affected.createwound(BRUISE, 20) - affected.fracture() - if (prob(40)) - user.visible_message("\red A rib pierces the lung!") - target.rupture_lung() - -/datum/surgery_step/ribcage/mend_ribcage - allowed_tools = list( - /obj/item/weapon/bonegel = 100, \ - /obj/item/weapon/screwdriver = 75 - ) - - min_duration = 20 - max_duration = 40 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - return ..() && target.op_stage.ribcage == 1 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "[user] starts applying \the [tool] to [target]'s ribcage." - var/self_msg = "You start applying \the [tool] to [target]'s ribcage." - user.visible_message(msg, self_msg) - target.custom_pain("Something hurts horribly in your chest!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "\blue [user] applied \the [tool] to [target]'s ribcage." - var/self_msg = "\blue You applied \the [tool] to [target]'s ribcage." - user.visible_message(msg, self_msg) - - target.op_stage.ribcage = 0 - -////////////////////////////////////////////////////////////////// -// ALIEN EMBRYO SURGERY // -////////////////////////////////////////////////////////////////// -/datum/surgery_step/ribcage/remove_embryo - allowed_tools = list( - /obj/item/weapon/hemostat = 100, \ - /obj/item/weapon/wirecutters = 75, \ - /obj/item/weapon/kitchen/utensil/fork = 20 - ) - blood_level = 2 - - min_duration = 80 - max_duration = 100 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/embryo = 0 - for(var/obj/item/alien_embryo/A in target) - embryo = 1 - break - return ..() && embryo && target.op_stage.ribcage == 2 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/msg = "[user] starts to pull something out from [target]'s ribcage with \the [tool]." - var/self_msg = "You start to pull something out from [target]'s ribcage with \the [tool]." - user.visible_message(msg, self_msg) - target.custom_pain("Something hurts horribly in your chest!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - user.visible_message("\red [user] rips the larva out of [target]'s ribcage!", - "You rip the larva out of [target]'s ribcage!") - - for(var/obj/item/alien_embryo/A in target) - A.loc = A.loc.loc - - -////////////////////////////////////////////////////////////////// -// CHEST INTERNAL ORGAN SURGERY // -////////////////////////////////////////////////////////////////// -/datum/surgery_step/ribcage/fix_chest_internal - allowed_tools = list( - /obj/item/stack/medical/advanced/bruise_pack= 100, \ - /obj/item/stack/medical/bruise_pack = 20, \ - /obj/item/stack/medical/bruise_pack/tajaran = 70, \ - ) - - min_duration = 70 - max_duration = 90 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(!hasorgans(target)) - return 0 - - var/is_chest_organ_damaged = 0 - var/datum/organ/external/chest/chest = target.get_organ("chest") - for(var/datum/organ/internal/I in chest.internal_organs) - if(I.damage > 0) - is_chest_organ_damaged = 1 - break - return ..() && is_chest_organ_damaged && target.op_stage.ribcage == 2 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/tool_name = "\the [tool]" - if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) - tool_name = "regenerative membrane" - if (istype(tool, /obj/item/stack/medical/bruise_pack)) - if (istype(tool, /obj/item/stack/medical/bruise_pack/tajaran)) - tool_name = "the poultice" - else - tool_name = "the bandaid" - var/datum/organ/external/chest/chest = target.get_organ("chest") - for(var/datum/organ/internal/I in chest.internal_organs) - if(I && I.damage > 0) - if(I.robotic < 2) - user.visible_message("[user] starts treating damage to [target]'s [I.name] with [tool_name].", \ - "You start treating damage to [target]'s [I.name] with [tool_name]." ) - else - user.visible_message("[user] attempts to repair [target]'s mechanical [I.name] with [tool_name]...", \ - "\blue You attempt to repair [target]'s mechanical [I.name] with [tool_name]...") - - target.custom_pain("The pain in your chest is living hell!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/tool_name = "\the [tool]" - if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) - tool_name = "regenerative membrane" - if (istype(tool, /obj/item/stack/medical/bruise_pack)) - if (istype(tool, /obj/item/stack/medical/bruise_pack/tajaran)) - tool_name = "the poultice" - else - tool_name = "the bandaid" - var/datum/organ/external/chest/chest = target.get_organ("chest") - for(var/datum/organ/internal/I in chest.internal_organs) - if(I && I.damage > 0) - if(I.robotic < 2) - user.visible_message("\blue [user] treats damage to [target]'s [I.name] with [tool_name].", \ - "\blue You treat damage to [target]'s [I.name] with [tool_name]." ) - else - user.visible_message("\blue [user] pokes [target]'s mechanical [I.name] with [tool_name]...", \ - "\blue You poke [target]'s mechanical [I.name] with [tool_name]... \red For no effect, since it's robotic.") - I.damage = 0 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/datum/organ/external/chest/affected = target.get_organ("chest") - user.visible_message("\red [user]'s hand slips, getting mess and tearing the inside of [target]'s chest with \the [tool]!", \ - "\red Your hand slips, getting mess and tearing the inside of [target]'s chest with \the [tool]!") - var/dam_amt = 2 - - if (istype(tool, /obj/item/stack/medical/advanced/bruise_pack)) - target.adjustToxLoss(5) - - else if (istype(tool, /obj/item/stack/medical/bruise_pack)) - if (istype(tool, /obj/item/stack/medical/bruise_pack/tajaran)) - target.adjustToxLoss(7) - else - dam_amt = 5 - target.adjustToxLoss(10) - affected.createwound(CUT, 5) - - for(var/datum/organ/internal/I in affected.internal_organs) - if(I && I.damage > 0) - I.take_damage(dam_amt,0) - -/datum/surgery_step/ribcage/fix_chest_internal_robot //For artificial organs - allowed_tools = list( - /obj/item/stack/nanopaste = 100, \ - /obj/item/weapon/bonegel = 30, \ - /obj/item/weapon/screwdriver = 70, \ - ) - - min_duration = 70 - max_duration = 90 - - can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - if(!hasorgans(target)) - return 0 - - var/is_chest_organ_damaged = 0 - var/datum/organ/internal/heart/heart = target.internal_organs_by_name["heart"] - var/datum/organ/external/chest/chest = target.get_organ("chest") - for(var/datum/organ/internal/I in chest.internal_organs) if(I.damage > 0) - is_chest_organ_damaged = 1 - break - return ..() && is_chest_organ_damaged && heart.robotic == 2 && target.op_stage.ribcage == 2 - - begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/datum/organ/internal/heart/heart = target.internal_organs_by_name["heart"] - - if(heart.damage > 0) - user.visible_message("[user] starts mending the mechanisms on [target]'s heart with \the [tool].", \ - "You start mending the mechanisms on [target]'s heart with \the [tool]." ) - target.custom_pain("The pain in your chest is living hell!",1) - ..() - - end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/datum/organ/internal/heart/heart = target.internal_organs_by_name["heart"] - if(heart.damage > 0) - user.visible_message("\blue [user] repairs [target]'s heart with \the [tool].", \ - "\blue You repair [target]'s heart with \the [tool]." ) - heart.damage = 0 - - fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) - var/datum/organ/internal/heart/heart = target.internal_organs_by_name["heart"] - user.visible_message("\red [user]'s hand slips, smearing [tool] in the incision in [target]'s heart, gumming it up!!" , \ - "\red Your hand slips, smearing [tool] in the incision in [target]'s heart, gumming it up!") - heart.take_damage(5, 0) - target.adjustToxLoss(5) - -////////////////////////////////////////////////////////////////// -// HEART SURGERY // -////////////////////////////////////////////////////////////////// -// To be finished after some tests. -// /datum/surgery_step/ribcage/heart/cut -// allowed_tools = list( -// /obj/item/weapon/scalpel = 100, \ -// /obj/item/weapon/kitchenknife = 75, \ -// /obj/item/weapon/shard = 50, \ -// ) - -// min_duration = 30 -// max_duration = 40 - -// can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) -// return ..() && target.op_stage.ribcage == 2 - diff --git a/code/modules/surgery/slimes.dm b/code/modules/surgery/slimes.dm new file mode 100644 index 00000000000..d962cfd3f4b --- /dev/null +++ b/code/modules/surgery/slimes.dm @@ -0,0 +1,93 @@ +////////////////////////////////////////////////////////////////// +// SLIME CORE EXTRACTION // +////////////////////////////////////////////////////////////////// + +/datum/surgery_step/slime + is_valid_target(mob/living/carbon/slime/target) + return istype(target, /mob/living/carbon/slime/) + + can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return target.stat == 2 + +/datum/surgery_step/slime/cut_flesh + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/kitchenknife = 75, \ + /obj/item/weapon/shard = 50, \ + ) + + min_duration = 30 + max_duration = 50 + + can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return ..() && target.core_removal_stage == 0 + + begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \ + "You start cutting through [target]'s flesh with \the [tool].") + + end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] cuts through [target]'s flesh with \the [tool].", \ + "\blue You cut through [target]'s flesh with \the [tool], revealing its silky innards.") + target.core_removal_stage = 1 + + fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \ + "\red Your hand slips, tearing [target]'s flesh with \the [tool]!") + +/datum/surgery_step/slime/cut_innards + allowed_tools = list( + /obj/item/weapon/scalpel = 100, \ + /obj/item/weapon/kitchenknife = 75, \ + /obj/item/weapon/shard = 50, \ + ) + + min_duration = 30 + max_duration = 50 + + can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return ..() && target.core_removal_stage == 1 + + begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \ + "You start cutting [target]'s silky innards apart with \the [tool].") + + end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("\blue [user] cuts [target]'s innards apart with \the [tool], exposing the cores.", \ + "\blue You cut [target]'s innards apart with \the [tool], exposing the cores.") + target.core_removal_stage = 2 + + fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, tearing [target]'s innards with \the [tool]!", \ + "\red Your hand slips, tearing [target]'s innards with \the [tool]!") + +/datum/surgery_step/slime/saw_core + allowed_tools = list( + /obj/item/weapon/circular_saw = 100, \ + /obj/item/weapon/hatchet = 75 + ) + + min_duration = 50 + max_duration = 70 + + can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + return ..() && (istype(target) && target.core_removal_stage == 2 && target.cores > 0) //This is being passed a human as target, unsure why. + + begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("[user] starts cutting out one of [target]'s cores with \the [tool].", \ + "You start cutting out one of [target]'s cores with \the [tool].") + + end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + target.cores-- + user.visible_message("\blue [user] cuts out one of [target]'s cores with \the [tool].",, \ + "\blue You cut out one of [target]'s cores with \the [tool]. [target.cores] cores left.") + + if(target.cores >= 0) + new target.coretype(target.loc) + if(target.cores <= 0) + target.icon_state = "[target.colour] baby slime dead-nocore" + + + fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + user.visible_message("\red [user]'s hand slips, causing \him to miss the core!", \ + "\red Your hand slips, causing you to miss the core!") \ No newline at end of file diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index b0116585ab6..9ce44d12607 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -86,12 +86,15 @@ proc/do_surgery(mob/living/M, mob/living/user, obj/item/tool) //check if tool is right or close enough and if this step is possible if( S.tool_quality(tool) && S.can_use(user, M, user.zone_sel.selecting, tool) && S.is_valid_target(M)) S.begin_step(user, M, user.zone_sel.selecting, tool) //start on it - //We had proper tools! (or RNG smiled.) and User did not move or change hands. + //We had proper tools! (or RNG smiled.) and user did not move or change hands. if( prob(S.tool_quality(tool)) && do_mob(user, M, rand(S.min_duration, S.max_duration))) S.end_step(user, M, user.zone_sel.selecting, tool) //finish successfully else if (tool in user.contents && user.Adjacent(M)) //or S.fail_step(user, M, user.zone_sel.selecting, tool) //malpractice~ return 1 //don't want to do weapony things after surgery + if (user.a_intent == "help") + user << "\red You can't see any useful way to use [tool] on [M]." + return 1 return 0 proc/sort_surgeries() @@ -114,5 +117,5 @@ proc/sort_surgeries() var/eyes = 0 var/face = 0 var/appendix = 0 - var/ribcage = 0 var/head_reattach = 0 + var/current_organ diff --git a/code/modules/virus2/effect.dm b/code/modules/virus2/effect.dm index 41fda7a1505..3ebeefeba8e 100644 --- a/code/modules/virus2/effect.dm +++ b/code/modules/virus2/effect.dm @@ -203,7 +203,7 @@ if(istype(mob, /mob/living/carbon/human)) var/mob/living/carbon/human/H = mob var/datum/organ/internal/brain/B = H.internal_organs_by_name["brain"] - if (B.damage < B.min_broken_damage) + if (B && B.damage < B.min_broken_damage) B.take_damage(5) else mob.setBrainLoss(50) diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index a5c7e0c7cdded57a409504f7390a1cb3adc6af7a..58a7aaf25c046d161364add6d4279166bd4ea571 100644 GIT binary patch literal 14638 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 Date: Sun, 28 Sep 2014 16:22:13 +0930 Subject: [PATCH 02/16] Updated changelog. --- html/changelog.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/html/changelog.html b/html/changelog.html index cc5a9f5fd0b..736ffca8cfd 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,6 +56,18 @@ should be listed in the changelog upon commit though. Thanks. --> +
+

28 September 2014

+

Zuhayr updated:

+
    +
  • Organs can now be removed and transplanted.
  • +
  • Brain surgery is now the same as chest surgery regarding the steps leading up to it.
  • +
  • Appendix and kidney now share the groin and removing the first will prevent appendicitis.
  • +
  • Lots of backend surgery/organ stuff, see the PR if you need to know.
  • +
+
+ +

20 September 2014

HarpyEagle updated:

From 786e67e94b3dec999d5251a00b5e70b018814730 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sun, 28 Sep 2014 17:42:12 +0930 Subject: [PATCH 03/16] Added more freezers to storage, added surgical tools to Robotics. --- maps/tgstation2.dmm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/maps/tgstation2.dmm b/maps/tgstation2.dmm index 561a24de2ae..25124f8f52c 100644 --- a/maps/tgstation2.dmm +++ b/maps/tgstation2.dmm @@ -2882,6 +2882,7 @@ "bdv" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/turf/simulated/floor,/area/hallway/primary/starboard) "bdw" = (/obj/machinery/optable,/obj/item/organ/brain,/obj/structure/window/basic{dir = 1},/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station) "bdx" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/plating,/area/maintenance/evahallway) +"bdy" = (/obj/structure/table,/obj/item/weapon/circular_saw,/obj/item/weapon/scalpel{pixel_y = 12},/obj/item/weapon/hemostat,/obj/item/weapon/retractor,/turf/simulated/floor{dir = 2; icon_state = "whitecorner"},/area/assembly/robotics) "bdz" = (/obj/machinery/door/firedoor/border_only{dir = 4; name = "Firelock East"},/turf/simulated/floor,/area/hallway/primary/starboard) "bdA" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor,/area/hallway/primary/starboard) "bdB" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/visible,/turf/simulated/floor/plating,/area/maintenance/auxsolarport) @@ -3742,7 +3743,7 @@ "btY" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating/airless,/area/rnd/test_area) "btZ" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating/airless,/area/rnd/test_area) "bua" = (/obj/machinery/meter,/obj/machinery/light{dir = 1},/obj/structure/closet/firecloset,/turf/simulated/floor/plating,/area/maintenance/substation/medical_science) -"bub" = (/obj/structure/table,/obj/item/weapon/circular_saw,/obj/item/weapon/scalpel{pixel_y = 12},/turf/simulated/floor{dir = 2; icon_state = "whitecorner"},/area/assembly/robotics) +"bub" = (/obj/machinery/light/small{dir = 4},/obj/structure/closet/crate/freezer,/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/surgery2) "buc" = (/obj/structure/table,/obj/item/device/flash/synthetic,/obj/item/device/flash/synthetic,/obj/item/device/flash/synthetic,/obj/item/device/flash/synthetic,/obj/item/device/flash/synthetic,/obj/item/device/flash/synthetic,/obj/structure/window/reinforced/tinted{dir = 4; icon_state = "twindow"},/obj/item/device/mmi/posibrain,/obj/item/device/robotanalyzer,/turf/simulated/floor{dir = 8; icon_state = "whitecorner"},/area/assembly/robotics) "bud" = (/turf/simulated/wall/r_wall,/area/rnd/xenobiology) "bue" = (/obj/structure/table,/obj/item/weapon/crowbar,/obj/item/device/radio/headset/headset_sci{pixel_x = -3},/obj/item/device/multitool{pixel_x = 3},/obj/item/device/multitool{pixel_x = 3},/obj/item/clothing/glasses/welding,/obj/item/clothing/glasses/welding,/turf/simulated/floor{icon_state = "white"},/area/assembly/robotics) @@ -6358,6 +6359,7 @@ "cso" = (/obj/structure/cable/green{d2 = 8; icon_state = "0-8"},/obj/machinery/power/smes/buildable{charge = 0},/turf/simulated/floor/plating,/area/maintenance/substation/medical_science) "csp" = (/obj/machinery/atmospherics/pipe/simple/visible/supply,/obj/machinery/atmospherics/pipe/simple/visible/scrubbers,/turf/simulated/floor/plating,/area/maintenance/virology) "csq" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1},/turf/simulated/floor{icon_state = "white"},/area/rnd/xenobiology) +"csr" = (/obj/machinery/light/small{dir = 8},/obj/structure/closet/crate/freezer,/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/surgery) "css" = (/obj/machinery/door/airlock/research{name = "Xenoflora Storage"; req_access_txt = "47"},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor{icon_state = "white"},/area/rnd/xenobiology) "cst" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor{dir = 4; icon_state = "whitegreen"},/area/rnd/xenobiology/xenoflora_storage) "csu" = (/obj/machinery/door/window/eastright{name = "Engineering Reception Desk"; req_one_access_txt = "10;24"},/obj/machinery/light,/turf/simulated/floor,/area/hallway/primary/aft) @@ -10557,14 +10559,12 @@ "dXx" = (/turf/unsimulated/wall{icon_state = "phoron9"},/area/alien) "dXy" = (/obj/machinery/washing_machine,/turf/simulated/floor{icon_state = "white"},/area/medical/virology) "dXB" = (/turf/simulated/wall,/area/medical/surgery2) -"dXC" = (/obj/machinery/light/small{dir = 4},/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/surgery2) "dXD" = (/turf/unsimulated/wall{icon_state = "phoron13"},/area/alien) "dXE" = (/turf/unsimulated/wall{icon_state = "phoron5"},/area/alien) "dXF" = (/turf/simulated/wall/r_wall,/area/medical/virologyaccess) "dXG" = (/obj/machinery/telecomms/allinone{intercept = 1; on = 0},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/syndicate_mothership) "dXH" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"; tag = "icon-intact-f (SOUTHWEST)"},/turf/simulated/floor{icon_state = "cafeteria"; dir = 5},/area/djstation) "dXI" = (/obj/structure/window/shuttle,/obj/structure/grille,/turf/simulated/shuttle/plating,/area/shuttle/escape/centcom) -"dXJ" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor{icon_state = "freezerfloor"},/area/medical/surgery) "dXK" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/o2{layer = 2.8; pixel_x = 4; pixel_y = 6},/obj/item/weapon/storage/firstaid/toxin,/obj/item/weapon/storage/firstaid/fire{layer = 2.9; pixel_x = 2; pixel_y = 3},/turf/unsimulated/floor{dir = 0; icon_state = "whitegreen"},/area/centcom/holding) "dXO" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 10; icon_state = "intact"; tag = "icon-intact-f (SOUTHWEST)"},/turf/simulated/floor/plating,/area/djstation) "dXS" = (/obj/machinery/door/airlock/external{frequency = 1380; icon_state = "door_locked"; id_tag = "escape_shuttle_hatch"; locked = 1; name = "Shuttle Hatch"; req_access_txt = "13"},/obj/machinery/mech_sensor{dir = 8; frequency = 1380; id_tag = "shuttle_dock_south_mech"; pixel_y = 19},/turf/simulated/shuttle/floor,/area/shuttle/escape/centcom) @@ -11138,7 +11138,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaabmQcLFcIHcInaxSaxSaxSbosaxSaxSatHbotboubovbkZbePaaaaaaaaaaaeaaebowbowbowbowbowbowbowaaaaaaboxbWwbWvbWxboBblpblpblpblpblpblpcecbmecepbqecetbWrbVLboFbarbarbWtbarbaraUnboHbWnbWkaUnbWobXpbXpbXpbXpbXpbWpbXpbWqceacdZbQYcdAbVNcdAbQYcdGcdHaaebnFboVbVUbVObVRbWjbnFbLIaUndzjaMXbWXawGbWmcqnbWVbWWbWTbixdUObWUdUJdUKdULbVWdUGdUFbWSbWRcmTckbbWQbWPbWNckbdUCbWObWMbWLdUzdUzbWIdUwbktbgZbiSdUubkxbkxblXbWHceLceMceHceKceCbmfbmgbpFbhlbWEbWDbWBbNtbUYbUTbUPbWAbNHbUIbNtbhCbkSbpMbhgaaaaaaaaaaaaaaebpNbpObMebpObMebpObpQaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaceTaxRcHMcHMbpRaTPbpSazQasSbpTbpSatHbpUbpVbpWbpXbePaaaaaaaaaaaaaaabowbowbowbowbowbowbowaaaaaabpYbpZblpbmkbmhbmhbmhbmhbmhbmpbmlbmhbmvbmAbmxbmVbmIbURbUSbarbqjbcSbUWbUVbtfbffasqbUaaUnaUnbkKbUcbUbbUfbUebUgbkKbUjbUibUrbUlbUsbUtbUubUDbUFbUGbUHbUJbUKbUMbqFbaDbqGbnFbUNaUndzVaCZbJfawGdUjdUkbVBdUibVybixdUebVwbVsbVtbVpbVpbVMbVHbVGcdtdUpbPZbVEbMEbPZbPZbPZbPZbVDbPZbPZbPZbktbktbktbgZbiSdTXbnYdTYbmWcdjbrcbrdbrebrebrebmbbmXbrfbrgbtObVkbVibNtbUEbUzbVgbVhbNHbUvbNtbmYbmrbhgbhgaaaaaaaaaaaaaaebrobrpbrqbrrbrrbrsbroaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabowbowbowbowbowbowbowbrubrvbrwbrxblpbGablpbnabnabnabncbNIbFYblpblpbnbbqgbqTbRUbIMbrCbrDbrEbcSbcSbLsbxIbffasqbrHbrIbrJbrNbwibLFbwkbPAbLBbkKaaebrQbLAbnzbqybIKbqybnzbLNbrUaaebnFbLKbLLbLJbaDbrZbnFbLIaUnbpcaCZaIOawGbKxbKzbKDbKEbKGbPZbPMbKHbPZbLDbPubWfbLDbPZbKIbRubPZbPZbKMbKLbQFbApbQIbQHbKQbKPbQVbPZbKTbKUbKRbnebiSbLbbKXbKXbnfbLfbkBbsFbrebrebrebmbbmXbsHbtObStbLibLgbtObNEbLkbNJbLjbNHbRTbNtbkGbsPbhgaaaaaaaaaaaaaaaaaebsQbsRbrqbrrbrqcfLbMeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabowbowbowbowbowbowbowcfDbsUcfDbsVbsWbGablpblpblpblpblpbNIbFYbsXbalbalbsYbcSbndbIMbtabtbbnnbnqbnqbnubntbnXbnvbozbtfbtgbxNbzwbKvbAdbKrbKubkKaaebrUbrUbRabQYbKkbnzbtqbrUbrUaaebtvbtvbtvbtvbtvbtvbtvbKfawGbLTbJraHfawGbJtbMmbMmbEDbJxbPZbJvbJwbMEbJFbJybJCbIXbMEbIWbIPbUdbJcbJbbIZbIZbIZbJgbIZbJqbJnbJlbJhbJSbJWbJXbqbbtebtcbvtbuMbvWbQTbkBbubbkCbkCbucbmbbmXbuebuZbUAbJObJLbuZbQmbJPbQnbJQbGwbtObtObwtbhgbhgbMNbMTbMTbMTbMUbMMbrobrrbrqbrrbrrcfjbroaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabowbowbowbowbowbowbowcfDbsUcfDbsVbsWbGablpblpblpblpblpbNIbFYbsXbalbalbsYbcSbndbIMbtabtbbnnbnqbnqbnubntbnXbnvbozbtfbtgbxNbzwbKvbAdbKrbKubkKaaebrUbrUbRabQYbKkbnzbtqbrUbrUaaebtvbtvbtvbtvbtvbtvbtvbKfawGbLTbJraHfawGbJtbMmbMmbEDbJxbPZbJvbJwbMEbJFbJybJCbIXbMEbIWbIPbUdbJcbJbbIZbIZbIZbJgbIZbJqbJnbJlbJhbJSbJWbJXbqbbtebtcbvtbuMbvWbQTbkBbdybkCbkCbucbmbbmXbuebuZbUAbJObJLbuZbQmbJPbQnbJQbGwbtObtObwtbhgbhgbMNbMTbMTbMTbMUbMMbrobrrbrqbrrbrrcfjbroaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtaaaaaaaaaaaaaaaaaaaafaaaaaaaaabowbowbowbowbowbowbowcdKbutcdKbuublpbGablpbrybrybrybrybNIbFYbuvbuwbalbuxbcSbndbIMbuybuzbxtbcSbPKbcSaNsaIOasqbpcbuFbtgbNNbPybPAbPAbPAbIDbkKbOpbOpbOpbrUbuRbIKbuRbrUcdacdacdabtvbIEbuVbuWbuXbuYbIIbIFawGbvcasqaIOawGbHebHgbHrbHIbHSbHTbHZbIabHKbHMbHNbHObIibIebIobIjbOLbOKbIbbOLbIwbIvbIzbIybItbIqbIubPZbGmbGobGcbGdbiSbvybGbbMgbvBbvBbkBbvCbvDbvEbkBbynbzHbvGbSobSnbGJbGBbGAbGybGybGUbGSbGRbGQbGPbBjbGKbIAbIBbICbPqbPqbPrbPwbvXbpObMeccRbMebpObvZaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabowbowbowbowbowbowbowbwabrvbwbbXSblpbGablpblpblpblpblpbNIbFYbuvbwdbalbwebcSbFZbBnbcSbBobPhbcSbcSbBpbtfbffasqbpcbuFbtgbkKbPObPxbRcbPxbFFbkKbwpbFHbFIbOpbrUbFBbrUcdabFEbNsbXubtvbFqbFrbFsbFtbFvbFvbBubBrbvcasqaIOawGbSkbLRbLRbEDbFebPZbEYbFabPZbLXbENbENbEzbPZbExbEvbPZbPZbPZbPZbPZbPZbECbPZbPZbMEbEBbPZbAqbAqbAqbEsbiSbtObuZbuZbuZbuZbuZbuZbuZbuZbuZbGwbCcbMibMpbSnbEhbGlbEibsqbsqbsqbErbRpbRlbRibEnbEjbFhbMLbMIbMJbMIbFkbMMbMNbMTbMUbMRbMMbRJaaaaaeaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtbrtaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabowbowbowbowbowbowbowcdKbutcdKbxubxvbPNblpblpblpbxvblpbNIbFYbuvbPQbalbPPbcSbndbIMbcSbgAbPRbcSbcSbxGbxIbffasqbxHbxIbxJbkKbRjbRgbRmbRkbPWbkKbPVbPUbPTbPSbCwbCgbQcbQdbPYbQabPXbtvbQhbycbycbydbyebyfbQEawGbCDaGXbSHawGbymbPfbPibPjcarbWibApbPebMEcbccbebENbPkbMEbyrbPlbMEceEceJcqebDccckbMlccEbAqbWlbOvcpybRvcbbbAqbCWbCYbCXbVCbDibVlbVlbDqbDnbPobDrbPobEEbFwbEJbPobFzbFJbGlbWubWsbPEbtObtObtObtObtObPGbPFbDubMNbMUbMMbWdbWebWgbWhbVYbWabWbbWcaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -11170,7 +11170,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabDfaaeaaeaaeaaaaaecHGaaecHGaaecsaaaecrZaaecsaaaecrZaaeaaeaaabwHdMydMEcRZdMxcOzdGQcONcOLdBQdMfdModBQdBQdMtdBQdBQcoldktdBQdLPdLLchqcOodLPdBQcaOcaOcaOcGqdLRcaOcjXcjXcjXcjXcjXcjXbiZbEaebRdibcDKcRCebObEaeaFciuebMdXBebKcRpcDJdiaebGdXBcixcJadXFcRicRedMVdXFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaaaaaaaabudcnbcmXcmYdMTdMUcphcQKcfccQNcPVcPBcQHdMKaaaaaaaaeaaeaaaaaaaaaaaaaaaaaaaaaaaecebdMYcebaaeaaaaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaecNscpJcNzcpJcNzcNDcpOcpJcpIcNDcpOcpJcpIcNEccVbQGdGQdKodGQdGQdGQdGQdGQcoAcovdJJcrTdHjdQTdJKdQVdQUchBcNldZEcrYchBcaTchRcjTcaOcsdcsecsbcsccaPdKecaOdRMdRMcsfclLclLcjXbobbEabEaebxcNJbEabEabEaebvciuebwdXBdXBdXBcNIebCdXBdXBcixcwKdXFdYdcNKdYddXFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaaaaeaaebudccCcoLccCdRNcmEculcNHcfccfccNFcfcbudbudaaaaaaaaaaaeaaeaaaaafaaaaaaaaaaaaaaeaaadLjaaaaaeaaeaaeaaeaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaecbYbSZcuqcgrcgqcjdcuschrcgFcjecurcgBcgCcjdbSZcgycgzcqrcqqcqwcqvcsxcrPcsBcjpcyWcuucuwckyclWcjkcjncjmcjhcjfcjjcjicaTckacjqcaOcaPcaPcaPcaPcaPcAEcaOcoVcoVcoVclLclLcjXbobcvMbEadXWcuicitdXVbEadXZciudXYdXBdYaciwcujdYbdXBcvRcixcwKdXFcizciyciBdXFaaaaaaaaaaaaaaaaaabVuckZbYRceXbVuaaeaaaaaaaaaaaabudccCccCccCcwXcwYcxxciCciLciJciQciNcjabudaaaaaaaaaaaaaaeaaeaaaaaaaaaaaaaaaaaeaaactIaaaaaeaaeaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaechKcfpcfmcbDcfmcbDcfmcbDcuecbDcfmcbDcudcuCcuCcuCcuDcuxbSZcfkcuBcvLcvKcircincuvcibcvEckyckxcimciichZchWchUchTchScaTckachOcaOcuScaPcaPchNcaPcuOcaOckgcfgchMcfgcfrcjXbobcuhbEadXJchichjchkchlchpckIchtchwchychzchCdXCdXBchgchdcobbZJbVuchhbVubZJaaaaaaaaeaaaaaaaaabVuchJccOccYbVuaaeaaeaaaaaaaaabudcfccfccfccfcckfculcbWcbWcbWchIcbWchFbudaaaaaaaaaaaaaaaciHciHciHbDfaaeaaeaaeaaectRaaeaaeaaeaaeaaeaaAciHciHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaechKcfpcfmcbDcfmcbDcfmcbDcuecbDcfmcbDcudcuCcuCcuCcuDcuxbSZcfkcuBcvLcvKcircincuvcibcvEckyckxcimciichZchWchUchTchScaTckachOcaOcuScaPcaPchNcaPcuOcaOckgcfgchMcfgcfrcjXbobcuhbEacsrchichjchkchlchpckIchtchwchychzchCbubdXBchgchdcobbZJbVuchhbVubZJaaaaaaaaeaaaaaaaaabVuchJccOccYbVuaaeaaeaaaaaaaaabudcfccfccfccfcckfculcbWcbWcbWchIcbWchFbudaaaaaaaaaaaaaaaciHciHciHbDfaaeaaeaaeaaectRaaeaaeaaeaaeaaeaaAciHciHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaeaaeaaecbYciccibbSZcibciYchYcvSciabSZcibbSZbSZbSZbSZbSZcGvcIfcFzcHWcFHcFzcipcFHcBvcFUcFJcFXcFVcFkcEZcFlchBckYcFncBychBcCJclgcjUciRcGtciSciTclmcaPcGecaOcGjcfgchscfgcnTcjXbobcExbEacDzckEcuLdYnbEadYtcmadYtdXBdYrcuZckGcELdXBcjHcobcobbVuckUckTcERbVubVubVucnJbVubVubVubVuckuckAcdbbVubVubVubZJaaaaaabudcnbcmXcmYcDfcDocxxcbWcbWcbWchIcbWcnkbudaaaaaaaaaaaaaaaciHaaaaaeaaaaaeaaaaaaaaaciPaaaaaeaaeaaaaaaaaaaaaciHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaeaaeaaaaaacbYciccibbSZcidcuIchXchHchGchHchYcuJciachLchHchHcuFcCVcuGcuHchHcCKcCKchHcEBchYcfTckrdeBdcxcEGbQGchBckjchBchBchBcjWcmIcjUchucClchAchxckdcaPcBscaOcBqcfgchscfgcfgcjXcjKcjQbEabEacjJbEabEabEacBncoacBpdXBdXBdXBcjRdXBdXBcjHcobaaabVucjFccgcjIcaZdbdcmzcmwcilcmycmxbVucchccgccfbVucjzcfCbVuaaeaaebudccCccCccCcmDcmEcBbcAOcjycjxcjscbWcmcbudbudbudbudaaaaaaciHaaacrecrecrecrecreaaeciPaaecrecrecrecrecreaaaciHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactvctvctvctvctvctvctvaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaaaaaaaaaaacbYciccidchHchHchHchHchHchGchHchHchHchGchYcxrcxdcxecuxcxcckhckicNmcNmckicEKbSZbSZckrcgAbSZcplcpqcpmcpicpfcpkcpjcpfcorcpLcpPcprcpzcpzcpAcpzcpTcpVcpWcpQcpSclHclHcjXcpGcomcoocoscoscoscotcogcofcofcofcofcofcofcofcofcozchdcobaaacaZcoBcdsdZpcaZdeNdZnbXKbXKdZmbXKdZkcoGcoQdWPdZjcglbXKbVuaaaaaabudccCccCccCcDfcMfcMgcJFcpbcoZcpccbWcbWcpdcoqcopbudaaeaaeciHaaecnKcnFcnFcnFcnFcnDciPcnAcnwcnwcnwcnwcnGaaeciHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa From 223bd86f1887d263b90dc05037d8e21c36936956 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Mon, 29 Sep 2014 00:40:24 +0930 Subject: [PATCH 04/16] Merge branch 'organremoval' of https://github.com/Zuhayr/Baystation12 into dev First pass on major conversion of xenomorphs to a human subspecies. Additional condensing of various redundant mob verbs. Converted larva and diona to their own class, collapsed the rest of xenomorphs into a human species, other stuff. Completely removed attack_alien(). Still have to reimplement some of the lost behavior for human/alien. Reapplies lost attack_alien() functionality other than tackling/caressing. Further alien/humanoid cleanup and xenospawn fix-ups. Also uncommented caste verbs. Removed half-finished abilities system since species.dm handles it. All xenomorphs functionality should be working now, other than the HUD, tackling and the xenomorph balance issues. Added icons for xenomorph castes, moved broadcast languages into datums, removed alien_talk and robot_talk vars. Merged with organ removal code. Reapplied verbs to simple_animals/slimes. Updated species definitions to have appropriate organs. Readded tackle as a human verb. Borer changes regarding brain removal. Working on moving the human HUD to the species datum a bit. Mixed results. Moved Cortical Link to a language, added borer husks. Tidied up the HUD stuff. Still need to make it rebuild properly when species is changed, but this will do for no Compile fix, forgot the DME. Fixed up ventcrawl, added new organ mechanics for dionaea. Fixed up some overlooked sections causing mobs without brains to die immediately. Fixed up plasma generation for queens, bugs with organs, force_organ issues with set_species(). --- baystation12.dme | 60 +- .../components/unary/vent_pump.dm | 8 +- code/_onclick/hud/alien.dm | 241 ------- code/_onclick/hud/hud.dm | 6 +- code/_onclick/hud/human.dm | 640 +++++++---------- code/_onclick/hud/screen_objects.dm | 2 - code/_onclick/other_mobs.dm | 13 +- code/controllers/hooks-defs.dm | 2 +- code/datums/datumvars.dm | 21 +- code/datums/mind.dm | 21 - .../gamemodes/changeling/changeling_powers.dm | 2 +- code/game/gamemodes/cult/runes.dm | 15 - code/game/gamemodes/events/ninja_equipment.dm | 32 +- code/game/gamemodes/events/space_ninja.dm | 10 +- code/game/gamemodes/mutiny/mutiny_hooks.dm | 2 +- code/game/gamemodes/objective.dm | 11 - code/game/jobs/access.dm | 2 +- code/game/machinery/bots/bots.dm | 22 +- code/game/machinery/bots/secbot.dm | 6 - code/game/machinery/camera/camera.dm | 17 +- code/game/machinery/cloning.dm | 7 +- .../machinery/computer/HolodeckControl.dm | 8 +- code/game/machinery/computer/cloning.dm | 7 +- code/game/machinery/doors/windowdoor.dm | 19 +- code/game/machinery/turrets.dm | 80 +-- code/game/mecha/mecha.dm | 41 +- code/game/objects/effects/aliens.dm | 166 ++--- code/game/objects/effects/spiders.dm | 2 +- code/game/objects/items.dm | 9 - .../objects/items/weapons/storage/secure.dm | 3 - .../objects/items/weapons/surgery_tools.dm | 672 ------------------ code/game/objects/structures.dm | 35 + .../structures/crates_lockers/closets.dm | 2 +- code/game/objects/structures/extinguisher.dm | 4 +- code/game/objects/structures/grille.dm | 35 +- code/game/objects/structures/inflatable.dm | 6 +- code/game/objects/structures/mineral_doors.dm | 4 +- code/game/objects/structures/mirror.dm | 22 +- .../stool_bed_chair_nest/alien_nests.dm | 13 +- code/game/objects/structures/tables_racks.dm | 110 +-- code/game/objects/structures/window.dm | 15 +- code/game/turfs/simulated/walls.dm | 2 +- code/game/verbs/suicide.dm | 21 - code/modules/admin/admin.dm | 4 - code/modules/admin/player_panel.dm | 7 +- code/modules/admin/topic.dm | 9 - code/modules/admin/verbs/randomverbs.dm | 63 +- code/modules/client/preferences.dm | 3 + code/modules/hydroponics/seed_datums.dm | 2 +- code/modules/hydroponics/seed_mobs.dm | 2 +- code/modules/mob/abilities.dm | 35 - code/modules/mob/death.dm | 2 + code/modules/mob/language.dm | 116 +++ code/modules/mob/living/carbon/alien/alien.dm | 270 ++----- .../mob/living/carbon/alien/alien_attacks.dm | 183 +++++ .../mob/living/carbon/alien/alien_damage.dm | 56 ++ code/modules/mob/living/carbon/alien/death.dm | 46 +- .../mob/living/carbon/alien/diona/diona.dm | 25 + .../carbon/alien/diona/diona_attacks.dm | 14 + .../living/carbon/alien/diona/diona_powers.dm | 90 +++ .../mob/living/carbon/alien/diona/life.dm | 20 + .../living/carbon/alien/diona/progression.dm | 40 ++ .../carbon/alien/diona/say_understands.dm | 6 + .../living/carbon/alien/{larva => }/emote.dm | 252 +++---- .../carbon/alien/humanoid/alien_powers.dm | 188 ----- .../carbon/alien/humanoid/caste/drone.dm | 48 -- .../carbon/alien/humanoid/caste/hunter.dm | 76 -- .../carbon/alien/humanoid/caste/sentinel.dm | 44 -- .../mob/living/carbon/alien/humanoid/death.dm | 17 - .../mob/living/carbon/alien/humanoid/emote.dm | 135 ---- .../living/carbon/alien/humanoid/humanoid.dm | 423 ----------- .../living/carbon/alien/humanoid/inventory.dm | 54 -- .../mob/living/carbon/alien/humanoid/life.dm | 453 ------------ .../mob/living/carbon/alien/humanoid/login.dm | 7 - .../mob/living/carbon/alien/humanoid/queen.dm | 92 --- .../carbon/alien/humanoid/update_icons.dm | 154 ---- .../mob/living/carbon/alien/larva/death.dm | 15 - .../living/carbon/alien/larva/inventory.dm | 3 - .../mob/living/carbon/alien/larva/larva.dm | 376 +--------- .../mob/living/carbon/alien/larva/life.dm | 369 ---------- .../mob/living/carbon/alien/larva/login.dm | 3 - .../mob/living/carbon/alien/larva/powers.dm | 56 -- .../living/carbon/alien/larva/progression.dm | 17 + .../living/carbon/alien/larva/update_icons.dm | 22 - code/modules/mob/living/carbon/alien/life.dm | 63 ++ code/modules/mob/living/carbon/alien/login.dm | 4 - .../modules/mob/living/carbon/alien/logout.dm | 4 - .../modules/mob/living/carbon/alien/powers.dm | 5 - .../mob/living/carbon/alien/progression.dm | 50 ++ code/modules/mob/living/carbon/alien/say.dm | 102 +-- .../mob/living/carbon/alien/special/_main.dm | 71 -- .../living/carbon/alien/special/snakeman.dm | 59 -- .../mob/living/carbon/alien/update_icons.dm | 22 + .../mob/living/carbon/brain/posibrain.dm | 1 - code/modules/mob/living/carbon/brain/say.dm | 6 +- code/modules/mob/living/carbon/carbon.dm | 14 +- .../mob/living/carbon/carbon_powers.dm | 39 + .../mob/living/carbon/human/alien/alien.dm | 92 +++ .../special => human/alien}/alien_embryo.dm | 300 ++++---- .../alien/alien_facehugger.dm} | 480 +++++++------ .../living/carbon/human/alien/alien_powers.dm | 228 ++++++ .../carbon/human/alien/alien_species.dm | 251 +++++++ code/modules/mob/living/carbon/human/death.dm | 11 +- code/modules/mob/living/carbon/human/emote.dm | 2 +- .../mob/living/carbon/human/examine.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 243 ++----- .../living/carbon/human/human_attackalien.dm | 62 -- .../living/carbon/human/human_attackhand.dm | 6 + .../mob/living/carbon/human/human_damage.dm | 13 +- .../mob/living/carbon/human/human_movement.dm | 9 +- .../mob/living/carbon/human/human_powers.dm | 221 ++++++ .../mob/living/carbon/human/human_species.dm | 34 + code/modules/mob/living/carbon/human/life.dm | 10 +- code/modules/mob/living/carbon/human/login.dm | 3 +- .../modules/mob/living/carbon/human/logout.dm | 4 + code/modules/mob/living/carbon/human/say.dm | 27 +- .../mob/living/carbon/{ => human}/species.dm | 261 ++++++- .../mob/living/carbon/human/update_icons.dm | 2 +- .../modules/mob/living/carbon/metroid/life.dm | 4 +- .../mob/living/carbon/metroid/metroid.dm | 97 +-- .../mob/living/carbon/metroid/powers.dm | 11 +- .../modules/mob/living/carbon/monkey/diona.dm | 267 ------- .../modules/mob/living/carbon/monkey/emote.dm | 10 +- code/modules/mob/living/carbon/monkey/life.dm | 48 +- .../mob/living/carbon/monkey/monkey.dm | 83 +-- .../mob/living/carbon/monkey/powers.dm | 5 - code/modules/mob/living/living.dm | 13 +- code/modules/mob/living/living_defines.dm | 8 + code/modules/mob/living/living_powers.dm | 18 + code/modules/mob/living/say.dm | 27 +- code/modules/mob/living/silicon/ai/ai.dm | 36 +- code/modules/mob/living/silicon/pai/pai.dm | 41 +- .../mob/living/silicon/robot/drone/drone.dm | 60 +- .../silicon/robot/drone/drone_abilities.dm | 22 - .../living/silicon/robot/drone/drone_items.dm | 8 +- .../modules/mob/living/silicon/robot/robot.dm | 81 +-- .../mob/living/silicon/robot/robot_powers.dm | 9 + code/modules/mob/living/silicon/say.dm | 106 +-- code/modules/mob/living/silicon/silicon.dm | 7 +- .../modules/mob/living/simple_animal/borer.dm | 580 --------------- .../mob/living/simple_animal/borer/borer.dm | 207 ++++++ .../simple_animal/borer/borer_captive.dm | 35 + .../simple_animal/borer/borer_powers.dm | 348 +++++++++ .../mob/living/simple_animal/borer/say.dm | 42 ++ .../mob/living/simple_animal/constructs.dm | 2 +- .../living/simple_animal/friendly/mouse.dm | 61 +- .../simple_animal/friendly/spiderbot.dm | 60 -- .../mob/living/simple_animal/parrot.dm | 9 +- .../mob/living/simple_animal/simple_animal.dm | 74 +- code/modules/mob/login.dm | 11 - code/modules/mob/mob_defines.dm | 4 - code/modules/mob/mob_grab.dm | 16 +- code/modules/mob/mob_helpers.dm | 28 +- code/modules/mob/say.dm | 2 - code/modules/mob/transform_procs.dm | 9 +- code/modules/organs/organ_alien.dm | 164 +++++ code/modules/organs/organ_internal.dm | 2 +- code/modules/power/apc.dm | 57 +- code/modules/power/lighting.dm | 21 +- code/modules/power/power.dm | 13 +- code/modules/projectiles/projectile/change.dm | 6 +- code/modules/surgery/slimes.dm | 4 +- code/setup.dm | 26 +- code/stylesheet.dm | 1 + icons/effects/species.dmi | Bin 22523 -> 21711 bytes icons/mob/alien.dmi | Bin 87076 -> 88728 bytes icons/mob/human_races/xenos/r_xenos_drone.dmi | Bin 0 -> 1764 bytes .../mob/human_races/xenos/r_xenos_hunter.dmi | Bin 0 -> 1895 bytes icons/mob/human_races/xenos/r_xenos_queen.dmi | Bin 0 -> 1928 bytes .../human_races/xenos/r_xenos_sentinel.dmi | Bin 0 -> 1817 bytes icons/mob/monkey.dmi | Bin 22415 -> 21022 bytes icons/mob/screen1_alien.dmi | Bin 140985 -> 141060 bytes 172 files changed, 4201 insertions(+), 7456 deletions(-) delete mode 100644 code/_onclick/hud/alien.dm delete mode 100644 code/modules/mob/abilities.dm create mode 100644 code/modules/mob/living/carbon/alien/alien_attacks.dm create mode 100644 code/modules/mob/living/carbon/alien/alien_damage.dm create mode 100644 code/modules/mob/living/carbon/alien/diona/diona.dm create mode 100644 code/modules/mob/living/carbon/alien/diona/diona_attacks.dm create mode 100644 code/modules/mob/living/carbon/alien/diona/diona_powers.dm create mode 100644 code/modules/mob/living/carbon/alien/diona/life.dm create mode 100644 code/modules/mob/living/carbon/alien/diona/progression.dm create mode 100644 code/modules/mob/living/carbon/alien/diona/say_understands.dm rename code/modules/mob/living/carbon/alien/{larva => }/emote.dm (86%) delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/death.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/emote.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/humanoid.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/inventory.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/life.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/login.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/queen.dm delete mode 100644 code/modules/mob/living/carbon/alien/humanoid/update_icons.dm delete mode 100644 code/modules/mob/living/carbon/alien/larva/death.dm delete mode 100644 code/modules/mob/living/carbon/alien/larva/inventory.dm delete mode 100644 code/modules/mob/living/carbon/alien/larva/life.dm delete mode 100644 code/modules/mob/living/carbon/alien/larva/login.dm delete mode 100644 code/modules/mob/living/carbon/alien/larva/powers.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/progression.dm delete mode 100644 code/modules/mob/living/carbon/alien/larva/update_icons.dm create mode 100644 code/modules/mob/living/carbon/alien/life.dm delete mode 100644 code/modules/mob/living/carbon/alien/login.dm delete mode 100644 code/modules/mob/living/carbon/alien/logout.dm delete mode 100644 code/modules/mob/living/carbon/alien/powers.dm create mode 100644 code/modules/mob/living/carbon/alien/progression.dm delete mode 100644 code/modules/mob/living/carbon/alien/special/_main.dm delete mode 100644 code/modules/mob/living/carbon/alien/special/snakeman.dm create mode 100644 code/modules/mob/living/carbon/alien/update_icons.dm create mode 100644 code/modules/mob/living/carbon/carbon_powers.dm create mode 100644 code/modules/mob/living/carbon/human/alien/alien.dm rename code/modules/mob/living/carbon/{alien/special => human/alien}/alien_embryo.dm (90%) rename code/modules/mob/living/carbon/{alien/special/facehugger.dm => human/alien/alien_facehugger.dm} (86%) create mode 100644 code/modules/mob/living/carbon/human/alien/alien_powers.dm create mode 100644 code/modules/mob/living/carbon/human/alien/alien_species.dm delete mode 100644 code/modules/mob/living/carbon/human/human_attackalien.dm create mode 100644 code/modules/mob/living/carbon/human/human_powers.dm create mode 100644 code/modules/mob/living/carbon/human/human_species.dm create mode 100644 code/modules/mob/living/carbon/human/logout.dm rename code/modules/mob/living/carbon/{ => human}/species.dm (52%) delete mode 100644 code/modules/mob/living/carbon/monkey/diona.dm delete mode 100644 code/modules/mob/living/carbon/monkey/powers.dm create mode 100644 code/modules/mob/living/living_powers.dm create mode 100644 code/modules/mob/living/silicon/robot/robot_powers.dm delete mode 100644 code/modules/mob/living/simple_animal/borer.dm create mode 100644 code/modules/mob/living/simple_animal/borer/borer.dm create mode 100644 code/modules/mob/living/simple_animal/borer/borer_captive.dm create mode 100644 code/modules/mob/living/simple_animal/borer/borer_powers.dm create mode 100644 code/modules/mob/living/simple_animal/borer/say.dm create mode 100644 code/modules/organs/organ_alien.dm create mode 100644 icons/mob/human_races/xenos/r_xenos_drone.dmi create mode 100644 icons/mob/human_races/xenos/r_xenos_hunter.dmi create mode 100644 icons/mob/human_races/xenos/r_xenos_queen.dmi create mode 100644 icons/mob/human_races/xenos/r_xenos_sentinel.dmi diff --git a/baystation12.dme b/baystation12.dme index 1c200c9afc0..037531f6fd7 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -40,7 +40,6 @@ #include "code\_onclick\other_mobs.dm" #include "code\_onclick\telekinesis.dm" #include "code\_onclick\hud\_defines.dm" -#include "code\_onclick\hud\alien.dm" #include "code\_onclick\hud\alien_larva.dm" #include "code\_onclick\hud\hud.dm" #include "code\_onclick\hud\human.dm" @@ -897,7 +896,6 @@ #include "code\modules\mining\drilling\distribution.dm" #include "code\modules\mining\drilling\drill.dm" #include "code\modules\mining\drilling\scanner.dm" -#include "code\modules\mob\abilities.dm" #include "code\modules\mob\death.dm" #include "code\modules\mob\emote.dm" #include "code\modules\mob\hear_say.dm" @@ -925,42 +923,33 @@ #include "code\modules\mob\living\living.dm" #include "code\modules\mob\living\living_defense.dm" #include "code\modules\mob\living\living_defines.dm" +#include "code\modules\mob\living\living_powers.dm" #include "code\modules\mob\living\login.dm" #include "code\modules\mob\living\logout.dm" #include "code\modules\mob\living\say.dm" #include "code\modules\mob\living\blob\blob.dm" #include "code\modules\mob\living\carbon\carbon.dm" #include "code\modules\mob\living\carbon\carbon_defines.dm" +#include "code\modules\mob\living\carbon\carbon_powers.dm" #include "code\modules\mob\living\carbon\give.dm" #include "code\modules\mob\living\carbon\shock.dm" -#include "code\modules\mob\living\carbon\species.dm" #include "code\modules\mob\living\carbon\alien\alien.dm" +#include "code\modules\mob\living\carbon\alien\alien_attacks.dm" +#include "code\modules\mob\living\carbon\alien\alien_damage.dm" #include "code\modules\mob\living\carbon\alien\death.dm" -#include "code\modules\mob\living\carbon\alien\login.dm" -#include "code\modules\mob\living\carbon\alien\logout.dm" -#include "code\modules\mob\living\carbon\alien\powers.dm" +#include "code\modules\mob\living\carbon\alien\emote.dm" +#include "code\modules\mob\living\carbon\alien\life.dm" +#include "code\modules\mob\living\carbon\alien\progression.dm" #include "code\modules\mob\living\carbon\alien\say.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\alien_powers.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\death.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\emote.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\humanoid.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\inventory.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\life.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\login.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\queen.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\update_icons.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\caste\drone.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\caste\hunter.dm" -#include "code\modules\mob\living\carbon\alien\humanoid\caste\sentinel.dm" -#include "code\modules\mob\living\carbon\alien\larva\death.dm" -#include "code\modules\mob\living\carbon\alien\larva\emote.dm" -#include "code\modules\mob\living\carbon\alien\larva\inventory.dm" +#include "code\modules\mob\living\carbon\alien\update_icons.dm" +#include "code\modules\mob\living\carbon\alien\diona\diona.dm" +#include "code\modules\mob\living\carbon\alien\diona\diona_attacks.dm" +#include "code\modules\mob\living\carbon\alien\diona\diona_powers.dm" +#include "code\modules\mob\living\carbon\alien\diona\life.dm" +#include "code\modules\mob\living\carbon\alien\diona\progression.dm" +#include "code\modules\mob\living\carbon\alien\diona\say_understands.dm" #include "code\modules\mob\living\carbon\alien\larva\larva.dm" -#include "code\modules\mob\living\carbon\alien\larva\life.dm" -#include "code\modules\mob\living\carbon\alien\larva\powers.dm" -#include "code\modules\mob\living\carbon\alien\larva\update_icons.dm" -#include "code\modules\mob\living\carbon\alien\special\alien_embryo.dm" -#include "code\modules\mob\living\carbon\alien\special\facehugger.dm" +#include "code\modules\mob\living\carbon\alien\larva\progression.dm" #include "code\modules\mob\living\carbon\brain\brain.dm" #include "code\modules\mob\living\carbon\brain\brain_item.dm" #include "code\modules\mob\living\carbon\brain\death.dm" @@ -974,19 +963,27 @@ #include "code\modules\mob\living\carbon\human\emote.dm" #include "code\modules\mob\living\carbon\human\examine.dm" #include "code\modules\mob\living\carbon\human\human.dm" -#include "code\modules\mob\living\carbon\human\human_attackalien.dm" #include "code\modules\mob\living\carbon\human\human_attackhand.dm" #include "code\modules\mob\living\carbon\human\human_attackpaw.dm" #include "code\modules\mob\living\carbon\human\human_damage.dm" #include "code\modules\mob\living\carbon\human\human_defense.dm" #include "code\modules\mob\living\carbon\human\human_defines.dm" #include "code\modules\mob\living\carbon\human\human_movement.dm" +#include "code\modules\mob\living\carbon\human\human_powers.dm" +#include "code\modules\mob\living\carbon\human\human_species.dm" #include "code\modules\mob\living\carbon\human\inventory.dm" #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\logout.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\update_icons.dm" #include "code\modules\mob\living\carbon\human\whisper.dm" +#include "code\modules\mob\living\carbon\human\alien\alien.dm" +#include "code\modules\mob\living\carbon\human\alien\alien_embryo.dm" +#include "code\modules\mob\living\carbon\human\alien\alien_facehugger.dm" +#include "code\modules\mob\living\carbon\human\alien\alien_powers.dm" +#include "code\modules\mob\living\carbon\human\alien\alien_species.dm" #include "code\modules\mob\living\carbon\metroid\death.dm" #include "code\modules\mob\living\carbon\metroid\emote.dm" #include "code\modules\mob\living\carbon\metroid\examine.dm" @@ -999,14 +996,12 @@ #include "code\modules\mob\living\carbon\metroid\subtypes.dm" #include "code\modules\mob\living\carbon\metroid\update_icons.dm" #include "code\modules\mob\living\carbon\monkey\death.dm" -#include "code\modules\mob\living\carbon\monkey\diona.dm" #include "code\modules\mob\living\carbon\monkey\emote.dm" #include "code\modules\mob\living\carbon\monkey\examine.dm" #include "code\modules\mob\living\carbon\monkey\inventory.dm" #include "code\modules\mob\living\carbon\monkey\life.dm" #include "code\modules\mob\living\carbon\monkey\login.dm" #include "code\modules\mob\living\carbon\monkey\monkey.dm" -#include "code\modules\mob\living\carbon\monkey\powers.dm" #include "code\modules\mob\living\carbon\monkey\update_icons.dm" #include "code\modules\mob\living\silicon\alarm.dm" #include "code\modules\mob\living\silicon\death.dm" @@ -1052,6 +1047,7 @@ #include "code\modules\mob\living\silicon\robot\robot_items.dm" #include "code\modules\mob\living\silicon\robot\robot_modules.dm" #include "code\modules\mob\living\silicon\robot\robot_movement.dm" +#include "code\modules\mob\living\silicon\robot\robot_powers.dm" #include "code\modules\mob\living\silicon\robot\wires.dm" #include "code\modules\mob\living\silicon\robot\drone\drone.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm" @@ -1060,13 +1056,16 @@ #include "code\modules\mob\living\silicon\robot\drone\drone_items.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm" #include "code\modules\mob\living\simple_animal\bees.dm" -#include "code\modules\mob\living\simple_animal\borer.dm" #include "code\modules\mob\living\simple_animal\constructs.dm" #include "code\modules\mob\living\simple_animal\corpse.dm" #include "code\modules\mob\living\simple_animal\parrot.dm" #include "code\modules\mob\living\simple_animal\shade.dm" #include "code\modules\mob\living\simple_animal\simple_animal.dm" #include "code\modules\mob\living\simple_animal\worm.dm" +#include "code\modules\mob\living\simple_animal\borer\borer.dm" +#include "code\modules\mob\living\simple_animal\borer\borer_captive.dm" +#include "code\modules\mob\living\simple_animal\borer\borer_powers.dm" +#include "code\modules\mob\living\simple_animal\borer\say.dm" #include "code\modules\mob\living\simple_animal\friendly\cat.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" #include "code\modules\mob\living\simple_animal\friendly\crab.dm" @@ -1109,6 +1108,7 @@ #include "code\modules\nano\nanoui.dm" #include "code\modules\organs\blood.dm" #include "code\modules\organs\organ.dm" +#include "code\modules\organs\organ_alien.dm" #include "code\modules\organs\organ_external.dm" #include "code\modules\organs\organ_internal.dm" #include "code\modules\organs\organ_objects.dm" diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index 80b168aabd1..925994546ee 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -425,14 +425,16 @@ return /* - Alt-click to ventcrawl - Monkeys, aliens, slimes and mice. + Alt-click to vent crawl - Monkeys, aliens, slimes and mice. This is a little buggy but somehow that just seems to plague ventcrawl. I am sorry, I don't know why. */ -/obj/machinery/atmospherics/unary/vent_pump/AltClick(var/mob/living/ML) +// Commenting this out for now, it's not critical, stated to be buggy, and seems like +// a really clumsy way of doing this. ~Z +/*/obj/machinery/atmospherics/unary/vent_pump/AltClick(var/mob/living/ML) if(istype(ML)) var/list/ventcrawl_verbs = list(/mob/living/carbon/monkey/verb/ventcrawl, /mob/living/carbon/alien/verb/ventcrawl, /mob/living/carbon/slime/verb/ventcrawl,/mob/living/simple_animal/mouse/verb/ventcrawl) if(length(ML.verbs & ventcrawl_verbs)) // alien queens have this removed, an istype would be complicated ML.handle_ventcrawl(src) return - ..() + ..()*/ \ No newline at end of file diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm deleted file mode 100644 index 01b10585273..00000000000 --- a/code/_onclick/hud/alien.dm +++ /dev/null @@ -1,241 +0,0 @@ -/datum/hud/proc/alien_hud() - - src.adding = list( ) - src.other = list( ) - - var/obj/screen/using - var/obj/screen/inventory/inv_box - - using = new /obj/screen() - using.name = "act_intent" - using.dir = SOUTHWEST - using.icon = 'icons/mob/screen1_alien.dmi' - using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent) - using.screen_loc = ui_acti - using.layer = 20 - src.adding += using - action_intent = using - -//intent small hud objects - var/icon/ico - - ico = new('icons/mob/screen1_alien.dmi', "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),1,ico.Height()/2,ico.Width()/2,ico.Height()) - using = new /obj/screen( src ) - using.name = "help" - using.icon = ico - using.screen_loc = ui_acti - using.layer = 21 - src.adding += using - help_intent = using - - ico = new('icons/mob/screen1_alien.dmi', "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,ico.Height()/2,ico.Width(),ico.Height()) - using = new /obj/screen( src ) - using.name = "disarm" - using.icon = ico - using.screen_loc = ui_acti - using.layer = 21 - src.adding += using - disarm_intent = using - - ico = new('icons/mob/screen1_alien.dmi', "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,1,ico.Width(),ico.Height()/2) - using = new /obj/screen( src ) - using.name = "grab" - using.icon = ico - using.screen_loc = ui_acti - using.layer = 21 - src.adding += using - grab_intent = using - - ico = new('icons/mob/screen1_alien.dmi', "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),1,1,ico.Width()/2,ico.Height()/2) - using = new /obj/screen( src ) - using.name = "harm" - using.icon = ico - using.screen_loc = ui_acti - using.layer = 21 - src.adding += using - hurt_intent = using - -//end intent small hud objects - - using = new /obj/screen() - using.name = "mov_intent" - using.dir = SOUTHWEST - using.icon = 'icons/mob/screen1_alien.dmi' - using.icon_state = (mymob.m_intent == "run" ? "running" : "walking") - using.screen_loc = ui_movi - using.layer = 20 - src.adding += using - move_intent = using - - using = new /obj/screen() - using.name = "drop" - using.icon = 'icons/mob/screen1_alien.dmi' - using.icon_state = "act_drop" - using.screen_loc = ui_drop_throw - using.layer = 19 - src.adding += using - -//equippable shit - //suit - inv_box = new /obj/screen/inventory() - inv_box.name = "o_clothing" - inv_box.dir = SOUTH - inv_box.icon = 'icons/mob/screen1_alien.dmi' - inv_box.icon_state = "equip" - inv_box.screen_loc = ui_alien_oclothing - inv_box.slot_id = slot_wear_suit - inv_box.layer = 19 - src.adding += inv_box - - inv_box = new /obj/screen/inventory() - inv_box.name = "r_hand" - inv_box.dir = WEST - inv_box.icon = 'icons/mob/screen1_alien.dmi' - inv_box.icon_state = "hand_inactive" - if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use - using.icon_state = "hand_active" - inv_box.screen_loc = ui_rhand - inv_box.layer = 19 - src.r_hand_hud_object = inv_box - inv_box.slot_id = slot_r_hand - src.adding += inv_box - - inv_box = new /obj/screen/inventory() - inv_box.name = "l_hand" - inv_box.dir = EAST - inv_box.icon = 'icons/mob/screen1_alien.dmi' - inv_box.icon_state = "hand_inactive" - if(mymob && mymob.hand) //This being 1 means the left hand is in use - inv_box.icon_state = "hand_active" - inv_box.screen_loc = ui_lhand - inv_box.layer = 19 - inv_box.slot_id = slot_l_hand - src.l_hand_hud_object = inv_box - src.adding += inv_box - - using = new /obj/screen/inventory() - using.name = "hand" - using.dir = SOUTH - using.icon = 'icons/mob/screen1_alien.dmi' - using.icon_state = "hand1" - using.screen_loc = ui_swaphand1 - using.layer = 19 - src.adding += using - - using = new /obj/screen/inventory() - using.name = "hand" - using.dir = SOUTH - using.icon = 'icons/mob/screen1_alien.dmi' - using.icon_state = "hand2" - using.screen_loc = ui_swaphand2 - using.layer = 19 - src.adding += using - - //pocket 1 - inv_box = new /obj/screen/inventory() - inv_box.name = "storage1" - inv_box.icon = 'icons/mob/screen1_alien.dmi' - inv_box.icon_state = "pocket" - inv_box.screen_loc = ui_storage1 - inv_box.slot_id = slot_l_store - inv_box.layer = 19 - src.adding += inv_box - - //pocket 2 - inv_box = new /obj/screen/inventory() - inv_box.name = "storage2" - inv_box.icon = 'icons/mob/screen1_alien.dmi' - inv_box.icon_state = "pocket" - inv_box.screen_loc = ui_storage2 - inv_box.slot_id = slot_r_store - inv_box.layer = 19 - src.adding += inv_box - - //head - inv_box = new /obj/screen/inventory() - inv_box.name = "head" - inv_box.icon = 'icons/mob/screen1_alien.dmi' - inv_box.icon_state = "hair" - inv_box.screen_loc = ui_alien_head - inv_box.slot_id = slot_head - inv_box.layer = 19 - src.adding += inv_box -//end of equippable shit - -/* - using = new /obj/screen() - using.name = "resist" - using.icon = 'icons/mob/screen1_alien.dmi' - using.icon_state = "act_resist" - using.screen_loc = ui_resist - using.layer = 19 - src.adding += using -*/ - - mymob.throw_icon = new /obj/screen() - mymob.throw_icon.icon = 'icons/mob/screen1_alien.dmi' - mymob.throw_icon.icon_state = "act_throw_off" - mymob.throw_icon.name = "throw" - mymob.throw_icon.screen_loc = ui_drop_throw - - mymob.oxygen = new /obj/screen() - mymob.oxygen.icon = 'icons/mob/screen1_alien.dmi' - mymob.oxygen.icon_state = "oxy0" - mymob.oxygen.name = "oxygen" - mymob.oxygen.screen_loc = ui_alien_oxygen - - mymob.toxin = new /obj/screen() - mymob.toxin.icon = 'icons/mob/screen1_alien.dmi' - mymob.toxin.icon_state = "tox0" - mymob.toxin.name = "toxin" - mymob.toxin.screen_loc = ui_alien_toxin - - mymob.fire = new /obj/screen() - mymob.fire.icon = 'icons/mob/screen1_alien.dmi' - mymob.fire.icon_state = "fire0" - mymob.fire.name = "fire" - mymob.fire.screen_loc = ui_alien_fire - - mymob.healths = new /obj/screen() - mymob.healths.icon = 'icons/mob/screen1_alien.dmi' - mymob.healths.icon_state = "health0" - mymob.healths.name = "health" - mymob.healths.screen_loc = ui_alien_health - - mymob.pullin = new /obj/screen() - mymob.pullin.icon = 'icons/mob/screen1_alien.dmi' - mymob.pullin.icon_state = "pull0" - mymob.pullin.name = "pull" - mymob.pullin.screen_loc = ui_pull_resist - - mymob.blind = new /obj/screen() - mymob.blind.icon = 'icons/mob/screen1_full.dmi' - mymob.blind.icon_state = "blackimageoverlay" - mymob.blind.name = " " - mymob.blind.screen_loc = "1,1" - mymob.blind.layer = 0 - - mymob.flash = new /obj/screen() - mymob.flash.icon = 'icons/mob/screen1_alien.dmi' - mymob.flash.icon_state = "blank" - mymob.flash.name = "flash" - mymob.flash.screen_loc = "1,1 to 15,15" - mymob.flash.layer = 17 - - mymob.zone_sel = new /obj/screen/zone_sel() - mymob.zone_sel.icon = 'icons/mob/screen1_alien.dmi' - mymob.zone_sel.overlays.Cut() - mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") - - mymob.client.screen = null - - mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.toxin, mymob.fire, mymob.healths, mymob.pullin, mymob.blind, mymob.flash) //, mymob.hands, mymob.rest, mymob.sleep, mymob.mach ) - mymob.client.screen += src.adding + src.other \ No newline at end of file diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 221eef2a1d8..9ea0cb2bffc 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -194,15 +194,13 @@ datum/hud/New(mob/owner) var/ui_alpha = mymob.client.prefs.UI_style_alpha if(ishuman(mymob)) - human_hud(ui_style, ui_color, ui_alpha) // Pass the player the UI style chosen in preferences + human_hud(ui_style, ui_color, ui_alpha, mymob) // Pass the player the UI style chosen in preferences else if(ismonkey(mymob)) monkey_hud(ui_style) else if(isbrain(mymob)) brain_hud(ui_style) - else if(islarva(mymob)) - larva_hud() else if(isalien(mymob)) - alien_hud() + larva_hud() else if(isAI(mymob)) ai_hud() else if(isrobot(mymob)) diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 82a9d79c47f..7425716cd9f 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -1,416 +1,305 @@ -/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_White.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255) +/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_White.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255, var/mob/living/carbon/human/target) + + var/datum/hud_data/hud_data + if(!istype(target)) + hud_data = new() + else + hud_data = target.species.hud + + if(hud_data.icon) + ui_style = hud_data.icon src.adding = list() src.other = list() src.hotkeybuttons = list() //These can be disabled for hotkey usersx + var/list/hud_elements = list() var/obj/screen/using var/obj/screen/inventory/inv_box - using = new /obj/screen() - using.name = "act_intent" - using.dir = SOUTHWEST - using.icon = ui_style - using.icon_state = "intent_"+mymob.a_intent - using.screen_loc = ui_acti - using.color = ui_color - using.alpha = ui_alpha - using.layer = 20 - src.adding += using - action_intent = using + // Draw the various inventory equipment slots. + var/has_hidden_gear + for(var/gear_slot in hud_data.gear) -//intent small hud objects - var/icon/ico + inv_box = new /obj/screen/inventory() + inv_box.icon = ui_style + inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha - ico = new(ui_style, "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),1,ico.Height()/2,ico.Width()/2,ico.Height()) - using = new /obj/screen( src ) - using.name = "help" - using.icon = ico - using.screen_loc = ui_acti - using.alpha = ui_alpha - using.layer = 21 - src.adding += using - help_intent = using + var/list/slot_data = hud_data.gear[gear_slot] + inv_box.name = gear_slot + inv_box.screen_loc = slot_data["loc"] + inv_box.slot_id = slot_data["slot"] + inv_box.icon_state = slot_data["state"] - ico = new(ui_style, "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,ico.Height()/2,ico.Width(),ico.Height()) - using = new /obj/screen( src ) - using.name = "disarm" - using.icon = ico - using.screen_loc = ui_acti - using.alpha = ui_alpha - using.layer = 21 - src.adding += using - disarm_intent = using + if(slot_data["dir"]) + inv_box.dir = slot_data["dir"] - ico = new(ui_style, "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,1,ico.Width(),ico.Height()/2) - using = new /obj/screen( src ) - using.name = "grab" - using.icon = ico - using.screen_loc = ui_acti - using.alpha = ui_alpha - using.layer = 21 - src.adding += using - grab_intent = using + if(slot_data["toggle"]) + src.other += inv_box + has_hidden_gear = 1 + else + src.adding += inv_box - ico = new(ui_style, "black") - ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) - ico.DrawBox(rgb(255,255,255,1),1,1,ico.Width()/2,ico.Height()/2) - using = new /obj/screen( src ) - using.name = "harm" - using.icon = ico - using.screen_loc = ui_acti - using.alpha = ui_alpha - using.layer = 21 - src.adding += using - hurt_intent = using + if(has_hidden_gear) + using = new /obj/screen() + using.name = "toggle" + using.icon = ui_style + using.icon_state = "other" + using.screen_loc = ui_inventory + using.layer = 20 + using.color = ui_color + using.alpha = ui_alpha + src.adding += using -//end intent small hud objects + // Draw the attack intent dialogue. + if(hud_data.has_a_intent) - using = new /obj/screen() - using.name = "mov_intent" - using.dir = SOUTHWEST - using.icon = ui_style - using.icon_state = (mymob.m_intent == "run" ? "running" : "walking") - using.screen_loc = ui_movi - using.layer = 20 - using.color = ui_color - using.alpha = ui_alpha - src.adding += using - move_intent = using + using = new /obj/screen() + using.name = "act_intent" + using.dir = SOUTHWEST + using.icon = ui_style + using.icon_state = "intent_"+mymob.a_intent + using.screen_loc = ui_acti + using.color = ui_color + using.alpha = ui_alpha + using.layer = 20 + src.adding += using + action_intent = using - using = new /obj/screen() - using.name = "drop" - using.icon = ui_style - using.icon_state = "act_drop" - using.screen_loc = ui_drop_throw - using.layer = 19 - using.color = ui_color - using.alpha = ui_alpha - src.hotkeybuttons += using + hud_elements |= using - inv_box = new /obj/screen/inventory() - inv_box.name = "i_clothing" - inv_box.dir = SOUTH - inv_box.icon = ui_style - inv_box.slot_id = slot_w_uniform - inv_box.icon_state = "center" - inv_box.screen_loc = ui_iclothing - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + //intent small hud objects + var/icon/ico - inv_box = new /obj/screen/inventory() - inv_box.name = "o_clothing" - inv_box.dir = SOUTH - inv_box.icon = ui_style - inv_box.slot_id = slot_wear_suit - inv_box.icon_state = "equip" - inv_box.screen_loc = ui_oclothing - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),1,ico.Height()/2,ico.Width()/2,ico.Height()) + using = new /obj/screen( src ) + using.name = "help" + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = 21 + src.adding += using + help_intent = using - inv_box = new /obj/screen/inventory() - inv_box.name = "r_hand" - inv_box.dir = WEST - inv_box.icon = ui_style - inv_box.icon_state = "hand_inactive" - if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use - inv_box.icon_state = "hand_active" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,ico.Height()/2,ico.Width(),ico.Height()) + using = new /obj/screen( src ) + using.name = "disarm" + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = 21 + src.adding += using + disarm_intent = using - src.r_hand_hud_object = inv_box - src.adding += inv_box + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,1,ico.Width(),ico.Height()/2) + using = new /obj/screen( src ) + using.name = "grab" + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = 21 + src.adding += using + grab_intent = using - inv_box = new /obj/screen/inventory() - inv_box.name = "l_hand" - inv_box.dir = EAST - inv_box.icon = ui_style - inv_box.icon_state = "hand_inactive" - if(mymob && mymob.hand) //This being 1 means the left hand is in use - inv_box.icon_state = "hand_active" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.l_hand_hud_object = inv_box - src.adding += inv_box + ico = new(ui_style, "black") + ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1) + ico.DrawBox(rgb(255,255,255,1),1,1,ico.Width()/2,ico.Height()/2) + using = new /obj/screen( src ) + using.name = "harm" + using.icon = ico + using.screen_loc = ui_acti + using.alpha = ui_alpha + using.layer = 21 + src.adding += using + hurt_intent = using + //end intent small hud objects - using = new /obj/screen/inventory() - using.name = "hand" - using.dir = SOUTH - using.icon = ui_style - using.icon_state = "hand1" - using.screen_loc = ui_swaphand1 - using.layer = 19 - using.color = ui_color - using.alpha = ui_alpha - src.adding += using + if(hud_data.has_m_intent) + using = new /obj/screen() + using.name = "mov_intent" + using.dir = SOUTHWEST + using.icon = ui_style + using.icon_state = (mymob.m_intent == "run" ? "running" : "walking") + using.screen_loc = ui_movi + using.layer = 20 + using.color = ui_color + using.alpha = ui_alpha + src.adding += using + move_intent = using - using = new /obj/screen/inventory() - using.name = "hand" - using.dir = SOUTH - using.icon = ui_style - using.icon_state = "hand2" - using.screen_loc = ui_swaphand2 - using.layer = 19 - using.color = ui_color - using.alpha = ui_alpha - src.adding += using + if(hud_data.has_drop) + using = new /obj/screen() + using.name = "drop" + using.icon = ui_style + using.icon_state = "act_drop" + using.screen_loc = ui_drop_throw + using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha + src.hotkeybuttons += using - inv_box = new /obj/screen/inventory() - inv_box.name = "id" - inv_box.dir = NORTH - inv_box.icon = ui_style - inv_box.icon_state = "id" - inv_box.screen_loc = ui_id - inv_box.slot_id = slot_wear_id - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.adding += inv_box + if(hud_data.has_hands) - inv_box = new /obj/screen/inventory() - inv_box.name = "mask" - inv_box.dir = NORTH - inv_box.icon = ui_style - inv_box.icon_state = "equip" - inv_box.screen_loc = ui_mask - inv_box.slot_id = slot_wear_mask - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + using = new /obj/screen() + using.name = "equip" + using.icon = ui_style + using.icon_state = "act_equip" + using.screen_loc = ui_equip + using.layer = 20 + using.color = ui_color + using.alpha = ui_alpha + src.adding += using - inv_box = new /obj/screen/inventory() - inv_box.name = "back" - inv_box.dir = NORTH - inv_box.icon = ui_style - inv_box.icon_state = "back" - inv_box.screen_loc = ui_back - inv_box.slot_id = slot_back - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.adding += inv_box + inv_box = new /obj/screen/inventory() + inv_box.name = "r_hand" + inv_box.dir = WEST + inv_box.icon = ui_style + inv_box.icon_state = "hand_inactive" + if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use + inv_box.icon_state = "hand_active" + inv_box.screen_loc = ui_rhand + inv_box.slot_id = slot_r_hand + inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha - inv_box = new /obj/screen/inventory() - inv_box.name = "storage1" - inv_box.icon = ui_style - inv_box.icon_state = "pocket" - inv_box.screen_loc = ui_storage1 - inv_box.slot_id = slot_l_store - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.adding += inv_box + src.r_hand_hud_object = inv_box + src.adding += inv_box - inv_box = new /obj/screen/inventory() - inv_box.name = "storage2" - inv_box.icon = ui_style - inv_box.icon_state = "pocket" - inv_box.screen_loc = ui_storage2 - inv_box.slot_id = slot_r_store - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.adding += inv_box + inv_box = new /obj/screen/inventory() + inv_box.name = "l_hand" + inv_box.dir = EAST + inv_box.icon = ui_style + inv_box.icon_state = "hand_inactive" + if(mymob && mymob.hand) //This being 1 means the left hand is in use + inv_box.icon_state = "hand_active" + inv_box.screen_loc = ui_lhand + inv_box.slot_id = slot_l_hand + inv_box.layer = 19 + inv_box.color = ui_color + inv_box.alpha = ui_alpha + src.l_hand_hud_object = inv_box + src.adding += inv_box - inv_box = new /obj/screen/inventory() - inv_box.name = "suit storage" - inv_box.icon = ui_style - inv_box.dir = 8 //The sprite at dir=8 has the background whereas the others don't. - inv_box.icon_state = "belt" - inv_box.screen_loc = ui_sstore1 - inv_box.slot_id = slot_s_store - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.adding += inv_box + using = new /obj/screen/inventory() + using.name = "hand" + using.dir = SOUTH + using.icon = ui_style + using.icon_state = "hand1" + using.screen_loc = ui_swaphand1 + using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha + src.adding += using - using = new /obj/screen() - using.name = "resist" - using.icon = ui_style - using.icon_state = "act_resist" - using.screen_loc = ui_pull_resist - using.layer = 19 - using.color = ui_color - using.alpha = ui_alpha - src.hotkeybuttons += using + using = new /obj/screen/inventory() + using.name = "hand" + using.dir = SOUTH + using.icon = ui_style + using.icon_state = "hand2" + using.screen_loc = ui_swaphand2 + using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha + src.adding += using - using = new /obj/screen() - using.name = "toggle" - using.icon = ui_style - using.icon_state = "other" - using.screen_loc = ui_inventory - using.layer = 20 - using.color = ui_color - using.alpha = ui_alpha - src.adding += using + if(hud_data.has_resist) + using = new /obj/screen() + using.name = "resist" + using.icon = ui_style + using.icon_state = "act_resist" + using.screen_loc = ui_pull_resist + using.layer = 19 + using.color = ui_color + using.alpha = ui_alpha + src.hotkeybuttons += using - using = new /obj/screen() - using.name = "equip" - using.icon = ui_style - using.icon_state = "act_equip" - using.screen_loc = ui_equip - using.layer = 20 - using.color = ui_color - using.alpha = ui_alpha - src.adding += using + if(hud_data.has_throw) + mymob.throw_icon = new /obj/screen() + mymob.throw_icon.icon = ui_style + mymob.throw_icon.icon_state = "act_throw_off" + mymob.throw_icon.name = "throw" + mymob.throw_icon.screen_loc = ui_drop_throw + mymob.throw_icon.color = ui_color + mymob.throw_icon.alpha = ui_alpha + src.hotkeybuttons += mymob.throw_icon + hud_elements |= mymob.throw_icon - inv_box = new /obj/screen/inventory() - inv_box.name = "gloves" - inv_box.icon = ui_style - inv_box.icon_state = "gloves" - inv_box.screen_loc = ui_gloves - inv_box.slot_id = slot_gloves - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + mymob.pullin = new /obj/screen() + mymob.pullin.icon = ui_style + mymob.pullin.icon_state = "pull0" + mymob.pullin.name = "pull" + mymob.pullin.screen_loc = ui_pull_resist + src.hotkeybuttons += mymob.pullin + hud_elements |= mymob.pullin - inv_box = new /obj/screen/inventory() - inv_box.name = "eyes" - inv_box.icon = ui_style - inv_box.icon_state = "glasses" - inv_box.screen_loc = ui_glasses - inv_box.slot_id = slot_glasses - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + if(hud_data.has_internals) + mymob.internals = new /obj/screen() + mymob.internals.icon = ui_style + mymob.internals.icon_state = "internal0" + mymob.internals.name = "internal" + mymob.internals.screen_loc = ui_internal - inv_box = new /obj/screen/inventory() - inv_box.name = "l_ear" - inv_box.icon = ui_style - inv_box.icon_state = "ears" - inv_box.screen_loc = ui_l_ear - inv_box.slot_id = slot_l_ear - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + if(hud_data.has_warnings) + mymob.oxygen = new /obj/screen() + mymob.oxygen.icon = ui_style + mymob.oxygen.icon_state = "oxy0" + mymob.oxygen.name = "oxygen" + mymob.oxygen.screen_loc = ui_oxygen + hud_elements |= mymob.oxygen - inv_box = new /obj/screen/inventory() - inv_box.name = "r_ear" - inv_box.icon = ui_style - inv_box.icon_state = "ears" - inv_box.screen_loc = ui_r_ear - inv_box.slot_id = slot_r_ear - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + mymob.toxin = new /obj/screen() + mymob.toxin.icon = ui_style + mymob.toxin.icon_state = "tox0" + mymob.toxin.name = "toxin" + mymob.toxin.screen_loc = ui_toxin + hud_elements |= mymob.toxin - inv_box = new /obj/screen/inventory() - inv_box.name = "head" - inv_box.icon = ui_style - inv_box.icon_state = "hair" - inv_box.screen_loc = ui_head - inv_box.slot_id = slot_head - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + mymob.fire = new /obj/screen() + mymob.fire.icon = ui_style + mymob.fire.icon_state = "fire0" + mymob.fire.name = "fire" + mymob.fire.screen_loc = ui_fire + hud_elements |= mymob.fire - inv_box = new /obj/screen/inventory() - inv_box.name = "shoes" - inv_box.icon = ui_style - inv_box.icon_state = "shoes" - inv_box.screen_loc = ui_shoes - inv_box.slot_id = slot_shoes - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.other += inv_box + mymob.healths = new /obj/screen() + mymob.healths.icon = ui_style + mymob.healths.icon_state = "health0" + mymob.healths.name = "health" + mymob.healths.screen_loc = ui_health + hud_elements |= mymob.healths - inv_box = new /obj/screen/inventory() - inv_box.name = "belt" - inv_box.icon = ui_style - inv_box.icon_state = "belt" - inv_box.screen_loc = ui_belt - inv_box.slot_id = slot_belt - inv_box.layer = 19 - inv_box.color = ui_color - inv_box.alpha = ui_alpha - src.adding += inv_box + if(hud_data.has_pressure) + mymob.pressure = new /obj/screen() + mymob.pressure.icon = ui_style + mymob.pressure.icon_state = "pressure0" + mymob.pressure.name = "pressure" + mymob.pressure.screen_loc = ui_pressure + hud_elements |= mymob.pressure - mymob.throw_icon = new /obj/screen() - mymob.throw_icon.icon = ui_style - mymob.throw_icon.icon_state = "act_throw_off" - mymob.throw_icon.name = "throw" - mymob.throw_icon.screen_loc = ui_drop_throw - mymob.throw_icon.color = ui_color - mymob.throw_icon.alpha = ui_alpha - src.hotkeybuttons += mymob.throw_icon + if(hud_data.has_bodytemp) + mymob.bodytemp = new /obj/screen() + mymob.bodytemp.icon = ui_style + mymob.bodytemp.icon_state = "temp1" + mymob.bodytemp.name = "body temperature" + mymob.bodytemp.screen_loc = ui_temp + hud_elements |= mymob.bodytemp - mymob.oxygen = new /obj/screen() - mymob.oxygen.icon = ui_style - mymob.oxygen.icon_state = "oxy0" - mymob.oxygen.name = "oxygen" - mymob.oxygen.screen_loc = ui_oxygen - - mymob.pressure = new /obj/screen() - mymob.pressure.icon = ui_style - mymob.pressure.icon_state = "pressure0" - mymob.pressure.name = "pressure" - mymob.pressure.screen_loc = ui_pressure - - mymob.toxin = new /obj/screen() - mymob.toxin.icon = ui_style - mymob.toxin.icon_state = "tox0" - mymob.toxin.name = "toxin" - mymob.toxin.screen_loc = ui_toxin - - mymob.internals = new /obj/screen() - mymob.internals.icon = ui_style - mymob.internals.icon_state = "internal0" - mymob.internals.name = "internal" - mymob.internals.screen_loc = ui_internal - - mymob.fire = new /obj/screen() - mymob.fire.icon = ui_style - mymob.fire.icon_state = "fire0" - mymob.fire.name = "fire" - mymob.fire.screen_loc = ui_fire - - mymob.bodytemp = new /obj/screen() - mymob.bodytemp.icon = ui_style - mymob.bodytemp.icon_state = "temp1" - mymob.bodytemp.name = "body temperature" - mymob.bodytemp.screen_loc = ui_temp - - mymob.healths = new /obj/screen() - mymob.healths.icon = ui_style - mymob.healths.icon_state = "health0" - mymob.healths.name = "health" - mymob.healths.screen_loc = ui_health - - mymob.nutrition_icon = new /obj/screen() - mymob.nutrition_icon.icon = ui_style - mymob.nutrition_icon.icon_state = "nutrition0" - mymob.nutrition_icon.name = "nutrition" - mymob.nutrition_icon.screen_loc = ui_nutrition - - mymob.pullin = new /obj/screen() - mymob.pullin.icon = ui_style - mymob.pullin.icon_state = "pull0" - mymob.pullin.name = "pull" - mymob.pullin.screen_loc = ui_pull_resist - src.hotkeybuttons += mymob.pullin + if(hud_data.has_nutrition) + mymob.nutrition_icon = new /obj/screen() + mymob.nutrition_icon.icon = ui_style + mymob.nutrition_icon.icon_state = "nutrition0" + mymob.nutrition_icon.name = "nutrition" + mymob.nutrition_icon.screen_loc = ui_nutrition + hud_elements |= mymob.nutrition_icon mymob.blind = new /obj/screen() mymob.blind.icon = 'icons/mob/screen1_full.dmi' @@ -419,6 +308,7 @@ mymob.blind.screen_loc = "1,1" mymob.blind.mouse_opacity = 0 mymob.blind.layer = 0 + hud_elements |= mymob.blind mymob.damageoverlay = new /obj/screen() mymob.damageoverlay.icon = 'icons/mob/screen1_full.dmi' @@ -427,6 +317,7 @@ mymob.damageoverlay.screen_loc = "1,1" mymob.damageoverlay.mouse_opacity = 0 mymob.damageoverlay.layer = 18.1 //The black screen overlay sets layer to 18 to display it, this one has to be just on top. + hud_elements |= mymob.damageoverlay mymob.flash = new /obj/screen() mymob.flash.icon = ui_style @@ -434,6 +325,7 @@ mymob.flash.name = "flash" mymob.flash.screen_loc = "1,1 to 15,15" mymob.flash.layer = 17 + hud_elements |= mymob.flash mymob.pain = new /obj/screen( null ) @@ -443,11 +335,13 @@ mymob.zone_sel.alpha = ui_alpha mymob.zone_sel.overlays.Cut() mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]") + hud_elements |= mymob.zone_sel //Handle the gun settings buttons mymob.gun_setting_icon = new /obj/screen/gun/mode(null) //mymob.gun_setting_icon.color = ui_color mymob.gun_setting_icon.alpha = ui_alpha + hud_elements |= mymob.gun_setting_icon mymob.item_use_icon = new /obj/screen/gun/item(null) //mymob.item_use_icon.color = ui_color @@ -468,7 +362,7 @@ mymob.client.screen = null - mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.pressure, mymob.toxin, mymob.bodytemp, mymob.internals, mymob.fire, mymob.healths, mymob.nutrition_icon, mymob.pullin, mymob.blind, mymob.flash, mymob.damageoverlay, mymob.gun_setting_icon) //, mymob.hands, mymob.rest, mymob.sleep) //, mymob.mach ) + mymob.client.screen += hud_elements mymob.client.screen += src.adding + src.hotkeybuttons inventory_shown = 0; diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 079c551ebf4..8a10310b3d4 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -235,8 +235,6 @@ if("walk") usr.m_intent = "run" usr.hud_used.move_intent.icon_state = "running" - if(istype(usr,/mob/living/carbon/alien/humanoid)) - usr.update_icons() if("m_intent") if(!usr.m_int) switch(usr.m_intent) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index b84b9f467c5..3c1cb437276 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -90,21 +90,10 @@ Aliens Defaults to same as monkey in most places */ -/mob/living/carbon/alien/UnarmedAttack(var/atom/A) - A.attack_alien(src) -/atom/proc/attack_alien(mob/user as mob) - attack_paw(user) - return + /mob/living/carbon/alien/RestrainedClickOn(var/atom/A) return -// Babby aliens -/mob/living/carbon/alien/larva/UnarmedAttack(var/atom/A) - A.attack_larva(src) -/atom/proc/attack_larva(mob/user as mob) - return - - /* Slimes Nothing happening here diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm index d36fc7a7c7f..001372b4e3e 100644 --- a/code/controllers/hooks-defs.dm +++ b/code/controllers/hooks-defs.dm @@ -47,7 +47,7 @@ /** * Podman hook. * Called in podmen.dm when someone is brought back as a Diona. - * Parameters: var/mob/living/carbon/monkey/diona + * Parameters: var/mob/living/carbon/alien/diona */ /hook/harvest_podman diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 4c01933dbe6..4777f061d60 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -495,7 +495,7 @@ client src.give_disease(M) href_list["datumrefresh"] = href_list["give_spell"] - + else if(href_list["give_disease2"]) if(!check_rights(R_ADMIN|R_FUN)) return @@ -777,6 +777,9 @@ client usr << "Mob doesn't exist anymore" return + // Clear out their species abilities. + H.species.remove_inherent_verbs(H) + if(H.set_species(new_species)) usr << "Set species of [H] to [H.species]." H.regenerate_icons() @@ -827,9 +830,9 @@ client else if(href_list["addverb"]) if(!check_rights(R_DEBUG)) return - + var/mob/living/H = locate(href_list["addverb"]) - + if(!istype(H)) usr << "This can only be done to instances of type /mob/living" return @@ -845,7 +848,7 @@ client possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/ai/proc,/mob/living/silicon/ai/verb) possibleverbs -= H.verbs possibleverbs += "Cancel" // ...And one for the bottom - + var/verb = input("Select a verb!", "Verbs",null) as anything in possibleverbs if(!H) usr << "Mob doesn't exist anymore" @@ -854,7 +857,7 @@ client return else H.verbs += verb - + else if(href_list["remverb"]) if(!check_rights(R_DEBUG)) return @@ -872,7 +875,7 @@ client else H.verbs -= verb - + else if(href_list["fix_nano"]) if(!check_rights(R_DEBUG)) return @@ -881,11 +884,11 @@ client if(!istype(H) || !H.client) usr << "This can only be done on mobs with clients" return - - + + nanomanager.send_resources(H.client) - + usr << "Resource files sent" H << "Your NanoUI Resource files have been refreshed" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 34dc2e13448..cc22ce05d37 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1234,27 +1234,6 @@ datum/mind ..() mind.assigned_role = "slime" -//XENO -/mob/living/carbon/alien/mind_initialize() - ..() - mind.assigned_role = "Alien" - //XENO HUMANOID -/mob/living/carbon/alien/humanoid/queen/mind_initialize() - ..() - mind.special_role = "Queen" - -/mob/living/carbon/alien/humanoid/hunter/mind_initialize() - ..() - mind.special_role = "Hunter" - -/mob/living/carbon/alien/humanoid/drone/mind_initialize() - ..() - mind.special_role = "Drone" - -/mob/living/carbon/alien/humanoid/sentinel/mind_initialize() - ..() - mind.special_role = "Sentinel" - //XENO LARVA /mob/living/carbon/alien/larva/mind_initialize() ..() mind.special_role = "Larva" diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm index be2bb88a172..d08679bbc12 100644 --- a/code/game/gamemodes/changeling/changeling_powers.dm +++ b/code/game/gamemodes/changeling/changeling_powers.dm @@ -111,7 +111,7 @@ src.visible_message("[src] transforms!") src.verbs -= /mob/proc/changeling_change_species - H.set_species(S,null,1) //Until someone moves body colour into DNA, they're going to have to use the default. + H.set_species(S,1) //Until someone moves body colour into DNA, they're going to have to use the default. spawn(10) src.verbs += /mob/proc/changeling_change_species diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 590df9cd07d..83ca646d894 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -690,21 +690,6 @@ var/list/sacrificed = list() if(prob(20)) ticker.mode.grant_runeword(usr) M.gib() -/* for(var/mob/living/carbon/alien/A) - for(var/mob/K in cultsinrange) - K.say("Barhah hra zar'garis!") - A.dust() /// A.gib() doesnt work for some reason, and dust() leaves that skull and bones thingy which we dont really need. - if (ticker.mode.name == "cult") - if(prob(75)) - usr << "\red The Geometer of Blood accepts your exotic sacrifice." - ticker.mode:grant_runeword(usr) - else - usr << "\red The Geometer of Blood accepts your exotic sacrifice." - usr << "\red However, this alien is not enough to gain His favor." - else - usr << "\red The Geometer of Blood accepts your exotic sacrifice." - return - return fizzle() */ /////////////////////////////////////////SIXTEENTH RUNE diff --git a/code/game/gamemodes/events/ninja_equipment.dm b/code/game/gamemodes/events/ninja_equipment.dm index b36eb64d8b4..ded12b2da80 100644 --- a/code/game/gamemodes/events/ninja_equipment.dm +++ b/code/game/gamemodes/events/ninja_equipment.dm @@ -1451,32 +1451,34 @@ It is possible to destroy the net by the occupant or someone else. return attack_hand() + if (HULK in usr.mutations) usr << text("\blue You easily destroy the energy net.") for(var/mob/O in oviewers(src)) O.show_message(text("\red [] rips the energy net apart!", usr), 1) health-=50 + else if(istype(usr,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = usr + if(H.species.can_shred(H)) + + H << text("\green You claw at the net.") + for(var/mob/O in oviewers(src)) + O.show_message(text("\red [] claws at the energy net!", H), 1) + + playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1) + health -= rand(10, 20) + + if(health <= 0) + H << text("\green You slice the energy net to pieces.") + for(var/mob/O in oviewers(src)) + O.show_message(text("\red [] slices the energy net apart!", H), 1) + healthcheck() return attack_paw() return attack_hand() - attack_alien() - if (islarva(usr)) - return - usr << text("\green You claw at the net.") - for(var/mob/O in oviewers(src)) - O.show_message(text("\red [] claws at the energy net!", usr), 1) - playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1) - health -= rand(10, 20) - if(health <= 0) - usr << text("\green You slice the energy net to pieces.") - for(var/mob/O in oviewers(src)) - O.show_message(text("\red [] slices the energy net apart!", usr), 1) - healthcheck() - return - attackby(obj/item/weapon/W as obj, mob/user as mob) var/aforce = W.force health = max(0, health - aforce) diff --git a/code/game/gamemodes/events/space_ninja.dm b/code/game/gamemodes/events/space_ninja.dm index c1fd9b219f9..5dae9e6e4b7 100644 --- a/code/game/gamemodes/events/space_ninja.dm +++ b/code/game/gamemodes/events/space_ninja.dm @@ -219,8 +219,8 @@ Malf AIs/silicons aren't added. Monkeys aren't added. Messes with objective comp //Xenos and deathsquads take precedence over everything else. //Unless the xenos are hiding in a locker somewhere, this'll find em. - for(var/mob/living/carbon/alien/humanoid/xeno in player_list) - if(istype(xeno)) + for(var/mob/living/carbon/human/xeno in player_list) + if(istype(xeno.species,/datum/species/xenos)) xeno_list += xeno if(assign_mission) @@ -230,11 +230,11 @@ Malf AIs/silicons aren't added. Monkeys aren't added. Messes with objective comp if(xeno_list.len>3)//If there are more than three humanoid xenos on the station, time to get dangerous. //Here we want the ninja to murder all the queens. The other aliens don't really matter. var/xeno_queen_list[] = list() - for(var/mob/living/carbon/alien/humanoid/queen/xeno_queen in xeno_list) - if(xeno_queen.mind&&xeno_queen.stat!=2) + for(var/mob/living/carbon/human/xeno_queen in xeno_list) + if(xeno_queen.species.name == "Xenomorph Queen" && xeno_queen.mind && xeno_queen.stat!=2) xeno_queen_list += xeno_queen if(xeno_queen_list.len&&side=="face")//If there are queen about and the probability is 50. - for(var/mob/living/carbon/alien/humanoid/queen/xeno_queen in xeno_queen_list) + for(var/mob/living/carbon/human/xeno_queen in xeno_queen_list) var/datum/objective/assassinate/ninja_objective = new ninja_objective.owner = ninja_mind //We'll do some manual overrides to properly set it up. diff --git a/code/game/gamemodes/mutiny/mutiny_hooks.dm b/code/game/gamemodes/mutiny/mutiny_hooks.dm index 5bcddade430..9e64bd2e700 100644 --- a/code/game/gamemodes/mutiny/mutiny_hooks.dm +++ b/code/game/gamemodes/mutiny/mutiny_hooks.dm @@ -12,7 +12,7 @@ mode.update_icon(H.mind) return 1 -/hook/harvest_podman/proc/update_icon(mob/living/carbon/monkey/diona/D) +/hook/harvest_podman/proc/update_icon(mob/living/carbon/alien/diona/D) var/datum/game_mode/mutiny/mode = get_mutiny_mode() if (!mode) return 1 diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 9ff5608e2df..d01e0e3506f 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -649,17 +649,6 @@ datum/objective/capture captured_amount+=0.5 continue captured_amount+=1 - for(var/mob/living/carbon/alien/humanoid/M in A)//Aliens are worth twice as much as humans. - if(istype(M, /mob/living/carbon/alien/humanoid/queen))//Queens are worth three times as much as humans. - if(M.stat==2) - captured_amount+=1.5 - else - captured_amount+=3 - continue - if(M.stat==2) - captured_amount+=1 - continue - captured_amount+=2 if(captured_amount[src]'s parts look very loose!" return -/obj/machinery/bot/attack_alien(var/mob/living/carbon/alien/user as mob) - src.health -= rand(15,30)*brute_dam_coeff - src.visible_message("\red [user] has slashed [src]!") - playsound(src.loc, 'sound/weapons/slice.ogg', 25, 1, -1) - if(prob(10)) - new /obj/effect/decal/cleanable/blood/oil(src.loc) - healthcheck() - - /obj/machinery/bot/attack_animal(var/mob/living/simple_animal/M as mob) if(M.melee_damage_upper == 0) return src.health -= M.melee_damage_upper @@ -155,6 +146,19 @@ /obj/machinery/bot/attack_ai(mob/user as mob) src.attack_hand(user) +/obj/machinery/bot/attack_hand(var/mob/living/carbon/human/user) + + if(!istype(user)) + return ..() + + if(user.species.can_shred(user)) + src.health -= rand(15,30)*brute_dam_coeff + src.visible_message("\red [user] has slashed [src]!") + playsound(src.loc, 'sound/weapons/slice.ogg', 25, 1, -1) + if(prob(10)) + new /obj/effect/decal/cleanable/blood/oil(src.loc) + healthcheck() + /******************************************************************/ // Navigation procs // Used for A-star pathfinding diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index 094f3ff7006..8868914872e 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -787,12 +787,6 @@ Auto Patrol: []"}, if(prob(50)) new /obj/item/robot_parts/l_arm(Tsec) -/obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob) - ..() - if(!isalien(target)) - src.target = user - src.mode = SECBOT_HUNT - //Secbot Construction /obj/item/clothing/head/helmet/attackby(var/obj/item/device/assembly/signaler/S, mob/user as mob) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 14f8f93e56f..1c8298bd0ba 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -88,15 +88,18 @@ src.view_range = num cameranet.updateVisibility(src, 0) -/obj/machinery/camera/attack_paw(mob/living/carbon/alien/humanoid/user as mob) +/obj/machinery/camera/attack_hand(mob/living/carbon/human/user as mob) + if(!istype(user)) return - status = 0 - visible_message("\The [user] slashes at [src]!") - playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) - icon_state = "[initial(icon_state)]1" - add_hiddenprint(user) - deactivate(user,0) + + if(user.species.can_shred(user)) + status = 0 + visible_message("\The [user] slashes at [src]!") + playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) + icon_state = "[initial(icon_state)]1" + add_hiddenprint(user) + deactivate(user,0) /obj/machinery/camera/attackby(W as obj, mob/living/user as mob) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 04f5efa5185..8f1eff7d632 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -77,9 +77,10 @@ if ((M.stat != 2) || (!M.client)) continue //They need a brain! - if ((istype(M, /mob/living/carbon/human)) && (!M.has_brain())) - continue - + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.species.has_organ["brain"] && !H.has_brain()) + continue if (M.ckey == find_key) selected = M break diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm index 5887e0bc326..65871a67b3d 100644 --- a/code/game/machinery/computer/HolodeckControl.dm +++ b/code/game/machinery/computer/HolodeckControl.dm @@ -339,10 +339,7 @@ var/global/list/holodeck_programs = list( /obj/structure/table/holotable/attack_paw(mob/user as mob) return attack_hand(user) -/obj/structure/table/holotable/attack_alien(mob/user as mob) //Removed code for larva since it doesn't work. Previous code is now a larva ability. /N - return attack_hand(user) - -/obj/structure/table/holotable/attack_animal(mob/living/simple_animal/user as mob) //Removed code for larva since it doesn't work. Previous code is now a larva ability. /N +/obj/structure/table/holotable/attack_animal(mob/living/user as mob) //Removed code for larva since it doesn't work. Previous code is now a larva ability. /N return attack_hand(user) /obj/structure/table/holotable/attack_hand(mob/user as mob) @@ -594,9 +591,6 @@ var/global/list/holodeck_programs = list( icon = 'icons/obj/objects.dmi' icon_state = "rack" -/obj/structure/rack/holorack/attack_alien(mob/user as mob) //Removed code for larva since it doesn't work. Previous code is now a larva ability. /N - return attack_hand(user) - /obj/structure/rack/holorack/attack_hand(mob/user as mob) return diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 47eb7ca5583..3897ee1d08c 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -338,7 +338,12 @@ scantemp = "Error: Unable to locate valid genetic data." return if (!subject.has_brain()) - scantemp = "Error: No signs of intelligence detected." + if(istype(subject, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = subject + if(H.species.has_organ["brain"]) + scantemp = "Error: No signs of intelligence detected." + else + scantemp = "Error: No signs of intelligence detected." return if (subject.suiciding == 1) scantemp = "Error: Subject's brain is not responding to scanning stimuli." diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 288465a160a..473bd973ed4 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -172,18 +172,15 @@ /obj/machinery/door/window/attack_ai(mob/user as mob) return src.attack_hand(user) -/obj/machinery/door/window/attack_paw(mob/user as mob) - if(istype(user, /mob/living/carbon/alien/humanoid)) - if(src.operating) - return - playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) - visible_message("\red [user] smashes against the [src.name].", 1) - take_damage(25) - else - return src.attack_hand(user) - - /obj/machinery/door/window/attack_hand(mob/user as mob) + + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(H)) + playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + visible_message("\red [user] smashes against the [src.name].", 1) + take_damage(25) + return return src.attackby(user, user) /obj/machinery/door/window/attackby(obj/item/weapon/I as obj, mob/user as mob) diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm index 5ad0ecae560..d3e9b81e157 100644 --- a/code/game/machinery/turrets.dm +++ b/code/game/machinery/turrets.dm @@ -71,6 +71,27 @@ var/targeting_active = 0 var/area/turret_protected/protected_area +/obj/machinery/turret/proc/take_damage(damage) + src.health -= damage + if(src.health<=0) + del src + return + +/obj/machinery/turret/attack_hand(var/mob/living/carbon/human/user) + + if(!istype(user)) + return ..() + + if(user.species.can_shred(user) && !(stat & BROKEN)) + playsound(src.loc, 'sound/weapons/slash.ogg', 25, 1, -1) + visible_message("\red [] has slashed at []!", user, src) + src.take_damage(15) + return + +/obj/machinery/turret/bullet_act(var/obj/item/projectile/Proj) + take_damage(Proj.damage) + ..() + return /obj/machinery/turret/New() spark_system = new /datum/effect/effect/system/spark_spread @@ -80,6 +101,11 @@ ..() return +/obj/machinery/turret/proc/update_health() + if(src.health<=0) + del src + return + /obj/machinery/turretcover name = "pop-up turret cover" icon = 'icons/obj/turrets.dmi' @@ -407,7 +433,7 @@ onclose(user, "turretid") -/obj/machinery/turret/attack_animal(mob/living/simple_animal/M as mob) +/obj/machinery/turret/attack_animal(mob/living/M as mob) if(M.melee_damage_upper == 0) return if(!(stat & BROKEN)) visible_message("\red [M] [M.attacktext] [src]!") @@ -420,22 +446,6 @@ M << "\red That object is useless to you." return - - - -/obj/machinery/turret/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if(!(stat & BROKEN)) - playsound(src.loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("\red [] has slashed at []!", M, src) - src.health -= 15 - if (src.health <= 0) - src.die() - else - M << "\green That object is useless to you." - return - - - /obj/machinery/turretid/Topic(href, href_list, var/nowindow = 0) if(..(href, href_list)) return @@ -494,6 +504,18 @@ icon = 'icons/obj/turrets.dmi' icon_state = "gun_turret" + proc/take_damage(damage) + src.health -= damage + if(src.health<=0) + del src + return + + + bullet_act(var/obj/item/projectile/Proj) + take_damage(Proj.damage) + ..() + return + ex_act() del src @@ -507,24 +529,6 @@ del src return - proc/update_health() - if(src.health<=0) - del src - return - - proc/take_damage(damage) - src.health -= damage - if(src.health<=0) - del src - return - - - bullet_act(var/obj/item/projectile/Proj) - src.take_damage(Proj.damage) - ..() - return - - attack_hand(mob/user as mob) user.set_machine(src) var/dat = {" @@ -546,12 +550,6 @@ attack_ai(mob/user as mob) return attack_hand(user) - - attack_alien(mob/user as mob) - user.visible_message("[user] slashes at [src]", "You slash at [src]") - src.take_damage(15) - return - Topic(href, href_list) if(href_list["power"]) src.on = !src.on diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 78ee794b532..decf7afb43e 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -418,7 +418,26 @@ /obj/mecha/attack_hand(mob/user as mob) src.log_message("Attack by hand/paw. Attacker - [user].",1) - if ((HULK in user.mutations) && !prob(src.deflect_chance)) + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(user)) + if(!prob(src.deflect_chance)) + src.take_damage(15) + src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + user << "\red You slash at the armored suit!" + visible_message("\red The [user] slashes at [src.name]'s armor!") + else + src.log_append_to_last("Armor saved.") + playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) + user << "\green Your claws had no effect!" + src.occupant_message("\blue The [user]'s claws are stopped by the armor.") + visible_message("\blue The [user] rebounds off [src.name]'s armor!") + else + user.visible_message("[user] hits [src.name]. Nothing happens","You hit [src.name] with no visible effect.") + src.log_append_to_last("Armor saved.") + return + else if ((HULK in user.mutations) && !prob(src.deflect_chance)) src.take_damage(15) src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) user.visible_message("[user] hits [src.name], doing some damage.", "You hit [src.name] with all your might. The metal creaks and bends.") @@ -430,25 +449,7 @@ /obj/mecha/attack_paw(mob/user as mob) return src.attack_hand(user) - -/obj/mecha/attack_alien(mob/user as mob) - src.log_message("Attack by alien. Attacker - [user].",1) - if(!prob(src.deflect_chance)) - src.take_damage(15) - src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST)) - playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) - user << "\red You slash at the armored suit!" - visible_message("\red The [user] slashes at [src.name]'s armor!") - else - src.log_append_to_last("Armor saved.") - playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1) - user << "\green Your claws had no effect!" - src.occupant_message("\blue The [user]'s claws are stopped by the armor.") - visible_message("\blue The [user] rebounds off [src.name]'s armor!") - return - - -/obj/mecha/attack_animal(mob/living/simple_animal/user as mob) +/obj/mecha/attack_animal(mob/living/user as mob) src.log_message("Attack by simple animal. Attacker - [user].",1) if(user.melee_damage_upper == 0) user.emote("[user.friendly] [src]") diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index 5e3ba542bfa..9983eff1ac0 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -14,8 +14,6 @@ name = "alien thing" desc = "theres something alien about this" icon = 'icons/mob/alien.dmi' -// unacidable = 1 //Aliens won't ment their own. - /* * Resin @@ -31,17 +29,17 @@ var/health = 200 //var/mob/living/affecting = null - wall - name = "resin wall" - desc = "Purple slime solidified into a wall." - icon_state = "resinwall" //same as resin, but consistency ho! +/obj/effect/alien/resin/wall + name = "resin wall" + desc = "Purple slime solidified into a wall." + icon_state = "resinwall" //same as resin, but consistency ho! - membrane - name = "resin membrane" - desc = "Purple slime just thin enough to let light pass through." - icon_state = "resinmembrane" - opacity = 0 - health = 120 +/obj/effect/alien/resin/membrane + name = "resin membrane" + desc = "Purple slime just thin enough to let light pass through." + icon_state = "resinmembrane" + opacity = 0 + health = 120 /obj/effect/alien/resin/New() ..() @@ -121,42 +119,7 @@ /obj/effect/alien/resin/attack_paw() return attack_hand() -/obj/effect/alien/resin/attack_alien() - if (islarva(usr))//Safety check for larva. /N - return - usr << "\green You claw at the [name]." - for(var/mob/O in oviewers(src)) - O.show_message("\red [usr] claws at the resin!", 1) - playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) - health -= rand(40, 60) - if(health <= 0) - usr << "\green You slice the [name] to pieces." - for(var/mob/O in oviewers(src)) - O.show_message("\red [usr] slices the [name] apart!", 1) - healthcheck() - return - /obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob) - /*if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2) - var/obj/item/weapon/grab/G = W - if(isalien(user)&&(ishuman(G.affecting)||ismonkey(G.affecting))) - //Only aliens can stick humans and monkeys into resin walls. Also, the wall must not have a person inside already. - if(!affecting) - if(G.state<2) - user << "\red You need a better grip to do that!" - return - G.affecting.loc = src - G.affecting.paralysis = 10 - for(var/mob/O in viewers(world.view, src)) - if (O.client) - O << text("\green [] places [] in the resin wall!", G.assailant, G.affecting) - affecting=G.affecting - del(W) - spawn(0) - process() - else - user << "\red This wall is already occupied." - return */ var/aforce = W.force health = max(0, health - aforce) @@ -234,7 +197,7 @@ Alien plants should do something if theres a lot of poison if(!linked_node || (get_dist(linked_node, src) > linked_node.node_range) ) return - + direction_loop: for(var/dirn in cardinal) var/turf/T = get_step(src, dirn) @@ -292,15 +255,6 @@ Alien plants should do something if theres a lot of poison health -= 5 healthcheck() -/*/obj/effect/alien/weeds/burn(fi_amount) - if (fi_amount > 18000) - spawn( 0 ) - del(src) - return - return 0 - return 1 -*/ - #undef NODERANGE @@ -382,61 +336,59 @@ Alien plants should do something if theres a lot of poison var/health = 100 var/status = GROWING //can be GROWING, GROWN or BURST; all mutually exclusive - New() - if(aliens_allowed) - ..() - spawn(rand(MIN_GROWTH_TIME,MAX_GROWTH_TIME)) - Grow() - else +/obj/effect/alien/egg/New() + if(aliens_allowed) + ..() + spawn(rand(MIN_GROWTH_TIME,MAX_GROWTH_TIME)) + Grow() + else + del(src) + +/obj/effect/alien/egg/attack_hand(user as mob) + + var/mob/living/carbon/M = user + if(!istype(M) || !(locate(/datum/organ/internal/xenos/hivenode) in M.internal_organs)) + return attack_hand(user) + + switch(status) + if(BURST) + user << "\red You clear the hatched egg." del(src) + return + if(GROWING) + user << "\red The child is not developed yet." + return + if(GROWN) + user << "\red You retrieve the child." + Burst(0) + return - attack_paw(user as mob) - if(isalien(user)) - switch(status) - if(BURST) - user << "\red You clear the hatched egg." - del(src) - return - if(GROWING) - user << "\red The child is not developed yet." - return - if(GROWN) - user << "\red You retrieve the child." - Burst(0) - return - else - return attack_hand(user) +/obj/effect/alien/egg/proc/GetFacehugger() + return locate(/obj/item/clothing/mask/facehugger) in contents - attack_hand(user as mob) - user << "It feels slimy." - return +/obj/effect/alien/egg/proc/Grow() + icon_state = "egg" + status = GROWN + new /obj/item/clothing/mask/facehugger(src) + return - proc/GetFacehugger() - return locate(/obj/item/clothing/mask/facehugger) in contents - - proc/Grow() - icon_state = "egg" - status = GROWN - new /obj/item/clothing/mask/facehugger(src) - return - - proc/Burst(var/kill = 1) //drops and kills the hugger if any is remaining - if(status == GROWN || status == GROWING) - var/obj/item/clothing/mask/facehugger/child = GetFacehugger() - icon_state = "egg_hatched" - flick("egg_opening", src) - status = BURSTING - spawn(15) - status = BURST - loc.contents += child//need to write the code for giving it to the alien later - if(kill && istype(child)) - child.Die() - else - for(var/mob/M in range(1,src)) - if(CanHug(M)) - child.Attach(M) - break +/obj/effect/alien/egg/proc/Burst(var/kill = 1) //drops and kills the hugger if any is remaining + if(status == GROWN || status == GROWING) + var/obj/item/clothing/mask/facehugger/child = GetFacehugger() + icon_state = "egg_hatched" + flick("egg_opening", src) + status = BURSTING + spawn(15) + status = BURST + child.loc = get_turf(src) + if(kill && istype(child)) + child.Die() + else + for(var/mob/M in range(1,src)) + if(CanHug(M)) + child.Attach(M) + break /obj/effect/alien/egg/bullet_act(var/obj/item/projectile/Proj) health -= Proj.damage diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index be54a95ba11..682347669a7 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -174,7 +174,7 @@ if(prob(25)) src.visible_message("\blue \the [src] skitters[pick(" away"," around","")].") else if(prob(5)) - //ventcrawl! + //vent crawl! for(var/obj/machinery/atmospherics/unary/vent_pump/v in view(7,src)) if(!v.welded) entry_vent = v diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b4155d6fcae..c7f8fadfcb2 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -155,15 +155,6 @@ /obj/item/attack_paw(mob/user as mob) - if(isalien(user)) // -- TLE - var/mob/living/carbon/alien/A = user - - if(!A.has_fine_manipulation || w_class >= 4) - if(src in A.contents) // To stop Aliens having items stuck in their pockets - A.drop_from_inventory(src) - user << "Your claws aren't capable of such fine manipulation." - return - if (istype(src.loc, /obj/item/weapon/storage)) for(var/mob/M in range(1, src.loc)) if (M.s_active == src.loc) diff --git a/code/game/objects/items/weapons/storage/secure.dm b/code/game/objects/items/weapons/storage/secure.dm index a30168479aa..635093436f8 100644 --- a/code/game/objects/items/weapons/storage/secure.dm +++ b/code/game/objects/items/weapons/storage/secure.dm @@ -32,9 +32,6 @@ ..() usr << text("The service panel is [src.open ? "open" : "closed"].") - attack_alien(mob/user as mob) - return attack_hand(user) - attack_paw(mob/user as mob) return attack_hand(user) diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm index 3080c05f09e..d9d7ec0126e 100644 --- a/code/game/objects/items/weapons/surgery_tools.dm +++ b/code/game/objects/items/weapons/surgery_tools.dm @@ -21,106 +21,6 @@ w_class = 2.0 origin_tech = "materials=1;biotech=1" -/*HAHA, SUCK IT, 2000 LINES OF SPAGHETTI CODE! - -NOW YOUR JOB IOS DONE BY ONLY 500 LINES OF SPAGHETTI CODE! - -LOOK FOR SURGERY.DM*/ - -/* -/obj/item/weapon/retractor/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) - return - - var/mob/living/carbon/human/H = M - if(istype(H) && ( \ - (H.head && H.head.flags & HEADCOVERSEYES) || \ - (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || \ - (H.glasses && H.glasses.flags & GLASSESCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - var/mob/living/carbon/monkey/Mo = M - if(istype(Mo) && ( \ - (Mo.wear_mask && Mo.wear_mask.flags & MASKCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - if(istype(M, /mob/living/carbon/alien) || istype(M, /mob/living/carbon/slime))//Aliens don't have eyes./N - user << "\red You cannot locate any eyes on this creature!" - return - - switch(M.eye_op_stage) - if(1.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is having his eyes retracted by [user].", 1) - M << "\red [user] begins to seperate your eyes with [src]!" - user << "\red You seperate [M]'s eyes with [src]!" - else - user.visible_message( \ - "\red [user] begins to have his eyes retracted.", \ - "\red You begin to pry open your eyes with [src]!" \ - ) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - if(affecting.take_damage(15)) - M:UpdateDamageIcon() - M.updatehealth() - else - M.take_organ_damage(15) - - M:eye_op_stage = 2.0 - - else if(user.zone_sel.selecting == "chest") - switch(M:alien_op_stage) - if(3.0) - var/mob/living/carbon/human/H = M - if(!istype(H)) - return ..() - - if(H.wear_suit || H.w_uniform) - user << "\red You're going to need to remove that suit/jumpsuit first." - return - - var/obj/item/alien_embryo/A = locate() in M.contents - if(!A) - return ..() - user.visible_message("\red [user] begins to pull something out of [M]'s chest.", "\red You begin to pull the alien organism out of [M]'s chest.") - - spawn(20 + rand(0,50)) - if(!A || A.loc != M) - return - - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("chest") - if(affecting.take_damage(30)) - M:UpdateDamageIcon() - else - M.take_organ_damage(30) - - if(A.stage > 3) - var/chance = 15 + max(0, A.stage - 3) * 10 - if(prob(chance)) - A.AttemptGrow(0) - M:alien_op_stage = 4.0 - - if(M) - user.visible_message("\red [user] pulls an alien organism out of [M]'s chest.", "\red You pull the alien organism out of [M]'s chest.") - A.loc = M.loc //alien embryo handles cleanup - - else if((!(user.zone_sel.selecting == "head")) || (!(user.zone_sel.selecting == "groin")) || (!(istype(M, /mob/living/carbon/human)))) - return ..() - - return -*/ - /* * Hemostat */ @@ -135,126 +35,6 @@ LOOK FOR SURGERY.DM*/ origin_tech = "materials=1;biotech=1" attack_verb = list("attacked", "pinched") -/* -/obj/item/weapon/hemostat/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) - return - - if(!((locate(/obj/machinery/optable, M.loc) && M.resting) || (locate(/obj/structure/table/, M.loc) && M.lying && prob(50)))) - return ..() - - if(user.zone_sel.selecting == "groin") - if(istype(M, /mob/living/carbon/human)) - switch(M:appendix_op_stage) - if(1.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [user] is beginning to clamp bleeders in [M]'s abdomen cut open with [src].", 1) - M << "\red [user] begins to clamp bleeders in your abdomen with [src]!" - user << "\red You clamp bleeders in [M]'s abdomen with [src]!" - M:appendix_op_stage = 2.0 - if(4.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [user] is removing [M]'s appendix with [src].", 1) - M << "\red [user] begins to remove your appendix with [src]!" - user << "\red You remove [M]'s appendix with [src]!" - for(var/datum/disease/D in M.viruses) - if(istype(D, /datum/disease/appendicitis)) - new /obj/item/weapon/reagent_containers/food/snacks/appendix/inflamed(get_turf(M)) - M:appendix_op_stage = 5.0 - return - new /obj/item/weapon/reagent_containers/food/snacks/appendix(get_turf(M)) - M:appendix_op_stage = 5.0 - return - - if (user.zone_sel.selecting == "eyes") - - var/mob/living/carbon/human/H = M - if(istype(H) && ( \ - (H.head && H.head.flags & HEADCOVERSEYES) || \ - (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || \ - (H.glasses && H.glasses.flags & GLASSESCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - var/mob/living/carbon/monkey/Mo = M - if(istype(Mo) && ( \ - (Mo.wear_mask && Mo.wear_mask.flags & MASKCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - if(istype(M, /mob/living/carbon/alien))//Aliens don't have eyes./N - user << "\red You cannot locate any eyes on this creature!" - return - - switch(M.eye_op_stage) - if(2.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is having his eyes mended by [user].", 1) - M << "\red [user] begins to mend your eyes with [src]!" - user << "\red You mend [M]'s eyes with [src]!" - else - user.visible_message( \ - "\red [user] begins to have his eyes mended.", \ - "\red You begin to mend your eyes with [src]!" \ - ) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - if(affecting.take_damage(15)) - M:UpdateDamageIcon() - M.updatehealth() - else - M.take_organ_damage(15) - M:eye_op_stage = 3.0 - - else if(user.zone_sel.selecting == "chest") - if(M:alien_op_stage == 2.0 || M:alien_op_stage == 3.0) - var/mob/living/carbon/human/H = M - if(!istype(H)) - return ..() - - if(H.wear_suit || H.w_uniform) - user << "\red You're going to need to remove that suit/jumpsuit first." - return - - user.visible_message("\red [user] begins to dig around in [M]'s chest.", "\red You begin to dig around in [M]'s chest.") - - spawn(20 + (M:alien_op_stage == 3 ? 0 : rand(0,50))) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("chest") - if(affecting.take_damage(30)) - M:UpdateDamageIcon() - else - M.take_organ_damage(30) - - var/obj/item/alien_embryo/A = locate() in M.contents - if(A) - var/dat = "\blue You found an unknown alien organism in [M]'s chest!" - if(A.stage < 4) - dat += " It's small and weak, barely the size of a foetus." - if(A.stage > 3) - dat += " It's grown quite large, and writhes slightly as you look at it." - if(prob(10)) - A.AttemptGrow() - user << dat - M:alien_op_stage = 3.0 - else - user << "\blue You find nothing of interest." - - else if((!(user.zone_sel.selecting == "head")) || (!(user.zone_sel.selecting == "groin")) || (!(istype(M, /mob/living/carbon/human)))) - return ..() - - return -*/ - /* * Cautery */ @@ -269,81 +49,6 @@ LOOK FOR SURGERY.DM*/ origin_tech = "materials=1;biotech=1" attack_verb = list("burnt") -/* -/obj/item/weapon/cautery/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) - return - - if(!((locate(/obj/machinery/optable, M.loc) && M.resting) || (locate(/obj/structure/table/, M.loc) && M.lying && prob(50)))) - return ..() - - if(user.zone_sel.selecting == "groin") - if(istype(M, /mob/living/carbon/human)) - switch(M:appendix_op_stage) - if(5.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [user] is beginning to cauterize the incision in [M]'s abdomen with [src].", 1) - M << "\red [user] begins to cauterize the incision in your abdomen with [src]!" - user << "\red You cauterize the incision in [M]'s abdomen with [src]!" - M:appendix_op_stage = 6.0 - for(var/datum/disease/appendicitis in M.viruses) - appendicitis.cure() - return - - if (user.zone_sel.selecting == "eyes") - - var/mob/living/carbon/human/H = M - if(istype(H) && ( \ - (H.head && H.head.flags & HEADCOVERSEYES) || \ - (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || \ - (H.glasses && H.glasses.flags & GLASSESCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - var/mob/living/carbon/monkey/Mo = M - if(istype(Mo) && ( \ - (Mo.wear_mask && Mo.wear_mask.flags & MASKCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - if(istype(M, /mob/living/carbon/alien))//Aliens don't have eyes./N - user << "\red You cannot locate any eyes on this creature!" - return - - switch(M.eye_op_stage) - if(3.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is having his eyes cauterized by [user].", 1) - M << "\red [user] begins to cauterize your eyes!" - user << "\red You cauterize [M]'s eyes with [src]!" - else - user.visible_message( \ - "\red [user] begins to have his eyes cauterized.", \ - "\red You begin to cauterize your eyes!" \ - ) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - if(affecting.take_damage(15)) - M:UpdateDamageIcon() - M.updatehealth() - else - M.take_organ_damage(15) - M.sdisabilities &= ~BLIND - M.eye_stat = 0 - M:eye_op_stage = 0.0 - - else if((!(user.zone_sel.selecting == "head")) || (!(user.zone_sel.selecting == "groin")) || (!(istype(M, /mob/living/carbon/human)))) - return ..() - - return -*/ - /* * Surgical Drill */ @@ -391,232 +96,6 @@ LOOK FOR SURGERY.DM*/ "\red [user] is slitting \his stomach open with the [src.name]! It looks like \he's trying to commit seppuku.") return (BRUTELOSS) -/* -/obj/item/weapon/scalpel/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) - return ..() - - //if(M.mutations & HUSK) return ..() - - if((CLUMSY in user.mutations) && prob(50)) - M = user - return eyestab(M,user) - - if(!((locate(/obj/machinery/optable, M.loc) && M.resting) || (locate(/obj/structure/table/, M.loc) && M.lying && prob(50)))) - return ..() - - src.add_fingerprint(user) - - if(user.zone_sel.selecting == "groin") - if(istype(M, /mob/living/carbon/human)) - switch(M:appendix_op_stage) - if(0.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is beginning to have his abdomen cut open with [src] by [user].", 1) - M << "\red [user] begins to cut open your abdomen with [src]!" - user << "\red You cut [M]'s abdomen open with [src]!" - M:appendix_op_stage = 1.0 - if(3.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is beginning to have his appendix seperated with [src] by [user].", 1) - M << "\red [user] begins to seperate your appendix with [src]!" - user << "\red You seperate [M]'s appendix with [src]!" - M:appendix_op_stage = 4.0 - return - - if(user.zone_sel.selecting == "head" || istype(M, /mob/living/carbon/slime)) - - var/mob/living/carbon/human/H = M - if(istype(H) && ( \ - (H.head && H.head.flags & HEADCOVERSEYES) || \ - (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || \ - (H.glasses && H.glasses.flags & GLASSESCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - var/mob/living/carbon/monkey/Mo = M - if(istype(Mo) && ( \ - (Mo.wear_mask && Mo.wear_mask.flags & MASKCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - switch(M:brain_op_stage) - if(0.0) - if(istype(M, /mob/living/carbon/slime)) - if(M.stat == 2) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M.name] is beginning to have its flesh cut open with [src] by [user].", 1) - M << "\red [user] begins to cut open your flesh with [src]!" - user << "\red You cut [M]'s flesh open with [src]!" - M:brain_op_stage = 1.0 - - return - - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is beginning to have his head cut open with [src] by [user].", 1) - M << "\red [user] begins to cut open your head with [src]!" - user << "\red You cut [M]'s head open with [src]!" - else - user.visible_message( \ - "\red [user] begins to cut open his skull with [src]!", \ - "\red You begin to cut open your head with [src]!" \ - ) - - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - if(affecting.take_damage(15)) - M:UpdateDamageIcon() - else - M.take_organ_damage(15) - - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - affecting.take_damage(7) - else - M.take_organ_damage(7) - - M.updatehealth() - M:brain_op_stage = 1.0 - - if(1) - if(istype(M, /mob/living/carbon/slime)) - if(M.stat == 2) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M.name] is having its silky innards cut apart with [src] by [user].", 1) - M << "\red [user] begins to cut apart your innards with [src]!" - user << "\red You cut [M]'s silky innards apart with [src]!" - M:brain_op_stage = 2.0 - return - if(2.0) - if(istype(M, /mob/living/carbon/slime)) - if(M.stat == 2) - var/mob/living/carbon/slime/slime = M - if(slime.cores > 0) - if(istype(M, /mob/living/carbon/slime)) - user << "\red You attempt to remove [M]'s core, but [src] is ineffective!" - return - - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is having his connections to the brain delicately severed with [src] by [user].", 1) - M << "\red [user] begins to cut open your head with [src]!" - user << "\red You cut [M]'s head open with [src]!" - else - user.visible_message( \ - "\red [user] begin to delicately remove the connections to his brain with [src]!", \ - "\red You begin to cut open your head with [src]!" \ - ) - if(M == user && prob(25)) - user << "\red You nick an artery!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - if(affecting.take_damage(75)) - M:UpdateDamageIcon() - else - M.take_organ_damage(75) - - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - affecting.take_damage(7) - else - M.take_organ_damage(7) - - M.updatehealth() - M:brain_op_stage = 3.0 - else - ..() - return - - else if(user.zone_sel.selecting == "eyes") - user << "\blue So far so good." - - var/mob/living/carbon/human/H = M - if(istype(H) && ( \ - (H.head && H.head.flags & HEADCOVERSEYES) || \ - (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || \ - (H.glasses && H.glasses.flags & GLASSESCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - var/mob/living/carbon/monkey/Mo = M - if(istype(Mo) && ( \ - (Mo.wear_mask && Mo.wear_mask.flags & MASKCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - if(istype(M, /mob/living/carbon/alien) || istype(M, /mob/living/carbon/slime))//Aliens don't have eyes./N - user << "\red You cannot locate any eyes on this creature!" - return - - switch(M:eye_op_stage) - if(0.0) - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] is beginning to have his eyes incised with [src] by [user].", 1) - M << "\red [user] begins to cut open your eyes with [src]!" - user << "\red You make an incision around [M]'s eyes with [src]!" - else - user.visible_message( \ - "\red [user] begins to cut around his eyes with [src]!", \ - "\red You begin to cut open your eyes with [src]!" \ - ) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - if(affecting.take_damage(15)) - M:UpdateDamageIcon() - else - M.take_organ_damage(15) - - user << "\blue So far so good before." - M.updatehealth() - M:eye_op_stage = 1.0 - user << "\blue So far so good after." - - else if(user.zone_sel.selecting == "chest") - switch(M:alien_op_stage) - if(0.0) - var/mob/living/carbon/human/H = M - if(!istype(H)) - return ..() - - if(H.wear_suit || H.w_uniform) - user << "\red You're going to need to remove that suit/jumpsuit first." - return - - user.visible_message("\red [user] begins to slice open [M]'s chest.", "\red You begin to slice open [M]'s chest.") - - spawn(rand(20,50)) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("chest") - if(affecting.take_damage(15)) - M:UpdateDamageIcon() - else - M.take_organ_damage(15) - - M:alien_op_stage = 1.0 - user << "\blue So far so good." - - else - return ..() -/* wat - else if((!(user.zone_sel.selecting == "head")) || (!(user.zone_sel.selecting == "groin")) || (!(istype(M, /mob/living/carbon/human)))) - return ..()*/ - return -*/ - /* * Researchable Scalpels */ @@ -667,157 +146,6 @@ LOOK FOR SURGERY.DM*/ sharp = 1 edge = 1 -/* -/obj/item/weapon/circular_saw/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) - return ..() - - if((CLUMSY in user.mutations) && prob(50)) - M = user - return eyestab(M,user) - - if(!((locate(/obj/machinery/optable, M.loc) && M.resting) || (locate(/obj/structure/table/, M.loc) && M.lying && prob(50)))) - return ..() - - src.add_fingerprint(user) - - if(user.zone_sel.selecting == "head" || istype(M, /mob/living/carbon/slime)) - - var/mob/living/carbon/human/H = M - if(istype(H) && ( \ - (H.head && H.head.flags & HEADCOVERSEYES) || \ - (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || \ - (H.glasses && H.glasses.flags & GLASSESCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - var/mob/living/carbon/monkey/Mo = M - if(istype(Mo) && ( \ - (Mo.wear_mask && Mo.wear_mask.flags & MASKCOVERSEYES) \ - )) - user << "\red You're going to need to remove that mask/helmet/glasses first." - return - - switch(M:brain_op_stage) - if(1.0) - if(istype(M, /mob/living/carbon/slime)) - return - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] has his skull sawed open with [src] by [user].", 1) - M << "\red [user] begins to saw open your head with [src]!" - user << "\red You saw [M]'s head open with [src]!" - else - user.visible_message( \ - "\red [user] saws open his skull with [src]!", \ - "\red You begin to saw open your head with [src]!" \ - ) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - if(affecting.take_damage(40)) - M:UpdateDamageIcon() - M.updatehealth() - else - M.take_organ_damage(40) - - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("head") - affecting.take_damage(7) - else - M.take_organ_damage(7) - - M.updatehealth() - M:brain_op_stage = 2.0 - - if(2.0) - if(istype(M, /mob/living/carbon/slime)) - if(M.stat == 2) - var/mob/living/carbon/slime/slime = M - if(slime.cores > 0) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M.name] is having one of its cores sawed out with [src] by [user].", 1) - - slime.cores-- - M << "\red [user] begins to remove one of your cores with [src]! ([slime.cores] cores remaining)" - user << "\red You cut one of [M]'s cores out with [src]! ([slime.cores] cores remaining)" - - new slime.coretype(M.loc) - - if(slime.cores <= 0) - M.icon_state = "[slime.colour] baby slime dead-nocore" - - return - - if(3.0) - /*if(M.mind && M.mind.changeling) - user << "\red The neural tissue regrows before your eyes as you cut it." - return*/ - - if(M != user) - for(var/mob/O in (viewers(M) - user - M)) - O.show_message("\red [M] has his spine's connection to the brain severed with [src] by [user].", 1) - M << "\red [user] severs your brain's connection to the spine with [src]!" - user << "\red You sever [M]'s brain's connection to the spine with [src]!" - else - user.visible_message( \ - "\red [user] severs his brain's connection to the spine with [src]!", \ - "\red You sever your brain's connection to the spine with [src]!" \ - ) - - user.attack_log += "\[[time_stamp()]\] Debrained [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" - M.attack_log += "\[[time_stamp()]\] Debrained by [user.name] ([user.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])" - - log_attack("[user.name] ([user.ckey]) debrained [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])") - - - var/obj/item/organ/brain/B = new(M.loc) - B.transfer_identity(M) - - M:brain_op_stage = 4.0 - M.death()//You want them to die after the brain was transferred, so not to trigger client death() twice. - - else - ..() - return - - else if(user.zone_sel.selecting == "chest") - switch(M:alien_op_stage) - if(1.0) - var/mob/living/carbon/human/H = M - if(!istype(H)) - return ..() - - if(H.wear_suit || H.w_uniform) - user << "\red You're going to need to remove that suit/jumpsuit first." - return - - user.visible_message("\red [user] begins to slice through the bone of [M]'s chest.", "\red You begin to slice through the bone of [M]'s chest.") - - spawn(20 + rand(0,50)) - if(M == user && prob(25)) - user << "\red You mess up!" - if(istype(M, /mob/living/carbon/human)) - var/datum/organ/external/affecting = M:get_organ("chest") - if(affecting.take_damage(15)) - M:UpdateDamageIcon() - else - M.take_organ_damage(15) - - M:alien_op_stage = 2.0 - user << "\blue So far so good." - - else - return ..() -/* - else if((!(user.zone_sel.selecting == "head")) || (!(user.zone_sel.selecting == "groin")) || (!(istype(M, /mob/living/carbon/human)))) - return ..() -*/ - return -*/ - //misc, formerly from code/defines/weapons.dm /obj/item/weapon/bonegel name = "bone gel" diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index af06f192bc3..a79860522da 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -1,11 +1,46 @@ /obj/structure icon = 'icons/obj/structures.dmi' var/climbable + var/breakable + var/parts + +/obj/structure/proc/destroy() + if(parts) + new parts(loc) + density = 0 + del(src) + +/obj/structure/attack_hand(mob/user) + if(breakable) + if(HULK in user.mutations) + user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) + visible_message("[user] smashes the [src] apart!") + destroy() + else if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(user)) + visible_message("[H] slices [src] apart!") + destroy() + +/obj/structure/attack_animal(mob/living/user) + if(breakable) + if(user.wall_smash) + visible_message("[user] smashes [src] apart!") + destroy() + +/obj/structure/attack_paw(mob/user) + if(breakable) attack_hand(user) /obj/structure/blob_act() if(prob(50)) del(src) +/obj/structure/meteorhit(obj/O as obj) + destroy(src) + +/obj/structure/attack_tk() + return + /obj/structure/ex_act(severity) switch(severity) if(1.0) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 0a302184006..637b7627067 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -172,7 +172,7 @@ return -/obj/structure/closet/attack_animal(mob/living/simple_animal/user as mob) +/obj/structure/closet/attack_animal(mob/living/user as mob) if(user.wall_smash) visible_message("\red [user] destroys the [src]. ") for(var/atom/movable/A as mob|obj in src) diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index cfcc3c1176d..3ba3c79a372 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -10,7 +10,7 @@ /obj/structure/extinguisher_cabinet/attackby(obj/item/O, mob/user) - if(isrobot(user) || isalien(user)) + if(isrobot(user)) return if(istype(O, /obj/item/weapon/extinguisher)) if(!has_extinguisher && opened) @@ -26,7 +26,7 @@ /obj/structure/extinguisher_cabinet/attack_hand(mob/user) - if(isrobot(user) || isalien(user)) + if(isrobot(user)) return if (hasorgans(user)) var/datum/organ/external/temp = user:organs_by_name["r_hand"] diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 630ed6687c8..e1f0804c0e9 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -31,32 +31,34 @@ attack_hand(user) /obj/structure/grille/attack_hand(mob/user as mob) + playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) - user.visible_message("[user] kicks [src].", \ + + var/damage_dealt + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(H)) + damage_dealt = 5 + user.visible_message("[user] mangles [src].", \ + "You mangle [src].", \ + "You hear twisting metal.") + + if(!damage_dealt) + user.visible_message("[user] kicks [src].", \ "You kick [src].", \ "You hear twisting metal.") if(shock(user, 70)) return + if(HULK in user.mutations) - health -= 5 + damage_dealt += 5 else - health -= 1 + damage_dealt += 1 + + health -= damage_dealt healthcheck() -/obj/structure/grille/attack_alien(mob/user as mob) - if(istype(user, /mob/living/carbon/alien/larva)) return - - playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) - user.visible_message("[user] mangles [src].", \ - "You mangle [src].", \ - "You hear twisting metal.") - - if(!shock(user, 70)) - health -= 5 - healthcheck() - return - /obj/structure/grille/attack_slime(mob/user as mob) var/mob/living/carbon/slime/S = user if (!S.is_adult) @@ -199,6 +201,7 @@ // returns 1 if shocked, 0 otherwise /obj/structure/grille/proc/shock(mob/user as mob, prb) + if(!anchored || destroyed) // anchored/destroyed grilles are never connected return 0 if(!prob(prb)) diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index cd9dfd3e8ae..8b586c94619 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -83,7 +83,7 @@ return - proc/attack_generic(mob/user as mob, damage = 0) //used by attack_alien, attack_animal, and attack_slime + proc/attack_generic(mob/user as mob, damage = 0) //used by attack_animal and attack_slime health -= damage if(health <= 0) user.visible_message("[user] tears open [src]!") @@ -91,10 +91,6 @@ else //for nicer text~ user.visible_message("[user] tears at [src]!") - attack_alien(mob/user as mob) - if(islarva(user)) return - attack_generic(user, 15) - attack_animal(mob/user as mob) if(!isanimal(user)) return var/mob/living/simple_animal/M = user diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 4902b6a631d..aa07d1621af 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -256,7 +256,9 @@ var/close_delay = 100 TryToSwitchState(atom/user) - if(isalien(user)) + + var/mob/living/carbon/M = user + if(istype(M) && locate(/datum/organ/internal/xenos/hivenode) in M.internal_organs) return ..() Open() diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 59771219737..f9b45a60754 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -10,11 +10,23 @@ /obj/structure/mirror/attack_hand(mob/user as mob) + if(shattered) return if(ishuman(user)) var/mob/living/carbon/human/H = user + if(H.a_intent == "hurt") + if(shattered) + playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1) + return + if(prob(30) || H.species.can_shred(H)) + user.visible_message("[user] smashes [src]!") + shatter() + else + user.visible_message("[user] hits [src] and bounces off!") + return + var/userloc = H.loc //see code/modules/mob/new_player/preferences.dm at approx line 545 for comments! @@ -83,16 +95,6 @@ visible_message("[user] hits [src] with [I]!") playsound(src.loc, 'sound/effects/Glasshit.ogg', 70, 1) - -/obj/structure/mirror/attack_alien(mob/user as mob) - if(islarva(user)) return - if(shattered) - playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1) - return - user.visible_message("[user] smashes [src]!") - shatter() - - /obj/structure/mirror/attack_animal(mob/user as mob) if(!isanimal(user)) return var/mob/living/simple_animal/M = user diff --git a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm index a45e2436b80..76ac4b18aca 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm @@ -30,15 +30,20 @@ return /obj/structure/stool/bed/nest/buckle_mob(mob/M as mob, mob/user as mob) + if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.restrained() || usr.stat || M.buckled || istype(user, /mob/living/silicon/pai) ) return - if(istype(M,/mob/living/carbon/alien)) - return - if(!istype(user,/mob/living/carbon/alien/humanoid)) + unbuckle() + + var/mob/living/carbon/xenos = user + var/mob/living/carbon/victim = M + + if(istype(victim) && locate(/datum/organ/internal/xenos/hivenode) in victim.internal_organs) return - unbuckle() + if(istype(xenos) && !(locate(/datum/organ/internal/xenos/hivenode) in xenos.internal_organs)) + return if(M == usr) return diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 2bda55b93fd..d6e461b4c1e 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -20,8 +20,9 @@ layer = 2.8 throwpass = 1 //You can throw objects over this, despite it's density.") climbable = 1 + breakable = 1 + parts = /obj/item/weapon/table_parts - var/parts = /obj/item/weapon/table_parts var/flipped = 0 var/health = 100 @@ -43,16 +44,6 @@ update_adjacent() ..() -/obj/structure/table/proc/destroy() - new parts(loc) - density = 0 - del(src) - -/obj/structure/rack/proc/destroy() - new parts(loc) - density = 0 - del(src) - /obj/structure/table/update_icon() spawn(2) //So it properly updates when deleting @@ -247,49 +238,6 @@ else dir = 2 -/obj/structure/table/ex_act(severity) - switch(severity) - if(1.0) - del(src) - return - if(2.0) - if (prob(50)) - del(src) - return - if(3.0) - if (prob(25)) - destroy() - else - return - - -/obj/structure/table/blob_act() - if(prob(75)) - destroy() - -/obj/structure/table/attack_paw(mob/user) - if(HULK in user.mutations) - user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - visible_message("[user] smashes the [src] apart!") - destroy() - - -/obj/structure/table/attack_alien(mob/user) - visible_message("[user] slices [src] apart!") - -/obj/structure/table/attack_animal(mob/living/simple_animal/user) - if(user.wall_smash) - visible_message("[user] smashes [src] apart!") - destroy() - - - -/obj/structure/table/attack_hand(mob/user) - if(HULK in user.mutations) - visible_message("[user] smashes [src] apart!") - user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - destroy() - /obj/structure/table/attack_tk() // no telehulk sorry return @@ -576,29 +524,9 @@ flags = FPRINT anchored = 1.0 throwpass = 1 //You can throw objects over this, despite it's density. - var/parts = /obj/item/weapon/rack_parts - -/obj/structure/rack/ex_act(severity) - switch(severity) - if(1.0) - del(src) - if(2.0) - del(src) - if(prob(50)) - new /obj/item/weapon/rack_parts(src.loc) - if(3.0) - if(prob(25)) - del(src) - new /obj/item/weapon/rack_parts(src.loc) - -/obj/structure/rack/blob_act() - if(prob(75)) - del(src) - return - else if(prob(50)) - new /obj/item/weapon/rack_parts(src.loc) - del(src) - return + breakable = 1 + climbable = 1 + parts = /obj/item/weapon/rack_parts /obj/structure/rack/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(air_group || (height==0)) return 1 @@ -629,32 +557,4 @@ return user.drop_item() if(W && W.loc) W.loc = src.loc - return - -/obj/structure/rack/meteorhit(obj/O as obj) - del(src) - - -/obj/structure/table/attack_hand(mob/user) - if(HULK in user.mutations) - visible_message("[user] smashes [src] apart!") - user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - destroy() - -/obj/structure/rack/attack_paw(mob/user) - if(HULK in user.mutations) - user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - visible_message("[user] smashes [src] apart!") - destroy() - -/obj/structure/rack/attack_alien(mob/user) - visible_message("[user] slices [src] apart!") - destroy() - -/obj/structure/rack/attack_animal(mob/living/simple_animal/user) - if(user.wall_smash) - visible_message("[user] smashes [src] apart!") - destroy() - -/obj/structure/rack/attack_tk() // no telehulk sorry return \ No newline at end of file diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 7052bf5a987..cad2907ac77 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -114,6 +114,14 @@ new /obj/item/weapon/shard(loc) if(reinf) new /obj/item/stack/rods(loc) del(src) + else if (istype(usr,/mob/living/carbon/human)) + + var/mob/living/carbon/human/H = usr + + if(H.species.can_shred(H)) + attack_generic(H,25) + return + else if (usr.a_intent == "hurt") playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1) usr.visible_message("\red [usr.name] bangs against the [src.name]!", \ @@ -131,7 +139,7 @@ return attack_hand(user) -/obj/structure/window/proc/attack_generic(mob/user as mob, damage = 0) //used by attack_alien, attack_animal, and attack_slime +/obj/structure/window/proc/attack_generic(mob/user as mob, damage = 0) //used by attack_animal and attack_slime health -= damage if(health <= 0) user.visible_message("[user] smashes through [src]!") @@ -142,11 +150,6 @@ user.visible_message("[user] smashes into [src]!") playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) - -/obj/structure/window/attack_alien(mob/user as mob) - if(islarva(user)) return - attack_generic(user, 15) - /obj/structure/window/attack_animal(mob/user as mob) if(!isanimal(user)) return var/mob/living/simple_animal/M = user diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index d264f8375d9..b654aeadaff 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -242,7 +242,7 @@ return src.attack_hand(user) -/turf/simulated/wall/attack_animal(mob/living/simple_animal/M as mob) +/turf/simulated/wall/attack_animal(mob/living/M as mob) if(M.wall_smash) if (istype(src, /turf/simulated/wall/r_wall) && !rotting) M << text("\blue This wall is far too strong for you to destroy.") diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index ee37b5eb9c8..82a81e5af74 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -191,27 +191,6 @@ else src << "Aborting suicide attempt." -/mob/living/carbon/alien/humanoid/verb/suicide() - set hidden = 1 - - if (stat == 2) - src << "You're already dead!" - return - - if (suiciding) - src << "You're already committing suicide! Be patient!" - return - - var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No") - - if(confirm == "Yes") - suiciding = 1 - viewers(src) << "\red [src] is thrashing wildly! It looks like \he's trying to commit suicide." - //put em at -175 - adjustOxyLoss(max(175 - getFireLoss() - getBruteLoss() - getOxyLoss(), 0)) - updatehealth() - - /mob/living/carbon/slime/verb/suicide() set hidden = 1 if (stat == 2) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 12b5bf77898..46b1beef780 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -141,10 +141,6 @@ var/global/floorIsLava = 0 body += {"

Rudimentary transformation:
These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

Observer | - \[ Alien: Drone, - Hunter, - Queen, - Sentinel, Larva \] Human \[ slime: Baby, diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 0a83ce49030..a5ccbb91002 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -233,11 +233,8 @@ M_job = "slime" else if(ismonkey(M)) M_job = "Monkey" - else if(isalien(M)) //aliens - if(islarva(M)) - M_job = "Alien larva" - else - M_job = "Alien" + else if(isalien(M)) + M_job = "Alien" else M_job = "Carbon-based" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 1493751ab10..d0cc41da62f 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -284,10 +284,6 @@ switch(href_list["simplemake"]) if("observer") M.change_mob_type( /mob/dead/observer , null, null, delmob ) - if("drone") M.change_mob_type( /mob/living/carbon/alien/humanoid/drone , null, null, delmob ) - if("hunter") M.change_mob_type( /mob/living/carbon/alien/humanoid/hunter , null, null, delmob ) - if("queen") M.change_mob_type( /mob/living/carbon/alien/humanoid/queen , null, null, delmob ) - if("sentinel") M.change_mob_type( /mob/living/carbon/alien/humanoid/sentinel , null, null, delmob ) if("larva") M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob ) if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob ) if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob ) @@ -2205,11 +2201,6 @@ if(aliens_allowed) new /datum/event/alien_infestation message_admins("[key_name_admin(usr)] has spawned aliens", 1) - if("alien_silent") //replaces the spawn_xeno verb - feedback_inc("admin_secrets_fun_used",1) - feedback_add_details("admin_secrets_fun_used","ALS") - if(aliens_allowed) - create_xeno() if("spiders") feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","SL") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index ce2a2800bbc..a0e9fd9878c 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -225,38 +225,6 @@ proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0) IonStorm(0) feedback_add_details("admin_verb","ION") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -//I use this proc for respawn character too. /N -/proc/create_xeno(ckey) - if(!ckey) - var/list/candidates = list() - for(var/mob/M in player_list) - if(M.stat != DEAD) continue //we are not dead! - if(!M.client.prefs.be_special & BE_ALIEN) continue //we don't want to be an alium - if(M.client.is_afk()) continue //we are afk - if(M.mind && M.mind.current && M.mind.current.stat != DEAD) continue //we have a live body we are tied to - candidates += M.ckey - if(candidates.len) - ckey = input("Pick the player you want to respawn as a xeno.", "Suitable Candidates") as null|anything in candidates - else - usr << "Error: create_xeno(): no suitable candidates." - if(!istext(ckey)) return 0 - - var/alien_caste = input(usr, "Please choose which caste to spawn.","Pick a caste",null) as null|anything in list("Queen","Hunter","Sentinel","Drone","Larva") - var/obj/effect/landmark/spawn_here = xeno_spawn.len ? pick(xeno_spawn) : pick(latejoin) - var/mob/living/carbon/alien/new_xeno - switch(alien_caste) - if("Queen") new_xeno = new /mob/living/carbon/alien/humanoid/queen(spawn_here) - if("Hunter") new_xeno = new /mob/living/carbon/alien/humanoid/hunter(spawn_here) - if("Sentinel") new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(spawn_here) - if("Drone") new_xeno = new /mob/living/carbon/alien/humanoid/drone(spawn_here) - if("Larva") new_xeno = new /mob/living/carbon/alien/larva(spawn_here) - else return 0 - - new_xeno.ckey = ckey - message_admins("\blue [key_name_admin(usr)] has spawned [ckey] as a filthy xeno [alien_caste].", 1) - return 1 - /* Allow admins to set players to be able to respawn/bypass 30 min wait, without the admin having to edit variables directly Ccomp's first proc. @@ -376,9 +344,6 @@ Ccomp's first proc. log_admin("[key_name(usr)] has [action] on joining the round if they use AntagHUD") message_admins("Admin [key_name_admin(usr)] has [action] on joining the round if they use AntagHUD", 1) - - - /* If a guy was gibbed and you want to revive him, this is a good way to do so. Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one. @@ -406,32 +371,9 @@ Traitors and the like can also be revived with the previous role mostly intact. return if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something - //Check if they were an alien - if(G_found.mind.assigned_role=="Alien") - if(alert("This character appears to have been an alien. Would you like to respawn them as such?",,"Yes","No")=="Yes") - var/turf/T - if(xeno_spawn.len) T = pick(xeno_spawn) - else T = pick(latejoin) - - var/mob/living/carbon/alien/new_xeno - switch(G_found.mind.special_role)//If they have a mind, we can determine which caste they were. - if("Hunter") new_xeno = new /mob/living/carbon/alien/humanoid/hunter(T) - if("Sentinel") new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(T) - if("Drone") new_xeno = new /mob/living/carbon/alien/humanoid/drone(T) - if("Queen") new_xeno = new /mob/living/carbon/alien/humanoid/queen(T) - else//If we don't know what special role they have, for whatever reason, or they're a larva. - create_xeno(G_found.ckey) - return - - //Now to give them their mind back. - G_found.mind.transfer_to(new_xeno) //be careful when doing stuff like this! I've already checked the mind isn't in use - new_xeno.key = G_found.key - new_xeno << "You have been fully respawned. Enjoy the game." - message_admins("\blue [key_name_admin(usr)] has respawned [new_xeno.key] as a filthy xeno.", 1) - return //all done. The ghost is auto-deleted //check if they were a monkey - else if(findtext(G_found.real_name,"monkey")) + if(findtext(G_found.real_name,"monkey")) if(alert("This character appears to have been a monkey. Would you like to respawn them as such?",,"Yes","No")=="Yes") var/mob/living/carbon/monkey/new_monkey = new(pick(latejoin)) G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use @@ -440,8 +382,7 @@ Traitors and the like can also be revived with the previous role mostly intact. message_admins("\blue [key_name_admin(usr)] has respawned [new_monkey.key] as a filthy xeno.", 1) return //all done. The ghost is auto-deleted - - //Ok, it's not a xeno or a monkey. So, spawn a human. + //Ok, it's not a monkey. So, spawn a human. var/mob/living/carbon/human/new_character = new(pick(latejoin))//The mob being spawned. var/datum/data/record/record_found //Referenced to later to either randomize or not randomize the character. diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 193d63f96c5..119076e6a87 100755 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1580,6 +1580,9 @@ datum/preferences var/datum/organ/internal/I = character.internal_organs_by_name[name] var/status = organ_data[name] + if(!I || !O) + continue + if(status == "amputated") O.amputated = 1 O.status |= ORGAN_DESTROYED diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index 51a8fb499ea..7b6710f6c43 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -1499,7 +1499,7 @@ proc/populate_seed_list() seed_noun = "nodes" display_name = "replicant pods" packet_icon = "seed-replicapod" - products = list(/mob/living/carbon/monkey/diona) + products = list(/mob/living/carbon/alien/diona) plant_icon = "replicapod" product_requires_player = 1 immutable = 1 diff --git a/code/modules/hydroponics/seed_mobs.dm b/code/modules/hydroponics/seed_mobs.dm index 0bb301298a5..d80247abd67 100644 --- a/code/modules/hydroponics/seed_mobs.dm +++ b/code/modules/hydroponics/seed_mobs.dm @@ -69,7 +69,7 @@ host << "\green You awaken slowly, stirring into sluggish motion as the air caresses you." // This is a hack, replace with some kind of species blurb proc. - if(istype(host,/mob/living/carbon/monkey/diona)) + if(istype(host,/mob/living/carbon/alien/diona)) host << "You are [host], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders." host << "Too much darkness will send you into shock and starve you, but light will help you heal." diff --git a/code/modules/mob/abilities.dm b/code/modules/mob/abilities.dm deleted file mode 100644 index e5e2be9af0b..00000000000 --- a/code/modules/mob/abilities.dm +++ /dev/null @@ -1,35 +0,0 @@ -/* -Creature-level abilities. -*/ - -/var/global/list/ability_verbs = list( ) - -/* - - Example ability: - -/client/proc/test_ability() - - set category = "Ability" - set name = "Test ability" - set desc = "An ability for testing." - - // Check if the client has a mob and if the mob is valid and alive. - if(!mob || !istype(mob,/mob/living) || mob.stat) - src << "\red You must be corporeal and alive to do that." - return 0 - - //Handcuff check. - if(mob.restrained()) - src << "\red You cannot do this while restrained." - return 0 - - if(istype(mob,/mob/living/carbon)) - var/mob/living/carbon/M = mob - if(M.handcuffed) - src << "\red You cannot do this while cuffed." - return 0 - - src << "\blue You perform an ability." - -*/ \ No newline at end of file diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index 797715c33e2..dc1ca257276 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -56,6 +56,8 @@ timeofdeath = world.time + var/tod = worldtime2text() //weasellos time of death patch + if(mind) mind.store_memory("Time of death: [tod]", 0) living_mob_list -= src dead_mob_list += src return ..(gibbed) diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index d54e1a90e7c..b0ffe74fe63 100755 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -12,6 +12,23 @@ var/flags = 0 // Various language flags. var/native // If set, non-native speakers will have trouble speaking. +/datum/language/proc/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + log_say("[key_name(speaker)] : ([name]) [message]") + + for(var/mob/player in player_list) + + var/understood = 0 + + if(istype(player,/mob/dead)) + understood = 1 + else if(src in player.languages) + understood = 1 + + if(understood) + if(!speaker_mask) speaker_mask = speaker.name + player << "[name], [speaker_mask] [speech_verb], \"[message]\"" + /datum/language/unathi name = "Sinta'unathi" desc = "The common language of Moghes, composed of sibilant hisses and rattles. Spoken natively by Unathi." @@ -74,6 +91,105 @@ colour = "rough" key = "3" +/datum/language/xenos + name = "Hivemind" + desc = "Xenomorphs have the strange ability to commune over a psychic hivemind." + speech_verb = "hisses" + colour = "alien" + key = "a" + flags = RESTRICTED | HIVEMIND + +/datum/language/ling + name = "Changeling" + desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance." + speech_verb = "says" + colour = "changeling" + key = "g" + flags = RESTRICTED | HIVEMIND + +/datum/language/ling/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + if(speaker.mind && speaker.mind.changeling) + ..(speaker,message,speaker.mind.changeling.changelingID) + else + ..(speaker,message) + +/datum/language/corticalborer + name = "Cortical Link" + desc = "Cortical borers possess a strange between their tiny minds." + speech_verb = "sings" + colour = "alien" + key = "x" + flags = RESTRICTED | HIVEMIND + +/datum/language/corticalborer/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + var/mob/living/simple_animal/borer/B + + if(istype(speaker,/mob/living/carbon)) + var/mob/living/carbon/M = speaker + B = M.has_brain_worms() + else if(istype(speaker,/mob/living/simple_animal/borer)) + B = speaker + + if(B) + speaker_mask = B.truename + ..(speaker,message,speaker_mask) + +/datum/language/binary + name = "Robot Talk" + desc = "Most human stations support free-use communications protocols and routing hubs for synthetic use." + speech_verb = "transmits" + colour = "say_quote" + key = "b" + flags = RESTRICTED | HIVEMIND + var/drone_only + +/datum/language/binary/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + if(!speaker.binarycheck()) + return + + if (!message) + return + + var/message_start = "[name], [speaker.name]" + var/message_body = "[speaker.say_quote(message)], \"[message]\"" + + for (var/mob/M in dead_mob_list) + if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping + M.show_message("[message_start] [message_body]", 2) + + world << "Got through checks, transmitting." + + for (var/mob/living/S in living_mob_list) + + if(drone_only && !istype(S,/mob/living/silicon/robot/drone)) + continue + else if(istype(S , /mob/living/silicon/ai)) + message_start = "[name], [speaker.name]" + else if (!S.binarycheck()) + continue + + S.show_message("[message_start] [message_body]", 2) + + var/list/listening = hearers(1, src) + listening -= src + + for (var/mob/living/M in listening) + if(istype(M, /mob/living/silicon) || M.binarycheck()) + continue + M.show_message("synthesised voice beeps, \"beep beep beep\"",2) + +/datum/language/binary/drone + name = "Drone Talk" + desc = "A heavily encoded damage control coordination stream." + speech_verb = "transmits" + colour = "say_quote" + key = "d" + flags = RESTRICTED | HIVEMIND + drone_only = 1 + // Language handling. /mob/proc/add_language(var/language) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 214c091c3e8..0cb28d10867 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -1,210 +1,90 @@ -#define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point -#define HEAT_DAMAGE_LEVEL_2 4 //Amount of damage applied when your body temperature passes the 400K point -#define HEAT_DAMAGE_LEVEL_3 8 //Amount of damage applied when your body temperature passes the 1000K point - /mob/living/carbon/alien + name = "alien" - voice_name = "alien" - speak_emote = list("hisses") + desc = "What IS that?" icon = 'icons/mob/alien.dmi' + icon_state = "alien" + pass_flags = PASSTABLE + melee_damage_lower = 1 + melee_damage_upper = 3 + attacktext = "bites" + attack_sound = null + friendly = "nuzzles" + wall_smash = 0 + + var/adult_form + var/dead_icon + var/amount_grown = 0 + var/max_grown = 10 + var/time_of_birth + var/co2overloadtime = null + var/temperature_resistance = T0C+75 + var/language + +/mob/living/carbon/alien/New() + + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + + var/datum/reagents/R = new/datum/reagents(100) + reagents = R + R.my_atom = src + + name = "[initial(name)] ([rand(1, 1000)])" + real_name = name + regenerate_icons() + + if(language) + add_language(language) + gender = NEUTER - dna = null - - var/storedPlasma = 250 - var/max_plasma = 500 - - alien_talk_understand = 1 - - var/obj/item/weapon/card/id/wear_id = null // Fix for station bounced radios -- Skie - var/has_fine_manipulation = 0 - - var/move_delay_add = 0 // movement delay to add - - status_flags = CANPARALYSE|CANPUSH - var/heal_rate = 1 - var/plasma_rate = 5 - - var/oxygen_alert = 0 - var/phoron_alert = 0 - var/fire_alert = 0 - - var/heat_protection = 0.5 - -/mob/living/carbon/alien/adjustToxLoss(amount) - storedPlasma = min(max(storedPlasma + amount,0),max_plasma) //upper limit of max_plasma, lower limit of 0 - return - -/mob/living/carbon/alien/adjustFireLoss(amount) // Weak to Fire - if(amount > 0) - ..(amount * 2) - else - ..(amount) - return - -/mob/living/carbon/alien/proc/getPlasma() - return storedPlasma - -/mob/living/carbon/alien/eyecheck() - return 2 - -/mob/living/carbon/alien/updatehealth() - if(status_flags & GODMODE) - health = maxHealth - stat = CONSCIOUS - else - //oxyloss is only used for suicide - //toxloss isn't used for aliens, its actually used as alien powers!! - health = maxHealth - getOxyLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - -/mob/living/carbon/alien/proc/handle_environment(var/datum/gas_mixture/environment) - - //If there are alien weeds on the ground then heal if needed or give some plasma - if(locate(/obj/effect/alien/weeds) in loc) - if(health >= maxHealth - getCloneLoss()) - adjustToxLoss(plasma_rate) - else - adjustBruteLoss(-heal_rate) - adjustFireLoss(-heal_rate) - adjustOxyLoss(-heal_rate) - - if(!environment) - return - var/loc_temp = T0C - if(istype(loc, /obj/mecha)) - var/obj/mecha/M = loc - loc_temp = M.return_temperature() - else if(istype(get_turf(src), /turf/space)) - var/turf/heat_turf = get_turf(src) - loc_temp = heat_turf.temperature - else if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) - loc_temp = loc:air_contents.temperature - else - loc_temp = environment.temperature - - //world << "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Fire protection: [heat_protection] - Location: [loc] - src: [src]" - - // Aliens are now weak to fire. - - //After then, it reacts to the surrounding atmosphere based on your thermal protection - if(loc_temp > bodytemperature) - //Place is hotter than we are - var/thermal_protection = heat_protection //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 += (1-thermal_protection) * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR) - else - bodytemperature += 1 * ((loc_temp - bodytemperature) / BODYTEMP_HEAT_DIVISOR) - // bodytemperature -= max((loc_temp - bodytemperature / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM) - - // +/- 50 degrees from 310.15K is the 'safe' zone, where no damage is dealt. - if(bodytemperature > 360.15) - //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 1000) - apply_damage(HEAT_DAMAGE_LEVEL_2, BURN) - fire_alert = max(fire_alert, 2) - if(1000 to INFINITY) - apply_damage(HEAT_DAMAGE_LEVEL_3, BURN) - fire_alert = max(fire_alert, 2) - return - -/mob/living/carbon/alien/proc/handle_mutations_and_radiation() - - if(getFireLoss()) - if((COLD_RESISTANCE in mutations) || prob(5)) - adjustFireLoss(-1) - - // Aliens love radiation nom nom nom - if (radiation) - if (radiation > 100) - radiation = 100 - - if (radiation < 0) - radiation = 0 - - switch(radiation) - if(1 to 49) - radiation-- - if(prob(25)) - adjustToxLoss(1) - - if(50 to 74) - radiation -= 2 - adjustToxLoss(1) - if(prob(5)) - radiation -= 5 - - if(75 to 100) - radiation -= 3 - adjustToxLoss(3) - -/mob/living/carbon/alien/IsAdvancedToolUser() - return has_fine_manipulation - -/mob/living/carbon/alien/Process_Spaceslipping() - return 0 // Don't slip in space. - -/mob/living/carbon/alien/Stat() - - statpanel("Status") - stat(null, "Intent: [a_intent]") - stat(null, "Move Mode: [m_intent]") ..() - if (client.statpanel == "Status") - stat(null, "Plasma Stored: [getPlasma()]/[max_plasma]") - - if(emergency_shuttle) - var/eta_status = emergency_shuttle.get_status_panel_eta() - if(eta_status) - stat(null, eta_status) - -/mob/living/carbon/alien/Stun(amount) - if(status_flags & CANSTUN) - stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun - else - // add some movement delay - move_delay_add = min(move_delay_add + round(amount / 2), 10) // a maximum delay of 10 +/mob/living/carbon/alien/u_equip(obj/item/W as obj) return -/mob/living/carbon/alien/getDNA() - return null +//This is fine, works the same as a human +/mob/living/carbon/alien/Bump(atom/movable/AM as mob|obj, yes) -/mob/living/carbon/alien/setDNA() + spawn( 0 ) + if ((!( yes ) || now_pushing)) + return + now_pushing = 1 + if(ismob(AM)) + var/mob/tmob = AM + if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations)) + if(prob(70)) + src << "\red You fail to push [tmob]'s fat ass out of the way." + now_pushing = 0 + return + if(!(tmob.status_flags & CANPUSH)) + now_pushing = 0 + return + tmob.LAssailant = src + + now_pushing = 0 + ..() + if (!( istype(AM, /atom/movable) )) + return + if (!( now_pushing )) + now_pushing = 1 + if (!( AM.anchored )) + var/t = get_dir(src, AM) + step(AM, t) + now_pushing = null + return return -/*---------------------------------------- -Proc: AddInfectionImages() -Des: Gives the client of the alien an image on each infected mob. -----------------------------------------*/ -/mob/living/carbon/alien/proc/AddInfectionImages() - if (client) - for (var/mob/living/C in mob_list) - if(C.status_flags & XENO_HOST) - var/obj/item/alien_embryo/A = locate() in C - var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]") - client.images += I - return +/mob/living/carbon/alien/Stat() + ..() + stat(null, "Progress: [amount_grown]/[max_grown]") - -/*---------------------------------------- -Proc: RemoveInfectionImages() -Des: Removes all infected images from the alien. -----------------------------------------*/ -/mob/living/carbon/alien/proc/RemoveInfectionImages() - if (client) - for(var/image/I in client.images) - if(dd_hasprefix_case(I.icon_state, "infected")) - del(I) - return - -/mob/living/carbon/alien/has_eyes() +/mob/living/carbon/alien/restrained() return 0 -#undef HEAT_DAMAGE_LEVEL_1 -#undef HEAT_DAMAGE_LEVEL_2 -#undef HEAT_DAMAGE_LEVEL_3 +/mob/living/carbon/alien/show_inv(mob/user as mob) + return //Consider adding cuffs and hats to this, for the sake of fun. + +/mob/living/carbon/alien/can_use_vents() + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/alien_attacks.dm b/code/modules/mob/living/carbon/alien/alien_attacks.dm new file mode 100644 index 00000000000..45a486adf7b --- /dev/null +++ b/code/modules/mob/living/carbon/alien/alien_attacks.dm @@ -0,0 +1,183 @@ +//There has to be a better way to define this shit. ~ Z +//can't equip anything +/mob/living/carbon/alien/attack_ui(slot_id) + return + +/mob/living/carbon/alien/meteorhit(O as obj) + for(var/mob/M in viewers(src, null)) + if ((M.client && !( M.blinded ))) + M.show_message(text("\red [] has been hit by []", src, O), 1) + if (health > 0) + adjustBruteLoss((istype(O, /obj/effect/meteor/small) ? 10 : 25)) + adjustFireLoss(30) + + updatehealth() + return + +/mob/living/carbon/alien/attack_animal(mob/living/M as mob) + + if(istype(M,/mob/living/simple_animal)) + var/mob/living/simple_animal/S = M + if(S.melee_damage_upper == 0) + S.emote("[S.friendly] [src]") + else + for(var/mob/O in viewers(src, null)) + O.show_message("\red [S] [S.attacktext] [src]!", 1) + var/damage = rand(S.melee_damage_lower, S.melee_damage_upper) + adjustBruteLoss(damage) + S.attack_log += text("\[[time_stamp()]\] attacked [src.name] ([src.ckey])") + src.attack_log += text("\[[time_stamp()]\] was attacked by [S.name] ([S.ckey])") + updatehealth() + +/mob/living/carbon/alien/attack_paw(mob/living/carbon/monkey/M as mob) + if(!(istype(M, /mob/living/carbon/monkey))) return//Fix for aliens receiving double messages when attacking other aliens. + + if (!ticker) + M << "You cannot attack people before the game has started." + return + + if (istype(loc, /turf) && istype(loc.loc, /area/start)) + M << "No attacking people at spawn, you jackass." + return + ..() + + switch(M.a_intent) + + if ("help") + help_shake_act(M) + else + if (istype(wear_mask, /obj/item/clothing/mask/muzzle)) + 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("\red [M.name] has bit [src]!"), 1) + adjustBruteLoss(rand(1, 3)) + updatehealth() + return + + +/mob/living/carbon/alien/attack_slime(mob/living/carbon/slime/M as mob) + if (!ticker) + M << "You cannot attack people before the game has started." + return + + if(M.Victim) return // can't attack while eating! + + 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) + + var/damage = rand(1, 3) + + if(M.is_adult) + damage = rand(20, 40) + else + damage = rand(5, 35) + + adjustBruteLoss(damage) + + + updatehealth() + + return + +/mob/living/carbon/alien/attack_hand(mob/living/carbon/human/M as mob) + if (!ticker) + M << "You cannot attack people before the game has started." + return + + if (istype(loc, /turf) && istype(loc.loc, /area/start)) + M << "No attacking people at spawn, you jackass." + return + + ..() + + if(M.gloves && istype(M.gloves,/obj/item/clothing/gloves)) + var/obj/item/clothing/gloves/G = M.gloves + if(G.cell) + if(M.a_intent == "hurt")//Stungloves. Any contact will stun the alien. + if(G.cell.charge >= 2500) + G.cell.use(2500) + + Weaken(5) + if (stuttering < 5) + stuttering = 5 + Stun(5) + + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message("\red [src] has been touched with the stun gloves by [M]!", 1, "\red You hear someone fall.", 2) + return + else + M << "\red Not enough charge! " + return + + switch(M.a_intent) + + if ("help") + if (health > 0) + help_shake_act(M) + else + if (M.health >= -75.0) + if ((M.head && M.head.flags & 4) || (M.wear_mask && !( M.wear_mask.flags & 32 )) ) + M << "\blue Remove that mask!" + return + var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human( ) + O.source = M + O.target = src + O.s_loc = M.loc + O.t_loc = loc + O.place = "CPR" + requests += O + spawn( 0 ) + O.process() + return + + if ("grab") + if (M == src) + return + var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src ) + + M.put_in_active_hand(G) + + grabbed_by += G + G.synch() + + 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) + + else + var/damage = rand(1, 9) + if (prob(90)) + if (HULK in M.mutations) + damage += 5 + spawn(0) + Paralyse(1) + step_away(src,M,15) + 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) + if (damage > 4.9) + Weaken(rand(10,15)) + 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) + 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) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/alien_damage.dm b/code/modules/mob/living/carbon/alien/alien_damage.dm new file mode 100644 index 00000000000..14835591203 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/alien_damage.dm @@ -0,0 +1,56 @@ +/mob/living/carbon/alien/ex_act(severity) + + if(!blinded) + flick("flash", flash) + + var/b_loss = null + var/f_loss = null + switch (severity) + if (1.0) + b_loss += 500 + gib() + return + + if (2.0) + + b_loss += 60 + + f_loss += 60 + + ear_damage += 30 + ear_deaf += 120 + + if(3.0) + b_loss += 30 + if (prob(50)) + Paralyse(1) + ear_damage += 15 + ear_deaf += 60 + + adjustBruteLoss(b_loss) + adjustFireLoss(f_loss) + + updatehealth() + + + +/mob/living/carbon/alien/blob_act() + if (stat == 2) + return + var/shielded = 0 + + var/damage = null + if (stat != 2) + damage = rand(10,30) + + if(shielded) + damage /= 4 + + //paralysis += 1 + + show_message("\red The blob attacks you!") + + adjustFireLoss(damage) + + updatehealth() + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm index 0a060dd1f70..7dfd2cc0ebc 100644 --- a/code/modules/mob/living/carbon/alien/death.dm +++ b/code/modules/mob/living/carbon/alien/death.dm @@ -1,41 +1,13 @@ -/mob/living/carbon/alien/gib() - death(1) - var/atom/movable/overlay/animation = null - monkeyizing = 1 - canmove = 0 - icon = null - invisibility = 101 +/mob/living/carbon/alien/death(gibbed) - animation = new(loc) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src + if(stat == DEAD) return + if(healths) healths.icon_state = "health6" + stat = DEAD - flick("gibbed-a", animation) - xgibs(loc, viruses) - dead_mob_list -= src + if(dead_icon) icon_state = dead_icon - spawn(15) - if(animation) del(animation) - if(src) del(src) + if(!gibbed) + update_canmove() + if(client) blind.layer = 0 -/mob/living/carbon/alien/dust() - death(1) - var/atom/movable/overlay/animation = null - monkeyizing = 1 - canmove = 0 - icon = null - invisibility = 101 - - animation = new(loc) - animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' - animation.master = src - - flick("dust-a", animation) - new /obj/effect/decal/remains/xeno(loc) - dead_mob_list -= src - - spawn(15) - if(animation) del(animation) - if(src) del(src) + return ..(gibbed) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm new file mode 100644 index 00000000000..3f4bc2105d8 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/diona.dm @@ -0,0 +1,25 @@ +/mob/living/carbon/alien/diona + name = "diona nymph" + voice_name = "diona nymph" + adult_form = /mob/living/carbon/human + speak_emote = list("chirrups") + icon_state = "nymph" + language = "Rootspeak" + + amount_grown = 0 + max_grown = 5 // Target number of donors. + + var/list/donors = list() + var/last_checked_stage = 0 + + universal_understand = 0 // Dionaea do not need to speak to people + universal_speak = 0 // before becoming an adult. Use *chirp. + holder_type = /obj/item/weapon/holder/diona + +/mob/living/carbon/alien/diona/New() + + ..() + verbs += /mob/living/carbon/proc/eat_weeds + verbs += /mob/living/carbon/proc/fertilize_plant + verbs += /mob/living/carbon/alien/diona/proc/steal_blood + verbs += /mob/living/carbon/alien/diona/proc/merge \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm new file mode 100644 index 00000000000..108333bf86f --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm @@ -0,0 +1,14 @@ +/mob/living/carbon/alien/diona/attack_hand(mob/living/carbon/human/M as mob) + + //Let people pick the little buggers up. + if(M.a_intent == "help") + if(M.species && M.species.name == "Diona") + M << "You feel your being twine with that of [src] as it merges with your biomass." + src << "You feel your being twine with that of [M] as you merge with its biomass." + src.verbs += /mob/living/carbon/alien/diona/proc/split + src.verbs -= /mob/living/carbon/alien/diona/proc/merge + src.loc = M + else + get_scooped(M) + + ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/diona_powers.dm b/code/modules/mob/living/carbon/alien/diona/diona_powers.dm new file mode 100644 index 00000000000..b8a47501a8f --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/diona_powers.dm @@ -0,0 +1,90 @@ +//Verbs after this point. +/mob/living/carbon/alien/diona/proc/merge() + + set category = "Abilities" + set name = "Merge with gestalt" + set desc = "Merge with another diona." + + if(istype(src.loc,/mob/living/carbon)) + src.verbs -= /mob/living/carbon/alien/diona/proc/merge + return + + var/list/choices = list() + for(var/mob/living/carbon/C in view(1,src)) + + if(!(src.Adjacent(C)) || !(C.client)) continue + + if(istype(C,/mob/living/carbon/human)) + var/mob/living/carbon/human/D = C + if(D.species && D.species.name == "Diona") + choices += C + + var/mob/living/M = input(src,"Who do you wish to merge with?") in null|choices + + if(!M || !src || !(src.Adjacent(M))) return + + if(istype(M,/mob/living/carbon/human)) + M << "You feel your being twine with that of [src] as it merges with your biomass." + M.status_flags |= PASSEMOTES + + src << "You feel your being twine with that of [M] as you merge with its biomass." + src.loc = M + src.verbs += /mob/living/carbon/alien/diona/proc/split + src.verbs -= /mob/living/carbon/alien/diona/proc/merge + else + return + +/mob/living/carbon/alien/diona/proc/split() + + set category = "Abilities" + set name = "Split from gestalt" + set desc = "Split away from your gestalt as a lone nymph." + + if(!(istype(src.loc,/mob/living/carbon))) + src.verbs -= /mob/living/carbon/alien/diona/proc/split + return + + src.loc << "You feel a pang of loss as [src] splits away from your biomass." + src << "You wiggle out of the depths of [src.loc]'s biomass and plop to the ground." + + var/mob/living/M = src.loc + + src.loc = get_turf(src) + src.verbs -= /mob/living/carbon/alien/diona/proc/split + src.verbs += /mob/living/carbon/alien/diona/proc/merge + + if(istype(M)) + for(var/atom/A in M.contents) + if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/weapon/holder)) + return + M.status_flags &= ~PASSEMOTES + +/mob/living/carbon/alien/diona/proc/steal_blood() + set category = "Abilities" + set name = "Steal Blood" + set desc = "Take a blood sample from a suitable donor." + + var/list/choices = list() + for(var/mob/living/carbon/human/H in oview(1,src)) + if(src.Adjacent(H)) + choices += H + + var/mob/living/carbon/human/M = input(src,"Who do you wish to take a sample from?") in null|choices + + if(!M || !src) return + + if(M.species.flags & NO_BLOOD) + src << "\red That donor has no blood to take." + return + + if(donors.Find(M.real_name)) + src << "\red That donor offers you nothing new." + return + + src.visible_message("\red [src] flicks out a feeler and neatly steals a sample of [M]'s blood.","\red You flick out a feeler and neatly steal a sample of [M]'s blood.") + donors += M.real_name + for(var/datum/language/L in M.languages) + languages |= L + + spawn(25) + update_progression() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/life.dm b/code/modules/mob/living/carbon/alien/diona/life.dm new file mode 100644 index 00000000000..26d236bcaa8 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/life.dm @@ -0,0 +1,20 @@ +/* TODO + if(alien) //Diona nymphs are the only alien monkey currently. + 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 + traumatic_shock -= light_amount + + if(nutrition > 500) + nutrition = 500 + if(light_amount > 2) //if there's enough light, heal + adjustBruteLoss(-1) + adjustToxLoss(-1) + adjustOxyLoss(-1) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/progression.dm b/code/modules/mob/living/carbon/alien/diona/progression.dm new file mode 100644 index 00000000000..b99f593a100 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/progression.dm @@ -0,0 +1,40 @@ +/mob/living/carbon/alien/diona/confirm_evolution() + + if(!is_alien_whitelisted(src, "Diona") && config.usealienwhitelist) + src << alert("You are currently not whitelisted to play as a full diona.") + return null + + if(amount_grown < max_grown) + src << "You are not yet ready for your growth..." + return null + + src.split() + + if(istype(loc,/obj/item/weapon/holder/diona)) + var/obj/item/weapon/holder/diona/L = loc + src.loc = L.loc + del(L) + + src.visible_message("\red [src] begins to shift and quiver, and erupts in a shower of shed bark as it splits into a tangle of nearly a dozen new dionaea.","\red You begin to shift and quiver, feeling your awareness splinter. All at once, we consume our stored nutrients to surge with growth, splitting into a tangle of at least a dozen new dionaea. We have attained our gestalt form.") + return "Diona" + +/mob/living/carbon/alien/diona/show_evolution_blurb() + //TODO + return + +/mob/living/carbon/alien/diona/update_progression() + + amount_grown = donors.len + + if(amount_grown <= last_checked_stage) + return + + // Only fire off these messages once. + last_checked_stage = amount_grown + if(amount_grown == max_grown) + src << "\green You feel ready to move on to your next stage of growth." + else if(amount_grown == 3) + universal_understand = 1 + src << "\green You feel your awareness expand, and realize you know how to understand the creatures around you." + else + src << "\green The blood seeps into your small form, and you draw out the echoes of memories and personality from it, working them into your budding mind." \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/say_understands.dm b/code/modules/mob/living/carbon/alien/diona/say_understands.dm new file mode 100644 index 00000000000..3f68a44cffb --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/say_understands.dm @@ -0,0 +1,6 @@ +/mob/living/carbon/alien/diona/say_understands(var/mob/other,var/datum/language/speaking = null) + + if (istype(other, /mob/living/carbon/human) && !speaking) + if(languages.len >= 2) // They have sucked down some blood. + return 1 + return ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/emote.dm b/code/modules/mob/living/carbon/alien/emote.dm similarity index 86% rename from code/modules/mob/living/carbon/alien/larva/emote.dm rename to code/modules/mob/living/carbon/alien/emote.dm index 375c5c6b0c9..0efcae7c911 100644 --- a/code/modules/mob/living/carbon/alien/larva/emote.dm +++ b/code/modules/mob/living/carbon/alien/emote.dm @@ -1,127 +1,127 @@ -/mob/living/carbon/alien/larva/emote(var/act,var/m_type=1,var/message = null) - - var/param = null - if (findtext(act, "-", 1, null)) - var/t1 = findtext(act, "-", 1, null) - param = copytext(act, t1 + 1, length(act) + 1) - act = copytext(act, 1, t1) - - if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' - act = copytext(act,1,length(act)) - var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) - - switch(act) - if ("me") - if(silent) - return - if (src.client) - if (client.prefs.muted & MUTE_IC) - src << "\red You cannot send IC messages (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - if (stat) - return - if(!(message)) - return - return custom_emote(m_type, message) - - if ("custom") - return custom_emote(m_type, message) - if("sign") - if (!src.restrained()) - message = text("The alien signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) - m_type = 1 - if ("burp") - if (!muzzled) - message = "[src] burps." - m_type = 2 - if("scratch") - if (!src.restrained()) - message = "The [src.name] scratches." - m_type = 1 - if("whimper") - if (!muzzled) - message = "The [src.name] whimpers." - m_type = 2 -// if("roar") -// if (!muzzled) -// message = "The [src.name] roars." Commenting out since larva shouldn't roar /N -// m_type = 2 - if("tail") - message = "The [src.name] waves its tail." - m_type = 1 - if("gasp") - message = "The [src.name] gasps." - m_type = 2 - if("shiver") - message = "The [src.name] shivers." - m_type = 2 - if("drool") - message = "The [src.name] drools." - m_type = 1 - if("scretch") - if (!muzzled) - message = "The [src.name] scretches." - m_type = 2 - if("choke") - message = "The [src.name] chokes." - m_type = 2 - if("moan") - message = "The [src.name] moans!" - m_type = 2 - if("nod") - message = "The [src.name] nods its head." - m_type = 1 -// if("sit") -// message = "The [src.name] sits down." //Larvan can't sit down, /N -// m_type = 1 - if("sway") - message = "The [src.name] sways around dizzily." - m_type = 1 - if("sulk") - message = "The [src.name] sulks down sadly." - m_type = 1 - if("twitch") - message = "The [src.name] twitches violently." - m_type = 1 - if("dance") - if (!src.restrained()) - message = "The [src.name] dances around happily." - m_type = 1 - if("roll") - if (!src.restrained()) - message = "The [src.name] rolls." - m_type = 1 - if("shake") - message = "The [src.name] shakes its head." - m_type = 1 - if("gnarl") - if (!muzzled) - message = "The [src.name] gnarls and shows its teeth.." - m_type = 2 - if("jump") - message = "The [src.name] jumps!" - m_type = 1 - if("hiss_") - message = "The [src.name] hisses softly." - m_type = 1 - if("collapse") - Paralyse(2) - message = text("[] collapses!", src) - m_type = 2 - if("help") - src << "burp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper" - else - src << text("Invalid Emote: []", act) - if ((message && src.stat == 0)) - log_emote("[name]/[key] : [message]") - if (m_type & 1) - for(var/mob/O in viewers(src, null)) - O.show_message(message, m_type) - //Foreach goto(703) - else - for(var/mob/O in hearers(src, null)) - O.show_message(message, m_type) - //Foreach goto(746) +/mob/living/carbon/alien/emote(var/act,var/m_type=1,var/message = null) + + var/param = null + if (findtext(act, "-", 1, null)) + var/t1 = findtext(act, "-", 1, null) + param = copytext(act, t1 + 1, length(act) + 1) + act = copytext(act, 1, t1) + + if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' + act = copytext(act,1,length(act)) + var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) + + switch(act) + if ("me") + if(silent) + return + if (src.client) + if (client.prefs.muted & MUTE_IC) + src << "\red You cannot send IC messages (muted)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return + if (stat) + return + if(!(message)) + return + return custom_emote(m_type, message) + + if ("custom") + return custom_emote(m_type, message) + if("sign") + if (!src.restrained()) + message = text("The alien signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) + m_type = 1 + if ("burp") + if (!muzzled) + message = "[src] burps." + m_type = 2 + if("scratch") + if (!src.restrained()) + message = "The [src.name] scratches." + m_type = 1 + if("whimper") + if (!muzzled) + message = "The [src.name] whimpers." + m_type = 2 + if("tail") + message = "The [src.name] waves its tail." + m_type = 1 + if("gasp") + message = "The [src.name] gasps." + m_type = 2 + if("shiver") + message = "The [src.name] shivers." + m_type = 2 + if("drool") + message = "The [src.name] drools." + m_type = 1 + if("scretch") + if (!muzzled) + message = "The [src.name] scretches." + m_type = 2 + if("choke") + message = "The [src.name] chokes." + m_type = 2 + if("moan") + message = "The [src.name] moans!" + m_type = 2 + if("nod") + message = "The [src.name] nods its head." + m_type = 1 +// if("sit") +// message = "The [src.name] sits down." //Larvan can't sit down, /N +// m_type = 1 + if("sway") + message = "The [src.name] sways around dizzily." + m_type = 1 + if("sulk") + message = "The [src.name] sulks down sadly." + m_type = 1 + if("twitch") + message = "The [src.name] twitches violently." + m_type = 1 + if("dance") + if (!src.restrained()) + message = "The [src.name] dances around happily." + m_type = 1 + if("roll") + if (!src.restrained()) + message = "The [src.name] rolls." + m_type = 1 + if("shake") + message = "The [src.name] shakes its head." + m_type = 1 + if("gnarl") + if (!muzzled) + message = "The [src.name] gnarls and shows its teeth.." + m_type = 2 + if("jump") + message = "The [src.name] jumps!" + m_type = 1 + if("hiss_") + message = "The [src.name] hisses softly." + m_type = 1 + if("collapse") + Paralyse(2) + message = text("[] collapses!", src) + m_type = 2 + if("chirp") + message = "The [src.name] chirps!" + playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0) + m_type = 2 + if("help") + src << "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper" + else + src << text("Invalid Emote: []", act) + if ((message && src.stat == 0)) + log_emote("[name]/[key] : [message]") + if (m_type & 1) + for(var/mob/O in viewers(src, null)) + O.show_message(message, m_type) + //Foreach goto(703) + else + for(var/mob/O in hearers(src, null)) + O.show_message(message, m_type) + //Foreach goto(746) return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm deleted file mode 100644 index 92426808b66..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ /dev/null @@ -1,188 +0,0 @@ -/*NOTES: -These are general powers. Specific powers are stored under the appropriate alien creature type. -*/ - -/*Alien spit now works like a taser shot. It won't home in on the target but will act the same once it does hit. -Doesn't work on other aliens/AI.*/ - - -/mob/living/carbon/alien/proc/powerc(X, Y)//Y is optional, checks for weed planting. X can be null. - if(stat) - src << "\green You must be conscious to do this." - return 0 - else if(X && getPlasma() < X) - src << "\green Not enough plasma stored." - return 0 - else if(Y && (!isturf(src.loc) || istype(src.loc, /turf/space))) - src << "\green Bad place for a garden!" - return 0 - else return 1 - -/mob/living/carbon/alien/humanoid/verb/plant() - set name = "Plant Weeds (50)" - set desc = "Plants some alien weeds" - set category = "Alien" - - if(powerc(50,1)) - adjustToxLoss(-50) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\green [src] has planted some alien weeds!"), 1) - new /obj/effect/alien/weeds/node(loc) - return - -/* -/mob/living/carbon/alien/humanoid/verb/ActivateHuggers() - set name = "Activate facehuggers (5)" - set desc = "Makes all nearby facehuggers activate" - set category = "Alien" - - if(powerc(5)) - adjustToxLoss(-5) - for(var/obj/item/clothing/mask/facehugger/F in range(8,src)) - F.GoActive() - emote("roar") - return -*/ -/mob/living/carbon/alien/humanoid/verb/whisp(mob/M as mob in oview()) - set name = "Whisper (10)" - set desc = "Whisper to someone" - set category = "Alien" - - if(powerc(10)) - adjustToxLoss(-10) - var/msg = sanitize(input("Message:", "Alien Whisper") as text|null) - if(msg) - log_say("AlienWhisper: [key_name(src)]->[M.key] : [msg]") - M << "\green You hear a strange, alien voice in your head... \italic [msg]" - src << {"\green You said: "[msg]" to [M]"} - return - -/mob/living/carbon/alien/humanoid/verb/transfer_plasma(mob/living/carbon/alien/M as mob in oview()) - set name = "Transfer Plasma" - set desc = "Transfer Plasma to another alien" - set category = "Alien" - - if(isalien(M)) - var/amount = input("Amount:", "Transfer Plasma to [M]") as num - if (amount) - amount = abs(round(amount)) - if(powerc(amount)) - if (get_dist(src,M) <= 1) - M.adjustToxLoss(amount) - adjustToxLoss(-amount) - M << "\green [src] has transfered [amount] plasma to you." - src << {"\green You have trasferred [amount] plasma to [M]"} - else - src << "\green You need to be closer." - return - - -/mob/living/carbon/alien/humanoid/proc/corrosive_acid(O as obj|turf in oview(1)) //If they right click to corrode, an error will flash if its an invalid target./N - set name = "Corrossive Acid (200)" - set desc = "Drench an object in acid, destroying it over time." - set category = "Alien" - - if(powerc(200)) - if(O in oview(1)) - // OBJ CHECK - if(isobj(O)) - var/obj/I = O - if(I.unacidable) //So the aliens don't destroy energy fields/singularies/other aliens/etc with their acid. - src << "\green You cannot dissolve this object." - return - // TURF CHECK - else if(istype(O, /turf/simulated)) - var/turf/T = O - // R WALL - if(istype(T, /turf/simulated/wall/r_wall)) - src << "\green You cannot dissolve this object." - return - // R FLOOR - if(istype(T, /turf/simulated/floor/engine)) - src << "\green You cannot dissolve this object." - return - else// Not a type we can acid. - return - - adjustToxLoss(-200) - new /obj/effect/alien/acid(get_turf(O), O) - visible_message("\green [src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!") - else - src << "\green Target is too far away." - return - - -/mob/living/carbon/alien/humanoid/proc/neurotoxin(mob/target as mob in oview()) - set name = "Spit Neurotoxin (50)" - set desc = "Spits neurotoxin at someone, paralyzing them for a short time if they are not wearing protective gear." - set category = "Alien" - - if(powerc(50)) - if(isalien(target)) - src << "\green Your allies are not a valid target." - return - adjustToxLoss(-50) - src << "\green You spit neurotoxin at [target]." - for(var/mob/O in oviewers()) - if ((O.client && !( O.blinded ))) - O << "\red [src] spits neurotoxin at [target]!" - //I'm not motivated enough to revise this. Prjectile code in general needs update. - var/turf/T = loc - var/turf/U = (istype(target, /atom/movable) ? target.loc : target) - - if(!U || !T) - return - while(U && !istype(U,/turf)) - U = U.loc - if(!istype(T, /turf)) - return - if (U == T) - usr.bullet_act(new /obj/item/projectile/energy/neurotoxin(usr.loc), get_organ_target()) - return - if(!istype(U, /turf)) - return - - var/obj/item/projectile/energy/neurotoxin/A = new /obj/item/projectile/energy/neurotoxin(usr.loc) - A.current = U - A.yo = U.y - T.y - A.xo = U.x - T.x - A.process() - return - -/mob/living/carbon/alien/humanoid/proc/resin() // -- TLE - set name = "Secrete Resin (75)" - set desc = "Secrete tough malleable resin." - set category = "Alien" - - if(powerc(75)) - var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in list("resin door","resin wall","resin membrane","resin nest") //would do it through typesof but then the player choice would have the type path and we don't want the internal workings to be exposed ICly - Urist - if(!choice || !powerc(75)) return - adjustToxLoss(-75) - src << "\green You shape a [choice]." - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [src] vomits up a thick purple substance and begins to shape it!"), 1) - switch(choice) - if("resin door") - new /obj/structure/mineral_door/resin(loc) - if("resin wall") - new /obj/effect/alien/resin/wall(loc) - if("resin membrane") - new /obj/effect/alien/resin/membrane(loc) - if("resin nest") - new /obj/structure/stool/bed/nest(loc) - return - -/mob/living/carbon/alien/humanoid/verb/regurgitate() - set name = "Regurgitate" - set desc = "Empties the contents of your stomach" - set category = "Alien" - - if(powerc()) - if(stomach_contents.len) - for(var/mob/M in src) - if(M in stomach_contents) - stomach_contents.Remove(M) - M.loc = loc - //Paralyse(10) - src.visible_message("\green [src] hurls out the contents of their stomach!") - return diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm deleted file mode 100644 index 6b7752f8137..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm +++ /dev/null @@ -1,48 +0,0 @@ -/mob/living/carbon/alien/humanoid/drone - name = "alien drone" - caste = "d" - maxHealth = 100 - health = 100 - icon_state = "aliend_s" - plasma_rate = 15 - -/mob/living/carbon/alien/humanoid/drone/New() - var/datum/reagents/R = new/datum/reagents(100) - reagents = R - R.my_atom = src - if(src.name == "alien drone") - src.name = text("alien drone ([rand(1, 1000)])") - src.real_name = src.name - verbs.Add(/mob/living/carbon/alien/humanoid/proc/resin,/mob/living/carbon/alien/humanoid/proc/corrosive_acid) - ..() -//Drones use the same base as generic humanoids. -//Drone verbs - -/mob/living/carbon/alien/humanoid/drone/verb/evolve() // -- TLE - set name = "Evolve (500)" - set desc = "Produce an interal egg sac capable of spawning children. Only one queen can exist at a time." - set category = "Alien" - - if(powerc(500)) - // Queen check - var/no_queen = 1 - for(var/mob/living/carbon/alien/humanoid/queen/Q in living_mob_list) - if(!Q.key && Q.has_brain()) - continue - no_queen = 0 - - if(src.has_brain_worms()) - src << "We cannot perform this ability at the present time!" - return - - if(no_queen) - adjustToxLoss(-500) - src << "\green You begin to evolve!" - for(var/mob/O in viewers(src, null)) - O.show_message(text("\green [src] begins to twist and contort!"), 1) - var/mob/living/carbon/alien/humanoid/queen/new_xeno = new (loc) - mind.transfer_to(new_xeno) - del(src) - else - src << "We already have an alive queen." - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm deleted file mode 100644 index 3a15f620b20..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm +++ /dev/null @@ -1,76 +0,0 @@ -/mob/living/carbon/alien/humanoid/hunter - name = "alien hunter" - caste = "h" - maxHealth = 150 - health = 150 - storedPlasma = 100 - max_plasma = 150 - icon_state = "alienh_s" - plasma_rate = 5 - -/mob/living/carbon/alien/humanoid/hunter/New() - var/datum/reagents/R = new/datum/reagents(100) - reagents = R - R.my_atom = src - if(name == "alien hunter") - name = text("alien hunter ([rand(1, 1000)])") - real_name = name - ..() - -/mob/living/carbon/alien/humanoid/hunter - - - handle_regular_hud_updates() - - ..() //-Yvarov - - if (healths) - if (stat != 2) - switch(health) - if(150 to INFINITY) - healths.icon_state = "health0" - if(100 to 150) - healths.icon_state = "health1" - if(50 to 100) - healths.icon_state = "health2" - if(25 to 50) - healths.icon_state = "health3" - if(0 to 25) - healths.icon_state = "health4" - else - healths.icon_state = "health5" - else - healths.icon_state = "health6" - - - handle_environment() - if(m_intent == "run" || resting) - ..() - else - adjustToxLoss(-heal_rate) - - -//Hunter verbs -/* -/mob/living/carbon/alien/humanoid/hunter/verb/invis() - set name = "Invisibility (50)" - set desc = "Makes you invisible for 15 seconds" - set category = "Alien" - - if(alien_invis) - update_icons() - else - if(powerc(50)) - adjustToxLoss(-50) - alien_invis = 1.0 - update_icons() - src << "\green You are now invisible." - for(var/mob/O in oviewers(src, null)) - O.show_message(text("\red [src] fades into the surroundings!"), 1) - spawn(250) - if(!isnull(src))//Don't want the game to runtime error when the mob no-longer exists. - alien_invis = 0.0 - update_icons() - src << "\green You are no longer invisible." - return -*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm deleted file mode 100644 index 226824c6ab4..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm +++ /dev/null @@ -1,44 +0,0 @@ -/mob/living/carbon/alien/humanoid/sentinel - name = "alien sentinel" - caste = "s" - maxHealth = 125 - health = 125 - storedPlasma = 100 - max_plasma = 250 - icon_state = "aliens_s" - plasma_rate = 10 - -/mob/living/carbon/alien/humanoid/sentinel/New() - var/datum/reagents/R = new/datum/reagents(100) - reagents = R - R.my_atom = src - if(name == "alien sentinel") - name = text("alien sentinel ([rand(1, 1000)])") - real_name = name - verbs.Add(/mob/living/carbon/alien/humanoid/proc/corrosive_acid,/mob/living/carbon/alien/humanoid/proc/neurotoxin) - ..() - -/mob/living/carbon/alien/humanoid/sentinel - - - handle_regular_hud_updates() - - ..() //-Yvarov - - if (healths) - if (stat != 2) - switch(health) - if(125 to INFINITY) - healths.icon_state = "health0" - if(100 to 125) - healths.icon_state = "health1" - if(75 to 100) - healths.icon_state = "health2" - if(25 to 75) - healths.icon_state = "health3" - if(0 to 25) - healths.icon_state = "health4" - else - healths.icon_state = "health5" - else - healths.icon_state = "health6" diff --git a/code/modules/mob/living/carbon/alien/humanoid/death.dm b/code/modules/mob/living/carbon/alien/humanoid/death.dm deleted file mode 100644 index 91138a43090..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/death.dm +++ /dev/null @@ -1,17 +0,0 @@ -/mob/living/carbon/alien/humanoid/death(gibbed) - if(stat == DEAD) return - if(healths) healths.icon_state = "health6" - stat = DEAD - - if(!gibbed) - playsound(loc, 'sound/voice/hiss6.ogg', 80, 1, 1) - for(var/mob/O in viewers(src, null)) - O.show_message("[src] lets out a waning guttural screech, green blood bubbling from its maw...", 1) - update_canmove() - if(client) blind.layer = 0 - update_icons() - - tod = worldtime2text() //weasellos time of death patch - if(mind) mind.store_memory("Time of death: [tod]", 0) - - return ..(gibbed) diff --git a/code/modules/mob/living/carbon/alien/humanoid/emote.dm b/code/modules/mob/living/carbon/alien/humanoid/emote.dm deleted file mode 100644 index 71dc56ef402..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/emote.dm +++ /dev/null @@ -1,135 +0,0 @@ -/mob/living/carbon/alien/humanoid/emote(var/act,var/m_type=1,var/message = null) - - var/param = null - if (findtext(act, "-", 1, null)) - var/t1 = findtext(act, "-", 1, null) - param = copytext(act, t1 + 1, length(act) + 1) - act = copytext(act, 1, t1) - - if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_' - act = copytext(act,1,length(act)) - var/muzzled = istype(src.wear_mask, /obj/item/clothing/mask/muzzle) - - switch(act) - if ("me") - if(silent) - return - if (src.client) - if (client.prefs.muted & MUTE_IC) - src << "\red You cannot send IC messages (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - if (stat) - return - if(!(message)) - return - return custom_emote(m_type, message) - - if ("custom") - return custom_emote(m_type, message) - if("sign") - if (!src.restrained()) - message = text("The alien signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) - m_type = 1 - if ("burp") - if (!muzzled) - message = "[src] burps." - m_type = 2 - if ("deathgasp") - message = "[src] lets out a waning guttural screech, green blood bubbling from its maw..." - m_type = 2 - if("scratch") - if (!src.restrained()) - message = "The [src.name] scratches." - m_type = 1 - if("whimper") - if (!muzzled) - message = "The [src.name] whimpers." - m_type = 2 - if("roar") - if (!muzzled) - message = "The [src.name] roars." - m_type = 2 - if("hiss") - if(!muzzled) - message = "The [src.name] hisses." - m_type = 2 - if("tail") - message = "The [src.name] waves its tail." - m_type = 1 - if("gasp") - message = "The [src.name] gasps." - m_type = 2 - if("shiver") - message = "The [src.name] shivers." - m_type = 2 - if("drool") - message = "The [src.name] drools." - m_type = 1 - if("scretch") - if (!muzzled) - message = "The [src.name] scretches." - m_type = 2 - if("choke") - message = "The [src.name] chokes." - m_type = 2 - if("moan") - message = "The [src.name] moans!" - m_type = 2 - if("nod") - message = "The [src.name] nods its head." - m_type = 1 - if("sit") - message = "The [src.name] sits down." - m_type = 1 - if("sway") - message = "The [src.name] sways around dizzily." - m_type = 1 - if("sulk") - message = "The [src.name] sulks down sadly." - m_type = 1 - if("twitch") - message = "The [src.name] twitches violently." - m_type = 1 - if("dance") - if (!src.restrained()) - message = "The [src.name] dances around happily." - m_type = 1 - if("roll") - if (!src.restrained()) - message = "The [src.name] rolls." - m_type = 1 - if("shake") - message = "The [src.name] shakes its head." - m_type = 1 - if("gnarl") - if (!muzzled) - message = "The [src.name] gnarls and shows its teeth.." - m_type = 2 - if("jump") - message = "The [src.name] jumps!" - m_type = 1 - if("collapse") - Paralyse(2) - message = text("[] collapses!", src) - m_type = 2 - if("help") - src << "burp, deathgasp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roar, roll, scratch,\nscretch, shake, sign-#, sit, sulk, sway, tail, twitch, whimper" - else - src << text("Invalid Emote: []", act) - if ((message && src.stat == 0)) - log_emote("[name]/[key] : [message]") - if (act == "roar") - playsound(src.loc, 'sound/voice/hiss5.ogg', 40, 1, 1) - if (act == "deathgasp") - playsound(src.loc, 'sound/voice/hiss6.ogg', 80, 1, 1) - if (m_type & 1) - for(var/mob/O in viewers(src, null)) - O.show_message(message, m_type) - //Foreach goto(703) - else - for(var/mob/O in hearers(src, null)) - O.show_message(message, m_type) - //Foreach goto(746) - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm deleted file mode 100644 index 03e590f036b..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ /dev/null @@ -1,423 +0,0 @@ -/mob/living/carbon/alien/humanoid - name = "alien" - icon_state = "alien_s" - - var/obj/item/clothing/suit/wear_suit = null //TODO: necessary? Are they even used? ~Carn - var/obj/item/clothing/head/head = null // - var/obj/item/weapon/r_store = null - var/obj/item/weapon/l_store = null - var/caste = "" - update_icon = 1 - -//This is fine right now, if we're adding organ specific damage this needs to be updated -/mob/living/carbon/alien/humanoid/New() - var/datum/reagents/R = new/datum/reagents(100) - reagents = R - R.my_atom = src - if(name == "alien") - name = text("alien ([rand(1, 1000)])") - real_name = name - ..() - -//This is fine, works the same as a human -/mob/living/carbon/alien/humanoid/Bump(atom/movable/AM as mob|obj, yes) - spawn( 0 ) - if ((!( yes ) || now_pushing)) - return - now_pushing = 0 - ..() - if (!istype(AM, /atom/movable)) - return - - if (ismob(AM)) - var/mob/tmob = AM - tmob.LAssailant = src - - if (!now_pushing) - now_pushing = 1 - if (!AM.anchored) - var/t = get_dir(src, AM) - if (istype(AM, /obj/structure/window)) - if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST) - for(var/obj/structure/window/win in get_step(AM,t)) - now_pushing = 0 - return - step(AM, t) - now_pushing = null - return - return - -/mob/living/carbon/alien/humanoid/movement_delay() - var/tally = 0 - if (istype(src, /mob/living/carbon/alien/humanoid/queen)) - tally += 5 - if (istype(src, /mob/living/carbon/alien/humanoid/drone)) - tally += 2 - if (istype(src, /mob/living/carbon/alien/humanoid/sentinel)) - tally += 1 - if (istype(src, /mob/living/carbon/alien/humanoid/hunter)) - tally = -1 // hunters go supersuperfast - return (tally + move_delay_add + config.alien_delay) - -///mob/living/carbon/alien/humanoid/bullet_act(var/obj/item/projectile/Proj) taken care of in living - -/mob/living/carbon/alien/humanoid/emp_act(severity) - if(wear_suit) wear_suit.emp_act(severity) - if(head) head.emp_act(severity) - if(r_store) r_store.emp_act(severity) - if(l_store) l_store.emp_act(severity) - ..() - -/mob/living/carbon/alien/humanoid/ex_act(severity) - if(!blinded) - flick("flash", flash) - - var/shielded = 0 - - var/b_loss = null - var/f_loss = null - switch (severity) - if (1.0) - b_loss += 500 - gib() - return - - if (2.0) - if (!shielded) - b_loss += 60 - - f_loss += 60 - - ear_damage += 30 - ear_deaf += 120 - - if(3.0) - b_loss += 30 - if (prob(50) && !shielded) - Paralyse(1) - ear_damage += 15 - ear_deaf += 60 - - adjustBruteLoss(b_loss) - adjustFireLoss(f_loss) - - updatehealth() - -/mob/living/carbon/alien/humanoid/blob_act() - if (stat == 2) - return - var/shielded = 0 - var/damage = null - if (stat != 2) - damage = rand(30,40) - - if(shielded) - damage /= 4 - - - show_message("\red The blob attacks!") - - adjustFireLoss(damage) - - return - - -/mob/living/carbon/alien/humanoid/meteorhit(O as obj) - for(var/mob/M in viewers(src, null)) - if ((M.client && !( M.blinded ))) - M.show_message(text("\red [] has been hit by []", src, O), 1) - if (health > 0) - adjustFireLoss((istype(O, /obj/effect/meteor/small) ? 10 : 25)) - adjustFireLoss(30) - - updatehealth() - return - -/mob/living/carbon/alien/humanoid/attack_paw(mob/living/carbon/monkey/M as mob) - if(!ismonkey(M)) return//Fix for aliens receiving double messages when attacking other aliens. - - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - ..() - - switch(M.a_intent) - - if ("help") - help_shake_act(M) - else - if (istype(wear_mask, /obj/item/clothing/mask/muzzle)) - 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("\red [M.name] has bit [src]!"), 1) - adjustBruteLoss(rand(1, 3)) - updatehealth() - return - - -/mob/living/carbon/alien/humanoid/attack_slime(mob/living/carbon/slime/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if(M.Victim) return // can't attack while eating! - - 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) - - var/damage = rand(1, 3) - - if(M.is_adult) - damage = rand(10, 40) - else - damage = rand(5, 35) - - adjustBruteLoss(damage) - - if(M.powerlevel > 0) - var/stunprob = 10 - var/power = M.powerlevel + rand(0,3) - - switch(M.powerlevel) - if(1 to 2) stunprob = 20 - if(3 to 4) stunprob = 30 - if(5 to 6) stunprob = 40 - if(7 to 8) stunprob = 60 - if(9) stunprob = 70 - if(10) stunprob = 95 - - if(prob(stunprob)) - 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) - - Weaken(power) - if (stuttering < power) - stuttering = power - Stun(power) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() - - if (prob(stunprob) && M.powerlevel >= 8) - adjustFireLoss(M.powerlevel * rand(6,10)) - - - updatehealth() - - return - -/mob/living/carbon/alien/humanoid/attack_animal(mob/living/simple_animal/M as mob) - if(M.melee_damage_upper == 0) - M.emote("[M.friendly] [src]") - 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) - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - adjustBruteLoss(damage) - updatehealth() - -/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - ..() - - if(M.gloves && istype(M.gloves,/obj/item/clothing/gloves)) - var/obj/item/clothing/gloves/G = M.gloves - if(G.cell) - if(M.a_intent == "hurt")//Stungloves. Any contact will stun the alien. - if(G.cell.charge >= 2500) - G.cell.use(2500) - - Weaken(5) - if (stuttering < 5) - stuttering = 5 - Stun(5) - - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\red [src] has been touched with the stun gloves by [M]!", 1, "\red You hear someone fall.", 2) - return - else - M << "\red Not enough charge! " - return - - switch(M.a_intent) - - if ("help") - if (health > 0) - help_shake_act(M) - else - if (M.health >= -75.0) - if (((M.head && M.head.flags & 4) || ((M.wear_mask && !( M.wear_mask.flags & 32 )) || ((head && head.flags & 4) || (wear_mask && !( wear_mask.flags & 32 )))))) - M << "\blue Remove that mask!" - return - var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human( ) - O.source = M - O.target = src - O.s_loc = M.loc - O.t_loc = loc - O.place = "CPR" - requests += O - spawn( 0 ) - O.process() - return - - if ("grab") - if (M == src || anchored) - return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src) - - M.put_in_active_hand(G) - - grabbed_by += G - G.synch() - - 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) - - if ("hurt") - var/damage = rand(1, 9) - if (prob(90)) - if (HULK in M.mutations)//HULK SMASH - damage += 14 - spawn(0) - Weaken(damage) // Why can a hulk knock an alien out but not knock out a human? Damage is robust enough. - step_away(src,M,15) - 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) - if (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) - 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) - - 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) - 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) - 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) - return - -/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other. -As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble. -In all, this is a lot like the monkey code. /N -*/ - -/mob/living/carbon/alien/humanoid/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - ..() - - switch(M.a_intent) - - if ("help") - sleeping = max(0,sleeping-5) - resting = 0 - 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) - - 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("\red [M.name] has bit []!", src), 1) - adjustBruteLoss(damage) - updatehealth() - else - M << "\green [name] is too injured for that." - return - - -/mob/living/carbon/alien/humanoid/restrained() - if (handcuffed) - return 1 - return 0 - - -/mob/living/carbon/alien/humanoid/var/co2overloadtime = null -/mob/living/carbon/alien/humanoid/var/temperature_resistance = T0C+75 - -/mob/living/carbon/alien/humanoid/show_inv(mob/user as mob) - - user.set_machine(src) - var/dat = {" -
[name]
-

-
Left Hand: [(l_hand ? text("[]", l_hand) : "Nothing")] -
Right Hand: [(r_hand ? text("[]", r_hand) : "Nothing")] -
Head: [(head ? text("[]", head) : "Nothing")] -
(Exo)Suit: [(wear_suit ? text("[]", wear_suit) : "Nothing")] -
Empty Pouches -
Close -
"} - user << browse(dat, text("window=mob[name];size=340x480")) - onclose(user, "mob[name]") - return - - diff --git a/code/modules/mob/living/carbon/alien/humanoid/inventory.dm b/code/modules/mob/living/carbon/alien/humanoid/inventory.dm deleted file mode 100644 index 0e03bf68923..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/inventory.dm +++ /dev/null @@ -1,54 +0,0 @@ -//unequip -/mob/living/carbon/alien/humanoid/u_equip(obj/item/W as obj) - if (W == wear_suit) - wear_suit = null - update_inv_wear_suit(0) - else if (W == head) - head = null - update_inv_head(0) - else if (W == r_store) - r_store = null - update_inv_pockets(0) - else if (W == l_store) - l_store = null - update_inv_pockets(0) - else if (W == r_hand) - r_hand = null - update_inv_r_hand(0) - else if (W == l_hand) - l_hand = null - update_inv_l_hand(0) - -/mob/living/carbon/alien/humanoid/attack_ui(slot_id) - var/obj/item/W = get_active_hand() - if(W) - if(!istype(W)) return - switch(slot_id) -// if("o_clothing") -// if("head") - if(slot_l_store) - if(l_store) - return - if(W.w_class > 3) - return - u_equip(W) - l_store = W - update_inv_pockets() - if(slot_r_store) - if(r_store) - return - if(W.w_class > 3) - return - u_equip(W) - r_store = W - update_inv_pockets() - else - switch(slot_id) - if(slot_wear_suit) - if(wear_suit) wear_suit.attack_alien(src) - if(slot_head) - if(head) head.attack_alien(src) - if(slot_l_store) - if(l_store) l_store.attack_alien(src) - if(slot_r_store) - if(r_store) r_store.attack_alien(src) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/life.dm b/code/modules/mob/living/carbon/alien/humanoid/life.dm deleted file mode 100644 index f1910fcfe30..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/life.dm +++ /dev/null @@ -1,453 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/mob/living/carbon/alien/humanoid - oxygen_alert = 0 - phoron_alert = 0 - fire_alert = 0 - - var/temperature_alert = 0 - - -/mob/living/carbon/alien/humanoid/Life() - set invisibility = 0 - set background = 1 - - if (monkeyizing) - return - - ..() - - var/datum/gas_mixture/environment = loc.return_air() - - if (stat != DEAD) //still breathing - - //First, resolve location and get a breath - - if(air_master.current_cycle%4==2) - //Only try to take a breath every 4 seconds, unless suffocating - spawn(0) breathe() - - 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) - - //Mutations and radiation - handle_mutations_and_radiation() - - //Chemicals in the body - handle_chemicals_in_body() - - //Disabilities - handle_disabilities() - - //Apparently, the person who wrote this code designed it so that - //blinded get reset each cycle and then get activated later in the - //code. Very ugly. I dont care. Moving this stuff here so its easy - //to find it. - blinded = null - - //Handle temperature/pressure differences between body and environment - handle_environment(environment) - - //stuff in the stomach - handle_stomach() - - - //Status updates, death etc. - handle_regular_status_updates() - update_canmove() - - // Grabbing - for(var/obj/item/weapon/grab/G in src) - G.process() - - if(client) - handle_regular_hud_updates() - - -/mob/living/carbon/alien/humanoid - proc/handle_disabilities() - if (disabilities & EPILEPSY) - if ((prob(1) && paralysis < 10)) - src << "\red You have a seizure!" - Paralyse(10) - if (disabilities & COUGHING) - if ((prob(5) && paralysis <= 1)) - drop_item() - spawn( 0 ) - emote("cough") - return - if (disabilities & TOURETTES) - if ((prob(10) && paralysis <= 1)) - Stun(10) - spawn( 0 ) - emote("twitch") - return - if (disabilities & NERVOUS) - if (prob(10)) - stuttering = max(10, stuttering) - - - proc/breathe() - if(reagents) - 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 < 0) - losebreath++ - - if(losebreath>0) //Suffocating so do not take a breath - losebreath-- - if (prob(75)) //High chance of gasping for air - 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) - - //No breath from internal atmosphere so get breath from location - if(!breath) - if(istype(loc, /obj/)) - var/obj/location_as_object = loc - breath = location_as_object.handle_internal_lifeform(src, BREATH_VOLUME) - else if(istype(loc, /turf/)) - 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 - for(var/obj/effect/effect/smoke/chem/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) - - - proc/get_breath_from_internal(volume_needed) - if(internal) - if (!contents.Find(internal)) - internal = null - if (!wear_mask || !(wear_mask.flags & MASKINTERNALS) ) - internal = null - if(internal) - if (internals) - internals.icon_state = "internal1" - return internal.remove_air_volume(volume_needed) - else - if (internals) - internals.icon_state = "internal0" - return null - - proc/handle_breath(datum/gas_mixture/breath) - if(status_flags & GODMODE) - return - - if(!breath || (breath.total_moles == 0)) - //Aliens breathe in vaccuum - return 0 - - var/phoron_used = 0 - var/breath_pressure = (breath.total_moles * R_IDEAL_GAS_EQUATION * breath.temperature) / BREATH_VOLUME - - //Partial pressure of the phoron in our breath - var/Toxins_pp = (breath.gas["phoron"] / breath.total_moles) * breath_pressure - - if(Toxins_pp) // Detect phoron in air - - adjustToxLoss(breath.gas["phoron"] * 250) - phoron_alert = max(phoron_alert, 1) - - phoron_used = breath.gas["phoron"] - - else - phoron_alert = 0 - - //Breathe in phoron and out oxygen - breath.adjust_gas("phoron", -phoron_used) - breath.adjust_gas("oxygen", phoron_used) - - if(breath.temperature > (T0C+66) && !(COLD_RESISTANCE in mutations)) // Hot air hurts :( - if(prob(20)) - src << "\red You feel a searing heat in your lungs!" - fire_alert = max(fire_alert, 1) - else - fire_alert = 0 - - //Temporary fixes to the alerts. - - return 1 - - - - proc/adjust_body_temperature(current, loc_temp, boost) - var/temperature = current - var/difference = abs(current-loc_temp) //get difference - var/increments// = difference/10 //find how many increments apart they are - if(difference > 50) - increments = difference/5 - else - increments = difference/10 - var/change = increments*boost // Get the amount to change by (x per increment) - var/temp_change - if(current < loc_temp) - temperature = min(loc_temp, temperature+change) - else if(current > loc_temp) - temperature = max(loc_temp, temperature-change) - temp_change = (temperature - current) - return temp_change - - /* - proc/get_thermal_protection() - var/thermal_protection = 1.0 - //Handle normal clothing - if(head && (head.body_parts_covered & HEAD)) - thermal_protection += 0.5 - if(wear_suit && (wear_suit.body_parts_covered & UPPER_TORSO)) - thermal_protection += 0.5 - if(wear_suit && (wear_suit.body_parts_covered & LEGS)) - thermal_protection += 0.2 - if(wear_suit && (wear_suit.body_parts_covered & ARMS)) - thermal_protection += 0.2 - if(wear_suit && (wear_suit.body_parts_covered & HANDS)) - thermal_protection += 0.2 - if(wear_suit && (wear_suit.flags & SUITSPACE)) - thermal_protection += 3 - if(COLD_RESISTANCE in mutations) - thermal_protection += 5 - - return thermal_protection - - proc/add_fire_protection(var/temp) - var/fire_prot = 0 - if(head) - if(head.protective_temperature > temp) - fire_prot += (head.protective_temperature/10) - if(wear_mask) - if(wear_mask.protective_temperature > temp) - fire_prot += (wear_mask.protective_temperature/10) - if(wear_suit) - if(wear_suit.protective_temperature > temp) - fire_prot += (wear_suit.protective_temperature/10) - - - return fire_prot - */ - - proc/handle_chemicals_in_body() - - if(reagents) reagents.metabolize(src) - - if(FAT in mutations) - if(nutrition < 100) - if(prob(round((50 - nutrition) / 100))) - src << "\blue You feel fit again!" - mutations.Remove(FAT) -/* else - if(nutrition > 500) - if(prob(5 + round((nutrition - 200) / 2))) - src << "\red You suddenly feel blubbery!" - mutations.Add(FAT) - FUCK YOU FATCODE -Hawk */ - if (nutrition > 0) - nutrition -= HUNGER_FACTOR - - 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 - 5) - jitteriness = max(0, jitteriness - 5) - else - dizziness = max(0, dizziness - 1) - jitteriness = max(0, jitteriness - 1) - - updatehealth() - - return //TODO: DEFERRED - - - proc/handle_regular_status_updates() - updatehealth() - - if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP - blinded = 1 - silent = 0 - else //ALIVE. LIGHTS ARE ON - if(health < config.health_threshold_dead || !has_brain()) - death() - blinded = 1 - stat = DEAD - silent = 0 - return 1 - - //UNCONSCIOUS. NO-ONE IS HOME - if( (getOxyLoss() > 50) || (config.health_threshold_crit > health) ) - if( health <= 20 && prob(1) ) - spawn(0) - emote("gasp") - if(!reagents.has_reagent("inaprovaline")) - adjustOxyLoss(1) - Paralyse(3) - - if(paralysis) - AdjustParalysis(-1) - blinded = 1 - stat = UNCONSCIOUS - else if(sleeping) - sleeping = max(sleeping-1, 0) - blinded = 1 - stat = UNCONSCIOUS - if( prob(10) && health ) - spawn(0) - emote("hiss") - //CONSCIOUS - else - stat = CONSCIOUS - - /* What in the living hell is this?*/ - if(move_delay_add > 0) - move_delay_add = max(0, move_delay_add - rand(1, 2)) - - //Eyes - if(sdisabilities & BLIND) //disabled-blind, doesn't get better on its own - blinded = 1 - else if(eye_blind) //blindness, heals slowly over time - eye_blind = max(eye_blind-1,0) - blinded = 1 - else if(eye_blurry) //blurry eyes heal slowly - eye_blurry = max(eye_blurry-1, 0) - - //Ears - if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own - ear_deaf = max(ear_deaf, 1) - else if(ear_deaf) //deafness, heals slowly over time - ear_deaf = max(ear_deaf-1, 0) - else if(ear_damage < 25) //ear damage heals slowly under this threshold. otherwise you'll need earmuffs - ear_damage = max(ear_damage-0.05, 0) - - //Other - handle_statuses() - return 1 - - - proc/handle_regular_hud_updates() - - if (stat == 2 || (XRAY in mutations)) - sight |= SEE_TURFS - sight |= SEE_MOBS - sight |= SEE_OBJS - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_LEVEL_TWO - else if (stat != 2) - sight |= SEE_MOBS - sight &= ~SEE_TURFS - sight &= ~SEE_OBJS - see_in_dark = 4 - see_invisible = SEE_INVISIBLE_LEVEL_TWO - - if (healths) - if (stat != 2) - switch(health) - if(100 to INFINITY) - healths.icon_state = "health0" - if(75 to 100) - healths.icon_state = "health1" - if(50 to 75) - healths.icon_state = "health2" - if(25 to 50) - healths.icon_state = "health3" - if(0 to 25) - healths.icon_state = "health4" - else - healths.icon_state = "health5" - else - healths.icon_state = "health6" - - if(pullin) pullin.icon_state = "pull[pulling ? 1 : 0]" - - - if (toxin) toxin.icon_state = "tox[phoron_alert ? 1 : 0]" - if (oxygen) oxygen.icon_state = "oxy[oxygen_alert ? 1 : 0]" - if (fire) fire.icon_state = "fire[fire_alert ? 1 : 0]" - //NOTE: the alerts dont reset when youre out of danger. dont blame me, - //blame the person who coded them. Temporary fix added. - if (client) - client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired) - - if ((blind && stat != 2)) - if ((blinded)) - blind.layer = 18 - else - blind.layer = 0 - - if (disabilities & NEARSIGHTED) - client.screen += global_hud.vimpaired - - if (eye_blurry) - client.screen += global_hud.blurry - - if (druggy) - client.screen += global_hud.druggy - - if (stat != 2) - if (machine) - if (!( machine.check_eye(src) )) - reset_view(null) - else - if(client && !client.adminobs) - reset_view(null) - - return 1 - - proc/handle_stomach() - spawn(0) - for(var/mob/living/M in stomach_contents) - if(M.loc != src) - stomach_contents.Remove(M) - continue - if(istype(M, /mob/living/carbon) && stat != 2) - if(M.stat == 2) - M.death(1) - stomach_contents.Remove(M) - del(M) - continue - if(air_master.current_cycle%3==1) - if(!(status_flags & GODMODE)) - M.adjustBruteLoss(5) - nutrition += 10 - -/mob/living/carbon/alien/humanoid/handle_stunned() - if(stunned && !..()) - update_icons() - return stunned diff --git a/code/modules/mob/living/carbon/alien/humanoid/login.dm b/code/modules/mob/living/carbon/alien/humanoid/login.dm deleted file mode 100644 index 607a03fef0f..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/login.dm +++ /dev/null @@ -1,7 +0,0 @@ -/mob/living/carbon/alien/humanoid/Login() - ..() - update_hud() - if(!isturf(loc)) - client.eye = loc - client.perspective = EYE_PERSPECTIVE - return diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm deleted file mode 100644 index 1b98392b814..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ /dev/null @@ -1,92 +0,0 @@ -/mob/living/carbon/alien/humanoid/queen - name = "alien queen" - caste = "q" - maxHealth = 250 - health = 250 - icon_state = "alienq_s" - status_flags = CANPARALYSE - heal_rate = 5 - plasma_rate = 20 - - -/mob/living/carbon/alien/humanoid/queen/New() - var/datum/reagents/R = new/datum/reagents(100) - reagents = R - R.my_atom = src - - //there should only be one queen - for(var/mob/living/carbon/alien/humanoid/queen/Q in living_mob_list) - if(Q == src) continue - if(Q.stat == DEAD) continue - if(Q.client) - name = "alien princess ([rand(1, 999)])" //if this is too cutesy feel free to change it/remove it. - break - - real_name = src.name - verbs.Add(/mob/living/carbon/alien/humanoid/proc/corrosive_acid,/mob/living/carbon/alien/humanoid/proc/neurotoxin,/mob/living/carbon/alien/humanoid/proc/resin) - verbs -= /mob/living/carbon/alien/verb/ventcrawl - ..() - - -/mob/living/carbon/alien/humanoid/queen - - handle_regular_hud_updates() - - ..() //-Yvarov - - if (src.healths) - if (src.stat != 2) - switch(health) - if(250 to INFINITY) - src.healths.icon_state = "health0" - if(175 to 250) - src.healths.icon_state = "health1" - if(100 to 175) - src.healths.icon_state = "health2" - if(50 to 100) - src.healths.icon_state = "health3" - if(0 to 50) - src.healths.icon_state = "health4" - else - src.healths.icon_state = "health5" - else - src.healths.icon_state = "health6" - - -//Queen verbs -/mob/living/carbon/alien/humanoid/queen/verb/lay_egg() - - set name = "Lay Egg (75)" - set desc = "Lay an egg to produce huggers to impregnate prey with." - set category = "Alien" - - if(locate(/obj/effect/alien/egg) in get_turf(src)) - src << "There's already an egg here." - return - - if(powerc(75,1))//Can't plant eggs on spess tiles. That's silly. - adjustToxLoss(-75) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\green [src] has laid an egg!"), 1) - new /obj/effect/alien/egg(loc) - return - - -/mob/living/carbon/alien/humanoid/queen/large - icon = 'icons/mob/alienqueen.dmi' - icon_state = "queen_s" - pixel_x = -16 - -/mob/living/carbon/alien/humanoid/queen/large/update_icons() - lying_prev = lying //so we don't update overlays for lying/standing unless our stance changes again - update_hud() //TODO: remove the need for this to be here - overlays.Cut() - if(lying) - if(resting) icon_state = "queen_sleep" - else icon_state = "queen_l" - for(var/image/I in overlays_lying) - overlays += I - else - icon_state = "queen_s" - for(var/image/I in overlays_standing) - overlays += I \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm deleted file mode 100644 index 57d0300b39d..00000000000 --- a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm +++ /dev/null @@ -1,154 +0,0 @@ -//Xeno Overlays Indexes////////// -#define X_HEAD_LAYER 1 -#define X_SUIT_LAYER 2 -#define X_L_HAND_LAYER 3 -#define X_R_HAND_LAYER 4 -#define TARGETED_LAYER 5 -#define X_TOTAL_LAYERS 5 -///////////////////////////////// - -/mob/living/carbon/alien/humanoid - var/list/overlays_lying[X_TOTAL_LAYERS] - var/list/overlays_standing[X_TOTAL_LAYERS] - -/mob/living/carbon/alien/humanoid/update_icons() - lying_prev = lying //so we don't update overlays for lying/standing unless our stance changes again - update_hud() //TODO: remove the need for this to be here - overlays.Cut() - if(stat == DEAD) - //If we mostly took damage from fire - if(fireloss > 125) - icon_state = "alien[caste]_husked" - else - icon_state = "alien[caste]_dead" - for(var/image/I in overlays_lying) - overlays += I - else if(lying) - if(resting) - icon_state = "alien[caste]_sleep" - else if(stat == UNCONSCIOUS) - icon_state = "alien[caste]_unconscious" - else - icon_state = "alien[caste]_l" - for(var/image/I in overlays_lying) - overlays += I - else - if(m_intent == "run") icon_state = "alien[caste]_running" - else icon_state = "alien[caste]_s" - for(var/image/I in overlays_standing) - overlays += I - -/mob/living/carbon/alien/humanoid/regenerate_icons() - ..() - if (monkeyizing) return - - update_inv_head(0) - update_inv_wear_suit(0) - update_inv_r_hand(0) - update_inv_l_hand(0) - update_inv_pockets(0) - update_hud() - update_icons() - - -/mob/living/carbon/alien/humanoid/update_hud() - //TODO - if (client) -// if(other) client.screen |= hud_used.other //Not used -// else client.screen -= hud_used.other //Not used - client.screen |= contents - - - -/mob/living/carbon/alien/humanoid/update_inv_wear_suit(var/update_icons=1) - if(wear_suit) - var/t_state = wear_suit.item_state - if(!t_state) t_state = wear_suit.icon_state - var/image/lying = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]2") - var/image/standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]") - - if(wear_suit.blood_DNA) - var/t_suit = "suit" - if( istype(wear_suit, /obj/item/clothing/suit/armor) ) - t_suit = "armor" - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "[t_suit]blood2") - standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "[t_suit]blood") - - //TODO - wear_suit.screen_loc = ui_alien_oclothing - if (istype(wear_suit, /obj/item/clothing/suit/straight_jacket)) - drop_from_inventory(handcuffed) - drop_r_hand() - drop_l_hand() - - overlays_lying[X_SUIT_LAYER] = lying - overlays_standing[X_SUIT_LAYER] = standing - else - overlays_lying[X_SUIT_LAYER] = null - overlays_standing[X_SUIT_LAYER] = null - if(update_icons) update_icons() - - -/mob/living/carbon/alien/humanoid/update_inv_head(var/update_icons=1) - if (head) - var/t_state = head.item_state - if(!t_state) t_state = head.icon_state - var/image/lying = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]2") - var/image/standing = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "[t_state]") - if(head.blood_DNA) - lying.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "helmetblood2") - standing.overlays += image("icon" = 'icons/effects/blood.dmi', "icon_state" = "helmetblood") - head.screen_loc = ui_alien_head - overlays_lying[X_HEAD_LAYER] = lying - overlays_standing[X_HEAD_LAYER] = standing - else - overlays_lying[X_HEAD_LAYER] = null - overlays_standing[X_HEAD_LAYER] = null - if(update_icons) update_icons() - - -/mob/living/carbon/alien/humanoid/update_inv_pockets(var/update_icons=1) - if(l_store) l_store.screen_loc = ui_storage1 - if(r_store) r_store.screen_loc = ui_storage2 - if(update_icons) update_icons() - - -/mob/living/carbon/alien/humanoid/update_inv_r_hand(var/update_icons=1) - if(r_hand) - var/t_state = r_hand.item_state - if(!t_state) t_state = r_hand.icon_state - r_hand.screen_loc = ui_rhand - overlays_standing[X_R_HAND_LAYER] = image("icon" = 'icons/mob/items_righthand.dmi', "icon_state" = t_state) - else - overlays_standing[X_R_HAND_LAYER] = null - if(update_icons) update_icons() - -/mob/living/carbon/alien/humanoid/update_inv_l_hand(var/update_icons=1) - if(l_hand) - var/t_state = l_hand.item_state - if(!t_state) t_state = l_hand.icon_state - l_hand.screen_loc = ui_lhand - overlays_standing[X_L_HAND_LAYER] = image("icon" = 'icons/mob/items_lefthand.dmi', "icon_state" = t_state) - else - overlays_standing[X_L_HAND_LAYER] = null - if(update_icons) update_icons() - -//Call when target overlay should be added/removed -/mob/living/carbon/alien/humanoid/update_targeted(var/update_icons=1) - if (targeted_by && target_locked) - overlays_lying[TARGETED_LAYER] = target_locked - overlays_standing[TARGETED_LAYER] = target_locked - else if (!targeted_by && target_locked) - del(target_locked) - if (!targeted_by) - overlays_lying[TARGETED_LAYER] = null - overlays_standing[TARGETED_LAYER] = null - if(update_icons) update_icons() - -//Xeno Overlays Indexes////////// -#undef X_HEAD_LAYER -#undef X_SUIT_LAYER -#undef X_L_HAND_LAYER -#undef X_R_HAND_LAYER -#undef TARGETED_LAYER -#undef X_TOTAL_LAYERS diff --git a/code/modules/mob/living/carbon/alien/larva/death.dm b/code/modules/mob/living/carbon/alien/larva/death.dm deleted file mode 100644 index 27f49e3ad9e..00000000000 --- a/code/modules/mob/living/carbon/alien/larva/death.dm +++ /dev/null @@ -1,15 +0,0 @@ -/mob/living/carbon/alien/larva/death(gibbed) - if(stat == DEAD) return - if(healths) healths.icon_state = "health6" - stat = DEAD - icon_state = "larva_dead" - - if(!gibbed) - update_canmove() - if(client) blind.layer = 0 - - tod = worldtime2text() //weasellos time of death patch - if(mind) mind.store_memory("Time of death: [tod]", 0) - living_mob_list -= src - - return ..(gibbed) diff --git a/code/modules/mob/living/carbon/alien/larva/inventory.dm b/code/modules/mob/living/carbon/alien/larva/inventory.dm deleted file mode 100644 index 076053b2530..00000000000 --- a/code/modules/mob/living/carbon/alien/larva/inventory.dm +++ /dev/null @@ -1,3 +0,0 @@ -//can't unequip since it can't equip anything -/mob/living/carbon/alien/larva/u_equip(obj/item/W as obj) - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 9f5640c69b1..c811fd2b09e 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -1,375 +1,19 @@ /mob/living/carbon/alien/larva name = "alien larva" real_name = "alien larva" - icon_state = "larva0" - pass_flags = PASSTABLE + adult_form = /mob/living/carbon/human + speak_emote = list("hisses") + icon_state = "larva" + language = "Hivemind" + melee_damage_lower = 3 + melee_damage_upper = 6 + + amount_grown = 0 + max_grown = 200 maxHealth = 25 health = 25 - storedPlasma = 50 - max_plasma = 50 - var/amount_grown = 0 - var/max_grown = 200 - var/time_of_birth - -//This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/larva/New() - var/datum/reagents/R = new/datum/reagents(100) - reagents = R - R.my_atom = src - if(name == "alien larva") - name = "alien larva ([rand(1, 1000)])" - real_name = name - regenerate_icons() ..() - -//This is fine, works the same as a human -/mob/living/carbon/alien/larva/Bump(atom/movable/AM as mob|obj, yes) - - spawn( 0 ) - if ((!( yes ) || now_pushing)) - return - now_pushing = 1 - if(ismob(AM)) - var/mob/tmob = AM - if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations)) - if(prob(70)) - src << "\red You fail to push [tmob]'s fat ass out of the way." - now_pushing = 0 - return - if(!(tmob.status_flags & CANPUSH)) - now_pushing = 0 - return - tmob.LAssailant = src - - now_pushing = 0 - ..() - if (!( istype(AM, /atom/movable) )) - return - if (!( now_pushing )) - now_pushing = 1 - if (!( AM.anchored )) - var/t = get_dir(src, AM) - step(AM, t) - now_pushing = null - return - return - -//This needs to be fixed -/mob/living/carbon/alien/larva/Stat() - ..() - stat(null, "Progress: [amount_grown]/[max_grown]") - -/mob/living/carbon/alien/larva/adjustToxLoss(amount) - if(stat != DEAD) - amount_grown = min(amount_grown + 1, max_grown) - ..(amount) - - -/mob/living/carbon/alien/larva/ex_act(severity) - if(!blinded) - flick("flash", flash) - - var/b_loss = null - var/f_loss = null - switch (severity) - if (1.0) - b_loss += 500 - gib() - return - - if (2.0) - - b_loss += 60 - - f_loss += 60 - - ear_damage += 30 - ear_deaf += 120 - - if(3.0) - b_loss += 30 - if (prob(50)) - Paralyse(1) - ear_damage += 15 - ear_deaf += 60 - - adjustBruteLoss(b_loss) - adjustFireLoss(f_loss) - - updatehealth() - - - -/mob/living/carbon/alien/larva/blob_act() - if (stat == 2) - return - var/shielded = 0 - - var/damage = null - if (stat != 2) - damage = rand(10,30) - - if(shielded) - damage /= 4 - - //paralysis += 1 - - show_message("\red The blob attacks you!") - - adjustFireLoss(damage) - - updatehealth() - return - - -//can't equip anything -/mob/living/carbon/alien/larva/attack_ui(slot_id) - return - -/mob/living/carbon/alien/larva/meteorhit(O as obj) - for(var/mob/M in viewers(src, null)) - if ((M.client && !( M.blinded ))) - M.show_message(text("\red [] has been hit by []", src, O), 1) - if (health > 0) - adjustBruteLoss((istype(O, /obj/effect/meteor/small) ? 10 : 25)) - adjustFireLoss(30) - - updatehealth() - return - - -/mob/living/carbon/alien/larva/attack_animal(mob/living/simple_animal/M as mob) - 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) - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - adjustBruteLoss(damage) - M.attack_log += text("\[[time_stamp()]\] attacked [src.name] ([src.ckey])") - src.attack_log += text("\[[time_stamp()]\] was attacked by [M.name] ([M.ckey])") - updatehealth() - - - -/mob/living/carbon/alien/larva/attack_paw(mob/living/carbon/monkey/M as mob) - if(!(istype(M, /mob/living/carbon/monkey))) return//Fix for aliens receiving double messages when attacking other aliens. - - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - ..() - - switch(M.a_intent) - - if ("help") - help_shake_act(M) - else - if (istype(wear_mask, /obj/item/clothing/mask/muzzle)) - 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("\red [M.name] has bit [src]!"), 1) - adjustBruteLoss(rand(1, 3)) - updatehealth() - return - - -/mob/living/carbon/alien/larva/attack_slime(mob/living/carbon/slime/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if(M.Victim) return // can't attack while eating! - - 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) - - var/damage = rand(1, 3) - - if(M.is_adult) - damage = rand(20, 40) - else - damage = rand(5, 35) - - adjustBruteLoss(damage) - - - updatehealth() - - return - -/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - ..() - - if(M.gloves && istype(M.gloves,/obj/item/clothing/gloves)) - var/obj/item/clothing/gloves/G = M.gloves - if(G.cell) - if(M.a_intent == "hurt")//Stungloves. Any contact will stun the alien. - if(G.cell.charge >= 2500) - G.cell.use(2500) - - Weaken(5) - if (stuttering < 5) - stuttering = 5 - Stun(5) - - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message("\red [src] has been touched with the stun gloves by [M]!", 1, "\red You hear someone fall.", 2) - return - else - M << "\red Not enough charge! " - return - - switch(M.a_intent) - - if ("help") - if (health > 0) - help_shake_act(M) - else - if (M.health >= -75.0) - if ((M.head && M.head.flags & 4) || (M.wear_mask && !( M.wear_mask.flags & 32 )) ) - M << "\blue Remove that mask!" - return - var/obj/effect/equip_e/human/O = new /obj/effect/equip_e/human( ) - O.source = M - O.target = src - O.s_loc = M.loc - O.t_loc = loc - O.place = "CPR" - requests += O - spawn( 0 ) - O.process() - return - - if ("grab") - if (M == src) - return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src ) - - M.put_in_active_hand(G) - - grabbed_by += G - G.synch() - - 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) - - else - var/damage = rand(1, 9) - if (prob(90)) - if (HULK in M.mutations) - damage += 5 - spawn(0) - Paralyse(1) - step_away(src,M,15) - 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) - if (damage > 4.9) - Weaken(rand(10,15)) - 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) - 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) - return - -/mob/living/carbon/alien/larva/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - ..() - - switch(M.a_intent) - - if ("help") - sleeping = max(0,sleeping-5) - resting = 0 - 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) - - 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("\red [M.name] has bit []!", src), 1) - adjustBruteLoss(damage) - updatehealth() - else - M << "\green [name] is too injured for that." - return - -/mob/living/carbon/alien/larva/restrained() - return 0 - -/mob/living/carbon/alien/larva/var/co2overloadtime = null -/mob/living/carbon/alien/larva/var/temperature_resistance = T0C+75 - -// new damage icon system -// now constructs damage icon for each organ from mask * damage field - - -/mob/living/carbon/alien/larva/show_inv(mob/user as mob) - - user.set_machine(src) - var/dat = {" -
[name]
-


-
Close -
"} - user << browse(dat, text("window=mob[name];size=340x480")) - onclose(user, "mob[name]") - return - -/* Commented out because it's duplicated in life.dm -/mob/living/carbon/alien/larva/proc/grow() // Larvae can grow into full fledged Xenos if they survive long enough -- TLE - if(icon_state == "larva_l" && !canmove) // This is a shit death check. It is made of shit and death. Fix later. - return - else - var/mob/living/carbon/alien/humanoid/A = new(loc) - A.key = key - del(src) */ \ No newline at end of file + add_language("Rootspeak") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm deleted file mode 100644 index 97abbdec382..00000000000 --- a/code/modules/mob/living/carbon/alien/larva/life.dm +++ /dev/null @@ -1,369 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/mob/living/carbon/alien/larva - - var/temperature_alert = 0 - - -/mob/living/carbon/alien/larva/Life() - set invisibility = 0 - set background = 1 - - if (monkeyizing) - return - - ..() - var/datum/gas_mixture/enviroment = loc.return_air() - if (stat != DEAD) //still breathing - - // GROW! - if(amount_grown < max_grown) - amount_grown++ - - //First, resolve location and get a breath - if(air_master.current_cycle%4==2) - //Only try to take a breath every 4 seconds, unless suffocating - spawn(0) breathe() - 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) - //Mutations and radiation - handle_mutations_and_radiation() - - //Chemicals in the body - handle_chemicals_in_body() - - - //Apparently, the person who wrote this code designed it so that - //blinded get reset each cycle and then get activated later in the - //code. Very ugly. I dont care. Moving this stuff here so its easy - //to find it. - blinded = null - - //Handle temperature/pressure differences between body and environment - handle_environment(enviroment) - - //stuff in the stomach - //handle_stomach() - - //Status updates, death etc. - handle_regular_status_updates() - update_canmove() - - // Grabbing - for(var/obj/item/weapon/grab/G in src) - G.process() - - //some kind of bug in canmove() isn't properly calling update_icons, so this is here as a placeholder - update_icons() - - if(client) - handle_regular_hud_updates() - - -/mob/living/carbon/alien/larva - - proc/breathe() - - 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 < 0) - losebreath++ - - if(losebreath>0) //Suffocating so do not take a breath - losebreath-- - if (prob(75)) //High chance of gasping for air - 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) - - //No breath from internal atmosphere so get breath from location - if(!breath) - if(istype(loc, /obj/)) - var/obj/location_as_object = loc - breath = location_as_object.handle_internal_lifeform(src, BREATH_VOLUME) - else if(istype(loc, /turf/)) - 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 - for(var/obj/effect/effect/smoke/chem/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) - - - proc/get_breath_from_internal(volume_needed) - if(internal) - if (!contents.Find(internal)) - internal = null - if (!wear_mask || !(wear_mask.flags & MASKINTERNALS) ) - internal = null - if(internal) - if (internals) - internals.icon_state = "internal1" - return internal.remove_air_volume(volume_needed) - else - if (internals) - internals.icon_state = "internal0" - return null - - proc/handle_breath(datum/gas_mixture/breath) - if(status_flags & GODMODE) - return - - if(!breath || (breath.total_moles == 0)) - //Aliens breathe in vaccuum - return 0 - - var/phoron_used = 0 - var/breath_pressure = (breath.total_moles * R_IDEAL_GAS_EQUATION * breath.temperature) / BREATH_VOLUME - - //Partial pressure of the phoron in our breath - var/Toxins_pp = (breath.gas["phoron"] / breath.total_moles) * breath_pressure - - if(Toxins_pp) // Detect phoron in air - - adjustToxLoss(breath.gas["phoron"] * 250) - phoron_alert = max(phoron_alert, 1) - - phoron_used = breath.gas["phoron"] - - else - phoron_alert = 0 - - //Breathe in phoron and out oxygen - breath.adjust_gas("phoron", -phoron_used) - breath.adjust_gas("oxygen", phoron_used) - - if(breath.temperature > (T0C+66) && !(COLD_RESISTANCE in mutations)) // Hot air hurts :( - if(prob(20)) - src << "\red You feel a searing heat in your lungs!" - fire_alert = max(fire_alert, 1) - else - fire_alert = 0 - - //Temporary fixes to the alerts. - - return 1 - - - proc/handle_chemicals_in_body() - if(reagents) reagents.metabolize(src) - - if(FAT in mutations) - if(nutrition < 100) - if(prob(round((50 - nutrition) / 100))) - src << "\blue You feel fit again!" - mutations.Add(FAT) -/* else - if(nutrition > 500) - if(prob(5 + round((nutrition - max_grown) / 2))) - src << "\red You suddenly feel blubbery!" - mutations.Add(FAT) -FUCK YOU MORE FAT CODE -Hawk*/ - if (nutrition > 0) - nutrition-= HUNGER_FACTOR - - 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 - 5) - jitteriness = max(0, jitteriness - 5) - else - dizziness = max(0, dizziness - 1) - jitteriness = max(0, jitteriness - 1) - - updatehealth() - - return //TODO: DEFERRED - - proc/handle_regular_status_updates() - updatehealth() - - if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP - blinded = 1 - silent = 0 - else //ALIVE. LIGHTS ARE ON - if(health < -25 || !has_brain()) - death() - blinded = 1 - silent = 0 - return 1 - - //UNCONSCIOUS. NO-ONE IS HOME - if( (getOxyLoss() > 25) || (0 > health) ) - //if( health <= 20 && prob(1) ) - // spawn(0) - // emote("gasp") - if(!reagents.has_reagent("inaprovaline")) - adjustOxyLoss(1) - Paralyse(3) - - if(paralysis) - AdjustParalysis(-2) - blinded = 1 - stat = UNCONSCIOUS - else if(sleeping) - sleeping = max(sleeping-1, 0) - blinded = 1 - stat = UNCONSCIOUS - if( prob(10) && health ) - spawn(0) - emote("hiss_") - //CONSCIOUS - else - stat = CONSCIOUS - - /* What in the living hell is this?*/ - if(move_delay_add > 0) - move_delay_add = max(0, move_delay_add - rand(1, 2)) - - //Eyes - if(sdisabilities & BLIND) //disabled-blind, doesn't get better on its own - blinded = 1 - else if(eye_blind) //blindness, heals slowly over time - eye_blind = max(eye_blind-1,0) - blinded = 1 - else if(eye_blurry) //blurry eyes heal slowly - eye_blurry = max(eye_blurry-1, 0) - - //Ears - if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own - ear_deaf = max(ear_deaf, 1) - else if(ear_deaf) //deafness, heals slowly over time - ear_deaf = max(ear_deaf-1, 0) - else if(ear_damage < 25) //ear damage heals slowly under this threshold. - ear_damage = max(ear_damage-0.05, 0) - - //Other - handle_statuses() - return 1 - - - proc/handle_regular_hud_updates() - - if (stat == 2 || (XRAY in mutations)) - sight |= SEE_TURFS - sight |= SEE_MOBS - sight |= SEE_OBJS - see_in_dark = 8 - see_invisible = SEE_INVISIBLE_LEVEL_TWO - else if (stat != 2) - sight |= SEE_MOBS - sight &= ~SEE_TURFS - sight &= ~SEE_OBJS - see_in_dark = 4 - see_invisible = SEE_INVISIBLE_LEVEL_TWO - - if (healths) - if (stat != 2) - switch(health) - if(25 to INFINITY) - healths.icon_state = "health0" - if(19 to 25) - healths.icon_state = "health1" - if(13 to 19) - healths.icon_state = "health2" - if(7 to 13) - healths.icon_state = "health3" - if(0 to 7) - healths.icon_state = "health4" - else - healths.icon_state = "health5" - else - healths.icon_state = "health6" - - if(pullin) pullin.icon_state = "pull[pulling ? 1 : 0]" - - - if (toxin) toxin.icon_state = "tox[phoron_alert ? 1 : 0]" - if (oxygen) oxygen.icon_state = "oxy[oxygen_alert ? 1 : 0]" - if (fire) fire.icon_state = "fire[fire_alert ? 1 : 0]" - //NOTE: the alerts dont reset when youre out of danger. dont blame me, - //blame the person who coded them. Temporary fix added. - if (client) - client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired) - - if ((blind && stat != 2)) - if ((blinded)) - blind.layer = 18 - else - blind.layer = 0 - - if (disabilities & NEARSIGHTED) - client.screen += global_hud.vimpaired - - if (eye_blurry) - client.screen += global_hud.blurry - - if (druggy) - client.screen += global_hud.druggy - - if (stat != 2) - if (machine) - if (!( machine.check_eye(src) )) - reset_view(null) - else - if(client && !client.adminobs) - reset_view(null) - - return 1 - - proc/handle_random_events() - return - - - proc/handle_stomach() - spawn(0) - for(var/mob/living/M in stomach_contents) - if(M.loc != src) - stomach_contents.Remove(M) - continue - if(istype(M, /mob/living/carbon) && stat != 2) - if(M.stat == 2) - M.death(1) - stomach_contents.Remove(M) - del(M) - continue - if(air_master.current_cycle%3==1) - if(!(M.status_flags & GODMODE)) - M.adjustBruteLoss(5) - nutrition += 10 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/login.dm b/code/modules/mob/living/carbon/alien/larva/login.dm deleted file mode 100644 index 33808a4d966..00000000000 --- a/code/modules/mob/living/carbon/alien/larva/login.dm +++ /dev/null @@ -1,3 +0,0 @@ -/mob/living/carbon/alien/larva/Login() - return ..() - diff --git a/code/modules/mob/living/carbon/alien/larva/powers.dm b/code/modules/mob/living/carbon/alien/larva/powers.dm deleted file mode 100644 index a1806692dfa..00000000000 --- a/code/modules/mob/living/carbon/alien/larva/powers.dm +++ /dev/null @@ -1,56 +0,0 @@ - -/mob/living/carbon/alien/larva/verb/hide() - set name = "Hide" - set desc = "Allows to hide beneath tables or certain items. Toggled on or off." - set category = "Alien" - - if(stat != CONSCIOUS) - return - - if (layer != TURF_LAYER+0.2) - layer = TURF_LAYER+0.2 - src << text("\green You are now hiding.") - for(var/mob/O in oviewers(src, null)) - if ((O.client && !( O.blinded ))) - O << text("[] scurries to the ground!", src) - else - layer = MOB_LAYER - src << text("\green You have stopped hiding.") - for(var/mob/O in oviewers(src, null)) - if ((O.client && !( O.blinded ))) - O << text("[] slowly peaks up from the ground...", src) - -/mob/living/carbon/alien/larva/verb/evolve() - set name = "Evolve" - set desc = "Evolve into a fully grown Alien." - set category = "Alien" - - if(stat != CONSCIOUS) - return - - if(handcuffed || legcuffed) - src << "\red You cannot evolve when you are cuffed." - - if(amount_grown >= max_grown) //TODO ~Carn - //green is impossible to read, so i made these blue and changed the formatting slightly - src << "\blue You are growing into a beautiful alien! It is time to choose a caste." - src << "\blue There are three to choose from:" - src << "Hunters \blue are strong and agile, able to hunt away from the hive and rapidly move through ventilation shafts. Hunters generate plasma slowly and have low reserves." - src << "Sentinels \blue are tasked with protecting the hive and are deadly up close and at a range. They are not as physically imposing nor fast as the hunters." - src << "Drones \blue are the working class, offering the largest plasma storage and generation. They are the only caste which may evolve again, turning into the dreaded alien queen." - var/alien_caste = alert(src, "Please choose which alien caste you shall belong to.",,"Hunter","Sentinel","Drone") - - var/mob/living/carbon/alien/humanoid/new_xeno - switch(alien_caste) - if("Hunter") - new_xeno = new /mob/living/carbon/alien/humanoid/hunter(loc) - if("Sentinel") - new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(loc) - if("Drone") - new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc) - if(mind) mind.transfer_to(new_xeno) - del(src) - return - else - src << "\red You are not fully grown." - return diff --git a/code/modules/mob/living/carbon/alien/larva/progression.dm b/code/modules/mob/living/carbon/alien/larva/progression.dm new file mode 100644 index 00000000000..50d75af813f --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/progression.dm @@ -0,0 +1,17 @@ +/mob/living/carbon/alien/larva/update_progression() + if(amount_grown < max_grown) + amount_grown++ + return + +/mob/living/carbon/alien/larva/confirm_evolution() + + src << "\blue You are growing into a beautiful alien! It is time to choose a caste." + src << "\blue There are three to choose from:" + src << "Hunters \blue are strong and agile, able to hunt away from the hive and rapidly move through ventilation shafts. Hunters generate plasma slowly and have low reserves." + src << "Sentinels \blue are tasked with protecting the hive and are deadly up close and at a range. They are not as physically imposing nor fast as the hunters." + src << "Drones \blue are the working class, offering the largest plasma storage and generation. They are the only caste which may evolve again, turning into the dreaded alien queen." + var/alien_caste = alert(src, "Please choose which alien caste you shall belong to.",,"Hunter","Sentinel","Drone") + return alien_caste ? "Xenomorph [alien_caste]" : null + +/mob/living/carbon/alien/larva/show_evolution_blurb() + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/update_icons.dm b/code/modules/mob/living/carbon/alien/larva/update_icons.dm deleted file mode 100644 index 3ab3fb3b382..00000000000 --- a/code/modules/mob/living/carbon/alien/larva/update_icons.dm +++ /dev/null @@ -1,22 +0,0 @@ - -/mob/living/carbon/alien/larva/regenerate_icons() - overlays = list() - update_icons() - -/mob/living/carbon/alien/larva/update_icons() - var/state = 0 - if(amount_grown > 150) - state = 2 - else if(amount_grown > 50) - state = 1 - - if(stat == DEAD) - icon_state = "larva[state]_dead" - else if (handcuffed || legcuffed) - icon_state = "larva[state]_cuff" - else if (stunned) - icon_state = "larva[state]_stun" - else if(lying || resting) - icon_state = "larva[state]_sleep" - else - icon_state = "larva[state]" diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm new file mode 100644 index 00000000000..5c0ea8ed1f4 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/life.dm @@ -0,0 +1,63 @@ +// Alien larva are quite simple. +/mob/living/carbon/alien/Life() + + set invisibility = 0 + set background = 1 + + if (monkeyizing) + return + + ..() + + if (stat != DEAD) //still breathing + + // GROW! + update_progression() + + // Radiation. + handle_mutations_and_radiation() + + // Chemicals in the body + handle_chemicals_in_body() + + blinded = null + + handle_environment() + + //Status updates, death etc. + handle_regular_status_updates() + update_canmove() + update_icons() + + if(client) + handle_regular_hud_updates() + +/mob/living/carbon/alien/proc/handle_chemicals_in_body() + return // Nothing yet. Maybe check it out at a later date. + +/mob/living/carbon/alien/proc/handle_mutations_and_radiation() + // Currently both Dionaea and larvae like to eat radiation, so I'm defining the + // rad absorbtion here. This will need to be changed if other baby aliens are added. + + if(!radiation) + return + + var/rads = radiation/25 + radiation -= rads + nutrition += rads + heal_overall_damage(rads,rads) + adjustOxyLoss(-(rads)) + adjustToxLoss(-(rads)) + return + +/mob/living/carbon/alien/proc/handle_environment(enviroment) + //TODO: Work out if larvae breathe/suffer from pressure/suffer from heat. + if(!enviroment) + return + +/mob/living/carbon/alien/proc/handle_regular_status_updates() + // TODO: sleep, blind, stunned, paralyzed? + return + +/mob/living/carbon/alien/proc/handle_regular_hud_updates() + return //TODO: Not sure what to do with this yet. \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/login.dm b/code/modules/mob/living/carbon/alien/login.dm deleted file mode 100644 index 9701338e4b2..00000000000 --- a/code/modules/mob/living/carbon/alien/login.dm +++ /dev/null @@ -1,4 +0,0 @@ -/mob/living/carbon/alien/humanoid/Login() - ..() - AddInfectionImages() - return diff --git a/code/modules/mob/living/carbon/alien/logout.dm b/code/modules/mob/living/carbon/alien/logout.dm deleted file mode 100644 index c0734cd21fd..00000000000 --- a/code/modules/mob/living/carbon/alien/logout.dm +++ /dev/null @@ -1,4 +0,0 @@ -/mob/living/carbon/alien/humanoid/Logout() - ..() - RemoveInfectionImages() - return diff --git a/code/modules/mob/living/carbon/alien/powers.dm b/code/modules/mob/living/carbon/alien/powers.dm deleted file mode 100644 index d9452a8d799..00000000000 --- a/code/modules/mob/living/carbon/alien/powers.dm +++ /dev/null @@ -1,5 +0,0 @@ -/mob/living/carbon/alien/verb/ventcrawl() // -- TLE - set name = "Crawl through vent" - set desc = "Enter an air vent and crawl through the pipe system." - set category = "Alien" - handle_ventcrawl() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/progression.dm b/code/modules/mob/living/carbon/alien/progression.dm new file mode 100644 index 00000000000..fe3ec5d2d5d --- /dev/null +++ b/code/modules/mob/living/carbon/alien/progression.dm @@ -0,0 +1,50 @@ +/mob/living/carbon/alien/verb/evolve() + + set name = "Evolve" + set desc = "Evolve into your adult form." + set category = "Abilities" + + if(stat != CONSCIOUS) + return + + if(!adult_form) + verbs -= /mob/living/carbon/alien/verb/evolve + return + + if(handcuffed || legcuffed) + src << "\red You cannot evolve when you are cuffed." + return + + if(amount_grown < max_grown) + src << "\red You are not fully grown." + return + + // confirm_evolution() handles choices and other specific requirements. + var/new_species = confirm_evolution() + if(!new_species || !adult_form ) + return + + var/mob/living/carbon/human/adult = new adult_form(get_turf(src)) + adult.set_species(new_species) + show_evolution_blurb() + + if(mind) + mind.transfer_to(adult) + else + adult.key = src.key + + for (var/obj/item/W in src.contents) + src.drop_from_inventory(W) + + for(var/datum/language/L in languages) + adult.add_language(L.name) + del(src) + +/mob/living/carbon/alien/proc/update_progression() + return + +/mob/living/carbon/alien/proc/confirm_evolution() + return + +/mob/living/carbon/alien/proc/show_evolution_blurb() + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/say.dm b/code/modules/mob/living/carbon/alien/say.dm index 28947ac55ee..f822078885f 100644 --- a/code/modules/mob/living/carbon/alien/say.dm +++ b/code/modules/mob/living/carbon/alien/say.dm @@ -1,68 +1,34 @@ -/mob/living/carbon/alien/say(var/message) - - if (silent) - return - - if (length(message) >= 2) - if (department_radio_keys[copytext(message, 1, 3)] == "alientalk") - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - if (stat == 2) - return say_dead(message) - else - alien_talk(message) - else - if (copytext(message, 1, 2) != "*" && !stat) - playsound(loc, "hiss", 25, 1, 1)//So aliens can hiss while they hiss yo/N - return ..(message) - else - -/mob/living/proc/alien_talk(var/message) - - log_say("[key_name(src)] : [message]") - message = trim(message) - - if (!message) - return - - var/message_a = say_quote(message) - var/rendered = "Hivemind, [name] [message_a]" - for (var/mob/living/S in player_list) - if(!S.stat) - if(S.alien_talk_understand) - if(S.alien_talk_understand == alien_talk_understand) - S.show_message(rendered, 2) - else if (S.hivecheck()) - S.show_message(rendered, 2) - - var/list/listening = hearers(1, src) - listening -= src - listening += src - - var/list/heard = list() - for (var/mob/M in listening) - if(!istype(M, /mob/living/carbon/alien) && !M.alien_talk_understand) - heard += M - - - if (length(heard)) - var/message_b - - message_b = "hsssss" - message_b = say_quote(message_b) - message_b = "[message_b]" - - rendered = "[voice_name] [message_b]" - - for (var/mob/M in heard) - M.show_message(rendered, 2) - - message = say_quote(message) - - rendered = "Hivemind, [name] [message_a]" - - for (var/mob/M in player_list) - if (istype(M, /mob/new_player)) - continue - if (M.stat > 1) - M.show_message(rendered, 2) \ No newline at end of file +/mob/living/carbon/alien/say(var/message) + var/verb = "says" + var/message_range = world.view + + if(client) + if(client.prefs.muted & MUTE_IC) + src << "\red You cannot speak in IC (Muted)." + return + + message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + + if(stat == 2) + return say_dead(message) + + var/datum/language/speaking = null + + if(length(message) >= 2) + var/channel_prefix = copytext(message, 1 ,3) + if(languages.len) + for(var/datum/language/L in languages) + if(lowertext(channel_prefix) == ":[L.key]") + verb = L.speech_verb + speaking = L + break + + if(speaking) + message = trim(copytext(message,3)) + + message = capitalize(trim_left(message)) + + if(!message || stat) + return + + ..(message, speaking, verb, null, null, message_range, null) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/special/_main.dm b/code/modules/mob/living/carbon/alien/special/_main.dm deleted file mode 100644 index eb5594f3c9e..00000000000 --- a/code/modules/mob/living/carbon/alien/special/_main.dm +++ /dev/null @@ -1,71 +0,0 @@ -//XCOM alien code -//By Xerif (Donated by the Foundation project, ss13.org) - -/mob/living/carbon/alien/humanoid/special - has_fine_manipulation = 1 - var/xcom_state - - New() - ..() - spawn (1) - var/datum/reagents/R = new/datum/reagents(100) - reagents = R - R.my_atom = src - - mind = new() - mind.key = key - mind.special_role = "Special Xeno" - - name = "[name] ([rand(1, 1000)])" - real_name = name - - src.stand_icon = new /icon('xcomalien.dmi', xcom_state) - src.lying_icon = new /icon('xcomalien.dmi', xcom_state) - src.icon = src.stand_icon - - remove_special_verbs() - - rebuild_appearance() - - death(gibbed) - ..() - spawn(5) - gib() - - Stat() - statpanel("Status") - if (src.client && src.client.holder) - stat(null, "([x], [y], [z])") - - stat(null, "Intent: [src.a_intent]") - stat(null, "Move Mode: [src.m_intent]") - - if (src.client.statpanel == "Status") - if (src.internal) - if (!src.internal.air_contents) - del(src.internal) - else - stat("Internal Atmosphere Info", src.internal.name) - stat("Tank Pressure", src.internal.air_contents.return_pressure()) - stat("Distribution Pressure", src.internal.distribute_pressure) - return - - alien_talk() - if(istype(src, /mob/living/carbon/alien/humanoid/special/etheral)) - ..() - return - if(istype(src, /mob/living/carbon/alien/humanoid/special/sectoid)) - ..() - return - return - -/mob/living/carbon/alien/humanoid/special/proc/xcom_attack() - return - -/mob/living/carbon/alien/humanoid/special/proc/remove_special_verbs() - verbs -= /mob/living/carbon/alien/humanoid/verb/plant - verbs -= /mob/living/carbon/alien/humanoid/verb/ActivateHuggers - verbs -= /mob/living/carbon/alien/humanoid/verb/whisp - verbs -= /mob/living/carbon/alien/humanoid/verb/transfer_plasma - verbs -= /mob/living/carbon/alien/humanoid/verb/corrode - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/special/snakeman.dm b/code/modules/mob/living/carbon/alien/special/snakeman.dm deleted file mode 100644 index 7aa7b9d5db0..00000000000 --- a/code/modules/mob/living/carbon/alien/special/snakeman.dm +++ /dev/null @@ -1,59 +0,0 @@ -/mob/living/carbon/alien/humanoid/special/snakeman - name = "Snakeman" - desc = "This race developed in an extremely hostile environment. They are extremely tough and can resist extreme temperature variations. Their mobility depends on a snake-like giant \"foot\" which protects all the vital organs. " - xcom_state = "snake" - - movement_delay() - return 4 - -/mob/living/carbon/alien/humanoid/special/snakeman/verb/lay_egg(mob/living/carbon/human/M as mob) - set name = "Impregnate" - set desc = "Lays an egg on a corpse, allowing the egg to feed." - set category = "Snakeman" - - set src = view(0) - - if(stat) - return - - if(!M) - return - - if(!M.client) - src << "This being is missing a brain." - return - - visible_message("[src] extends a probiscis and stabs it into [M]") - - if (!do_mob(usr, M, 50)) - usr << "\red The injection of the egg has been interrupted!" - return - - if(M.client) - M.client.mob = new/mob/living/carbon/alien/humanoid/special/snakeman(new/obj/effect/snake_egg(src.loc)) - visible_message("[src] injects [M] with an egg.") - visible_message("The egg absorbs [M]") - M.mutations |= NOCLONE - M.update_body() - M.death() - else - src << "This being is missing a brain." - - return - -/obj/effect/snake_egg - name = "Egg" - icon = 'icons/mob/alien.dmi' - icon_state = "egg" - density = 1 - anchored = 1 - - New() - ..() - - spawn(300) - for(var/mob/M in src) - M.loc = src.loc - icon_state = "egg_hatched" - density = 0 - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/update_icons.dm b/code/modules/mob/living/carbon/alien/update_icons.dm new file mode 100644 index 00000000000..794078a3b3f --- /dev/null +++ b/code/modules/mob/living/carbon/alien/update_icons.dm @@ -0,0 +1,22 @@ +/mob/living/carbon/alien/regenerate_icons() + overlays = list() + update_icons() + +/mob/living/carbon/alien/update_icons() + + var/state = 0 + if(amount_grown > max_grown*0.75) + state = 2 + else if(amount_grown > max_grown*0.25) + state = 1 + + if(stat == DEAD) + icon_state = "[initial(icon_state)][state]_dead" + else if (handcuffed || legcuffed) + icon_state = "[initial(icon_state)][state]_cuff" + else if (stunned) + icon_state = "[initial(icon_state)][state]_stun" + else if(lying || resting) + icon_state = "[initial(icon_state)][state]_sleep" + else + icon_state = "[initial(icon_state)][state]" diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index 5ee424bd8db..f17bfa5d736 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -132,7 +132,6 @@ src.brainmob.real_name = src.brainmob.name src.brainmob.loc = src src.brainmob.container = src - src.brainmob.robot_talk_understand = 1 src.brainmob.stat = 0 src.brainmob.silent = 0 dead_mob_list -= src.brainmob diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm index fa09d87f22a..4756cc88ad4 100644 --- a/code/modules/mob/living/carbon/brain/say.dm +++ b/code/modules/mob/living/carbon/brain/say.dm @@ -1,3 +1,4 @@ +//TODO: Convert this over for languages. /mob/living/carbon/brain/say(var/message) if (silent) return @@ -5,11 +6,6 @@ if(!(container && (istype(container, /obj/item/device/mmi) || istype(container, /obj/item/device/mmi/posibrain)))) return //No MMI, can't speak, bucko./N else - if ((department_radio_keys[copytext(message, 1, 3)] == "binary") && (container && istype(container, /obj/item/device/mmi/posibrain))) - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - robot_talk(message) - return if(prob(emp_damage*4)) if(prob(10))//10% chane to drop the message entirely return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f0c22c9f596..1687016f85c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -224,7 +224,11 @@ M.visible_message("[M] shakes [src] trying to wake [t_him] up!", \ "You shake [src] trying to wake [t_him] up!") else - M.visible_message("[M] hugs [src] to make [t_him] feel better!", \ + var/mob/living/carbon/human/H = M + if(istype(H)) + H.species.hug(H,src) + else + M.visible_message("[M] hugs [src] to make [t_him] feel better!", \ "You hug [src] to make [t_him] feel better!") AdjustParalysis(-3) @@ -427,7 +431,7 @@ //Brain slug proc for voluntary removal of control. /mob/living/carbon/proc/release_control() - set category = "Alien" + set category = "Abilities" set name = "Release Control" set desc = "Release control of your host's body." @@ -447,7 +451,7 @@ //Brain slug proc for tormenting the host. /mob/living/carbon/proc/punish_host() - set category = "Alien" + set category = "Abilities" set name = "Torment host" set desc = "Punish your host with agony." @@ -470,7 +474,7 @@ return 0 /mob/living/carbon/proc/spawn_larvae() - set category = "Alien" + set category = "Abilities" set name = "Reproduce" set desc = "Spawn several young." @@ -491,4 +495,4 @@ else src << "You do not have enough chemicals stored to reproduce." - return + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon_powers.dm b/code/modules/mob/living/carbon/carbon_powers.dm new file mode 100644 index 00000000000..c477d26031d --- /dev/null +++ b/code/modules/mob/living/carbon/carbon_powers.dm @@ -0,0 +1,39 @@ +//TODO: Consider renaming carbon/monkey to carbon/small. + +/mob/living/carbon/proc/fertilize_plant() + + set category = "Abilities" + set name = "Fertilize plant" + set desc = "Turn your food into nutrients for plants." + + var/list/trays = list() + for(var/obj/machinery/portable_atmospherics/hydroponics/tray in range(1)) + if(tray.nutrilevel < 10 && src.Adjacent(tray)) + trays += tray + + var/obj/machinery/portable_atmospherics/hydroponics/target = input("Select a tray:") as null|anything in trays + + if(!src || !target || target.nutrilevel == 10) return //Sanity check. + + src.nutrition -= ((10-target.nutrilevel)*5) + target.nutrilevel = 10 + src.visible_message("\red [src] secretes a trickle of green liquid, refilling [target]'s nutrient tray.","\red You secrete a trickle of green liquid from your tail, refilling [target]'s nutrient tray.") + +/mob/living/carbon/proc/eat_weeds() + + set category = "Abilities" + set name = "Eat Weeds" + set desc = "Clean the weeds out of soil or a hydroponics tray." + + var/list/trays = list() + for(var/obj/machinery/portable_atmospherics/hydroponics/tray in range(1)) + if(tray.weedlevel > 0 && src.Adjacent(tray)) + trays += tray + + var/obj/machinery/portable_atmospherics/hydroponics/target = input("Select a tray:") as null|anything in trays + + if(!src || !target || target.weedlevel == 0) return //Sanity check. + + src.reagents.add_reagent("nutriment", target.weedlevel) + target.weedlevel = 0 + src.visible_message("\red [src] begins rooting through [target], ripping out weeds and eating them noisily.","\red You begin rooting through [target], ripping out weeds and eating them noisily.") diff --git a/code/modules/mob/living/carbon/human/alien/alien.dm b/code/modules/mob/living/carbon/human/alien/alien.dm new file mode 100644 index 00000000000..4c5c9e739b2 --- /dev/null +++ b/code/modules/mob/living/carbon/human/alien/alien.dm @@ -0,0 +1,92 @@ +proc/create_new_xenomorph(var/alien_caste,var/target) + + target = get_turf(target) + if(!target || !alien_caste) return + + var/mob/living/carbon/human/new_alien = new(target) + new_alien.set_species("Xenomorph [alien_caste]") + return new_alien + +/mob/living/carbon/human/xdrone/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Drone") + +/mob/living/carbon/human/xsentinel/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Sentinel") + +/mob/living/carbon/human/xhunter/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Hunter") + +/mob/living/carbon/human/xqueen/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Queen") + +/mob/living/carbon/human/Stat() + + ..() + +// I feel like we should generalize/condense down all the various icon-rendering antag procs. +/*---------------------------------------- +Proc: AddInfectionImages() +Des: Gives the client of the alien an image on each infected mob. +----------------------------------------*/ +/mob/living/carbon/human/proc/AddInfectionImages() + if (client) + for (var/mob/living/C in mob_list) + if(C.status_flags & XENO_HOST) + var/obj/item/alien_embryo/A = locate() in C + var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]") + client.images += I + return + +/*---------------------------------------- +Proc: RemoveInfectionImages() +Des: Removes all infected images from the alien. +----------------------------------------*/ +/mob/living/carbon/human/proc/RemoveInfectionImages() + if (client) + for(var/image/I in client.images) + if(dd_hasprefix_case(I.icon_state, "infected")) + del(I) + return + +/* TODO: Convert this over. +/mob/living/carbon/human/alien/show_inv(mob/user as mob) + + user.set_machine(src) + var/dat = {" +
[name]
+

+
Left Hand: [(l_hand ? text("[]", l_hand) : "Nothing")] +
Right Hand: [(r_hand ? text("[]", r_hand) : "Nothing")] +
Head: [(head ? text("[]", head) : "Nothing")] +
(Exo)Suit: [(wear_suit ? text("[]", wear_suit) : "Nothing")] +
Empty Pouches +
Close +
"} + user << browse(dat, text("window=mob[name];size=340x480")) + onclose(user, "mob[name]") + return + */ + +/* TODO: Convert this over. +/mob/living/carbon/human/alien/queen/large + icon = 'icons/mob/alienqueen.dmi' + icon_state = "queen_s" + pixel_x = -16 + +/mob/living/carbon/human/alien/queen/large/update_icons() + lying_prev = lying //so we don't update overlays for lying/standing unless our stance changes again + update_hud() //TODO: remove the need for this to be here + overlays.Cut() + if(lying) + if(resting) icon_state = "queen_sleep" + else icon_state = "queen_l" + for(var/image/I in overlays_lying) + overlays += I + else + icon_state = "queen_s" + for(var/image/I in overlays_standing) + overlays += I*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/human/alien/alien_embryo.dm similarity index 90% rename from code/modules/mob/living/carbon/alien/special/alien_embryo.dm rename to code/modules/mob/living/carbon/human/alien/alien_embryo.dm index 35b9e9fbfd0..4bdddc2ca6a 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/human/alien/alien_embryo.dm @@ -1,143 +1,159 @@ -// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability -// It functions almost identically (see code/datums/diseases/alien_embryo.dm) - -/obj/item/alien_embryo - name = "alien embryo" - desc = "All slimy and yuck." - icon = 'icons/mob/alien.dmi' - icon_state = "larva0_dead" - var/mob/living/affected_mob - var/stage = 0 - -/obj/item/alien_embryo/New() - if(istype(loc, /mob/living)) - affected_mob = loc - processing_objects.Add(src) - spawn(0) - AddInfectionImages(affected_mob) - else - del(src) - -/obj/item/alien_embryo/Del() - if(affected_mob) - affected_mob.status_flags &= ~(XENO_HOST) - spawn(0) - RemoveInfectionImages(affected_mob) - ..() - -/obj/item/alien_embryo/process() - if(!affected_mob) return - if(loc != affected_mob) - affected_mob.status_flags &= ~(XENO_HOST) - processing_objects.Remove(src) - spawn(0) - RemoveInfectionImages(affected_mob) - affected_mob = null - return - - if(stage < 5 && prob(3)) - stage++ - spawn(0) - RefreshInfectionImage(affected_mob) - - switch(stage) - if(2, 3) - if(prob(1)) - affected_mob.emote("sneeze") - if(prob(1)) - affected_mob.emote("cough") - if(prob(1)) - affected_mob << "\red Your throat feels sore." - if(prob(1)) - affected_mob << "\red Mucous runs down the back of your throat." - if(4) - if(prob(1)) - affected_mob.emote("sneeze") - if(prob(1)) - affected_mob.emote("cough") - if(prob(2)) - affected_mob << "\red Your muscles ache." - if(prob(20)) - affected_mob.take_organ_damage(1) - if(prob(2)) - affected_mob << "\red Your stomach hurts." - if(prob(20)) - affected_mob.adjustToxLoss(1) - affected_mob.updatehealth() - if(5) - affected_mob << "\red You feel something tearing its way out of your stomach..." - affected_mob.adjustToxLoss(10) - affected_mob.updatehealth() - if(prob(50)) - AttemptGrow() - -/obj/item/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1) - var/list/candidates = get_alien_candidates() - var/picked = null - - // To stop clientless larva, we will check that our host has a client - // if we find no ghosts to become the alien. If the host has a client - // he will become the alien but if he doesn't then we will set the stage - // to 2, so we don't do a process heavy check everytime. - - if(candidates.len) - picked = pick(candidates) - else if(affected_mob.client) - picked = affected_mob.key - else - stage = 4 // Let's try again later. - return - - if(affected_mob.lying) - affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_lie") - else - affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_stand") - spawn(6) - var/mob/living/carbon/alien/larva/new_xeno = new(affected_mob.loc) - new_xeno.key = picked - new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100) //To get the player's attention - if(gib_on_success) - affected_mob.gib() - del(src) - -/*---------------------------------------- -Proc: RefreshInfectionImage() -Des: Removes all infection images from aliens and places an infection image on all infected mobs for aliens. -----------------------------------------*/ -/obj/item/alien_embryo/proc/RefreshInfectionImage() - for(var/mob/living/carbon/alien/alien in player_list) - if(alien.client) - for(var/image/I in alien.client.images) - if(dd_hasprefix_case(I.icon_state, "infected")) - del(I) - for(var/mob/living/L in mob_list) - if(iscorgi(L) || iscarbon(L)) - if(L.status_flags & XENO_HOST) - var/I = image('icons/mob/alien.dmi', loc = L, icon_state = "infected[stage]") - alien.client.images += I - -/*---------------------------------------- -Proc: AddInfectionImages(C) -Des: Checks if the passed mob (C) is infected with the alien egg, then gives each alien client an infected image at C. -----------------------------------------*/ -/obj/item/alien_embryo/proc/AddInfectionImages(var/mob/living/C) - if(C) - for(var/mob/living/carbon/alien/alien in player_list) - if(alien.client) - if(C.status_flags & XENO_HOST) - var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[stage]") - alien.client.images += I - -/*---------------------------------------- -Proc: RemoveInfectionImage(C) -Des: Removes the alien infection image from all aliens in the world located in passed mob (C). -----------------------------------------*/ - -/obj/item/alien_embryo/proc/RemoveInfectionImages(var/mob/living/C) - if(C) - for(var/mob/living/carbon/alien/alien in player_list) - if(alien.client) - for(var/image/I in alien.client.images) - if(I.loc == C) - if(dd_hasprefix_case(I.icon_state, "infected")) +// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability +// It functions almost identically (see code/datums/diseases/alien_embryo.dm) + +/obj/item/alien_embryo + name = "alien embryo" + desc = "All slimy and yuck." + icon = 'icons/mob/alien.dmi' + icon_state = "larva0_dead" + var/mob/living/affected_mob + var/stage = 0 + +/obj/item/alien_embryo/New() + if(istype(loc, /mob/living)) + affected_mob = loc + processing_objects.Add(src) + spawn(0) + AddInfectionImages(affected_mob) + else + del(src) + +/obj/item/alien_embryo/Del() + if(affected_mob) + affected_mob.status_flags &= ~(XENO_HOST) + spawn(0) + RemoveInfectionImages(affected_mob) + ..() + +/obj/item/alien_embryo/process() + if(!affected_mob) return + if(loc != affected_mob) + affected_mob.status_flags &= ~(XENO_HOST) + processing_objects.Remove(src) + spawn(0) + RemoveInfectionImages(affected_mob) + affected_mob = null + return + + if(stage < 5 && prob(3)) + stage++ + spawn(0) + RefreshInfectionImage(affected_mob) + + switch(stage) + if(2, 3) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your throat feels sore." + if(prob(1)) + affected_mob << "\red Mucous runs down the back of your throat." + if(4) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(2)) + affected_mob << "\red Your muscles ache." + if(prob(20)) + affected_mob.take_organ_damage(1) + if(prob(2)) + affected_mob << "\red Your stomach hurts." + if(prob(20)) + affected_mob.adjustToxLoss(1) + affected_mob.updatehealth() + if(5) + affected_mob << "\red You feel something tearing its way out of your stomach..." + affected_mob.adjustToxLoss(10) + affected_mob.updatehealth() + if(prob(50)) + AttemptGrow() + +/obj/item/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1) + var/list/candidates = get_alien_candidates() + var/picked = null + + // To stop clientless larva, we will check that our host has a client + // if we find no ghosts to become the alien. If the host has a client + // he will become the alien but if he doesn't then we will set the stage + // to 2, so we don't do a process heavy check everytime. + + if(candidates.len) + picked = pick(candidates) + else if(affected_mob.client) + picked = affected_mob.key + else + stage = 4 // Let's try again later. + return + + if(affected_mob.lying) + affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_lie") + else + affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_stand") + spawn(6) + var/mob/living/carbon/alien/larva/new_xeno = new(affected_mob.loc) + new_xeno.key = picked + new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100) //To get the player's attention + if(gib_on_success) + affected_mob.gib() + del(src) + +/*---------------------------------------- +Proc: RefreshInfectionImage() +Des: Removes all infection images from aliens and places an infection image on all infected mobs for aliens. +----------------------------------------*/ +/obj/item/alien_embryo/proc/RefreshInfectionImage() + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/datum/organ/internal/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + for(var/image/I in alien.client.images) + if(dd_hasprefix_case(I.icon_state, "infected")) + del(I) + for(var/mob/living/L in mob_list) + if(iscorgi(L) || iscarbon(L)) + if(L.status_flags & XENO_HOST) + var/I = image('icons/mob/alien.dmi', loc = L, icon_state = "infected[stage]") + alien.client.images += I + +/*---------------------------------------- +Proc: AddInfectionImages(C) +Des: Checks if the passed mob (C) is infected with the alien egg, then gives each alien client an infected image at C. +----------------------------------------*/ +/obj/item/alien_embryo/proc/AddInfectionImages(var/mob/living/C) + if(C) + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/datum/organ/internal/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + if(C.status_flags & XENO_HOST) + var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[stage]") + alien.client.images += I + +/*---------------------------------------- +Proc: RemoveInfectionImage(C) +Des: Removes the alien infection image from all aliens in the world located in passed mob (C). +----------------------------------------*/ + +/obj/item/alien_embryo/proc/RemoveInfectionImages(var/mob/living/C) + + if(C) + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/datum/organ/internal/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + for(var/image/I in alien.client.images) + if(I.loc == C) + if(dd_hasprefix_case(I.icon_state, "infected")) del(I) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/human/alien/alien_facehugger.dm similarity index 86% rename from code/modules/mob/living/carbon/alien/special/facehugger.dm rename to code/modules/mob/living/carbon/human/alien/alien_facehugger.dm index fc702d3f631..ffbaed6cc75 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/human/alien/alien_facehugger.dm @@ -1,241 +1,239 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -//TODO: Make these simple_animals - -var/const/MIN_IMPREGNATION_TIME = 100 //time it takes to impregnate someone -var/const/MAX_IMPREGNATION_TIME = 150 - -var/const/MIN_ACTIVE_TIME = 200 //time between being dropped and going idle -var/const/MAX_ACTIVE_TIME = 400 - -/obj/item/clothing/mask/facehugger - name = "alien" - desc = "It has some sort of a tube at the end of its tail." - icon = 'icons/mob/alien.dmi' - icon_state = "facehugger" - item_state = "facehugger" - w_class = 1 //note: can be picked up by aliens unlike most other items of w_class below 4 - flags = FPRINT | TABLEPASS | MASKCOVERSMOUTH | MASKCOVERSEYES | MASKINTERNALS - body_parts_covered = FACE|EYES - throw_range = 5 - - var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case - - var/sterile = 0 - - var/strength = 5 - - var/attached = 0 - -/obj/item/clothing/mask/facehugger/attack_paw(user as mob) //can be picked up by aliens - if(isalien(user)) - attack_hand(user) - return - else - ..() - return - -/obj/item/clothing/mask/facehugger/attack_hand(user as mob) - if((stat == CONSCIOUS && !sterile) && !isalien(user)) - Attach(user) - return - else - ..() - return - -/obj/item/clothing/mask/facehugger/attack(mob/living/M as mob, mob/user as mob) - ..() - user.drop_from_inventory(src) - Attach(M) - -/obj/item/clothing/mask/facehugger/New() - if(aliens_allowed) - ..() - else - del(src) - -/obj/item/clothing/mask/facehugger/examine() - ..() - switch(stat) - if(DEAD,UNCONSCIOUS) - usr << "\red \b [src] is not moving." - if(CONSCIOUS) - usr << "\red \b [src] seems to be active." - if (sterile) - usr << "\red \b It looks like the proboscis has been removed." - return - -/obj/item/clothing/mask/facehugger/attackby() - Die() - return - -/obj/item/clothing/mask/facehugger/bullet_act() - Die() - return - -/obj/item/clothing/mask/facehugger/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(exposed_temperature > 300) - Die() - return - -/obj/item/clothing/mask/facehugger/equipped(mob/M) - Attach(M) - -/obj/item/clothing/mask/facehugger/Crossed(atom/target) - HasProximity(target) - return - -/obj/item/clothing/mask/facehugger/on_found(mob/finder as mob) - if(stat == CONSCIOUS) - HasProximity(finder) - return 1 - return - -/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj) - if(CanHug(AM)) - Attach(AM) - -/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed) - ..() - if(stat == CONSCIOUS) - icon_state = "[initial(icon_state)]_thrown" - spawn(15) - if(icon_state == "[initial(icon_state)]_thrown") - icon_state = "[initial(icon_state)]" - -/obj/item/clothing/mask/facehugger/throw_impact(atom/hit_atom) - ..() - if(stat == CONSCIOUS) - icon_state = "[initial(icon_state)]" - Attach(hit_atom) - throwing = 0 - -/obj/item/clothing/mask/facehugger/proc/Attach(M as mob) - if( (!iscorgi(M) && !iscarbon(M)) || isalien(M)) - return - if(attached) - return - else - attached++ - spawn(MAX_IMPREGNATION_TIME) - attached = 0 - - var/mob/living/L = M //just so I don't need to use : - - if(loc == L) return - if(stat != CONSCIOUS) return - if(!sterile) L.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage - - L.visible_message("\red \b [src] leaps at [L]'s face!") - - if(ishuman(L)) - var/mob/living/carbon/human/H = L - if(H.head && H.head.flags & HEADCOVERSMOUTH) - H.visible_message("\red \b [src] smashes against [H]'s [H.head]!") - Die() - return - - if(iscarbon(M)) - var/mob/living/carbon/target = L - - if(target.wear_mask) - if(prob(20)) return - var/obj/item/clothing/W = target.wear_mask - if(!W.canremove) return - target.drop_from_inventory(W) - - target.visible_message("\red \b [src] tears [W] off of [target]'s face!") - - target.equip_to_slot(src, slot_wear_mask) - - if(!sterile) L.Paralyse(MAX_IMPREGNATION_TIME/6) //something like 25 ticks = 20 seconds with the default settings - else if (iscorgi(M)) - var/mob/living/simple_animal/corgi/C = M - src.loc = C - C.facehugger = src - C.wear_mask = src - //C.regenerate_icons() - - GoIdle() //so it doesn't jump the people that tear it off - - spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME)) - Impregnate(L) - - return - -/obj/item/clothing/mask/facehugger/proc/Impregnate(mob/living/target as mob) - if(!target || target.wear_mask != src || target.stat == DEAD) //was taken off or something - return - - if(!sterile) - //target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance - new /obj/item/alien_embryo(target) - target.status_flags |= XENO_HOST - - target.visible_message("\red \b [src] falls limp after violating [target]'s face!") - - Die() - icon_state = "[initial(icon_state)]_impregnated" - - if(iscorgi(target)) - var/mob/living/simple_animal/corgi/C = target - src.loc = get_turf(C) - C.facehugger = null - else - target.visible_message("\red \b [src] violates [target]'s face!") - return - -/obj/item/clothing/mask/facehugger/proc/GoActive() - if(stat == DEAD || stat == CONSCIOUS) - return - - stat = CONSCIOUS - icon_state = "[initial(icon_state)]" - -/* for(var/mob/living/carbon/alien/alien in world) - var/image/activeIndicator = image('icons/mob/alien.dmi', loc = src, icon_state = "facehugger_active") - activeIndicator.override = 1 - if(alien && alien.client) - alien.client.images += activeIndicator */ - - return - -/obj/item/clothing/mask/facehugger/proc/GoIdle() - if(stat == DEAD || stat == UNCONSCIOUS) - return - -/* RemoveActiveIndicators() */ - - stat = UNCONSCIOUS - icon_state = "[initial(icon_state)]_inactive" - - spawn(rand(MIN_ACTIVE_TIME,MAX_ACTIVE_TIME)) - GoActive() - return - -/obj/item/clothing/mask/facehugger/proc/Die() - if(stat == DEAD) - return - -/* RemoveActiveIndicators() */ - - icon_state = "[initial(icon_state)]_dead" - stat = DEAD - - src.visible_message("\red \b[src] curls up into a ball!") - - return - -/proc/CanHug(var/mob/M) - - if(iscorgi(M)) - return 1 - - if(!iscarbon(M) || isalien(M)) - return 0 - var/mob/living/carbon/C = M - if(ishuman(C)) - var/mob/living/carbon/human/H = C - if(H.head && H.head.flags & HEADCOVERSMOUTH) - return 0 - return 1 +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +//TODO: Make these simple_animals + +var/const/MIN_IMPREGNATION_TIME = 100 //time it takes to impregnate someone +var/const/MAX_IMPREGNATION_TIME = 150 + +var/const/MIN_ACTIVE_TIME = 200 //time between being dropped and going idle +var/const/MAX_ACTIVE_TIME = 400 + +/obj/item/clothing/mask/facehugger + name = "alien" + desc = "It has some sort of a tube at the end of its tail." + icon = 'icons/mob/alien.dmi' + icon_state = "facehugger" + item_state = "facehugger" + w_class = 1 //note: can be picked up by aliens unlike most other items of w_class below 4 + flags = FPRINT | TABLEPASS | MASKCOVERSMOUTH | MASKCOVERSEYES | MASKINTERNALS + body_parts_covered = FACE|EYES + throw_range = 5 + + var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case + var/sterile = 0 + var/strength = 5 + var/attached = 0 + +/obj/item/clothing/mask/facehugger/attack_paw(user as mob) //can be picked up by aliens + attack_hand(user) + return + +/obj/item/clothing/mask/facehugger/attack_hand(user as mob) + + if((stat == CONSCIOUS && !sterile)) + Attach(user) + return + else + ..() + return + +/obj/item/clothing/mask/facehugger/attack(mob/living/M as mob, mob/user as mob) + ..() + user.drop_from_inventory(src) + Attach(M) + +/obj/item/clothing/mask/facehugger/New() + if(aliens_allowed) + ..() + else + del(src) + +/obj/item/clothing/mask/facehugger/examine() + ..() + switch(stat) + if(DEAD,UNCONSCIOUS) + usr << "\red \b [src] is not moving." + if(CONSCIOUS) + usr << "\red \b [src] seems to be active." + if (sterile) + usr << "\red \b It looks like the proboscis has been removed." + return + +/obj/item/clothing/mask/facehugger/attackby() + Die() + return + +/obj/item/clothing/mask/facehugger/bullet_act() + Die() + return + +/obj/item/clothing/mask/facehugger/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 300) + Die() + return + +/obj/item/clothing/mask/facehugger/equipped(mob/M) + Attach(M) + +/obj/item/clothing/mask/facehugger/Crossed(atom/target) + HasProximity(target) + return + +/obj/item/clothing/mask/facehugger/on_found(mob/finder as mob) + if(stat == CONSCIOUS) + HasProximity(finder) + return 1 + return + +/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj) + if(CanHug(AM)) + Attach(AM) + +/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed) + ..() + if(stat == CONSCIOUS) + icon_state = "[initial(icon_state)]_thrown" + spawn(15) + if(icon_state == "[initial(icon_state)]_thrown") + icon_state = "[initial(icon_state)]" + +/obj/item/clothing/mask/facehugger/throw_impact(atom/hit_atom) + ..() + if(stat == CONSCIOUS) + icon_state = "[initial(icon_state)]" + Attach(hit_atom) + throwing = 0 + +/obj/item/clothing/mask/facehugger/proc/Attach(M as mob) + + if((!iscorgi(M) && !iscarbon(M))) + return + + if(attached) + return + + var/mob/living/carbon/C = M + if(istype(C) && locate(/datum/organ/internal/xenos/hivenode) in C.internal_organs) + return + + attached++ + spawn(MAX_IMPREGNATION_TIME) + attached = 0 + + var/mob/living/L = M //just so I don't need to use : + + if(loc == L) return + if(stat != CONSCIOUS) return + if(!sterile) L.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage + + L.visible_message("\red \b [src] leaps at [L]'s face!") + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.head && H.head.flags & HEADCOVERSMOUTH) + H.visible_message("\red \b [src] smashes against [H]'s [H.head]!") + Die() + return + + if(iscarbon(M)) + var/mob/living/carbon/target = L + + if(target.wear_mask) + if(prob(20)) return + var/obj/item/clothing/W = target.wear_mask + if(!W.canremove) return + target.drop_from_inventory(W) + + target.visible_message("\red \b [src] tears [W] off of [target]'s face!") + + target.equip_to_slot(src, slot_wear_mask) + + if(!sterile) L.Paralyse(MAX_IMPREGNATION_TIME/6) //something like 25 ticks = 20 seconds with the default settings + else if (iscorgi(M)) + var/mob/living/simple_animal/corgi/corgi = M + src.loc = corgi + corgi.facehugger = src + corgi.wear_mask = src + //C.regenerate_icons() + + GoIdle() //so it doesn't jump the people that tear it off + + spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME)) + Impregnate(L) + + return + +/obj/item/clothing/mask/facehugger/proc/Impregnate(mob/living/target as mob) + if(!target || target.wear_mask != src || target.stat == DEAD) //was taken off or something + return + + if(!sterile) + //target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance + new /obj/item/alien_embryo(target) + target.status_flags |= XENO_HOST + + target.visible_message("\red \b [src] falls limp after violating [target]'s face!") + + Die() + icon_state = "[initial(icon_state)]_impregnated" + + if(iscorgi(target)) + var/mob/living/simple_animal/corgi/C = target + src.loc = get_turf(C) + C.facehugger = null + else + target.visible_message("\red \b [src] violates [target]'s face!") + return + +/obj/item/clothing/mask/facehugger/proc/GoActive() + if(stat == DEAD || stat == CONSCIOUS) + return + + stat = CONSCIOUS + icon_state = "[initial(icon_state)]" + + return + +/obj/item/clothing/mask/facehugger/proc/GoIdle() + if(stat == DEAD || stat == UNCONSCIOUS) + return + +/* RemoveActiveIndicators() */ + + stat = UNCONSCIOUS + icon_state = "[initial(icon_state)]_inactive" + + spawn(rand(MIN_ACTIVE_TIME,MAX_ACTIVE_TIME)) + GoActive() + return + +/obj/item/clothing/mask/facehugger/proc/Die() + if(stat == DEAD) + return + +/* RemoveActiveIndicators() */ + + icon_state = "[initial(icon_state)]_dead" + stat = DEAD + + src.visible_message("\red \b[src] curls up into a ball!") + + return + +/proc/CanHug(var/mob/M) + + if(iscorgi(M)) + return 1 + + if(!iscarbon(M)) + return 0 + + var/mob/living/carbon/C = M + if(istype(C) && locate(/datum/organ/internal/xenos/hivenode) in C.internal_organs) + return 0 + + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(H.head && H.head.flags & HEADCOVERSMOUTH) + return 0 + return 1 diff --git a/code/modules/mob/living/carbon/human/alien/alien_powers.dm b/code/modules/mob/living/carbon/human/alien/alien_powers.dm new file mode 100644 index 00000000000..4b522c3552b --- /dev/null +++ b/code/modules/mob/living/carbon/human/alien/alien_powers.dm @@ -0,0 +1,228 @@ +/proc/alien_queen_exists(var/ignore_self,var/mob/living/carbon/human/self) + for(var/mob/living/carbon/human/Q in living_mob_list) + if(self && ignore_self && self == Q) + continue + if(Q.species.name != "Xenomorph Queen") + continue + if(!Q.key || !Q.client || Q.stat) + continue + return 1 + return 0 + +/mob/living/carbon/human/proc/gain_plasma(var/amount) + + var/datum/organ/internal/xenos/plasmavessel/I = internal_organs_by_name["plasma vessel"] + if(!istype(I)) return + + if(amount) + I.stored_plasma += amount + I.stored_plasma = max(0,min(I.stored_plasma,I.max_plasma)) + +/mob/living/carbon/human/proc/check_alien_ability(var/cost,var/needs_foundation,var/needs_organ) + + var/datum/organ/internal/xenos/plasmavessel/P = internal_organs_by_name["plasma vessel"] + if(!istype(P)) + src << "Your plasma vessel has been removed!" + return + + if(needs_organ) + var/datum/organ/internal/I = internal_organs_by_name[needs_organ] + if(!I) + src << "Your [needs_organ] has been removed!" + return + else if((I.status & ORGAN_CUT_AWAY) || I.is_broken()) + src << "Your [needs_organ] is too damaged to function!" + return + + if(P.stored_plasma < cost) + src << "\red You don't have enough phoron stored to do that." + return 0 + + if(needs_foundation) + var/turf/T = get_turf(src) + var/has_foundation + if(T) + //TODO: Work out the actual conditions this needs. + if(!(istype(T,/turf/space))) + has_foundation = 1 + if(!has_foundation) + src << "\red You need a solid foundation to do that on." + return 0 + + P.stored_plasma -= cost + return 1 + +// Free abilities. +/mob/living/carbon/human/proc/transfer_plasma(mob/living/carbon/human/M as mob in oview()) + set name = "Transfer Plasma" + set desc = "Transfer Plasma to another alien" + set category = "Abilities" + + if (get_dist(src,M) <= 1) + src << "\green You need to be closer." + return + + var/datum/organ/internal/xenos/plasmavessel/I = M.internal_organs_by_name["plasma vessel"] + if(!istype(I)) + src << "\green Their plasma vessel is missing." + return + + var/amount = input("Amount:", "Transfer Plasma to [M]") as num + if (amount) + amount = abs(round(amount)) + if(check_alien_ability(amount,0,"plasma vessel")) + M.gain_plasma(amount) + M << "\green [src] has transfered [amount] plasma to you." + src << "\green You have transferred [amount] plasma to [M]" + return + +// Queen verbs. +/mob/living/carbon/human/proc/lay_egg() + + set name = "Lay Egg (75)" + set desc = "Lay an egg to produce huggers to impregnate prey with." + set category = "Abilities" + + if(!aliens_allowed) + src << "You begin to lay an egg, but hesitate. You suspect it isn't allowed." + verbs -= /mob/living/carbon/human/proc/lay_egg + return + + if(locate(/obj/effect/alien/egg) in get_turf(src)) + src << "There's already an egg here." + return + + if(check_alien_ability(75,1,"egg sac")) + for(var/mob/O in viewers(src, null)) + O.show_message(text("\green [src] has laid an egg!"), 1) + new /obj/effect/alien/egg(loc) + + return + +// Drone verbs. +/mob/living/carbon/human/proc/evolve() + set name = "Evolve (500)" + set desc = "Produce an interal egg sac capable of spawning children. Only one queen can exist at a time." + set category = "Abilities" + + if(alien_queen_exists()) + src << "We already have an active queen." + return + + if(check_alien_ability(500)) + src << "\green You begin to evolve!" + for(var/mob/O in viewers(src, null)) + O.show_message(text("\green [src] begins to twist and contort!"), 1) + src.set_species("Xenomorph Queen") + + return + +/mob/living/carbon/human/proc/plant() + set name = "Plant Weeds (50)" + set desc = "Plants some alien weeds" + set category = "Abilities" + + if(check_alien_ability(50,1,"resin spinner")) + for(var/mob/O in viewers(src, null)) + O.show_message(text("\green [src] has planted some alien weeds!"), 1) + new /obj/effect/alien/weeds/node(loc) + return + +/mob/living/carbon/human/proc/corrosive_acid(O as obj|turf in oview(1)) //If they right click to corrode, an error will flash if its an invalid target./N + set name = "Corrosive Acid (200)" + set desc = "Drench an object in acid, destroying it over time." + set category = "Abilities" + + if(!O in oview(1)) + src << "\green [O] is too far away." + return + + // OBJ CHECK + if(isobj(O)) + var/obj/I = O + if(I.unacidable) //So the aliens don't destroy energy fields/singularies/other aliens/etc with their acid. + src << "\green You cannot dissolve this object." + return + + // TURF CHECK + else if(istype(O, /turf/simulated)) + var/turf/T = O + // R WALL + if(istype(T, /turf/simulated/wall/r_wall)) + src << "\green You cannot dissolve this object." + return + // R FLOOR + if(istype(T, /turf/simulated/floor/engine)) + src << "\green You cannot dissolve this object." + return + else// Not a type we can acid. + return + + if(check_alien_ability(200,0,"acid gland")) + new /obj/effect/alien/acid(get_turf(O), O) + visible_message("\green [src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!") + + return + +/mob/living/carbon/human/proc/neurotoxin(mob/target as mob in oview()) + set name = "Spit Neurotoxin (50)" + set desc = "Spits neurotoxin at someone, paralyzing them for a short time if they are not wearing protective gear." + set category = "Abilities" + + if(!check_alien_ability(50,0,"acid gland")) + return + + src << "\green You spit neurotoxin at [target]." + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + O << "\red [src] spits neurotoxin at [target]!" + + //I'm not motivated enough to revise this. Prjectile code in general needs update. + // Maybe change this to use throw_at? ~ Z + var/turf/T = loc + var/turf/U = (istype(target, /atom/movable) ? target.loc : target) + + if(!U || !T) + return + while(U && !istype(U,/turf)) + U = U.loc + if(!istype(T, /turf)) + return + if (U == T) + usr.bullet_act(new /obj/item/projectile/energy/neurotoxin(usr.loc), get_organ_target()) + return + if(!istype(U, /turf)) + return + + var/obj/item/projectile/energy/neurotoxin/A = new /obj/item/projectile/energy/neurotoxin(usr.loc) + A.current = U + A.yo = U.y - T.y + A.xo = U.x - T.x + A.process() + return + +/mob/living/carbon/human/proc/resin() // -- TLE + set name = "Secrete Resin (75)" + set desc = "Secrete tough malleable resin." + set category = "Abilities" + + var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in list("resin door","resin wall","resin membrane","resin nest") //would do it through typesof but then the player choice would have the type path and we don't want the internal workings to be exposed ICly - Urist + if(!choice) + return + + if(!check_alien_ability(75,1,"resin spinner")) + return + + src << "\green You shape a [choice]." + for(var/mob/O in viewers(src, null)) + O.show_message(text("\red [src] vomits up a thick purple substance and begins to shape it!"), 1) + switch(choice) + if("resin door") + new /obj/structure/mineral_door/resin(loc) + if("resin wall") + new /obj/effect/alien/resin/wall(loc) + if("resin membrane") + new /obj/effect/alien/resin/membrane(loc) + if("resin nest") + new /obj/structure/stool/bed/nest(loc) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/alien/alien_species.dm b/code/modules/mob/living/carbon/human/alien/alien_species.dm new file mode 100644 index 00000000000..185a3b60c75 --- /dev/null +++ b/code/modules/mob/living/carbon/human/alien/alien_species.dm @@ -0,0 +1,251 @@ +//TODO: Generalize some kind of power pool so that other races can use it. +//Stand-in until this is made more lore-friendly. +/datum/species/xenos + name = "Xenomorph" + language = "Hivemind" + unarmed_type = /datum/unarmed_attack/claws/strong + secondary_unarmed_type = /datum/unarmed_attack/bite/strong + hud_type = /datum/hud_data/alien + gluttonous = 2 + + eyes = "blank_eyes" + + brute_mod = 0.5 // Hardened carapace. + burn_mod = 2 // Weak to fire. + + warning_low_pressure = 50 + hazard_low_pressure = -1 + + cold_level_1 = 50 + cold_level_2 = -1 + cold_level_3 = -1 + + flags = IS_WHITELISTED | NO_BREATHE | NO_SCAN | NO_PAIN | RAD_ABSORB | NO_SLIP | NO_POISON + + reagent_tag = IS_XENOS + + blood_color = "#05EE05" + flesh_color = "#282846" + gibbed_anim = "gibbed-a" + dusted_anim = "dust-a" + death_message = "lets out a waning guttural screech, green blood bubbling from its maw." + death_sound = 'sound/voice/hiss6.ogg' + + breath_type = null + poison_type = null + + has_organ = list( + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel, + "hive node" = /datum/organ/internal/xenos/hivenode + ) + + var/alien_number = 0 + var/caste_name = "creature" // Used to update alien name. + var/weeds_heal_rate = 1 // Health regen on weeds. + var/weeds_plasma_rate = 5 // Plasma regen on weeds. + +/datum/species/xenos/hug(var/mob/living/carbon/human/H,var/mob/living/target) + H.visible_message("[H] caresses [target] with its scythe-like arm.", \ + "You caress [target] with your scythe-like arm.") + + +/datum/species/xenos/handle_post_spawn(var/mob/living/carbon/human/H) + + if(H.mind) + H.mind.assigned_role = "Alien" + H.mind.special_role = "Alien" + + alien_number++ //Keep track of how many aliens we've had so far. + H.real_name = "alien [caste_name] ([alien_number])" + H.name = H.real_name + + ..() + +/datum/species/xenos/handle_environment_special(var/mob/living/carbon/human/H) + + if(!H.loc) + return + + if(locate(/obj/effect/alien/weeds) in H.loc) + if(H.health >= H.maxHealth - H.getCloneLoss()) + var/datum/organ/internal/xenos/plasmavessel/P = H.internal_organs_by_name["plasma vessel"] + P.stored_plasma += weeds_plasma_rate + P.stored_plasma = min(max(P.stored_plasma,0),P.max_plasma) + else + H.adjustBruteLoss(-weeds_heal_rate) + H.adjustFireLoss(-weeds_heal_rate) + H.adjustOxyLoss(-weeds_heal_rate) + H.adjustToxLoss(-weeds_heal_rate) + ..() + +/datum/species/xenos/handle_login_special(var/mob/living/carbon/human/H) + H.AddInfectionImages() + ..() + +/datum/species/xenos/handle_logout_special(var/mob/living/carbon/human/H) + H.RemoveInfectionImages() + ..() + +/datum/species/xenos/drone + name = "Xenomorph Drone" + caste_name = "drone" + weeds_plasma_rate = 15 + slowdown = 2 + tail = "xenos_drone_tail" + + icobase = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' + + has_organ = list( + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/queen, + "acid gland" = /datum/organ/internal/xenos/acidgland, + "hive node" = /datum/organ/internal/xenos/hivenode, + "resin spinner" = /datum/organ/internal/xenos/resinspinner + ) + + inherent_verbs = list( + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/plant, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/evolve, + /mob/living/carbon/human/proc/resin, + /mob/living/carbon/human/proc/corrosive_acid + ) + +/datum/species/xenos/drone/handle_post_spawn(var/mob/living/carbon/human/H) + + var/mob/living/carbon/human/A = H + if(!istype(A)) + return ..() + ..() + +/datum/species/xenos/hunter + + name = "Xenomorph Hunter" + weeds_plasma_rate = 5 + caste_name = "hunter" + slowdown = -1 + total_health = 150 + tail = "xenos_hunter_tail" + + icobase = 'icons/mob/human_races/xenos/r_xenos_hunter.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_hunter.dmi' + + has_organ = list( + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/hunter, + "hive node" = /datum/organ/internal/xenos/hivenode + ) + + inherent_verbs = list( + /mob/living/carbon/human/proc/tackle, + /mob/living/carbon/human/proc/gut, + /mob/living/carbon/human/proc/leap, + /mob/living/carbon/human/proc/psychic_whisper, + /mob/living/carbon/human/proc/regurgitate + ) + +/datum/species/xenos/sentinel + name = "Xenomorph Sentinel" + weeds_plasma_rate = 10 + caste_name = "sentinel" + slowdown = 1 + total_health = 125 + tail = "xenos_sentinel_tail" + + icobase = 'icons/mob/human_races/xenos/r_xenos_sentinel.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_sentinel.dmi' + + has_organ = list( + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/sentinel, + "acid gland" = /datum/organ/internal/xenos/acidgland, + "hive node" = /datum/organ/internal/xenos/hivenode + ) + + inherent_verbs = list( + /mob/living/carbon/human/proc/tackle, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/corrosive_acid, + /mob/living/carbon/human/proc/neurotoxin + ) + +/datum/species/xenos/queen + + name = "Xenomorph Queen" + weeds_heal_rate = 5 + weeds_plasma_rate = 20 + caste_name = "queen" + slowdown = 5 + tail = "xenos_queen_tail" + + icobase = 'icons/mob/human_races/xenos/r_xenos_queen.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_queen.dmi' + + has_organ = list( + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "egg sac" = /datum/organ/internal/xenos/eggsac, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/queen, + "acid gland" = /datum/organ/internal/xenos/acidgland, + "hive node" = /datum/organ/internal/xenos/hivenode, + "resin spinner" = /datum/organ/internal/xenos/resinspinner + ) + + inherent_verbs = list( + /mob/living/carbon/human/proc/psychic_whisper, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/lay_egg, + /mob/living/carbon/human/proc/plant, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/corrosive_acid, + /mob/living/carbon/human/proc/neurotoxin, + /mob/living/carbon/human/proc/resin + ) + + //maxHealth = 250 + //health = 250 + +/datum/species/xenos/queen/handle_login_special(var/mob/living/carbon/human/H) + ..() + // Make sure only one official queen exists at any point. + if(!alien_queen_exists(1,H)) + H.real_name = "alien queen ([alien_number])" + H.name = H.real_name + else + H.real_name = "alien princess ([alien_number])" + H.name = H.real_name + +/datum/hud_data/alien + + icon = 'icons/mob/screen1_alien.dmi' + has_a_intent = 1 + has_m_intent = 1 + has_warnings = 1 + has_hands = 1 + has_drop = 1 + has_throw = 1 + has_resist = 1 + has_pressure = 0 + has_nutrition = 0 + has_bodytemp = 0 + has_internals = 0 + + gear = list( + "o_clothing" = list("loc" = ui_belt, "slot" = slot_wear_suit, "state" = "equip", "dir" = SOUTH), + "head" = list("loc" = ui_id, "slot" = slot_head, "state" = "hair"), + "storage1" = list("loc" = ui_storage1, "slot" = slot_l_store, "state" = "pocket"), + "storage2" = list("loc" = ui_storage2, "slot" = slot_r_store, "state" = "pocket"), + ) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index e14cd9c5345..f97397fe4cd 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -19,10 +19,11 @@ // Override the current limb status and don't cause an explosion E.droplimb(1,1) - flick("gibbed-h", animation) if(species) + flick(species.gibbed_anim, animation) hgibs(loc, viruses, dna, species.flesh_color, species.blood_color) else + flick("gibbed-h", animation) hgibs(loc, viruses, dna) spawn(15) @@ -42,8 +43,8 @@ animation.icon = 'icons/mob/mob.dmi' animation.master = src - flick("dust-h", animation) - new /obj/effect/decal/remains/human(loc) + flick(species.dusted_anim, animation) + new species.remains_type(loc) spawn(15) if(animation) del(animation) @@ -97,7 +98,9 @@ vox_kills++ //Bad vox. Shouldn't be killing humans. if(!gibbed) - emote("deathgasp") //let the world KNOW WE ARE DEAD + + emote("deathgasp") //let the world KNOW WE ARE DEAD // Doing this with the deathgasp emote seems odd. + if(species && species.death_sound) playsound(loc, species.death_sound, 80, 1, 1) //For ninjas exploding when they die. if( istype(wear_suit, /obj/item/clothing/suit/space/space_ninja) && wear_suit:s_initialized ) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 75eff694fac..9b5a526ca17 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -207,7 +207,7 @@ m_type = 2 if ("deathgasp") - message = "[src] seizes up and falls limp, \his eyes dead and lifeless..." + message = "[src] [species.death_message]" m_type = 1 if ("giggle") diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index c672950a18b..6196e711597 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -240,7 +240,7 @@ if(getBrainLoss() >= 60) msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n" - if(has_brain() && stat != DEAD) + if((!species.has_organ["brain"] || has_brain()) && stat != DEAD) if(!key) msg += "[t_He] [t_is] fast asleep. It doesn't look like they are waking up anytime soon.\n" else if(!client) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 3f7faeac8e6..ba433afb173 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -4,46 +4,20 @@ voice_name = "unknown" icon = 'icons/mob/human.dmi' icon_state = "body_m_s" + var/list/hud_list[9] var/datum/species/species //Contains icon generation and language information, set during New(). var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. -/mob/living/carbon/human/dummy - real_name = "Test Dummy" - status_flags = GODMODE|CANPUSH - -/mob/living/carbon/human/skrell/New(var/new_loc) - h_style = "Skrell Male Tentacles" - ..(new_loc, "Skrell") - -/mob/living/carbon/human/tajaran/New(var/new_loc) - h_style = "Tajaran Ears" - ..(new_loc, "Tajaran") - -/mob/living/carbon/human/unathi/New(var/new_loc) - h_style = "Unathi Horns" - ..(new_loc, "Unathi") - -/mob/living/carbon/human/vox/New(var/new_loc) - h_style = "Short Vox Quills" - ..(new_loc, "Vox") - -/mob/living/carbon/human/voxarmalis/New(var/new_loc) - h_style = "Bald" - ..(new_loc, "Vox Armalis") - -/mob/living/carbon/human/diona/New(var/new_loc) - ..(new_loc, "Diona") - -/mob/living/carbon/human/machine/New(var/new_loc) - h_style = "blue IPC screen" - ..(new_loc, "Machine") - /mob/living/carbon/human/New(var/new_loc, var/new_species = null) + if(!dna) + dna = new /datum/dna(null) + // Species name is handled by set_species() + if(!species) if(new_species) - set_species(new_species,null,1) + set_species(new_species) else set_species() @@ -51,10 +25,6 @@ reagents = R R.my_atom = src - if(!dna) - dna = new /datum/dna(null) - dna.species=species.name - hud_list[HEALTH_HUD] = image('icons/mob/hud.dmi', src, "hudhealth100") hud_list[STATUS_HUD] = image('icons/mob/hud.dmi', src, "hudhealthy") hud_list[ID_HUD] = image('icons/mob/hud.dmi', src, "hudunknown") @@ -65,7 +35,6 @@ hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[STATUS_HUD_OOC] = image('icons/mob/hud.dmi', src, "hudhealthy") - ..() if(dna) @@ -176,6 +145,7 @@ stat(null, eta_status) if (client.statpanel == "Status") + if (internal) if (!internal.air_contents) del(internal) @@ -183,10 +153,15 @@ stat("Internal Atmosphere Info", internal.name) stat("Tank Pressure", internal.air_contents.return_pressure()) stat("Distribution Pressure", internal.distribute_pressure) + + var/datum/organ/internal/xenos/plasmavessel/P = internal_organs_by_name["plasma vessel"] + if(P) + stat(null, "Phoron Stored: [P.stored_plasma]/[P.max_plasma]") if(mind) if(mind.changeling) stat("Chemical Storage", mind.changeling.chem_charges) stat("Genetic Damage Time", mind.changeling.geneticdamage) + if (istype(wear_suit, /obj/item/clothing/suit/space/space_ninja)&&wear_suit:s_initialized) stat("Energy Charge", round(wear_suit:cell:charge/100)) @@ -299,7 +274,7 @@ return -/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/carbon/human/attack_animal(mob/living/M as mob) if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else @@ -856,11 +831,21 @@ ..() return - ///eyecheck() ///Returns a number between -1 to 2 /mob/living/carbon/human/eyecheck() var/number = 0 + + if(!species.has_organ["eyes"]) //No eyes, can't hurt them. + return 2 + + if(internal_organs_by_name["eyes"]) // Eyes are fucked, not a 'weak point'. + var/datum/organ/internal/I = internal_organs_by_name["eyes"] + if(I.status & ORGAN_CUT_AWAY) + return 2 + else + return 2 + if(istype(src.head, /obj/item/clothing/head/welding)) if(!src.head:up) number += 2 @@ -878,7 +863,7 @@ /mob/living/carbon/human/IsAdvancedToolUser() - return 1//Humans can use guns and such + return species.has_fine_manipulation /mob/living/carbon/human/abiotic(var/full_body = 0) @@ -1261,7 +1246,7 @@ else usr << "\blue [self ? "Your" : "[src]'s"] pulse is [src.get_pulse(GETPULSE_HAND)]." -/mob/living/carbon/human/proc/set_species(var/new_species, var/force_organs, var/default_colour) +/mob/living/carbon/human/proc/set_species(var/new_species, var/default_colour) if(!dna) if(!new_species) @@ -1272,16 +1257,15 @@ else dna.species = new_species - if(species && (species.name && species.name == new_species)) - return - - if(species && species.language) - remove_language(species.language) + if(species) + if(species.name && species.name == new_species) + return + if(species.language) + remove_language(species.language) species = all_species[new_species] - if(force_organs || !organs || !organs.len) - species.create_organs(src) + species.create_organs(src) if(species.language) add_language(species.language) @@ -1300,6 +1284,7 @@ spawn(0) update_icons() + vessel.add_reagent("blood",560-vessel.total_volume) fixblood() if(species) @@ -1381,156 +1366,6 @@ // Might need re-wording. user << "There is no exposed flesh or thin material [target_zone == "head" ? "on their head" : "on their body"] to inject into." - -//Putting a couple of procs here that I don't know where else to dump. -//Mostly going to be used for Vox and Vox Armalis, but other human mobs might like them (for adminbuse). - -/mob/living/carbon/human/proc/leap() - set category = "IC" - set name = "Leap" - set desc = "Leap at a target and grab them aggressively." - - if(last_special > world.time) - return - - if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) - src << "You cannot leap in your current state." - return - - var/list/choices = list() - for(var/mob/living/M in view(6,src)) - if(!istype(M,/mob/living/silicon)) - choices += M - choices -= src - - var/mob/living/T = input(src,"Who do you wish to leap at?") as null|anything in choices - - if(!T || !src || src.stat) return - - if(get_dist(get_turf(T), get_turf(src)) > 6) return - - if(last_special > world.time) - return - - if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) - src << "You cannot leap in your current state." - return - - last_special = world.time + 75 - status_flags |= LEAPING - - src.visible_message("\The [src] leaps at [T]!") - src.throw_at(get_step(get_turf(T),get_turf(src)), 5, 1, src) - playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) - - sleep(5) - - if(status_flags & LEAPING) status_flags &= ~LEAPING - - if(!src.Adjacent(T)) - src << "\red You miss!" - return - - T.Weaken(5) - - //Only official raider vox get the grab and no self-prone." - if(src.mind && src.mind.special_role != "Vox Raider") - src.Weaken(5) - return - - var/use_hand = "left" - if(l_hand) - if(r_hand) - src << "\red You need to have one hand free to grab someone." - return - else - use_hand = "right" - - src.visible_message("\The [src] seizes [T] aggressively!") - - var/obj/item/weapon/grab/G = new(src,T) - if(use_hand == "left") - l_hand = G - else - r_hand = G - - G.state = GRAB_AGGRESSIVE - G.icon_state = "grabbed1" - G.synch() - -/mob/living/carbon/human/proc/gut() - set category = "IC" - set name = "Gut" - set desc = "While grabbing someone aggressively, rip their guts out or tear them apart." - - if(last_special > world.time) - return - - if(stat || paralysis || stunned || weakened || lying) - src << "\red You cannot do that in your current state." - return - - var/obj/item/weapon/grab/G = locate() in src - if(!G || !istype(G)) - src << "\red You are not grabbing anyone." - return - - if(G.state < GRAB_AGGRESSIVE) - src << "\red You must have an aggressive grab to gut your prey!" - return - - last_special = world.time + 50 - - visible_message("\The [src] rips viciously at \the [G.affecting]'s body with its claws!") - - if(istype(G.affecting,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = G.affecting - H.apply_damage(50,BRUTE) - if(H.stat == 2) - H.gib() - else - var/mob/living/M = G.affecting - if(!istype(M)) return //wut - M.apply_damage(50,BRUTE) - if(M.stat == 2) - M.gib() - -/mob/living/carbon/human/proc/commune() - set category = "IC" - set name = "Commune with creature" - set desc = "Send a telepathic message to an unlucky recipient." - - var/list/targets = list() - var/target = null - var/text = null - - targets += getmobs() //Fill list, prompt user with list - target = input("Select a creature!", "Speak to creature", null, null) as null|anything in targets - - if(!target) return - - text = input("What would you like to say?", "Speak to creature", null, null) - - text = trim(copytext(sanitize(text), 1, MAX_MESSAGE_LEN)) - - if(!text) return - - var/mob/M = targets[target] - - if(istype(M, /mob/dead/observer) || M.stat == DEAD) - src << "Not even a [src.species.name] can speak to the dead." - return - - log_say("[key_name(src)] communed to [key_name(M)]: [text]") - - M << "\blue Like lead slabs crashing into the ocean, alien thoughts drop into your mind: [text]" - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.species.name == src.species.name) - return - H << "\red Your nose begins to bleed..." - H.drip(1) - /mob/living/carbon/human/print_flavor_text() var/list/equipment = list(src.head,src.wear_mask,src.glasses,src.w_uniform,src.wear_suit,src.gloves,src.shoes) var/head_exposed = 1 @@ -1569,6 +1404,16 @@ flavor_text += "\n\n" return ..() +/mob/living/carbon/human/getDNA() + if(species.flags & NO_SCAN) + return null + ..() + +/mob/living/carbon/human/setDNA() + if(species.flags & NO_SCAN) + return + ..() + /mob/living/carbon/human/has_brain() if(internal_organs_by_name["brain"]) var/datum/organ/internal/brain = internal_organs_by_name["brain"] @@ -1581,4 +1426,4 @@ var/datum/organ/internal/eyes = internal_organs_by_name["eyes"] if(eyes && istype(eyes) && !eyes.status & ORGAN_CUT_AWAY) return 1 - return 0 + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_attackalien.dm b/code/modules/mob/living/carbon/human/human_attackalien.dm deleted file mode 100644 index ea73d63f8d5..00000000000 --- a/code/modules/mob/living/carbon/human/human_attackalien.dm +++ /dev/null @@ -1,62 +0,0 @@ -/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if(check_shields(0, M.name)) - visible_message("\red [M] attempted to touch [src]!") - return 0 - - switch(M.a_intent) - if ("help") - visible_message(text("\blue [M] caresses [src] with its scythe like arm.")) - if ("grab") - if(M == src || anchored) - return - if (w_uniform) - w_uniform.add_fingerprint(M) - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src) - - M.put_in_active_hand(G) - - grabbed_by += G - G.synch() - LAssailant = M - - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message(text("\red [] has grabbed [] passively!", M, src)) - - if("hurt") - if (w_uniform) - w_uniform.add_fingerprint(M) - var/damage = rand(15, 30) - if(!damage) - playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1) - visible_message("\red [M] has lunged at [src]!") - return 0 - var/datum/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting)) - var/armor_block = run_armor_check(affecting, "melee") - - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - visible_message("\red [M] has slashed at [src]!") - - apply_damage(damage, BRUTE, affecting, armor_block) - if (damage >= 25) - visible_message("\red [M] has wounded [src]!") - apply_effect(rand(0.5,3), WEAKEN, armor_block) - updatehealth() - - if("disarm") - if (prob(80)) - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - Weaken(rand(0.5,3)) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has tackled down []!", M, src), 1) - if (prob(25)) - M.Weaken(rand(2,4)) - else - if (prob(80)) - playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - drop_item() - visible_message(text("\red [] disarmed []!", M, src)) - else - playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1) - visible_message(text("\red [] has tried to disarm []!", M, src)) - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index bacef8541bc..46e70c06acb 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -111,7 +111,13 @@ return 1 if("hurt") + + // See if they can attack, and which attacks to use. var/datum/unarmed_attack/attack = M.species.unarmed + if(!attack.is_usable(M)) + attack = M.species.secondary_unarmed + if(!attack.is_usable(M)) + return 0 M.attack_log += text("\[[time_stamp()]\] [pick(attack.attack_verb)]ed [src.name] ([src.ckey])") src.attack_log += text("\[[time_stamp()]\] Has been [pick(attack.attack_verb)]ed by [M.name] ([M.ckey])") diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 8b4e010d4b5..602c00edf62 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -1,7 +1,8 @@ //Updates the mob's health from organs and mob damage variables /mob/living/carbon/human/updatehealth() + if(status_flags & GODMODE) - health = 100 + health = species.total_health stat = CONSCIOUS return var/total_burn = 0 @@ -9,9 +10,15 @@ for(var/datum/organ/external/O in organs) //hardcoded to streamline things a bit total_brute += O.brute_dam total_burn += O.burn_dam - health = 100 - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute + + var/oxy_l = (species.flags & NO_BREATHE ? 0 : getOxyLoss()) + var/tox_l = (species.flags & NO_POISON ? 0 : getToxLoss()) + var/clone_l = getCloneLoss() //TODO: link this to RAD_ABSORB or NO_SCAN + + health = species.total_health - oxy_l - tox_l - clone_l - total_burn - total_brute + //TODO: fix husking - if( ((100 - total_burn) < config.health_threshold_dead) && stat == DEAD) //100 only being used as the magic human max health number, feel free to change it if you add a var for it -- Urist + if( ((species.total_health - total_burn) < config.health_threshold_dead) && stat == DEAD) ChangeToHusk() return diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 337d32652c0..30c883becbc 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -1,8 +1,9 @@ /mob/living/carbon/human/movement_delay() + var/tally = 0 - if(species && species.flags & IS_SLOW) - tally = 7 + if(species.slowdown) + tally = species.slowdown if (istype(loc, /turf/space)) return -1 // It's hard to be slowed down in space by... anything @@ -79,6 +80,10 @@ /mob/living/carbon/human/Process_Spaceslipping(var/prob_slip = 5) //If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such. + + if(species.flags & NO_SLIP) + return + if(stat) prob_slip = 0 // Changing this to zero to make it line up with the comment, and also, make more sense. diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm new file mode 100644 index 00000000000..18373808554 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -0,0 +1,221 @@ +// These should all be procs, you can add them to humans/subspecies by +// species.dm's inherent_verbs ~ Z + +/mob/living/carbon/human/proc/tackle() + set category = "Abilities" + set name = "Tackle" + set desc = "Tackle someone down." + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + src << "You cannot tackle someone in your current state." + return + + var/list/choices = list() + for(var/mob/living/M in view(6,src)) + if(!istype(M,/mob/living/silicon)) + choices += M + choices -= src + + var/mob/living/T = input(src,"Who do you wish to tackle?") as null|anything in choices + + if(!T || !src || src.stat) return + + if(get_dist(get_turf(T), get_turf(src)) > 6) return + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + src << "You cannot leap in your current state." + return + + last_special = world.time + 50 + + var/failed + if(prob(75)) + T.Weaken(rand(0.5,3)) + else + src.Weaken(rand(2,4)) + failed = 1 + + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + if(failed) + src.Weaken(rand(2,4)) + + for(var/mob/O in viewers(src, null)) + if ((O.client && !( O.blinded ))) + O.show_message(text("\red [] [failed ? "tried to tackle" : "has tackled"] down []!", src, T), 1) + +/mob/living/carbon/human/proc/leap() + set category = "Abilities" + set name = "Leap" + set desc = "Leap at a target and grab them aggressively." + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + src << "You cannot leap in your current state." + return + + var/list/choices = list() + for(var/mob/living/M in view(6,src)) + if(!istype(M,/mob/living/silicon)) + choices += M + choices -= src + + var/mob/living/T = input(src,"Who do you wish to leap at?") as null|anything in choices + + if(!T || !src || src.stat) return + + if(get_dist(get_turf(T), get_turf(src)) > 6) return + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + src << "You cannot leap in your current state." + return + + last_special = world.time + 75 + status_flags |= LEAPING + + src.visible_message("\The [src] leaps at [T]!") + src.throw_at(get_step(get_turf(T),get_turf(src)), 5, 1, src) + playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) + + sleep(5) + + if(status_flags & LEAPING) status_flags &= ~LEAPING + + if(!src.Adjacent(T)) + src << "\red You miss!" + return + + T.Weaken(5) + + //Only official cool kids get the grab and no self-prone. + if(src.mind && src.mind.special_role) + src.Weaken(5) + return + + var/use_hand = "left" + if(l_hand) + if(r_hand) + src << "\red You need to have one hand free to grab someone." + return + else + use_hand = "right" + + src.visible_message("\The [src] seizes [T] aggressively!") + + var/obj/item/weapon/grab/G = new(src,T) + if(use_hand == "left") + l_hand = G + else + r_hand = G + + G.state = GRAB_AGGRESSIVE + G.icon_state = "grabbed1" + G.synch() + +/mob/living/carbon/human/proc/gut() + set category = "Abilities" + set name = "Gut" + set desc = "While grabbing someone aggressively, rip their guts out or tear them apart." + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying) + src << "\red You cannot do that in your current state." + return + + var/obj/item/weapon/grab/G = locate() in src + if(!G || !istype(G)) + src << "\red You are not grabbing anyone." + return + + if(G.state < GRAB_AGGRESSIVE) + src << "\red You must have an aggressive grab to gut your prey!" + return + + last_special = world.time + 50 + + visible_message("\The [src] rips viciously at \the [G.affecting]'s body with its claws!") + + if(istype(G.affecting,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = G.affecting + H.apply_damage(50,BRUTE) + if(H.stat == 2) + H.gib() + else + var/mob/living/M = G.affecting + if(!istype(M)) return //wut + M.apply_damage(50,BRUTE) + if(M.stat == 2) + M.gib() + +/mob/living/carbon/human/proc/commune() + set category = "Abilities" + set name = "Commune with creature" + set desc = "Send a telepathic message to an unlucky recipient." + + var/list/targets = list() + var/target = null + var/text = null + + targets += getmobs() //Fill list, prompt user with list + target = input("Select a creature!", "Speak to creature", null, null) as null|anything in targets + + if(!target) return + + text = input("What would you like to say?", "Speak to creature", null, null) + + text = trim(copytext(sanitize(text), 1, MAX_MESSAGE_LEN)) + + if(!text) return + + var/mob/M = targets[target] + + if(istype(M, /mob/dead/observer) || M.stat == DEAD) + src << "Not even a [src.species.name] can speak to the dead." + return + + log_say("[key_name(src)] communed to [key_name(M)]: [text]") + + M << "\blue Like lead slabs crashing into the ocean, alien thoughts drop into your mind: [text]" + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(H.species.name == src.species.name) + return + H << "\red Your nose begins to bleed..." + H.drip(1) + +/mob/living/carbon/human/proc/regurgitate() + set name = "Regurgitate" + set desc = "Empties the contents of your stomach" + set category = "Abilities" + + if(stomach_contents.len) + for(var/mob/M in src) + if(M in stomach_contents) + stomach_contents.Remove(M) + M.loc = loc + src.visible_message("\red [src] hurls out the contents of their stomach!") + return + +/mob/living/carbon/human/proc/psychic_whisper(mob/M as mob in oview()) + set name = "Psychic Whisper" + set desc = "Whisper silently to someone over a distance." + set category = "Abilities" + + var/msg = sanitize(input("Message:", "Psychic Whisper") as text|null) + if(msg) + log_say("PsychicWhisper: [key_name(src)]->[M.key] : [msg]") + M << "\green You hear a strange, alien voice in your head... \italic [msg]" + src << "\green You said: \"[msg]\" to [M]" + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm new file mode 100644 index 00000000000..c313c6015e0 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -0,0 +1,34 @@ +// These may have some say.dm bugs regarding understanding common, +// might be worth adapting the bugs into a feature and using these +// subtypes as a basis for non-common-speaking alien foreigners. ~ Z + +/mob/living/carbon/human/dummy + real_name = "Test Dummy" + status_flags = GODMODE|CANPUSH + +/mob/living/carbon/human/skrell/New(var/new_loc) + h_style = "Skrell Male Tentacles" + ..(new_loc, "Skrell") + +/mob/living/carbon/human/tajaran/New(var/new_loc) + h_style = "Tajaran Ears" + ..(new_loc, "Tajaran") + +/mob/living/carbon/human/unathi/New(var/new_loc) + h_style = "Unathi Horns" + ..(new_loc, "Unathi") + +/mob/living/carbon/human/vox/New(var/new_loc) + h_style = "Short Vox Quills" + ..(new_loc, "Vox") + +/mob/living/carbon/human/voxarmalis/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Vox Armalis") + +/mob/living/carbon/human/diona/New(var/new_loc) + ..(new_loc, "Diona") + +/mob/living/carbon/human/machine/New(var/new_loc) + h_style = "blue IPC screen" + ..(new_loc, "Machine") \ 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 dd02d3c17d7..c4dec0abe89 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -638,9 +638,13 @@ return 1 proc/handle_environment(datum/gas_mixture/environment) + if(!environment) return + //Stuff like the xenomorph's plasma regen happens here. + species.handle_environment_special(src) + //Moved pressure calculations here for use in skip-processing check. var/pressure = environment.return_pressure() var/adjusted_pressure = calculate_affecting_pressure(pressure) @@ -1084,7 +1088,7 @@ handle_organs() //Optimized. handle_blood() - if(health <= config.health_threshold_dead || !has_brain()) + if(health <= config.health_threshold_dead || (species.has_organ["brain"] && !has_brain())) death() blinded = 1 silent = 0 @@ -1660,8 +1664,8 @@ if(stat == 2) holder.icon_state = "hudhealth-100" // X_X else - holder.icon_state = "hud[RoundHealth(health)]" - + var/percentage_health = RoundHealth(((0.0+health)/species.total_health)*100) + holder.icon_state = "hud[percentage_health]" hud_list[HEALTH_HUD] = holder if(hud_updateflag & 1 << STATUS_HUD) diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm index 80d6f00288b..d18d5035025 100644 --- a/code/modules/mob/living/carbon/human/login.dm +++ b/code/modules/mob/living/carbon/human/login.dm @@ -2,4 +2,5 @@ ..() update_hud() ticker.mode.update_all_synd_icons() //This proc only sounds CPU-expensive on paper. It is O(n^2), but the outer for-loop only iterates through syndicates, which are only prsenet in nuke rounds and even when they exist, there's usually 6 of them. - return + if(species) species.handle_login_special(src) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/logout.dm b/code/modules/mob/living/carbon/human/logout.dm new file mode 100644 index 00000000000..f449ce991ad --- /dev/null +++ b/code/modules/mob/living/carbon/human/logout.dm @@ -0,0 +1,4 @@ +/mob/living/carbon/human/Logout() + ..() + if(species) species.handle_logout_special(src) + return \ 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 8d361c70608..2b9878e345c 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -1,4 +1,7 @@ /mob/living/carbon/human/say(var/message) + + //TODO: Add checks for species who do not speak common. + var/verb = "says" var/alt_name = "" var/message_range = world.view @@ -38,6 +41,12 @@ verb = speaking.speech_verb message = copytext(message,3) + // This is broadcast to all mobs with the language, + // irrespective of distance or anything else. + if(speaking.flags & HIVEMIND) + speaking.broadcast(src,trim(message)) + return + message = capitalize(trim(message)) if(speech_problem_flag) @@ -103,16 +112,6 @@ if("whisper") whisper_say(message, speaking, alt_name) return - if("binary") - if(robot_talk_understand || binarycheck()) - robot_talk(message) - return - if("changeling") - if(mind && mind.changeling) - for(var/mob/Changeling in mob_list) - if((Changeling.mind && Changeling.mind.changeling) || istype(Changeling, /mob/dead/observer)) - Changeling << "[mind.changeling.changelingID]: [message]" - return else if(message_mode) if(message_mode in (radiochannels | "department")) @@ -125,8 +124,8 @@ var/sound/speech_sound var/sound_vol - if((species.name == "Vox" || species.name == "Vox Armalis") && prob(20)) - speech_sound = sound('sound/voice/shriek1.ogg') + if(species.speech_sounds && prob(20)) + speech_sound = sound(pick(species.speech_sounds)) sound_vol = 50 ..(message, speaking, verb, alt_name, italics, message_range, used_radios, speech_sound, sound_vol) //ohgod we should really be passing a datum here. @@ -172,8 +171,8 @@ //These only pertain to common. Languages are handled by mob/say_understands() if (!speaking) - if (istype(other, /mob/living/carbon/monkey/diona)) - if(other.languages.len >= 2) //They've sucked down some blood and can speak common now. + if (istype(other, /mob/living/carbon/alien/diona)) + if(other.languages.len >= 2) //They've sucked down some blood and can speak common now. return 1 if (istype(other, /mob/living/silicon)) return 1 diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/human/species.dm similarity index 52% rename from code/modules/mob/living/carbon/species.dm rename to code/modules/mob/living/carbon/human/species.dm index d5e8a167614..d2727d94d33 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -3,24 +3,43 @@ */ /datum/species - var/name // Species name. - + var/name // Species name. var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. var/eyes = "eyes_s" // Icon for eyes. - var/primitive // Lesser form, if any (ie. monkey for humans) - var/tail // Name of tail image in species effects icon file. - var/language // Default racial language, if any. - var/unarmed //For empty hand harm-intent attack - var/unarmed_type = /datum/unarmed_attack - var/secondary_langs = list() // The names of secondary languages that are available to this species. - var/mutantrace // Safeguard due to old code. + var/primitive // Lesser form, if any (ie. monkey for humans) + var/tail // Name of tail image in species effects icon file. + var/language // Default racial language, if any. + var/datum/unarmed_attack/unarmed // For empty hand harm-intent attack + var/datum/unarmed_attack/secondary_unarmed // For empty hand harm-intent attack if the first fails. + var/datum/hud_data/hud + var/hud_type + var/slowdown = 0 + var/gluttonous // Can eat some mobs. 1 for monkeys, 2 for people. + + var/unarmed_type = /datum/unarmed_attack + var/secondary_unarmed_type = /datum/unarmed_attack/bite + + var/secondary_langs = list() // The names of secondary languages that are available to this species. + var/mutantrace // Safeguard due to old code. + var/list/speech_sounds // A list of sounds to potentially play when speaking. + var/has_fine_manipulation = 1 // Can use small items. + var/insulated // Immune to electrocution. + + // Some species-specific gibbing data. + var/gibbed_anim = "gibbed-h" + var/dusted_anim = "dust-h" + var/remains_type = /obj/effect/decal/remains/xeno + var/death_sound + var/death_message = "seizes up and falls limp, their eyes dead and lifeless..." var/breath_type = "oxygen" // Non-oxygen gas breathed, if any. var/poison_type = "phoron" // Poisonous air. var/exhale_type = "carbon_dioxide" // Exhaled gas type. + var/total_health = 100 //Point at which the mob will enter crit. + var/cold_level_1 = 260 // Cold damage level 1 below this point. var/cold_level_2 = 200 // Cold damage level 2 below this point. var/cold_level_3 = 120 // Cold damage level 3 below this point. @@ -54,6 +73,8 @@ var/race_key = 0 var/icon/icon_template + // Species-specific abilities. + var/list/inherent_verbs var/list/has_organ = list( "heart" = /datum/organ/internal/heart, "lungs" = /datum/organ/internal/lungs, @@ -63,12 +84,30 @@ "appendix" = /datum/organ/internal/appendix, "eyes" = /datum/organ/internal/eyes ) + /datum/species/New() - unarmed = new unarmed_type() + if(hud_type) + hud = new hud_type() + else + hud = new() + + if(unarmed_type) unarmed = new unarmed_type() + if(secondary_unarmed_type) secondary_unarmed = new secondary_unarmed_type() /datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. - //This is a basic humanoid limb setup. + + //Trying to work out why species changes aren't fixing organs properly. + if(H.organs) H.organs.Cut() + if(H.internal_organs) H.internal_organs.Cut() + if(H.organs_by_name) H.organs_by_name.Cut() + if(H.internal_organs_by_name) H.internal_organs_by_name.Cut() + H.organs = list() + H.internal_organs = list() + H.organs_by_name = list() + H.internal_organs_by_name = list() + + //This is a basic humanoid limb setup. H.organs_by_name["chest"] = new/datum/organ/external/chest() H.organs_by_name["groin"] = new/datum/organ/external/groin(H.organs_by_name["chest"]) H.organs_by_name["head"] = new/datum/organ/external/head(H.organs_by_name["chest"]) @@ -81,7 +120,6 @@ H.organs_by_name["l_foot"] = new/datum/organ/external/l_foot(H.organs_by_name["l_leg"]) H.organs_by_name["r_foot"] = new/datum/organ/external/r_foot(H.organs_by_name["r_leg"]) - H.internal_organs = list() for(var/organ in has_organ) var/organ_type = has_organ[organ] H.internal_organs_by_name[organ] = new organ_type(H) @@ -99,19 +137,60 @@ for(var/datum/organ/internal/I in H.internal_organs) I.mechanize() -/datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H) //Handles anything not already covered by basic species assignment. +/datum/species/proc/hug(var/mob/living/carbon/human/H,var/mob/living/target) + + var/t_him = "them" + switch(target.gender) + if(MALE) + t_him = "him" + if(FEMALE) + t_him = "her" + + H.visible_message("[H] hugs [target] to make [t_him] feel better!", \ + "You hug [target] to make [t_him] feel better!") + +/datum/species/proc/remove_inherent_verbs(var/mob/living/carbon/human/H) + if(inherent_verbs) + for(var/verb_path in inherent_verbs) + H.verbs -= verb_path return +/datum/species/proc/add_inherent_verbs(var/mob/living/carbon/human/H) + if(inherent_verbs) + for(var/verb_path in inherent_verbs) + H.verbs |= verb_path + return + +/datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H) //Handles anything not already covered by basic species assignment. + add_inherent_verbs(H) + /datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns). if(flags & IS_SYNTHETIC) - //H.make_jittery(200) //S-s-s-s-sytem f-f-ai-i-i-i-i-lure-ure-ure-ure H.h_style = "" spawn(100) - //H.is_jittery = 0 - //H.jitteriness = 0 H.update_hair() return +// Only used for alien plasma weeds atm, but could be used for Dionaea later. +/datum/species/proc/handle_environment_special(var/mob/living/carbon/human/H) + return + +// Used to update alien icons for aliens. +/datum/species/proc/handle_login_special(var/mob/living/carbon/human/H) + return + +// As above. +/datum/species/proc/handle_logout_special(var/mob/living/carbon/human/H) + return + +// Builds the HUD using species-specific icons and usable slots. +/datum/species/proc/build_hud(var/mob/living/carbon/human/H) + return + +// Grabs the window recieved when you click-drag someone onto you. +/datum/species/proc/get_inventory_dialogue(var/mob/living/carbon/human/H) + return + /datum/species/human name = "Human" language = "Sol Common" @@ -130,8 +209,10 @@ language = "Sinta'unathi" tail = "sogtail" unarmed_type = /datum/unarmed_attack/claws + secondary_unarmed_type = /datum/unarmed_attack/bite/strong primitive = /mob/living/carbon/monkey/unathi darksight = 3 + gluttonous = 1 cold_level_1 = 280 //Default 260 - Lower is better cold_level_2 = 220 //Default 200 @@ -191,7 +272,10 @@ icobase = 'icons/mob/human_races/r_vox.dmi' deform = 'icons/mob/human_races/r_def_vox.dmi' language = "Vox-pidgin" - unarmed_type = /datum/unarmed_attack/claws //I dont think it will hurt to give vox claws too. + unarmed_type = /datum/unarmed_attack/claws/strong + secondary_unarmed_type = /datum/unarmed_attack/bite/strong + + speech_sounds = list('sound/voice/shriek1.ogg') warning_low_pressure = 50 hazard_low_pressure = 0 @@ -204,6 +288,7 @@ breath_type = "nitrogen" poison_type = "oxygen" + insulated = 1 flags = NO_SCAN @@ -212,23 +297,24 @@ reagent_tag = IS_VOX -/datum/species/vox/handle_post_spawn(var/mob/living/carbon/human/H) + inherent_verbs = list( + /mob/living/carbon/human/proc/leap + ) - H.verbs += /mob/living/carbon/human/proc/leap - ..() - -/datum/species/vox/armalis/handle_post_spawn(var/mob/living/carbon/human/H) - - H.verbs += /mob/living/carbon/human/proc/gut - H.verbs += /mob/living/carbon/human/proc/commune - ..() + has_organ = list( + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "liver" = /datum/organ/internal/liver, + "kidneys" = /datum/organ/internal/kidney, + "brain" = /datum/organ/internal/brain, + "eyes" = /datum/organ/internal/eyes + ) /datum/species/vox/armalis name = "Vox Armalis" icobase = 'icons/mob/human_races/r_armalis.dmi' deform = 'icons/mob/human_races/r_armalis.dmi' language = "Vox-pidgin" - unarmed_type = /datum/unarmed_attack/claws/armalis warning_low_pressure = 50 hazard_low_pressure = 0 @@ -258,13 +344,29 @@ reagent_tag = IS_VOX + inherent_verbs = list( + /mob/living/carbon/human/proc/leap, + /mob/living/carbon/human/proc/gut, + /mob/living/carbon/human/proc/commune + ) + /datum/species/diona name = "Diona" icobase = 'icons/mob/human_races/r_diona.dmi' deform = 'icons/mob/human_races/r_def_plant.dmi' language = "Rootspeak" unarmed_type = /datum/unarmed_attack/diona - primitive = /mob/living/carbon/monkey/diona + primitive = /mob/living/carbon/alien/diona + slowdown = 7 + + has_organ = list( + "nutrient channel" = /datum/organ/internal/diona/nutrients, + "neural strata" = /datum/organ/internal/diona/strata, + "response node" = /datum/organ/internal/diona/node, + "gas bladder" = /datum/organ/internal/diona/bladder, + "polyp segment" = /datum/organ/internal/diona/polyp, + "anchoring ligament" = /datum/organ/internal/diona/ligament + ) warning_low_pressure = 50 hazard_low_pressure = -1 @@ -279,7 +381,7 @@ body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not - flags = IS_WHITELISTED | NO_BREATHE | REQUIRE_LIGHT | NO_SCAN | IS_PLANT | RAD_ABSORB | NO_BLOOD | IS_SLOW | NO_PAIN + flags = IS_WHITELISTED | NO_BREATHE | REQUIRE_LIGHT | NO_SCAN | IS_PLANT | RAD_ABSORB | NO_BLOOD | NO_PAIN | NO_SLIP blood_color = "#004400" flesh_color = "#907E4A" @@ -288,17 +390,16 @@ /datum/species/diona/handle_post_spawn(var/mob/living/carbon/human/H) H.gender = NEUTER - return ..() /datum/species/diona/handle_death(var/mob/living/carbon/human/H) - var/mob/living/carbon/monkey/diona/S = new(get_turf(H)) + var/mob/living/carbon/alien/diona/S = new(get_turf(H)) if(H.mind) H.mind.transfer_to(S) - for(var/mob/living/carbon/monkey/diona/D in H.contents) + for(var/mob/living/carbon/alien/diona/D in H.contents) if(D.client) D.loc = H.loc else @@ -335,18 +436,65 @@ blood_color = "#1F181F" flesh_color = "#575757" -//Species unarmed attacks + has_organ = list( + "heart" = /datum/organ/internal/heart, + "brain" = /datum/organ/internal/brain, + ) +// Called when using the shredding behavior. +/datum/species/proc/can_shred(var/mob/living/carbon/human/H) + + if(H.a_intent != "hurt") + return 0 + + if(unarmed.shredding && unarmed.is_usable(H)) + return 1 + else if(secondary_unarmed.shredding && secondary_unarmed.is_usable(H)) + return 1 + + return 0 + +//Species unarmed attacks /datum/unarmed_attack var/attack_verb = list("attack") // Empty hand hurt intent verb. var/damage = 0 // Extra empty hand attack damage. var/attack_sound = "punch" var/miss_sound = 'sound/weapons/punchmiss.ogg' + var/shredding = 0 // Calls the old attack_alien() behavior on objects/mobs when on harm intent. var/sharp = 0 var/edge = 0 +/datum/unarmed_attack/proc/is_usable(var/mob/living/carbon/human/user) + if(user.restrained()) + return 0 + + // Check if they have a functioning hand. + var/datum/organ/external/E = user.organs_by_name["l_hand"] + if(E && !(E.status & ORGAN_DESTROYED)) + return 1 + + E = user.organs_by_name["r_hand"] + if(E && !(E.status & ORGAN_DESTROYED)) + return 1 + + return 0 + +/datum/unarmed_attack/bite + attack_verb = list("bite") // 'x has biteed y', needs work. + attack_sound = 'sound/weapons/bite.ogg' + shredding = 1 + damage = 5 + sharp = 1 + edge = 1 + +/datum/unarmed_attack/bite/is_usable(var/mob/living/carbon/human/user) + if (user.wear_mask && istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) + return 0 + return 1 + /datum/unarmed_attack/punch attack_verb = list("punch") + damage = 3 /datum/unarmed_attack/diona attack_verb = list("lash", "bludgeon") @@ -360,6 +508,47 @@ sharp = 1 edge = 1 -/datum/unarmed_attack/claws/armalis - attack_verb = list("slash", "claw") - damage = 10 //they're huge! they should do a little more damage, i'd even go for 15-20 maybe... +/datum/unarmed_attack/claws/strong + attack_verb = list("slash") + damage = 10 + shredding = 1 + +/datum/unarmed_attack/bite/strong + attack_verb = list("maul") + damage = 15 + shredding = 1 + +/datum/hud_data + var/icon // If set, overrides ui_style. + var/has_a_intent = 1 // Set to draw intent box. + var/has_m_intent = 1 // Set to draw move intent box. + var/has_warnings = 1 // Set to draw environment warnings. + var/has_pressure = 1 // Draw the pressure indicator. + var/has_nutrition = 1 // Draw the nutrition indicator. + var/has_bodytemp = 1 // Draw the bodytemp indicator. + var/has_hands = 1 // Set to draw shand. + var/has_drop = 1 // Set to draw drop button. + var/has_throw = 1 // Set to draw throw button. + var/has_resist = 1 // Set to draw resist button. + var/has_internals = 1 // Set to draw the internals toggle button. + + // Contains information on the position and tag for all inventory slots + // to be drawn for the mob. This is fairly delicate, try to avoid messing with it + // unless you know exactly what it does. + var/list/gear = list( + "i_clothing" = list("loc" = ui_iclothing, "slot" = slot_w_uniform, "state" = "center", "toggle" = 1, "dir" = SOUTH), + "o_clothing" = list("loc" = ui_oclothing, "slot" = slot_wear_suit, "state" = "equip", "toggle" = 1, "dir" = SOUTH), + "mask" = list("loc" = ui_mask, "slot" = slot_wear_mask, "state" = "equip", "toggle" = 1, "dir" = NORTH), + "gloves" = list("loc" = ui_gloves, "slot" = slot_gloves, "state" = "gloves", "toggle" = 1), + "eyes" = list("loc" = ui_glasses, "slot" = slot_glasses, "state" = "glasses","toggle" = 1), + "l_ear" = list("loc" = ui_l_ear, "slot" = slot_l_ear, "state" = "ears", "toggle" = 1), + "r_ear" = list("loc" = ui_r_ear, "slot" = slot_r_ear, "state" = "ears", "toggle" = 1), + "head" = list("loc" = ui_head, "slot" = slot_head, "state" = "hair", "toggle" = 1), + "shoes" = list("loc" = ui_shoes, "slot" = slot_shoes, "state" = "shoes", "toggle" = 1), + "suit storage" = list("loc" = ui_sstore1, "slot" = slot_s_store, "state" = "belt", "dir" = 8), + "back" = list("loc" = ui_back, "slot" = slot_back, "state" = "back", "dir" = NORTH), + "id" = list("loc" = ui_id, "slot" = slot_wear_id, "state" = "id", "dir" = NORTH), + "storage1" = list("loc" = ui_storage1, "slot" = slot_l_store, "state" = "pocket"), + "storage2" = list("loc" = ui_storage2, "slot" = slot_r_store, "state" = "pocket"), + "belt" = list("loc" = ui_belt, "slot" = slot_belt, "state" = "belt") + ) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 2ae79230d22..ad609cad732 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -412,7 +412,7 @@ proc/get_damage_icon_part(damage_state, body_part) if(f_style) var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] - if(facial_hair_style && src.species.name in facial_hair_style.species_allowed) + if(facial_hair_style && facial_hair_style.species_allowed && src.species.name in facial_hair_style.species_allowed) var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") if(facial_hair_style.do_colouration) facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm index c82d517d590..7820e2a416f 100644 --- a/code/modules/mob/living/carbon/metroid/life.dm +++ b/code/modules/mob/living/carbon/metroid/life.dm @@ -362,11 +362,11 @@ else for(var/mob/living/carbon/C in targets) if(!Discipline && prob(5)) - if(ishuman(C) || isalienadult(C)) + if(ishuman(C)) Target = C break - if(islarva(C) || ismonkey(C)) + if(isalien(C) || ismonkey(C)) Target = C break diff --git a/code/modules/mob/living/carbon/metroid/metroid.dm b/code/modules/mob/living/carbon/metroid/metroid.dm index 85fdb33a8da..df9d22c5dc2 100644 --- a/code/modules/mob/living/carbon/metroid/metroid.dm +++ b/code/modules/mob/living/carbon/metroid/metroid.dm @@ -54,6 +54,9 @@ var/core_removal_stage = 0 //For removing cores. /mob/living/carbon/slime/New() + + verbs += /mob/living/proc/ventcrawl + create_reagents(100) spawn (0) number = rand(1, 1000) @@ -274,7 +277,7 @@ updatehealth() return -/mob/living/carbon/slime/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/carbon/slime/attack_animal(mob/living/M as mob) if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else @@ -447,93 +450,6 @@ visible_message("[M] has attempted to punch [src]!") return - - -/mob/living/carbon/slime/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - switch(M.a_intent) - if ("help") - visible_message("[M] caresses [src] with its scythe like arm.") - - if ("hurt") - - if (prob(95)) - attacked += 10 - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - var/damage = rand(15, 30) - if (damage >= 25) - damage = rand(20, 40) - visible_message("[M] has attacked [name]!", \ - "[M] has attacked [name]!") - else - visible_message("[M] has wounded [name]!", \ - ")[M] has wounded [name]!") - adjustBruteLoss(damage) - updatehealth() - else - playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to lunge at [name]!", \ - "[M] has attempted to lunge at [name]!") - - if ("grab") - if (M == src || anchored) - return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src ) - - M.put_in_active_hand(G) - - G.synch() - - LAssailant = M - - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message(" [M] has grabbed [name] passively!") - - if ("disarm") - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - var/damage = 5 - attacked += 10 - - if(prob(95)) - visible_message("[M] has tackled [name]!", \ - "[M] has tackled [name]!") - - if(Victim || Target) - Victim = null - Target = null - anchored = 0 - if(prob(80) && !client) - Discipline++ - if(!istype(src, /mob/living/carbon/slime)) - if(Discipline == 1) - attacked = 0 - - spawn() - SStun = 1 - sleep(rand(5,20)) - SStun = 0 - - spawn(0) - - step_away(src,M,15) - sleep(3) - step_away(src,M,15) - - else - drop_item() - visible_message("[M] has disarmed [name]!", - "[M] has disarmed [name]!") - adjustBruteLoss(damage) - updatehealth() - return - /mob/living/carbon/slime/attackby(obj/item/W, mob/user) if(W.force > 0) attacked += 10 @@ -615,6 +531,11 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75 ++Discipline return +/mob/living/carbon/slime/can_use_vents() + if(Victim) + return "You cannot ventcrawl while feeding." + ..() + /obj/item/slime_extract name = "slime extract" desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"." diff --git a/code/modules/mob/living/carbon/metroid/powers.dm b/code/modules/mob/living/carbon/metroid/powers.dm index bb7dcbe7bbc..15fdb60349f 100644 --- a/code/modules/mob/living/carbon/metroid/powers.dm +++ b/code/modules/mob/living/carbon/metroid/powers.dm @@ -104,7 +104,7 @@ adjustBruteLoss(-10) adjustFireLoss(-10) adjustCloneLoss(-10) - + updatehealth() if(Victim) Victim.updatehealth() @@ -225,11 +225,4 @@ else src << "I am not ready to reproduce yet..." else - src << "I am not old enough to reproduce yet..." - -/mob/living/carbon/slime/verb/ventcrawl() - set name = "Crawl through Vent" - set desc = "Enter an air vent and crawl through the pipe system." - set category = "Slime" - if(Victim) return - handle_ventcrawl() \ No newline at end of file + src << "I am not old enough to reproduce yet..." \ No newline at end of file diff --git a/code/modules/mob/living/carbon/monkey/diona.dm b/code/modules/mob/living/carbon/monkey/diona.dm deleted file mode 100644 index 0a123347010..00000000000 --- a/code/modules/mob/living/carbon/monkey/diona.dm +++ /dev/null @@ -1,267 +0,0 @@ -/* - Tiny babby plant critter plus procs. -*/ - -//Mob defines. -/mob/living/carbon/monkey/diona - name = "diona nymph" - voice_name = "diona nymph" - speak_emote = list("chirrups") - icon_state = "nymph1" - var/list/donors = list() - var/ready_evolve = 0 - universal_understand = 0 // Dionaea do not need to speak to people - universal_speak = 0 // before becoming an adult. Use *chirp. - holder_type = /obj/item/weapon/holder/diona - -/mob/living/carbon/monkey/diona/attack_hand(mob/living/carbon/human/M as mob) - - //Let people pick the little buggers up. - if(M.a_intent == "help") - if(M.species && M.species.name == "Diona") - M << "You feel your being twine with that of [src] as it merges with your biomass." - src << "You feel your being twine with that of [M] as you merge with its biomass." - src.verbs += /mob/living/carbon/monkey/diona/proc/split - src.verbs -= /mob/living/carbon/monkey/diona/proc/merge - src.loc = M - else - get_scooped(M) - - ..() - -/mob/living/carbon/monkey/diona/New() - - ..() - gender = NEUTER - dna.mutantrace = "plant" - greaterform = "Diona" - add_language("Rootspeak") - src.verbs += /mob/living/carbon/monkey/diona/proc/merge - -//Verbs after this point. - -/mob/living/carbon/monkey/diona/proc/merge() - - set category = "Diona" - set name = "Merge with gestalt" - set desc = "Merge with another diona." - - if(istype(src.loc,/mob/living/carbon)) - src.verbs -= /mob/living/carbon/monkey/diona/proc/merge - return - - var/list/choices = list() - for(var/mob/living/carbon/C in view(1,src)) - - if(!(src.Adjacent(C)) || !(C.client)) continue - - if(istype(C,/mob/living/carbon/human)) - var/mob/living/carbon/human/D = C - if(D.species && D.species.name == "Diona") - choices += C - - var/mob/living/M = input(src,"Who do you wish to merge with?") in null|choices - - if(!M || !src || !(src.Adjacent(M))) return - - if(istype(M,/mob/living/carbon/human)) - M << "You feel your being twine with that of [src] as it merges with your biomass." - M.status_flags |= PASSEMOTES - - src << "You feel your being twine with that of [M] as you merge with its biomass." - src.loc = M - src.verbs += /mob/living/carbon/monkey/diona/proc/split - src.verbs -= /mob/living/carbon/monkey/diona/proc/merge - else - return - -/mob/living/carbon/monkey/diona/proc/split() - - set category = "Diona" - set name = "Split from gestalt" - set desc = "Split away from your gestalt as a lone nymph." - - if(!(istype(src.loc,/mob/living/carbon))) - src.verbs -= /mob/living/carbon/monkey/diona/proc/split - return - - src.loc << "You feel a pang of loss as [src] splits away from your biomass." - src << "You wiggle out of the depths of [src.loc]'s biomass and plop to the ground." - - var/mob/living/M = src.loc - - src.loc = get_turf(src) - src.verbs -= /mob/living/carbon/monkey/diona/proc/split - src.verbs += /mob/living/carbon/monkey/diona/proc/merge - - if(istype(M)) - for(var/atom/A in M.contents) - if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/weapon/holder)) - return - M.status_flags &= ~PASSEMOTES - -/mob/living/carbon/monkey/diona/verb/fertilize_plant() - - set category = "Diona" - set name = "Fertilize plant" - set desc = "Turn your food into nutrients for plants." - - var/list/trays = list() - for(var/obj/machinery/portable_atmospherics/hydroponics/tray in range(1)) - if(tray.nutrilevel < 10 && src.Adjacent(tray)) - trays += tray - - var/obj/machinery/portable_atmospherics/hydroponics/target = input("Select a tray:") as null|anything in trays - - if(!src || !target || target.nutrilevel == 10) return //Sanity check. - - src.nutrition -= ((10-target.nutrilevel)*5) - target.nutrilevel = 10 - src.visible_message("\red [src] secretes a trickle of green liquid from its tail, refilling [target]'s nutrient tray.","\red You secrete a trickle of green liquid from your tail, refilling [target]'s nutrient tray.") - -/mob/living/carbon/monkey/diona/verb/eat_weeds() - - set category = "Diona" - set name = "Eat Weeds" - set desc = "Clean the weeds out of soil or a hydroponics tray." - - var/list/trays = list() - for(var/obj/machinery/portable_atmospherics/hydroponics/tray in range(1)) - if(tray.weedlevel > 0 && src.Adjacent(tray)) - trays += tray - - var/obj/machinery/portable_atmospherics/hydroponics/target = input("Select a tray:") as null|anything in trays - - if(!src || !target || target.weedlevel == 0) return //Sanity check. - - src.reagents.add_reagent("nutriment", target.weedlevel) - target.weedlevel = 0 - src.visible_message("\red [src] begins rooting through [target], ripping out weeds and eating them noisily.","\red You begin rooting through [target], ripping out weeds and eating them noisily.") - -/mob/living/carbon/monkey/diona/verb/evolve() - - set category = "Diona" - set name = "Evolve" - set desc = "Grow to a more complex form." - - if(!is_alien_whitelisted(src, "Diona") && config.usealienwhitelist) - src << alert("You are currently not whitelisted to play as a full diona.") - return 0 - - if(donors.len < 5) - src << "You are not yet ready for your growth..." - return - - if(nutrition < 400) - src << "You have not yet consumed enough to grow..." - return - - src.split() - src.visible_message("\red [src] begins to shift and quiver, and erupts in a shower of shed bark as it splits into a tangle of nearly a dozen new dionaea.","\red You begin to shift and quiver, feeling your awareness splinter. All at once, we consume our stored nutrients to surge with growth, splitting into a tangle of at least a dozen new dionaea. We have attained our gestalt form.") - - var/mob/living/carbon/human/adult = new(get_turf(src.loc)) - adult.set_species("Diona") - - if(istype(loc,/obj/item/weapon/holder/diona)) - var/obj/item/weapon/holder/diona/L = loc - src.loc = L.loc - del(L) - - for(var/datum/language/L in languages) - adult.add_language(L.name) - adult.regenerate_icons() - - adult.name = "diona ([rand(100,999)])" - adult.real_name = adult.name - adult.ckey = src.ckey - - for (var/obj/item/W in src.contents) - src.drop_from_inventory(W) - del(src) - -/mob/living/carbon/monkey/diona/verb/steal_blood() - set category = "Diona" - set name = "Steal Blood" - set desc = "Take a blood sample from a suitable donor." - - var/list/choices = list() - for(var/mob/living/carbon/human/H in oview(1,src)) - if(src.Adjacent(H)) - choices += H - - var/mob/living/carbon/human/M = input(src,"Who do you wish to take a sample from?") in null|choices - - if(!M || !src) return - - if(M.species.flags & NO_BLOOD) - src << "\red That donor has no blood to take." - return - - if(donors.Find(M.real_name)) - src << "\red That donor offers you nothing new." - return - - src.visible_message("\red [src] flicks out a feeler and neatly steals a sample of [M]'s blood.","\red You flick out a feeler and neatly steal a sample of [M]'s blood.") - donors += M.real_name - for(var/datum/language/L in M.languages) - languages |= L - - spawn(25) - update_progression() - -/mob/living/carbon/monkey/diona/proc/update_progression() - - if(!donors.len) - return - - if(donors.len == 5) - ready_evolve = 1 - src << "\green You feel ready to move on to your next stage of growth." - else if(donors.len == 3) - universal_understand = 1 - src << "\green You feel your awareness expand, and realize you know how to understand the creatures around you." - else - src << "\green The blood seeps into your small form, and you draw out the echoes of memories and personality from it, working them into your budding mind." - - -/mob/living/carbon/monkey/diona/say_understands(var/mob/other,var/datum/language/speaking = null) - - if (istype(other, /mob/living/carbon/human) && !speaking) - if(languages.len >= 2) // They have sucked down some blood. - return 1 - return ..() - -/mob/living/carbon/monkey/diona/say(var/message) - var/verb = "says" - var/message_range = world.view - - if(client) - if(client.prefs.muted & MUTE_IC) - src << "\red You cannot speak in IC (Muted)." - return - - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - - if(stat == 2) - return say_dead(message) - - var/datum/language/speaking = null - - if(length(message) >= 2) - var/channel_prefix = copytext(message, 1 ,3) - if(languages.len) - for(var/datum/language/L in languages) - if(lowertext(channel_prefix) == ":[L.key]") - verb = L.speech_verb - speaking = L - break - - if(speaking) - message = trim(copytext(message,3)) - - message = capitalize(trim_left(message)) - - if(!message || stat) - return - - ..(message, speaking, verb, null, null, message_range, null) diff --git a/code/modules/mob/living/carbon/monkey/emote.dm b/code/modules/mob/living/carbon/monkey/emote.dm index d5328183f31..92493b6d386 100644 --- a/code/modules/mob/living/carbon/monkey/emote.dm +++ b/code/modules/mob/living/carbon/monkey/emote.dm @@ -31,11 +31,6 @@ if ("custom") return custom_emote(m_type, message) - if ("chirp") - if(istype(src,/mob/living/carbon/monkey/diona)) - message = "The [src.name] chirps!" - playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0) - m_type = 2 if("sign") if (!src.restrained()) message = text("The monkey signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null)) @@ -119,10 +114,7 @@ message = "The [src.name] lets out a faint chimper as it collapses and stops moving..." m_type = 1 if("help") - var/text = "choke, " - if(istype(src,/mob/living/carbon/monkey/diona)) - text += "chirp, " - text += "collapse, dance, deathgasp, drool, gasp, shiver, gnarl, jump, paw, moan, nod, roar, roll, scratch,\nscretch, shake, sign-#, sit, sulk, sway, tail, twitch, whimper" + text += "choke, collapse, dance, deathgasp, drool, gasp, shiver, gnarl, jump, paw, moan, nod, roar, roll, scratch,\nscretch, shake, sign-#, sit, sulk, sway, tail, twitch, whimper" src << text else src << text("Invalid Emote: []", act) diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index 44a7e7a2593..50380a580ae 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -23,16 +23,14 @@ environment = loc.return_air() if (stat != DEAD) - if(!istype(src,/mob/living/carbon/monkey/diona)) //still breathing - //First, resolve location and get a breath - if(air_master.current_cycle%4==2) - //Only try to take a breath every 4 seconds, unless suffocating - breathe() - 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) - + //First, resolve location and get a breath + if(air_master.current_cycle%4==2) + //Only try to take a breath every 4 seconds, unless suffocating + breathe() + 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) //Updates the number of stored chemicals for powers handle_changeling() @@ -122,15 +120,6 @@ if (radiation) - if(istype(src,/mob/living/carbon/monkey/diona)) //Filthy check. Dionaea don't take rad damage. - var/rads = radiation/25 - radiation -= rads - nutrition += rads - heal_overall_damage(rads,rads) - adjustOxyLoss(-(rads)) - adjustToxLoss(-(rads)) - return - if (radiation > 100) radiation = 100 Weaken(10) @@ -439,27 +428,8 @@ proc/handle_chemicals_in_body() - if(alien) //Diona nymphs are the only alien monkey currently. - 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 - traumatic_shock -= light_amount - - if(nutrition > 500) - nutrition = 500 - if(light_amount > 2) //if there's enough light, heal - adjustBruteLoss(-1) - adjustToxLoss(-1) - adjustOxyLoss(-1) - if(reagents && reagents.reagent_list.len) - reagents.metabolize(src,alien) + reagents.metabolize(src) if (drowsyness) drowsyness-- diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 7bb9af2a158..2d9abfa2466 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -14,7 +14,6 @@ //var/uni_append = "12C4E2" // Small appearance modifier for different species. var/list/uni_append = list(0x12C,0x4E2) // Same as above for DNA2. var/update_muts = 1 // Monkey gene must be set at start. - var/alien = 0 //Used for reagent metabolism. /mob/living/carbon/monkey/tajara name = "farwa" @@ -98,15 +97,6 @@ greaterform = "Tajaran" add_language("Siik'tajr") -/mob/living/carbon/monkey/diona/New() - - ..() - alien = 1 - gender = NEUTER - dna.mutantrace = "plant" - greaterform = "Diona" - add_language("Rootspeak") - /mob/living/carbon/monkey/movement_delay() var/tally = 0 if(reagents) @@ -301,78 +291,7 @@ O.show_message(text("\red [] has disarmed [name]!", M), 1) return -/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - 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) - - if ("hurt") - if ((prob(95) && health > 0)) - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - var/damage = rand(15, 30) - if (damage >= 25) - 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("\red [] has wounded [name]!", M), 1) - else - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has slashed [name]!", M), 1) - 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("\red [] has attempted to lunge at [name]!", M), 1) - - if ("grab") - if (M == src) - return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src ) - - M.put_in_active_hand(G) - - grabbed_by += G - G.synch() - - 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) - - if ("disarm") - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - var/damage = 5 - if(prob(95)) - Weaken(15) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has tackled down [name]!", M), 1) - else - drop_item() - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has disarmed [name]!", M), 1) - adjustBruteLoss(damage) - updatehealth() - return - -/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/carbon/monkey/attack_animal(mob/living/M as mob) if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else diff --git a/code/modules/mob/living/carbon/monkey/powers.dm b/code/modules/mob/living/carbon/monkey/powers.dm deleted file mode 100644 index e7c6937cda2..00000000000 --- a/code/modules/mob/living/carbon/monkey/powers.dm +++ /dev/null @@ -1,5 +0,0 @@ -/mob/living/carbon/monkey/verb/ventcrawl() - set name = "Crawl through Vent" - set desc = "Enter an air vent and crawl through the pipe system." - set category = "Monkey" - handle_ventcrawl() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index a4e5e0586fd..8fc440c9217 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1,4 +1,3 @@ - /mob/living/verb/succumb() set hidden = 1 if ((src.health < 0 && src.health > -95.0)) @@ -611,7 +610,7 @@ if(CM.handcuffed && CM.canmove && (CM.last_special <= world.time)) CM.next_move = world.time + 100 CM.last_special = world.time + 100 - if(isalienadult(CM) || (HULK in usr.mutations))//Don't want to do a lot of logic gating here. + if(HULK in usr.mutations) //Don't want to do a lot of logic gating here. usr << "\red You attempt to break your handcuffs. (This will take around 5 seconds and you need to stand still)" for(var/mob/O in viewers(CM)) O.show_message(text("\red [] is trying to break the handcuffs!", CM), 1) @@ -648,7 +647,7 @@ else if(CM.legcuffed && CM.canmove && (CM.last_special <= world.time)) CM.next_move = world.time + 100 CM.last_special = world.time + 100 - if(isalienadult(CM) || (HULK in usr.mutations))//Don't want to do a lot of logic gating here. + if(HULK in usr.mutations) //Don't want to do a lot of logic gating here. usr << "\red You attempt to break your legcuffs. (This will take around 5 seconds and you need to stand still)" for(var/mob/O in viewers(CM)) O.show_message(text("\red [] is trying to break the legcuffs!", CM), 1) @@ -699,6 +698,11 @@ src << "You can't vent crawl while you're stunned!" return + var/special_fail_msg = can_use_vents() + if(special_fail_msg) + src << "\red [special_fail_msg]" + return + if(vent_found) // one was passed in, probably from vent/AltClick() if(vent_found.welded) src << "That vent is welded shut." @@ -784,6 +788,9 @@ var/area/new_area = get_area(loc) if(new_area) new_area.Entered(src) +/mob/living/proc/can_use_vents() + return "You can't fit into that vent." + /mob/living/proc/has_brain() return 1 diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 312bccff0fd..1ac5faa11fa 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -38,3 +38,11 @@ var/tod = null // Time of death var/update_slimes = 1 var/silent = null //Can't talk. Value goes down every life proc. + + // Putting these here for attack_animal(). + var/melee_damage_lower = 0 + var/melee_damage_upper = 0 + var/attacktext = "attacks" + var/attack_sound = null + var/friendly = "nuzzles" + var/wall_smash = 0 \ No newline at end of file diff --git a/code/modules/mob/living/living_powers.dm b/code/modules/mob/living/living_powers.dm new file mode 100644 index 00000000000..d2a8e35320e --- /dev/null +++ b/code/modules/mob/living/living_powers.dm @@ -0,0 +1,18 @@ +/mob/living/proc/ventcrawl() + set name = "Crawl through Vent" + set desc = "Enter an air vent and crawl through the pipe system." + set category = "Abilities" + handle_ventcrawl() + return + +/mob/living/proc/hide() + set name = "Hide" + set desc = "Allows to hide beneath tables or certain items. Toggled on or off." + set category = "Abilities" + + if (layer != TURF_LAYER+0.2) + layer = TURF_LAYER+0.2 + src << text("\blue You are now hiding.") + else + layer = MOB_LAYER + src << text("\blue You have stopped hiding.") \ No newline at end of file diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 95dd82aafed..f778e462096 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -9,12 +9,8 @@ var/list/department_radio_keys = list( ":e" = "Engineering", "#e" = "Engineering", ".e" = "Engineering", ":s" = "Security", "#s" = "Security", ".s" = "Security", ":w" = "whisper", "#w" = "whisper", ".w" = "whisper", - ":b" = "binary", "#b" = "binary", ".b" = "binary", - ":a" = "alientalk", "#a" = "alientalk", ".a" = "alientalk", ":t" = "Syndicate", "#t" = "Syndicate", ".t" = "Syndicate", ":u" = "Supply", "#u" = "Supply", ".u" = "Supply", - ":g" = "changeling", "#g" = "changeling", ".g" = "changeling", - ":d" = "dronechat", "#d" = "dronechat", ".d" = "dronechat", ":R" = "right ear", "#R" = "right ear", ".R" = "right ear", ":L" = "left ear", "#L" = "left ear", ".L" = "left ear", @@ -26,12 +22,8 @@ var/list/department_radio_keys = list( ":E" = "Engineering", "#E" = "Engineering", ".E" = "Engineering", ":S" = "Security", "#S" = "Security", ".S" = "Security", ":W" = "whisper", "#W" = "whisper", ".W" = "whisper", - ":B" = "binary", "#B" = "binary", ".B" = "binary", - ":A" = "alientalk", "#A" = "alientalk", ".A" = "alientalk", ":T" = "Syndicate", "#T" = "Syndicate", ".T" = "Syndicate", ":U" = "Supply", "#U" = "Supply", ".U" = "Supply", - ":G" = "changeling", "#G" = "changeling", ".G" = "changeling", - ":D" = "dronechat", "#D" = "dronechat", ".D" = "dronechat", //kinda localization -- rastaf0 //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. @@ -45,33 +37,18 @@ var/list/department_radio_keys = list( ":ó" = "Engineering", "#ó" = "Engineering", ".ó" = "Engineering", ":û" = "Security", "#û" = "Security", ".û" = "Security", ":ö" = "whisper", "#ö" = "whisper", ".ö" = "whisper", - ":è" = "binary", "#è" = "binary", ".è" = "binary", - ":ô" = "alientalk", "#ô" = "alientalk", ".ô" = "alientalk", ":å" = "Syndicate", "#å" = "Syndicate", ".å" = "Syndicate", ":é" = "Supply", "#é" = "Supply", ".é" = "Supply", - ":ï" = "changeling", "#ï" = "changeling", ".ï" = "changeling" ) /mob/living/proc/binarycheck() + if (istype(src, /mob/living/silicon/pai)) return - if (issilicon(src)) - return 1 + if (!ishuman(src)) return - var/mob/living/carbon/human/H = src - if (H.l_ear || H.r_ear) - var/obj/item/device/radio/headset/dongle - if(istype(H.l_ear,/obj/item/device/radio/headset)) - dongle = H.l_ear - else - dongle = H.r_ear - if(!istype(dongle)) return - if(dongle.translate_binary) return 1 -/mob/living/proc/hivecheck() - if (isalien(src)) return 1 - if (!ishuman(src)) return var/mob/living/carbon/human/H = src if (H.l_ear || H.r_ear) var/obj/item/device/radio/headset/dongle diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 1fd5dff5357..c84c5b43559 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -511,41 +511,7 @@ var/list/ai_verbs_default = list( updatehealth() return 2 -/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - 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]'s plating with its scythe like arm."), 1) - - else //harm - var/damage = rand(10, 20) - if (prob(90)) - playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has slashed at []!", M, src), 1) - if(prob(8)) - flick("noise", flash) - 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("\red [] took a swipe at []!", M, src), 1) - return - -/mob/living/silicon/ai/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/silicon/ai/attack_animal(mob/living/M as mob) if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 6015ab13023..6c6904e3106 100755 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -3,7 +3,6 @@ icon = 'icons/mob/pai.dmi' icon_state = "repairbot" - robot_talk_understand = 0 emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person) small = 1 pass_flags = 1 @@ -204,40 +203,6 @@ //mob/living/silicon/pai/bullet_act(var/obj/item/projectile/Proj) -/mob/living/silicon/pai/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(src.loc, /turf) && istype(src.loc.loc, /area/start)) - M << "You cannot attack someone in the spawn area." - return - - 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]'s casing with its scythe like arm."), 1) - - else //harm - var/damage = rand(10, 20) - if (prob(90)) - playsound(src.loc, 'sound/weapons/slash.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has slashed at []!", M, src), 1) - if(prob(8)) - flick("noise", src.flash) - src.adjustBruteLoss(damage) - src.updatehealth() - else - playsound(src.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("\red [] took a swipe at []!", M, src), 1) - return - ///mob/living/silicon/pai/attack_hand(mob/living/carbon/M as mob) /mob/living/silicon/pai/proc/switchCamera(var/obj/machinery/camera/C) @@ -470,4 +435,8 @@ pose = addtext(pose,".") //Makes sure all emotes end with a period. msg += "\nIt is [pose]" - usr << msg \ No newline at end of file + usr << msg + +// No binary for pAIs. +/mob/living/silicon/pai/binarycheck() + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index be9a36c8199..cdca3b18ef1 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -13,6 +13,8 @@ lawupdate = 0 density = 1 req_access = list(access_engine, access_robotics) + integrated_light_power = 2 + local_transmit = 1 // We need to keep track of a few module items so we don't need to do list operations // every time we need them. These get set in New() after the module is chosen. @@ -30,6 +32,13 @@ ..() + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + + remove_language("Robot Talk") + add_language("Robot Talk", 0) + add_language("Drone Talk", 1) + if(camera && "Robots" in camera.network) camera.network.Add("Engineering") @@ -87,57 +96,6 @@ /mob/living/silicon/robot/drone/pick_module() return -//Drones can only use binary and say emotes. NOTHING else. -//TBD, fix up boilerplate. ~ Z -/mob/living/silicon/robot/drone/say(var/message) - - if (!message) - return - - if (src.client) - if(client.prefs.muted & MUTE_IC) - src << "You cannot send IC messages (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - - if (stat == 2) - return say_dead(message) - - if(copytext(message,1,2) == "*") - return emote(copytext(message,2)) - else if(length(message) >= 2) - - if(parse_message_mode(message, "NONE") == "dronechat") - - if(!is_component_functioning("radio")) - src << "\red Your radio transmitter isn't functional." - return - - for (var/mob/living/S in living_mob_list) - if(istype(S, /mob/living/silicon/robot/drone)) - S << "Drone Talk, [name] transmits, \"[trim(copytext(message,3))]\"" - - for (var/mob/M in dead_mob_list) - if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) - M << "Drone Talk, [name] transmits, \"[trim(copytext(message,3))]\"" - - else - - var/list/listeners = hearers(5,src) - listeners |= src - - for(var/mob/living/silicon/robot/drone/D in listeners) - if(D.client) D << "[src] transmits, \"[message]\"" - - for (var/mob/M in player_list) - if (istype(M, /mob/new_player)) - continue - else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) - if(M.client) M << "[src] transmits, \"[message]\"" - //Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..(). /mob/living/silicon/robot/drone/attackby(obj/item/weapon/W as obj, mob/user as mob) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm index 2c45af24d1b..bac16de92e6 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm @@ -21,28 +21,6 @@ return -/mob/living/silicon/robot/drone/verb/hide() - set name = "Hide" - set desc = "Allows you to hide beneath tables or certain items. Toggled on or off." - set category = "Drone" - - if (layer != TURF_LAYER+0.2) - layer = TURF_LAYER+0.2 - src << text("\blue You are now hiding.") - else - layer = MOB_LAYER - src << text("\blue You have stopped hiding.") - -/mob/living/silicon/robot/drone/verb/light() - set name = "Light On/Off" - set desc = "Activate a low power omnidirectional LED. Toggled on or off." - set category = "Drone" - - if(luminosity) - SetLuminosity(0) - return - SetLuminosity(2) - //Actual picking-up event. /mob/living/silicon/robot/drone/attack_hand(mob/living/carbon/human/M as mob) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 94a9e138e97..50806f0da2f 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -80,14 +80,14 @@ wrapped = thing break - if(wrapped) //Already have an item. - + if(wrapped) //Already have an item. + //Temporary put wrapped into user so target's attackby() checks pass. wrapped.loc = user - + //Pass the attack on to the target. This might delete/relocate wrapped. target.attackby(wrapped,user) - + //If wrapped did neither get deleted nor put into target, put it back into the gripper. if(wrapped && user && (wrapped.loc == user)) wrapped.loc = src diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index a39f27022c4..667aeb186d2 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -19,6 +19,7 @@ var/list/robot_verbs_default = list( var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best var/crisis //Admin-settable for combat module use. var/crisis_override = 0 + var/integrated_light_power = 5 //Hud stuff @@ -79,6 +80,8 @@ var/list/robot_verbs_default = list( spark_system.set_up(5, 0, src) spark_system.attach(src) + add_language("Robot Talk", 1) + ident = rand(1, 999) updatename("Default") updateicon() @@ -846,72 +849,6 @@ var/list/robot_verbs_default = list( spark_system.start() return ..() -/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - if (!ticker) - M << "You cannot attack people before the game has started." - return - - if (istype(loc, /turf) && istype(loc.loc, /area/start)) - M << "No attacking people at spawn, you jackass." - return - - 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]'s plating with its scythe-like arm."), 1) - - if ("grab") - if (M == src) - return - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src ) - - M.put_in_active_hand(G) - - grabbed_by += G - G.synch() - 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) - - if ("hurt") - var/damage = rand(10, 20) - if (prob(90)) - - playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - for(var/mob/O in viewers(src, null)) - O.show_message(text("\red [] has slashed at []!", M, src), 1) - if(prob(8)) - flick("noise", flash) - 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("\red [] took a swipe at []!", M, src), 1) - - if ("disarm") - if(!(lying)) - if (rand(1,100) <= 85) - Stun(7) - step(src,get_dir(M,src)) - spawn(5) step(src,get_dir(M,src)) - playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1) - for(var/mob/O in viewers(src, null)) - if ((O.client && !( O.blinded ))) - O.show_message(text("\red [] has forced back []!", M, src), 1) - 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("\red [] attempted to force back []!", M, src), 1) - return - - - /mob/living/silicon/robot/attack_slime(mob/living/carbon/slime/M as mob) if (!ticker) M << "You cannot attack people before the game has started." @@ -970,7 +907,7 @@ var/list/robot_verbs_default = list( return -/mob/living/silicon/robot/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/silicon/robot/attack_animal(mob/living/M as mob) if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else @@ -1337,7 +1274,6 @@ var/list/robot_verbs_default = list( /mob/living/silicon/robot/proc/remove_robot_verbs() src.verbs -= robot_verbs_default - // Uses power from cyborg's cell. Returns 1 on success or 0 on failure. // Properly converts using CELLRATE now! Amount is in Joules. /mob/living/silicon/robot/proc/cell_use_power(var/amount = 0) @@ -1352,4 +1288,11 @@ var/list/robot_verbs_default = list( if(cell.use(amount * CELLRATE * CYBORG_POWER_USAGE_MULTIPLIER)) used_power_this_tick += amount * CYBORG_POWER_USAGE_MULTIPLIER return 1 - return 0 + return 0 + +/mob/living/silicon/robot/binarycheck() + if(is_component_functioning("comms")) + var/datum/robot_component/RC = get_component("comms") + use_power(RC.active_usage) + return 1 + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_powers.dm b/code/modules/mob/living/silicon/robot/robot_powers.dm new file mode 100644 index 00000000000..f51af52b182 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_powers.dm @@ -0,0 +1,9 @@ +/mob/living/silicon/robot/verb/light() + set name = "Light On/Off" + set desc = "Activate your inbuilt light. Toggled on or off." + set category = "Robot Commands" + + if(luminosity) + SetLuminosity(0) + return + SetLuminosity(integrated_light_power) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index c979eec0dce..7f04c7b3ee8 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -54,7 +54,6 @@ var/mob/living/silicon/robot/R = src var/mob/living/silicon/pai/P = src - //Must be concious to speak if (stat) return @@ -69,21 +68,35 @@ else message = trim(copytext(message,3)) - if(message_mode && bot_type == IS_ROBOT && message_mode != "binary" && !R.is_component_functioning("radio")) - src << "\red Your radio isn't functional at this time." - return - if(bot_type == IS_ROBOT && message_mode != "binary") - var/datum/robot_component/radio/RA = R.get_component("radio") - if (!R.cell_use_power(RA.active_usage)) - usr << "\red Not enough power to transmit message." - return - //parse language key and consume it var/datum/language/speaking = parse_language(message) if (speaking) verb = speaking.speech_verb message = copytext(message,3) + if(speaking.flags & HIVEMIND) + speaking.broadcast(src,trim(message)) + return + + // Currently used by drones. + if(local_transmit) + var/list/listeners = hearers(5,src) + listeners |= src + + for(var/mob/living/silicon/D in listeners) + if(D.client && istype(D,src.type)) + D << "[src] transmits, \"[message]\"" + + for (var/mob/M in player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + if(M.client) M << "[src] transmits, \"[message]\"" + return + + if(message_mode && bot_type == IS_ROBOT && !R.is_component_functioning("radio")) + src << "\red Your radio isn't functional at this time." + return switch(message_mode) if("department") @@ -98,21 +111,6 @@ P.radio.talk_into(src,message,message_mode,verb,speaking) return 1 - if("binary") - switch(bot_type) - if(IS_ROBOT) - if(!R.is_component_functioning("comms")) - src << "\red Your binary communications component isn't functional." - return - var/datum/robot_component/binary_communication/B = R.get_component("comms") - if(!R.cell_use_power(B.active_usage)) - src << "\red Not enough power to transmit message." - return - if(IS_PAI) - src << "You do not appear to have that function" - return - - robot_talk(message) return 1 if("general") switch(bot_type) @@ -185,64 +183,6 @@ return return 1 -/mob/living/proc/robot_talk(var/message) - - log_say("[key_name(src)] : [message]") - - message = trim(message) - - if (!message) - return - - var/verb = say_quote(message) - - - var/rendered = "Robotic Talk, [name] [verb], \"[message]\"" - - for (var/mob/living/S in living_mob_list) - if(S.robot_talk_understand && (S.robot_talk_understand == robot_talk_understand)) // This SHOULD catch everything caught by the one below, but I'm not going to change it. - if(istype(S , /mob/living/silicon/ai)) - var/renderedAI = "Robotic Talk, [name] [verb], \"[message]\"" - S.show_message(renderedAI, 2) - else - var/mob/living/silicon/robot/borg = S - if(istype(borg) && borg.is_component_functioning("comms")) - var/datum/robot_component/RC = borg.get_component("comms") - if(!borg.use_power(RC.active_usage)) - continue // No power. - S.show_message(rendered, 2) - - - else if (S.binarycheck()) - if(istype(S , /mob/living/silicon/ai)) - var/renderedAI = "Robotic Talk, [name] [verb], \"[message]\"" - S.show_message(renderedAI, 2) - else - S.show_message(rendered, 2) - - var/list/listening = hearers(1, src) - listening -= src - - var/list/heard = list() - for (var/mob/M in listening) - if(!istype(M, /mob/living/silicon) && !M.robot_talk_understand) - heard += M - if (length(heard)) - var/message_beep - verb = "beeps" - message_beep = "beep beep beep" - - rendered = "[voice_name] [verb], \"[message_beep]\"" - - for (var/mob/M in heard) - M.show_message(rendered, 2) - - rendered = "Robotic Talk, [name] [verb], \"[message]\"" - - for (var/mob/M in dead_mob_list) - if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping - M.show_message(rendered, 2) - #undef IS_AI #undef IS_ROBOT #undef IS_PAI diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 6f0778a056d..692609afb88 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -1,6 +1,5 @@ /mob/living/silicon gender = NEUTER - robot_talk_understand = 1 voice_name = "synthesized voice" var/syndicate = 0 var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS @@ -14,6 +13,7 @@ var/speak_query = "queries" var/pose //Yes, now AIs can pose too. var/obj/item/device/camera/siliconcam/aiCamera = null //photography + var/local_transmit //If set, can only speak to others of the same type within a short range. var/sensor_mode = 0 //Determines the current HUD. #define SEC_HUD 1 //Security HUD mode @@ -214,4 +214,7 @@ set desc = "Sets an extended description of your character's features." set category = "IC" - flavor_text = copytext(sanitize(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text), 1) \ No newline at end of file + flavor_text = copytext(sanitize(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text), 1) + +/mob/living/silicon/binarycheck() + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/modules/mob/living/simple_animal/borer.dm deleted file mode 100644 index f377a846c67..00000000000 --- a/code/modules/mob/living/simple_animal/borer.dm +++ /dev/null @@ -1,580 +0,0 @@ -/datum/game_mode/var/list/borers = list() - -/mob/living/captive_brain - name = "host brain" - real_name = "host brain" - universal_understand = 1 - -/mob/living/captive_brain/say(var/message) - - if (src.client) - if(client.prefs.muted & MUTE_IC) - src << "\red You cannot speak in IC (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - - if(istype(src.loc,/mob/living/simple_animal/borer)) - - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - if (!message) - return - log_say("[key_name(src)] : [message]") - if (stat == 2) - return say_dead(message) - - var/mob/living/simple_animal/borer/B = src.loc - src << "You whisper silently, \"[message]\"" - B.host << "The captive mind of [src] whispers, \"[message]\"" - - for (var/mob/M in player_list) - if (istype(M, /mob/new_player)) - continue - else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) - M << "The captive mind of [src] whispers, \"[message]\"" - -/mob/living/captive_brain/emote(var/message) - return - -/mob/living/simple_animal/borer - name = "cortical borer" - real_name = "cortical borer" - desc = "A small, quivering sluglike creature." - speak_emote = list("chirrups") - emote_hear = list("chirrups") - response_help = "pokes" - response_disarm = "prods the" - response_harm = "stomps on the" - icon_state = "brainslug" - icon_living = "brainslug" - icon_dead = "brainslug_dead" - speed = 5 - a_intent = "harm" - stop_automated_movement = 1 - status_flags = CANPUSH - attacktext = "nips" - friendly = "prods" - wander = 0 - pass_flags = PASSTABLE - universal_understand = 1 - holder_type = /obj/item/weapon/holder/borer - - var/used_dominate - var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. - var/mob/living/carbon/human/host // Human host for the brain worm. - var/truename // Name used for brainworm-speak. - var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. - var/controlling // Used in human death check. - var/docile = 0 // Sugar can stop borers from acting. - var/has_reproduced - var/roundstart - -/mob/living/simple_animal/borer/roundstart - roundstart = 1 - -/mob/living/simple_animal/borer/Life() - - ..() - - if(host) - - if(!stat && !host.stat) - - if(host.reagents.has_reagent("sugar")) - if(!docile) - if(controlling) - host << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility." - else - src << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility." - docile = 1 - else - if(docile) - if(controlling) - host << "\blue You shake off your lethargy as the sugar leaves your host's blood." - else - src << "\blue You shake off your lethargy as the sugar leaves your host's blood." - docile = 0 - - if(chemicals < 250) - chemicals++ - if(controlling) - - if(docile) - host << "\blue You are feeling far too docile to continue controlling your host..." - host.release_control() - return - - if(prob(5)) - host.adjustBrainLoss(rand(1,2)) - - if(prob(host.brainloss/20)) - host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]") - -/mob/living/simple_animal/borer/New() - ..() - truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]" - if(!roundstart) request_player() - -/mob/living/simple_animal/borer/say(var/message) - - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - message = capitalize(message) - - if(!message) - return - - if (stat == 2) - return say_dead(message) - - if (stat) - return - - if (src.client) - if(client.prefs.muted & MUTE_IC) - src << "\red You cannot speak in IC (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - - if (copytext(message, 1, 2) == "*") - return emote(copytext(message, 2)) - - if (copytext(message, 1, 2) == ";") //Brain borer hivemind. - return borer_speak(message) - - if(!host) - //TODO: have this pick a random mob within 3 tiles to speak for the borer. - src << "You have no host to speak to." - return //No host, no audible speech. - - src << "You drop words into [host]'s mind: \"[message]\"" - host << "Your own thoughts speak: \"[message]\"" - - for (var/mob/M in player_list) - if (istype(M, /mob/new_player)) - continue - else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) - M << "[src.truename] whispers to [host], \"[message]\"" - -/mob/living/simple_animal/borer/Stat() - ..() - statpanel("Status") - - if(emergency_shuttle) - var/eta_status = emergency_shuttle.get_status_panel_eta() - if(eta_status) - stat(null, eta_status) - - if (client.statpanel == "Status") - stat("Chemicals", chemicals) - -// VERBS! - -/mob/living/simple_animal/borer/proc/borer_speak(var/message) - if(!message) - return - - for(var/mob/M in mob_list) - if(M.mind && (istype(M, /mob/living/simple_animal/borer) || istype(M, /mob/dead/observer))) - M << "Cortical link, [truename]: [copytext(message, 2)]" - -/mob/living/simple_animal/borer/verb/dominate_victim() - set category = "Alien" - set name = "Paralyze Victim" - set desc = "Freeze the limbs of a potential host with supernatural fear." - - if(world.time - used_dominate < 150) - src << "You cannot use that ability again so soon." - return - - if(host) - src << "You cannot do that from within a host body." - return - - if(src.stat) - src << "You cannot do that in your current state." - return - - var/list/choices = list() - for(var/mob/living/carbon/C in view(3,src)) - if(C.stat != 2) - choices += C - - if(world.time - used_dominate < 150) - src << "You cannot use that ability again so soon." - return - - var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices - - if(!M || !src) return - - if(M.has_brain_worms()) - src << "You cannot infest someone who is already infested!" - return - - src << "\red You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread." - M << "\red You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing." - M.Weaken(10) - - used_dominate = world.time - -/mob/living/simple_animal/borer/verb/bond_brain() - set category = "Alien" - set name = "Assume Control" - set desc = "Fully connect to the brain of your host." - - if(!host) - src << "You are not inside a host body." - return - - if(src.stat) - src << "You cannot do that in your current state." - return - - if(docile) - src << "\blue You are feeling far too docile to do that." - return - - src << "You begin delicately adjusting your connection to the host brain..." - - spawn(100+(host.brainloss*5)) - - if(!host || !src || controlling) - return - else - src << "\red You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system." - host << "\red You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours." - - // host -> brain - var/h2b_id = host.computer_id - var/h2b_ip= host.lastKnownIP - host.computer_id = null - host.lastKnownIP = null - - del(host_brain) - host_brain = new(src) - - host_brain.ckey = host.ckey - - host_brain.name = host.name - - if(!host_brain.computer_id) - host_brain.computer_id = h2b_id - - if(!host_brain.lastKnownIP) - host_brain.lastKnownIP = h2b_ip - - // self -> host - var/s2h_id = src.computer_id - var/s2h_ip= src.lastKnownIP - src.computer_id = null - src.lastKnownIP = null - - host.ckey = src.ckey - - if(!host.computer_id) - host.computer_id = s2h_id - - if(!host.lastKnownIP) - host.lastKnownIP = s2h_ip - - controlling = 1 - - host.verbs += /mob/living/carbon/proc/release_control - host.verbs += /mob/living/carbon/proc/punish_host - host.verbs += /mob/living/carbon/proc/spawn_larvae - - return - -/mob/living/simple_animal/borer/verb/secrete_chemicals() - set category = "Alien" - set name = "Secrete Chemicals" - set desc = "Push some chemicals into your host's bloodstream." - - if(!host) - src << "You are not inside a host body." - return - - if(stat) - src << "You cannot secrete chemicals in your current state." - - if(docile) - src << "\blue You are feeling far too docile to do that." - return - - if(chemicals < 50) - src << "You don't have enough chemicals!" - - var/chem = input("Select a chemical to secrete.", "Chemicals") in list("bicaridine","tramadol","hyperzine","alkysine") - - if(chemicals < 50 || !host || controlling || !src || stat) //Sanity check. - return - - src << "\red You squirt a measure of [chem] from your reservoirs into [host]'s bloodstream." - host.reagents.add_reagent(chem, 10) - chemicals -= 50 - -/mob/living/simple_animal/borer/verb/release_host() - set category = "Alien" - set name = "Release Host" - set desc = "Slither out of your host." - - if(!host) - src << "You are not inside a host body." - return - - if(stat) - src << "You cannot leave your host in your current state." - - if(docile) - src << "\blue You are feeling far too docile to do that." - return - - if(!host || !src) return - - src << "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal." - - if(!host.stat) - host << "An odd, uncomfortable pressure begins to build inside your skull, behind your ear..." - - spawn(100) - - if(!host || !src) return - - if(src.stat) - src << "You cannot release your host in your current state." - return - - src << "You wiggle out of [host]'s ear and plop to the ground." - if(!host.stat) - host << "Something slimy wiggles out of your ear and plops to the ground!" - - detatch() - leave_host() - -/mob/living/simple_animal/borer/proc/detatch() - - if(!host || !controlling) return - - if(istype(host,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = host - var/datum/organ/external/head = H.get_organ("head") - head.implants -= src - - controlling = 0 - - host.verbs -= /mob/living/carbon/proc/release_control - host.verbs -= /mob/living/carbon/proc/punish_host - host.verbs -= /mob/living/carbon/proc/spawn_larvae - - if(host_brain) - - // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed. - // computer_id and IP are not updated magically on their own in offline mobs -walter0o - - // host -> self - var/h2s_id = host.computer_id - var/h2s_ip= host.lastKnownIP - host.computer_id = null - host.lastKnownIP = null - - src.ckey = host.ckey - - if(!src.computer_id) - src.computer_id = h2s_id - - if(!host_brain.lastKnownIP) - src.lastKnownIP = h2s_ip - - // brain -> host - var/b2h_id = host_brain.computer_id - var/b2h_ip= host_brain.lastKnownIP - host_brain.computer_id = null - host_brain.lastKnownIP = null - - host.ckey = host_brain.ckey - - if(!host.computer_id) - host.computer_id = b2h_id - - if(!host.lastKnownIP) - host.lastKnownIP = b2h_ip - - del(host_brain) - -/mob/living/simple_animal/borer/proc/leave_host() - - if(!host) return - - src.loc = get_turf(host) - - reset_view(null) - machine = null - - host.reset_view(null) - host.machine = null - - var/mob/living/H = host - H.status_flags &= ~PASSEMOTES - host = null - return - -/mob/living/simple_animal/borer/verb/infest() - set category = "Alien" - set name = "Infest" - set desc = "Infest a suitable humanoid host." - - if(host) - src << "You are already within a host." - return - - if(stat) - src << "You cannot infest a target in your current state." - return - - var/list/choices = list() - for(var/mob/living/carbon/C in view(1,src)) - if(C.stat != 2 && src.Adjacent(C)) - choices += C - - var/mob/living/carbon/M = input(src,"Who do you wish to infest?") in null|choices - - if(!M || !src) return - - if(!(src.Adjacent(M))) return - - if(M.has_brain_worms()) - src << "You cannot infest someone who is already infested!" - return - - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.check_head_coverage()) - src << "You cannot get through that host's protective gear." - return - - M << "Something slimy begins probing at the opening of your ear canal..." - src << "You slither up [M] and begin probing at their ear canal..." - - if(!do_after(src,30)) - src << "As [M] moves away, you are dislodged and fall to the ground." - return - - if(!M || !src) return - - if(src.stat) - src << "You cannot infest a target in your current state." - return - - if(M.stat == 2) - src << "That is not an appropriate target." - return - - if(M in view(1, src)) - src << "You wiggle into [M]'s ear." - if(!M.stat) - M << "Something disgusting and slimy wiggles into your ear!" - - src.host = M - src.loc = M - - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/datum/organ/external/head = H.get_organ("head") - head.implants += src - - host.status_flags |= PASSEMOTES - - return - else - src << "They are no longer in range!" - return - -/mob/living/simple_animal/borer/verb/ventcrawl() - set name = "Crawl through Vent" - set desc = "Enter an air vent and crawl through the pipe system." - set category = "Alien" - -// if(!istype(V,/obj/machinery/atmoalter/siphs/fullairsiphon/air_vent)) -// return - var/obj/machinery/atmospherics/unary/vent_pump/vent_found - var/welded = 0 - for(var/obj/machinery/atmospherics/unary/vent_pump/v in range(1,src)) - if(!v.welded) - vent_found = v - break - else - welded = 1 - if(vent_found) - if(vent_found.network&&vent_found.network.normal_members.len) - var/list/vents = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in vent_found.network.normal_members) - if(temp_vent.loc == loc) - continue - vents.Add(temp_vent) - var/list/choices = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/vent in vents) - if(vent.loc.z != loc.z) - continue - var/atom/a = get_turf(vent) - choices.Add(a.loc) - var/turf/startloc = loc - var/obj/selection = input("Select a destination.", "Duct System") in choices - var/selection_position = choices.Find(selection) - if(loc==startloc) - var/obj/target_vent = vents[selection_position] - if(target_vent) - loc = target_vent.loc - else - src << "\blue You need to remain still while entering a vent." - else - src << "\blue This vent is not connected to anything." - else if(welded) - src << "\red That vent is welded." - else - src << "\blue You must be standing on or beside an air vent to enter it." - return - -//copy paste from alien/larva, if that func is updated please update this one alsoghost -/mob/living/simple_animal/borer/verb/hide() - set name = "Hide" - set desc = "Allows to hide beneath tables or certain items. Toggled on or off." - set category = "Alien" - - if (layer != TURF_LAYER+0.2) - layer = TURF_LAYER+0.2 - src << text("\blue You are now hiding.") - else - layer = MOB_LAYER - src << text("\blue You have stopped hiding.") - -//Procs for grabbing players. -/mob/living/simple_animal/borer/proc/request_player() - for(var/mob/dead/observer/O in player_list) - if(jobban_isbanned(O, "Syndicate")) - continue - if(O.client) - if(O.client.prefs.be_special & BE_ALIEN) - question(O.client) - -/mob/living/simple_animal/borer/proc/question(var/client/C) - spawn(0) - if(!C) return - var/response = alert(C, "A cortical borer needs a player. Are you interested?", "Cortical borer request", "Yes", "No", "Never for this round") - if(!C || ckey) - return - if(response == "Yes") - transfer_personality(C) - else if (response == "Never for this round") - C.prefs.be_special ^= BE_ALIEN - -/mob/living/simple_animal/borer/proc/transfer_personality(var/client/candidate) - - if(!candidate) - return - - src.mind = candidate.mob.mind - src.ckey = candidate.ckey - if(src.mind) - src.mind.assigned_role = "Cortical Borer" - src.mind.special_role = "Cortical Borer" diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm new file mode 100644 index 00000000000..2cfdc1f8c40 --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/borer.dm @@ -0,0 +1,207 @@ +/datum/game_mode/var/list/borers = list() + +/mob/living/simple_animal/borer + name = "cortical borer" + real_name = "cortical borer" + desc = "A small, quivering sluglike creature." + speak_emote = list("chirrups") + emote_hear = list("chirrups") + response_help = "pokes" + response_disarm = "prods the" + response_harm = "stomps on the" + icon_state = "brainslug" + icon_living = "brainslug" + icon_dead = "brainslug_dead" + speed = 5 + a_intent = "harm" + stop_automated_movement = 1 + status_flags = CANPUSH + attacktext = "nips" + friendly = "prods" + wander = 0 + pass_flags = PASSTABLE + universal_understand = 1 + holder_type = /obj/item/weapon/holder/borer + + var/used_dominate + var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. + var/mob/living/carbon/human/host // Human host for the brain worm. + var/truename // Name used for brainworm-speak. + var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. + var/controlling // Used in human death check. + var/docile = 0 // Sugar can stop borers from acting. + var/has_reproduced + var/roundstart + +/mob/living/simple_animal/borer/roundstart + roundstart = 1 + +/mob/living/simple_animal/borer/New() + ..() + + add_language("Cortical Link") + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + + truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]" + if(!roundstart) request_player() + +/mob/living/simple_animal/borer/Life() + + ..() + + if(host) + + if(!stat && !host.stat) + + if(host.reagents.has_reagent("sugar")) + if(!docile) + if(controlling) + host << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility." + else + src << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility." + docile = 1 + else + if(docile) + if(controlling) + host << "\blue You shake off your lethargy as the sugar leaves your host's blood." + else + src << "\blue You shake off your lethargy as the sugar leaves your host's blood." + docile = 0 + + if(chemicals < 250) + chemicals++ + if(controlling) + + if(docile) + host << "\blue You are feeling far too docile to continue controlling your host..." + host.release_control() + return + + if(prob(5)) + host.adjustBrainLoss(rand(1,2)) + + if(prob(host.brainloss/20)) + host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]") + +/mob/living/simple_animal/borer/Stat() + ..() + statpanel("Status") + + if(emergency_shuttle) + var/eta_status = emergency_shuttle.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + + if (client.statpanel == "Status") + stat("Chemicals", chemicals) + +/mob/living/simple_animal/borer/proc/detatch() + + if(!host || !controlling) return + + if(istype(host,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = host + var/datum/organ/external/head = H.get_organ("head") + head.implants -= src + + controlling = 0 + + host.remove_language("Cortical Link") + host.verbs -= /mob/living/carbon/proc/release_control + host.verbs -= /mob/living/carbon/proc/punish_host + host.verbs -= /mob/living/carbon/proc/spawn_larvae + + if(host_brain) + + // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed. + // computer_id and IP are not updated magically on their own in offline mobs -walter0o + + // host -> self + var/h2s_id = host.computer_id + var/h2s_ip= host.lastKnownIP + host.computer_id = null + host.lastKnownIP = null + + src.ckey = host.ckey + + if(!src.computer_id) + src.computer_id = h2s_id + + if(!host_brain.lastKnownIP) + src.lastKnownIP = h2s_ip + + // brain -> host + var/b2h_id = host_brain.computer_id + var/b2h_ip= host_brain.lastKnownIP + host_brain.computer_id = null + host_brain.lastKnownIP = null + + host.ckey = host_brain.ckey + + if(!host.computer_id) + host.computer_id = b2h_id + + if(!host.lastKnownIP) + host.lastKnownIP = b2h_ip + + del(host_brain) + +/mob/living/simple_animal/borer/proc/leave_host() + + if(!host) return + + if(host.mind) + //If they're not a proper traitor, reset their antag status. + if(host.mind.special_role == "Borer Thrall") + host << "You are no longer an antagonist." + ticker.mode.borers -= host.mind + host.mind.special_role = null + + src.loc = get_turf(host) + + reset_view(null) + machine = null + + host.reset_view(null) + host.machine = null + + var/mob/living/H = host + H.status_flags &= ~PASSEMOTES + host = null + return + +//Procs for grabbing players. +/mob/living/simple_animal/borer/proc/request_player() + for(var/mob/dead/observer/O in player_list) + if(jobban_isbanned(O, "Syndicate")) + continue + if(O.client) + if(O.client.prefs.be_special & BE_ALIEN) + question(O.client) + +/mob/living/simple_animal/borer/proc/question(var/client/C) + spawn(0) + if(!C) return + var/response = alert(C, "A cortical borer needs a player. Are you interested?", "Cortical borer request", "Yes", "No", "Never for this round") + if(!C || ckey) + return + if(response == "Yes") + transfer_personality(C) + else if (response == "Never for this round") + C.prefs.be_special ^= BE_ALIEN + +/mob/living/simple_animal/borer/proc/transfer_personality(var/client/candidate) + + if(!candidate) + return + + src.mind = candidate.mob.mind + src.ckey = candidate.ckey + if(src.mind) + src.mind.assigned_role = "Cortical Borer" + src.mind.special_role = "Cortical Borer" + ticker.mode.borers |= src.mind + +/mob/living/carbon/alien/can_use_vents() + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/borer/borer_captive.dm b/code/modules/mob/living/simple_animal/borer/borer_captive.dm new file mode 100644 index 00000000000..808a2199f18 --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/borer_captive.dm @@ -0,0 +1,35 @@ +/mob/living/captive_brain + name = "host brain" + real_name = "host brain" + universal_understand = 1 + +/mob/living/captive_brain/say(var/message) + + if (src.client) + if(client.prefs.muted & MUTE_IC) + src << "\red You cannot speak in IC (muted)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return + + if(istype(src.loc,/mob/living/simple_animal/borer)) + + message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + if (!message) + return + log_say("[key_name(src)] : [message]") + if (stat == 2) + return say_dead(message) + + var/mob/living/simple_animal/borer/B = src.loc + src << "You whisper silently, \"[message]\"" + B.host << "The captive mind of [src] whispers, \"[message]\"" + + for (var/mob/M in player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + M << "The captive mind of [src] whispers, \"[message]\"" + +/mob/living/captive_brain/emote(var/message) + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/borer/borer_powers.dm b/code/modules/mob/living/simple_animal/borer/borer_powers.dm new file mode 100644 index 00000000000..9f47dd6cf49 --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/borer_powers.dm @@ -0,0 +1,348 @@ +/mob/living/simple_animal/borer/verb/release_host() + set category = "Abilities" + set name = "Release Host" + set desc = "Slither out of your host." + + if(!host) + src << "You are not inside a host body." + return + + if(stat) + src << "You cannot leave your host in your current state." + + if(docile) + src << "\blue You are feeling far too docile to do that." + return + + if(!host || !src) return + + src << "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal." + + if(!host.stat) + host << "An odd, uncomfortable pressure begins to build inside your skull, behind your ear..." + + spawn(100) + + if(!host || !src) return + + if(src.stat) + src << "You cannot release your host in your current state." + return + + src << "You wiggle out of [host]'s ear and plop to the ground." + if(host.mind) + if(!host.stat) + host << "Something slimy wiggles out of your ear and plops to the ground!" + host << "As though waking from a dream, you shake off the insidious mind control of the brain worm. Your thoughts are your own again." + + detatch() + leave_host() + +/mob/living/simple_animal/borer/verb/infest() + set category = "Abilities" + set name = "Infest" + set desc = "Infest a suitable humanoid host." + + if(host) + src << "You are already within a host." + return + + if(stat) + src << "You cannot infest a target in your current state." + return + + var/list/choices = list() + for(var/mob/living/carbon/C in view(1,src)) + if(src.Adjacent(C)) + choices += C + + var/mob/living/carbon/M = input(src,"Who do you wish to infest?") in null|choices + + if(!M || !src) return + + if(!(src.Adjacent(M))) return + + if(M.has_brain_worms()) + src << "You cannot infest someone who is already infested!" + return + + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + + if(!H.species.has_organ["brain"]) + src << "\The [H] does not seem to have an ear canal to breach." + return + + if(H.check_head_coverage()) + src << "You cannot get through that host's protective gear." + return + + M << "Something slimy begins probing at the opening of your ear canal..." + src << "You slither up [M] and begin probing at their ear canal..." + + if(!do_after(src,30)) + src << "As [M] moves away, you are dislodged and fall to the ground." + return + + if(!M || !src) return + + if(src.stat) + src << "You cannot infest a target in your current state." + return + + if(M in view(1, src)) + src << "You wiggle into [M]'s ear." + if(!M.stat) + M << "Something disgusting and slimy wiggles into your ear!" + + src.host = M + src.host.status_flags |= PASSEMOTES + src.loc = M + + //Update their traitor status. + if(host.mind) + if(!host.mind.special_role) + ticker.mode.borers |= host.mind + host.mind.special_role = "Borer Thrall" + host << "A creeping lassitude surrounds you. Your mind is being invaded by an alien intelligence and that's just fine." + host << "You are now a thrall to a cortical borer. Please listen to what they have to say; they're in your head." + show_generic_antag_text(host.mind) + + if(istype(M,/mob/living/carbon/human)) + + var/mob/living/carbon/human/H = M + var/datum/organ/internal/I = H.internal_organs_by_name["brain"] + if(!I) // No brain organ, so the borer moves in and replaces it permanently. + replace_brain() + else + // If they're in normally, implant removal can get them out. + var/datum/organ/external/head = H.get_organ("head") + head.implants += src + + return + else + src << "They are no longer in range!" + return + +/mob/living/simple_animal/borer/verb/devour_brain() + set category = "Abilities" + set name = "Devour Brain" + set desc = "Take permanent control of a dead host." + + if(!host) + src << "You are not inside a host body." + return + + if(host.stat != 2) + src << "Your host is still alive." + return + + if(stat) + src << "You cannot do that in your current state." + + if(docile) + src << "\blue You are feeling far too docile to do that." + return + + + src << "It only takes a few moments to render the dead host brain down into a nutrient-rich slurry..." + replace_brain() + +// BRAIN WORM ZOMBIES AAAAH. +/mob/living/simple_animal/borer/proc/replace_brain() + + var/mob/living/carbon/human/H = host + + if(!istype(host)) + src << "This host does not have a suitable brain." + return + + src << "You settle into the empty brainpan and begin to expand, fusing inextricably with the dead flesh of [H]." + + H.add_language("Cortical Link") + + if(host.stat == 2) + H.verbs |= /mob/living/carbon/human/proc/jumpstart + + H.verbs |= /mob/living/carbon/human/proc/psychic_whisper + H.verbs |= /mob/living/carbon/human/proc/tackle + H.verbs |= /mob/living/carbon/proc/spawn_larvae + + if(H.client) + H.ghostize(0) + + if(src.mind) + src.mind.special_role = "Borer Husk" + src.mind.transfer_to(host) + + H.ChangeToHusk() + + var/datum/organ/internal/borer/B = new(H) + H.internal_organs_by_name["brain"] = B + H.internal_organs |= B + + var/s2h_id = src.computer_id + var/s2h_ip= src.lastKnownIP + src.computer_id = null + src.lastKnownIP = null + + if(!H.computer_id) + H.computer_id = s2h_id + + if(!H.lastKnownIP) + H.lastKnownIP = s2h_ip + +/mob/living/simple_animal/borer/verb/secrete_chemicals() + set category = "Abilities" + set name = "Secrete Chemicals" + set desc = "Push some chemicals into your host's bloodstream." + + if(!host) + src << "You are not inside a host body." + return + + if(stat) + src << "You cannot secrete chemicals in your current state." + + if(docile) + src << "\blue You are feeling far too docile to do that." + return + + if(chemicals < 50) + src << "You don't have enough chemicals!" + + var/chem = input("Select a chemical to secrete.", "Chemicals") in list("bicaridine","tramadol","hyperzine","alkysine") + + if(chemicals < 50 || !host || controlling || !src || stat) //Sanity check. + return + + src << "\red You squirt a measure of [chem] from your reservoirs into [host]'s bloodstream." + host.reagents.add_reagent(chem, 10) + chemicals -= 50 + +/mob/living/simple_animal/borer/verb/dominate_victim() + set category = "Abilities" + set name = "Paralyze Victim" + set desc = "Freeze the limbs of a potential host with supernatural fear." + + if(world.time - used_dominate < 150) + src << "You cannot use that ability again so soon." + return + + if(host) + src << "You cannot do that from within a host body." + return + + if(src.stat) + src << "You cannot do that in your current state." + return + + var/list/choices = list() + for(var/mob/living/carbon/C in view(3,src)) + if(C.stat != 2) + choices += C + + if(world.time - used_dominate < 150) + src << "You cannot use that ability again so soon." + return + + var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices + + if(!M || !src) return + + if(M.has_brain_worms()) + src << "You cannot infest someone who is already infested!" + return + + src << "\red You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread." + M << "\red You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing." + M.Weaken(10) + + used_dominate = world.time + +/mob/living/simple_animal/borer/verb/bond_brain() + set category = "Abilities" + set name = "Assume Control" + set desc = "Fully connect to the brain of your host." + + if(!host) + src << "You are not inside a host body." + return + + if(src.stat) + src << "You cannot do that in your current state." + return + + if(docile) + src << "\blue You are feeling far too docile to do that." + return + + src << "You begin delicately adjusting your connection to the host brain..." + + spawn(100+(host.brainloss*5)) + + if(!host || !src || controlling) + return + else + + src << "\red You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system." + host << "\red You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours." + host.add_language("Cortical Link") + + // host -> brain + var/h2b_id = host.computer_id + var/h2b_ip= host.lastKnownIP + host.computer_id = null + host.lastKnownIP = null + + del(host_brain) + host_brain = new(src) + + host_brain.ckey = host.ckey + + host_brain.name = host.name + + if(!host_brain.computer_id) + host_brain.computer_id = h2b_id + + if(!host_brain.lastKnownIP) + host_brain.lastKnownIP = h2b_ip + + // self -> host + var/s2h_id = src.computer_id + var/s2h_ip= src.lastKnownIP + src.computer_id = null + src.lastKnownIP = null + + host.ckey = src.ckey + + if(!host.computer_id) + host.computer_id = s2h_id + + if(!host.lastKnownIP) + host.lastKnownIP = s2h_ip + + controlling = 1 + + host.verbs += /mob/living/carbon/proc/release_control + host.verbs += /mob/living/carbon/proc/punish_host + host.verbs += /mob/living/carbon/proc/spawn_larvae + + return + +/mob/living/carbon/human/proc/jumpstart() + set category = "Abilities" + set name = "Revive Host" + set desc = "Send a jolt of electricity through your host, reviving them." + + if(stat != 2) + usr << "Your host is already alive." + return + + verbs -= /mob/living/carbon/human/proc/jumpstart + visible_message("With a hideous, rattling moan, [src] shudders back to life!") + + rejuvenate() + vessel.add_reagent("blood",560-vessel.total_volume) + fixblood() + update_canmove() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/borer/say.dm b/code/modules/mob/living/simple_animal/borer/say.dm new file mode 100644 index 00000000000..c0bfb0711f9 --- /dev/null +++ b/code/modules/mob/living/simple_animal/borer/say.dm @@ -0,0 +1,42 @@ +/mob/living/simple_animal/borer/say(var/message) + + message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + message = capitalize(message) + + if(!message) + return + + if (stat == 2) + return say_dead(message) + + if (stat) + return + + if (src.client) + if(client.prefs.muted & MUTE_IC) + src << "\red You cannot speak in IC (muted)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return + + if (copytext(message, 1, 2) == "*") + return emote(copytext(message, 2)) + + var/datum/language/L = parse_language(message) + if(L && L.flags & HIVEMIND) + L.broadcast(src,trim(copytext(message,3)),src.truename) + return + + if(!host) + //TODO: have this pick a random mob within 3 tiles to speak for the borer. + src << "You have no host to speak to." + return //No host, no audible speech. + + src << "You drop words into [host]'s mind: \"[message]\"" + host << "Your own thoughts speak: \"[message]\"" + + for (var/mob/M in player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + M << "[src.truename] whispers to [host], \"[message]\"" \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 48dc61b08e4..d3aa156ea4b 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -88,7 +88,7 @@ now_pushing = null -/mob/living/simple_animal/construct/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/simple_animal/construct/attack_animal(mob/living/M as mob) if(istype(M, /mob/living/simple_animal/construct/builder)) health += 5 M.emote("mends some of \the [src]'s wounds.") diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 5a13dccc49b..4f5eda2af94 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -51,6 +51,10 @@ /mob/living/simple_animal/mouse/New() ..() + + verbs += /mob/living/proc/ventcrawl + verbs += /mob/living/proc/hide + name = "[name] ([rand(1, 1000)])" if(!body_color) body_color = pick( list("brown","gray","white") ) @@ -59,7 +63,6 @@ icon_dead = "mouse_[body_color]_dead" desc = "It's a small [body_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself." - /mob/living/simple_animal/mouse/proc/splat() src.health = 0 src.stat = DEAD @@ -69,59 +72,6 @@ if(client) client.time_died_as_mouse = world.time -/mob/living/simple_animal/mouse/verb/ventcrawl() - set name = "Crawl through Vent" - set desc = "Enter an air vent and crawl through the pipe system." - set category = "Mouse" - handle_ventcrawl() - return - -//copy paste from alien/larva, if that func is updated please update this one alsoghost -/mob/living/simple_animal/mouse/verb/hide() - set name = "Hide" - set desc = "Allows to hide beneath tables or certain items. Toggled on or off." - set category = "Mouse" - - if (layer != TURF_LAYER+0.2) - layer = TURF_LAYER+0.2 - src << text("\blue You are now hiding.") - /* - for(var/mob/O in oviewers(src, null)) - if ((O.client && !( O.blinded ))) - O << text("[] scurries to the ground!", src) - */ - else - layer = MOB_LAYER - src << text("\blue You have stopped hiding.") - /* - for(var/mob/O in oviewers(src, null)) - if ((O.client && !( O.blinded ))) - O << text("[] slowly peaks up from the ground...", src) - */ - -//make mice fit under tables etc? this was hacky, and not working -/* -/mob/living/simple_animal/mouse/Move(var/dir) - - var/turf/target_turf = get_step(src,dir) - //CanReachThrough(src.loc, target_turf, src) - var/can_fit_under = 0 - if(target_turf.ZCanPass(get_turf(src),1)) - can_fit_under = 1 - - ..(dir) - if(can_fit_under) - src.loc = target_turf - for(var/d in cardinal) - var/turf/O = get_step(T,d) - //Simple pass check. - if(O.ZCanPass(T, 1) && !(O in open) && !(O in closed) && O in possibles) - open += O - */ - -///mob/living/simple_animal/mouse/restrained() //Hotfix to stop mice from doing things with MouseDrop -// return 1 - /mob/living/simple_animal/mouse/start_pulling(var/atom/movable/AM)//Prevents mouse from pulling things src << "You are too small to pull anything." return @@ -163,3 +113,6 @@ response_help = "pets" response_disarm = "gently pushes aside" response_harm = "splats" + +/mob/living/carbon/alien/can_use_vents() + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm index 1c489f4902c..4c95c54c7bf 100644 --- a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/friendly/spiderbot.dm @@ -215,67 +215,7 @@ src.Del() return -//copy paste from alien/larva, if that func is updated please update this one also -/mob/living/simple_animal/spiderbot/verb/ventcrawl() - set name = "Crawl through Vent" - set desc = "Enter an air vent and crawl through the pipe system." - set category = "Spiderbot" - -// if(!istype(V,/obj/machinery/atmoalter/siphs/fullairsiphon/air_vent)) -// return - var/obj/machinery/atmospherics/unary/vent_pump/vent_found - var/welded = 0 - for(var/obj/machinery/atmospherics/unary/vent_pump/v in range(1,src)) - if(!v.welded) - vent_found = v - break - else - welded = 1 - if(vent_found) - if(vent_found.network&&vent_found.network.normal_members.len) - var/list/vents = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in vent_found.network.normal_members) - if(temp_vent.loc == loc) - continue - vents.Add(temp_vent) - var/list/choices = list() - for(var/obj/machinery/atmospherics/unary/vent_pump/vent in vents) - if(vent.loc.z != loc.z) - continue - var/atom/a = get_turf(vent) - choices.Add(a.loc) - var/turf/startloc = loc - var/obj/selection = input("Select a destination.", "Duct System") in choices - var/selection_position = choices.Find(selection) - if(loc==startloc) - var/obj/target_vent = vents[selection_position] - if(target_vent) - loc = target_vent.loc - else - src << "\blue You need to remain still while entering a vent." - else - src << "\blue This vent is not connected to anything." - else if(welded) - src << "\red That vent is welded." - else - src << "\blue You must be standing on or beside an air vent to enter it." - return - -//copy paste from alien/larva, if that func is updated please update this one alsoghost -/mob/living/simple_animal/spiderbot/verb/hide() - set name = "Hide" - set desc = "Allows to hide beneath tables or certain items. Toggled on or off." - set category = "Spiderbot" - - if (layer != TURF_LAYER+0.2) - layer = TURF_LAYER+0.2 - src << text("\blue You are now hiding.") - else - layer = MOB_LAYER - src << text("\blue You have stopped hiding.") - //Cannibalized from the parrot mob. ~Zuhayr - /mob/living/simple_animal/spiderbot/verb/drop_held_item() set name = "Drop held item" set category = "Spiderbot" diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 5740e51b1e3..000b125673b 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -135,8 +135,8 @@ if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) return - //Is the usr's mob type able to do this? (lolaliens) - if(ishuman(usr) || ismonkey(usr) || isrobot(usr) || isalienadult(usr)) + //Is the usr's mob type able to do this? + if(ishuman(usr) || ismonkey(usr) || isrobot(usr)) //Removing from inventory if(href_list["remove_inv"]) @@ -235,11 +235,8 @@ /mob/living/simple_animal/parrot/attack_paw(mob/living/carbon/monkey/M as mob) attack_hand(M) -/mob/living/simple_animal/parrot/attack_alien(mob/living/carbon/monkey/M as mob) - attack_hand(M) - //Simple animals -/mob/living/simple_animal/parrot/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/simple_animal/parrot/attack_animal(mob/living/M as mob) if(client) return diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index e5f91363627..b9e6e714dd5 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -44,17 +44,14 @@ var/min_n2 = 0 var/max_n2 = 0 var/unsuitable_atoms_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above - + var/speed = 0 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly - var/melee_damage_lower = 0 - var/melee_damage_upper = 0 - var/attacktext = "attacks" - var/attack_sound = null - var/friendly = "nuzzles" //If the mob does no damage with it's attack - var/wall_smash = 0 //if they can smash walls - - var/speed = 0 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster + melee_damage_lower = 0 + melee_damage_upper = 0 + attacktext = "attacks" + attack_sound = null + friendly = "nuzzles" //If the mob does no damage with it's attack /mob/living/simple_animal/New() ..() @@ -212,7 +209,7 @@ if(act == "scream") act = "whimper" //ugly hack to stop animals screaming when crushed :P ..(act, type, desc) -/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M as mob) +/mob/living/simple_animal/attack_animal(mob/living/M as mob) if(M.melee_damage_upper == 0) M.emote("[M.friendly] [src]") else @@ -228,7 +225,7 @@ /mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) if(!Proj || Proj.nodamage) return - + adjustBruteLoss(Proj.damage) return 0 @@ -270,59 +267,6 @@ return -/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - - 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) - if ("grab") - if(M == src) - return - if(!(status_flags & CANPUSH)) - return - - var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src ) - - M.put_in_active_hand(G) - - grabbed_by += G - G.synch() - G.affecting = src - 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) - - if("hurt", "disarm") - var/damage = rand(15, 30) - visible_message("\red [M] has slashed at [src]!") - adjustBruteLoss(damage) - - return - -/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L as mob) - - switch(L.a_intent) - if("help") - visible_message("\blue [L] rubs it's head against [src]") - - - else - - var/damage = rand(5, 10) - visible_message("\red [L] bites [src]!") - - if(stat != DEAD) - adjustBruteLoss(damage) - L.amount_grown = min(L.amount_grown + damage, L.max_grown) - - /mob/living/simple_animal/attack_slime(mob/living/carbon/slime/M as mob) if (!ticker) M << "You cannot attack people before the game has started." @@ -461,4 +405,4 @@ message = capitalize(trim_left(message)) - ..(message, null, verb) + ..(message, null, verb) \ No newline at end of file diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index bf5be72fc44..4b9d28402cd 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -45,15 +45,4 @@ client.eye = src client.perspective = MOB_PERSPECTIVE - //Clear ability list and update from mob. - client.verbs -= ability_verbs - - if(abilities) - client.verbs |= abilities - - if(istype(src,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = src - if(H.species && H.species.abilities) - client.verbs |= H.species.abilities - nanomanager.send_resources(client) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 86f3724fb55..ca3a2b85510 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -88,7 +88,6 @@ var/list/pinned = list() // List of things pinning this creature to walls (see living_defense.dm) var/list/embedded = list() // Embedded items, since simple mobs don't have organs. var/list/languages = list() // For speaking/listening. - var/list/abilities = list() // For species-derived or admin-given powers. var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null. var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes @@ -97,7 +96,6 @@ var/timeofdeath = 0.0//Living var/cpr_time = 1.0//Carbon - var/bodytemperature = 310.055 //98.7 F var/drowsyness = 0.0//Carbon var/dizziness = 0//Carbon @@ -210,8 +208,6 @@ //Whether or not mobs can understand other mobtypes. These stay in /mob so that ghosts can hear everything. var/universal_speak = 0 // Set to 1 to enable the mob to speak to everyone -- TLE var/universal_understand = 0 // Set to 1 to enable the mob to understand everyone, not necessarily speak - var/robot_talk_understand = 0 - var/alien_talk_understand = 0 var/has_limbs = 1 //Whether this mob have any limbs he can move with var/can_stand = 1 //Whether this mob have ability to stand diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index a95f8612c1b..ad8915f5e34 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -191,10 +191,22 @@ return if(M == assailant && state >= GRAB_AGGRESSIVE) - if( (ishuman(user) && (FAT in user.mutations) && ismonkey(affecting) ) || ( isalien(user) && iscarbon(affecting) ) ) + var/can_eat + + if((FAT in user.mutations) && ismonkey(affecting)) + can_eat = 1 + else + var/mob/living/carbon/human/H = user + if(istype(H) && iscarbon(affecting) && H.species.gluttonous) + if(H.species.gluttonous == 2) + can_eat = 2 + else if(!ishuman(affecting)) + can_eat = 1 + + if(can_eat) var/mob/living/carbon/attacker = user user.visible_message("[user] is attempting to devour [affecting]!") - if(istype(user, /mob/living/carbon/alien/humanoid/hunter)) + if(can_eat == 2) if(!do_mob(user, affecting)||!do_after(user, 30)) return else if(!do_mob(user, affecting)||!do_after(user, 100)) return diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 93cca72284a..51676ca04fb 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -5,6 +5,11 @@ return 1 return 0 +/proc/isalien(A) + if(istype(A, /mob/living/carbon/alien)) + return 1 + return 0 + /proc/ismonkey(A) if(A && istype(A, /mob/living/carbon/monkey)) return 1 @@ -15,21 +20,6 @@ return 1 return 0 -/proc/isalien(A) - if(istype(A, /mob/living/carbon/alien)) - return 1 - return 0 - -/proc/isalienadult(A) - if(istype(A, /mob/living/carbon/alien/humanoid)) - return 1 - return 0 - -/proc/islarva(A) - if(istype(A, /mob/living/carbon/alien/larva)) - return 1 - return 0 - /proc/isslime(A) if(istype(A, /mob/living/carbon/slime)) return 1 @@ -189,7 +179,7 @@ var/list/global/organ_rel_size = list( var/ran_zone = zone while (ran_zone == zone) - ran_zone = pick ( + ran_zone = pick ( organ_rel_size["head"]; "head", organ_rel_size["chest"]; "chest", organ_rel_size["groin"]; "groin", @@ -202,7 +192,7 @@ var/list/global/organ_rel_size = list( organ_rel_size["l_foot"]; "l_foot", organ_rel_size["r_foot"]; "r_foot", ) - + return ran_zone // Emulates targetting a specific body part, and miss chances @@ -399,7 +389,7 @@ var/list/intents = list("help","disarm","grab","hurt") set name = "a-intent" set hidden = 1 - if(ishuman(src) || isalienadult(src) || isbrain(src)) + if(ishuman(src) || isbrain(src)) switch(input) if("help","disarm","grab","hurt") a_intent = input @@ -410,7 +400,7 @@ var/list/intents = list("help","disarm","grab","hurt") if(hud_used && hud_used.action_intent) hud_used.action_intent.icon_state = "intent_[a_intent]" - else if(isrobot(src) || ismonkey(src) || islarva(src)) + else if(isrobot(src) || ismonkey(src)) switch(input) if("help") a_intent = "help" diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index 6d5e308c7a6..27ecfcc87e9 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -90,8 +90,6 @@ return 1 if (istype(other, src.type) || istype(src, other.type)) return 1 - if(src.alien_talk_understand && other.alien_talk_understand) - return 1 return 0 //Language check. diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 2307d00bcb7..77ec2c13054 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -197,14 +197,7 @@ del(t) var/alien_caste = pick("Hunter","Sentinel","Drone") - var/mob/living/carbon/alien/humanoid/new_xeno - switch(alien_caste) - if("Hunter") - new_xeno = new /mob/living/carbon/alien/humanoid/hunter(loc) - if("Sentinel") - new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(loc) - if("Drone") - new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc) + var/mob/living/carbon/human/new_xeno = create_new_xenomorph(alien_caste,loc) new_xeno.a_intent = "hurt" new_xeno.key = key diff --git a/code/modules/organs/organ_alien.dm b/code/modules/organs/organ_alien.dm new file mode 100644 index 00000000000..5d1d4874235 --- /dev/null +++ b/code/modules/organs/organ_alien.dm @@ -0,0 +1,164 @@ +//DIONA ORGANS. +/datum/organ/internal/diona + removed_type = /obj/item/organ/diona + +/datum/organ/internal/diona/process() + return + +/datum/organ/internal/diona/nutrients + name = "nutrient vessel" + parent_organ = "chest" + +/datum/organ/internal/diona/strata + name = "neural strata" + parent_organ = "chest" + +/datum/organ/internal/diona/node + name = "receptor node" + parent_organ = "head" + +/datum/organ/internal/diona/bladder + name = "gas bladder" + parent_organ = "head" + +/datum/organ/internal/diona/polyp + name = "polyp segment" + parent_organ = "groin" + +/datum/organ/internal/diona/ligament + name = "anchoring ligament" + parent_organ = "groin" + +/obj/item/organ/diona + name = "diona nymph" + icon = 'icons/obj/objects.dmi' + icon_state = "nymph" + +/obj/item/organ/diona/removed(var/mob/living/target,var/mob/living/user) + + var/mob/living/carbon/human/H = target + if(!istype(target)) + del(src) + + if(!H.internal_organs.len) + H.death() + + //This is a terrible hack and I should be ashamed. + var/datum/seed/diona = seed_types["diona"] + if(!diona) + del(src) + + var/mob/living/carbon/alien/diona/D = new(get_turf(src)) + diona.request_player(D) + + del(src) + +//CORTICAL BORER ORGANS. +/datum/organ/internal/borer + name = "cortical borer" + parent_organ = "head" + removed_type = /obj/item/organ/borer + vital = 1 + +/datum/organ/internal/borer/process() + + // Borer husks regenerate health, feel no pain, and are resistant to stuns and brainloss. + for(var/chem in list("tricordrazine","tramadol","hyperzine","alkysine")) + if(owner.reagents.get_reagent_amount(chem) < 3) + owner.reagents.add_reagent(chem, 5) + + // They're also super gross and ooze ichor. + if(prob(5)) + var/obj/effect/decal/cleanable/blood/splatter/goo = new(get_turf(owner)) + goo.name = "husk ichor" + goo.desc = "It's thick and stinks of decay." + goo.basecolor = "#412464" + goo.update_icon() + +/obj/item/organ/borer + name = "cortical borer" + icon = 'icons/obj/objects.dmi' + icon_state = "borer" + organ_tag = "brain" + desc = "A disgusting space slug." + +/obj/item/organ/borer/removed(var/mob/living/target,var/mob/living/user) + + + ..() + + var/mob/living/simple_animal/borer/B = target.has_brain_worms() + if(B) + B.leave_host() + B.ckey = target.ckey + + spawn(0) + del(src) + +//XENOMORPH ORGANS +/datum/organ/internal/xenos/eggsac + name = "egg sac" + parent_organ = "groin" + removed_type = /obj/item/organ/xenos/eggsac + +/datum/organ/internal/xenos/plasmavessel + name = "plasma vessel" + parent_organ = "chest" + removed_type = /obj/item/organ/xenos/plasmavessel + var/stored_plasma = 0 + var/max_plasma = 500 + +/datum/organ/internal/xenos/plasmavessel/queen + name = "bloated plasma vessel" + stored_plasma = 200 + max_plasma = 500 + +/datum/organ/internal/xenos/plasmavessel/sentinel + stored_plasma = 100 + max_plasma = 250 + +/datum/organ/internal/xenos/plasmavessel/hunter + name = "tiny plasma vessel" + stored_plasma = 100 + max_plasma = 150 + +/datum/organ/internal/xenos/acidgland + name = "acid gland" + parent_organ = "head" + removed_type = /obj/item/organ/xenos/acidgland + +/datum/organ/internal/xenos/hivenode + name = "hive node" + parent_organ = "chest" + removed_type = /obj/item/organ/xenos/hivenode + +/datum/organ/internal/xenos/resinspinner + name = "resin spinner" + parent_organ = "head" + removed_type = /obj/item/organ/xenos/resinspinner + +/obj/item/organ/xenos + name = "xeno organ" + icon = 'icons/effects/blood.dmi' + desc = "It smells like an accident in a chemical factory." + organ_tag = "special" //TODO functionality for transplants. + +/obj/item/organ/xenos/eggsac + name = "egg sac" + icon_state = "xgibmid1" + +/obj/item/organ/xenos/plasmavessel + name = "plasma vessel" + icon_state = "xgibdown" + +/obj/item/organ/xenos/acidgland + name = "acid gland" + icon_state = "xgibtorso" + +/obj/item/organ/xenos/hivenode + name = "hive node" + icon_state = "xgibmid2" + +/obj/item/organ/xenos/resinspinner + name = "hive node" + icon_state = "xgibmid2" \ No newline at end of file diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index e8c7acbfbf0..9c26f814e95 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -2,7 +2,7 @@ INTERNAL ORGANS ****************************************************/ -/mob/living/carbon/human/var/list/internal_organs = list() +/mob/living/carbon/var/list/internal_organs = list() /datum/organ/internal var/damage = 0 // amount of damage to the organ diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 64f53e5e55b..e3b758e6b2c 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -161,8 +161,6 @@ spawn(5) src.update() - - /obj/machinery/power/apc/proc/make_terminal() // create a terminal object at the same position as original turf loc // wires will attach to this @@ -627,15 +625,16 @@ // attack with hand - remove cell (if cover open) or interact with the APC /obj/machinery/power/apc/attack_hand(mob/user) -// if (!can_use(user)) This already gets called in interact() and in topic() -// return + if(!user) return + src.add_fingerprint(user) - //Synthetic human mob goes here. + //Human mob special interaction goes here. if(istype(user,/mob/living/carbon/human)) var/mob/living/carbon/human/H = user + if(H.species.flags & IS_SYNTHETIC && H.a_intent == "grab") if(emagged || stat & BROKEN) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread @@ -663,6 +662,28 @@ else user << "There is no charge to draw from that APC." return + else if(H.species.can_shred(H)) + user.visible_message("\red [user.name] slashes at the [src.name]!", "\blue You slash at the [src.name]!") + playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) + var/allcut = 1 + for(var/wire in apcwirelist) + if(!isWireCut(apcwirelist[wire])) + allcut = 0 + break + if(beenhit >= pick(3, 4) && wiresexposed != 1) + wiresexposed = 1 + src.update_icon() + src.visible_message("\red The [src.name]'s cover flies open, exposing the wires!") + + else if(wiresexposed == 1 && allcut == 0) + for(var/wire in apcwirelist) + cut(apcwirelist[wire]) + src.update_icon() + src.visible_message("\red The [src.name]'s wires are shredded!") + else + beenhit += 1 + return + if(usr == user && opened && (!issilicon(user))) if(cell) @@ -683,32 +704,6 @@ //user.set_machine(src) src.interact(user) -/obj/machinery/power/apc/attack_alien(mob/living/carbon/alien/humanoid/user) - if(!user) - return - user.visible_message("\red [user.name] slashes at the [src.name]!", "\blue You slash at the [src.name]!") - playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) - var/allcut = 1 - for(var/wire in apcwirelist) - if(!isWireCut(apcwirelist[wire])) - allcut = 0 - break - if(beenhit >= pick(3, 4) && wiresexposed != 1) - wiresexposed = 1 - src.update_icon() - src.visible_message("\red The [src.name]'s cover flies open, exposing the wires!") - - else if(wiresexposed == 1 && allcut == 0) - for(var/wire in apcwirelist) - cut(apcwirelist[wire]) - src.update_icon() - src.visible_message("\red The [src.name]'s wires are shredded!") - else - beenhit += 1 - return - - - /obj/machinery/power/apc/interact(mob/user) if(!user) return diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 067b207d132..9f82dbec050 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -454,18 +454,7 @@ src.flicker(1) return -// Aliens smash the bulb but do not get electrocuted./N -/obj/machinery/light/attack_alien(mob/living/carbon/alien/humanoid/user)//So larva don't go breaking light bulbs. - if(status == LIGHT_EMPTY||status == LIGHT_BROKEN) - user << "\green That object is useless to you." - return - else if (status == LIGHT_OK||status == LIGHT_BURNED) - for(var/mob/M in viewers(src)) - M.show_message("\red [user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2) - broken() - return - -/obj/machinery/light/attack_animal(mob/living/simple_animal/M) +/obj/machinery/light/attack_animal(mob/living/M) if(M.melee_damage_upper == 0) return if(status == LIGHT_EMPTY||status == LIGHT_BROKEN) M << "\red That object is useless to you." @@ -486,6 +475,14 @@ user << "There is no [fitting] in this light." return + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(H.species.can_shred(H)) + for(var/mob/M in viewers(src)) + M.show_message("\red [user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2) + broken() + return + // make it burn hands if not wearing fire-insulated gloves if(on) var/prot = 0 diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index e6b49ec298b..82936a1dc83 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -78,7 +78,7 @@ has_power = master_area.powered(power_channel) else has_power = powered(power_channel) - + if(has_power) stat &= ~NOPOWER else @@ -271,14 +271,17 @@ //No animations will be performed by this proc. /proc/electrocute_mob(mob/living/carbon/M as mob, var/power_source, var/obj/source, var/siemens_coeff = 1.0) if(istype(M.loc,/obj/mecha)) return 0 //feckin mechs are dumb - - //This is for performance optimization only. + + //This is for performance optimization only. //DO NOT modify siemens_coeff here. That is checked in human/electrocute_act() if(istype(M,/mob/living/carbon/human)) var/mob/living/carbon/human/H = M - if(H.gloves) + if(H.species.insulated) + return 0 + else if(H.gloves) var/obj/item/clothing/gloves/G = H.gloves - if(G.siemens_coefficient == 0) return 0 //to avoid spamming with insulated glvoes on + if(G.siemens_coefficient == 0) + return 0 //to avoid spamming with insulated glvoes on var/area/source_area if(istype(power_source,/area)) diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm index fc88f6b5190..72250fbf1a3 100644 --- a/code/modules/projectiles/projectile/change.dm +++ b/code/modules/projectiles/projectile/change.dm @@ -53,11 +53,7 @@ new_mob.universal_speak = 1 if("xeno") var/alien_caste = pick("Hunter","Sentinel","Drone","Larva") - switch(alien_caste) - if("Hunter") new_mob = new /mob/living/carbon/alien/humanoid/hunter(M.loc) - if("Sentinel") new_mob = new /mob/living/carbon/alien/humanoid/sentinel(M.loc) - if("Drone") new_mob = new /mob/living/carbon/alien/humanoid/drone(M.loc) - else new_mob = new /mob/living/carbon/alien/larva(M.loc) + new_mob = create_new_xenomorph(alien_caste,M.loc) new_mob.universal_speak = 1 if("human") new_mob = new /mob/living/carbon/human(M.loc, pick(all_species)) diff --git a/code/modules/surgery/slimes.dm b/code/modules/surgery/slimes.dm index d962cfd3f4b..048c6d3e3c1 100644 --- a/code/modules/surgery/slimes.dm +++ b/code/modules/surgery/slimes.dm @@ -20,7 +20,7 @@ max_duration = 50 can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && target.core_removal_stage == 0 + return ..() && istype(target) && target.core_removal_stage == 0 begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \ @@ -46,7 +46,7 @@ max_duration = 50 can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) - return ..() && target.core_removal_stage == 1 + return ..() && istype(target) && target.core_removal_stage == 1 begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \ diff --git a/code/setup.dm b/code/setup.dm index cd455dda5b6..fd44b399ca5 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -741,27 +741,28 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse #define NO_BREATHE 2 #define NO_SCAN 4 #define NO_PAIN 8 +#define NO_SLIP 16 +#define NO_POISON 32 -#define HAS_SKIN_TONE 16 -#define HAS_SKIN_COLOR 32 -#define HAS_LIPS 64 -#define HAS_UNDERWEAR 128 -#define HAS_TAIL 256 +#define HAS_SKIN_TONE 64 +#define HAS_SKIN_COLOR 128 +#define HAS_LIPS 256 +#define HAS_UNDERWEAR 512 +#define HAS_TAIL 1024 -#define IS_SLOW 512 -#define IS_PLANT 1024 -#define IS_WHITELISTED 2048 +#define IS_PLANT 2048 +#define IS_WHITELISTED 4096 +#define IS_SYNTHETIC 8192 -#define RAD_ABSORB 4096 -#define REQUIRE_LIGHT 8192 - -#define IS_SYNTHETIC 16384 +#define RAD_ABSORB 16384 +#define REQUIRE_LIGHT 32768 //Language flags. #define WHITELISTED 1 // Language is available if the speaker is whitelisted. #define RESTRICTED 2 // Language can only be accquired by spawning or an admin. #define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight #define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. +#define HIVEMIND 16 // Broadcast to all mobs with this language. //Flags for zone sleeping #define ZONE_ACTIVE 1 @@ -826,6 +827,7 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse #define IS_VOX 2 #define IS_SKRELL 3 #define IS_UNATHI 4 +#define IS_XENOS 5 #define MAX_GEAR_COST 5 //Used in chargen for loadout limit. diff --git a/code/stylesheet.dm b/code/stylesheet.dm index 4d93845d98c..2647e5a0d35 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -65,6 +65,7 @@ h1.alert, h2.alert {color: #000000;} .tajaran_signlang {color: #941C1C;} .skrell {color: #00CED1;} .soghun {color: #228B22;} +.changeling {color: #800080;} .vox {color: #AA00AA;} .rough {font-family: "Trebuchet MS", cursive, sans-serif;} .say_quote {font-family: Georgia, Verdana, sans-serif;} diff --git a/icons/effects/species.dmi b/icons/effects/species.dmi index d5405066ab9ba5575f27236d6c526ace00231f9d..4c1516b8581ee0302520bec61f488d4a493c30fe 100644 GIT binary patch literal 21711 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 literal 22523 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 diff --git a/icons/mob/alien.dmi b/icons/mob/alien.dmi index 36a6aa33682a45e71e3dead57a006e0eb4c80c31..24b09492de066773f5ba9988845a4846e6e4a487 100644 GIT binary patch delta 26321 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 DbhS%H delta 24656 zcmb@tWmHse_%=GUbccd~v@}RagQQ9-Ae|y0CEaX5x=~6{I;Fcq7+Sh>=)hd~#t>E~ZLEvp?S1a>tynFr@&lUPVJx$clXo~r?y2dY*W zIt|SNMG1f_c#wduZY4^uQ&0Qe1@M$^+7*(RQ{Cf}rBGIg_Zrv|9!WB0)r~%p^ zDH3E1DQg9Pb*5%NonRXGs25D%j2dC_5xV)-X^YbP{_jLCDi^Zi=V^cNzCb=%TY@^q z;B@B^RA81d`6CPqSNVJN+#k$QLV5O|n6m^Qk}rWZ6;>awqf0J=)HzsbO~A+o}6HsctaVU<^Ur%u2#-KBZVB+H}XW*7&;n+ z0TEwtXc)(-hFN|5wraW3hnoilYjvKug8sv7-T!ZPy8s$Jh#Y;llt%&riyi z{L+fk**qvUPj=sad;0q=IbNaS#AQu6msiC>7jA3*-{7yvP{EzK;?Y&|{S^u8&UPCT$WO_HQx3davEHFIG6FXAmBtAe%f5E%^n*Hjsaq0N;G}BKCGAFYc zRjAid{k%B_#!S6OjFu^FPwSNLQ4PyUPs>}g4XTGwfeS$F>YDv`@$o%Da*(urkaS=p z3MQ|=UbsO512L^k98US!lhk=LeVfAxGdskjQHeU4%~WsF8-#Yoe5Ces%?p%bdOhnn zGYs@%qE2R1Z0wCseTi|>DOa)msRwhGTL#-s->Ta()Fef=|5_aWknr9TwkdCgb1tGS z;$*<(N63J@T;8+5){{=${O!u@Y}C2Axp^V7{i(^xAdd1D5-b85X$6IlBKM)N)pq-i zx!~sz|5jt#VAEG5WzODkv)Rj>nq%*By5Mjd_~!+b`(1~tC+2j2B@km>bW$+K%5~-8 zrHR<-f4eY730gvmp_G`V)9{zx&xq09@hINcC|>|-kHdpx9Ib5af5YuaS3g z{66TnLv4?@_lH*|gZ*}_+98k~t3xVfx7#ebGGpIg+jpUE9M3PGhsooW`I=N&jzqK$ zggs*%9iPkY2Jj!##-_k^xVq&m%*pw`zko!IyK=Q%9UD@Syg+a4n~DiVr-pEa&W3N1 zrU(H}dL7$ArnjQ`sGQCQm;}cX_?f+FjKekDxZk_HulAf?gztB=8iq{gPsorf!)Z0R z85wu3e#b^;&3_&hH)a|Sc8D_SN#P}q_j$(rB^>)yCS8PEmQ;6L z;S&8ks>zMr&B5oj_m>Dh^Je5p5DSr#K|diNC4wCI+eVel?A;+JWA>4eEXph%YTp() z^qW49KjU9VY7Hrp2xFj3N<53%pS+tVk&j5JWb}SIA5&nuCg*JDZGH|#_aXF_MTXrE zYtq?mq4Xy35e^Lb_8eoZR>%dxlmvareHM5#7^s%co%*5*^zj|yY6kU?gPon%dK_R9 z5D>6p;3T5WIFEXVn7Zufyqtg3s|I`9Rk5#y;^yH*JHQ_h`F%>R#J`C~T~TiONEJmD zEq3G-hK~)|lq$Ds_3G9-g`BJ&MQ~KNi(1V3?uQN;dw)4Zn}No5-TaiRaZCR?z8IJS zWrEiH?54MX++H2WA}M*y`bc4D3V`LxV(oe61$ERwZ+Zuz<-bf?2)AKF?ox3zNfiY0 z%kZg{=tNMK5@u$Mvd^8j1KZ{HJ|D&U==@v+?jfZ>ygUkggE(g_?ki?bR%x}$Afb>M z^wH$>baq=Q!KS5}*}!#?Qivp0+IKz^JktK_3x5;|2AL>F5;{1;@jvA2CBU68CJOpf z>f?w8z3ehatoAbzF4gn-TA`wa$mgVTK8F)_h)-eZv~L91lfEJ&8I+>>vwR`Tw7faj z9Ma^v8)FQJ3q!JBtWxTS?*TBf(_)lv#8X z=k_m~ie&JZkZ&r4&C4AO2Y}ToDkzTgqL8!S+Hna!B|7Kaphqeb|0x4KY1a2qVYsHe zj0F>P!@j$$jQipkMt6Gp`OEd6uUNHmC4a&yvXTW?whG+VpNhu?hjArkF9?R7=Fn3DIC+O^*N5T4mTiolzM*MusQG5e|3 zkFmIGm9-Sd42NfTVB7xK`McNPBp^m7;V>D zE%g_)QHJUvf8~ukSt-Th{^jMaLLe9g`pEG!zs_ya{DSB=&5t0${|+$A&l^sP^u=x3 z;Woj6dt&-xydOQp*<%5%)rmT<$(kv8dlQ;ZG3ntc*E%&?MMW&BVrgT3S%&16+nSX^ zRwh3wN_cugHSnk+c|&$7OcV^wCbj6jS|M8E>d6^9QxR%Scx1u~h<##X?`Q71PdxpU zR>HK*^UE+Ye)|Q=EFDIYr_#X4SG)OdJXYy~Z)BdS zW*d0c3~(6Ptlt*+ET4Rg)rp-c9+;GTrnaUG_m!wYdqza~O^0Gz!URJS!z7cI_pxV9 zQ4`OlPIM5zC+co0V{^3NVd^7>h=>UB;t%E81W!dj>aijZ2z8C3leZ|nC%OABG7pY* zPNbCXNlXNu3Cl15Q7r42n(>Lr$pxfl7mdZmxB~I+Mn>rr9%|S+C|0j^jXhQ|Mgq{V z5#Tn} z{Y3oal8*gD0n5r_;^T&EYmq&_3$eey014F(>Ci^!J7QcDlYJ3`s|&)@a)e(@520TO zg2m5ryB#T%TU~q8Ss8q_bfSEZa<|8kzI5qf_9@#vlhP|6CtHB*^M{;)8{ESO95y$b zlq=yotpr{gdD0C18Y;9d{xjN;MI~SoXAf-i)U036t@kMpOP{SUX$onZx~y4^y2zci ze8(e=w({(NHZTw5$gk~h-DG^Qnpz!rNm#So=+X`pIH!Z zaD8u;t%4+2+kKX{nXn%9>$hRfSBfi$=j*gXFaS*c&@u@P=)v;!x8Z%}2!9p*X>Thr z>B~S2>SX!%_bJhwcu>hX0*lW~r>n<26@FJe$#~6ehdmkB+2?U0+>E)_@mAioVunj< zQ@!1pKMm1HUbx)LpEBmBTa{QV?#&wf{AWVAJbz6C=}5lDfg&yE{j$0N4D&Q`_7{B>K=I~cuG!37dt-w zPNha;FFZGwiALOm2#hjJ$Tf*E17IWu+pm{TlvuMlPF6JiGETO1jI2w(fgK~uov?AZ zT@7D>`G~3P!Nzkqp7%BwhqwJSI6or;@Hl|3@_btKT+K1eOKG^5_<45>%UWsLcQpM= z;Sp*7YDrF3b8fCeMdk0eG6Xsy^>e|MKW#6NRb7^RX)AC6B zvh}hWVv2lHCS%K9$+1{lsAk*o**qsPZ&ecS&)%-nKX(Kxp&l=P_*-47CJPwe-r0AI zz8YrZQHhOwuA4x6F)xphCqKCXx2(smte9rTw2!GcKfOvsABvkzZy?bi5)I%K4TZAo zvY;koTmH_!&Lt~{K~oe@@B0biRA0rDfzaD*WGy{rYH_!A%^~c8NqGFN=YDyfmASNdr4V83KXFXrHB_-TpJ9N=) z**V4LE8Vy_+=+Q6{hPsT$QkdQ!X3HstUIN<6FaTxgT?dQpT~v z(*y$PHsdVI_U)rFsdZ1dPCqOAa1I+=^=8eJ)VS5HmF75PRoBXS!vQB~#IbSb$yQDG>b<<9)f(OgK*?b&R;$ z1?I1x6x+)XpNu=v1Ke3;b$>VQ*t%;L?e)CKF&PDe*@ur> zT8UfOIb$&wtu-}dpbIk_D!*b8GKh&$tEi~RFdLFLzQhqo!t@{In&WDN2;z4y?<<-< zB;x>Gz&>6+!&!0+=q|KGE-eU-xIY9!4|y#o18D9Ti$ET~PR`m)<{Icg^7Z+ioc(=a z^P60nocmtmgsjfqFy-4N(3#3E^m8x(1&ivu5J;LGZ$<|-7V=r#Hed3Bz8u2189vUKL;`Gek$w(#qNQou z(X?@AU$0M=TMOCl9|2@%nix;+nIh@-mIVg#n9J(DE^${tJ2DA_PnE`Np2Y7ZAsrnu zb`7%zU*e*CwvUc^!uaU(VD}lFqc0Rf;F~U#Nx}{GWso1G74mTlvLE zv=o9#Jn*#TdN7yAt4*n7ik1TlQZplznm<{A>Ikdt9f%j<#*z+6+Uq(n7<_zzCL@lS z^HO{dM>s-_X_YZ4`OGui!fB=rIF-+#DH4lU;71*8qL5ch=3&dA^1a%`NBj}H@_LY* zfYVbW?N+^|B4&tI+^WQmUzes;Ag+3{VM=O#UfxMEmhHjUM#UHjy(CPNlUXchHAn}H z14*C>8Q3P@%wJ6VQn${zf}+62I6CV_vCW;{mB?5QRkW0R)x=NoH59KWZuXhgX9qd& z57cFEj{8Yxx2(HHjy#ob=4*|c!$b|7f!B>LWpIzBcn@gK#yW{z>wKLam&RusOAfHO zDLUDZ>@Dn#P8YR#(^I z`AZLvAq{4+7Yj4irYVxK1q}_eqa2Lhfe=AeWxt()*Gl?nsyW&J7$F^MerKdhfB+l+ z1~WsJY~_clnQ)TgflVCrc}mYqxl_jNe@`Vi%> zQbqt0O%ph6JX7NkFFx|p`N8Xg`Z@JCAH5sB_{qwb2~&e)H$zWtpRKvQ$`5&^-sf5I z{_Ie{ijB~Lj@ba6XvLNRVY9wRKdmGKHvYWs>+6?3MFK0f2;GCC#pnkbZy0~dcRG*0 zL`JP30|z~!KB4{9RQ4S)9cg)VF8bt=%A3x4pzidi)9j z+~{!HYscGh7~jn^=qc>DCB45_?>U zP$M%qgWE3=!!?}c#eGSvxB*CXd!?apM)|R&fUn}g%1}Z;i)p&?cX!b z1J3z3O6?mjUqn3o@`iFc}6&0sppXVtc=nzDKru?5q~tk6jN}0;Nlp@LqSd zX6n!<1gn+h_Xam()l!qgD9lRClA;$5(2GbE2wpUGL{$?%)TIy>k2+aDwL7i^j4sB` z0G}|qYmBAmR?V#xNZ-Am{P^$E&UL=YTl+w(>P58(W>mOW%bC9hLIR$@b#MFU))c^A0ureNmGn%%f`FE_V=#wRC2Dq{RjDM(p>KQW3vo* zQf#-*m+_RDgpRJ6J>#Q=t;gZ69LaF(`o zFYCMEjfU_E%&TSw$H{sJoz}gw(8S`2vYx!R$q-02g=C$m<4O?B*Y|7&aH&AjgDxEN zL(*VE@j9Bmx$eN)rEV|xLnA49*1~(+0CPL7!wc_%<%LGj!`y~VLD*d^D@6#utfzpT zJ{N_gYoz7PaT~Dd>3KW|nbe3e4~h8$!q~}bKj8!G2J4W3u)s5r0;sr5)lXTY+}gR8 zvWfX9>(?Jl^7&l%`}ugB$u0^wmbopGCz6Y^GLc^H@UNncq9?KSL0qi>pK*%@PvmwY z^V{}+DB^4Zk}$W+=i%q@{pT;%=i_p#%1q7&BkwqL19ol z7Xeb*`Q4`doeRc~OR9|FbTIt>HeC}5&vv%<llp*PSdkC+?EdV@bC{z9ZZHnEa zL+GY_g3w&Cco9|9gg#DZU7e+b;_mNn0g3kt6wzEw$I?qE0`7wAUB3x61nPEdIPPmY zzYBa4f@J2jqNV*78d61!5LZ6@dhR&Xt4=1*YGVCy4NL9d!#m8pm9Fn}*)2^pn^T(} z%^O@0>GzhTsiJA>3);nZ@ZkV=q6y-!DKS(nhG!JZA}0iH8FQtj-q|L+Cs+(EO=1lz@h))VE| zfmebx=%2V*Cc~z=v)G_qW=tw~RV`}y@iP&xg6z~5X$LVJ6C7Ahagjgz#UA}#m z@HRDC%Uzp3zJq9m0k^EFYMHAo zdrP_8&?QSZGzjR69c1iNQHq+8>0#}MM#h8oC3l=>3<>}AFFy-%;i#Mt`Wo+qC93N0 z2ioA|N5Hwo+w>Z0_3oIyKe7ndeZBAn_)wgA6IA2di?%b!Z%JtUZ@+lW&WP!}YejxW0N<8g4`qPOI4bqPOuK}>WO zD>Rb14PSwm#MA}qto}Bc@5i{8>!CovYio9B{vV_~UCqD_E8pRn^+V7TF2W({9+%iH zd@Ip}_K)2L8(cdyG8KcKde?CJf&97DU-X-%YRLTJXiyQM+NnUf)jN{+7fZJ@G3@{a z?y*Mq#6yR`+%gtrhu8prn>vo44dXT6>r};PxZ@$(cL~Vsc{eXA+Q0JbD?AN1pX$q~ zx)-UctVC%Sx-s=mudW;Hj1}Ml{c*jWI4CAUqTHiSqKO1%O19sI(cC6}-b5@hC?9Rr zh{8GJoRdX`gbRNfwf6hb2R?uPydQ8-<>3gPd1z~Mi(lM-=|(2b{`*2pQF=nqS5=-q#zuba5p7JvWer@6VMMJSoaV-Eyg&Cl=;Wh2F*lv*~G99;j8GC=w@z* znBMZ=fp%fQf>Gc7u%mo)i)mcfHLuH41L~%zrkg?p@guGUFM4?QSXlNIu78=h0Ll0p z1cMWUwgv=@onc`5CGVLJv8>tmmHieS{BCU&3D5eEe3QwC?`?sL31Mr*M zFhRNrcsTTfgV${SowC6>e~6*+SCEg_(wHG<&+bZbGI6r&ob9ZNr9ulL zX9E35(I-7`l{+J+QBK?;DL2(4UgPbh5xGaOG>|3c11e}IT`*+F3-}*{rJb<4=xu>h zd70~)D5tOCan}q=${;eCLF0%U-2T;O9$#djUhN9!-0>?5tUc%Ec5B9qqWeqxrLC$> ze>ai0$~3{PgByVyVCW5)+r+?yA~u7rM*7d6hQp)LlM`uqh>c&pQEvELw+KVd!0KgQ zQ-2Eq{-9x+kNV3rcx`IYMojT9C>Z#GJYNSg0LHv%RGkPY&nqekxBT|XY5220C|~Hr zvvP>N&_56Br!jKYd`HOLoJPV^h=*?87g6ukPDC zkxO;Qa(DU^Xz-!qkr_#;_N-Z13^yFH!}cnK?^0T>700_T=l=%rAErD3XD~zbXc;+d zwDz~nLaf`F^8m#fOsh@4pvZ;8@^VA8)}kYntC9BqS^Lq$+J9Zr)j>#MO-WKUsvkx{ z3)I0N2UR@nDyW~k$D?P9sMDktCGXK6R+w;$b-N`<)bGl(-gD!QxLrp8F!6i)1^3@b zu2cWS1X`KX{a)904bxv8stBh%RB7-l;7YzOWS9zMR<-DL5}sUoO>le>L=QJZsD# zT(0Cy|Hnj-Iqa}XKY+Bi1E1H)aqo#6!a&y!bT)R95?A@cl{z?L`M(hZ_Tdl?zqnis*#7to`b($iYG3s_f5ewVKLDZS&a_{cYPUg6_p@JrP zzQDG?yJq^KiuHfZzIUg0?Z+7)jTY0mf5vQP2u4|nZ>|yo@8$lM+k)iWx53rPuHnOV z%ENK_YZWTOk@{+sc{{05OscY9CgC-}?Nx0$>7_&Hopil(4)SZIjbh_s8*;IZ?(pi~ zs@}okE;JDvFkAMpg*CiEaI-vjSu=APmpr_JTTiqeG?AOHPT#mUqkuf*kec_;CEc&f zWB4hl&;5t+Is_mvUtf%r=8p$ybPC=suH9)UpWj;s~`bn?yf=R8|nT?3MQPeZT@ z4UNtVdQc$qicvx0lM6@nex1ALJW1wzQkH(}o;JOYM zB|^NKpa%`ti;{joB?>2C^~)43Q^90L@rM? zP7S{QvVFTSA?B1NS`PH~3kCdPuBu_Qj~Y=TEC_&^x_{K*Jk#w9+Zihez-9S9XAC?= zNePgFs;ucWh%+^2>_5M(tuCrXY)T zJjub5SmTgJq<6b-Bj?3j>1_dQN%Vi^MA<{c8e3HUM&9A@o;K6mODmLu9Xh!P-%6TK z!mm!DXtyu%8kMtV$=jQKkxN$o_VdYuB+6)HtGCC$;G0zqhW8*C{g*F_GY`<9L(sej z6Ttkt14$yMU@Pa;a90(k*Ej^rAP%U)bCs);3x&;aI+>#ep4$EZZS5&Fh=ZE|6K^Dk z{X_bchY|=v=7Er=H=WNzLDDtw3jYfTQZD#$0~a7rp-RuXc3zHL(!Ji!@B@+L!7xL9 z^cGdw$gfW@o*!R41faswtS9PXor4QwKL1O{zfQV~Fa2(n@ugz~pCQ~lpDk86)Txb; znps{Y>;7m!<`g5BB=4PcuaR_y{{^?=T`2GqOWA%y_1Cph#qpLSsXa}*Pfokjz|gob65qJ2QlkCZ-e1DT&VnQuMGM=vvGxe<8K6(*`oH?et86tp{=bW1N*8L>f3>j3RL7t1 zzyDtXc>ga2lC$HXVuqN~g#4e98YE7cOYFoTQ2%0$|G$xP3`y7(7Qq+;@aSUocV6fa zUOor$PdvL%&n<5l)lIFFA+8H;JaTEOsv&zdDi5ctBzcQITh)oW33^Tg95G0zhXnx| zKx2d0@_QzdH)j{K^QN?ZjxgU=Re5MNEz%js&;{4kT~0T1$Kv(Ji{sOhmvrnk`*VrF z+E}t5IR0OtVLXTtu6E)=iLY>CMn^==Zr!Xfd#p}Ic17I+8q0_q&%7YV_xF9-2_}4f zAlpbW4Tq$q2rmyJ$gzX=@%g=WCLDU*$#OuvfJhr0K3+lsr6i1P2jA@=*IQTH>xsM#1EooIxStU%eiSmy%SsD%8=y9ak(I8~)em|QP9)sq5&w1`2T=kcGXVnK> z#;nf8Ge2WDiJrggykxjYxH-l4q@)=W_x%(W#9yt=x75B-%M6k=khAwZZy z>@<_RG#d6dTAmJdX$0ClgG76CsB;YCJq4!z4pAYsG{SNVLC+M^tl@VL|E`HC^l>o*)4(Gh#T>i+@Dg1_nXXDoG@v|rUfR!yLuR}U2 zB(2WwT<+D6#cbi3c4pL)>&x|!KX7fSe~^_UU5o)|vAq+ zJeB_0$`Cu7x=~cP%(T9PCjmJHI{+&z`V+~=*HB$OQJJR3RF%^(>s(l&UX&)R_M_G= zt#sS8x5aZHt42V%Vj>LN?2hNi?;5pZE{34&p6&PjCM{u`)F(X2wA2V-ddB<|Jd~vj z$g^J--%MU=x2w7q&4k0BLbRuWzW2lrG>!_b1V*j7yMD91Cm6Mdt2WbGR0I!TzMTXs z&L%(cp zPT`oJ$jR7Tqoc3$?zOtMk|BFfs8L=5ZAD1Rk+cG3I#IF<;e>tTVn8EBZ)oiZt7YMm z5aLcrxgHTs?N}eD5V21;EAGl3qp7K5zYZwLV+g7J`s|4y>_@8u^CF9z(yK$~@xDBv z&sdIZ`;tVlbYmO==hx*IOjxgY?(6378}K9?MgMFueV3rEIR;^XZ+`@%gE9jR@^R@` zv8NG~`vZr#|C%Q~4{2iXTE!ZK<`~)Ts@7~eCtJ&L{59r$Me8u-!jT*#yjZp)z>R{T zpAFsfSJO+49nKa@7X8w{H*TERF_r6>2{b({t`K!UW5vY8D#e8;s9_#xZ|xf~GIo)_ z?1#sC945y7dlXoYIeGur%>TFO0-p`uCZ~bk5 z(~wKYiDH_$hzQ7t@BhxA39vykAkmH1}L&0{l4n$hp~5p7_pq%r$23PwZ| z#G0cCtsiYl(kz#og}n@p2Qt6qS(hYX>o7`VM2Tsch@z#H_(uD%gw>TrhTRybXp zymNy^+#qApAMgr_La|)R^(*=#<6*RV-}T=W3(}eDi(TNZPoh&(3y%U({bhrL-x!)R z{@e+ClKwLan_8&BtE~}vNyE;mX>{(Po(0*&>6Q~P?!~L4Qmy0d|LzBvqc_Js*i+|R(^3gS`vpD+%JE* zbH0Pk%@w)!E|8vC9`EXc9-@DjEco_hGnRw{y-jj64#%?VjPl{`CUqF^)PoP0@t<_464 z$z3BQ%3~%GxAVvynis`s08L@n`1jxqy<}?7ypp2`&1TvUd$wQ-kF^+?{eU`!EMVBW zv~}}8&P%6P^3i>YB~+X#?F|XzKCx=M8QAVrJvul*Us=A{y1fe7&)Clx?#{Pc5Z8|6 zactL~X@^nqo~}M~YgIpbK8FU#1f7k3Z;p{84BDBR2d!53Q`~=by?6cB#MHHuOxr5* z0g!Z)j57O9&D`9HX<-^A;a@>BW|^#}WFAB;lUJr`(OR=(K^KAz;B#*;=C-{R{`_X> zk2&XXzq{M&FNOSVHYz1DY6~KD{hEF|rwZv9bJ$q9&6)!hN&FUofo76I$4RphLN_FA z6gV6}y4`trK6H7E4_3X2w0&3s6)pM4 zbyAvf++CjLFe680Na)rfyu1^#FVzInb87TW6vWVX{Zp_B5SoInsVx3H;-?9npTgRH zD+QD7zWg1Ovy2 zmY&f;g*U8mDhh60Q2!d*=d83$N8-;Ea**y}NNb^lYKfeDS$?LQh$_37{1USA#elWv zu7pMr!rA?$OdG?6{Vz0GQtt$e#G(|i#Ec}4v zZaRoz3uScrMRLQ`?=y+|e+o6RR7JQX1+NEWA3uH`_}&anSY> zd1hOQ zPLCN5y-dIZ8PY1ysZ7cr;R?A^jGoiih+U_fJ|bwa1pf+Twnd?^KIw{kP!1_d1tZx1 z(|Jo#VqIyZf1s@3%f{sYbm9I-WB~s+l~DmPe>f_{k&43PKb65t@c*J&{y$2V|8uew zlq~xOk7e;-Nr(BmA#)YSlx5WaIPD0pGEl=0V%MC80S(-Dc5~^7K)qCWpd1hyF~4GVDa{7t)OGtRl#KLc=(^E2WryT`<0QL zeExX7x;h8Rb**li^=@W1On0Hqvro)qN`&~T-h5fy!o!K5#ddb(`eqBb6%GX36Tv+A@tghd{QAHa0$KW*6AjDHLy3+~k#u2$ zto(0QFf9MSSwRi(Qv$bR37i6kHX}6y)J%aJ;Q*JtHifc0{yYIrHO|(j0`9-Z(()@3 zG-ps%nq*fHKDBt)_wTOlz~<(rF5Hd%_-);$fWf_20}|A-Maai2si02|JTKSeTf9yg z?4JnXadbA^2Qzg%tlJiJW3{$M&5AybT(maHaC-Oj-scto&bch*t$mK8^9NkJUAwWB zRR=hafyDo=sfus!(pKGm%t|h}cMcadIwwBu?gr8+&CMS8M8y#xgIfWLo;MFh-jTYa z9m;WnI#*gR2oc`t)&hU118Lji#_Yje@Ls_a;0A_%BXbfra`#B&8FJPaDYpgbnV; zz-n{x5QxMQD6;0}r+ayCUuxvoRDkwEq(;vBk(Y#{X-fgggFJ{PH1RQvOzxNcaa>T z4fkgC!+&wh)+`WG{+HLvqf{6SVj?fU9##Xs!iV}O|MehPIIZNKELbAOtfVymPk%zW z&zkK&NH9$q{eNP|{~yo+;H~qbEpkI9#B^Isc9m{htOsvjjG5f;7QpDNFA%<0D(?TT z1Nt}!A36jt#VMIc1tKXqpZ-WoF8Af(SlTXpqz{hkn-hk`Mx6bMnG+@z`=rAaxL7yx zaP2R7_Y7mv0Fq%L53gj@$;S|1n5BeY8eeyJAZm&Z<+Xr zpVatF1mfR+^BCfPd&|e!3GSVN>L~D|a+ZCYdXUP?g(f>=GI1s|C6D+H;<@$_{YMtt zf1wj-nWMFR*{7@mr?Kq+Qaf6N5wtk z(e<^^8U+@btYLid^cuq&rm zl70Sh*((dv4Fmf}4TQM7J#pXz6B+;6P7}4!^CnesH%81s(B}l^xLrCg%H;P%|FM|C*RbEbGELB<= zOTDgOY;iFPizmK7?#DxxdyJpj{KCGW77`tB1 z(}vmcS;w|zJkix)7BB1)!zj*(-b{h$ZNvGfp8Uz!67&DVnv?gYU zn6c8_m8gvkzQ@sQKHda0Q+Hn~c|5&6k+6HpF-U61X;h&(S7Xr{iflHdHNMEN;#YR) z7#5mhMW=#1=o(P$^4Tm1={tyuZ4JE-VP!S%48hlMb|#g0``wbW8!kMvveO?ch$3V^ zsg>e;ey2A>6Rng>90`RBPjQPdI?8pvH8MUAlp*)eend*#4J7}FHX&+e8VX90lKCiz z1aDzGL48GOoVDyy(xfXNc=r(5hYn?9EgkXfwiG-%zttZX{f*bt&UYumJ{++_w9Vgx z!9{*c6VWO;h9UA$Oo^!@0e4r^q@gfY5)+z4&A6rFKT!pYSEWq92cELEAW; zpYZ|UGUr9Xz-ek=;{%`Oc+OO|;lZs@*l*~SeOEQ^E1h@i?ewatPSyNvElZo#lKR(s zd8LE6xCh&^jOhI4Fn1ePUh;DD`oTtE2L@6qRT&$sC^2+^A?X7rP%%2xyYp#lzh~X1 zdHG`o@BSx(t1W5*q;2z(;P8dth8q)L9lTWMDYMdSZEVmWcfb&63f6~6Kx`put8{MYGw;Tb z&gW;Y>1yn_iP5dbQRHEVbi8UWRYsk}=G&>^@_*;sTL_k7q2AwkZi66b{z282mDxF6 zZer$S7^FhBC+aHzld0B^!UeU1dD39gZ~{mw5k2^%4iHj@Hi?@Uq>*VmUxifG-Ie@x zf&)xT&QUbWq6M3kDjD4FX*2QdLJO}mX2 z#y&)v8KS0oEIHI)UcOSMFv{K`$*KZ>B0hEetbF`+0Wdinra-9ufC>Gdgw!9V*ZIU@zGrR0dnn&9roh@G z_5Ih2_oMXAN>4b6v#*8Xtfc{{}mdTh-xyC zbV*A>5inc--oH6McO zJKRH(IJlgt9IN+#(zlHO!U$2NFNMa8>0fbD5i6_>W}J`=LZrQAEy1X#6ksizJ9ewT zmt{`F2b=v@{_68mE5<>WKLp6ef>N$*LGJ6c0CDB)R_O|{Udma0B>yB)N26_m<4d}e z6N*H@iGN#~`rk0R0lB3$xW8Zap~=C7SHKoV&PyIh$lBY#z48F6`h|EnBT*@ZshK_h zlRGv7bfUqJn)b%M^BC7gsZIw@>xu%}Y z5wiFjbIV@2=0y*aj6{yv5(l*WNW-9xoG{cFH?LB$z=mIod`P(qqQ<3qe%W;hONYZ) z6=W2snacVAGzFiWd`vN-wq#Y>L@O4fzv9X@zF=&2{WJ_9Qo72MLS${AlWxBg&<_n# zmA_F{LI1QZEsV;i?)`^eHB^pK`nAUmjym~v)!$+4B}q@cz5U*mAC_%_t6iZvWn~0c z%LuF`r{kT)`2)dtc!C9dGIyg|Tv5#rz=P=U-VZj}<5wbNeNL$oXhN|`DLoTaF8;4ZzBC@n zFZ_GPnys-@iY!^P6p^xwEJ?ByQuaOBB10=XvqGc;?N#n0xN~+}F9zb$!3z>pG|N@KM#o4CXhq6Xt5?5!RY=Y8bh* z(;&xghTkplO6=U}3?+vX_kJ9{d}3g8%(l2iCSIG1czU9VYt!J{H5(U;plqDBNwlKl z6E!;wN^6Gwr2qbK4J7E?#J?64nV*L&N=RgeK@($yn4>y1>_>RDUv3$1m{>Z$$q>Wt zrL0`+>qW|cOE@*!QRr$Exf)jC z?~pd*+IWR*vwN12N6HgDEv3#Q@hyyv{Q~zKi_MD=;g+e%k1p|FZ?4Za6d$s^adaU3 z=1(4b_Y~6S*^g52(5~wXb-Uw(dzvgILT>!OJr=dn=3|~tt21DPIHV5tjQnx6&ycML zJ=-(AjB;;sxToXhe?BxQixs}MS=0A+g?bLMJDTaU`bKm8LX|~^)bm$$X zUvR#FD5>zo`lyR4mja=5Q|6}tbKkokJjp#d!1&NekJ&9(^tP+LxHGE6bZ)ag4|n;Hnr zMCsg6``cQT#P7^@;> zu3PKmyRjLeUVA074Dd~hv$W;}_>M#hu9v}Mn4i-=m}@vyD5qbbTA@=aSi||!rg{EzK7lS_EmMJ^1dY{FzYeH(9f2!o5s94(0C*J z#|zkx)9Pi1y=#O>bi*F}pBBYBLxo88R^(&6m@Af%&Hv;M9YEYl9PF0HIs7$S zy#Qi}Vpc^0+Yy55adQVogB)RCTDS4X)P7MF>0`$8!uK-gm-S9sIP#mu+I4@zztw9srYPuXBg5U*;7uo9lxYFDl}Vf6QcJDEVDRFLS=?XepX3F zytpuJ_M`c)J?c5)32h&>*}1EY_4DM7Xo6Qb?4GukX*aT+YandefXLXQEcqi$wY~e@ zxwqe`lqOLZLz)-7lL>2yP0v>C^__Q-z1KQVUJzCrgJ?q|cp)A(3Dd^U1AU)=WtG)J zn$&^bC=|-1%Rx-)O7HBMUIWfCX6HI#RbB^JV;rvK5o?IvVMVX(n0Ia;f~AtrCi2%n zyFsn>)P9E~Q)H6tsVrBtzkJ){P__1(H00n#TNhmmotm4krQ2cF!kRPil%DTQLD!fP z)p+@0podQ%$q37iS7q+rCQu&*gIA`;6L`p$jjTw->m1G5j?ee?e>$Gxb9iK;E)p)@ z+mW{I?7Av&2wh}Ys8pCEaqqC4|30;HU+1I%kDKyK+~+0N0)k9*;9r~o6@ORYURRZE z&T^;sB?+rcKv2)Z)leO0lw;hF&+kZdBqxPJdXv&1heZ{nKLdF_{l0AK{6kOb;0Ght zzqfDs`3+2J-S?nFitr5j$cQ*X(4WYwTfxWGPV9jMKL2BZ^|XxCa|)d$Of;g7$d8qf zpGPYtun}D;RfAi`apNsbQiR~y&I7)aKL@YEI>q#YIw6^ z8Ca-Cy1x1;o+DizP#zffdp;=Pf<$^mE1g&kxTlpwACg9eU(Nb;*~3F37Z|my;mzMt z^WS}dd|r}%5IWw>d70#EC0Ibr8oPHO^y@uo1GuzJv=&W6E_k)Q>Sdm3Fz>I^?n6~V zY}6t}%klVc>UeVQ`)6S0Vc&cdw0$c5$3WiVGsb}nKRSL%nCwPUDm()IJFEDr796;v2_ zosHTPxM{EMKArlcZj;vqs!|v=2OSszSFHRAE_FodK8vgio7ke54a)7>-J)b&wXa$cP-FW zZnY;lHO77{gXOcpGIH(fk#=?>sCS=K+Kx>{GYUXwX1T_@MaluMD7q3r7xlv{(9olvo2q5Fr_HH|y7e=b=sPKT3wLk-SL$>5MF6u%8 zJ;g#9O-GGS`MyTRD z78f)TGRSN1nGWFOQ<@Dq9{zku6~ZtyG?w{~vo<<){14XsNJvk)lOBpQ7jOeS3+-}N%u-k32wVH4ZEzGV0&0a#y3Cx%{lYRir2M>g-hb{Y?_>m)Z@Sdpx zfWG|R%SlY5@YT4S*Lz#XJ7USP->Llu?5^zSZ{Ow|9b7if!63VLx?>#aIj0W;boT5~ zVO5o0LVxh=ADmOrJRAvXi{rHV6GvPu=w$KfJ4svy;lM{+7Y~r4RO_^ij ze*hUesJrvodkKX5(eGw zw4Y{rw%tFX4v0D(m#!z0Z*Y6x@?@z1P7Qwzkf>d_h!aR)7R6e-hM155eXgeF z3ikU?=Nd_v#AT4NvIBg9Z&bY_*(7%7XAM!I|Mapdk(FA@YvP*X4k8cSg~0VmoRq8p zpa%KNhN@VlQka;VSb`V@$AzB<#QNU^GT+Mb;~etb+*LI_Ybz^2B`T+Y`%mmS#E!RY z?d16=Ylg^|ZrsA9#tAea)hk%HGY9H76`M56QP9(>1R zBaUj1*kH!S35&BU*X@d=UDjdwFc%-H1sZ7U#iUI$@?b^+19#R>AI|wjX|acI&>-E- z-NI14?hIz#tjp`iT4uT>T1iIVDSgAf+VwL}FOSjm&~+7s%lcf8g#ucGC((=gQ3;jd z{7;j2hlg2!V(}sbV&-i-$go{T(Jt!BFM{pby=>W!+jeMnj1wvE4+^A(3Hk3&Q5SkC zAQU))Q?Gb1Hhl&z?$af^39cswDo+PJy}D|Ps#3V&q$J|(cOsjxYhEdb8(-R!!hvnL z=UogBMJPBj^m4|>B&QJIokDDSh)X-IO7*x6CzRKG(!-h9A+zbSW$xK~x3oAjOMGMCLSo{A~&J1>)?8;-##otI*wjq>}k zMm-h_7(|h=&r0MWXy-Wzoy#t?Ru79w4B{WD`pTi}QXapX9jaIO`qTMPoXu7>|UF#7wi+xSbIZaeBx=?vx)iGMcG_cf`PA28hJGNu>UJY+ z^ki{{bGqu6^NBToQk$cmqs7=+<#W@GuY`}kqO676K;kW%nPWBbe7Zv^mer9^Pm{KV zOsuG17r7>bjZsYxbWRTG1^rDyw_Cq<0Z`*e&@$u-67xYtC z;;Rn0_@l~~R)!K0UR^IcmhoF&H`_H)>J%eo9s_F1jmP7+TI5`?FCytM+a>!xb4KfN zk0VcK$<^?U^&_Y4)h)f5e7_vbE>e5hk>dN7>)&Olj|`@HMO9yU>`Ep|W6kggL{1 zU_X#g(3#=lY9=h&;SrQO6qOZ-ABl_-g6Q8>(@PDFrSb1sPkb1sZT8L}s-~BlW)G8T zP1o$_s_g9_r4ODpYGFjCya@SkFfVh*nbA_uZYU7G-M}=#q&=o$FJ{(&2lJ+!3Lr$K z;3(uNf92@Yk8+2|`i{8tEXy%sboVd|iMd=wm6Zchy%Rj$627fpwh+-!Gp^vP9EF3z zdVBuuRl>@V;C#mrqx>*dg=yHpT-7tzitOsFuT9Hs{{18TGhu<}Ha`S_-&1{Zf6{)Z zE!1ws`y|Psglh8ry5V48nxR zzy1v2j}A$6QyRzjceHhD+%8|^>T^3DUeT+Q&@!ofuk|Lh<+K{oC*o<~i884fVZYmS zWiyBnmcKu{IPDb39`JNazaqCld4zm6g+>I7{;fqt>*nRj%28J zW9=xTr^ZZYv}KqiTiI^IFe3~kZw6R1wN<;DlCv%L$v`*^qW8czaRE1)J%F!O%WE=f z(ULqa2B^XP39X@ZLsx8^ZJy{!U{Ug|B^a#N7{ldzU&XbxW7&w;QL6ols%lae?n%Xc z8VVw}Un$hGVhvrVU8(38w;nKnXw!;C?4K=*3x^4=Mu2= zi?4meEg=2Vi=I^!)@iQ!OrQ6xB{Q4=XT5(LEXMxf!XF21D}*rS=vpvb+p!E3r2tNR zP`miO8&)`_RDj1Fk`X&sWcnoo=%2#iTn_7&GkvoOV0Epsaj3x8fTcPG+tnx#$nxd!frCUuAFOqW#hm!~}CkZJp}#A5u0`0HY}F zYEh-XavOtbw3eea7tI1lUwjop-YrLqM@um8*~SuX7rLr;(Y{J{G|y=~HpSPl`s(8k zO;Q>TpQRi1Z}njP^cGhg=Z;^2r7*&GNr^G-Gfw72ws1K>U4?*?)*r<$UqA}H&i7xZ zJb*X^#@4NEiaQrDj+$?`2{k#_-aR?`uwT1sfU&SWKK-=1y4%)w{t4=&o+Cqo;lEZd z1eo`ipA;nVql`8~<>q`&0t@GofjEheXP(_G7m!!O?W9JQ_9kWjjVxN^@rJ~^mTL zgOGbjsuuWwgsKkngE7hE>ChWJ)7B~KY?-Tapdwk2Ae0|+F>V4B=tqa3ffs%<`w!yJ zR9I5ay!Q0W1BFX4I@i9*mP*5HY`ve;(RIWBXnxMY^| zYyDh9VO9mG+;_)8Az*b$oId?=F{&K{&sS;%nj`EMr!Bzf)hFhUvbKJ{*6)nWaoon_ zl!5uH?ucDQ8-d8%d5e?THn08jlDLe27GRHyBIBSYa}a!mte&S!rQV$LqY^|c!*e-oBm-e)lkf5TY6|_-8dF3%sXpT^rV|HQHZK93SCV zcqYFy_;fa*URF-P2-KMUnzZ-9X;})Bj}-0p(Jjr}&x&dkCbXQT+Lvf67csZxDYzr+ zh9UKL+pZkfFu%;_8p3%vLHXZEgBh@*#X%JW@M_PGJ^PQ=1jwR{gOj_65GWwz89Ia( z8VD$tmU0ojR>S^Gj9w}AQ;q1{ML)TQ&pgq2z~n%9q5B83mDAN$zaQhB+P}ORHgSJ7 z9~S2QbN$~^H8N=yWR(uMI#iB$u5VQ)gnyFh@&ledl3#rm8mxoW27v~$h|HQ+rW}F&*dn7y_kRZ zL@>(J!D>ym3rJrbl^(Zxx@d;ju1qutUWGcr=X(&4x_AVS>+FJdPsWqj6Qrq7u$Diz z27zN+({avGzbyPV++3)}zDvu3O_X0hs}o~`Q!Hx|JE+$pcxSqAOQV2+-_+z~aeOUN z=qI&#Rz~F^^zMyY)NoXz*8X_j(R+$Z5T$zNlYj#!gQE2XD(PGGI*vy-weDEaZyp#g z#ENLI(wIm9zGeJY^QKPFS0;rYvB7*YYmu7F{q&tve9xEakKKUBlVLG6234>6Lm*o3d zDys6b3{7_k>F_{Bpnr<0oJ*do2K@K>>{-`dVOV7ii>FLR-7&-d5p1fh;x${qK8Kr3 z#*lRr{a2A6SpSKu z_IOLUr;bN2n@oaBH%QI3udwTN2bmYIoi4m%*gd^V=y%IuERl2Jl$KAdpJwMWvbxn$ z^_(TP*B5e{by>y#-KQ>3vLJ=gZ7Y}0-;y$lj{WRC3de{So`MY-@;pJaIITkt@-^va z4#ALW-te9s*>Rf@bF9v*OuK!Rzl3^4b?TiD$1*dyipm^mVXzxA*3(sM U4O%ZAz`*CCp_#$E^UksV3!BR7Bme*a diff --git a/icons/mob/human_races/xenos/r_xenos_drone.dmi b/icons/mob/human_races/xenos/r_xenos_drone.dmi new file mode 100644 index 0000000000000000000000000000000000000000..19094d66ed9c1c3e3359308d3431e2ca4c92d6ba GIT binary patch literal 1764 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 X$Z|RiOe$Bd{}GFwwX;Em2w0dKUjYEn5d{I< z;3M!OJ2@Ny(%#y^q_eY=n@3#ZqAfxUX@$$cVzKM%>kI}1&MO81^N7nR9t{9kWa)by z2?>ez_I3j)0KAfa>xWp#6I*4Z{O4$pBH7$TDgX$VO!dge&C}K$-N{? zX}RE~{&()%m5}8jal;k|OY1WQk`i8d4;wyMN2SdOdx=c?HvG=$qMmsO$iYJrs`jy* z(%kLclhLUmXS_L{K3BUWYf@MbBokG!3b--FG5O{E>k}@`X03;DE~9pH-w!WZtu>Mu zuA@g6;xe@`HgX6rq!*<|&dBharU&WQ4%3-zJAHY59}hValqdLGv8&5-`QE+&`5q0T zgj(&vy~f!&#mll2n>B&voM+$25J8p$$p zBU8i}tPSH@O8C0-&+?z!)f>>GNPnsD=mwzz`n#DVhYfB=JPUD+{cO}fZlG(yq^xI^ z5aXOv^m05r%m&X&g=}4IfR!#dKOY^wwdbJ_*g$p7)!*pYh>K_I^EEJaHz^9|bwWEd znoZg?S<88TTSU9a9czT1;R8)ldo2n;}u6>4?6DdDJXDvA;*T5}mgJ#eTF+xvBR;Pw0 zZMR|6+;q+>!N{-Jp0VMcA_+RVm}W>Fs7cD6f3^CM3aJI9k}5&M7e-tNMlcm`F8k8* zoN_b18-3j2WVWBEqK_}GgaL0BD>;3plIzIXF;i7Xoxmnf z0oSdAQ}udng^H{1=?-zmZVkGOh<6KRE_ZY@P3MYHA zwKd%QzRnd3ajmtJ0JIZyIuwP!PBywI*SpJ0&oDsmg^=gH;>k3zsrZ{wYBiE$G+bjE zd>ppEHIUmVYCH3mTeA&KM;_CT$0cCyNSRC4xt_;WC7k@fxu5KDtl08Xe*+cT`Fixw z_P?Vbh%;h)kE3wNHwFyVla+CXDMpm^t;t~s2dkTyo`{xg+lJ4!SJhf99 z#5=wdg3+9t4T+kGxxr_96wB5Yo@5e#;|GF-5VarAdeiN;;CIrt1WS}E$lVd(?W#ah zTE+;%8tJ;JK!O19T*0tbyp8(v?g z5r&#nS2(AU-tQLixKp#YH(rkEDBh1p0|0pF%Qc(5*9L@D4y~1<0>dTsY6I%XaSaT_ zq_cJ6g%xf-ah=4m|5A-Iuw@s5iiW;9HuS1vl#%CI*ae0?h~a=bY;Ow;l`LFJ8+T_G zx3CtzcZ4Xn7n6Fg=D_Y|T88>)a#SksVx_iCsXE=Qe8D20%A2kSG_p3pxGmjqe*!Zo zjFO`9nK+9s(RX*|kk(I>>Oa_#o`Qu>xGf#>2q^GC}1xGnzpbU%lSFs#bp}qWV^e;5b_qSyRhX{vG8Hw$?|z-aT=k zRNt83A_ep{u%hHt&K(ZWbPE#O>a<>IvTsN+_?n+9oOJqQ>gJEYEKF>TYtZho{{b*I BaL@n% literal 0 HcmV?d00001 diff --git a/icons/mob/human_races/xenos/r_xenos_sentinel.dmi b/icons/mob/human_races/xenos/r_xenos_sentinel.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5b250c7445e05ca6425a89bb5b9ebe3b514d6cb6 GIT binary patch literal 1817 zcmYjRc|6mP8~@D02piVdF~?BJt7wkO^$l|_<;$$-a6}BX93hI|Hpe$9M~+ZTj?m55 zT=lgrOoXU8_G@K2DEBdDYs-GTepl~*-tXslJLFH5TjP4cJeyLpP1aD>&a+r;tm*G2v0M z;gJ^sAfYrX&qlrz1#>z-4ewZR{0HGqVDOnPADC3~^||!Iyj+fJ_6z%=c=ILxvBoE@ z{7%d33kO$fU%~^G)uPAet*%O!B^%Wm;K#RpDjG(7|W>3)op11_O-zD&`ZgHrgjs(J$5C*3TO1mJDLHL`YD zv7dw_lz)73x#!k7VHIfaYZTxqojFVpCW!8+_)?s8K^7Uh zZ1LBlZz-y)uFx{%g$s60>_z2w@SUa%CbfCdSfDHz&*~Yh*ERldoE|6Iyw$IulkTdP z41ltBFOJhhF;hocuJvS!6Kofn1Z#Pte6{UrWz+`ZmzUieeY3NN)v{lWjTLbqRH}rD z?x5-0(e{}PRde_em5IT8#}7VD8|Ed9OUuYfuIY1omPLe|{1*!^i^u`mtE}bVqlR8X zGY<9TsLy^G)7yhGU2^|)!SDv=q4{^8N^1A7%WFmdmJL^la?wlQb<@-BOU3FH0)ZH% zRy^y+E))ARdpp@_eTlM_!_hj;&AMtCswZyISHF5B-8mj>j{vc90X{tXh>)gzhM2s_>Udw_G@M?YrC zZ)p#Q6OG%pW!|R|or`qjjdJFGatkm!GX9txS)Hy(Gvu3rCyMjmeSP6@g`5~I&0_B| z7)k{A0t!V6Vm}B98+bZl>ON$2u6@JW0Z4)A_Lr?GPiZZ$51T)aIc`!=ko5%b}Fs{;k3 zeH8d~8i^NFZ+x2x!|;H#U3=y_o`ZjwlvY&fot3NEd&Fb%1}ebSCPO8z^l8ez9b$OT z*w&N%A0}$^eI_Pk>6Kj}GNfbqNd0AFkDWT22MkL!A7t$g;>nIy#pwa>N(w=Ly;;CK zK3IuUwxTBwHp<>gj31nW)}ck_$XWKy0bS4ZQM~>5a*JheQ;==9!H_jj&;(&-HP8B4 z^5!U8@hQW=sZZ_fqwx2X&GsmTMv0F;vHaWRlVttKe({0?6T?N%Ftjuw@>BP-{F2tk znUHgW{fZ5hFMdA^OoF@4qqveIy!^4Zj@uRt1U;Q&bOG|#sBG&Z7-tWsr|7_xe*vvfOcekC literal 0 HcmV?d00001 diff --git a/icons/mob/monkey.dmi b/icons/mob/monkey.dmi index b00b4a08fa00b39d94177b620f8db13474ab34a4..b9c1299ec25e4bf010618605cdf6d8dbd326bcc8 100644 GIT binary patch delta 1721 zcmV;q21fahuK}K<0gxnrW_naubVOxyV{&P5bZKvH004NLrPRG{!Y~jA@Hu&k6Rc1* zl%Y$O3RE$`E1<)^*d~r0`GXLizC#BJYGg~uQ>35$m+vl~!`JqEcYw`)S6;|@WewD@ zetR#ALGd7=hL2TQNK!(E-wz)!5Y#a1tZ8YiW@W*Z^H9UOEE=ui>+;xh=+tTPcGHx>gwW)xG;}`OIt-Fb+6nYW)FD|wrtM&os#6^$ zksoj(Z&enYG>%ZiYVl`qm=bm({PVu0T0E@B?M;)uq7vv{%t4ovWCxutC2_?t?HXhx zqY&hhy}r{UC*(<5YCL$v0fKyGv%9_U?hMjYw z`(ozi@uM93|5yhR5uH7O12}7%-c+jf@+bmGjz4{^{ykJuq`{XpO>b>E*-(S5iHL~Ek3grObB?2BP18#!fk)@-%lpbez8L;BP&s~I zxrlW7+1rOs3Eh0Yi0>je21G>E9Zod~D_;cC$;S6l$`|W{%CVyizMSJ|V@DmgJPuJG z10o_i+X4l!ZQI@-Z@-7@?%%$N$q^5iXXjB~-Np^i!^JCCeT3W8cYkhcVSar6{cn+vsru=c zKRaFn5fPnDzB*vp{bn*50D!x<1pu}1mG3i|OlV!OtU-#u{tf`(gU>#0_fWpcv1Kg) zLO%;YL`2=ecL%(_f4*LO{cwK=uCngo{!Yv7+D-lJo!@^&|3JLR9r%ySG){ z|B-O_ors9Ki{?1aGdGgA9?4sc?q-kQbNgDZev48VwY7H-c^EWD$N`2)8 zKnT(HF;B9o>(F%_U+vbH#bPo1wLAzQoc$*vqV5vtNmvUhm9pmTj z;MPBH*1FGzf9({_!Pvas&o=V2ca=w8Rw@<5Vle>K@N4zC?I!C0^jZzlZu#Uo{2T)! zBI+H!JK)h7N3$%;ligmaR005upSy!ggC!V-0n4&Z4ByciN0aNC!^qDzKsDe1z;#^+ zAy6un;JPjfg@P7kppDKrTA@(TT-QaZRDuu!uIo0`f2i`ie?&yoI|6?h1AtoSrE-pz z$~oHNrjAR4C486=Sjn263>P(c{07d3(m~6=S;?B-%F)EH#Z4WCVZe3W+V4(LYcLE0 zi<{N1SgrRo$AE~4x?i9GP6&Zd-Y6l_G~p>B1YSB1tQLV(t}#5-&a~As^}QNU&C6ui ztA8iMf7i0C$b(Ie+58WHT4#`BKtx2n#n){}Ks7j~C#tiYjzhM9q5fOC&1DJ@2r~??lL_|a#BftPAA|mPl1~3s3Q3w1Bcdg;p(qwro P00000NkvXXu0mjf@ab9< delta 3120 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 Sx0L|sOGQy#q4=rEhyMovr1Wh7 delta 16780 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 UBXxn#AmHb*hK_o Date: Tue, 30 Sep 2014 10:43:16 +0930 Subject: [PATCH 05/16] Added Binary to posibrains. --- code/modules/mob/living/carbon/brain/posibrain.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index f17bfa5d736..437f883ec31 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -128,6 +128,7 @@ /obj/item/device/mmi/posibrain/New() src.brainmob = new(src) + src.brainmob.add_language("Binary") src.brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[rand(100, 999)]" src.brainmob.real_name = src.brainmob.name src.brainmob.loc = src From 0a0e94e12e30487f69504eb0e1b8dd21f352d3e7 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 10:44:56 +0930 Subject: [PATCH 06/16] Moved human brainloss to the brain organ. --- .../mob/living/carbon/human/human_damage.dm | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 602c00edf62..1fad51fcd90 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -22,21 +22,45 @@ ChangeToHusk() return -/mob/living/carbon/human/getBrainLoss() - var/res = brainloss +/mob/living/carbon/human/adjustBrainLoss(var/amount) + + if(status_flags & GODMODE) return 0 //godmode + if(species && species.has_organ["brain"]) var/datum/organ/internal/brain/sponge = internal_organs_by_name["brain"] - if(!sponge) - res += 200 + if(sponge) + sponge.take_damage(amount) + sponge.damage = min(max(brainloss, 0),(maxHealth*2)) + brainloss = sponge.damage else - if (sponge.is_bruised()) - res += 20 - if (sponge.is_broken()) - res += 50 + brainloss = 200 + else + brainloss = 0 - res = min(res,maxHealth*2) - return res - return 0 +/mob/living/carbon/human/setBrainLoss(var/amount) + + if(status_flags & GODMODE) return 0 //godmode + + if(species && species.has_organ["brain"]) + var/datum/organ/internal/brain/sponge = internal_organs_by_name["brain"] + if(sponge) + sponge.damage = min(max(amount, 0),(maxHealth*2)) + brainloss = sponge.damage + else + brainloss = 200 + else + brainloss = 0 + +/mob/living/carbon/human/getBrainLoss() + + if(status_flags & GODMODE) return 0 //godmode + + if(species && species.has_organ["brain"]) + var/datum/organ/internal/brain/sponge = internal_organs_by_name["brain"] + brainloss = min(sponge.damage,maxHealth*2) + else + brainloss = 0 + return brainloss //These procs fetch a cumulative total damage from all organs /mob/living/carbon/human/getBruteLoss() From 051a6ff18b67140d4dbc648af5de719066700517 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 10:48:18 +0930 Subject: [PATCH 07/16] Fixed a message issue with turrets. --- code/game/machinery/turrets.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm index d3e9b81e157..af5b67c16dd 100644 --- a/code/game/machinery/turrets.dm +++ b/code/game/machinery/turrets.dm @@ -84,7 +84,7 @@ if(user.species.can_shred(user) && !(stat & BROKEN)) playsound(src.loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("\red [] has slashed at []!", user, src) + visible_message("\red [user] has slashed at [src]!") src.take_damage(15) return From c0c4b99b34db8636450e10e1eb7efdc6f39f970a Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 10:48:45 +0930 Subject: [PATCH 08/16] Some prep work/support work for the alien resting icons. --- code/modules/mob/living/carbon/human/alien/alien_species.dm | 3 +++ code/modules/mob/living/carbon/human/species.dm | 3 +++ code/modules/mob/living/carbon/human/update_icons.dm | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/alien/alien_species.dm b/code/modules/mob/living/carbon/human/alien/alien_species.dm index 185a3b60c75..a29ce75087a 100644 --- a/code/modules/mob/living/carbon/human/alien/alien_species.dm +++ b/code/modules/mob/living/carbon/human/alien/alien_species.dm @@ -6,6 +6,9 @@ unarmed_type = /datum/unarmed_attack/claws/strong secondary_unarmed_type = /datum/unarmed_attack/bite/strong hud_type = /datum/hud_data/alien + + has_fine_manipulation = 0 + insulated = 1 gluttonous = 2 eyes = "blank_eyes" diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index d2727d94d33..fdbcd422ad7 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -3,9 +3,12 @@ */ /datum/species + var/name // Species name. + var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. + var/prone_icon // If set, draws this from icobase when mob is prone. var/eyes = "eyes_s" // Icon for eyes. var/primitive // Lesser form, if any (ie. monkey for humans) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index ad609cad732..a49760a5279 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -161,7 +161,7 @@ Please contact me on #coderbus IRC. ~Carn x for(var/image/I in overlays_standing) overlays += I - if(lying) + if(lying && !species.prone_icon) //Only rotate them if we're not drawing a specific icon for being prone. var/matrix/M = matrix() M.Turn(90) M.Scale(size_multiplier) From 74eae5a6bd221ba0358808386a9758506540268a Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 11:58:40 +0930 Subject: [PATCH 09/16] Moved radiation and light processing to organs. --- .../carbon/human/alien/alien_species.dm | 71 ++++++++++--------- .../mob/living/carbon/human/human_damage.dm | 2 +- code/modules/mob/living/carbon/human/life.dm | 8 ++- .../mob/living/carbon/human/species.dm | 2 +- code/modules/organs/organ.dm | 13 ---- code/modules/organs/organ_alien.dm | 35 ++++++--- code/modules/organs/organ_internal.dm | 64 ++++++++++++----- code/modules/reagents/Chemistry-Reagents.dm | 21 +++--- code/setup.dm | 7 +- 9 files changed, 134 insertions(+), 89 deletions(-) diff --git a/code/modules/mob/living/carbon/human/alien/alien_species.dm b/code/modules/mob/living/carbon/human/alien/alien_species.dm index a29ce75087a..c7a73828553 100644 --- a/code/modules/mob/living/carbon/human/alien/alien_species.dm +++ b/code/modules/mob/living/carbon/human/alien/alien_species.dm @@ -1,4 +1,3 @@ -//TODO: Generalize some kind of power pool so that other races can use it. //Stand-in until this is made more lore-friendly. /datum/species/xenos name = "Xenomorph" @@ -23,7 +22,7 @@ cold_level_2 = -1 cold_level_3 = -1 - flags = IS_WHITELISTED | NO_BREATHE | NO_SCAN | NO_PAIN | RAD_ABSORB | NO_SLIP | NO_POISON + flags = IS_WHITELISTED | NO_BREATHE | NO_SCAN | NO_PAIN | NO_SLIP | NO_POISON reagent_tag = IS_XENOS @@ -38,11 +37,12 @@ poison_type = null has_organ = list( - "heart" = /datum/organ/internal/heart, - "lungs" = /datum/organ/internal/lungs, - "brain" = /datum/organ/internal/brain, - "plasma vessel" = /datum/organ/internal/xenos/plasmavessel, - "hive node" = /datum/organ/internal/xenos/hivenode + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel, + "hive node" = /datum/organ/internal/xenos/hivenode, + "nutrient vessel" = /datum/organ/internal/diona/nutrients ) var/alien_number = 0 @@ -54,7 +54,6 @@ H.visible_message("[H] caresses [target] with its scythe-like arm.", \ "You caress [target] with your scythe-like arm.") - /datum/species/xenos/handle_post_spawn(var/mob/living/carbon/human/H) if(H.mind) @@ -103,13 +102,14 @@ deform = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' has_organ = list( - "heart" = /datum/organ/internal/heart, - "lungs" = /datum/organ/internal/lungs, - "brain" = /datum/organ/internal/brain, - "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/queen, - "acid gland" = /datum/organ/internal/xenos/acidgland, - "hive node" = /datum/organ/internal/xenos/hivenode, - "resin spinner" = /datum/organ/internal/xenos/resinspinner + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/queen, + "acid gland" = /datum/organ/internal/xenos/acidgland, + "hive node" = /datum/organ/internal/xenos/hivenode, + "resin spinner" = /datum/organ/internal/xenos/resinspinner, + "nutrient vessel" = /datum/organ/internal/diona/nutrients ) inherent_verbs = list( @@ -141,11 +141,12 @@ deform = 'icons/mob/human_races/xenos/r_xenos_hunter.dmi' has_organ = list( - "heart" = /datum/organ/internal/heart, - "lungs" = /datum/organ/internal/lungs, - "brain" = /datum/organ/internal/brain, - "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/hunter, - "hive node" = /datum/organ/internal/xenos/hivenode + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/hunter, + "hive node" = /datum/organ/internal/xenos/hivenode, + "nutrient vessel" = /datum/organ/internal/diona/nutrients ) inherent_verbs = list( @@ -168,12 +169,13 @@ deform = 'icons/mob/human_races/xenos/r_xenos_sentinel.dmi' has_organ = list( - "heart" = /datum/organ/internal/heart, - "lungs" = /datum/organ/internal/lungs, - "brain" = /datum/organ/internal/brain, - "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/sentinel, - "acid gland" = /datum/organ/internal/xenos/acidgland, - "hive node" = /datum/organ/internal/xenos/hivenode + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/sentinel, + "acid gland" = /datum/organ/internal/xenos/acidgland, + "hive node" = /datum/organ/internal/xenos/hivenode, + "nutrient vessel" = /datum/organ/internal/diona/nutrients ) inherent_verbs = list( @@ -197,14 +199,15 @@ deform = 'icons/mob/human_races/xenos/r_xenos_queen.dmi' has_organ = list( - "heart" = /datum/organ/internal/heart, - "lungs" = /datum/organ/internal/lungs, - "brain" = /datum/organ/internal/brain, - "egg sac" = /datum/organ/internal/xenos/eggsac, - "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/queen, - "acid gland" = /datum/organ/internal/xenos/acidgland, - "hive node" = /datum/organ/internal/xenos/hivenode, - "resin spinner" = /datum/organ/internal/xenos/resinspinner + "heart" = /datum/organ/internal/heart, + "lungs" = /datum/organ/internal/lungs, + "brain" = /datum/organ/internal/brain, + "egg sac" = /datum/organ/internal/xenos/eggsac, + "plasma vessel" = /datum/organ/internal/xenos/plasmavessel/queen, + "acid gland" = /datum/organ/internal/xenos/acidgland, + "hive node" = /datum/organ/internal/xenos/hivenode, + "resin spinner" = /datum/organ/internal/xenos/resinspinner, + "nutrient vessel" = /datum/organ/internal/diona/nutrients ) inherent_verbs = list( diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 1fad51fcd90..b115ffe94cd 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -13,7 +13,7 @@ var/oxy_l = (species.flags & NO_BREATHE ? 0 : getOxyLoss()) var/tox_l = (species.flags & NO_POISON ? 0 : getToxLoss()) - var/clone_l = getCloneLoss() //TODO: link this to RAD_ABSORB or NO_SCAN + var/clone_l = getCloneLoss() //TODO: link this to NO_SCAN health = species.total_health - oxy_l - tox_l - clone_l - total_burn - total_brute diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index c4dec0abe89..e15a622950e 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -282,7 +282,8 @@ radiation = Clamp(radiation,0,100) if (radiation) - if(species.flags & RAD_ABSORB) + var/datum/organ/internal/diona/nutrients/rad_organ = locate() in internal_organs + if(!rad_organ || rad_organ.is_broken()) var/rads = radiation/25 radiation -= rads nutrition += rads @@ -984,7 +985,8 @@ if(status_flags & GODMODE) return 0 //godmode - if(species.flags & REQUIRE_LIGHT) + var/datum/organ/internal/diona/node/light_organ = locate() in internal_organs + if(light_organ && !light_organ.is_broken()) 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 @@ -1047,7 +1049,7 @@ if(overeatduration > 1) overeatduration -= 2 //doubled the unfat rate - if(species.flags & REQUIRE_LIGHT) + if(!light_organ || light_organ.is_broken()) if(nutrition < 200) take_overall_damage(2,0) traumatic_shock++ diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index fdbcd422ad7..76a98e5c823 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -384,7 +384,7 @@ body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not - flags = IS_WHITELISTED | NO_BREATHE | REQUIRE_LIGHT | NO_SCAN | IS_PLANT | RAD_ABSORB | NO_BLOOD | NO_PAIN | NO_SLIP + flags = IS_WHITELISTED | NO_BREATHE | NO_SCAN | IS_PLANT | NO_BLOOD | NO_PAIN | NO_SLIP blood_color = "#004400" flesh_color = "#907E4A" diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 12b180fd546..a69ee36c7d6 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -75,19 +75,6 @@ for(var/datum/organ/internal/I in internal_organs) I.process() - // Also handles some internal organ processing when the organs are missing completely. - // Only handles missing liver and kidneys for now. - // This is a bit harsh, but really if you're missing an entire bodily organ you're in deep shit. - if(species.has_organ["liver"]) - var/datum/organ/internal/liver = internal_organs_by_name["liver"] - if(!liver || liver.status & ORGAN_CUT_AWAY) - reagents.add_reagent("toxin", rand(1,3)) - - if(species.has_organ["kidneys"]) - var/datum/organ/internal/kidney = internal_organs_by_name["kidneys"] - if(!kidney || kidney.status & ORGAN_CUT_AWAY) - reagents.add_reagent("toxin", rand(1,3)) - if(!force_process && !bad_external_organs.len) return diff --git a/code/modules/organs/organ_alien.dm b/code/modules/organs/organ_alien.dm index 5d1d4874235..e04287bc3f3 100644 --- a/code/modules/organs/organ_alien.dm +++ b/code/modules/organs/organ_alien.dm @@ -5,18 +5,10 @@ /datum/organ/internal/diona/process() return -/datum/organ/internal/diona/nutrients - name = "nutrient vessel" - parent_organ = "chest" - /datum/organ/internal/diona/strata name = "neural strata" parent_organ = "chest" -/datum/organ/internal/diona/node - name = "receptor node" - parent_organ = "head" - /datum/organ/internal/diona/bladder name = "gas bladder" parent_organ = "head" @@ -29,10 +21,21 @@ name = "anchoring ligament" parent_organ = "groin" +/datum/organ/internal/diona/node + name = "receptor node" + parent_organ = "head" + removed_type = /obj/item/organ/diona/node + +/datum/organ/internal/diona/nutrients + name = "nutrient vessel" + parent_organ = "chest" + removed_type = /obj/item/organ/diona/nutrients + /obj/item/organ/diona name = "diona nymph" icon = 'icons/obj/objects.dmi' icon_state = "nymph" + organ_tag = "special" // Turns into a nymph instantly, no transplanting possible. /obj/item/organ/diona/removed(var/mob/living/target,var/mob/living/user) @@ -53,6 +56,22 @@ del(src) +//These are different to the standard diona organs as they have a purpose in other +// species (absorbing radiation and light respectively) +/obj/item/organ/diona/nutrients + name = "nutrient vessel" + organ_tag = "nutrient vessel" + +/obj/item/organ/diona/nutrients/removed() + return + +/obj/item/organ/diona/node + name = "receptor node" + organ_tag = "receptor node" + +/obj/item/organ/diona/node/removed() + return + //CORTICAL BORER ORGANS. /datum/organ/internal/borer name = "cortical borer" diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index 9c26f814e95..3a84eb3a11c 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -1,3 +1,5 @@ +#define PROCESS_ACCURACY 10 + /**************************************************** INTERNAL ORGANS ****************************************************/ @@ -21,7 +23,7 @@ return damage >= min_bruised_damage /datum/organ/internal/proc/is_broken() - return damage >= min_broken_damage + return damage >= min_broken_damage || status & ORGAN_CUT_AWAY /datum/organ/internal/New(mob/living/carbon/human/H) ..() @@ -163,11 +165,12 @@ /datum/organ/internal/liver name = "liver" parent_organ = "chest" - var/process_accuracy = 10 removed_type = /obj/item/organ/liver process() + ..() + if (germ_level > INFECTION_LEVEL_ONE) if(prob(1)) owner << "\red Your skin itches." @@ -175,40 +178,67 @@ if(prob(1)) spawn owner.vomit() - if(owner.life_tick % process_accuracy == 0) - if(src.damage < 0) - src.damage = 0 + if(owner.life_tick % PROCESS_ACCURACY == 0) //High toxins levels are dangerous if(owner.getToxLoss() >= 60 && !owner.reagents.has_reagent("anti_toxin")) //Healthy liver suffers on its own if (src.damage < min_broken_damage) - src.damage += 0.2 * process_accuracy + src.damage += 0.2 * PROCESS_ACCURACY //Damaged one shares the fun else var/datum/organ/internal/O = pick(owner.internal_organs) if(O) - O.damage += 0.2 * process_accuracy + O.damage += 0.2 * PROCESS_ACCURACY //Detox can heal small amounts of damage if (src.damage && src.damage < src.min_bruised_damage && owner.reagents.has_reagent("anti_toxin")) - src.damage -= 0.2 * process_accuracy + src.damage -= 0.2 * PROCESS_ACCURACY - // Damaged liver means some chemicals are very dangerous - if(src.damage >= src.min_bruised_damage) - for(var/datum/reagent/R in owner.reagents.reagent_list) - // Ethanol and all drinks are bad - if(istype(R, /datum/reagent/ethanol)) - owner.adjustToxLoss(0.1 * process_accuracy) - // Can't cope with toxins at all - if(istype(R, /datum/reagent/toxin)) - owner.adjustToxLoss(0.3 * process_accuracy) + if(src.damage < 0) + src.damage = 0 + + // Get the effectiveness of the liver. + var/filter_effect = 3 + if(is_bruised()) + filter_effect -= 1 + if(is_broken()) + filter_effect -= 2 + + // Do some reagent filtering/processing. + for(var/datum/reagent/R in owner.reagents.reagent_list) + // Damaged liver means some chemicals are very dangerous + // The liver is also responsible for clearing out alcohol and toxins. + // Ethanol and all drinks are bad.K + if(istype(R, /datum/reagent/ethanol)) + if(filter_effect < 3) + owner.adjustToxLoss(0.1 * PROCESS_ACCURACY) + owner.reagents.remove_reagent(R.id, R.custom_metabolism*filter_effect) + // Can't cope with toxins at all + else if(istype(R, /datum/reagent/toxin)) + if(filter_effect < 3) + owner.adjustToxLoss(0.3 * PROCESS_ACCURACY) + owner.reagents.remove_reagent(R.id, ALCOHOL_METABOLISM*filter_effect) /datum/organ/internal/kidney name = "kidneys" parent_organ = "groin" removed_type = /obj/item/organ/kidneys + process() + + ..() + + // Coffee is really bad for you with busted kidneys. + // This should probably be expanded in some way, but fucked if I know + // what else kidneys can process in our reagent list. + var/datum/reagent/coffee = locate(/datum/reagent/drink/coffee) in owner.reagents.reagent_list + if(coffee) + if(is_bruised()) + owner.adjustToxLoss(0.1 * PROCESS_ACCURACY) + else if(is_broken()) + owner.adjustToxLoss(0.3 * PROCESS_ACCURACY) + /datum/organ/internal/brain name = "brain" parent_organ = "head" diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index 13962c71346..fbf206fbc65 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -1,7 +1,6 @@ #define SOLID 1 #define LIQUID 2 #define GAS 3 -#define FOOD_METABOLISM 0.4 #define REAGENTS_OVERDOSE 30 #define REM REAGENTS_EFFECT_MULTIPLIER @@ -653,13 +652,17 @@ datum for (var/ID in C.virus2) var/datum/disease2/disease/V = C.virus2[ID] if(prob(5)) + M:antibodies |= V.antigen if(prob(50)) M.radiation += 50 // curing it that way may kill you instead - var/mob/living/carbon/human/H - if(istype(C,/mob/living/carbon/human)) - H = C - if(!H || (H.species && !(H.species.flags & RAD_ABSORB))) M.adjustToxLoss(100) - M:antibodies |= V.antigen + var/absorbed + if(istype(C,/mob/living/carbon)) + var/mob/living/carbon/H = C + var/datum/organ/internal/diona/nutrients/rad_organ = locate() in H.internal_organs + if(rad_organ && !rad_organ.is_broken()) + absorbed = 1 + if(!absorbed) + M.adjustToxLoss(100) ..() return @@ -1493,11 +1496,11 @@ datum var/toxpwr = 0.7 // Toxins are really weak, but without being treated, last very long. custom_metabolism = 0.1 - on_mob_life(var/mob/living/M as mob) + on_mob_life(var/mob/living/M as mob,var/alien) if(!M) M = holder.my_atom if(toxpwr) M.adjustToxLoss(toxpwr*REM) - ..() + if(alien) ..() //Kind of a catch-all for aliens without kidneys. return toxin/amatoxin @@ -2972,7 +2975,7 @@ datum on_mob_life(var/mob/living/M as mob, var/alien) M:nutrition += nutriment_factor - holder.remove_reagent(src.id, FOOD_METABOLISM) + holder.remove_reagent(src.id, (alien ? FOOD_METABOLISM : ALCOHOL_METABOLISM)) // Catch-all for creatures without livers. if (adj_drowsy) M.drowsyness = max(0,M.drowsyness + adj_drowsy) if (adj_sleepy) M.sleeping = max(0,M.sleeping + adj_sleepy) diff --git a/code/setup.dm b/code/setup.dm index fd44b399ca5..f0530653527 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -754,9 +754,6 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse #define IS_WHITELISTED 4096 #define IS_SYNTHETIC 8192 -#define RAD_ABSORB 16384 -#define REQUIRE_LIGHT 32768 - //Language flags. #define WHITELISTED 1 // Language is available if the speaker is whitelisted. #define RESTRICTED 2 // Language can only be accquired by spawning or an admin. @@ -854,3 +851,7 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse #define ATMOS_DEFAULT_VOLUME_PIPE 70 //L var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF") + +// Reagent metabolism defines. +#define FOOD_METABOLISM 0.4 +#define ALCOHOL_METABOLISM 0.1 From 161d21f8d0b3b75693e91dc192e0abd7eb111adb Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 12:03:19 +0930 Subject: [PATCH 10/16] Added cuff-breaking checks for can_shred(). --- code/modules/mob/living/living.dm | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 8fc440c9217..5c5805bfaf3 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -610,7 +610,16 @@ if(CM.handcuffed && CM.canmove && (CM.last_special <= world.time)) CM.next_move = world.time + 100 CM.last_special = world.time + 100 - if(HULK in usr.mutations) //Don't want to do a lot of logic gating here. + + var/can_break_cuffs + if(HULK in usr.mutations) + can_break_cuffs = 1 + else if(istype(CM,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = CM + if(H.species.can_shred(H)) + can_break_cuffs = 1 + + if(can_break_cuffs) //Don't want to do a lot of logic gating here. usr << "\red You attempt to break your handcuffs. (This will take around 5 seconds and you need to stand still)" for(var/mob/O in viewers(CM)) O.show_message(text("\red [] is trying to break the handcuffs!", CM), 1) @@ -647,7 +656,16 @@ else if(CM.legcuffed && CM.canmove && (CM.last_special <= world.time)) CM.next_move = world.time + 100 CM.last_special = world.time + 100 - if(HULK in usr.mutations) //Don't want to do a lot of logic gating here. + + var/can_break_cuffs + if(HULK in usr.mutations) + can_break_cuffs = 1 + else if(istype(CM,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = CM + if(H.species.can_shred(H)) + can_break_cuffs = 1 + + if(can_break_cuffs) //Don't want to do a lot of logic gating here. usr << "\red You attempt to break your legcuffs. (This will take around 5 seconds and you need to stand still)" for(var/mob/O in viewers(CM)) O.show_message(text("\red [] is trying to break the legcuffs!", CM), 1) From a0d23b38001444f678566da2847a0ca5a98958e5 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 12:17:33 +0930 Subject: [PATCH 11/16] Reimplements ninja and cult species rarity bonuses. --- code/game/gamemodes/cult/runes.dm | 16 ++++++++++++---- code/game/gamemodes/objective.dm | 12 +++++++++--- .../living/carbon/human/alien/alien_species.dm | 3 +++ code/modules/mob/living/carbon/human/species.dm | 8 ++++++-- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 83ca646d894..67785f85855 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -581,7 +581,15 @@ var/list/sacrificed = list() if(iscultist(C) && !C.stat) cultsinrange += C C.say("Barhah hra zar[pick("'","`")]garis!") + for(var/mob/H in victims) + + var/worth = 0 + if(istype(H,/mob/living/carbon/human)) + var/mob/living/carbon/human/lamb = H + if(lamb.species.rarity_value > 3) + worth = 1 + if (ticker.mode.name == "cult") if(H.mind == ticker.mode:sacrifice_target) if(cultsinrange.len >= 3) @@ -596,8 +604,8 @@ var/list/sacrificed = list() else if(cultsinrange.len >= 3) if(H.stat !=2) - if(prob(80)) - usr << "\red The Geometer of Blood accepts this sacrifice." + if(prob(80) || worth) + usr << "\red The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice." ticker.mode:grant_runeword(usr) else usr << "\red The Geometer of blood accepts this sacrifice." @@ -607,8 +615,8 @@ var/list/sacrificed = list() else H.gib() else - if(prob(40)) - usr << "\red The Geometer of blood accepts this sacrifice." + if(prob(40) || worth) + usr << "\red The Geometer of blood accepts this [worth ? "exotic " : ""]sacrifice." ticker.mode:grant_runeword(usr) else usr << "\red The Geometer of blood accepts this sacrifice." diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index d01e0e3506f..e2cc152c8eb 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -637,18 +637,24 @@ datum/objective/capture check_completion()//Basically runs through all the mobs in the area to determine how much they are worth. var/captured_amount = 0 var/area/centcom/holding/A = locate() - for(var/mob/living/carbon/human/M in A)//Humans. + + for(var/mob/living/carbon/human/M in A) // Humans (and subtypes). + var/worth = M.species.rarity_value if(M.stat==2)//Dead folks are worth less. - captured_amount+=0.5 + worth*=0.5 continue - captured_amount+=1 + captured_amount += worth + for(var/mob/living/carbon/monkey/M in A)//Monkeys are almost worthless, you failure. captured_amount+=0.1 + for(var/mob/living/carbon/alien/larva/M in A)//Larva are important for research. if(M.stat==2) captured_amount+=0.5 continue captured_amount+=1 + + if(captured_amount Date: Tue, 30 Sep 2014 13:23:28 +0930 Subject: [PATCH 12/16] Added Add and Remove Organ options to VV. --- code/datums/datumvars.dm | 74 +++++++++++++++++++++++++-- code/modules/organs/organ_internal.dm | 20 +++++--- 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 4777f061d60..1e6d9790eb2 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -259,6 +259,8 @@ client body += "" body += "" body += "" + body += "" + body += "" body += "" @@ -875,6 +877,74 @@ client else H.verbs -= verb + else if(href_list["addorgan"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/M = locate(href_list["addorgan"]) + if(!istype(M)) + usr << "This can only be done to instances of type /mob/living/carbon" + return + + var/new_organ = input("Please choose an organ to add.","Organ",null) as null|anything in typesof(/datum/organ/internal)-/datum/organ/internal + + if(!M) + usr << "Mob doesn't exist anymore" + return + + if(locate(new_organ) in M.internal_organs) + usr << "Mob already has that organ." + return + + if(istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/datum/organ/internal/I = new new_organ(H) + + var/organ_slot = input(usr, "Which slot do you want the organ to go in ('default' for default)?") as text|null + + if(!organ_slot) + return + + if(organ_slot != "default") + organ_slot = sanitize(copytext(organ_slot,1,MAX_MESSAGE_LEN)) + else + if(I.removed_type) + var/obj/item/organ/O = new I.removed_type() + organ_slot = O.organ_tag + del(O) + else + organ_slot = "unknown organ" + + if(H.internal_organs_by_name[organ_slot]) + usr << "[H] already has an organ in that slot." + del(I) + return + + H.internal_organs_by_name[organ_slot] = I + usr << "Added new [new_organ] to [H] as slot [organ_slot]." + else + new new_organ(M) + usr << "Added new [new_organ] to [M]." + + else if(href_list["remorgan"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/M = locate(href_list["remorgan"]) + if(!istype(M)) + usr << "This can only be done to instances of type /mob/living/carbon" + return + + var/rem_organ = input("Please choose an organ to remove.","Organ",null) as null|anything in M.internal_organs + + if(!M) + usr << "Mob doesn't exist anymore" + return + + if(!(locate(rem_organ) in M.internal_organs)) + usr << "Mob does not have that organ." + return + + usr << "Removed [rem_organ] from [M]." + del(rem_organ) else if(href_list["fix_nano"]) if(!check_rights(R_DEBUG)) return @@ -885,8 +955,6 @@ client usr << "This can only be done on mobs with clients" return - - nanomanager.send_resources(H.client) usr << "Resource files sent" @@ -894,8 +962,6 @@ client log_admin("[key_name(usr)] resent the NanoUI resource files to [key_name(H)] ") - - else if(href_list["regenerateicons"]) if(!check_rights(0)) return diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index 3a84eb3a11c..c2df9a30f0f 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -25,15 +25,19 @@ /datum/organ/internal/proc/is_broken() return damage >= min_broken_damage || status & ORGAN_CUT_AWAY -/datum/organ/internal/New(mob/living/carbon/human/H) +/datum/organ/internal/New(mob/living/carbon/M) ..() - if(H) - var/datum/organ/external/E = H.organs_by_name[src.parent_organ] - if(E.internal_organs == null) - E.internal_organs = list() - E.internal_organs |= src - H.internal_organs |= src - src.owner = H + if(M && istype(M)) + + M.internal_organs |= src + src.owner = M + + var/mob/living/carbon/human/H = M + if(istype(H)) + var/datum/organ/external/E = H.organs_by_name[src.parent_organ] + if(E.internal_organs == null) + E.internal_organs = list() + E.internal_organs |= src /datum/organ/internal/process() From f44a53fb696433f37c0d6fd139ebd671f9f81110 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 13:28:56 +0930 Subject: [PATCH 13/16] Removed a debug. --- code/modules/mob/language.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index b0ffe74fe63..383d20ff182 100755 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -160,8 +160,6 @@ if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping M.show_message("[message_start] [message_body]", 2) - world << "Got through checks, transmitting." - for (var/mob/living/S in living_mob_list) if(drone_only && !istype(S,/mob/living/silicon/robot/drone)) From b4646b65e81ebcb83ae2cec0a08a64b86b29d75e Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 14:09:41 +0930 Subject: [PATCH 14/16] Fixed up organ transplant rejection, added cortical stacks, changed vox over to use organ stacks. --- code/game/gamemodes/heist/heist.dm | 16 +++------- .../objects/items/weapons/implants/implant.dm | 7 +---- code/modules/admin/verbs/one_click_antag.dm | 19 ++---------- .../mob/living/carbon/human/species.dm | 3 +- code/modules/organs/blood.dm | 2 +- code/modules/organs/organ_alien.dm | 31 ++++++++++++++++++- code/modules/organs/organ_internal.dm | 5 +-- code/modules/reagents/Chemistry-Reagents.dm | 2 +- code/modules/surgery/organs_internal.dm | 13 ++++++-- maps/tgstation2.dmm | 4 +-- 10 files changed, 58 insertions(+), 44 deletions(-) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 320e89d9b2f..1f05a64fadc 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -112,15 +112,9 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' for(var/datum/organ/external/limb in vox.organs) limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT) - //Generate cortical stack. - var/datum/organ/external/affected = vox.get_organ("head") - - var/obj/item/weapon/implant/cortical/I = new(vox) - I.imp_in = vox - I.implanted = 1 - affected.implants += I - I.part = affected - cortical_stacks += I + // Keep track of their stack. + if(vox.internal_organs_by_name["stack"]) + cortical_stacks |= vox.internal_organs_by_name["stack"] vox.equip_vox_raider() vox.regenerate_icons() @@ -130,8 +124,8 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' if(cortical_stacks.len == 0) return 0 - for(var/obj/stack in cortical_stacks) - if (get_area(stack) != locate(/area/shuttle/vox/station)) + for(var/datum/organ/internal/stack/vox/stack in cortical_stacks) + if(stack.organ_holder && get_area(stack.organ_holder) != locate(/area/shuttle/vox/station)) return 0 return 1 diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index c474650f9ae..89e265aed8b 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -498,9 +498,4 @@ the implant may become unstable and either pre-maturely inject the subject or si return 1 islegal() - return 0 - -/obj/item/weapon/implant/cortical - name = "cortical stack" - desc = "A fist-sized mass of biocircuits and chips." - icon_state = "implant_evil" + return 0 \ No newline at end of file diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 95fbc615c8a..18fcee188b5 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -517,24 +517,11 @@ client/proc/one_click_antag() new_vox.mind.special_role = "Vox Raider" new_vox.mutations |= NOCLONE //Stops the station crew from messing around with their DNA. - //Now apply cortical stack. - var/datum/organ/external/affected = new_vox.get_organ("head") - - //To avoid duplicates. - for(var/obj/item/weapon/implant/cortical/imp in new_vox.contents) - affected.implants -= imp - del(imp) - - var/obj/item/weapon/implant/cortical/I = new(new_vox) - I.imp_in = new_vox - I.implanted = 1 - affected.implants += I - I.part = affected - if(ticker.mode && ( istype( ticker.mode,/datum/game_mode/heist ) ) ) var/datum/game_mode/heist/M = ticker.mode - cortical_stacks += I - M.raiders[new_vox.mind] = I + if(new_vox.internal_organs_by_name["stack"]) + cortical_stacks |= new_vox.internal_organs_by_name["stack"] + M.raiders[new_vox.mind] = new_vox.internal_organs_by_name["stack"] ticker.mode.traitors += new_vox.mind new_vox.equip_vox_raider() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 953468af391..36ab00b6565 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -311,7 +311,8 @@ "liver" = /datum/organ/internal/liver, "kidneys" = /datum/organ/internal/kidney, "brain" = /datum/organ/internal/brain, - "eyes" = /datum/organ/internal/eyes + "eyes" = /datum/organ/internal/eyes, + "stack" = /datum/organ/internal/stack/vox ) /datum/species/vox/armalis diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 38feee53e28..45eb41585d8 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -30,7 +30,7 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 /mob/living/carbon/human/proc/fixblood() for(var/datum/reagent/blood/B in vessel.reagent_list) if(B.id == "blood") - B.data = list( "donor"=src,"viruses"=null,"blood_DNA"=dna.unique_enzymes,"blood_colour"= species.blood_color,"blood_type"=dna.b_type, \ + B.data = list( "donor"=src,"viruses"=null,"species"=species.name,"blood_DNA"=dna.unique_enzymes,"blood_colour"= species.blood_color,"blood_type"=dna.b_type, \ "resistances"=null,"trace_chem"=null, "virus2" = null, "antibodies" = null) B.color = B.data["blood_color"] diff --git a/code/modules/organs/organ_alien.dm b/code/modules/organs/organ_alien.dm index e04287bc3f3..8eb5f12a31d 100644 --- a/code/modules/organs/organ_alien.dm +++ b/code/modules/organs/organ_alien.dm @@ -180,4 +180,33 @@ /obj/item/organ/xenos/resinspinner name = "hive node" - icon_state = "xgibmid2" \ No newline at end of file + icon_state = "xgibmid2" + +//VOX ORGANS. +/datum/organ/internal/stack + name = "cortical stack" + removed_type = /obj/item/organ/stack + parent_organ = "head" + robotic = 2 + vital = 1 + var/backup_time = 0 + var/datum/mind/backup + +/datum/organ/internal/stack/process() + if(owner && owner.stat != 2 && !is_broken()) + backup_time = world.time + if(owner.mind) backup = owner.mind + +/datum/organ/internal/stack/vox + removed_type = /obj/item/organ/stack/vox + +/datum/organ/internal/stack/vox/stack + +/obj/item/organ/stack + name = "cortical stack" + icon_state = "brain-prosthetic" + organ_tag = "stack" + robotic = 2 + +/obj/item/organ/stack/vox + name = "vox cortical stack" \ No newline at end of file diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index c2df9a30f0f..39840c88f00 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -13,9 +13,9 @@ var/parent_organ = "chest" var/robotic = 0 //For being a robot var/removed_type //When removed, forms this object. - var/list/transplant_data // Blood DNA and colour of donor var/rejecting // Is this organ already being rejected? - + var/obj/item/organ/organ_holder // If not in a body, held in this item. + var/list/transplant_data /datum/organ/internal/proc/rejuvenate() damage=0 @@ -275,5 +275,6 @@ if(istype(removed_organ)) removed_organ.organ_data = src removed_organ.update() + organ_holder = removed_organ return removed_organ \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm index fbf206fbc65..c16999067b1 100644 --- a/code/modules/reagents/Chemistry-Reagents.dm +++ b/code/modules/reagents/Chemistry-Reagents.dm @@ -94,7 +94,7 @@ datum blood - data = new/list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"blood_colour"= "#A10808","resistances"=null,"trace_chem"=null, "antibodies" = null) + data = new/list("donor"=null,"viruses"=null,"species"="Human","blood_DNA"=null,"blood_type"=null,"blood_colour"= "#A10808","resistances"=null,"trace_chem"=null, "antibodies" = null) name = "Blood" id = "blood" reagent_state = LIQUID diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 87675e906ef..1d8fa06e537 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -404,12 +404,19 @@ if(istype(O)) - if(!O.organ_data.transplant_data) + var/datum/reagent/blood/transplant_blood = O.reagents.reagent_list["blood"] + if(!transplant_blood) O.organ_data.transplant_data = list() - O.organ_data.transplant_data["species"] = target.species.name + O.organ_data.transplant_data["species"] = target.species.name O.organ_data.transplant_data["blood_type"] = target.dna.b_type - O.organ_data.transplant_data["blood_DNA"] = target.dna.unique_enzymes + O.organ_data.transplant_data["blood_DNA"] = target.dna.unique_enzymes + else + O.organ_data.transplant_data = list() + O.organ_data.transplant_data["species"] = transplant_blood.data["species"] + O.organ_data.transplant_data["blood_type"] = transplant_blood.data["blood_type"] + O.organ_data.transplant_data["blood_DNA"] = transplant_blood.data["blood_DNA"] + O.organ_data.organ_holder = null O.organ_data.owner = target target.internal_organs |= O.organ_data affected.internal_organs |= O.organ_data diff --git a/maps/tgstation2.dmm b/maps/tgstation2.dmm index 65c12df98e5..90119baa49c 100644 --- a/maps/tgstation2.dmm +++ b/maps/tgstation2.dmm @@ -7893,6 +7893,7 @@ "cVO" = (/obj/machinery/turretcover{density = 1},/turf/unsimulated/floor{icon_state = "bot"},/area/centcom/evac) "cVP" = (/obj/structure/table,/obj/item/device/antibody_scanner,/obj/machinery/requests_console{department = "Virology"; name = "Virology Requests Console"; pixel_x = -32},/turf/simulated/floor{icon_state = "white"},/area/medical/virology) "cVQ" = (/obj/structure/sign/securearea,/turf/simulated/wall/r_wall,/area/tcommsat/computer) +"cVR" = (/obj/machinery/body_scanconsole,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station) "cVT" = (/obj/structure/table,/turf/simulated/floor/plating,/area/maintenance/engi_shuttle) "cVU" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor/plating,/area/maintenance/engi_shuttle) "cVV" = (/obj/machinery/light{dir = 8},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor{dir = 4; icon_state = "warning"},/area/rnd/xenobiology) @@ -8624,7 +8625,6 @@ "djY" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/poddoor{id = "skipjack"; name = "Skipjack Blast Shielding"},/turf/simulated/shuttle/plating/vox,/area/shuttle/vox/station) "djZ" = (/obj/machinery/embedded_controller/radio/airlock/airlock_controller{tag_airpump = "vox_east_vent"; tag_exterior_door = "vox_northeast_lock"; frequency = 1331; id_tag = "vox_east_control"; tag_interior_door = "vox_southeast_lock"; pixel_x = -24; req_access_txt = "150"; tag_chamber_sensor = "vox_east_sensor"},/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1331; id_tag = "vox_east_vent"},/turf/simulated/shuttle/plating/vox,/area/shuttle/vox/station) "dka" = (/obj/machinery/atmospherics/pipe/manifold/visible{dir = 4},/turf/simulated/shuttle/plating/vox,/area/shuttle/vox/station) -"dkb" = (/obj/machinery/body_scanconsole{known_implants = list(/obj/item/weapon/implant/cortical)},/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station) "dkc" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/machinery/camera/autoname{dir = 4},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor{dir = 8; icon_state = "whitegreen"},/area/rnd/xenobiology/xenoflora_storage) "dkd" = (/obj/machinery/sleep_console,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station) "dke" = (/obj/machinery/bodyscanner,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox/station) @@ -11505,7 +11505,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUscUvcUvcUvcUvcUvcUvdS aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUscVlcVmcVmdSTcVmcVmcVmdSTcVmcVmcVmdSTcVmcVmdSUcUsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOIdjPdjOdjNdjNdjNdjNdjNdjNcVgdjNcVgdjNdjNdjNdjNdjNdjNdjOdjPdOIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUsdTbdTcdTccVzdTfdTgdThcVzdTddTddTecVzdTjdTicVycUsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOIdkqdkpdksdkrdkxdkycVgdjKcVgdjKcVgdjKcVgdkvebtdkucQkdkpdkqdOIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUsdTcdTkdTbcVXdTodTndTgcVXdTmdTldTdcVXdTpcVydTqcUsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadOIdjYdkpdjkdjkdjkdjkcVgdjkdjkdjkdjkdjkcVgdjkdjkdkzdjkdkpdjYdOIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUscUscUscUscUscUscUscUscUscUscUscUscUscUscUscUscUsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacVbcVgebqdkldkkdkidkjcVgdkhdjkdjkdjkdkgcVgdkfdkddkedkbebqcVgcVdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacUscUscUscUscUscUscUscUscUscUscUscUscUscUscUscUscUsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacVbcVgebqdkldkkdkidkjcVgdkhdjkdjkdjkdkgcVgdkfdkddkecVRebqcVgcVdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacWJcVgdkmdkmcVgcVgcVgcVgdkodjkdjkdjkdEFcVgcVgcVgcVgdkmdkmcVgcWNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacWJcWOcWOcWNaaaaaacVgdjzdjkdjkdjkdEzcVgaaaaaacWJcWOcWOcWNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacVgdjBdjkdjkdjkdEzcVgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa From e2ce1fa2dfdd24371339508cc452fb61bfe4bae4 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 15:28:30 +0930 Subject: [PATCH 15/16] Collapsed Bump() down to carbon from alien and monkey. Stripped out extraneous stuff from carbon/alien HUD. Implemented some life stuff for aliens. --- code/_onclick/hud/alien_larva.dm | 47 +----- code/game/objects/items/weapons/shards.dm | 2 +- code/modules/mob/living/carbon/alien/alien.dm | 38 +---- .../mob/living/carbon/alien/diona/life.dm | 36 ++--- .../mob/living/carbon/alien/larva/life.dm | 14 ++ code/modules/mob/living/carbon/alien/life.dm | 137 ++++++++++++++++-- code/modules/mob/living/carbon/carbon.dm | 97 ++++--------- .../mob/living/carbon/carbon_powers.dm | 60 ++++++++ .../carbon/human/alien/alien_species.dm | 11 +- .../mob/living/carbon/human/species.dm | 2 +- .../mob/living/carbon/monkey/monkey.dm | 36 ----- code/modules/mob/mob.dm | 9 ++ 12 files changed, 276 insertions(+), 213 deletions(-) create mode 100644 code/modules/mob/living/carbon/alien/larva/life.dm diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm index 4e29827e892..b2a85e20765 100644 --- a/code/_onclick/hud/alien_larva.dm +++ b/code/_onclick/hud/alien_larva.dm @@ -5,58 +5,22 @@ var/obj/screen/using - using = new /obj/screen() - using.name = "act_intent" - using.dir = SOUTHWEST - using.icon = 'icons/mob/screen1_alien.dmi' - using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent) - using.screen_loc = ui_acti - using.layer = 20 - src.adding += using - action_intent = using - using = new /obj/screen() using.name = "mov_intent" using.dir = SOUTHWEST using.icon = 'icons/mob/screen1_alien.dmi' using.icon_state = (mymob.m_intent == "run" ? "running" : "walking") - using.screen_loc = ui_movi + using.screen_loc = ui_acti using.layer = 20 src.adding += using move_intent = using - mymob.oxygen = new /obj/screen() - mymob.oxygen.icon = 'icons/mob/screen1_alien.dmi' - mymob.oxygen.icon_state = "oxy0" - mymob.oxygen.name = "oxygen" - mymob.oxygen.screen_loc = ui_alien_oxygen - - mymob.toxin = new /obj/screen() - mymob.toxin.icon = 'icons/mob/screen1_alien.dmi' - mymob.toxin.icon_state = "tox0" - mymob.toxin.name = "toxin" - mymob.toxin.screen_loc = ui_alien_toxin - - - mymob.fire = new /obj/screen() - mymob.fire.icon = 'icons/mob/screen1_alien.dmi' - mymob.fire.icon_state = "fire0" - mymob.fire.name = "fire" - mymob.fire.screen_loc = ui_alien_fire - - mymob.healths = new /obj/screen() mymob.healths.icon = 'icons/mob/screen1_alien.dmi' mymob.healths.icon_state = "health0" mymob.healths.name = "health" mymob.healths.screen_loc = ui_alien_health - mymob.pullin = new /obj/screen() - mymob.pullin.icon = 'icons/mob/screen1_alien.dmi' - mymob.pullin.icon_state = "pull0" - mymob.pullin.name = "pull" - mymob.pullin.screen_loc = ui_pull_resist - mymob.blind = new /obj/screen() mymob.blind.icon = 'icons/mob/screen1_full.dmi' mymob.blind.icon_state = "blackimageoverlay" @@ -71,11 +35,6 @@ mymob.flash.screen_loc = "1,1 to 15,15" mymob.flash.layer = 17 - mymob.zone_sel = new /obj/screen/zone_sel() - mymob.zone_sel.overlays.Cut() - mymob.zone_sel.overlays += image("icon" = 'icons/mob/zone_sel.dmi', "icon_state" = text("[]", mymob.zone_sel.selecting)) - mymob.client.screen = null - - mymob.client.screen += list( mymob.zone_sel, mymob.oxygen, mymob.toxin, mymob.fire, mymob.healths, mymob.pullin, mymob.blind, mymob.flash) //, mymob.rest, mymob.sleep, mymob.mach ) - mymob.client.screen += src.adding + src.other + mymob.client.screen += list( mymob.healths, mymob.blind, mymob.flash) //, mymob.rest, mymob.sleep, mymob.mach ) + mymob.client.screen += src.adding + src.other \ No newline at end of file diff --git a/code/game/objects/items/weapons/shards.dm b/code/game/objects/items/weapons/shards.dm index 1eeb6dff8df..0ecbe900d2e 100644 --- a/code/game/objects/items/weapons/shards.dm +++ b/code/game/objects/items/weapons/shards.dm @@ -76,7 +76,7 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) + if(H.species.flags & IS_SYNTHETIC || H.species.insulated) return if( !H.shoes && ( !H.wear_suit || !(H.wear_suit.body_parts_covered & FEET) ) ) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 0cb28d10867..5d48ec1f3c4 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -11,18 +11,20 @@ attack_sound = null friendly = "nuzzles" wall_smash = 0 + health = 100 + maxHealth = 100 var/adult_form var/dead_icon var/amount_grown = 0 var/max_grown = 10 var/time_of_birth - var/co2overloadtime = null - var/temperature_resistance = T0C+75 var/language /mob/living/carbon/alien/New() + time_of_birth = world.time + verbs += /mob/living/proc/ventcrawl verbs += /mob/living/proc/hide @@ -44,38 +46,6 @@ /mob/living/carbon/alien/u_equip(obj/item/W as obj) return -//This is fine, works the same as a human -/mob/living/carbon/alien/Bump(atom/movable/AM as mob|obj, yes) - - spawn( 0 ) - if ((!( yes ) || now_pushing)) - return - now_pushing = 1 - if(ismob(AM)) - var/mob/tmob = AM - if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations)) - if(prob(70)) - src << "\red You fail to push [tmob]'s fat ass out of the way." - now_pushing = 0 - return - if(!(tmob.status_flags & CANPUSH)) - now_pushing = 0 - return - tmob.LAssailant = src - - now_pushing = 0 - ..() - if (!( istype(AM, /atom/movable) )) - return - if (!( now_pushing )) - now_pushing = 1 - if (!( AM.anchored )) - var/t = get_dir(src, AM) - step(AM, t) - now_pushing = null - return - return - /mob/living/carbon/alien/Stat() ..() stat(null, "Progress: [amount_grown]/[max_grown]") diff --git a/code/modules/mob/living/carbon/alien/diona/life.dm b/code/modules/mob/living/carbon/alien/diona/life.dm index 26d236bcaa8..5a82e3f373c 100644 --- a/code/modules/mob/living/carbon/alien/diona/life.dm +++ b/code/modules/mob/living/carbon/alien/diona/life.dm @@ -1,20 +1,20 @@ -/* TODO - if(alien) //Diona nymphs are the only alien monkey currently. - 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 +//Dionaea regenerate health and nutrition in light. +/mob/living/carbon/alien/diona/handle_environment(datum/gas_mixture/environment) - nutrition += light_amount - traumatic_shock -= light_amount + 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 - if(nutrition > 500) - nutrition = 500 - if(light_amount > 2) //if there's enough light, heal - adjustBruteLoss(-1) - adjustToxLoss(-1) - adjustOxyLoss(-1) -*/ \ No newline at end of file + nutrition += light_amount + + if(nutrition > 500) + nutrition = 500 + if(light_amount > 2) //if there's enough light, heal + adjustBruteLoss(-1) + adjustFireLoss(-1) + adjustToxLoss(-1) + adjustOxyLoss(-1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm new file mode 100644 index 00000000000..c5dddfd7ac0 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -0,0 +1,14 @@ +//Larvae regenerate health and nutrition from plasma and alien weeds. +/mob/living/carbon/alien/larva/handle_environment() + + var/turf/T = loc + if(!T) return + var/datum/gas_mixture/environment = T.return_air() + if(!environment) return + + if(environment.gas["phoron"] > 0 || locate(/obj/effect/alien/weeds) in T.contents) + update_progression() + adjustBruteLoss(-1) + adjustFireLoss(-1) + adjustToxLoss(-1) + adjustOxyLoss(-1) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm index 5c0ea8ed1f4..9ddce0c5497 100644 --- a/code/modules/mob/living/carbon/alien/life.dm +++ b/code/modules/mob/living/carbon/alien/life.dm @@ -4,8 +4,8 @@ set invisibility = 0 set background = 1 - if (monkeyizing) - return + if (monkeyizing) return + if(!loc) return ..() @@ -50,14 +50,131 @@ adjustToxLoss(-(rads)) return -/mob/living/carbon/alien/proc/handle_environment(enviroment) - //TODO: Work out if larvae breathe/suffer from pressure/suffer from heat. - if(!enviroment) - return - /mob/living/carbon/alien/proc/handle_regular_status_updates() - // TODO: sleep, blind, stunned, paralyzed? - return + + if(status_flags & GODMODE) return 0 + + if(stat == DEAD) + blinded = 1 + silent = 0 + else + updatehealth() + + if(health <= 0) + death() + blinded = 1 + silent = 0 + return 1 + + if(paralysis) + AdjustParalysis(-1) + blinded = 1 + stat = UNCONSCIOUS + if(halloss > 0) + adjustHalLoss(-3) + else if(sleeping) + + adjustHalLoss(-3) + if (mind) + if((mind.active && client != null) || immune_to_ssd) + sleeping = max(sleeping-1, 0) + blinded = 1 + stat = UNCONSCIOUS + + else if(resting) + if(halloss > 0) + adjustHalLoss(-3) + + //CONSCIOUS + else + stat = CONSCIOUS + if(halloss > 0) + adjustHalLoss(-1) + + // Eyes and blindness. + if(!has_eyes()) + eye_blind = 1 + blinded = 1 + eye_blurry = 1 + else if(eye_blind) + eye_blind = max(eye_blind-1,0) + blinded = 1 + else if(eye_blurry) + eye_blurry = max(eye_blurry-1, 0) + + //Ears + if(sdisabilities & DEAF) //disabled-deaf, doesn't get better on its own + ear_deaf = max(ear_deaf, 1) + else if(ear_deaf) //deafness, heals slowly over time + ear_deaf = max(ear_deaf-1, 0) + ear_damage = max(ear_damage-0.05, 0) + + return 1 /mob/living/carbon/alien/proc/handle_regular_hud_updates() - return //TODO: Not sure what to do with this yet. \ No newline at end of file + + if (stat == 2 || (XRAY in src.mutations)) + sight |= SEE_TURFS + sight |= SEE_MOBS + sight |= SEE_OBJS + see_in_dark = 8 + see_invisible = SEE_INVISIBLE_LEVEL_TWO + else if (stat != 2) + sight &= ~SEE_TURFS + sight &= ~SEE_MOBS + sight &= ~SEE_OBJS + see_in_dark = 2 + see_invisible = SEE_INVISIBLE_LIVING + + if (healths) + if (stat != 2) + switch(health) + 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" + else + healths.icon_state = "health7" + + if(pullin) + pullin.icon_state = "pull[pulling ? 1 : 0]" + + if (client) + client.screen.Remove(global_hud.blurry,global_hud.druggy,global_hud.vimpaired) + + if ((blind && stat != 2)) + if ((blinded)) + blind.layer = 18 + else + blind.layer = 0 + if (disabilities & NEARSIGHTED) + client.screen += global_hud.vimpaired + if (eye_blurry) + client.screen += global_hud.blurry + if (druggy) + client.screen += global_hud.druggy + + if (stat != 2) + if (machine) + if (!( machine.check_eye(src) )) + reset_view(null) + else + if(client && !client.adminobs) + reset_view(null) + + return 1 + +/mob/living/carbon/alien/proc/handle_environment(datum/gas_mixture/environment) + // At the moment, neither of the alien species breathe or suffer from pressure. + // TODO: Implement heat and phoron exposure checks. + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 1687016f85c..468f2861fa5 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -428,71 +428,38 @@ if(alert(src,"You sure you want to sleep for a while?","Sleep","Yes","No") == "Yes") usr.sleeping = 20 //Short nap -//Brain slug proc for voluntary removal of control. -/mob/living/carbon/proc/release_control() +/mob/living/carbon/Bump(atom/movable/AM as mob|obj, yes) - set category = "Abilities" - set name = "Release Control" - set desc = "Release control of your host's body." + spawn( 0 ) + if ((!( yes ) || now_pushing)) + return + now_pushing = 1 + if(ismob(AM)) + var/mob/tmob = AM + if(istype(tmob, /mob/living/carbon/human) && (HULK in tmob.mutations)) + if(prob(70)) + usr << "\red You fail to push [tmob]'s fat ass out of the way." + now_pushing = 0 + return + if(!(tmob.status_flags & CANPUSH)) + now_pushing = 0 + return - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(B && B.host_brain) - src << "\red You withdraw your probosci, releasing control of [B.host_brain]" - - B.detatch() - - verbs -= /mob/living/carbon/proc/release_control - verbs -= /mob/living/carbon/proc/punish_host - verbs -= /mob/living/carbon/proc/spawn_larvae - - else - src << "\red ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !" - -//Brain slug proc for tormenting the host. -/mob/living/carbon/proc/punish_host() - set category = "Abilities" - set name = "Torment host" - set desc = "Punish your host with agony." - - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(!B) + tmob.LAssailant = src + now_pushing = 0 + ..() + if (!( istype(AM, /atom/movable) )) + return + if (!( now_pushing )) + now_pushing = 1 + if (!( AM.anchored )) + var/t = get_dir(src, AM) + if (istype(AM, /obj/structure/window)) + if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST) + for(var/obj/structure/window/win in get_step(AM,t)) + now_pushing = 0 + return + step(AM, t) + now_pushing = null return - - if(B.host_brain.ckey) - src << "\red You send a punishing spike of psychic agony lancing into your host's brain." - B.host_brain << "\red Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!" - -//Check for brain worms in head. -/mob/proc/has_brain_worms() - - for(var/I in contents) - if(istype(I,/mob/living/simple_animal/borer)) - return I - - return 0 - -/mob/living/carbon/proc/spawn_larvae() - set category = "Abilities" - set name = "Reproduce" - set desc = "Spawn several young." - - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(!B) - return - - if(B.chemicals >= 100) - src << "\red Your host twitches and quivers as you rapidly excrete a larva from your sluglike body." - visible_message("\red [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!") - B.chemicals -= 100 - B.has_reproduced = 1 - - new /obj/effect/decal/cleanable/vomit(get_turf(src)) - playsound(loc, 'sound/effects/splat.ogg', 50, 1) - new /mob/living/simple_animal/borer(get_turf(src)) - - else - src << "You do not have enough chemicals stored to reproduce." - return \ No newline at end of file + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon_powers.dm b/code/modules/mob/living/carbon/carbon_powers.dm index c477d26031d..f4bc6e4d68f 100644 --- a/code/modules/mob/living/carbon/carbon_powers.dm +++ b/code/modules/mob/living/carbon/carbon_powers.dm @@ -37,3 +37,63 @@ src.reagents.add_reagent("nutriment", target.weedlevel) target.weedlevel = 0 src.visible_message("\red [src] begins rooting through [target], ripping out weeds and eating them noisily.","\red You begin rooting through [target], ripping out weeds and eating them noisily.") + +//Brain slug proc for voluntary removal of control. +/mob/living/carbon/proc/release_control() + + set category = "Abilities" + set name = "Release Control" + set desc = "Release control of your host's body." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(B && B.host_brain) + src << "\red You withdraw your probosci, releasing control of [B.host_brain]" + + B.detatch() + + verbs -= /mob/living/carbon/proc/release_control + verbs -= /mob/living/carbon/proc/punish_host + verbs -= /mob/living/carbon/proc/spawn_larvae + + else + src << "\red ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !" + +//Brain slug proc for tormenting the host. +/mob/living/carbon/proc/punish_host() + set category = "Abilities" + set name = "Torment host" + set desc = "Punish your host with agony." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(!B) + return + + if(B.host_brain.ckey) + src << "\red You send a punishing spike of psychic agony lancing into your host's brain." + B.host_brain << "\red Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!" + +/mob/living/carbon/proc/spawn_larvae() + set category = "Abilities" + set name = "Reproduce" + set desc = "Spawn several young." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(!B) + return + + if(B.chemicals >= 100) + src << "\red Your host twitches and quivers as you rapidly excrete a larva from your sluglike body." + visible_message("\red [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!") + B.chemicals -= 100 + B.has_reproduced = 1 + + new /obj/effect/decal/cleanable/vomit(get_turf(src)) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + new /mob/living/simple_animal/borer(get_turf(src)) + + else + src << "You do not have enough chemicals stored to reproduce." + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/alien/alien_species.dm b/code/modules/mob/living/carbon/human/alien/alien_species.dm index 09302235c34..c1c820a17f1 100644 --- a/code/modules/mob/living/carbon/human/alien/alien_species.dm +++ b/code/modules/mob/living/carbon/human/alien/alien_species.dm @@ -69,10 +69,12 @@ /datum/species/xenos/handle_environment_special(var/mob/living/carbon/human/H) - if(!H.loc) - return + var/turf/T = H.loc + if(!T) return + var/datum/gas_mixture/environment = T.return_air() + if(!environment) return - if(locate(/obj/effect/alien/weeds) in H.loc) + if(environment.gas["phoron"] > 0 || locate(/obj/effect/alien/weeds) in T) if(H.health >= H.maxHealth - H.getCloneLoss()) var/datum/organ/internal/xenos/plasmavessel/P = H.internal_organs_by_name["plasma vessel"] P.stored_plasma += weeds_plasma_rate @@ -82,7 +84,8 @@ H.adjustFireLoss(-weeds_heal_rate) H.adjustOxyLoss(-weeds_heal_rate) H.adjustToxLoss(-weeds_heal_rate) - ..() + ..() + /datum/species/xenos/handle_login_special(var/mob/living/carbon/human/H) H.AddInfectionImages() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 36ab00b6565..6b4e3b45868 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -28,7 +28,7 @@ var/mutantrace // Safeguard due to old code. var/list/speech_sounds // A list of sounds to potentially play when speaking. var/has_fine_manipulation = 1 // Can use small items. - var/insulated // Immune to electrocution. + var/insulated // Immune to electrocution and glass shards to the feet. // Some species-specific gibbing data. var/gibbed_anim = "gibbed-h" diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 2d9abfa2466..a38ba9c6957 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -111,42 +111,6 @@ tally += (283.222 - bodytemperature) / 10 * 1.75 return tally+config.monkey_delay -/mob/living/carbon/monkey/Bump(atom/movable/AM as mob|obj, yes) - - spawn( 0 ) - if ((!( yes ) || now_pushing)) - return - now_pushing = 1 - if(ismob(AM)) - var/mob/tmob = AM - if(istype(tmob, /mob/living/carbon/human) && (HULK in tmob.mutations)) - if(prob(70)) - usr << "\red You fail to push [tmob]'s fat ass out of the way." - now_pushing = 0 - return - if(!(tmob.status_flags & CANPUSH)) - now_pushing = 0 - return - - tmob.LAssailant = src - now_pushing = 0 - ..() - if (!( istype(AM, /atom/movable) )) - return - if (!( now_pushing )) - now_pushing = 1 - if (!( AM.anchored )) - var/t = get_dir(src, AM) - if (istype(AM, /obj/structure/window)) - if(AM:ini_dir == NORTHWEST || AM:ini_dir == NORTHEAST || AM:ini_dir == SOUTHWEST || AM:ini_dir == SOUTHEAST) - for(var/obj/structure/window/win in get_step(AM,t)) - now_pushing = 0 - return - step(AM, t) - now_pushing = null - return - return - /mob/living/carbon/monkey/Topic(href, href_list) ..() if (href_list["mach_close"]) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index feee1b00f4c..c2430de0da3 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1036,3 +1036,12 @@ mob/proc/yank_out_object() if(paralysis) AdjustParalysis(-1) return paralysis + +//Check for brain worms in head. +/mob/proc/has_brain_worms() + + for(var/I in contents) + if(istype(I,/mob/living/simple_animal/borer)) + return I + + return 0 \ No newline at end of file From bab862f24c7abfde1f8f54da97325d98f19d0f90 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Tue, 30 Sep 2014 16:07:47 +0930 Subject: [PATCH 16/16] Readded transform procs for xenos. --- code/modules/admin/admin.dm | 14 ++++++++++++-- code/modules/admin/topic.dm | 6 ++++-- code/modules/mob/mob_transformation_simple.dm | 6 +++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 46b1beef780..5b369dc9f4b 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -141,8 +141,18 @@ var/global/floorIsLava = 0 body += {"

Rudimentary transformation:
These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

Observer | - Larva \] - Human + \[ Xenos: Larva + Drone + Hunter + Sentinel + Queen \] | + \[ Crew: Human + Unathi + Tajaran + Skrell + Vox \] | \[ + Nymph + Diona \] | \[ slime: Baby, Adult \] Monkey | diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d0cc41da62f..2e087971bce 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -267,6 +267,7 @@ href_list["secretsadmin"] = "check_antagonist" else if(href_list["simplemake"]) + if(!check_rights(R_SPAWN)) return var/mob/M = locate(href_list["mob"]) @@ -285,8 +286,9 @@ switch(href_list["simplemake"]) if("observer") M.change_mob_type( /mob/dead/observer , null, null, delmob ) if("larva") M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob ) - if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob ) - if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob ) + if("nymph") M.change_mob_type( /mob/living/carbon/alien/diona , null, null, delmob ) + if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob, href_list["species"]) + if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob ) if("monkey") M.change_mob_type( /mob/living/carbon/monkey , null, null, delmob ) if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob ) if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob ) diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm index bea08693fbc..f07cadb9e80 100644 --- a/code/modules/mob/mob_transformation_simple.dm +++ b/code/modules/mob/mob_transformation_simple.dm @@ -2,7 +2,7 @@ //This proc is the most basic of the procs. All it does is make a new mob on the same tile and transfer over a few variables. //Returns the new mob //Note that this proc does NOT do MMI related stuff! -/mob/proc/change_mob_type(var/new_type = null, var/turf/location = null, var/new_name = null as text, var/delete_old_mob = 0 as num) +/mob/proc/change_mob_type(var/new_type = null, var/turf/location = null, var/new_name = null as text, var/delete_old_mob = 0 as num, var/subspecies) if(istype(src,/mob/new_player)) usr << "\red cannot convert players who have not entered yet." @@ -48,6 +48,10 @@ else M.key = key + if(subspecies && istype(M,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + H.set_species(subspecies) + if(delete_old_mob) spawn(1) del(src)