From 9ce76d72eea825981a4d9de8808a4b4869dd35f7 Mon Sep 17 00:00:00 2001 From: SapphicOverload Date: Mon, 7 Oct 2024 05:40:35 -0400 Subject: [PATCH 01/28] skill issue to do: -chemistry -virology -balance stuff -??? i forgor --- code/__DEFINES/skills.dm | 29 +++++ code/__DEFINES/traits/declarations.dm | 6 ++ code/__HELPERS/mobs.dm | 8 +- code/_onclick/hud/alert.dm | 68 ++++++++++++ code/controllers/subsystem/shuttle.dm | 4 +- code/datums/components/blocking.dm | 2 + code/datums/components/mech_pilot.dm | 7 -- .../diseases/advance/symptoms/necropolis.dm | 4 +- code/datums/martial.dm | 6 +- code/datums/martial/lightning_flow.dm | 4 +- code/datums/martial/ultra_violence.dm | 4 +- code/datums/mind.dm | 61 +++++++++++ code/datums/mutations/body.dm | 2 - code/datums/wires/_wires.dm | 65 ++++++++---- code/datums/wounds/bones.dm | 14 +-- code/datums/wounds/burns.dm | 4 +- code/datums/wounds/pierce.dm | 4 +- code/datums/wounds/slash.dm | 6 +- code/game/machinery/computer/dna_console.dm | 27 ++--- code/game/mecha/mecha.dm | 21 ++-- code/game/mecha/mecha_defense.dm | 21 ++-- code/game/objects/items.dm | 17 +-- code/game/objects/items/devices/scanners.dm | 8 +- .../objects/items/granters/mech_piloting.dm | 2 +- code/game/objects/items/stacks/medical.dm | 6 +- code/game/objects/items/tools/weldingtool.dm | 2 +- .../objects/structures/ghost_role_spawners.dm | 20 ++++ code/modules/antagonists/abductor/abductor.dm | 3 + .../bloodsuckers/bloodsucker_mobs.dm | 1 - .../antagonists/bloodsuckers/bloodsuckers.dm | 14 +-- .../antagonists/bloodsuckers/clans/_clan.dm | 1 - .../bloodsuckers/powers/fortitude.dm | 2 - .../bloodsuckers/powers/gangrel.dm | 2 +- code/modules/antagonists/brother/brother.dm | 3 + code/modules/antagonists/ert/ert.dm | 2 + code/modules/antagonists/nukeop/nukeop.dm | 3 + code/modules/awaymissions/corpse.dm | 12 +++ code/modules/clothing/under/costume.dm | 5 +- code/modules/clothing/under/miscellaneous.dm | 37 ------- code/modules/hydroponics/grown.dm | 36 ++++--- code/modules/hydroponics/grown/kudzu.dm | 11 +- code/modules/hydroponics/growninedible.dm | 5 + code/modules/hydroponics/hydroponics.dm | 15 +-- code/modules/hydroponics/seeds.dm | 68 ++++++------ code/modules/jobs/job_types/_job.dm | 16 +++ code/modules/jobs/job_types/ai.dm | 9 ++ .../jobs/job_types/atmospheric_technician.dm | 9 ++ code/modules/jobs/job_types/botanist.dm | 9 ++ code/modules/jobs/job_types/captain.dm | 9 ++ code/modules/jobs/job_types/chemist.dm | 9 ++ code/modules/jobs/job_types/chief_engineer.dm | 9 ++ .../jobs/job_types/chief_medical_officer.dm | 9 ++ code/modules/jobs/job_types/detective.dm | 9 ++ code/modules/jobs/job_types/geneticist.dm | 9 ++ .../jobs/job_types/head_of_security.dm | 9 ++ code/modules/jobs/job_types/medical_doctor.dm | 8 ++ .../jobs/job_types/research_director.dm | 9 ++ code/modules/jobs/job_types/roboticist.dm | 9 ++ code/modules/jobs/job_types/scientist.dm | 9 ++ .../jobs/job_types/security_officer.dm | 9 ++ code/modules/jobs/job_types/shaft_miner.dm | 9 ++ .../jobs/job_types/station_engineer.dm | 9 ++ code/modules/jobs/job_types/virologist.dm | 9 ++ code/modules/jobs/job_types/warden.dm | 9 ++ code/modules/library/lib_items.dm | 1 + .../mob/living/carbon/human/_species.dm | 10 +- code/modules/mob/living/carbon/human/human.dm | 32 ++++-- .../mob/living/carbon/human/human_defense.dm | 2 + .../mob/living/carbon/human/human_helpers.dm | 8 +- .../mob/living/carbon/human/physiology.dm | 2 +- .../living/carbon/human/species_types/IPC.dm | 4 +- .../carbon/human/species_types/ethereal.dm | 1 - .../carbon/human/species_types/golems.dm | 14 ++- .../human/species_types/lizardpeople.dm | 5 +- .../carbon/human/species_types/mothmen.dm | 2 +- .../carbon/human/species_types/mushpeople.dm | 2 +- .../carbon/human/species_types/plasmamen.dm | 2 +- .../carbon/human/species_types/polysmorphs.dm | 1 - .../carbon/human/species_types/wy_synths.dm | 2 +- .../carbon/human/species_types/zombies.dm | 2 +- code/modules/mob/living/life.dm | 9 +- code/modules/projectiles/gun.dm | 4 +- .../projectiles/guns/energy/special.dm | 2 +- .../chemistry/reagents/alcohol_reagents.dm | 2 - code/modules/shuttle/computer.dm | 3 +- code/modules/shuttle/shuttle.dm | 14 +-- .../surgery/advanced/bioware/ligament_hook.dm | 1 + .../bioware/ligament_reinforcement.dm | 1 + .../surgery/advanced/bioware/muscled_veins.dm | 1 + .../advanced/bioware/nerve_grounding.dm | 1 + .../advanced/bioware/nerve_splicing.dm | 1 + .../advanced/bioware/vein_threading.dm | 1 + code/modules/surgery/advanced/brainwashing.dm | 1 + code/modules/surgery/advanced/dna_recovery.dm | 1 + code/modules/surgery/advanced/lobotomy.dm | 1 + .../surgery/advanced/necrotic_revival.dm | 1 + code/modules/surgery/advanced/pacification.dm | 1 + code/modules/surgery/brain_surgery.dm | 20 ++-- code/modules/surgery/coronary_bypass.dm | 1 + .../surgery/experimental_dissection.dm | 7 +- code/modules/surgery/hepatectomy.dm | 1 + code/modules/surgery/ipc_revival.dm | 1 + code/modules/surgery/limb_augmentation.dm | 2 +- code/modules/surgery/lobectomy.dm | 1 + code/modules/surgery/surgery.dm | 4 +- code/modules/surgery/surgery_step.dm | 23 ++-- tgui/packages/tgui/interfaces/SkillMenu.js | 100 ++++++++++++++++++ yogstation.dme | 2 +- .../game/objects/items/devices/scanners.dm | 2 +- .../modules/jobs/job_types/brig_physician.dm | 9 ++ .../modules/jobs/job_types/mining_medic.dm | 9 ++ .../modules/jobs/job_types/network_admin.dm | 9 ++ .../code/modules/jobs/job_types/paramedic.dm | 9 ++ .../carbon/human/species_types/plantpeople.dm | 2 +- .../species_types/preternis/preternis.dm | 2 +- .../carbon/human/species_types/szlachta.dm | 2 +- 116 files changed, 872 insertions(+), 297 deletions(-) create mode 100644 code/__DEFINES/skills.dm delete mode 100644 code/datums/components/mech_pilot.dm create mode 100644 tgui/packages/tgui/interfaces/SkillMenu.js diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm new file mode 100644 index 000000000000..9d96999e4e95 --- /dev/null +++ b/code/__DEFINES/skills.dm @@ -0,0 +1,29 @@ + +/// Medicine and surgery. +#define SKILL_PHYSIOLOGY "physiology" +/// Construction and repair of structures and machinery. +#define SKILL_MECHANICAL "mechanics" +/// Hacking, piloting, and robotic maintenance. +#define SKILL_TECHNICAL "technical" +/// Chemistry, botany, physics, and other sciences. +#define SKILL_SCIENCE "science" +/// Strength, endurance, accuracy. +#define SKILL_FITNESS "fitness" + +/// No experience whatsoever. +#define EXP_NONE 0 +/// Some experience, but not much. +#define EXP_LOW 1 +/// Enough experience to do a decent job. +#define EXP_MID 2 +/// Above average skill level. +#define EXP_HIGH 3 +/// Exceptionally skilled. +#define EXP_MASTER 4 +/// Uniquely gifted. Not obtainable through normal means. +#define EXP_GENIUS 5 + +/// Experience required to increase your skills by one level. Increases exponentially the higher your level already is. +#define EXPERIENCE_PER_LEVEL 200 + +#define SKILL_TO_ACTION_SPEED(skill_level) ((12 - skill_level) / 10) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index b26926922814..18900cd1e786 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -109,6 +109,8 @@ #define TRAIT_IGNOREDAMAGESLOWDOWN "ignoredamageslowdown" /// Makes the screen go black and white while illuminating all mobs based on their body temperature #define TRAIT_INFRARED_VISION "infrared_vision" +/// Punches don't stun. Use this instead of setting punchstunchance to zero. +#define TRAIT_NO_PUNCH_STUN "no-punch-stun" //////////////////////////////////////////////////////////////////////////////////// //-------------------------Species Specific defines-------------------------------// @@ -440,6 +442,10 @@ #define TRAIT_PRESENT_VISION "present-vision" #define TRAIT_DISK_VERIFIER "disk-verifier" #define TRAIT_NOMOBSWAP "no-mob-swap" +/// Can allocate 5 points into one skill instead of the usual 4 +#define TRAIT_EXCEPTIONAL_SKILL "exceptional-skill" +/// Acts as an additional skill point for piloting mechs, up to EXP_MASTER. +#define TRAIT_SKILLED_PILOT "skilled-pilot" /// Can examine IDs to see if they are roundstart. #define TRAIT_ID_APPRAISER "id_appraiser" /// Gives us turf, mob and object vision through walls diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index fe064a3bb285..50beb1ad5d47 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -319,7 +319,7 @@ GLOBAL_LIST_EMPTY(species_list) * given `delay`. Returns `TRUE` on success or `FALSE` on failure. * Interaction_key is the assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set. */ -/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1) +/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, skill_check = null) if(!user) return FALSE if(!isnum(delay)) @@ -344,6 +344,9 @@ GLOBAL_LIST_EMPTY(species_list) if(!(timed_action_flags & IGNORE_SLOWDOWNS)) delay *= user.action_speed_modifier * user.do_after_coefficent() //yogs: darkspawn + + if(skill_check && user.mind) + delay *= (12 - user.get_skill(skill_check)) / 10 var/datum/progressbar/progbar if(progress) @@ -378,6 +381,9 @@ GLOBAL_LIST_EMPTY(species_list) . = FALSE break + if(skill_check) // get better at things by practicing them + user.add_exp(skill_check, delay) + if(!QDELETED(progbar)) progbar.end_progress() diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 7dd13348d904..0ac650842636 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -322,6 +322,74 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." var/mob/living/carbon/C = mob_viewer C.take(giver, receiving) +//SKILLS + +/atom/movable/screen/alert/skill_up + name = "Allocate Skill Points" + desc = "You have unspent skill points! Click here to allocate them." + var/list/allocated_skills = list( + SKILL_PHYSIOLOGY = 0, + SKILL_MECHANICAL = 0, + SKILL_TECHNICAL = 0, + SKILL_SCIENCE = 0, + SKILL_FITNESS = 0, + ) + var/allocated_points = 0 + +/atom/movable/screen/alert/skill_up/Click(location, control, params) + . = ..() + ui_interact(mob_viewer) + +/atom/movable/screen/alert/skill_up/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "SkillMenu", "Allocate Skill Points") + ui.open() + +/atom/movable/screen/alert/skill_up/ui_data(mob/user) + var/list/data = list() + var/list/skill_data = list() + for(var/skill in user.mind.skills) + skill_data.Add(list(list( + "base" = user.get_skill(skill), + "allocated" = allocated_skills[skill], + ))) + data["skills"] = skill_data + data["skill_points"] = user.mind.skill_points + data["allocated_points"] = allocated_points + data["exceptional_skill"] = HAS_TRAIT(user, TRAIT_EXCEPTIONAL_SKILL) + return data + +/atom/movable/screen/alert/skill_up/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + var/mob/user = usr + if(!user.mind) + CRASH("User ([user]) without a mind attempted to allocate skill points!") + switch(action) + if("confirm") + for(var/skill in user.mind.skills) + user.adjust_skill(skill, allocated_skills[skill], max_skill = EXP_GENIUS) + allocated_skills[skill] = 0 + user.mind.skill_points -= allocated_points + allocated_points = 0 + if(!user.mind.skill_points) + user.clear_alert("skill points") + return TRUE + if("allocate") + allocated_skills[params["skill"]] += params["amount"] + allocated_points += params["amount"] + return TRUE + +/atom/movable/screen/alert/skill_up/ui_status(mob/user) + if(!user.mind) + return UI_CLOSE + return UI_INTERACTIVE + +/atom/movable/screen/alert/skill_up/ui_state(mob/user) + return GLOB.always_state + //ALIENS /atom/movable/screen/alert/alien_tox diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 3eb9e427b382..e1575b94ddc6 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -523,14 +523,14 @@ SUBSYSTEM_DEF(shuttle) * * dock_id - The ID of the destination (stationary docking port) to move to * * timed - If true, have the shuttle follow normal spool-up, jump, dock process. If false, immediately move to the new location. */ -/datum/controller/subsystem/shuttle/proc/moveShuttle(shuttle_id, dock_id, timed) +/datum/controller/subsystem/shuttle/proc/moveShuttle(shuttle_id, dock_id, timed, skill_multiplier = 1) var/obj/docking_port/mobile/shuttle_port = getShuttle(shuttle_id) var/obj/docking_port/stationary/docking_target = getDock(dock_id) if(!shuttle_port) return DOCKING_NULL_SOURCE if(timed) - if(shuttle_port.request(docking_target)) + if(shuttle_port.request(docking_target, skill_multiplier)) return DOCKING_IMMOBILIZED else if(shuttle_port.initiate_docking(docking_target) != DOCKING_SUCCESS) diff --git a/code/datums/components/blocking.dm b/code/datums/components/blocking.dm index 57ca6e47f5ac..65789d74df1f 100644 --- a/code/datums/components/blocking.dm +++ b/code/datums/components/blocking.dm @@ -220,6 +220,8 @@ if(!blocking_component.can_block(defender, incoming, damage, attack_type)) return 0 force_returned = blocking_component.block_force + if(attack_type & MELEE_ATTACK) // being stronger provides a small increase to melee blocking + force_returned += defender.get_skill(SKILL_FITNESS) if(HAS_TRAIT(weapon, TRAIT_PARRYING)) force_returned *= PARRY_BONUS return max(force_returned - max(armour_penetration - weapon.armour_penetration, 0) * AP_TO_FORCE, 0) diff --git a/code/datums/components/mech_pilot.dm b/code/datums/components/mech_pilot.dm deleted file mode 100644 index a28b024db458..000000000000 --- a/code/datums/components/mech_pilot.dm +++ /dev/null @@ -1,7 +0,0 @@ -/// A component for clothes that affect one's ability to pilot mechs -/datum/component/mech_pilot - /// Modifier of mech delay, based on percentage 1 = 100%. lower is faster - var/piloting_speed = 1 - -/datum/component/mech_pilot/Initialize(_piloting_speed = 1) - piloting_speed = _piloting_speed diff --git a/code/datums/diseases/advance/symptoms/necropolis.dm b/code/datums/diseases/advance/symptoms/necropolis.dm index 7d6319b02df0..32d789f65578 100644 --- a/code/datums/diseases/advance/symptoms/necropolis.dm +++ b/code/datums/diseases/advance/symptoms/necropolis.dm @@ -57,7 +57,7 @@ fullpower = TRUE H.physiology.punchdamagehigh_bonus += 4 H.physiology.punchdamagelow_bonus += 4 - H.physiology.punchstunthreshold_bonus += 1 //Makes standard punches 5-14 with higher stun chance (1-10, stun on 10 -> 5-14, stun on 11-14) + H.physiology.punchstunchance_bonus += 0.4 //Makes standard punches 5-14 with higher stun chance (1-10, stun on 10 -> 5-14, stun on 11-14) H.physiology.brute_mod *= 0.6 H.physiology.burn_mod *= 0.6 H.physiology.heat_mod *= 0.6 @@ -103,7 +103,7 @@ H.remove_movespeed_modifier(MOVESPEED_ID_NECRO_VIRUS_SLOWDOWN) H.physiology.punchdamagehigh_bonus -= 4 H.physiology.punchdamagelow_bonus -= 4 - H.physiology.punchstunthreshold_bonus -= 1 + H.physiology.punchstunchance_bonus -= 0.4 H.physiology.brute_mod /= 0.6 H.physiology.burn_mod /= 0.6 H.physiology.heat_mod /= 0.6 diff --git a/code/datums/martial.dm b/code/datums/martial.dm index 8f20d7be0cae..3c6dfa4854a2 100644 --- a/code/datums/martial.dm +++ b/code/datums/martial.dm @@ -101,8 +101,8 @@ * used for basic punch attacks */ /datum/martial_art/proc/basic_hit(mob/living/carbon/human/A,mob/living/carbon/human/D) - - var/damage = rand(A.get_punchdamagelow(), A.get_punchdamagehigh()) + var/percentile = rand() + var/damage = LERP(A.get_punchdamagelow(), A.get_punchdamagehigh(), percentile) var/atk_verb = pick(A.dna.species.attack_verbs) var/atk_effect = A.dna.species.attack_effect @@ -129,7 +129,7 @@ log_combat(A, D, "punched") - if((D.stat != DEAD) && damage >= A.get_punchstunthreshold()) + if((D.stat != DEAD) && percentile > (1 - A.get_punchstunchance()) && !HAS_TRAIT(A, TRAIT_NO_PUNCH_STUN)) D.visible_message(span_danger("[A] has knocked [D] down!!"), \ span_userdanger("[A] has knocked [D] down!")) D.apply_effect(40, EFFECT_KNOCKDOWN, armor_block) diff --git a/code/datums/martial/lightning_flow.dm b/code/datums/martial/lightning_flow.dm index e2b7772915e6..f73e43104f20 100644 --- a/code/datums/martial/lightning_flow.dm +++ b/code/datums/martial/lightning_flow.dm @@ -8,7 +8,7 @@ id = MARTIALART_LIGHTNINGFLOW no_guns = TRUE help_verb = /mob/living/carbon/human/proc/lightning_flow_help - martial_traits = list(TRAIT_STRONG_GRABBER) + martial_traits = list(TRAIT_STRONG_GRABBER, TRAIT_NO_PUNCH_STUN) var/dashing = FALSE COOLDOWN_DECLARE(action_cooldown) var/list/action_modifiers = list() @@ -147,7 +147,6 @@ var/mob/living/carbon/human/user = H user.physiology.punchdamagelow_bonus += 5 user.physiology.punchdamagehigh_bonus += 5 - user.physiology.punchstunthreshold_bonus += 6 //no knockdowns /datum/martial_art/lightning_flow/on_remove(mob/living/carbon/human/H) UnregisterSignal(H, COMSIG_MOB_CLICKON) @@ -155,7 +154,6 @@ var/mob/living/carbon/human/user = H user.physiology.punchdamagelow_bonus -= 5 user.physiology.punchdamagehigh_bonus -= 5 - user.physiology.punchstunthreshold_bonus -= 6 return ..() #undef ACTION_DELAY diff --git a/code/datums/martial/ultra_violence.dm b/code/datums/martial/ultra_violence.dm index b216f9ca19ce..f3a578ba23a4 100644 --- a/code/datums/martial/ultra_violence.dm +++ b/code/datums/martial/ultra_violence.dm @@ -16,7 +16,7 @@ help_verb = /mob/living/carbon/human/proc/ultra_violence_help gun_exceptions = list(/obj/item/gun/ballistic/revolver/ipcmartial) no_gun_message = "This gun is not compliant with Ultra Violence standards." - martial_traits = list(TRAIT_NOSOFTCRIT, TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_NOLIMBDISABLE, TRAIT_NO_STUN_WEAPONS, TRAIT_NO_BLOCKING, TRAIT_NODISMEMBER, TRAIT_STUNIMMUNE, TRAIT_SLEEPIMMUNE, TRAIT_NO_HOLDUP) + martial_traits = list(TRAIT_NOSOFTCRIT, TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_NOLIMBDISABLE, TRAIT_NO_STUN_WEAPONS, TRAIT_NO_PUNCH_STUN, TRAIT_NO_BLOCKING, TRAIT_NODISMEMBER, TRAIT_STUNIMMUNE, TRAIT_SLEEPIMMUNE, TRAIT_NO_HOLDUP) ///used to keep track of the dash stuff var/dashing = FALSE var/dashes = 3 @@ -429,7 +429,6 @@ H.dna.species.attack_sound = 'sound/weapons/shotgunshot.ogg' H.dna.species.punchdamagelow += 4 H.dna.species.punchdamagehigh += 4 //no fancy comboes, just punches - H.dna.species.punchstunthreshold += 50 //disables punch stuns H.dna.species.staminamod = 0 //my god, why must you make me add all these additional things, stop trying to disable them, just kill them RegisterSignal(H, COMSIG_MOB_CLICKON, PROC_REF(on_click)) // death to click_intercept H.throw_alert("dash_charge", /atom/movable/screen/alert/ipcmartial, dashes+1) @@ -440,7 +439,6 @@ H.dna.species.attack_sound = initial(H.dna.species.attack_sound) //back to flimsy tin tray punches H.dna.species.punchdamagelow -= 4 H.dna.species.punchdamagehigh -= 4 - H.dna.species.punchstunthreshold -= 50 H.dna.species.staminamod = initial(H.dna.species.staminamod) UnregisterSignal(H, COMSIG_MOB_CLICKON) deltimer(dash_timer) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 328069dfef05..a75e1460291f 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -50,6 +50,27 @@ var/list/restricted_roles = list() var/list/datum/objective/objectives = list() + /// The owner of this mind's ability to perform certain kinds of tasks. + var/list/skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_NONE, + ) + + /// Progress towards increasing their skill level + var/list/exp_progress = list( + SKILL_PHYSIOLOGY = 0, + SKILL_MECHANICAL = 0, + SKILL_TECHNICAL = 0, + SKILL_SCIENCE = 0, + SKILL_FITNESS = 0, + ) + + /// Free skill points to allocate + var/skill_points = 0 + var/linglink var/datum/martial_art/martial_art var/static/default_martial_art = new/datum/martial_art @@ -326,6 +347,9 @@ if (!istype(traitor_mob)) return + traitor_mob.add_skill_points(EXP_LOW) // one extra skill point + ADD_TRAIT(traitor_mob, TRAIT_EXCEPTIONAL_SKILL, type) + var/list/all_contents = traitor_mob.get_all_contents() var/obj/item/modular_computer/PDA = locate() in all_contents var/obj/item/radio/R = locate() in all_contents @@ -818,6 +842,43 @@ mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist) mind.active = TRUE //indicates that the mind is currently synced with a client +/// Returns the mob's skill level +/mob/proc/get_skill(skill) + if(!mind) + return EXP_NONE + return mind.skills[skill] + +/// Adjusts the mob's skill level +/mob/proc/adjust_skill(skill, amount=0, min_skill = EXP_NONE, max_skill = EXP_MASTER) + if(!mind) + return + mind.skills[skill] = clamp(mind.skills[skill] + amount, min_skill, max_skill) + +/// Checks if the mob's skill level meets a given threshold. +/mob/proc/skill_check(skill, amount, inclusive = FALSE) + if(!mind) + return FALSE + return (mind.skills[skill] >= amount) + +/// Adds progress towards increasing skill level. Returns TRUE if it improved the skill. +/mob/proc/add_exp(skill, amount) + if(!mind) + return FALSE + if(mind.exp_progress[skill] + amount >= EXPERIENCE_PER_LEVEL * (2**mind.skills[skill])) // exp required scales exponentially + mind.exp_progress[skill] = 0 + adjust_skill(skill, 1) + to_chat(src, span_boldnotice("your [skill] skill is now level [get_skill(skill)]!")) + return TRUE + mind.exp_progress[skill] += amount + return FALSE + +/// Adds skill points to be allocated at will. +/mob/proc/add_skill_points(amount) + if(!mind) + return + mind.skill_points += amount + throw_alert("skill points", /atom/movable/screen/alert/skill_up) + /datum/mind/proc/has_martialart(string) if(martial_art && martial_art.id == string) return martial_art diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 20800284facb..daa7d3591035 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -281,7 +281,6 @@ var/strength_punchpower = GET_MUTATION_POWER(src) * 2 - 1 //Normally +1, strength chromosome increases it to +2 owner.physiology.punchdamagehigh_bonus += strength_punchpower owner.physiology.punchdamagelow_bonus += strength_punchpower - owner.physiology.punchstunthreshold_bonus += strength_punchpower //So we dont change the stun chance ADD_TRAIT(owner, TRAIT_QUICKER_CARRY, src) /datum/mutation/human/strong/on_losing(mob/living/carbon/human/owner) @@ -290,7 +289,6 @@ var/strength_punchpower = GET_MUTATION_POWER(src) * 2 - 1 owner.physiology.punchdamagehigh_bonus -= strength_punchpower owner.physiology.punchdamagelow_bonus -= strength_punchpower - owner.physiology.punchstunthreshold_bonus -= strength_punchpower REMOVE_TRAIT(owner, TRAIT_QUICKER_CARRY, src) //Yogs end diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 0b6bcc355f44..2d79bf20bc9d 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -37,6 +37,28 @@ var/list/colors = list() /// List of attached assemblies. var/list/assemblies = list() + /// Skill required to identify each wire, EXP_GENIUS if not specified here. + var/static/list/wire_difficulty = list( + WIRE_SHOCK = EXP_MID, + WIRE_RESET_MODULE = EXP_MID, + WIRE_ZAP = EXP_MID, + WIRE_ZAP1 = EXP_HIGH, + WIRE_ZAP2 = EXP_HIGH, + WIRE_LOCKDOWN = EXP_HIGH, + WIRE_CAMERA = EXP_HIGH, + WIRE_POWER = EXP_HIGH, + WIRE_POWER1 = EXP_MASTER, + WIRE_POWER2 = EXP_MASTER, + WIRE_IDSCAN = EXP_MASTER, + WIRE_UNBOLT = EXP_MASTER, + WIRE_BACKUP1 = EXP_MASTER, + WIRE_BACKUP2 = EXP_MASTER, + WIRE_LAWSYNC = EXP_MASTER, + WIRE_PANIC = EXP_MASTER, + WIRE_OPEN = EXP_MASTER, + WIRE_HACK = EXP_MASTER, + WIRE_AI = EXP_MASTER, + ) /// If every instance of these wires should be random. Prevents wires from showing up in station blueprints. var/randomize = FALSE @@ -139,6 +161,29 @@ /datum/wires/proc/is_dud_color(color) return is_dud(get_wire(color)) +/datum/wires/proc/is_revealed(color, mob/user) + // Admin ghost can see a purpose of each wire. + if(IsAdminGhost(user)) + return TRUE + + // Same for anyone with an abductor multitool. + else if(user.is_holding_item_of_type(/obj/item/multitool/abductor)) + return TRUE + + // Station blueprints do that too, but only if the wires are not randomized. + else if(!randomize) + if(user.is_holding_item_of_type(/obj/item/areaeditor/blueprints)) + return TRUE + else if(user.is_holding_item_of_type(/obj/item/photo)) + var/obj/item/photo/P = user.is_holding_item_of_type(/obj/item/photo) + if(P.picture.has_blueprints) //if the blueprints are in frame + return TRUE + + var/skill_required = wire_difficulty[get_wire(color)] + if(skill_required && user.skill_check(SKILL_TECHNICAL, skill_required)) + return TRUE + return FALSE + /datum/wires/proc/cut(wire) if(is_cut(wire)) cut_wires -= wire @@ -240,30 +285,12 @@ /datum/wires/ui_data(mob/user) var/list/data = list() var/list/payload = list() - var/reveal_wires = FALSE - - // Admin ghost can see a purpose of each wire. - if(IsAdminGhost(user)) - reveal_wires = TRUE - - // Same for anyone with an abductor multitool. - else if(user.is_holding_item_of_type(/obj/item/multitool/abductor)) - reveal_wires = TRUE - - // Station blueprints do that too, but only if the wires are not randomized. - else if(!randomize) - if(user.is_holding_item_of_type(/obj/item/areaeditor/blueprints)) - reveal_wires = TRUE - else if(user.is_holding_item_of_type(/obj/item/photo)) - var/obj/item/photo/P = user.is_holding_item_of_type(/obj/item/photo) - if(P.picture.has_blueprints) //if the blueprints are in frame - reveal_wires = TRUE var/colorblind = HAS_TRAIT(user, TRAIT_COLORBLIND) for(var/color in colors) payload.Add(list(list( "color" = color, - "wire" = ((reveal_wires && !is_dud_color(color) && !colorblind) ? get_wire(color) : null), + "wire" = (!colorblind && !is_dud_color(color) && is_revealed(color, user)) ? get_wire(color) : null, "cut" = is_color_cut(color), "attached" = is_attached(color) ))) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 4069a9a9519f..0a4c6a2abb31 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -239,10 +239,10 @@ var/time = base_treat_time playsound(victim, 'sound/surgery/bone1.ogg', 25) - if(!do_after(user, time, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, time, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return - if(prob(65)) + if(prob(60 + user.get_skill(SKILL_PHYSIOLOGY) * 5)) user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.name] back into place!"), span_notice("You snap [victim]'s dislocated [limb.name] back into place!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.name] back into place!")) victim.emote("scream") @@ -260,10 +260,10 @@ var/time = base_treat_time playsound(victim, 'sound/surgery/bone1.ogg', 25) - if(!do_after(user, time, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, time, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return - if(prob(65)) + if(prob(60 + user.get_skill(SKILL_PHYSIOLOGY))) user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.name] with a sickening crack!"), span_danger("You snap [victim]'s dislocated [limb.name] with a sickening crack!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.name] with a sickening crack!")) victim.emote("scream") @@ -283,7 +283,7 @@ playsound(victim, 'sound/surgery/bone1.ogg', 25) - if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), victim, extra_checks=CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), victim, extra_checks=CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return playsound(victim, 'sound/surgery/bone3.ogg', 25) @@ -362,7 +362,7 @@ user.visible_message(span_danger("[user] begins hastily applying [I] to [victim]'s' [limb.name]..."), span_warning("You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name], disregarding the warning label...")) - if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), victim, extra_checks=CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), victim, extra_checks=CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return I.use(1) @@ -403,7 +403,7 @@ user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [limb.name]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...")) - if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), victim, extra_checks=CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), victim, extra_checks=CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return if(victim == user) diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index 48767f764ac8..c95d5f5989cc 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -207,7 +207,7 @@ /datum/wound/burn/proc/ointment(obj/item/stack/medical/ointment/I, mob/user) user.visible_message(span_notice("[user] begins applying [I] to [victim]'s [limb.name]..."), span_notice("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.name]...")) playsound(I, pick(I.apply_sounds), 25) - if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return limb.heal_damage(I.heal_brute, I.heal_burn) @@ -228,7 +228,7 @@ return user.visible_message(span_notice("[user] begins wrapping [victim]'s [limb.name] with [I]..."), span_notice("You begin wrapping [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) playsound(I, pick(I.apply_sounds), 25) - if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return limb.heal_damage(I.heal_brute, I.heal_burn) diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 3d6099d25e91..224357ec3d76 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -114,7 +114,7 @@ user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.name] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) playsound(I, pick(I.apply_sounds), 25) - if(!do_after(user, base_treat_time * self_penalty_mult * I.treatment_speed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * self_penalty_mult * I.treatment_speed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return user.visible_message(span_green("[user] stitches up some of the bleeding on [victim]."), span_green("You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].")) @@ -140,7 +140,7 @@ user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.name] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) playsound(I, 'sound/surgery/cautery1.ogg', 75, TRUE, falloff_exponent = 1) - if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult * I.toolspeed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult * I.toolspeed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return playsound(I, 'sound/surgery/cautery2.ogg', 75, TRUE, falloff_exponent = 1) diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 88e15955d55a..9d75413268af 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -171,7 +171,7 @@ user.visible_message(span_warning("[user] begins aiming [lasgun] directly at [victim]'s [limb.name]..."), span_userdanger("You begin aiming [lasgun] directly at [user == victim ? "your" : "[victim]'s"] [limb.name]...")) playsound(lasgun, 'sound/surgery/cautery1.ogg', 75, TRUE, falloff_exponent = 1) - if(!do_after(user, base_treat_time * self_penalty_mult, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * self_penalty_mult, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return playsound(lasgun, 'sound/surgery/cautery2.ogg', 75, TRUE, falloff_exponent = 1) @@ -195,7 +195,7 @@ user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.name] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) playsound(I, 'sound/surgery/cautery1.ogg', 75, TRUE, falloff_exponent = 1) - if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult * I.toolspeed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult * I.toolspeed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return playsound(I, 'sound/surgery/cautery2.ogg', 75, TRUE, falloff_exponent = 1) @@ -219,7 +219,7 @@ user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.name] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.name] with [I]...")) playsound(I, pick(I.apply_sounds), 25) - if(!do_after(user, base_treat_time * self_penalty_mult * I.treatment_speed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) + if(!do_after(user, base_treat_time * self_penalty_mult * I.treatment_speed, victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)), skill_check = SKILL_PHYSIOLOGY)) return user.visible_message(span_green("[user] stitches up some of the bleeding on [victim]."), span_green("You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"].")) diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 6886963b44f9..90ffa66534e3 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -357,8 +357,9 @@ . = TRUE - add_fingerprint(usr) - usr.set_machine(src) + var/mob/user = usr + add_fingerprint(user) + user.set_machine(src) switch(action) // Connect this DNA Console to a nearby DNA Scanner @@ -373,7 +374,7 @@ if(!scanner_operational()) return - connected_scanner.toggle_open(usr) + connected_scanner.toggle_open(user) return // Toggle the door bolts on the attached DNA Scanner @@ -395,7 +396,7 @@ scanner_occupant.dna.remove_all_mutations(list(MUT_NORMAL, MUT_EXTRA)) scanner_occupant.dna.generate_dna_blocks() - scrambleready = world.time + SCRAMBLE_TIMEOUT + scrambleready = world.time + SCRAMBLE_TIMEOUT * (10 - user.get_skill(SKILL_SCIENCE)) / 10 to_chat(usr,span_notice("DNA scrambled.")) scanner_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER*50/(connected_scanner.damage_coeff ** 2) return @@ -494,7 +495,7 @@ if((newgene == "J") && (jokerready < world.time)) var/truegenes = GET_SEQUENCE(path) newgene = truegenes[genepos] - jokerready = world.time + JOKER_TIMEOUT - (JOKER_UPGRADE * (connected_scanner.precision_coeff-1)) + jokerready = world.time + JOKER_TIMEOUT - (JOKER_UPGRADE * (connected_scanner.precision_coeff + user.get_skill(SKILL_SCIENCE) - 1)) // If the gene is an X, we want to update the default genes with the new // X to allow highlighting logic to work on the tgui interface. @@ -624,9 +625,9 @@ // to improve our injector's radiation generation if(scanner_operational()) I.damage_coeff = connected_scanner.damage_coeff*4 - injectorready = world.time + INJECTOR_TIMEOUT * (1 - 0.1 * connected_scanner.precision_coeff) + injectorready = world.time + INJECTOR_TIMEOUT * (1 - (connected_scanner.precision_coeff + user.get_skill(SKILL_SCIENCE)) / 10) else - injectorready = world.time + INJECTOR_TIMEOUT + injectorready = world.time + INJECTOR_TIMEOUT * (1 - user.get_skill(SKILL_SCIENCE) / 10) else I.name = "[HM.name] mutator" I.doitanyway = TRUE @@ -634,9 +635,9 @@ // to improve our injector's radiation generation if(scanner_operational()) I.damage_coeff = connected_scanner.damage_coeff - injectorready = world.time + INJECTOR_TIMEOUT * 5 * (1 - 0.1 * connected_scanner.precision_coeff) + injectorready = world.time + INJECTOR_TIMEOUT * 5 * (1 - (connected_scanner.precision_coeff + user.get_skill(SKILL_SCIENCE)) / 10) else - injectorready = world.time + INJECTOR_TIMEOUT * 5 + injectorready = world.time + INJECTOR_TIMEOUT * 5 * (1 - user.get_skill(SKILL_SCIENCE) / 10) return @@ -1159,7 +1160,7 @@ // If we successfully created an injector, don't forget to set the new // ready timer. if(I) - injectorready = world.time + INJECTOR_TIMEOUT + injectorready = world.time + INJECTOR_TIMEOUT * (1 - user.get_skill(SKILL_SCIENCE) / 10) return @@ -1256,7 +1257,7 @@ len = length(scanner_occupant.dna.unique_identity) if("uf") len = length(scanner_occupant.dna.unique_features) - rad_pulse_timer = world.time + (radduration*10) + rad_pulse_timer = world.time + (radduration * (10 - user.get_skill(SKILL_SCIENCE))) rad_pulse_index = WRAP(text2num(params["index"]), 1, len+1) begin_processing() return @@ -1346,9 +1347,9 @@ // to improve our injector's radiation generation if(scanner_operational()) I.damage_coeff = connected_scanner.damage_coeff - injectorready = world.time + INJECTOR_TIMEOUT * 8 * (1 - 0.1 * connected_scanner.precision_coeff) + injectorready = world.time + INJECTOR_TIMEOUT * 8 * (1 - (connected_scanner.precision_coeff + user.get_skill(SKILL_SCIENCE)) / 10) else - injectorready = world.time + INJECTOR_TIMEOUT * 8 + injectorready = world.time + INJECTOR_TIMEOUT * 8 * (1 - user.get_skill(SKILL_SCIENCE) / 10) return diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index d412c0c1adfe..899b7e70898c 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -1038,7 +1038,7 @@ visible_message("[user] starts to climb into [name].") - if(do_after(user, enter_delay, src)) + if(do_after(user, round(enter_delay * (check_eva()**2)), src, skill_check = null)) if(atom_integrity <= 0) to_chat(user, span_warning("You cannot get in the [name], it has been destroyed!")) else if(occupant) @@ -1372,18 +1372,9 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013??? if(QDELETED(I)) return -// Checks the pilot and their clothing for mech speed buffs +// Check the pilot for mech piloting skill /obj/mecha/proc/check_eva() - var/evaNum = 1 - if(ishuman(occupant)) - var/mob/living/carbon/human/H = occupant //if the person is skilled - var/datum/component/mech_pilot/skill = H.GetComponent(/datum/component/mech_pilot) - if(skill) - evaNum *= skill.piloting_speed - - var/obj/item/clothing/under/clothes = H.get_item_by_slot(ITEM_SLOT_ICLOTHING) //if the jumpsuit directly assists the pilot - if(clothes) - var/datum/component/mech_pilot/MP = clothes.GetComponent(/datum/component/mech_pilot) - if(MP) - evaNum *= MP.piloting_speed - return evaNum + var/effective_skill = occupant.get_skill(SKILL_TECHNICAL) + if(effective_skill < EXP_MASTER && HAS_TRAIT(occupant, TRAIT_SKILLED_PILOT)) + effective_skill += EXP_LOW // mech pilot suit adds extra pilot skill, up to EXP_MASTER + return (12 - effective_skill) / 10 diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index e5148836eabe..8cd30c749d27 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -212,7 +212,7 @@ if(wrecked) try_repair(tool, user) else if(atom_integrity < max_integrity) - while(atom_integrity < max_integrity && tool.use_tool(src, user, 1 SECONDS, volume=50, amount=1)) + while(atom_integrity < max_integrity && tool.use_tool(src, user, 1 SECONDS, volume=50, amount=1, skill_check = SKILL_MECHANICAL)) if(internal_damage & MECHA_INT_TANK_BREACH) clearInternalDamage(MECHA_INT_TANK_BREACH) to_chat(user, span_notice("You repair the damaged gas tank.")) @@ -334,9 +334,11 @@ return ..() /obj/mecha/proc/try_repair(obj/item/I, mob/living/user) - if(!capacitor?.rating) + if(!(capacitor || user.skill_check(SKILL_TECHNICAL, EXP_GENIUS) || user.skill_check(SKILL_MECHANICAL, EXP_GENIUS))) // with enough technical wizardry, you can repair ANY mech to_chat(user, span_warning("[src] is damaged beyond repair, there is nothing you can do.")) return + + var/effective_skill = user.get_skill(SKILL_MECHANICAL) + capacitor?.rating switch(repair_state) if(MECHA_WRECK_CUT) @@ -345,7 +347,7 @@ span_notice("[user] begins to weld together \the [src]'s broken parts..."), span_notice("You begin welding together \the [src]'s broken parts..."), ) - if(I.use_tool(src, user, 20 SECONDS / capacitor.rating, amount = 5, volume = 100, robo_check = TRUE)) + if(I.use_tool(src, user, 20 SECONDS / effective_skill, amount = 5, volume = 100, skill_check = SKILL_MECHANICAL)) repair_state = MECHA_WRECK_DENTED repair_hint = span_notice("The chassis has suffered major damage and will require the dents to be smoothed out with a welder.") to_chat(user, span_notice("The parts are loosely reattached, but are dented wildly out of place.")) @@ -356,7 +358,7 @@ span_notice("[user] welds out the many, many dents in \the [src]'s chassis..."), span_notice("You weld out the many, many dents in \the [src]'s chassis..."), ) - if(I.use_tool(src, user, 20 SECONDS / capacitor.rating, amount = 5, volume = 100, robo_check = TRUE)) + if(I.use_tool(src, user, 20 SECONDS / effective_skill, amount = 5, volume = 100, skill_check = SKILL_MECHANICAL)) repair_state = MECHA_WRECK_LOOSE repair_hint = span_notice("The mecha wouldn't make it two steps before falling apart. The bolts must be tightened with a wrench.") to_chat(user, span_notice("The chassis has been repaired, but the bolts are incredibly loose and need to be tightened.")) @@ -367,7 +369,7 @@ span_notice("[user] slowly tightens the bolts of \the [src]..."), span_notice("You slowly tighten the bolts of \the [src]..."), ) - if(I.use_tool(src, user, 18 SECONDS / capacitor.rating, volume = 50, robo_check = TRUE)) + if(I.use_tool(src, user, 18 SECONDS / effective_skill, volume = 50, skill_check = SKILL_MECHANICAL)) repair_state = MECHA_WRECK_UNWIRED repair_hint = span_notice("The mech is nearly ready, but the wiring has been fried and needs repair.") to_chat(user, span_notice("The bolts are tightened and the mecha is looking as good as new, but the wiring was fried in the destruction and needs repair.")) @@ -378,13 +380,14 @@ span_notice("[user] starts repairing the wiring on \the [src]..."), span_notice("You start repairing the wiring on \the [src]..."), ) - if(I.use_tool(src, user, 12 SECONDS / capacitor.rating, amount = 5, volume = 50, robo_check = TRUE)) + if(I.use_tool(src, user, 12 SECONDS / effective_skill, amount = 5, volume = 50, skill_check = SKILL_MECHANICAL)) repair_state = MECHA_WRECK_MISSING_CAPACITOR - repair_hint = span_notice("The wiring is functional, but it's still missing a capacitor.") + repair_hint = span_notice("The wiring is functional, but its capacitor needs to be replaced.") if(MECHA_WRECK_MISSING_CAPACITOR) if(istype(I, /obj/item/stock_parts/capacitor)) - QDEL_NULL(capacitor) + if(capacitor) + QDEL_NULL(capacitor) capacitor = I I.forceMove(src) user.visible_message(span_notice("[user] replaces the capacitor of \the [src].")) @@ -475,6 +478,8 @@ /obj/mecha/atom_break(damage_flag) . = ..() + if(wrecked) + return wrecked = TRUE repair_state = MECHA_WRECK_CUT repair_hint = span_notice("The parts are scattered apart, but can be welded back together.") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index a4af6863e9bf..f60f013f775c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -956,24 +956,29 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) // Called when a mob tries to use the item as a tool. // Handles most checks. -/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, robo_check) +/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_check = null) // No delay means there is no start message, and no reason to call tool_start_check before use_tool. // Run the start check here so we wouldn't have to call it manually. if(!delay && !tool_start_check(user, amount)) return delay *= toolspeed - if(((IS_ENGINEERING(user) || (robo_check && IS_JOB(user, "Roboticist"))) && (tool_behaviour in MECHANICAL_TOOLS)) || (IS_MEDICAL(user) && (tool_behaviour in MEDICAL_TOOLS))) - delay *= 0.8 // engineers and doctors use their own tools faster - if(volume) // Play tool sound at the beginning of tool usage. play_tool_sound(target, volume) if(delay) // Create a callback with checks that would be called every tick by do_after. var/datum/callback/tool_check = CALLBACK(src, PROC_REF(tool_check_callback), user, amount, extra_checks) - - if(!do_after(user, delay, target, extra_checks=tool_check)) + if(!skill_check) + if(is_wire_tool(src)) + skill_check = SKILL_TECHNICAL + else if(tool_behaviour in MECHANICAL_TOOLS) + skill_check = SKILL_MECHANICAL + else if(tool_behaviour in MEDICAL_TOOLS) + skill_check = SKILL_PHYSIOLOGY + else + skill_check = SKILL_FITNESS // hatchets and pickaxes + if(!do_after(user, delay, target, extra_checks=tool_check, skill_check=skill_check)) return else // Invoke the extra checks once, just in case. diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 3c393210f154..3e2644baeeec 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -603,7 +603,7 @@ GENE SCANNER /obj/item/analyzer/attack_self(mob/user) add_fingerprint(user) - scangasses(user) //yogs start: Makes the gas scanning able to be used elseware + atmosanalyzer_scan(user, user.loc) //yogs start: Makes the gas scanning able to be used elseware /obj/item/analyzer/afterattack(atom/target as obj, mob/user, proximity) if(!proximity) @@ -773,10 +773,10 @@ GENE SCANNER else combined_msg += span_notice("[target] is empty!") - if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected - var/instability = round(cached_scan_results["fusion"], 0.01) + if(cached_scan_results && cached_scan_results["fusion"] && user.skill_check(SKILL_SCIENCE, EXP_LOW)) //notify the user if a fusion reaction was detected combined_msg += span_boldnotice("Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.") - combined_msg += span_notice("Instability of the last fusion reaction: [instability].") + if(user.skill_check(SKILL_SCIENCE, EXP_MID)) + combined_msg += span_notice("Instability of the last fusion reaction: [round(cached_scan_results["fusion"], 0.01)].") to_chat(user, examine_block(combined_msg.Join("\n"))) return TRUE diff --git a/code/game/objects/items/granters/mech_piloting.dm b/code/game/objects/items/granters/mech_piloting.dm index 9792539ef6fc..33c82f565fed 100644 --- a/code/game/objects/items/granters/mech_piloting.dm +++ b/code/game/objects/items/granters/mech_piloting.dm @@ -14,4 +14,4 @@ /obj/item/book/granter/mechpiloting/on_reading_finished(mob/user) . = ..() - user.AddComponent(/datum/component/mech_pilot, 0.8) + user.adjust_skill(SKILL_TECHNICAL, EXP_MID, max_skill = EXP_GENIUS) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 741da1e7256b..e262a1d8af55 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -52,13 +52,13 @@ playsound(src, pick(apply_sounds), 25) if(!silent) user.visible_message(span_notice("[user] starts to apply \the [src] on [user.p_them()]self..."), span_notice("You begin applying \the [src] on yourself...")) - if(!do_after(user, self_delay, M, extra_checks=CALLBACK(M, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE))) + if(!do_after(user, self_delay, M, extra_checks=CALLBACK(M, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE), skill_check = SKILL_PHYSIOLOGY)) return else if(other_delay) playsound(src, pick(apply_sounds), 25) if(!silent) user.visible_message(span_notice("[user] starts to apply \the [src] on [M]."), span_notice("You begin applying \the [src] on [M]...")) - if(!do_after(user, other_delay, M, extra_checks=CALLBACK(M, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE))) + if(!do_after(user, other_delay, M, extra_checks=CALLBACK(M, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE), skill_check = SKILL_PHYSIOLOGY)) return if(heal(M, user)) @@ -180,7 +180,7 @@ /// Use other_delay if healing someone else (usually 1 second) /// Use self_delay if healing yourself (usually 3 seconds) /// Reduce delay by 20% if medical - if(!do_after(user, (user == M ? self_delay : other_delay) * (IS_MEDICAL(user) ? 0.8 : 1), M)) + if(!do_after(user, (user == M ? self_delay : other_delay) * (IS_MEDICAL(user) ? 0.8 : 1), M, skill_check = SKILL_PHYSIOLOGY)) return playsound(src, 'sound/effects/rip1.ogg', 25) diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 5f202eb38222..fe17d95cb452 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -166,7 +166,7 @@ update_appearance(UPDATE_ICON) -/obj/item/weldingtool/use_tool(atom/target, mob/living/user, delay, amount, volume, datum/callback/extra_checks, robo_check) +/obj/item/weldingtool/use_tool(atom/target, mob/living/user, delay, amount, volume, datum/callback/extra_checks, skill_check) target.add_overlay(sparks) . = ..() target.cut_overlay(sparks) diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index e3b77da69693..e49470f9d176 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -48,6 +48,14 @@ flavour_text = "The wastes are sacred ground, its monsters a blessed bounty. \ You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest." assignedrole = "Ash Walker" + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_MID, + ) + skill_points = EXP_HIGH var/datum/team/ashwalkers/team /obj/effect/mob_spawn/human/ash_walker/special(mob/living/new_spawn) @@ -73,6 +81,14 @@ flavour_text = "The wastes are sacred ground, its monsters a blessed bounty. You and your people have become one with the tendril and its land. \ You have seen lights in the distance and from the skies: outsiders that come with greed in their hearts. Fresh sacrifices for your nest." assignedrole = "Ash Walker Shaman" + base_skills = list( + SKILL_PHYSIOLOGY = EXP_HIGH, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = EXP_LOW /datum/outfit/ashwalker name = "Ashwalker" @@ -608,6 +624,7 @@ GLOBAL_LIST_EMPTY(servant_golem_users) important_info = "Do not abandon the base or give supplies to NT employees under any circumstances." outfit = /datum/outfit/syndicate_empty/icemoon_base assignedrole = "Icemoon Syndicate" + skill_points = EXP_GENIUS // 5 skill points /obj/effect/mob_spawn/human/syndicate/icemoon_syndicate/special(mob/living/new_spawn) //oops! new_spawn.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) @@ -901,3 +918,6 @@ GLOBAL_LIST_EMPTY(servant_golem_users) /datum/outfit/syndicate_derelict_engi/post_equip(mob/living/carbon/human/H) H.faction |= ROLE_SYNDICATE + H.adjust_skill(SKILL_MECHANICAL, EXP_MID) + H.adjust_skill(SKILL_TECHNICAL, EXP_MID) + H.add_skill_points(EXP_MID) diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm index 4edbb2f306b4..9a6e3c6eb7db 100644 --- a/code/modules/antagonists/abductor/abductor.dm +++ b/code/modules/antagonists/abductor/abductor.dm @@ -90,6 +90,9 @@ H.real_name = "[team.name] [sub_role]" H.equipOutfit(outfit) + H.adjust_skill(SKILL_PHYSIOLOGY, EXP_GENIUS, max_skill = EXP_GENIUS) + H.adjust_skill(SKILL_TECHNICAL, EXP_GENIUS, max_skill = EXP_GENIUS) + H.adjust_skill(SKILL_SCIENCE, EXP_GENIUS, max_skill = EXP_GENIUS) //Teleport to ship for(var/obj/effect/landmark/abductor/LM in GLOB.landmarks_list) diff --git a/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm b/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm index c02c5c61dd9c..68a2e413ee5b 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsucker_mobs.dm @@ -225,7 +225,6 @@ additionalmessage = "You have mutated werewolf claws!" user.physiology.punchdamagehigh_bonus += 2.5 user.physiology.punchdamagelow_bonus += 2.5 - user.physiology.punchstunthreshold_bonus += 2.5 mutation = /obj/item/clothing/gloves/wolfclaws slot = ITEM_SLOT_GLOVES if(4) diff --git a/code/modules/antagonists/bloodsuckers/bloodsuckers.dm b/code/modules/antagonists/bloodsuckers/bloodsuckers.dm index cba129347f7f..e73ca1af3af8 100644 --- a/code/modules/antagonists/bloodsuckers/bloodsuckers.dm +++ b/code/modules/antagonists/bloodsuckers/bloodsuckers.dm @@ -251,10 +251,10 @@ all_powers.Grant(new_body) var/old_punchdamagelow var/old_punchdamagehigh - var/old_punchstunthreshold + var/old_punchstunchance var/old_species_punchdamagelow var/old_species_punchdamagehigh - var/old_species_punchstunthreshold + var/old_species_punchstunchance if(ishuman(old_body)) var/mob/living/carbon/human/old_user = old_body var/datum/species/old_species = old_user.dna.species @@ -262,15 +262,15 @@ //Keep track of what they were old_punchdamagelow = old_species.punchdamagelow old_punchdamagehigh = old_species.punchdamagehigh - old_punchstunthreshold = old_species.punchstunthreshold + old_punchstunchance = old_species.punchstunchance //Then reset them old_species.punchdamagelow = initial(old_species.punchdamagelow) old_species.punchdamagehigh = initial(old_species.punchdamagehigh) - old_species.punchstunthreshold = initial(old_species.punchstunthreshold) + old_species.punchstunchance = initial(old_species.punchstunchance) //Then save the new, old, original species values so we can use them in the next part. This is starting to get convoluted. old_species_punchdamagelow = old_species.punchdamagelow old_species_punchdamagehigh = old_species.punchdamagehigh - old_species_punchstunthreshold = old_species.punchstunthreshold + old_species_punchstunchance = old_species.punchstunchance if(ishuman(new_body)) var/mob/living/carbon/human/new_user = new_body var/datum/species/new_species = new_user.dna.species @@ -278,7 +278,7 @@ //Adjust new species punch damage new_species.punchdamagelow += (old_punchdamagelow - old_species_punchdamagelow) //Takes whatever DIFFERENCE you had between your punch damage and that of the baseline species new_species.punchdamagehigh += (old_punchdamagehigh - old_species_punchdamagehigh) //and adds it to your new species, thus preserving whatever bonuses you got - new_species.punchstunthreshold += (old_punchstunthreshold - old_species_punchstunthreshold) + new_species.punchstunchance += (old_punchstunchance - old_species_punchstunchance) //Give Bloodsucker Traits if(old_body) @@ -540,7 +540,7 @@ user.dna?.remove_all_mutations() user_species.punchdamagelow += 1 //lowest possible punch damage - 0 user_species.punchdamagehigh += 1 //highest possible punch damage - 9 - user_species.punchstunthreshold += 1 //To not change rng knockdowns + user_species.punchstunchance += 1 //To not change rng knockdowns /// Give Bloodsucker Traits owner.current.add_traits(bloodsucker_traits, BLOODSUCKER_TRAIT) /// No Skittish "People" allowed diff --git a/code/modules/antagonists/bloodsuckers/clans/_clan.dm b/code/modules/antagonists/bloodsuckers/clans/_clan.dm index b74fab47b9d4..0ffafd146f6f 100644 --- a/code/modules/antagonists/bloodsuckers/clans/_clan.dm +++ b/code/modules/antagonists/bloodsuckers/clans/_clan.dm @@ -182,7 +182,6 @@ user_species.punchdamagelow += 0.5 // This affects the hitting power of Brawn. user_species.punchdamagehigh += 0.5 - user_species.punchstunthreshold += 0.5 // We're almost done - Spend your Rank now. bloodsuckerdatum.bloodsucker_level++ diff --git a/code/modules/antagonists/bloodsuckers/powers/fortitude.dm b/code/modules/antagonists/bloodsuckers/powers/fortitude.dm index a84f1f2815df..9aa2837e81f1 100644 --- a/code/modules/antagonists/bloodsuckers/powers/fortitude.dm +++ b/code/modules/antagonists/bloodsuckers/powers/fortitude.dm @@ -106,7 +106,6 @@ to_chat(user, span_notice("Shadow tentacles form and attach themselves to your body, you feel as if your muscles have merged with the shadows!")) user.physiology.punchdamagehigh_bonus += 0.5 * level_current user.physiology.punchdamagelow_bonus += 0.5 * level_current - user.physiology.punchstunthreshold_bonus += 0.5 * level_current //So we dont give them stun baton hands /datum/action/cooldown/bloodsucker/fortitude/shadow/process() . = ..() @@ -125,4 +124,3 @@ bloodsuckerdatum.frenzygrab.remove(user) user.physiology.punchdamagehigh_bonus -= 0.5 * level_current user.physiology.punchdamagelow_bonus -= 0.5 * level_current - user.physiology.punchstunthreshold_bonus -= 0.5 * level_current diff --git a/code/modules/antagonists/bloodsuckers/powers/gangrel.dm b/code/modules/antagonists/bloodsuckers/powers/gangrel.dm index d5de69d59b08..3b125a3f16dc 100644 --- a/code/modules/antagonists/bloodsuckers/powers/gangrel.dm +++ b/code/modules/antagonists/bloodsuckers/powers/gangrel.dm @@ -78,7 +78,7 @@ playsound(user.loc, 'sound/creatures/gorilla.ogg', 50) user.dna.species.punchdamagelow += 10 user.dna.species.punchdamagehigh += 10 //very stronk - user.dna.species.punchstunthreshold += 10 + user.dna.species.punchstunchance += 10 user.dna.species.action_speed_coefficient *= 1.3 user.dna.species.armor += 15 bloodsuckerdatum.AddBloodVolume(50) diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 51b6ce24b2cd..e4fb643d8c68 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -33,6 +33,9 @@ W.on_reading_finished(brother) qdel(W) + brother.add_skill_points(EXP_HIGH) // extra skills + ADD_TRAIT(brother, TRAIT_EXCEPTIONAL_SKILL, type) + if(istype(brother)) var/obj/item/storage/box/bloodbrother/T = new() if(brother.equip_to_slot_or_del(T, ITEM_SLOT_BACKPACK)) diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index 53778771773e..b31b215080a7 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -261,6 +261,8 @@ if(!istype(H)) return H.equipOutfit(outfit) + H.add_skill_points(EXP_GENIUS) // 5 skill points to allocate, you can put it all into fitness or specialize as a medic or pilot + ADD_TRAIT(H, TRAIT_EXCEPTIONAL_SKILL, type) // allowed to allocate 5 points into a single skill /datum/antagonist/ert/greet() if(!ert_team) diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 2e53e926ab3e..e2c2a954800c 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -32,6 +32,9 @@ H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs H.equipOutfit(nukeop_outfit) + + H.add_skill_points(EXP_GENIUS) // 5 skill points to allocate, you can put it all into fitness or specialize as a medic or pilot + ADD_TRAIT(H, TRAIT_EXCEPTIONAL_SKILL, ROLE_OPERATIVE) // allowed to allocate 5 points into a single skill return TRUE /datum/antagonist/nukeop/greet() diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index b7f67d15d085..e943160424bd 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -167,6 +167,15 @@ var/backpack_contents = -1 var/suit_store = -1 + var/list/base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_NONE, + ) + var/skill_points = 3 + var/hair_style var/facial_hair_style var/skin_tone @@ -200,6 +209,9 @@ H.skin_tone = skin_tone else H.skin_tone = random_skin_tone() + for(var/skill in base_skills) + H.adjust_skill(skill, base_skills[skill]) + H.add_skill_points(skill_points) H.update_hair() H.update_body() if(outfit) diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm index 61fe38fcfae0..50d18b0c6de1 100644 --- a/code/modules/clothing/under/costume.dm +++ b/code/modules/clothing/under/costume.dm @@ -270,10 +270,7 @@ fitted = NO_FEMALE_UNIFORM alternate_worn_layer = GLOVES_LAYER //covers hands but gloves can go over it. This is how these things work in my head. can_adjust = FALSE - -/obj/item/clothing/under/costume/mech_suit/Initialize(mapload) - . = ..() - AddComponent(/datum/component/mech_pilot, 0.9) + clothing_traits = list(TRAIT_SKILLED_PILOT) /obj/item/clothing/under/costume/mech_suit/white name = "white mech pilot's suit" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index feece142b66d..58f919e399ee 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -804,43 +804,6 @@ armor = list(MELEE = 10, BULLET = 0, LASER = 10, ENERGY = 0, BOMB = 5, BIO = 0, RAD = 0, FIRE = 40, ACID = 10, WOUND= 5) mutantrace_variation = MUTANTRACE_VARIATION -/obj/item/clothing/under/mech_suit - name = "red mech pilot's suit" - desc = "A red mech pilot's suit. Might make your butt look big." - icon_state = "red_mech_suit" - item_state = "red_mech_suit" - body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - fitted = NO_FEMALE_UNIFORM - alternate_worn_layer = GLOVES_LAYER //covers hands but gloves can go over it. This is how these things work in my head. - can_adjust = FALSE - -/obj/item/clothing/under/mech_suit/Initialize(mapload) - ..() - AddComponent(/datum/component/mech_pilot, 0.9) - -/obj/item/clothing/under/mech_suit/white - name = "white mech pilot's suit" - desc = "A white mech pilot's suit. Very fetching." - icon_state = "white_mech_suit" - item_state = "white_mech_suit" - mutantrace_variation = MUTANTRACE_VARIATION - -/obj/item/clothing/under/mech_suit/blue - name = "blue mech pilot's suit" - desc = "A blue mech pilot's suit. For the more reluctant mech pilots." - icon_state = "blue_mech_suit" - item_state = "blue_mech_suit" - mutantrace_variation = MUTANTRACE_VARIATION - -/obj/item/clothing/under/mech_suit/cybersun - name = "Cybersun mech pilot's suit" - desc = "An armored mech pilot suit, used exclusively by Cybersun mech agents." - icon_state = "black_mech_suit" - item_state = "black_mech_suit" - armor = list(MELEE = 15, BULLET = 15, LASER = 10, ENERGY = 10, BOMB = 50, BIO = 50, RAD = 20, FIRE = 50, ACID = 50, WOUND = 5) - mutantrace_variation = MUTANTRACE_VARIATION - /obj/item/clothing/under/lampskirt name = "lamp dress" desc = "A peculier garment woven in silk; under the lower dress appears to be a lamp and a switch." diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 1f6a890a010f..e8bacbe9ea96 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -56,12 +56,14 @@ return 1 return 0 -/obj/item/reagent_containers/food/snacks/grown/examine(user) +/obj/item/reagent_containers/food/snacks/grown/examine(mob/user) . = ..() if(seed) for(var/datum/plant_gene/trait/T in seed.genes) if(T.examine_line) . += T.examine_line + if(user.skill_check(SKILL_SCIENCE, EXP_LOW)) // science skill lets you estimate a plant's stats by examining it + . += seed.get_analyzer_text(user, TRUE) /// Ghost attack proc /obj/item/reagent_containers/food/snacks/grown/attack_ghost(mob/user) @@ -84,26 +86,28 @@ /obj/item/reagent_containers/food/snacks/grown/attackby(obj/item/O, mob/user, params) ..() if (istype(O, /obj/item/plant_analyzer)) - playsound(src, 'sound/effects/fastbeep.ogg', 30) - var/msg = "This is \a [span_name("[src]")].\n" - if(seed) - msg += seed.get_analyzer_text() - var/reag_txt = "" - if(seed) - for(var/reagent_id in seed.reagents_add) - var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id] - var/amt = reagents.get_reagent_amount(reagent_id) - reag_txt += "\n[span_info("- [R.name]: [amt]")]" - - if(reag_txt) - msg += reag_txt - msg += "
[span_info("")]" - to_chat(user, examine_block(msg)) + analyze_plant(user) else if(seed) for(var/datum/plant_gene/trait/T in seed.genes) T.on_attackby(src, O, user) +/obj/item/reagent_containers/food/snacks/grown/proc/analyze_plant(mob/user) + playsound(src, 'sound/effects/fastbeep.ogg', 30) + var/msg = "This is \a [span_name("[src]")].\n" + if(seed) + msg += seed.get_analyzer_text(user) + var/reag_txt = "" + if(seed) + for(var/reagent_id in seed.reagents_add) + var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id] + var/amt = reagents.get_reagent_amount(reagent_id) + reag_txt += "\n[span_info("- [R.name]: [amt]")]" + + if(reag_txt) + msg += reag_txt + msg += "
[span_info("")]" + to_chat(user, examine_block(msg)) // Various gene procs /obj/item/reagent_containers/food/snacks/grown/attack_self(mob/user) diff --git a/code/modules/hydroponics/grown/kudzu.dm b/code/modules/hydroponics/grown/kudzu.dm index 1e888fe5a1bf..74de8046bfed 100644 --- a/code/modules/hydroponics/grown/kudzu.dm +++ b/code/modules/hydroponics/grown/kudzu.dm @@ -47,12 +47,13 @@ plant(user) to_chat(user, span_notice("You plant the kudzu. You monster.")) -/obj/item/seeds/kudzu/get_analyzer_text() +/obj/item/seeds/kudzu/get_analyzer_text(mob/user, check_skills = FALSE) var/text = ..() - var/text_string = "" - for(var/datum/spacevine_mutation/SM in mutations) - text_string += "[(text_string == "") ? "" : ", "][SM.name]" - text += "\n Plant Mutations: [(text_string == "") ? "None" : text_string]" + if(!check_skills || user.skill_check(SKILL_SCIENCE, EXP_HIGH)) + var/text_string = "" + for(var/datum/spacevine_mutation/SM in mutations) + text_string += "[(text_string == "") ? "" : ", "][SM.name]" + text += "\n Plant Mutations: [(text_string == "") ? "None" : text_string]" return text /obj/item/seeds/kudzu/on_chem_reaction(datum/reagents/S) diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm index 323dafd1e3a9..a8c69a303eb6 100644 --- a/code/modules/hydroponics/growninedible.dm +++ b/code/modules/hydroponics/growninedible.dm @@ -32,6 +32,11 @@ w_class = round((seed.potency / 100) * 2, 1) + 1 //more potent plants are larger add_juice() +/obj/item/grown/examine(mob/user) + . = ..() + if(user.skill_check(SKILL_SCIENCE, EXP_LOW)) + . += seed.get_analyzer_text(user, TRUE) + /// Ghost attack proc /obj/item/grown/attack_ghost(mob/user) ..() diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 51a277060ef7..9ed9411eb882 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -301,7 +301,7 @@ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_harvest3")) -/obj/machinery/hydroponics/examine(user) +/obj/machinery/hydroponics/examine(mob/user) . = ..() if(myseed) . += span_info("It has [span_name("[myseed.plantname]")] planted.") @@ -311,6 +311,9 @@ . += span_info("It's ready to harvest.") else if (plant_health <= (myseed.endurance / 2)) . += span_warning("It looks unhealthy.") + + if(user.skill_check(SKILL_SCIENCE, EXP_LOW)) + . += myseed.get_analyzer_text(user, TRUE) else . += span_info("It's empty.") @@ -327,8 +330,6 @@ to_chat(user, span_warning("It's filled with weeds!")) if(pestlevel >= 5) to_chat(user, span_warning("It's filled with tiny worms!")) - to_chat(user, "" ) - /obj/machinery/hydroponics/proc/weedinvasion() // If a weed growth is sufficient, this happens. dead = 0 @@ -983,9 +984,9 @@ /obj/machinery/hydroponics/soil/update_icon_lights() return // Has no lights -/obj/machinery/hydroponics/soil/attackby(obj/item/O, mob/user, params) - if(O.tool_behaviour == TOOL_SHOVEL && !istype(O, /obj/item/shovel/spade)) //Doesn't include spades because of uprooting plants +/obj/machinery/hydroponics/soil/attackby_secondary(obj/item/weapon, mob/user, params) + if(weapon.tool_behaviour == TOOL_SHOVEL) to_chat(user, span_notice("You clear up [src]!")) qdel(src) - else - return ..() + return SECONDARY_ATTACK_CONTINUE_CHAIN + return ..() diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index 62e0e73fdece..7ea45326e59e 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -1,3 +1,7 @@ +/// Randomized plant stat with a set amount of inaccuracy +#define RANDOMIZE_PLANT_STAT(plant_stat, inaccuracy) ((inaccuracy && plant_stat >= round(1 / inaccuracy, 1)) ? \ + ("[plant_stat + rand(inaccuracy)*plant_stat - inaccuracy]-[plant_stat + rand(inaccuracy)*plant_stat]") : plant_stat) + // ******************************************************** // Here's all the seeds (plants) that can be used in hydro // ******************************************************** @@ -288,35 +292,39 @@ C.value = weed_chance -/obj/item/seeds/proc/get_analyzer_text() //in case seeds have something special to tell to the analyzer +/obj/item/seeds/proc/get_analyzer_text(mob/user, check_skills = FALSE) //in case seeds have something special to tell to the analyzer var/text = "" - if(!get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && !get_gene(/datum/plant_gene/trait/plant_type/alien_properties)) - text += "- Plant type: Normal plant\n" - if(get_gene(/datum/plant_gene/trait/plant_type/weed_hardy)) - text += "- Plant type: Weed. Can grow in nutrient-poor soil.\n" - if(get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) - text += "- Plant type: Mushroom. Can grow in dry soil.\n" - if(get_gene(/datum/plant_gene/trait/plant_type/alien_properties)) - text += "- Plant type: [span_warning("UNKNOWN")] \n" - if(potency != -1) - text += "- Potency: [potency]\n" - if(yield != -1) - text += "- Yield: [yield]\n" - text += "- Maturation speed: [maturation]\n" - if(yield != -1) - text += "- Production speed: [production]\n" - text += "- Endurance: [endurance]\n" - text += "- Lifespan: [lifespan]\n" - text += "- Weed Growth Rate: [weed_rate]\n" - text += "- Weed Vulnerability: [weed_chance]\n" - if(rarity) - text += "- Species Discovery Value: [rarity]\n" - var/all_traits = "" - for(var/datum/plant_gene/trait/traits in genes) - if(istype(traits, /datum/plant_gene/trait/plant_type)) - continue - all_traits += " [traits.get_name()]" - text += "- Plant Traits:[all_traits]\n" + if(!check_skills || user.skill_check(SKILL_SCIENCE, EXP_LOW)) // basic knowledge will tell you what a + if(!get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && !get_gene(/datum/plant_gene/trait/plant_type/alien_properties)) + text += "- Plant type: Normal plant\n" + if(get_gene(/datum/plant_gene/trait/plant_type/weed_hardy)) + text += "- Plant type: Weed. Can grow in nutrient-poor soil.\n" + if(get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) + text += "- Plant type: Mushroom. Can grow in dry soil.\n" + if(get_gene(/datum/plant_gene/trait/plant_type/alien_properties)) + text += "- Plant type: [span_warning("UNKNOWN")] \n" + if(!check_skills || user.skill_check(SKILL_SCIENCE, EXP_HIGH)) + var/inaccuracy = check_skills ? (EXP_GENIUS - user.get_skill(SKILL_SCIENCE)) / (EXP_GENIUS * 4) : 0 + if(potency != -1) + text += "- Potency: [RANDOMIZE_PLANT_STAT(potency, inaccuracy)]\n" + if(yield != -1) + text += "- Yield: [RANDOMIZE_PLANT_STAT(yield, inaccuracy)]\n" + text += "- Maturation speed: [RANDOMIZE_PLANT_STAT(maturation, inaccuracy)]\n" + if(yield != -1) + text += "- Production speed: [RANDOMIZE_PLANT_STAT(production, inaccuracy)]\n" + text += "- Endurance: [RANDOMIZE_PLANT_STAT(endurance, inaccuracy)]\n" + text += "- Lifespan: [RANDOMIZE_PLANT_STAT(lifespan, inaccuracy)]\n" + text += "- Weed Growth Rate: [RANDOMIZE_PLANT_STAT(weed_rate, inaccuracy)]\n" + text += "- Weed Vulnerability: [RANDOMIZE_PLANT_STAT(weed_chance, inaccuracy)]\n" + if(rarity) + text += "- Species Discovery Value: [rarity]\n" + if(!check_skills || user.skill_check(SKILL_SCIENCE, EXP_MID)) + var/all_traits = "" + for(var/datum/plant_gene/trait/traits in genes) + if(istype(traits, /datum/plant_gene/trait/plant_type)) + continue + all_traits += " [traits.get_name()]" + text += "- Plant Traits:[all_traits]\n" text += "" @@ -328,7 +336,7 @@ /// Ghost attack proc /obj/item/seeds/attack_ghost(mob/user) to_chat(user, span_info("This is \a [span_name("[src]")].")) - var/text = get_analyzer_text() + var/text = get_analyzer_text(user) if(text) to_chat(user, span_notice("[text]")) @@ -336,7 +344,7 @@ if (istype(O, /obj/item/plant_analyzer)) playsound(src, 'sound/effects/fastbeep.ogg', 30) to_chat(user, span_info("This is \a [span_name("[src]")].")) - var/text = get_analyzer_text() + var/text = get_analyzer_text(user) if(text) to_chat(user, span_notice("[text]")) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 93eb97a31e59..10f75f860354 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -77,6 +77,18 @@ ///Lazylist of traits added to the liver of the mob assigned this job (used for the classic "cops heal from donuts" reaction, among others) var/list/liver_traits = null + /// Baseline skill levels this job should have + var/list/base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_NONE, + ) + + /// Number of free skill points to allocate + var/skill_points = 3 + /// Display order of the job var/display_order = JOB_DISPLAY_ORDER_DEFAULT @@ -209,6 +221,10 @@ H.dna.species.after_equip_job(src, H, visualsOnly) + for(var/skill in base_skills) + H.adjust_skill(skill, base_skills[skill]) + H.add_skill_points(skill_points) + if(!visualsOnly && announce) announce(H) diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm index 9df34178ac02..fca0d5107e25 100644 --- a/code/modules/jobs/job_types/ai.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -15,6 +15,15 @@ display_order = JOB_DISPLAY_ORDER_AI var/do_special_check = TRUE + base_skills = list( + SKILL_PHYSIOLOGY = EXP_MASTER, + SKILL_MECHANICAL = EXP_MASTER, + SKILL_TECHNICAL = EXP_MASTER, + SKILL_SCIENCE = EXP_MASTER, + SKILL_FITNESS = EXP_NONE, // it can't fucking MOVE + ) + skill_points = 0 + departments_list = list( /datum/job_department/silicon, ) diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm index 01444973c938..a2a8859c0c84 100644 --- a/code/modules/jobs/job_types/atmospheric_technician.dm +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -20,6 +20,15 @@ display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN minimal_character_age = 24 //Intense understanding of thermodynamics, gas law, gas interaction, construction and safe containment of gases, creation of new ones, math beyond your wildest imagination + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_LOW, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_LOW, + SKILL_FITNESS = EXP_LOW, + ) + skill_points = 3 + departments_list = list( /datum/job_department/engineering, ) diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm index e413975af63f..606ffd0346f3 100644 --- a/code/modules/jobs/job_types/botanist.dm +++ b/code/modules/jobs/job_types/botanist.dm @@ -19,6 +19,15 @@ display_order = JOB_DISPLAY_ORDER_BOTANIST minimal_character_age = 22 //Biological understanding of plants and how to manipulate their DNAs and produces relatively "safely". Not just something that comes to you without education + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_MID, + SKILL_FITNESS = EXP_LOW, + ) + skill_points = 2 + departments_list = list( /datum/job_department/service, ) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index fde18435cb5d..19a07163b5ef 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -30,6 +30,15 @@ /datum/job_department/command, ) + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_MID, + ) + skill_points = 2 + mind_traits = list(TRAIT_DISK_VERIFIER) mail_goodies = list( diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm index 5beb433c9e41..1536fcbdfbe4 100644 --- a/code/modules/jobs/job_types/chemist.dm +++ b/code/modules/jobs/job_types/chemist.dm @@ -24,6 +24,15 @@ display_order = JOB_DISPLAY_ORDER_CHEMIST minimal_character_age = 24 //A lot of experimental drugs plus understanding the facilitation and purpose of several subtances; what treats what and how to safely manufacture it + base_skills = list( + SKILL_PHYSIOLOGY = EXP_LOW, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_HIGH, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 2 + departments_list = list( /datum/job_department/medical, ) diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index de80adfed05c..07f44886c2ab 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -17,6 +17,15 @@ exp_type_department = EXP_TYPE_ENGINEERING alt_titles = list("Engineering Director", "Head of Engineering", "Senior Engineer", "Chief Engineering Officer") + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_MID, + SKILL_TECHNICAL = EXP_MID, + SKILL_SCIENCE = EXP_LOW, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 3 // lots of different skills required + outfit = /datum/outfit/job/ce added_access = list(ACCESS_CAPTAIN, ACCESS_AI_MASTER) diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index c24f83422b19..902e90b6141f 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -32,6 +32,15 @@ display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER minimal_character_age = 30 //Do you knoW HOW MANY JOBS YOU HAVE TO KNOW TO DO?? This should really be like 35 or something + base_skills = list( + SKILL_PHYSIOLOGY = EXP_MID, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_MID, + SKILL_FITNESS = EXP_LOW, + ) + skill_points = 3 + departments_list = list( /datum/job_department/medical, /datum/job_department/command, diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm index c754aed3dc92..f5ea848a83de 100644 --- a/code/modules/jobs/job_types/detective.dm +++ b/code/modules/jobs/job_types/detective.dm @@ -26,6 +26,15 @@ display_order = JOB_DISPLAY_ORDER_DETECTIVE minimal_character_age = 22 //Understanding of forensics, crime analysis, and theory. Less of a grunt officer and more of an intellectual, theoretically, despite how this is never reflected in-game + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_MID, + SKILL_FITNESS = EXP_LOW, + ) + skill_points = 2 + departments_list = list( /datum/job_department/security, ) diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm index 9140376187a4..3f50f875df7d 100644 --- a/code/modules/jobs/job_types/geneticist.dm +++ b/code/modules/jobs/job_types/geneticist.dm @@ -22,6 +22,15 @@ display_order = JOB_DISPLAY_ORDER_GENETICIST minimal_character_age = 24 //Genetics would likely require more education than your average position due to the sheer number of alien physiologies and experimental nature of the field + base_skills = list( + SKILL_PHYSIOLOGY = EXP_LOW, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_HIGH, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 2 + departments_list = list( /datum/job_department/medical, ) diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index 173c9f052cef..024354102c88 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -37,6 +37,15 @@ display_order = JOB_DISPLAY_ORDER_HEAD_OF_SECURITY minimal_character_age = 28 //You need some experience on your belt and a little gruffiness; you're still a foot soldier, not quite a tactician commander back at base + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_HIGH, + ) + skill_points = 1 // officers don't really have much to do + departments_list = list( /datum/job_department/security, /datum/job_department/command, diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index 284c7c33629b..7a0b23e08d40 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -28,6 +28,14 @@ /datum/job_department/medical, ) + base_skills = list( + SKILL_PHYSIOLOGY = EXP_HIGH, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_LOW, + SKILL_FITNESS = EXP_NONE, + ) + mail_goodies = list( /obj/item/healthanalyzer/advanced = 15, /obj/effect/spawner/lootdrop/surgery_tool_advanced = 6, diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 21537077bb69..f8fc1cc681c3 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -37,6 +37,15 @@ display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR minimal_character_age = 26 //Barely knows more than actual scientists, just responsibility and AI things + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_MID, + SKILL_SCIENCE = EXP_HIGH, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 2 + departments_list = list( /datum/job_department/science, /datum/job_department/command, diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index ffd5560039da..c81f10ba52ca 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -23,6 +23,15 @@ display_order = JOB_DISPLAY_ORDER_ROBOTICIST minimal_character_age = 22 //Engineering, AI theory, robotic knowledge and the like + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_LOW, + SKILL_TECHNICAL = EXP_MID, + SKILL_SCIENCE = EXP_LOW, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 2 + departments_list = list( /datum/job_department/science, ) diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm index a97b7dca3ab0..9b4f9c72a3a2 100644 --- a/code/modules/jobs/job_types/scientist.dm +++ b/code/modules/jobs/job_types/scientist.dm @@ -24,6 +24,15 @@ display_order = JOB_DISPLAY_ORDER_SCIENTIST minimal_character_age = 24 //Consider the level of knowledge that spans xenobio, nanites, and toxins + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_MID, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 3 + departments_list = list( /datum/job_department/science, ) diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index fed23668d65b..a621070c54f0 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -28,6 +28,15 @@ display_order = JOB_DISPLAY_ORDER_SECURITY_OFFICER minimal_character_age = 18 //Just a few months of boot camp, not a whole year + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_HIGH, + ) + skill_points = 1 // officers don't really have much to do + departments_list = list( /datum/job_department/security, ) diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index af917644e4e2..9b392fd37f2b 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -22,6 +22,15 @@ display_order = JOB_DISPLAY_ORDER_SHAFT_MINER minimal_character_age = 18 //Young and fresh bodies for a high mortality job, what more could you ask for + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_HIGH, + ) + skill_points = 2 // "unskilled" labor + departments_list = list( /datum/job_department/cargo, ) diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm index aab47082a52a..999373f05f36 100644 --- a/code/modules/jobs/job_types/station_engineer.dm +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -24,6 +24,15 @@ display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER minimal_character_age = 22 //You need to know a lot of complicated stuff about engines, could theoretically just have a traditional bachelor's + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_MID, + SKILL_TECHNICAL = EXP_LOW, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 3 + departments_list = list( /datum/job_department/engineering, ) diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm index 918a071ff94d..3ec880243ef4 100644 --- a/code/modules/jobs/job_types/virologist.dm +++ b/code/modules/jobs/job_types/virologist.dm @@ -26,6 +26,15 @@ display_order = JOB_DISPLAY_ORDER_VIROLOGIST minimal_character_age = 24 //Requires understanding of microbes, biology, infection, and all the like, as well as being able to understand how to interface the machines. Epidemiology is no joke of a field + base_skills = list( + SKILL_PHYSIOLOGY = EXP_MID, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_MID, + SKILL_FITNESS = EXP_NONE, + ) + skill_points = 2 + departments_list = list( /datum/job_department/medical, ) diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index 7e0791411c37..ae6182c0ec48 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -30,6 +30,15 @@ display_order = JOB_DISPLAY_ORDER_WARDEN minimal_character_age = 20 //You're a sergeant, probably has some experience in the field + base_skills = list( + SKILL_PHYSIOLOGY = EXP_NONE, + SKILL_MECHANICAL = EXP_NONE, + SKILL_TECHNICAL = EXP_NONE, + SKILL_SCIENCE = EXP_NONE, + SKILL_FITNESS = EXP_HIGH, + ) + skill_points = 1 // officers don't really have much to do + departments_list = list( /datum/job_department/security, ) diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index a18772061cfe..74659a68cbb9 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -199,6 +199,7 @@ var/unique = 0 //0 - Normal book, 1 - Should not be treated as normal book, unable to be copied, unable to be modified var/title //The real name of the book. var/window_size = null // Specific window size for the book, i.e: "1920x1080", Size x Width + var/list/skill_gain /obj/item/book/attack_self(mob/user) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index d942bc2dface..0a8695a97530 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -106,8 +106,8 @@ GLOBAL_LIST_EMPTY(features_by_species) var/punchdamagelow = 1 ///highest possible punch damage var/punchdamagehigh = 10 - ///damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical - var/punchstunthreshold = 10 + ///chance for a punch to stun + var/punchstunchance = 0.1 ///values of inaccuracy that adds to the spread of any ranged weapon var/aiminginaccuracy = 0 ///base electrocution coefficient @@ -1731,6 +1731,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(M) M.handle_counter(target, user) return FALSE + user.add_exp(SKILL_FITNESS, 5) if(attacker_style && attacker_style.harm_act(user,target)) return TRUE else @@ -1741,7 +1742,8 @@ GLOBAL_LIST_EMPTY(features_by_species) atk_verb = "kick" atk_effect = ATTACK_EFFECT_KICK user.do_attack_animation(target, atk_effect) - var/damage = rand(user.get_punchdamagelow(), user.get_punchdamagehigh()) + var/percentile = rand() + var/damage = LERP(user.get_punchdamagelow(), user.get_punchdamagehigh(), percentile) var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected)) @@ -1782,7 +1784,7 @@ GLOBAL_LIST_EMPTY(features_by_species) target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) log_combat(user, target, "punched") - if((target.stat != DEAD) && damage >= user.get_punchstunthreshold()) + if((target.stat != DEAD) && percentile > (1 - user.get_punchstunchance()) && !HAS_TRAIT(user, TRAIT_NO_PUNCH_STUN)) target.visible_message(span_danger("[user] has knocked [target] down!"), \ span_userdanger("[user] has knocked [target] down!"), null, COMBAT_MESSAGE_RANGE) var/knockdown_duration = 40 + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 40 base stun + 40 stun modifier = 80 stun duration, which is the old base duration diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6d4a46637004..26564d9183c3 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -915,19 +915,33 @@ /mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target) var/carrydelay = 50 //if you have latex you are faster at grabbing var/skills_space = null // Changes depending on glove type + + var/nanochips = FALSE + var/effective_skill = get_skill(SKILL_FITNESS) if(HAS_TRAIT(src, TRAIT_QUICKEST_CARRY)) - carrydelay = 25 - skills_space = "masterfully" + effective_skill += EXP_HIGH + nanochips = TRUE else if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY)) - carrydelay = 30 - skills_space = "expertly" + effective_skill += EXP_MID + nanochips = TRUE else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY)) - carrydelay = 40 - skills_space = "quickly" + effective_skill += EXP_LOW + + switch(effective_skill) + if(EXP_MASTER to INFINITY) + carrydelay = 25 + skills_space = "masterfully" + if(EXP_MID to EXP_MASTER) + carrydelay = 30 + skills_space = "expertly" + if(EXP_LOW to EXP_MID) + carrydelay = 40 + skills_space = "quickly" + if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE)) visible_message(span_notice("[src] starts [skills_space] lifting [target] onto their back.."), //Joe Medic starts quickly/expertly lifting Grey Tider onto their back.. - span_notice("[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space ? "[skills_space] " : ""]start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]")) + span_notice("[nanochips ? "Using your gloves' nanochips, you" : "You"] [skills_space ? "[skills_space] " : ""]start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]")) //(Using your gloves' nanochips, you/You) ( /quickly/expertly) start to lift Grey Tider onto your back(, while assisted by the nanochips in your gloves../...) if(do_after(src, carrydelay, target)) //Second check to make sure they're still valid to be carried @@ -1071,6 +1085,10 @@ return FALSE return ..() +/mob/living/carbon/human/handle_skills(delta_time) + if(IS_SCIENCE(src)) // scientists give a small boost to science points based on science skill, more if they're the RD + SSresearch.science_tech.research_points[TECHWEB_POINT_TYPE_DEFAULT] += get_skill(SKILL_SCIENCE) * (IS_COMMAND(src) ? 2 : 1) + /mob/living/carbon/human/species var/race = null diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 876399540bd0..be90febd5a03 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -26,6 +26,8 @@ else if(bodypart_flag & cover.body_parts_partial_covered) protection += cover.armor.getRating(armor_flag) * 0.5 protection += physiology.armor.getRating(armor_flag) + if(armor_flag == MELEE) + protection += get_skill(SKILL_FITNESS) return protection ///Get all the clothing on a specific body part diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 8d81a51a33d3..8d1df1cbc55c 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -279,13 +279,13 @@ return dna.species.get_biological_state() /mob/living/carbon/human/proc/get_punchdamagehigh() //Gets the total maximum punch damage - return dna.species.punchdamagehigh + physiology.punchdamagehigh_bonus + return dna.species.punchdamagehigh + physiology.punchdamagehigh_bonus + (get_skill(SKILL_FITNESS) / 2) /mob/living/carbon/human/proc/get_punchdamagelow() //Gets the total minimum punch damage - return dna.species.punchdamagelow + physiology.punchdamagelow_bonus + return dna.species.punchdamagelow + physiology.punchdamagelow_bonus + get_skill(SKILL_FITNESS) -/mob/living/carbon/human/proc/get_punchstunthreshold() //Gets the total punch damage needed to knock down someone - return dna.species.punchstunthreshold + physiology.punchstunthreshold_bonus +/mob/living/carbon/human/proc/get_punchstunchance() //Gets the total chance to knock down someone + return dna.species.punchstunchance + physiology.punchstunchance_bonus /// Fully randomizes everything according to the given flags. /mob/living/carbon/human/proc/randomize_human_appearance(randomize_flags = ALL) diff --git a/code/modules/mob/living/carbon/human/physiology.dm b/code/modules/mob/living/carbon/human/physiology.dm index 76a869459e3a..a164c67ac0bf 100644 --- a/code/modules/mob/living/carbon/human/physiology.dm +++ b/code/modules/mob/living/carbon/human/physiology.dm @@ -30,7 +30,7 @@ var/punchdamagehigh_bonus = 0 //Increased maximum punch damage var/punchdamagelow_bonus = 0 //Increased minimum punch damage - var/punchstunthreshold_bonus = 0 //Increased stun threshhold on punches so we don't get knockdown hands + var/punchstunchance_bonus = 0 //Increased stun threshhold on punches so we don't get knockdown hands var/crawl_speed = 0 // Movement speed modifier when crawling diff --git a/code/modules/mob/living/carbon/human/species_types/IPC.dm b/code/modules/mob/living/carbon/human/species_types/IPC.dm index 9a2fb5ec28e8..831766fb4f4f 100644 --- a/code/modules/mob/living/carbon/human/species_types/IPC.dm +++ b/code/modules/mob/living/carbon/human/species_types/IPC.dm @@ -409,7 +409,7 @@ ipc martial arts stuff armor = 10 punchdamagelow = 5 punchdamagehigh = 12 - punchstunthreshold = 12 + punchstunchance = 0.2 mutant_organs = list() inherent_traits = list( TRAIT_RESISTCOLD, @@ -576,7 +576,7 @@ ipc martial arts stuff speedmod = -0.2 punchdamagelow = 10 punchdamagehigh = 19 - punchstunthreshold = 14 //about 50% chance to stun + punchstunchance = 0.5 //50% chance to stun disguise_fail_health = 35 changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN //admin only... sorta diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 69710b36a3f4..06abeb0e403d 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -20,7 +20,6 @@ coldmod = 2.0 //Don't extinguish the stars speedmod = -0.1 //Light and energy move quickly punchdamagehigh = 11 //Fire hand more painful - punchstunthreshold = 11 //Still stuns on max hit, but subsequently lower chance to stun overall attack_type = BURN //burn bish damage_overlay_type = "" //We are too cool for regular damage overlays species_traits = list(NOEYESPRITES, EYECOLOR, MUTCOLORS, HAIR, FACEHAIR, HAS_FLESH) // i mean i guess they have blood so they can have wounds too diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 610824967db8..db24367520c8 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -11,7 +11,7 @@ siemens_coeff = 0 punchdamagelow = 5 punchdamagehigh = 14 - punchstunthreshold = 11 //about 40% chance to stun + punchstunchance = 0.4 //40% chance to stun no_equip = list(ITEM_SLOT_MASK, ITEM_SLOT_OCLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET, ITEM_SLOT_ICLOTHING, ITEM_SLOT_SUITSTORE) nojumpsuit = 1 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC @@ -194,7 +194,7 @@ name = "Silver Golem" id = "silver golem" fixed_mut_color = "#dddddd" - punchstunthreshold = 9 //60% chance, from 40% + punchstunchance = 0.6 //60% chance, from 40% meat = /obj/item/stack/ore/silver info_text = "As a Silver Golem, your attacks have a higher chance of stunning. Being made of silver, your body is immune to most types of magic." prefix = "Silver" @@ -217,7 +217,6 @@ stunmod = 0.4 punchdamagelow = 12 punchdamagehigh = 21 - punchstunthreshold = 18 //still 40% stun chance speedmod = 4 //pretty fucking slow meat = /obj/item/stack/ore/iron info_text = "As a Plasteel Golem, you are slower, but harder to stun, and hit very hard when punching. You also magnetically attach to surfaces and so don't float without gravity and cannot have positions swapped with other beings." @@ -583,7 +582,7 @@ say_mod = "honks" punchdamagelow = 0 punchdamagehigh = 1 - punchstunthreshold = 2 //Harmless and can't stun + punchstunchance = 0 //Harmless and can't stun meat = /obj/item/stack/ore/bananium info_text = "As a Bananium Golem, you are made for pranking. Your body emits natural honks, and you can barely even hurt people when punching them. Your skin also bleeds banana peels when damaged." attack_verbs = list("honk") @@ -796,7 +795,7 @@ burnmod = 2 // don't get burned speedmod = 1 // not as heavy as stone punchdamagelow = 4 - punchstunthreshold = 7 + punchstunchance = 0.2 punchdamagehigh = 8 // not as heavy as stone prefix = "Cloth" special_names = null @@ -1049,7 +1048,7 @@ heatmod = 2 speedmod = 1.5 punchdamagelow = 4 - punchstunthreshold = 7 + punchstunchance = 0.2 punchdamagehigh = 8 var/last_creation = 0 var/brother_creation_cooldown = 300 @@ -1468,7 +1467,6 @@ burnmod = 0.75 speedmod = 1 // not as heavy as stone heatmod = 0.1 //very little damage, but still there. Its like how a candle doesn't melt in seconds but still melts. - punchstunthreshold = 7 punchdamagehigh = 9 // not as heavy as stone prefix = "Wax" special_names = list("Candelabra", "Candle") @@ -1663,7 +1661,7 @@ inherent_traits = list(TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOGUNS) speedmod = 1.5 // Slightly faster armor = 25 - punchstunthreshold = 13 + punchstunchance = 0.2 fixed_mut_color = "48002b" info_text = "As a Tar Golem, you burn very very easily and can temporarily turn yourself into a pool of tar, in this form you are invulnerable to all attacks." random_eligible = FALSE //If false, the golem subtype can't be made through golem mutation toxin diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 1ed6a54a442c..f918e4279785 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -220,7 +220,6 @@ burnmod = 1.15 speedmod = -0.1 //similar to ethereals, should help with saving others punchdamagehigh = 7 - punchstunthreshold = 7 action_speed_coefficient = 0.9 //they're smart and efficient unlike other lizards species_language_holder = /datum/language_holder/lizard/shaman var/datum/action/cooldown/spell/touch/heal/lizard_touch @@ -230,6 +229,7 @@ . = ..() lizard_touch = new(C) lizard_touch.Grant(C) + C.adjust_skill(SKILL_PHYSIOLOGY, EXP_HIGH) //removes the heal spell /datum/species/lizard/ashwalker/shaman/on_species_loss(mob/living/carbon/C) @@ -285,8 +285,7 @@ burnmod = 0.8 brutemod = 0.9 //something something dragon scales punchdamagelow = 3 - punchdamagehigh = 12 - punchstunthreshold = 12 //+2 claws of powergaming + punchdamagehigh = 12 //+2 claws of powergaming /datum/species/lizard/draconid/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 71dbd6c68c36..9d02cfde6563 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -19,7 +19,7 @@ burnmod = 1.25 //Fluffy and flammable brutemod = 0.9 //Evasive buggers punchdamagehigh = 9 //Weird fluffy bug fist - punchstunthreshold = 10 //No stun punches + punchstunchance = 0 //No stun punches mutanteyes = /obj/item/organ/eyes/moth changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT species_language_holder = /datum/language_holder/mothmen diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index d40d1473418c..037cbb99c868 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -17,7 +17,7 @@ punchdamagelow = 6 punchdamagehigh = 14 - punchstunthreshold = 14 //about 44% chance to stun + punchstunchance = 0.44 //44% chance to stun no_equip = list(ITEM_SLOT_MASK, ITEM_SLOT_OCLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET, ITEM_SLOT_ICLOTHING) diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index ade9a58e7d29..1c4993f950c8 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -20,7 +20,7 @@ burnmod = 0.9 //Plasma is a surprisingly good insulator if not around oxygen heatmod = 1.5 //Don't let the plasma actually heat up though punchdamagehigh = 7 //Bone punches are weak and usually inside soft suit gloves - punchstunthreshold = 7 //Stuns on max hit as usual, somewhat higher stun chance because math + punchstunchance = 0.15 //Stuns on max hit as usual, somewhat higher stun chance because math species_gibs = "plasma" breathid = GAS_PLASMA damage_overlay_type = ""//let's not show bloody wounds or burns over bones. diff --git a/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm b/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm index 8d16f1f25d68..0382ba8e374a 100644 --- a/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm +++ b/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm @@ -24,7 +24,6 @@ speedmod = -0.1 //apex predator humanoid hybrid inert_mutation = ACIDSPIT punchdamagehigh = 11 //slightly better high end of damage - punchstunthreshold = 11 //technically slightly worse stunchance damage_overlay_type = "polysmorph" species_gibs = "polysmorph" deathsound = 'sound/voice/hiss6.ogg' diff --git a/code/modules/mob/living/carbon/human/species_types/wy_synths.dm b/code/modules/mob/living/carbon/human/species_types/wy_synths.dm index af6cd3aadd05..9830a8120233 100644 --- a/code/modules/mob/living/carbon/human/species_types/wy_synths.dm +++ b/code/modules/mob/living/carbon/human/species_types/wy_synths.dm @@ -58,7 +58,7 @@ punchdamagehigh = 12 punchdamagelow = 5 - punchstunthreshold = 11 + punchstunchance = 0.2 var/last_warned diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 82d55c063c9e..8f23496c66dc 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -135,7 +135,7 @@ staminamod = 0.5 //difficult to subdue via nonlethal means punchdamagelow = 13 punchdamagehigh = 16 - punchstunthreshold = 17 //pretty good punch damage but no knockdown + punchstunchance = 0 //pretty good punch damage but no knockdown ///no guns or soft crit inherent_traits = list( TRAIT_STABLELIVER, diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index cbfc194eb95c..9669a7fa63cc 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -1,7 +1,7 @@ -/mob/living/proc/Life(seconds_per_tick = SSMOBS_DT, times_fired) +/mob/living/proc/Life(delta_time = SSMOBS_DT, times_fired) set waitfor = FALSE - var/signal_result = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds_per_tick, times_fired) + var/signal_result = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, delta_time, times_fired) if(signal_result & COMPONENT_LIVING_CANCEL_LIFE_PROCESSING) // mmm less work return @@ -69,6 +69,8 @@ //Yogs end handle_gravity() + handle_skills(delta_time) + if(stat != DEAD) handle_traits() // eye, ear, brain damages handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc @@ -147,3 +149,6 @@ if(gravity >= GRAVITY_DAMAGE_TRESHOLD) //Aka gravity values of 3 or more var/grav_stregth = gravity - GRAVITY_DAMAGE_TRESHOLD adjustBruteLoss(min(grav_stregth,3)) + +/mob/living/proc/handle_skills(delta_time) + return diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index e0f1e9c14e9a..5fc1ee5d8dd1 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -368,10 +368,10 @@ return var/sprd = 0 - var/randomized_gun_spread = 0 + var/randomized_gun_spread = EXP_GENIUS - user.get_skill(SKILL_FITNESS) var/rand_spr = rand() if(spread > 0) - randomized_gun_spread = rand(0,spread) + randomized_gun_spread += rand(0,spread) if(ishuman(user)) //nice shootin' tex var/mob/living/carbon/human/H = user bonus_spread += H.dna.species.aiminginaccuracy diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 630609d030a8..d89f55a352d5 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -222,7 +222,7 @@ else progress_flash_divisor-- -/obj/item/gun/energy/plasmacutter/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks, robo_check) +/obj/item/gun/energy/plasmacutter/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks, skill_check) if(amount) var/mutable_appearance/sparks = mutable_appearance('icons/effects/welding_effect.dmi', "welding_sparks", GASFIRE_LAYER, src, ABOVE_LIGHTING_PLANE) target.add_overlay(sparks) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 23d14a470841..2466a71b1c75 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1194,14 +1194,12 @@ All effects don't start immediately, but rather get worse over time; the rate is var/mob/living/carbon/human/guy = M guy.physiology.punchdamagehigh_bonus += 2 guy.physiology.punchdamagelow_bonus += 2 - guy.physiology.punchstunthreshold_bonus += 2 /datum/reagent/consumable/ethanol/amasec/on_mob_end_metabolize(mob/living/carbon/M) if(ishuman(M)) var/mob/living/carbon/human/guy = M guy.physiology.punchdamagehigh_bonus -= 2 guy.physiology.punchdamagelow_bonus -= 2 - guy.physiology.punchstunthreshold_bonus -= 2 return ..() /datum/reagent/consumable/ethanol/changelingsting diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm index 19dcfd4ee5cd..bb46be700fdb 100644 --- a/code/modules/shuttle/computer.dm +++ b/code/modules/shuttle/computer.dm @@ -184,7 +184,8 @@ log_admin("[usr] attempted to href dock exploit on [src] with target location \"[params["shuttle_id"]]\"") message_admins("[usr] just attempted to href dock exploit on [src] with target location \"[params["shuttle_id"]]\"") return - switch(SSshuttle.moveShuttle(shuttleId, params["shuttle_id"], 1)) + var/mob/user = usr + switch(SSshuttle.moveShuttle(shuttleId, params["shuttle_id"], 1, (10 - user.get_skill(SKILL_TECHNICAL)) / 10)) if(0) say("Shuttle departing. Please stand away from the doors.") return TRUE diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index e6feab8ec934..46b7fba4e0bc 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -692,7 +692,7 @@ message_admins("Shuttle [src] repeatedly failed to create transit zone.") //call the shuttle to destination S -/obj/docking_port/mobile/proc/request(obj/docking_port/stationary/S) +/obj/docking_port/mobile/proc/request(obj/docking_port/stationary/S, skill_multiplier = 1) if(!check_dock(S)) testing("check_dock failed on request for [src]") return @@ -703,22 +703,22 @@ switch(mode) if(SHUTTLE_CALL) if(S == destination) - if(timeLeft(1) < callTime * engine_coeff) - setTimer(callTime * engine_coeff) + if(timeLeft(1) < callTime * engine_coeff * skill_multiplier) + setTimer(callTime * engine_coeff * skill_multiplier) else destination = S - setTimer(callTime * engine_coeff) + setTimer(callTime * engine_coeff * skill_multiplier) if(SHUTTLE_RECALL) if(S == destination) - setTimer(callTime * engine_coeff - timeLeft(1)) + setTimer(callTime * engine_coeff * skill_multiplier - timeLeft(1)) else destination = S - setTimer(callTime * engine_coeff) + setTimer(callTime * engine_coeff * skill_multiplier) mode = SHUTTLE_CALL if(SHUTTLE_IDLE, SHUTTLE_IGNITING) destination = S mode = SHUTTLE_IGNITING - setTimer(ignitionTime) + setTimer(ignitionTime * skill_multiplier) //recall the shuttle to where it was previously /obj/docking_port/mobile/proc/cancel() diff --git a/code/modules/surgery/advanced/bioware/ligament_hook.dm b/code/modules/surgery/advanced/bioware/ligament_hook.dm index b4a5d18f864b..e98a50323aeb 100644 --- a/code/modules/surgery/advanced/bioware/ligament_hook.dm +++ b/code/modules/surgery/advanced/bioware/ligament_hook.dm @@ -17,6 +17,7 @@ name = "reshape ligaments" accept_hand = TRUE time = 12.5 SECONDS + difficulty = EXP_HIGH preop_sound = 'sound/surgery/bone1.ogg' success_sound = 'sound/surgery/bone3.ogg' diff --git a/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm b/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm index 9b8d190853cf..a4e4e5eb95af 100644 --- a/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm +++ b/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm @@ -17,6 +17,7 @@ name = "reinforce ligaments" accept_hand = TRUE time = 12.5 SECONDS + difficulty = EXP_HIGH preop_sound = 'sound/surgery/bone1.ogg' success_sound = 'sound/surgery/bone3.ogg' diff --git a/code/modules/surgery/advanced/bioware/muscled_veins.dm b/code/modules/surgery/advanced/bioware/muscled_veins.dm index 32352725b522..3ebabec7268d 100644 --- a/code/modules/surgery/advanced/bioware/muscled_veins.dm +++ b/code/modules/surgery/advanced/bioware/muscled_veins.dm @@ -16,6 +16,7 @@ name = "shape vein muscles" accept_hand = TRUE time = 12.5 SECONDS + difficulty = EXP_HIGH preop_sound = 'sound/surgery/organ2.ogg' success_sound = 'sound/surgery/organ1.ogg' diff --git a/code/modules/surgery/advanced/bioware/nerve_grounding.dm b/code/modules/surgery/advanced/bioware/nerve_grounding.dm index 32d1726b112c..b1cac2533e18 100644 --- a/code/modules/surgery/advanced/bioware/nerve_grounding.dm +++ b/code/modules/surgery/advanced/bioware/nerve_grounding.dm @@ -15,6 +15,7 @@ /datum/surgery_step/ground_nerves name = "ground nerves" accept_hand = TRUE + difficulty = EXP_HIGH time = 155 /datum/surgery_step/ground_nerves/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) diff --git a/code/modules/surgery/advanced/bioware/nerve_splicing.dm b/code/modules/surgery/advanced/bioware/nerve_splicing.dm index e26e57d96927..661cc512d147 100644 --- a/code/modules/surgery/advanced/bioware/nerve_splicing.dm +++ b/code/modules/surgery/advanced/bioware/nerve_splicing.dm @@ -16,6 +16,7 @@ name = "splice nerves" accept_hand = TRUE time = 15.5 SECONDS + difficulty = EXP_HIGH preop_sound = 'sound/surgery/organ2.ogg' success_sound = 'sound/surgery/organ1.ogg' diff --git a/code/modules/surgery/advanced/bioware/vein_threading.dm b/code/modules/surgery/advanced/bioware/vein_threading.dm index c212f624c91e..fcafcf08026d 100644 --- a/code/modules/surgery/advanced/bioware/vein_threading.dm +++ b/code/modules/surgery/advanced/bioware/vein_threading.dm @@ -16,6 +16,7 @@ name = "thread veins" accept_hand = TRUE time = 12.5 SECONDS + difficulty = EXP_HIGH preop_sound = 'sound/surgery/organ2.ogg' success_sound = 'sound/surgery/organ1.ogg' diff --git a/code/modules/surgery/advanced/brainwashing.dm b/code/modules/surgery/advanced/brainwashing.dm index 933c20340f19..e0c09326c23b 100644 --- a/code/modules/surgery/advanced/brainwashing.dm +++ b/code/modules/surgery/advanced/brainwashing.dm @@ -33,6 +33,7 @@ /datum/surgery_step/brainwash name = "brainwash" implements = list(TOOL_HEMOSTAT = 85, TOOL_WIRECUTTER = 50, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15) + difficulty = EXP_GENIUS time = 20 SECONDS preop_sound = 'sound/surgery/hemostat1.ogg' success_sound = 'sound/surgery/hemostat1.ogg' diff --git a/code/modules/surgery/advanced/dna_recovery.dm b/code/modules/surgery/advanced/dna_recovery.dm index a2727b553ca9..36d3ca221084 100644 --- a/code/modules/surgery/advanced/dna_recovery.dm +++ b/code/modules/surgery/advanced/dna_recovery.dm @@ -44,6 +44,7 @@ /datum/surgery_step/dna_recovery name = "recover DNA" implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30) + difficulty = EXP_HIGH time = 15 SECONDS chems_needed = list(/datum/reagent/medicine/rezadone, /datum/reagent/toxin/amanitin, /datum/reagent/consumable/entpoly) require_all_chems = FALSE diff --git a/code/modules/surgery/advanced/lobotomy.dm b/code/modules/surgery/advanced/lobotomy.dm index fb928ed82f51..41c2ce77c945 100644 --- a/code/modules/surgery/advanced/lobotomy.dm +++ b/code/modules/surgery/advanced/lobotomy.dm @@ -25,6 +25,7 @@ name = "perform lobotomy" implements = list(TOOL_SCALPEL = 85, /obj/item/melee/transforming/energy/sword = 55, /obj/item/kitchen/knife = 35, /obj/item/shard = 25, /obj/item = 20) + difficulty = EXP_MASTER time = 10 SECONDS preop_sound = 'sound/surgery/scalpel1.ogg' success_sound = 'sound/surgery/scalpel2.ogg' diff --git a/code/modules/surgery/advanced/necrotic_revival.dm b/code/modules/surgery/advanced/necrotic_revival.dm index 14046abc0976..113ea23a991a 100644 --- a/code/modules/surgery/advanced/necrotic_revival.dm +++ b/code/modules/surgery/advanced/necrotic_revival.dm @@ -21,6 +21,7 @@ /datum/surgery_step/bionecrosis name = "start bionecrosis" implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30) + difficulty = EXP_HIGH time = 50 chems_needed = list(/datum/reagent/toxin/zombiepowder, /datum/reagent/medicine/rezadone) require_all_chems = FALSE diff --git a/code/modules/surgery/advanced/pacification.dm b/code/modules/surgery/advanced/pacification.dm index 84b09c83a5f1..325e774c1bee 100644 --- a/code/modules/surgery/advanced/pacification.dm +++ b/code/modules/surgery/advanced/pacification.dm @@ -21,6 +21,7 @@ /datum/surgery_step/pacify name = "rewire brain" implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) + difficulty = EXP_MASTER time = 4 SECONDS preop_sound = 'sound/surgery/hemostat1.ogg' success_sound = 'sound/surgery/hemostat1.ogg' diff --git a/code/modules/surgery/brain_surgery.dm b/code/modules/surgery/brain_surgery.dm index 5130e39ebb03..48de46aa8689 100644 --- a/code/modules/surgery/brain_surgery.dm +++ b/code/modules/surgery/brain_surgery.dm @@ -41,6 +41,7 @@ /datum/surgery_step/fix_brain name = "fix brain" implements = list(TOOL_HEMOSTAT = 85, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) //don't worry, pouring some alcohol on their open brain will get that chance to 100 + difficulty = EXP_MASTER // do NOT attempt this without experience! repeatable = TRUE time = 12 SECONDS //long and complicated preop_sound = 'sound/surgery/hemostat1.ogg' @@ -48,13 +49,6 @@ failure_sound = 'sound/surgery/organ2.ogg' fuckup_damage = 20 -/datum/surgery_step/fix_brain/positron - name = "recalibrate brain" - implements = list(TOOL_MULTITOOL = 100, TOOL_SCREWDRIVER = 40, TOOL_HEMOSTAT = 25) //sterilizine doesn't work on IPCs so they get 100% chance, besides it's likely easier than fixing an organic brain - preop_sound = 'sound/items/tape_flip.ogg' - success_sound = 'sound/items/taperecorder_close.ogg' - failure_sound = 'sound/machines/defib_zap.ogg' - /datum/surgery/brain_surgery/can_start(mob/user, mob/living/carbon/target) var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) if(!B) @@ -95,3 +89,15 @@ else user.visible_message("[user] suddenly notices that the brain [user.p_they()] [user.p_were()] working on is not there anymore.", span_warning("You suddenly notice that the brain you were working on is not there anymore.")) return FALSE + +/datum/surgery_step/fix_brain/positron + name = "recalibrate brain" + implements = list(TOOL_MULTITOOL = 100, TOOL_SCREWDRIVER = 40, TOOL_HEMOSTAT = 25) //sterilizine doesn't work on IPCs so they get 100% chance, besides it's likely easier than fixing an organic brain + preop_sound = 'sound/items/tape_flip.ogg' + success_sound = 'sound/items/taperecorder_close.ogg' + failure_sound = 'sound/machines/defib_zap.ogg' + +/datum/surgery_step/fix_brain/positron/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + . = ..() + if(. && user.skill_check(SKILL_TECHNICAL, EXP_MASTER)) // not really any chance + target.cure_all_traumas(TRAUMA_RESILIENCE_LOBOTOMY) diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm index f4c679035a92..5b135725f04a 100644 --- a/code/modules/surgery/coronary_bypass.dm +++ b/code/modules/surgery/coronary_bypass.dm @@ -76,6 +76,7 @@ /datum/surgery_step/coronary_bypass name = "graft coronary bypass" implements = list(TOOL_HEMOSTAT = 90, TOOL_WIRECUTTER = 35, /obj/item/stack/packageWrap = 15, /obj/item/stack/cable_coil = 5) + difficulty = EXP_HIGH time = 9 SECONDS preop_sound = 'sound/surgery/hemostat1.ogg' success_sound = 'sound/surgery/hemostat1.ogg' diff --git a/code/modules/surgery/experimental_dissection.dm b/code/modules/surgery/experimental_dissection.dm index 300718ce442e..e9f2eee2a18d 100644 --- a/code/modules/surgery/experimental_dissection.dm +++ b/code/modules/surgery/experimental_dissection.dm @@ -42,7 +42,7 @@ return FALSE . = ..() -/datum/surgery_step/dissection/proc/check_value(mob/living/target, datum/surgery/experimental_dissection/ED) +/datum/surgery_step/dissection/proc/check_value(mob/user, mob/living/target, datum/surgery/experimental_dissection/ED) var/cost = EXPDIS_BASE_REWARD var/multi_surgery_adjust = 0 @@ -77,10 +77,11 @@ //multiply by multiplier in surgery cost *= ED.value_multiplier + cost *= (5 + user.get_skill(SKILL_SCIENCE)) / 5 return (cost-multi_surgery_adjust) /datum/surgery_step/dissection/success(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) - var/points_earned = check_value(target, surgery) + var/points_earned = check_value(user, target, surgery) user.visible_message("[user] dissects [target], discovering [points_earned] point\s of data!", span_notice("You dissect [target], and write down [points_earned] point\s worth of discoveries!")) new /obj/item/research_notes(user.loc, points_earned, TECHWEB_POINT_TYPE_GENERIC, "biology") var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST) @@ -91,7 +92,7 @@ /datum/surgery_step/dissection/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] dissects [target]!", span_notice("You dissect [target], but do not find anything particularly interesting.")) - new /obj/item/research_notes(user.loc, round(check_value(target, surgery)) * 0.01, TECHWEB_POINT_TYPE_GENERIC, "biology") + new /obj/item/research_notes(user.loc, round(check_value(user, target, surgery)) * 0.01, TECHWEB_POINT_TYPE_GENERIC, "biology") var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST) target.apply_damage(80, BRUTE, L) return TRUE diff --git a/code/modules/surgery/hepatectomy.dm b/code/modules/surgery/hepatectomy.dm index 2ad6b8123424..ddbb9cfa3b13 100644 --- a/code/modules/surgery/hepatectomy.dm +++ b/code/modules/surgery/hepatectomy.dm @@ -35,6 +35,7 @@ name = "excise damaged lung node" implements = list(TOOL_SCALPEL = 95, /obj/item/melee/transforming/energy/sword = 65, /obj/item/kitchen/knife = 45, /obj/item/shard = 35) + difficulty = EXP_HIGH time = 4.2 SECONDS preop_sound = 'sound/surgery/scalpel1.ogg' success_sound = 'sound/surgery/organ1.ogg' diff --git a/code/modules/surgery/ipc_revival.dm b/code/modules/surgery/ipc_revival.dm index f432e4a8a574..4e82973d0565 100644 --- a/code/modules/surgery/ipc_revival.dm +++ b/code/modules/surgery/ipc_revival.dm @@ -24,6 +24,7 @@ time = 5 SECONDS repeatable = TRUE // so you don't have to restart the whole thing if it fails implements = list(TOOL_MULTITOOL = 100, TOOL_WIRECUTTER = 50) + difficulty = EXP_HIGH preop_sound = 'sound/items/tape_flip.ogg' success_sound = 'sound/items/taperecorder_close.ogg' failure_sound = 'sound/machines/defib_zap.ogg' diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 165912ac0c16..214e1007d4a3 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -94,7 +94,7 @@ "[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!", "[user] successfully augments [target]'s [parse_zone(target_zone)]!") log_combat(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] COMBAT MODE: [user.combat_mode ? "ON" : "OFF"]") - var/points = 150 * (target.client ? 1 : 0.1) + var/points = 150 * (target.client ? 1 : 0.1) * (5 + user.get_skill(SKILL_SCIENCE)) / 5 SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points)) to_chat(user, "The augment uploads diagnostic data to the research cloud, giving a bonus of research points!") else diff --git a/code/modules/surgery/lobectomy.dm b/code/modules/surgery/lobectomy.dm index 924059fb0b7f..3cc5bea40fdc 100644 --- a/code/modules/surgery/lobectomy.dm +++ b/code/modules/surgery/lobectomy.dm @@ -35,6 +35,7 @@ name = "excise damaged lung node" implements = list(TOOL_SCALPEL = 95, /obj/item/melee/transforming/energy/sword = 65, /obj/item/kitchen/knife = 45, /obj/item/shard = 35) + difficulty = EXP_HIGH time = 4.2 SECONDS preop_sound = 'sound/surgery/scalpel1.ogg' success_sound = 'sound/surgery/organ1.ogg' diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 16f2adf27025..03d963f99da7 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -161,7 +161,7 @@ SSblackbox.record_feedback("tally", "surgeries_completed", 1, type) qdel(src) -/datum/surgery/proc/get_probability_multiplier() +/datum/surgery/proc/get_probability_multiplier(mob/user, datum/surgery_step/surgery_step, skill_checked = SKILL_PHYSIOLOGY) var/probability = 0.5 var/turf/T = get_turf(target) @@ -171,7 +171,7 @@ probability = SB.success_chance break - return probability + success_multiplier + return probability + success_multiplier + ((user.get_skill(skill_checked) - surgery_step.difficulty) / 10) /datum/surgery/proc/get_icon() var/mutable_appearance/new_icon = mutable_appearance(icon, icon_state) diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index cdcaeba3fee3..127e9522179e 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -34,7 +34,10 @@ /// Sound played if the step succeeded var/success_sound /// Sound played if the step fails - var/failure_sound + var/failure_sound + + /// Level of skill required to not have increased failure chance + var/difficulty = EXP_MID /datum/surgery_step/proc/try_op(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) var/success = FALSE @@ -102,22 +105,24 @@ return FALSE play_preop_sound(user, target, target_zone, tool, surgery) - if(is_species(user, /datum/species/lizard/ashwalker/shaman))//shaman is slightly better at surgeries - speed_mod *= 0.9 - if(istype(user.get_item_by_slot(ITEM_SLOT_GLOVES), /obj/item/clothing/gloves/color/latex)) var/obj/item/clothing/gloves/color/latex/surgicalgloves = user.get_item_by_slot(ITEM_SLOT_GLOVES) speed_mod *= surgicalgloves.surgeryspeed + + var/obj/item/bodypart/operated_bodypart = target.get_bodypart(target_zone) + if(!operated_bodypart) // if the limb is missing, check what it should be attached to instead + operated_bodypart = target.get_bodypart(BODY_ZONE_CHEST) + var/skill_checked = operated_bodypart?.status == BODYPART_ROBOTIC ? SKILL_TECHNICAL : SKILL_PHYSIOLOGY var/previous_loc = user.loc // If we have a tool, use it - if((tool && tool.use_tool(target, user, time * speed_mod, robo_check = TRUE)) || do_after(user, time * speed_mod, target)) + if((tool && tool.use_tool(target, user, time * speed_mod, skill_check = skill_checked)) || do_after(user, time * speed_mod, target, skill_check = skill_checked)) var/prob_chance = 100 if(implement_type) //this means it isn't a require hand or any item step. prob_chance = implements[implement_type] - prob_chance *= surgery.get_probability_multiplier() + prob_chance *= surgery.get_probability_multiplier(user, src, skill_checked) // Blood splatters on tools and user if(tool && prob(bloody_chance)) @@ -138,10 +143,8 @@ target.balloon_alert(user, "Failure!") play_failure_sound(user, target, target_zone, tool, surgery) if(iscarbon(target) && !HAS_TRAIT(target, TRAIT_SURGERY_PREPARED) && target.stat != DEAD && !IS_IN_STASIS(target) && fuckup_damage) //not under the effects of anaesthetics or a strong painkiller, harsh penalty to success chance - if(!issilicon(user) && !HAS_TRAIT(user, TRAIT_SURGEON)) //borgs and abductors are immune to this - var/obj/item/bodypart/operated_bodypart = target.get_bodypart(target_zone) - if(!operated_bodypart || operated_bodypart?.status == BODYPART_ORGANIC) //robot limbs don't feel pain - cause_ouchie(user, target, target_zone, tool, advance) + if(!issilicon(user) && !HAS_TRAIT(user, TRAIT_SURGEON) && (!operated_bodypart || operated_bodypart?.status == BODYPART_ORGANIC)) //robot limbs don't feel pain + cause_ouchie(user, target, target_zone, tool, advance) if(advance && !repeatable) surgery.status++ if(surgery.status > surgery.steps.len) diff --git a/tgui/packages/tgui/interfaces/SkillMenu.js b/tgui/packages/tgui/interfaces/SkillMenu.js new file mode 100644 index 000000000000..26c88eaa7733 --- /dev/null +++ b/tgui/packages/tgui/interfaces/SkillMenu.js @@ -0,0 +1,100 @@ +import { useBackend } from '../backend'; +import { formatSiUnit } from '../format'; +import { Box, Button, Icon, LabeledList, NumberInput, Section, Tabs, Tooltip } from '../components'; +import { Window } from '../layouts'; + +export const SkillMenu = (props, context) => { + const { act, data } = useBackend(context); + const { skill_points, allocated_points } = data; + + return ( + + +
+ + + + + + + +
+
+
+ ); +}; + +const AdjustSkill = (props, context) => { + const { act, data } = useBackend(context); + const { skill, name, index, tooltip } = props; + const { skills, skill_points, allocated_points, exceptional_skill } = data; + const { base, allocated } = skills[index] + + return ( + + + + +