From 9fcde12b4ff6ce5155919907ad85c3fcf3e6714d Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sun, 28 Sep 2014 01:21:36 +0930 Subject: [PATCH 01/19] 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 d09a530659..1c200c9afc 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 98ab127825..6cd983732b 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 1cd7c4aad8..d36fc7a7c7 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 dba42d74d6..a9959ef063 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 ac85b18ae3..496eac9195 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 6750f7c83e..590df9cd07 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 63c3f7d3c8..e035b665c9 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 70901add18..c2608cfa3d 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 0000000000..4ce50d404c --- /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 1762225088..ce76680b0d 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 5e1fbbe50d..04f5efa518 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 9ce8ccb4fc..47eb7ca558 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 cf05308e40..345d9f44d5 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 6e1cc86633..b4155d6fca 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 d3149ab90f..aa7e260371 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 dd60f16645..f5ad4fa9fd 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 ddadcfddd8..3080c05f09 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 f4400132e8..fdb6a93b2e 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 19223c48f1..42a63f26e5 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 9518394916..fdd28f5bcc 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 23d5416fca..214c091c3e 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 2b084ce8b5..6b7752f813 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 defcc968d1..f1910fcfe3 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 9bb6ae4376..97abbdec38 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 6959828f9b..ae2ed01192 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 27b9da88e8..d2ba4fbb94 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 62916d818d..897b03c8a1 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 6877ed4b85..5ee424bd8d 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 0dff048d00..feed242bef 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 2a9850171e..c672950a18 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 b250884e9f..3f7faeac8e 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 01caff57e5..8b4e010d4b 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 c5fb663116..dd02d3c17d 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 67f0b904ed..85fdb33a8d 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 ce68106358..44a7e7a259 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 286bffb3a0..d5e8a16761 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 daf0e37004..a4e5e0586f 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 3a691d9d35..38feee53e2 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 f0c28d87c3..12b180fd54 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 79bbe771b3..c4df67cc87 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 4ed1004756..e8c7acbfbf 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 0000000000..c48a9d4b54 --- /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 b1858cd698..13962c7134 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 29001d9723..28e369f531 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 5e6277c8e7..5617a3802e 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 91332eab06..0000000000 --- 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 0bc1407567..605b1503d5 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 4bc804eab5..0000000000 --- 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 0000000000..85b5dd8dd3 --- /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 0000000000..dcd6cc4b31 --- /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 d142b8ef67..0fa9f4863a 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 94c7b2b861..a05c6f120b 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 57df6a398c..7e2fbc776e 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 0000000000..87675e906e --- /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 67f3cb82de..ccd9d388e2 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 c14d065cd9..0000000000 --- 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 0000000000..d962cfd3f4 --- /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 b0116585ab..9ce44d1260 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 41fda7a150..3ebeefeba8 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/19] Updated changelog. --- html/changelog.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/html/changelog.html b/html/changelog.html index cc5a9f5fd0..736ffca8cf 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/19] 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 561a24de2a..25124f8f52 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/19] 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 1c200c9afc..037531f6fd 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 80b168aabd..925994546e 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 01b1058527..0000000000 --- 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 221eef2a1d..9ea0cb2bff 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 82a9d79c47..7425716cd9 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 079c551ebf..8a10310b3d 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 b84b9f467c..3c1cb43727 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 d36fc7a7c7..001372b4e3 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 4c01933dbe..4777f061d6 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 34dc2e1344..cc22ce05d3 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 be2bb88a17..d08679bbc1 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 590df9cd07..83ca646d89 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 b36eb64d8b..ded12b2da8 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 c1fd9b219f..5dae9e6e4b 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 5bcddade43..9e64bd2e70 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 9ff5608e2d..d01e0e3506 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 094f3ff700..8868914872 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 14f8f93e56..1c8298bd0b 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 04f5efa518..8f1eff7d63 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 5887e0bc32..65871a67b3 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 47eb7ca558..3897ee1d08 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 288465a160..473bd973ed 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 5ad0ecae56..d3e9b81e15 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 78ee794b53..decf7afb43 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 5e3ba542bf..9983eff1ac 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 be54a95ba1..682347669a 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 b4155d6fca..c7f8fadfcb 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 a30168479a..635093436f 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 3080c05f09..d9d7ec0126 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 af06f192bc..a79860522d 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 0a30218400..637b762706 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 cfcc3c1176..3ba3c79a37 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 630ed6687c..e1f0804c0e 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 cd9dfd3e8a..8b586c9461 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 4902b6a631..aa07d1621a 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 5977121973..f9b45a6075 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 a45e2436b8..76ac4b18ac 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 2bda55b93f..d6e461b4c1 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 7052bf5a98..cad2907ac7 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 d264f8375d..b654aeadaf 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 ee37b5eb9c..82a81e5af7 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 12b5bf7789..46b1beef78 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 0a83ce4903..a5ccbb9100 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 1493751ab1..d0cc41da62 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 ce2a2800bb..a0e9fd9878 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 193d63f96c..119076e6a8 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 51a8fb499e..7b6710f6c4 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 0bb301298a..d80247abd6 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 e5e2be9af0..0000000000 --- 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 797715c33e..dc1ca25727 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 d54e1a90e7..b0ffe74fe6 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 214c091c3e..0cb28d1086 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 0000000000..45a486adf7 --- /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 0000000000..1483559120 --- /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 0a060dd1f7..7dfd2cc0eb 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 0000000000..3f4bc2105d --- /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 0000000000..108333bf86 --- /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 0000000000..b8a47501a8 --- /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 0000000000..26d236bcaa --- /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 0000000000..b99f593a10 --- /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 0000000000..3f68a44cff --- /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 375c5c6b0c..0efcae7c91 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 92426808b6..0000000000 --- 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 6b7752f813..0000000000 --- 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 3a15f620b2..0000000000 --- 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 226824c6ab..0000000000 --- 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 91138a4309..0000000000 --- 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 71dc56ef40..0000000000 --- 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 03e590f036..0000000000 --- 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 0e03bf6892..0000000000 --- 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 f1910fcfe3..0000000000 --- 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 607a03fef0..0000000000 --- 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 1b98392b81..0000000000 --- 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 57d0300b39..0000000000 --- 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 27f49e3ad9..0000000000 --- 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 076053b253..0000000000 --- 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 9f5640c69b..c811fd2b09 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 97abbdec38..0000000000 --- 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 33808a4d96..0000000000 --- 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 a1806692df..0000000000 --- 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 0000000000..50d75af813 --- /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 3ab3fb3b38..0000000000 --- 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 0000000000..5c0ea8ed1f --- /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 9701338e4b..0000000000 --- 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 c0734cd21f..0000000000 --- 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 d9452a8d79..0000000000 --- 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 0000000000..fe3ec5d2d5 --- /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 28947ac55e..f822078885 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 eb5594f3c9..0000000000 --- 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 7aa7b9d5db..0000000000 --- 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 0000000000..794078a3b3 --- /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 5ee424bd8d..f17bfa5d73 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 fa09d87f22..4756cc88ad 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 f0c22c9f59..1687016f85 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 0000000000..c477d26031 --- /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 0000000000..4c5c9e739b --- /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 35b9e9fbfd..4bdddc2ca6 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 fc702d3f63..ffbaed6cc7 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 0000000000..4b522c3552 --- /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 0000000000..185a3b60c7 --- /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 e14cd9c534..f97397fe4c 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 75eff694fa..9b5a526ca1 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 c672950a18..6196e71159 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 3f7faeac8e..ba433afb17 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 ea73d63f8d..0000000000 --- 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 bacef8541b..46e70c06ac 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 8b4e010d4b..602c00edf6 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 337d32652c..30c883becb 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 0000000000..1837380855 --- /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 0000000000..c313c6015e --- /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 dd02d3c17d..c4dec0abe8 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 80d6f00288..d18d503502 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 0000000000..f449ce991a --- /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 8d361c7060..2b9878e345 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 d5e8a16761..d2727d94d3 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 2ae79230d2..ad609cad73 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 c82d517d59..7820e2a416 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 85fdb33a8d..df9d22c5dc 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 bb7dcbe7bb..15fdb60349 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 0a12334701..0000000000 --- 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 d5328183f3..92493b6d38 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 44a7e7a259..50380a580a 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 7bb9af2a15..2d9abfa246 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 e7c6937cda..0000000000 --- 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 a4e5e0586f..8fc440c921 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 312bccff0f..1ac5faa11f 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 0000000000..d2a8e35320 --- /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 95dd82aafe..f778e46209 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 1fd5dff535..c84c5b4355 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 6015ab1302..6c6904e310 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 be9a36c819..cdca3b18ef 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 2c45af24d1..bac16de92e 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 94a9e138e9..50806f0da2 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 a39f27022c..667aeb186d 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 0000000000..f51af52b18 --- /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 c979eec0dc..7f04c7b3ee 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 6f0778a056..692609afb8 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 f377a846c6..0000000000 --- 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 0000000000..2cfdc1f8c4 --- /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 0000000000..808a2199f1 --- /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 0000000000..9f47dd6cf4 --- /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 0000000000..c0bfb0711f --- /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 48dc61b08e..d3aa156ea4 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 5a13dccc49..4f5eda2af9 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 1c489f4902..4c95c54c7b 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 5740e51b1e..000b125673 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 e5f9136362..b9e6e714dd 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 bf5be72fc4..4b9d28402c 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 86f3724fb5..ca3a2b8551 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 a95f8612c1..ad8915f5e3 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 93cca72284..51676ca04f 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 6d5e308c7a..27ecfcc87e 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 2307d00bcb..77ec2c1305 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 0000000000..5d1d487423 --- /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 e8c7acbfbf..9c26f814e9 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 64f53e5e55..e3b758e6b2 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 067b207d13..9f82dbec05 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 e6b49ec298..82936a1dc8 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 fc88f6b519..72250fbf1a 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 d962cfd3f4..048c6d3e3c 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 cd455dda5b..fd44b399ca 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 4d93845d98..2647e5a0d3 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 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 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/19] 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 f17bfa5d73..437f883ec3 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/19] 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 602c00edf6..1fad51fcd9 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/19] 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 d3e9b81e15..af5b67c16d 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/19] 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 185a3b60c7..a29ce75087 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 d2727d94d3..fdbcd422ad 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 ad609cad73..a49760a527 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/19] 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 a29ce75087..c7a7382855 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 1fad51fcd9..b115ffe94c 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 c4dec0abe8..e15a622950 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 fdbcd422ad..76a98e5c82 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 12b180fd54..a69ee36c7d 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 5d1d487423..e04287bc3f 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 9c26f814e9..3a84eb3a11 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 13962c7134..fbf206fbc6 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 fd44b399ca..f053065352 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/19] 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 8fc440c921..5c5805bfaf 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/19] 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 83ca646d89..67785f8585 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 d01e0e3506..e2cc152c8e 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/19] 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 4777f061d6..1e6d9790eb 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 3a84eb3a11..c2df9a30f0 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/19] 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 b0ffe74fe6..383d20ff18 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/19] 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 320e89d9b2..1f05a64fad 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 c474650f9a..89e265aed8 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 95fbc615c8..18fcee188b 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 953468af39..36ab00b656 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 38feee53e2..45eb41585d 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 e04287bc3f..8eb5f12a31 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 c2df9a30f0..39840c88f0 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 fbf206fbc6..c16999067b 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 87675e906e..1d8fa06e53 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 65c12df98e..90119baa49 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/19] 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 4e29827e89..b2a85e2076 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 1eeb6dff8d..0ecbe900d2 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 0cb28d1086..5d48ec1f3c 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 26d236bcaa..5a82e3f373 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 0000000000..c5dddfd7ac --- /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 5c0ea8ed1f..9ddce0c549 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 1687016f85..468f2861fa 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 c477d26031..f4bc6e4d68 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 09302235c3..c1c820a17f 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 36ab00b656..6b4e3b4586 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 2d9abfa246..a38ba9c695 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 feee1b00f4..c2430de0da 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/19] 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 46b1beef78..5b369dc9f4 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 d0cc41da62..2e087971bc 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 bea08693fb..f07cadb9e8 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) From cc21a1b405de93b7aedfc1fa07cc7f02b528b1d0 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Wed, 1 Oct 2014 18:32:24 +0930 Subject: [PATCH 17/19] Muzzle check/changeling check removal, thanks Harpy. --- code/modules/mob/living/carbon/human/say.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 2b9878e345..21b336a650 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -19,9 +19,6 @@ var/message_mode = parse_message_mode(message, "headset") - if (istype(wear_mask, /obj/item/clothing/mask/muzzle) && message_mode != "changeling") //Todo: Add this to speech_problem_flag checks. - return - if(copytext(message,1,2) == "*") return emote(copytext(message,2)) @@ -47,6 +44,9 @@ speaking.broadcast(src,trim(message)) return + if (istype(wear_mask, /obj/item/clothing/mask/muzzle)) + return + message = capitalize(trim(message)) if(speech_problem_flag) From 3fd8b64f864e7b070c6a3d105c2531af74f3a728 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Wed, 1 Oct 2014 22:21:34 +0930 Subject: [PATCH 18/19] Added new diona icons, added heat to alien life(), added fire indicator. --- baystation12.dme | 2 ++ code/_onclick/hud/alien_larva.dm | 8 +++++- .../living/carbon/alien/diona/update_icons.dm | 8 ++++++ .../mob/living/carbon/alien/larva/life.dm | 8 +++--- code/modules/mob/living/carbon/alien/life.dm | 23 +++++++++++++----- .../mob/living/carbon/alien/update_icons.dm | 2 -- icons/mob/alien.dmi | Bin 88728 -> 93777 bytes 7 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 code/modules/mob/living/carbon/alien/diona/update_icons.dm diff --git a/baystation12.dme b/baystation12.dme index 6b5a935141..2b31f2fb17 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -949,7 +949,9 @@ #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\diona\update_icons.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\progression.dm" #include "code\modules\mob\living\carbon\brain\brain.dm" #include "code\modules\mob\living\carbon\brain\brain_item.dm" diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm index b2a85e2076..5037353ff1 100644 --- a/code/_onclick/hud/alien_larva.dm +++ b/code/_onclick/hud/alien_larva.dm @@ -35,6 +35,12 @@ mymob.flash.screen_loc = "1,1 to 15,15" mymob.flash.layer = 17 + 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_fire + mymob.client.screen = null - mymob.client.screen += list( mymob.healths, mymob.blind, mymob.flash) //, mymob.rest, mymob.sleep, mymob.mach ) + mymob.client.screen += list( mymob.healths, mymob.blind, mymob.flash, mymob.fire) //, mymob.rest, mymob.sleep, mymob.mach ) mymob.client.screen += src.adding + src.other \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/diona/update_icons.dm b/code/modules/mob/living/carbon/alien/diona/update_icons.dm new file mode 100644 index 0000000000..b39972cdad --- /dev/null +++ b/code/modules/mob/living/carbon/alien/diona/update_icons.dm @@ -0,0 +1,8 @@ +/mob/living/carbon/alien/diona/update_icons() + + if(stat == DEAD) + icon_state = "[initial(icon_state)]_dead" + else if(lying || resting || stunned) + icon_state = "[initial(icon_state)]_sleep" + else + icon_state = "[initial(icon_state)]" diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm index c5dddfd7ac..8d40ef9d5a 100644 --- a/code/modules/mob/living/carbon/alien/larva/life.dm +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -1,12 +1,10 @@ //Larvae regenerate health and nutrition from plasma and alien weeds. -/mob/living/carbon/alien/larva/handle_environment() +/mob/living/carbon/alien/larva/handle_environment(var/datum/gas_mixture/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) + var/turf/T = get_turf(src) + if(environment.gas["phoron"] > 0 || (T && locate(/obj/effect/alien/weeds) in T.contents)) update_progression() adjustBruteLoss(-1) adjustFireLoss(-1) diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm index 9ddce0c549..7a51069fe8 100644 --- a/code/modules/mob/living/carbon/alien/life.dm +++ b/code/modules/mob/living/carbon/alien/life.dm @@ -22,7 +22,8 @@ blinded = null - handle_environment() + if(loc) + handle_environment(loc.return_air()) //Status updates, death etc. handle_regular_status_updates() @@ -36,6 +37,7 @@ 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. @@ -85,7 +87,6 @@ if(halloss > 0) adjustHalLoss(-3) - //CONSCIOUS else stat = CONSCIOUS if(halloss > 0) @@ -109,6 +110,8 @@ ear_deaf = max(ear_deaf-1, 0) ear_damage = max(ear_damage-0.05, 0) + update_icons() + return 1 /mob/living/carbon/alien/proc/handle_regular_hud_updates() @@ -174,7 +177,15 @@ 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 +/mob/living/carbon/alien/proc/handle_environment(var/datum/gas_mixture/environment) + // Both alien subtypes survive in vaccum and suffer in high temperatures, + // so I'll just define this once, for both (see radiation comment above) + if(!environment) return + + if(environment.temperature > (T0C+66)) + adjustFireLoss((environment.temperature - (T0C+66))/5) // Might be too high, check in testing. + if (fire) fire.icon_state = "fire2" + if(prob(20)) + src << "\red You feel a searing heat!" + else + if (fire) fire.icon_state = "fire0" diff --git a/code/modules/mob/living/carbon/alien/update_icons.dm b/code/modules/mob/living/carbon/alien/update_icons.dm index 794078a3b3..7bb90a4d9e 100644 --- a/code/modules/mob/living/carbon/alien/update_icons.dm +++ b/code/modules/mob/living/carbon/alien/update_icons.dm @@ -12,8 +12,6 @@ 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) diff --git a/icons/mob/alien.dmi b/icons/mob/alien.dmi index 24b09492de066773f5ba9988845a4846e6e4a487..2f31429878b2a40b8ba64228bb6e0d49bb3b9b4f 100644 GIT binary patch literal 93777 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 Date: Wed, 1 Oct 2014 23:34:50 +0930 Subject: [PATCH 19/19] Changelog. --- html/changelog.html | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/html/changelog.html b/html/changelog.html index 5afb3a0ecf..fecd3052c1 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,7 +56,49 @@ should be listed in the changelog upon commit though. Thanks. --> -+

+
+

1 October 2014

+

Zuhayr updated:

+
    +
  • Added species organ checks to several areas (phoron burn, welder burn, appendicitis, vox cortical stacks, flashes).
  • +
  • Added VV option to add or remove organs.
  • +
  • Added simple bioprinter (adminspawn).
  • +
  • Added smashing/slashing behavior from xenos to some unarmed attacks.
  • +
  • Added some new state icons for diona nymphs.
  • +
  • Added borer husk functionality (cortical borers can turn dead humans into zombies).
  • +
  • Added tackle verb.
  • +
  • Added NO_SLIP.
  • +
  • Added species-specific orans to Dionaea, new Xenomorphs and vox.
  • +
  • Added colour and species to blood data.
  • +
  • Added lethal consequences to missing your heart.
  • +
  • Removed robot_talk_understand and alien_talk_understand.
  • +
  • Removed attack_alien() and several flavours of is_alien() procs.
  • +
  • Removed /mob/living/carbon/alien/humanoid.
  • +
  • Removed alien_hud().
  • +
  • Removed IS_SLOW, NEEDS_LIGHT and RAD_ABSORB.
  • +
  • Renamed is_larva() to is_alien().
  • +
  • Refactored a ton of files, either condensing or expanding them, or moving them to new directories.
  • +
  • Refactored some attack vars from simple_animal to mob/living level.
  • +
  • Refactored internal organs to /mob/living/carbon level.
  • +
  • Refactored rad and light absorbtion to organ level.
  • +
  • Refactored brains to /obj/item/organ/brain.
  • +
  • Refactored a lot of blood splattering to use blood_splatter() proc.
  • +
  • Refactored broadcast languages (changeling and alien hiveminds, drone and binary chat) to actual languages.
  • +
  • Refactored xenomorph abilities to work for humans.
  • +
  • Refactored xenomorphs into human species.
  • +
  • Rewrote larva_hud() and human_hud(). The latter now takes data from the species datum.
  • +
  • Rewrote diona nymphs as descendents of /mob/living/carbon/alien.
  • +
  • Rewrote xenolarva as descendents of /mob/living/carbon/alien.
  • +
  • Rewrote /mob/living/carbon/alien.
  • +
  • Moved alcohol and toxin processing to the liver.
  • +
  • Moved drone light proc to robot level, added integrated_light_power and local_transmit vars to robots.
  • +
  • Moved human brainloss onto the brain organ.
  • +
  • Shuffled around and collapsed several redundant procs down to carbon level (hide, ventcrawl, Bump).
  • +
  • Fixed species swaps from NO_BLOOD to those with blood killing the subject instantly.
  • +
+
+ +

28 September 2014

Gamerofthegame updated: