Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions code/__DEFINES/is_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isdullahan(A) (is_species(A, /datum/species/dullahan))
#define ismonkey(A) (is_species(A, /datum/species/monkey))
#define isandroid(A) (is_species(A, /datum/species/android))
#define ispreternis(A) (is_species(A, /datum/species/preternis))

//more carbon mobs

Expand Down
14 changes: 14 additions & 0 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,17 @@

//Saves a proc call, life is suffering. If who has no targets_from var, we assume it's just who
#define GET_TARGETS_FROM(who) (who.targets_from ? who.get_targets_from() : who)

#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
1 change: 1 addition & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NOSOFTCRIT "nosoftcrit"
#define TRAIT_MINDSHIELD "mindshield"
#define TRAIT_DISSECTED "dissected"
#define TRAIT_MEDICALIGNORE "medical_ignore"
/// Can hear observers
#define TRAIT_SIXTHSENSE "sixth_sense"
#define TRAIT_FEARLESS "fearless"
Expand Down
4 changes: 4 additions & 0 deletions code/datums/diseases/_MobProcs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@
if(HAS_TRAIT(src, TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity)
return FALSE

var/infectchance = dna.species ? dna.species.virus_infect_chance : 100
if(!prob(infectchance))
return FALSE

for(var/thing in D.required_organs)
if(!((locate(thing) in bodyparts) || (locate(thing) in internal_organs)))
return FALSE
Expand Down
7 changes: 7 additions & 0 deletions code/datums/diseases/advance/advance.dm
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@
SSdisease.archive_diseases[the_id] = Copy()
if(new_name)
AssignName()
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()

//Generate disease properties based on the effects. Returns an associated list.
/datum/disease/advance/proc/GenerateProperties()
Expand Down
4 changes: 2 additions & 2 deletions code/game/objects/items/defib.dm
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,8 @@
var/mobhealth = H.health
H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0)
H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0, TRUE) // force tox heal for toxin lovers too
H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0)
H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0, required_status = BODYPART_ANY)
H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0, required_status = BODYPART_ANY)
H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually.
user.visible_message(span_notice("[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful."))
playsound(src, 'sound/machines/defib_success.ogg', 50, FALSE)
Expand Down
32 changes: 32 additions & 0 deletions code/game/objects/items/inducer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,38 @@
if(istype(A, /obj/item/gun/energy))
to_chat(user, span_alert("Error unable to interface with device."))
return FALSE
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(ispreternis(H)) //let's charge some dumb robot players
if(user.zone_selected != BODY_ZONE_CHEST)
to_chat(user, span_warning("You need to target [A]'s chest with [src] to recharge [H.p_them()]!"))
recharging = FALSE
return TRUE
coefficient = 0.1
var/totransfer = min(cell.charge,(powertransfer * coefficient))
var/datum/species/preternis/preternis = H.dna.species
var/done_any = FALSE
if(preternis.charge >= PRETERNIS_LEVEL_FULL - 25)
to_chat(user, span_notice("[A] is fully charged!"))
recharging = FALSE
return TRUE
user.visible_message("[user] starts recharging [A] with [src].",span_notice("You start recharging [A] with [src]."))
while(preternis.charge < PRETERNIS_LEVEL_FULL - 25)
if(do_after(user, 1 SECONDS, target = user) && cell.charge)
done_any = TRUE
cell.use(totransfer*coefficient)
preternis.charge = clamp(preternis.charge + (powertransfer*coefficient), PRETERNIS_LEVEL_NONE, PRETERNIS_LEVEL_FULL)
H.apply_damage(totransfer*coefficient, BURN, BODY_ZONE_CHEST, wound_bonus = CANT_WOUND)
user.visible_message("Smoke rises off of [A]'s body!",span_notice("You smell something burning as [A] is charged by the [src]!"))
do_sparks(1, FALSE, A)
if(O)
O.update_icon()
else
break
if(done_any) // Only show a message if we succeeded at least once
user.visible_message("[user] recharged [A]!",span_notice("You recharged [A]!"))
recharging = FALSE
return TRUE
if(istype(A, /obj))
O = A
if(C)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
..()
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
if(E)
if(istype(E, /obj/item/organ/eyes/robotic/preternis))
E.Remove(user, 1)
var/obj/item/organ/eyes/neweyes = new(user)
neweyes.Insert(user, 1)
neweyes.flash_protect = 2
if(!active)
E.sight_flags |= SEE_MOBS | SEE_OBJS | SEE_TURFS //Add sight flags to the user's eyes
E.flash_protect = FLASH_PROTECTION_SENSITIVE //Adjust the user's eyes' flash protection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ GLOBAL_VAR_INIT(cryo_overlay_cover_off, mutable_appearance('icons/obj/cryogenics
return
if(mob_occupant.stat == DEAD) // We don't bother with dead people.
return

if(HAS_TRAIT(mob_occupant,TRAIT_MEDICALIGNORE) && !(mob_occupant.getCloneLoss() + mob_occupant.getToxLoss() + mob_occupant.getOxyLoss()))
src.visible_message("<span class='warning'>[src] is unable to treat [mob_occupant] as they cannot be treated with conventional medicine.</span>")
playsound(src,'sound/machines/cryo_warning_ignore.ogg',60,1)
on = FALSE
sleep(2)// here for timing. Shuts off right at climax of the effect before falloff.
update_icon()
return

if(mob_occupant.get_organic_health() >= mob_occupant.getMaxHealth()) // Don't bother with fully healed people.
if(iscarbon(mob_occupant))
var/mob/living/carbon/C = mob_occupant
Expand Down
6 changes: 6 additions & 0 deletions code/modules/language/language_holder.dm
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ Key procs
spoken_languages = list(/datum/language/slime = list(LANGUAGE_ATOM))
blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM))

/datum/language_holder/preternis
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/machine = list(LANGUAGE_ATOM),)
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/machine = list(LANGUAGE_ATOM),)

/datum/language_holder/lizard
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/draconic = list(LANGUAGE_ATOM))
Expand Down
6 changes: 3 additions & 3 deletions code/modules/mob/living/carbon/damage_procs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,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)))
continue
if((brute && BP.brute_dam) || (burn && BP.burn_dam) || (stamina && BP.stamina_dam))
parts += BP
Expand Down Expand Up @@ -194,12 +194,12 @@
* It automatically updates health status
*/
/mob/living/carbon/heal_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, required_status)
var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn,stamina,required_status)
var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn,stamina,required_status ? required_status : BODYPART_ORGANIC)
if(!parts.len)
return
var/obj/item/bodypart/picked = pick(parts)
var/damage_calculator = picked.get_damage(TRUE) //heal_damage returns update status T/F instead of amount healed so we dance gracefully around this
if(picked.heal_damage(brute, burn, stamina, required_status))
if(picked.heal_damage(brute, burn, stamina, required_status ? required_status : BODYPART_ORGANIC))
update_damage_overlays()
return max(damage_calculator - picked.get_damage(TRUE), 0)

Expand Down
2 changes: 2 additions & 0 deletions code/modules/mob/living/carbon/human/emote.dm
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@
'sound/creatures/monkey/monkey_screech_5.ogg',
'sound/creatures/monkey/monkey_screech_6.ogg',
'sound/creatures/monkey/monkey_screech_7.ogg')
else if (ispreternis(H))
return 'goon/sound/robot_scream.ogg'

/datum/emote/living/carbon/human/scream/screech //If a human tries to screech it'll just scream.
key = "screech"
Expand Down
23 changes: 22 additions & 1 deletion code/modules/mob/living/carbon/human/species.dm
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,17 @@ GLOBAL_LIST_EMPTY(roundstart_races)
///List of visual overlays created by handle_body()
var/list/body_vis_overlays = list()

var/draw_robot_hair = FALSE //DAMN ROBOTS STEALING OUR HAIR AND AIR

///Chance of a mob with this species to infect with a virus
var/virus_infect_chance = 100

///How big boost to it's propetries gets a disease that infects a mob with this species
var/virus_resistance_boost = 0
var/virus_stealth_boost = 0
var/virus_stage_rate_boost = 0
var/virus_transmittable_boost = 0

///////////
// PROCS //
///////////
Expand Down Expand Up @@ -440,6 +451,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)

C.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/species, multiplicative_slowdown=speedmod)

if(draw_robot_hair)
for(var/obj/item/bodypart/BP in C.bodyparts)
BP.draw_robot_hair = TRUE

SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)

/**
Expand Down Expand Up @@ -482,6 +497,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)

C.remove_movespeed_modifier(/datum/movespeed_modifier/species)

for(var/obj/item/bodypart/BP in C.bodyparts)
BP.draw_robot_hair = initial(BP.draw_robot_hair)

SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)

/**
Expand Down Expand Up @@ -510,7 +528,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/dynamic_fhair_suffix = ""

//for augmented heads
if(noggin.status == BODYPART_ROBOTIC)
if(noggin.status == BODYPART_ROBOTIC && !draw_robot_hair)
return

//we check if our hat or helmet hides our facial hair.
Expand Down Expand Up @@ -1561,6 +1579,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
// called before a projectile hit
return 0

/datum/species/proc/spec_AltClickOn(atom/A,mob/living/carbon/human/H)
return FALSE

//////////////////////////
// ENVIRONMENT HANDLERS //
//////////////////////////
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/obj/item/organ/eyes/robotic/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
//preternis eyes need to be powered by a preternis to function, in a non preternis they slowly power down to blindness
organ_flags = ORGAN_SYNTHETIC

low_threshold_passed = span_info("Your Preternis eyes switch to battery saver mode.")
high_threshold_passed = span_info("Your Preternis eyes only show a sliver of battery life left!")
now_failing = span_warning("An empty battery icon is all you can see as your eyes shut off!")
now_fixed = span_info("Lines of text scroll in your vision as your eyes begin rebooting.")
high_threshold_cleared = span_info("Your Preternis eyes have recharged enough to re-enable most functionality.")
low_threshold_cleared = span_info("Your Preternis eyes have almost fully recharged.")
var/powered = TRUE
actions_types = list(/datum/action/item_action/organ_action/use)
var/night_vision = TRUE

/obj/item/organ/eyes/robotic/preternis/ui_action_click()
if(damage > low_threshold)
//no nightvision if your eyes are hurt
return
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/robotic/preternis/on_life()
. = ..()
if(!owner)
return
if(ispreternis(owner) && !powered)
powered = TRUE
to_chat(owner, span_notice("A battery icon disappears from your vision as your [src] switch to external power."))
if(!ispreternis(owner) && powered) //these eyes depend on being inside a preternis for power
powered = FALSE
to_chat(owner, span_boldwarning("Your [src] flash warnings that they've lost their power source, and are running on emergency power!"))
if(powered)
//when powered, they recharge by healing
owner.adjustOrganLoss(ORGAN_SLOT_EYES,-0.5)
else
//to simulate running out of power, they take damage
owner.adjustOrganLoss(ORGAN_SLOT_EYES,0.5)

if(damage < low_threshold)
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/eyes/robotic/preternis/examine(mob/user)
. = ..()
if(status == ORGAN_ROBOTIC && (organ_flags & ORGAN_FAILING))
. += span_warning("[src] appears to be completely out of charge. However, that's nothing popping them back in a Preternis wouldn't fix.")

else if(organ_flags & ORGAN_FAILING)
. += span_warning("[src] appears to be completely out of charge. If they were put back in a Preternis they would surely recharge in time.")

else if(damage > high_threshold)
. += span_warning("[src] seem to flicker on and off. They must be pretty low on charge without being in a Preternis")

/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
Loading