diff --git a/code/__DEFINES/~yogs_defines/is_helpers.dm b/code/__DEFINES/~yogs_defines/is_helpers.dm index bda2fe14f2e7..934572c7b3f8 100644 --- a/code/__DEFINES/~yogs_defines/is_helpers.dm +++ b/code/__DEFINES/~yogs_defines/is_helpers.dm @@ -3,3 +3,5 @@ #define is_shadow_or_thrall(M) (is_thrall(M) || is_shadow(M)) #define isspacepod(A) (istype(A, /obj/spacepod)) + +#define ispreternis(A) (is_species(A, /datum/species/preternis)) \ No newline at end of file diff --git a/code/__DEFINES/~yogs_defines/mobs.dm b/code/__DEFINES/~yogs_defines/mobs.dm new file mode 100644 index 000000000000..0ef3d1f09169 --- /dev/null +++ b/code/__DEFINES/~yogs_defines/mobs.dm @@ -0,0 +1,13 @@ +#define PRETERNIS_LEVEL_FULL 550 +#define PRETERNIS_LEVEL_WELL_FED 450 +#define PRETERNIS_LEVEL_FED 350 +#define PRETERNIS_LEVEL_HUNGRY 250 +#define PRETERNIS_LEVEL_STARVING 150 +#define PRETERNIS_LEVEL_NONE 0 + +#define ELECTRICITY_TO_NUTRIMENT_FACTOR 0.44 //1 power unit to 44 preternis charge they can uncharge an apc to 50% at most + +#define PRETERNIS_NV_OFF 2 //numbers of tile they can see +#define PRETERNIS_NV_ON 8 + +#define BODYPART_ANY -1 //use this when healing with something that needs a specefied bodypart type for all diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm index f8752e798591..30e4a5ba5b41 100644 --- a/code/modules/mob/living/carbon/damage_procs.dm +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -117,7 +117,7 @@ var/list/obj/item/bodypart/parts = list() for(var/X in bodyparts) var/obj/item/bodypart/BP = X - if(status && (BP.status != status)) + if(!(status == BODYPART_ANY) && (status && (BP.status != status))) //yogs - allows robot limb healing override continue if((brute && BP.brute_dam) || (burn && BP.burn_dam) || (stamina && BP.stamina_dam)) parts += BP diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index a896df17ba64..0905b432d807 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -338,7 +338,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/dynamic_fhair_suffix = "" //for augmented heads - if(HD.status == BODYPART_ROBOTIC) + if(HD.status == BODYPART_ROBOTIC && !yogs_draw_robot_hair) //yogs - allow for robot head hair return //we check if our hat or helmet hides our facial hair. diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index a858cd1a966e..0133856dcb71 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -148,7 +148,7 @@ if(owner && (owner.status_flags & GODMODE)) return FALSE //godmode - if(required_status && (status != required_status)) + if(!(required_status == -1) && (required_status && (status != required_status))) //yogs -- adds in BODYPART_ANY return FALSE var/dmg_mlt = CONFIG_GET(number/damage_multiplier) @@ -197,8 +197,8 @@ //Damage cannot go below zero. //Cannot remove negative damage (i.e. apply damage) /obj/item/bodypart/proc/heal_damage(brute, burn, stamina, required_status, updating_health = TRUE) - - if(required_status && (status != required_status)) //So we can only heal certain kinds of limbs, ie robotic vs organic. + // yogs -- line below updated to allow for robotic body part healing override + if(!(required_status == BODYPART_ANY) && (required_status && (status != required_status)) ) //So we can only heal certain kinds of limbs, ie robotic vs organic. return brute_dam = round(max(brute_dam - brute, 0), DAMAGE_PRECISION) diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 23f54fefae97..022405011ace 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -195,7 +195,7 @@ . = ..() if(dropped) //certain overlays only appear when the limb is being detached from its owner. - if(status != BODYPART_ROBOTIC) //having a robotic head hides certain features. + if(status != BODYPART_ROBOTIC || yogs_draw_robot_hair) //having a robotic head hides certain features. //yogs -- preternis hair //facial hair if(facial_hair_style) var/datum/sprite_accessory/S = GLOB.facial_hair_styles_list[facial_hair_style] diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index c37337936d84..02dd25878aa4 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -18,7 +18,8 @@ /datum/language/ratvar, /datum/language/aphasia, /datum/language/piratespeak, - /datum/language/japanese //yogs + /datum/language/japanese, + /datum/language/machine //yogs )) /obj/item/organ/tongue/Initialize(mapload) diff --git a/config/game_options.txt b/config/game_options.txt index b2c681e772e1..f0fad9ef9cda 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -445,6 +445,7 @@ ROUNDSTART_RACES lizard #ROUNDSTART_RACES moth ROUNDSTART_RACES plasmaman #ROUNDSTART_RACES shadow +ROUNDSTART_RACES preternis ## Races that are better than humans in some ways, but worse in others ROUNDSTART_RACES ethereal diff --git a/yogstation.dme b/yogstation.dme index 26eedf4896bc..3ed3f0aeb7e2 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -117,6 +117,7 @@ #include "code\__DEFINES\~yogs_defines\keybindings.dm" #include "code\__DEFINES\~yogs_defines\logging.dm" #include "code\__DEFINES\~yogs_defines\mentor.dm" +#include "code\__DEFINES\~yogs_defines\mobs.dm" #include "code\__DEFINES\~yogs_defines\preferences.dm" #include "code\__DEFINES\~yogs_defines\shuttles.dm" #include "code\__DEFINES\~yogs_defines\spacepods.dm" @@ -2813,7 +2814,9 @@ #include "yogstation\code\datums\components\uplink.dm" #include "yogstation\code\datums\components\walks.dm" #include "yogstation\code\datums\components\storage\storage.dm" +#include "yogstation\code\datums\diseases\_MobProcs.dm" #include "yogstation\code\datums\diseases\cluwnification.dm" +#include "yogstation\code\datums\diseases\advance\advance.dm" #include "yogstation\code\datums\diseases\advance\symptoms\confusion.dm" #include "yogstation\code\datums\diseases\advance\symptoms\heal.dm" #include "yogstation\code\datums\mood_events\generic_positive_events.dm" @@ -3071,6 +3074,10 @@ #include "yogstation\code\modules\mob\living\carbon\human\species_types\jellypeople.dm" #include "yogstation\code\modules\mob\living\carbon\human\species_types\lizard.dm" #include "yogstation\code\modules\mob\living\carbon\human\species_types\plantpeople.dm" +#include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\organs.dm" +#include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\power_suck.dm" +#include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\preternis.dm" +#include "yogstation\code\modules\mob\living\carbon\human\species_types\preternis\screen_alerts.dm" #include "yogstation\code\modules\mob\living\silicon\silicon.dm" #include "yogstation\code\modules\mob\living\silicon\ai\ai.dm" #include "yogstation\code\modules\mob\living\silicon\ai\vox_sounds.dm" @@ -3159,6 +3166,7 @@ #include "yogstation\code\modules\stock_market\logs.dm" #include "yogstation\code\modules\stock_market\stockmarket.dm" #include "yogstation\code\modules\stock_market\stocks.dm" +#include "yogstation\code\modules\surgery\bodypart.dm" #include "yogstation\code\modules\surgery\tools.dm" #include "yogstation\code\modules\surgery\organs\shadowling_organs.dm" #include "yogstation\code\modules\uplink\uplink_item.dm" diff --git a/yogstation/code/datums/diseases/_MobProcs.dm b/yogstation/code/datums/diseases/_MobProcs.dm new file mode 100644 index 000000000000..074271f0afc0 --- /dev/null +++ b/yogstation/code/datums/diseases/_MobProcs.dm @@ -0,0 +1,5 @@ +/mob/living/carbon/human/CanContractDisease(datum/disease/D) + var/infectchance = dna.species ? dna.species.yogs_virus_infect_chance : 100 //will this compile? who knows + if(prob(infectchance)) + return ..() + return FALSE \ No newline at end of file diff --git a/yogstation/code/datums/diseases/advance/advance.dm b/yogstation/code/datums/diseases/advance/advance.dm new file mode 100644 index 000000000000..44c416ee694c --- /dev/null +++ b/yogstation/code/datums/diseases/advance/advance.dm @@ -0,0 +1,9 @@ +/datum/disease/advance/Refresh(new_name) + ..() + if(affected_mob?.dna) + var/datum/species/S = affected_mob.dna.species + properties["resistance"] += S.virus_resistance_boost + properties["stealth"] += S.virus_stealth_boost + properties["stage_rate"] += S.virus_stage_rate_boost + properties["transmittable"] += S.virus_transmittable_boost + AssignProperties() //this is a bit inefficent because its called twice but modularization amiright? \ No newline at end of file diff --git a/yogstation/code/modules/mob/living/carbon/human/species.dm b/yogstation/code/modules/mob/living/carbon/human/species.dm index 30147d61e0b3..612355a461d1 100644 --- a/yogstation/code/modules/mob/living/carbon/human/species.dm +++ b/yogstation/code/modules/mob/living/carbon/human/species.dm @@ -3,8 +3,30 @@ //////////////////// /obj/item/bodypart var/should_draw_yogs = FALSE - + /mob/living/carbon/proc/draw_yogs_parts(do_it) for(var/O in bodyparts) var/obj/item/bodypart/B = O - B.should_draw_yogs = do_it \ No newline at end of file + B.should_draw_yogs = do_it + +/datum/species + var/yogs_draw_robot_hair = FALSE //DAMN ROBOTS STEALING OUR HAIR AND AIR + var/yogs_virus_infect_chance = 100 + var/virus_resistance_boost = 0 + var/virus_stealth_boost = 0 + var/virus_stage_rate_boost = 0 + var/virus_transmittable_boost = 0 + +/datum/species/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) + . = ..() + if(yogs_draw_robot_hair) + for(var/obj/item/bodypart/BP in C.bodyparts) + BP.yogs_draw_robot_hair = TRUE + +/datum/species/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) + . = ..() + for(var/obj/item/bodypart/BP in C.bodyparts) + BP.yogs_draw_robot_hair = initial(BP.yogs_draw_robot_hair) + +/datum/species/proc/spec_AltClickOn(atom/A,mob/living/carbon/human/H) + return FALSE diff --git a/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/organs.dm b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/organs.dm new file mode 100644 index 000000000000..2206003e834d --- /dev/null +++ b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/organs.dm @@ -0,0 +1,62 @@ +/obj/item/organ/eyes/preternis + name = "preternis eyes" + desc = "An experimental upgraded version of eyes that can see in the dark.They are designed to fit preternis" + see_in_dark = PRETERNIS_NV_ON + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE + actions_types = list(/datum/action/item_action/organ_action/use) + var/night_vision = TRUE + +/obj/item/organ/eyes/preternis/ui_action_click() + var/datum/species/preternis/S = owner.dna.species + if(S.charge < PRETERNIS_LEVEL_FED) + return + sight_flags = initial(sight_flags) + switch(lighting_alpha) + if (LIGHTING_PLANE_ALPHA_VISIBLE) + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE + if (LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE) + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + if (LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE) + lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE + else + lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE + sight_flags &= ~SEE_BLACKNESS + owner.update_sight() + +/obj/item/organ/eyes/preternis/on_life() + . = ..() + if(!ispreternis(owner)) + qdel(src) //these eyes depend on being inside a preternis + return + var/datum/species/preternis/S = owner.dna.species + if(S.charge >= PRETERNIS_LEVEL_FED) + if(see_in_dark == PRETERNIS_NV_OFF) + see_in_dark = PRETERNIS_NV_ON + owner.update_sight() + else + if(see_in_dark == PRETERNIS_NV_ON) + see_in_dark = PRETERNIS_NV_OFF + owner.update_sight() + if(lighting_alpha < LIGHTING_PLANE_ALPHA_VISIBLE) + lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE + sight_flags &= ~SEE_BLACKNESS + owner.update_sight() + +/obj/item/organ/lungs/preternis + name = "preternis lungs" + desc = "An experimental set of lungs.Due to the cybernetic nature of these lungs,they are less resistant to heat and cold but are more efficent at filtering oxygen." + icon_state = "lungs-c" + safe_oxygen_min = 12 + safe_toxins_max = 10 + gas_stimulation_min = 0.1 //fucking filters removing my stimulants + + cold_level_1_threshold = 280 + cold_level_1_damage = 1.5 + cold_level_2_threshold = 260 + cold_level_2_damage = 3 + cold_level_3_threshold = 200 + cold_level_3_damage = 4.5 + + heat_level_1_threshold = 320 + heat_level_2_threshold = 400 + heat_level_3_threshold = 600 //HALP MY LUNGS ARE ON FIRE diff --git a/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/power_suck.dm b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/power_suck.dm new file mode 100644 index 000000000000..7eeb693c948f --- /dev/null +++ b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/power_suck.dm @@ -0,0 +1,186 @@ +/mob/living/carbon/AltClickOn(atom/A) + dna?.species.spec_AltClickOn(A,src) + return ..() + +/datum/species/preternis/spec_AltClickOn(atom/A,H) + return drain_power_from(H, A) + +/datum/species/preternis/proc/drain_power_from(mob/living/carbon/human/H, atom/A) + if(!istype(H) || !A) + return FALSE + + if(draining) + to_chat(H,"CONSUME protocols can only be used on one object at any single time.") + return FALSE + if(!A.can_consume_power_from()) + return FALSE //if it returns text, we want it to continue so we can get the error message later. + + draining = TRUE + + var/siemens_coefficient = 1 + + if(H.reagents.has_reagent("teslium")) + siemens_coefficient *= 1.5 + + if (charge >= PRETERNIS_LEVEL_FULL - 25) //just to prevent spam a bit + to_chat(H,"CONSUME protocol reports no need for additional power at this time.") + draining = FALSE + return TRUE + + if(H.gloves) + if(!H.gloves.siemens_coefficient) + to_chat(H,"NOTICE: [H.gloves] prevent electrical contact - CONSUME protocol aborted.") + draining = FALSE + return TRUE + else + if(H.gloves.siemens_coefficient < 1) + to_chat(H,"NOTICE: [H.gloves] are interfering with electrical contact - advise removal before activating CONSUME protocol.") + siemens_coefficient *= H.gloves.siemens_coefficient + + H.face_atom(A) + H.visible_message("[H] starts placing their hands on [A]...", "You start placing your hands on [A]...") + if(!do_after(H, 20, target = A)) + to_chat(H,"CONSUME protocol aborted.") + draining = FALSE + return TRUE + + to_chat(H,"Extracutaneous implants detect viable power source. Initiating CONSUME protocol.") + + var/done = FALSE + var/drain = 150 * siemens_coefficient + + var/cycle = 0 + var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread() + spark_system.attach(A) + spark_system.set_up(5, 0, A) + + + + while(!done) + cycle++ + var/nutritionIncrease = drain * ELECTRICITY_TO_NUTRIMENT_FACTOR + + if(charge + nutritionIncrease > PRETERNIS_LEVEL_FULL) + nutritionIncrease = CLAMP(PRETERNIS_LEVEL_FULL - charge, PRETERNIS_LEVEL_NONE,PRETERNIS_LEVEL_FULL) //if their nutrition goes up from some other source, this could be negative, which would cause bad things to happen. + drain = nutritionIncrease/ELECTRICITY_TO_NUTRIMENT_FACTOR + + if (do_after(H,5, target = A)) + var/can_drain = A.can_consume_power_from() + if(!can_drain || istext(can_drain)) + if(istext(can_drain)) + to_chat(H,can_drain) + done = TRUE + else + playsound(A.loc, "sparks", 50, 1) + if(prob(75)) + spark_system.start() + var/drained = A.consume_power_from(drain) + if(drained < drain) + to_chat(H,"[A]'s power has been depleted, CONSUME protocol halted.") + done = TRUE + charge = CLAMP(charge + (drained * ELECTRICITY_TO_NUTRIMENT_FACTOR),PRETERNIS_LEVEL_NONE,PRETERNIS_LEVEL_FULL) + + if(!done) + if(charge > (PRETERNIS_LEVEL_FULL - 25)) + to_chat(H,"CONSUME protocol complete. Physical nourishment refreshed.") + done = TRUE + else if(!(cycle % 4)) + var/nutperc = round((charge / PRETERNIS_LEVEL_FULL) * 100) + to_chat(H,"CONSUME protocol continues. Current satiety level: [nutperc]%.") + else + done = TRUE + qdel(spark_system) + draining = FALSE + return TRUE + +/atom/proc/can_consume_power_from() + return FALSE //if a string is returned, it will evaluate as false and be output to the person draining. + +/atom/proc/consume_power_from(amount) + return FALSE //return the amount that was drained. + +#define MIN_DRAINABLE_POWER 10 + +//CELL// +/obj/item/stock_parts/cell/can_consume_power_from() + if(charge < MIN_DRAINABLE_POWER) + return "Power cell depleted, cannot consume power." + return TRUE + +/obj/item/stock_parts/cell/consume_power_from(amount) + if((charge - amount) < MIN_DRAINABLE_POWER) + amount = max(charge - MIN_DRAINABLE_POWER, 0) + use(amount) + return amount + +//APC// +/obj/machinery/power/apc/can_consume_power_from() + if(!cell) + return "APC cell absent, cannot consume power." + if(stat & BROKEN) + return "APC is damaged, cannot consume power." + if(!operating || shorted) + return "APC main breaker is off, cannot consume power." + if(cell.charge < MIN_DRAINABLE_POWER) + return "APC cell depleted, cannot consume power." + return TRUE + +/obj/machinery/power/apc/consume_power_from(amount) + if((cell.charge - amount) < MIN_DRAINABLE_POWER) + amount = max(cell.charge - MIN_DRAINABLE_POWER, 0) + cell.use(amount) + if(charging == 2) + charging = 0 //if we do not do this here, the APC can get stuck thinking it is fully charged. + update() + return amount + +//SMES// +/obj/machinery/power/smes/can_consume_power_from() + if(stat & BROKEN) + return "SMES is damaged, cannot consume power." + if(!output_attempt) + return "SMES is not outputting power, cannot consume power." + if(charge < MIN_DRAINABLE_POWER) + return "SMES cells depleted, cannot consume power." + return TRUE + +/obj/machinery/power/smes/consume_power_from(amount) + if((charge - amount) < MIN_DRAINABLE_POWER) + amount = max(charge - MIN_DRAINABLE_POWER, 0) + charge -= amount + return amount + +//MECH// +/obj/mecha/can_consume_power_from() + if(!cell) + return "Mech power cell absent, cannot consume power." + if(cell.charge < MIN_DRAINABLE_POWER) + return "Mech power cell depleted, cannot consume power." + return TRUE + +/obj/mecha/consume_power_from(amount) + occupant_message("Warning: Unauthorized access through sub-route 4, block H, detected.") + if((cell.charge - amount) < MIN_DRAINABLE_POWER) + amount = max(cell.charge - MIN_DRAINABLE_POWER, 0) + cell.use(amount) + return amount + +//BORG// +/mob/living/silicon/robot/can_consume_power_from() + if(!cell) + return "Cyborg power cell absent, cannot consume power." + if(cell.charge < MIN_DRAINABLE_POWER) + return "Cyborg power cell depleted, cannot consume power." + return TRUE + +/mob/living/silicon/robot/consume_power_from(amount) + src << "Warning: Unauthorized access through sub-route 12, block C, detected." + if((cell.charge - amount) < MIN_DRAINABLE_POWER) + amount = max(cell.charge - MIN_DRAINABLE_POWER, 0) + cell.use(amount) + return amount + +#undef MIN_DRAINABLE_POWER + + + diff --git a/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/preternis.dm b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/preternis.dm new file mode 100644 index 000000000000..804cf556940f --- /dev/null +++ b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/preternis.dm @@ -0,0 +1,161 @@ +/* +procs: + +handle_charge - called in spec_life(),handles the alert indicators,the power loss death and decreasing the charge level +adjust_charge - take a positive or negative value to adjust the charge level +*/ + +/datum/species/preternis + name = "Preternis" + id = "preternis" + default_color = "FFFFFF" + changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT + inherent_traits = list(TRAIT_NOHUNGER,TRAIT_RADIMMUNE) + species_traits = list(EYECOLOR,HAIR,LIPS) + say_mod = "intones" + attack_verb = "assault" + meat = null + toxic_food = NONE + brutemod = 1.25 + burnmod = 1.5 + yogs_draw_robot_hair = TRUE + mutanteyes = /obj/item/organ/eyes/preternis + mutantlungs = /obj/item/organ/lungs/preternis + yogs_virus_infect_chance = 20 + virus_resistance_boost = 10 //YEOUTCH,good luck getting it out + + var/charge = PRETERNIS_LEVEL_FULL + var/eating_msg_cooldown = FALSE + var/emag_lvl = 0 + var/power_drain = 0.5 //probably going to have to tweak this shit + var/tesliumtrip = FALSE + var/draining = FALSE + + +/datum/species/preternis/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) + . = ..() + for (var/V in C.bodyparts) + var/obj/item/bodypart/BP = V + BP.change_bodypart_status(ORGAN_ROBOTIC,FALSE,TRUE) + BP.burn_reduction = 0 + BP.brute_reduction = 0 + if(istype(BP,/obj/item/bodypart/chest) || istype(BP,/obj/item/bodypart/head)) + continue + BP.max_damage = 35 + C.grant_language(/datum/language/machine) //learn it once,learn it forever i guess,this isnt removed on species loss to prevent curators from forgetting machine language + +/datum/species/preternis/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) + . = ..() + for (var/V in C.bodyparts) + var/obj/item/bodypart/BP = V + BP.change_bodypart_status(ORGAN_ORGANIC,FALSE,TRUE) + BP.burn_reduction = initial(BP.burn_reduction) + BP.brute_reduction = initial(BP.brute_reduction) + C.clear_alert("preternis_emag") //this means a changeling can transform from and back to a preternis to clear the emag status but w/e i cant find a solution to not do that + C.clear_fullscreen("preternis_emag") + C.remove_movespeed_modifier("preternis_teslium") + +/datum/species/preternis/spec_emp_act(mob/living/carbon/human/H, severity) + . = ..() + switch(severity) + if(EMP_HEAVY) + H.adjustBruteLoss(20) + H.adjustFireLoss(20) + H.Paralyze(50) + charge *= 0.4 + H.visible_message("Electricity ripples over [H]'s subdermal implants, smoking profusely.", \ + "A surge of searing pain erupts throughout your very being! As the pain subsides, a terrible sensation of emptiness is left in its wake.") + if(EMP_LIGHT) + H.adjustBruteLoss(10) + H.adjustFireLoss(10) + H.Paralyze(20) + charge *= 0.6 + H.visible_message("A faint fizzling emanates from [H].", \ + "A fit of twitching overtakes you as your subdermal implants convulse violently from the electromagnetic disruption. Your sustenance reserves have been partially depleted from the blast.") + +/datum/species/preternis/spec_emag_act(mob/living/carbon/human/H, mob/user) + . = ..() + if(emag_lvl == 2) + return + emag_lvl = min(emag_lvl + 1,2) + playsound(H.loc, 'sound/machines/warning-buzzer.ogg', 50, 1, 1) + H.Paralyze(60) + switch(emag_lvl) + if(1) + H.adjustBrainLoss(50) //HALP AM DUMB + to_chat(H,"ALERT! MEMORY UNIT [rand(1,5)] FAILURE.NERVEOUS SYSTEM DAMAGE.") + if(2) + H.overlay_fullscreen("preternis_emag", /obj/screen/fullscreen/high) + H.throw_alert("preternis_emag", /obj/screen/alert/high/preternis) + to_chat(H,"ALERT! OPTIC SENSORS FAILURE.VISION PROCESSOR COMPROMISED.") + +/datum/species/preternis/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + . = ..() + + if(H.reagents.has_reagent("oil")) + H.adjustFireLoss(-2*REAGENTS_EFFECT_MULTIPLIER,FALSE,FALSE, BODYPART_ANY) + + if(H.reagents.has_reagent("welding_fuel")) + H.adjustFireLoss(-1*REAGENTS_EFFECT_MULTIPLIER,FALSE,FALSE, BODYPART_ANY) + + if(H.reagents.has_reagent("teslium",10)) //10 u otherwise it wont update and they will remain quikk + H.add_movespeed_modifier("preternis_teslium", update=TRUE, priority=101, multiplicative_slowdown=-2, blacklisted_movetypes=(FLYING|FLOATING)) + if(H.health < 50 && H.health > 0) + H.adjustOxyLoss(-1*REAGENTS_EFFECT_MULTIPLIER) + H.adjustBruteLoss(-1*REAGENTS_EFFECT_MULTIPLIER,FALSE,FALSE, BODYPART_ANY) + H.adjustFireLoss(-1*REAGENTS_EFFECT_MULTIPLIER,FALSE,FALSE, BODYPART_ANY) + H.AdjustParalyzed(-3) + H.AdjustStun(-3) + H.AdjustKnockdown(-3) + H.adjustStaminaLoss(-5*REAGENTS_EFFECT_MULTIPLIER) + charge = CLAMP(charge - 10 * REAGENTS_METABOLISM,PRETERNIS_LEVEL_NONE,PRETERNIS_LEVEL_FULL) + burnmod = 200 + tesliumtrip = TRUE + else if(tesliumtrip) + burnmod = initial(burnmod) + tesliumtrip = FALSE + H.remove_movespeed_modifier("preternis_teslium") + + if (istype(chem,/datum/reagent/consumable)) + var/datum/reagent/consumable/food = chem + if (food.nutriment_factor) + var/nutrition = food.nutriment_factor * 0.2 + charge = CLAMP(charge + nutrition,PRETERNIS_LEVEL_NONE,PRETERNIS_LEVEL_FULL) + if (!eating_msg_cooldown) + eating_msg_cooldown = TRUE + addtimer(VARSET_CALLBACK(src, eating_msg_cooldown, FALSE), 2 MINUTES) + to_chat(H,"NOTICE: Digestive subroutines are inefficient. Seek sustenance via power-cell C.O.N.S.U.M.E. technology induction.") + + if(chem.current_cycle >= 20) + H.reagents.del_reagent(chem.id) + + + return FALSE + +/datum/species/preternis/spec_fully_heal(mob/living/carbon/human/H) + . = ..() + charge = PRETERNIS_LEVEL_FULL + emag_lvl = 0 + H.clear_alert("preternis_emag") + H.clear_fullscreen("preternis_emag") + burnmod = initial(burnmod) + tesliumtrip = FALSE + H.remove_movespeed_modifier("preternis_teslium") //full heal removes chems so it wont update the teslium speed up until they eat something + +/datum/species/preternis/spec_life(mob/living/carbon/human/H) + . = ..() + handle_charge(H) + +/datum/species/preternis/proc/handle_charge(mob/living/carbon/human/H) + charge = CLAMP(charge - power_drain,PRETERNIS_LEVEL_NONE,PRETERNIS_LEVEL_FULL) + if(charge == PRETERNIS_LEVEL_NONE) + to_chat(H,"Warning! System power criti-$#@$") + H.death() + else if(charge < PRETERNIS_LEVEL_STARVING) + H.throw_alert("preternis_charge", /obj/screen/alert/preternis_charge, 3) + else if(charge < PRETERNIS_LEVEL_HUNGRY) + H.throw_alert("preternis_charge", /obj/screen/alert/preternis_charge, 2) + else if(charge < PRETERNIS_LEVEL_FED) + H.throw_alert("preternis_charge", /obj/screen/alert/preternis_charge, 1) + else + H.clear_alert("preternis_charge") diff --git a/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/screen_alerts.dm b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/screen_alerts.dm new file mode 100644 index 000000000000..9a8045f43cd5 --- /dev/null +++ b/yogstation/code/modules/mob/living/carbon/human/species_types/preternis/screen_alerts.dm @@ -0,0 +1,8 @@ +/obj/screen/alert/high/preternis + name = "Optic sensor failure" + desc = "Main unit optic sensors damage detected.Vision processor compromised" + +/obj/screen/alert/preternis_charge + name = "Low power" + desc = "Find a power cell to recharge from or you may lose power." + icon_state = "lowcell" \ No newline at end of file diff --git a/yogstation/code/modules/surgery/bodypart.dm b/yogstation/code/modules/surgery/bodypart.dm new file mode 100644 index 000000000000..14ac6280c2fc --- /dev/null +++ b/yogstation/code/modules/surgery/bodypart.dm @@ -0,0 +1,2 @@ +/obj/item/bodypart + var/yogs_draw_robot_hair = FALSE \ No newline at end of file