Job Perks - True Professionals (#29478)

* ddsadsa

ddsadsa

* moderate again

* revert

* medical first steps

* more work

* lots more work done

* more progress

* finished up

* attack chain linter

* attack chain update

* attack chain work

* fixes + chemist update

* gives comments
This commit is contained in:
Kyani
2025-06-13 19:40:29 +00:00
committed by GitHub
parent 341058c682
commit 586e2e6c4d
31 changed files with 553 additions and 56 deletions
@@ -109,20 +109,22 @@
for(var/mutation_type in active_mutations)
var/datum/mutation/mutation = GLOB.dna_mutations[mutation_type]
mutation.on_life(src)
if(!ignore_gene_stability && gene_stability < GENETIC_DAMAGE_STAGE_1)
var/gene_bonus
if(mind && HAS_TRAIT(mind, TRAIT_GENETIC_BUDGET))
gene_bonus = 5
if(!ignore_gene_stability && gene_stability < GENETIC_DAMAGE_STAGE_1 - gene_bonus)
var/instability = DEFAULT_GENE_STABILITY - gene_stability
if(prob(instability * 0.1))
adjustFireLoss(min(10, instability * 0.67))
to_chat(src, "<span class='danger'>You feel like your skin is burning and bubbling off!</span>")
if(gene_stability < GENETIC_DAMAGE_STAGE_2)
if(gene_stability < GENETIC_DAMAGE_STAGE_2 - gene_bonus)
if(prob(instability * 0.83))
adjustCloneLoss(min(8, instability * 0.05))
to_chat(src, "<span class='danger'>You feel as if your body is warping.</span>")
if(prob(instability * 0.1))
adjustToxLoss(min(10, instability * 0.67))
to_chat(src, "<span class='danger'>You feel weak and nauseous.</span>")
if(gene_stability < GENETIC_DAMAGE_STAGE_3 && prob(1))
if(gene_stability < (GENETIC_DAMAGE_STAGE_3 - gene_bonus) && prob(1))
to_chat(src, "<span class='biggerdanger'>You feel incredibly sick... Something isn't right!</span>")
spawn(300)
if(gene_stability < GENETIC_DAMAGE_STAGE_3)
@@ -895,8 +897,9 @@
if(HAS_TRAIT(H, TRAIT_NOBREATH))
continue //no puking if you can't smell!
// Humans can lack a mind datum, y'know
if(H.mind && (H.mind.assigned_role == "Detective" || H.mind.assigned_role == "Coroner"))
continue //too cool for puke
if(H.mind && HAS_TRAIT(H.mind, TRAIT_CORPSE_RESIST))
to_chat(H, "<span class='warning'>You smell something rotting nearby.</span>")
continue
to_chat(H, "<span class='warning'>You smell something foul...</span>")
H.fakevomit()
@@ -2174,3 +2174,45 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
return FALSE
return TRUE
/mob/living/carbon/human/AltClick(mob/user, modifiers)
. = ..()
if(user.stat || user.restrained() || (!in_range(src, user)))
return
if(user.mind && !HAS_TRAIT(user.mind, TRAIT_MED_EXAMINE))
return
user.visible_message("[user] begins to thoroughly examine [src].")
if(do_after_once(user, 12 SECONDS, target = src, allow_moving = FALSE, attempt_cancel_message = "You couldn't get a good look at [src]!"))
var/list/missing = list("head", "chest", "groin", "l_arm", "r_arm", "l_hand", "r_hand", "l_leg", "r_leg", "l_foot", "r_foot")
var/list/analysis = list()
for(var/obj/item/organ/external/E in src.bodyparts)
missing -= E.limb_name
if(E.status & ORGAN_DEAD)
analysis += "<span class='info'>You conclude [src]'s [E.name] is dead.</span>"
if(E.status & ORGAN_INT_BLEEDING)
analysis += "<span class='info'>You conclude [src]'s [E.name] has internal bleeding.</span>"
if(E.status & ORGAN_BURNT)
analysis += "<span class='info'>You conclude [src]'s [E.name] has been critically burned.</span>"
if(E.status & ORGAN_BROKEN)
if(!E.broken_description)
analysis += "<span class='info'>You conclude [src]'s [E.name] is broken.</span>"
else
analysis += "<span class='info'>You conclude [src]'s [E.name] has a [E.broken_description].</span>"
to_chat(user, chat_box_healthscan(analysis.Join("<br>")))
/mob/living/carbon/human/pointed(atom/A as mob|obj|turf in view())
set name = "Point To"
set category = null
if(next_move >= world.time)
return
if(istype(A, /obj/effect/temp_visual/point) || istype(A, /atom/movable/emissive_blocker))
return FALSE
if(mind && HAS_TRAIT(mind, TRAIT_COFFEE_SNOB) && reagents.has_reagent("coffee"))
changeNext_move(CLICK_CD_POINT / 3)
else
changeNext_move(CLICK_CD_POINT)
DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(run_pointed), A))
+6 -2
View File
@@ -941,8 +941,12 @@
if(user.a_intent == INTENT_HARM && stat == DEAD && butcher_results && I.sharp) //can we butcher it?
to_chat(user, "<span class='notice'>You begin to butcher [src]...</span>")
playsound(loc, 'sound/weapons/slice.ogg', 50, TRUE, -1)
if(do_mob(user, src, 8 SECONDS) && Adjacent(I))
harvest(user)
if(user.mind && HAS_TRAIT(user.mind, TRAIT_BUTCHER))
if(do_mob(user, src, 3 SECONDS) && Adjacent(I))
harvest(user)
else
if(do_mob(user, src, 8 SECONDS) && Adjacent(I))
harvest(user)
return TRUE
/mob/living/proc/harvest(mob/living/user)
@@ -104,6 +104,9 @@
/// Famous last words -- if succumbing, what the user's last words were
var/last_words
/// Does this mob talk with a BIG VOICE. 0 off, 1 single use, 2 multi-use
var/big_voice = 0
///This variable is the chance for a mob to automatically dodge a bullet. Useful for admins, and applied to some mobs by default, such as the malfunctioning drone mobs.
var/advanced_bullet_dodge_chance = 0
+4 -1
View File
@@ -105,7 +105,7 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
return returns
/mob/living/say(message, verb = null, sanitize = TRUE, ignore_speech_problems = FALSE, ignore_atmospherics = FALSE, ignore_languages = FALSE, automatic = FALSE)
/mob/living/say(message, verb = null, sanitize = TRUE, ignore_speech_problems = FALSE, ignore_atmospherics = FALSE, ignore_languages = FALSE, automatic = FALSE, bigvoice = FALSE)
if(client)
if(check_mute(client.ckey, MUTE_IC))
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
@@ -139,6 +139,9 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
message = trim_left(message)
if(big_voice)
message = "<span class='reallybig'>[message]</span>"
//parse the language code and consume it
var/list/message_pieces = list()
if(ignore_languages)
@@ -130,6 +130,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/base_icon = ""
/// If set to TRUE, the robot's 3 module slots will progressively become unusable as they take damage.
var/modules_break = TRUE
/// Is the robot already being charged by a roboticist?
var/being_charged
/// Maximum brightness of a robot's headlamp. Set as a var for easy adjusting.
var/lamp_max = 10
@@ -923,6 +925,33 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/item_interaction(mob/living/user, obj/item/W, list/modifiers)
// Check if the user is trying to insert another component like a radio, actuator, armor etc.
if(istype(W, /obj/item/stock_parts/cell) && user.mind && HAS_TRAIT(user.mind, TRAIT_CYBORG_SPECIALIST) && !opened && user.a_intent != INTENT_HARM)
var/obj/item/stock_parts/cell/donor = W
if(being_charged)
to_chat(user, "<span class='warning'>You are already charging [src]!")
return ITEM_INTERACT_COMPLETE
if(donor.charge == 0)
to_chat(user, "<span class='warning'>[donor] has no charge to donate!")
return ITEM_INTERACT_COMPLETE
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
being_charged = TRUE
while(do_after(user, 0.5 SECONDS, target = src))
var/cell_difference = cell.maxcharge - cell.charge
if(donor.charge >= 500 && cell_difference >= 500)
cell.charge += 500
donor.charge -= 500
else if(donor.charge <= cell_difference)
cell.charge += donor.charge
donor.charge = 0
else if(donor.charge > cell_difference)
cell.charge = cell.maxcharge
donor.charge -= cell_difference
if(donor.charge == 0 || cell.charge >= cell.maxcharge)
donor.update_icon(UPDATE_OVERLAYS)
break
cell.update_icon(UPDATE_OVERLAYS)
being_charged = FALSE
return ITEM_INTERACT_COMPLETE
if(istype(W, /obj/item/robot_parts/robot_component) && opened)
for(var/V in components)
var/datum/robot_component/C = components[V]
@@ -1129,10 +1158,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
C.uninstall()
thing.forceMove(loc)
/mob/living/silicon/robot/attacked_by(obj/item/I, mob/living/user, def_zone)
if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt.
spark_system.start()