From 87389243e66de7c3387061f2f61e101e3857751d Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Mon, 4 May 2020 17:30:15 +0200 Subject: [PATCH 01/12] r p g skills WIP. --- code/__DEFINES/skills/skills.dm | 22 +++++++ code/datums/skills/_skill.dm | 98 +++++++++++++++++++++++++++-- code/datums/skills/_skill_holder.dm | 21 ++++--- code/datums/skills/engineering.dm | 3 + tgstation.dme | 1 + 5 files changed, 130 insertions(+), 15 deletions(-) create mode 100644 code/datums/skills/engineering.dm diff --git a/code/__DEFINES/skills/skills.dm b/code/__DEFINES/skills/skills.dm index b97b921550..d8c37bec59 100644 --- a/code/__DEFINES/skills/skills.dm +++ b/code/__DEFINES/skills/skills.dm @@ -1,3 +1,5 @@ +#define GET_SKILL_DATUM(path) GLOB.skill_datums[path] + /// true/false #define SKILL_PROGRESSION_BINARY 1 /// numerical @@ -5,11 +7,31 @@ /// Enum #define SKILL_PROGRESSION_ENUM 3 + /// Max value of skill for numerical skills #define SKILL_NUMERICAL_MAX 100 /// Min value of skill for numerical skills #define SKILL_NUMERICAL_MIN 0 +// Values for experience skills +#define STD_XP_LVL_UP 100 +#define STD_XP_LVL_MULTI 2 +#define STD_MAX_LVL 4 + +#define RPG_MAX_LVL 100 + +#define DORF_XP_LVL_UP 400 +#define DORF_XP_LVL_MULTI 100 +#define DORF_MAX_LVL 20 // Dabbling, novice, adequate, [...], legendary +3, legendary +4, legendary +5 + +//How experience levels are calculated. +#define XP_LEVEL(std, multi, lvl) (std * (multi**lvl)) +#define DORF_XP_LEVEL(std, extra, lvl) (std*lvl+extra*(lvl*(lvl/2+0.5))) + +//level up methods defines +#define STANDARD_LEVEL_UP "standard_level_up" +#define DWARFY_LEVEL_UP "dwarfy_level_up" + // Standard values for job starting skills #define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm index 2dd321c4c6..f7225283cd 100644 --- a/code/datums/skills/_skill.dm +++ b/code/datums/skills/_skill.dm @@ -9,16 +9,13 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) S = new path .[S.type] = S -/proc/get_skill_datum(path) - return GLOB.skill_datums[path] - /proc/sanitize_skill_value(path, value) - var/datum/skill/S = get_skill_datum(path) + var/datum/skill/S = GET_SKILL_DATUM(path) // don't check, if we runtime let it happen. return S.sanitize_value(value) /proc/is_skill_value_greater(path, existing, new_value) - var/datum/skill/S = get_skill_datum(path) + var/datum/skill/S = GET_SKILL_DATUM(path) // don't check, if we runtime let it happen. return S.is_value_greater(existing, new_value) @@ -30,6 +27,8 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) var/name /// Our description var/desc + /// Color of the name as shown in the html readout + var/name_color = "#000000" /// Our progression type var/progression_type /// Abstract type @@ -41,6 +40,13 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) /datum/skill/proc/sanitize_value(new_value) return new_value +/** + * Sets the new value of this skill in the holder skills list. + * As well as possible feedback messages or secondary effects on value change, that's on you. + */ +/datum/skill/proc/set_skill(datum/skill_holder/H, value, mob/owner) + H.skills[type] = value + /** * Checks if a value is greater */ @@ -93,3 +99,85 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) /datum/skill/enum/sanitize_value(new_value) if(new_value in valid_values) return new_value + +/** + * Classing r p g styled skills, tiered by lvl, and current/nextlvl experience. + */ +/datum/skill/experience + abstract_type = /datum/skill/experience + var/standard_xp_lvl_up = STD_XP_LVL_UP //the standard required to level up. def: 100 + var/xp_lvl_multiplier = STD_XP_LVL_UP //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.) + var/max_lvl = STD_MAX_LVL + var/level_up_method = STANDARD_LEVEL_UP //how levels are calculated. + var/list/levels = list() //level thresholds, if associative, these will be preceded by tiers such as "novice" or "trained" + var/associative = FALSE //See above. + var/unskilled_tier = "Unskilled" //Only relevant for associative experience levels + +//Builds the levels list. +/datum/skill/experience/New() + . = ..() + var/max_assoc = "" + var/max_assoc_start = 1 + for(var/lvl in 1 to max_lvl) + var/value + switch(level_up_method) + if(STANDARD_LEVEL_UP) + value = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl) + if(DWARFY_LEVEL_UP) + value = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl) + value = round(value) + if(!associative) + levels += value + continue + if(max_assoc) + levels["[max_assoc] +[max_assoc_start++]"] = value + continue + var/key = LAZYACCESS(levels, lvl) + if(!key) + if(lvl == 1) //You dun goof it. + stack_trace("Skill datum [src] was set to have an associative levels list despite the latted having no key.") + associative = FALSE + levels += value + continue + max_assoc = levels[lvl-1] + levels["[max_assoc] +[max_assoc_start++]"] = value + levels[key] = value + + +/datum/skill/experience/sanitize_value(new_value) + return round(max(new_value, 0)) + +/datum/skill/experience/set_skill(datum/skill_holder/H, value, mob/owner) + var/old_value = H.skills[type] + H.skills[type] = value + if(value > old_value) + +/datum/skill/experience/standard_render_value(value) + var/current_lvl = associative ? unskilled_tier : 0 + var/current_lvl_xp_sum = 0 + var/next_lvl_xp_sum + for(var/lvl in 1 to max_lvl) + next_lvl_xp_sum = associative ? levels[levels[lvl]] : levels[lvl] + if(value < next_lvl_xp_sum) + break + current_lvl_xp_sum = next_lvl_xp_sum + current_lvl = associative ? levels[lvl] : current_lvl+1 + + return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp_sum])[value > next_lvl_xp_sum ? " \[MAX!\]" : ""]" + +/datum/skill/experience/job + levels = ("Basic", "Trained", "Experienced", "Master") + associative = TRUE + +//quite the reference, no? +/datum/skill/experience/dwarfy + abstract_type = /datum/skill/experience/dwarfy + standard_xp_lvl_up = DORF_XP_LVL_UP + xp_lvl_multiplier = DORF_XP_LVL_MULTI + max_lvl = DORF_MAX_LVL + levels = list("Novice", "Adequate", "Competent", "Skilled", + "Proficient", "Talented", "Adept", "Expert", + "Professional", "Accomplished", "Great", "Master", + "High Master", "Grand Master", "Legendary") + associative = TRUE + unskilled_tier = "Dabbling" diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm index 352adc46ff..71744b7d43 100644 --- a/code/datums/skills/_skill_holder.dm +++ b/code/datums/skills/_skill_holder.dm @@ -33,36 +33,37 @@ /** * Sets the value of a skill. */ -/datum/skill_holder/proc/set_skill_value(skill, value) - if(!ispath(skill)) +/datum/skill_holder/proc/set_skill_value(skill, value, owner) + if(!ispath(skill, /datum/skill)) CRASH("Invalid set_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. - LAZYINITLIST(skills) - value = sanitize_skill_value(skill, value) + var/datum/skill/S = GET_SKILL_DATUM(path) + value = S.sanitize_value(value) if(!isnull(value)) - skills[skill] = value + LAZYINITLIST(skills) + S.set_skill(src, value, owner) return TRUE return FALSE /** * Boosts a skill to a value if not aobve */ -/datum/skill_holder/proc/boost_skill_value_to(skill, value) +/datum/skill_holder/proc/boost_skill_value_to(skill, value, mob/owner) var/current = get_skill_value(skill) if(!is_skill_value_greater(skill, current, value)) return FALSE - set_skill_value(skill, value) + set_skill_value(skill, value, owner) return TRUE /** * Automatic skill increase, multiplied by skill affinity if existing. * Only works if skill is numerical. */ -/datum/skill_holder/proc/auto_gain_experience(skill, value) +/datum/skill_holder/proc/auto_gain_experience(skill, value, mob/owner) if(!ispath(skill, /datum/skill/numerical)) CRASH("You cannot auto increment a non numerical skill!") var/current = get_skill_value(skill) var/affinity = get_skill_affinity(skill) - boost_skill_value_to(skill, current + (value * affinity)) + boost_skill_value_to(skill, current + (value * affinity), owner) /** * Generates a HTML readout of our skills. @@ -73,6 +74,6 @@ out += "" for(var/path in skills) var/datum/skill/S = GLOB.skill_datums[path] - out += "" + out += "" out += "
SkillValue
[S.name][S.standard_render_value(skills[path])]
[S.name][S.standard_render_value(skills[path])]
" return out.Join("") diff --git a/code/datums/skills/engineering.dm b/code/datums/skills/engineering.dm new file mode 100644 index 0000000000..c06accea77 --- /dev/null +++ b/code/datums/skills/engineering.dm @@ -0,0 +1,3 @@ +/datum/skill/experience/job/wiring + name = "Wiring" + desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor." diff --git a/tgstation.dme b/tgstation.dme index 9aa47506d3..68ae7669f3 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -575,6 +575,7 @@ #include "code\datums\skills\_check_skills.dm" #include "code\datums\skills\_skill.dm" #include "code\datums\skills\_skill_holder.dm" +#include "code\datums\skills\engineering.dm" #include "code\datums\skills\medical.dm" #include "code\datums\status_effects\buffs.dm" #include "code\datums\status_effects\debuffs.dm" From 643ef48f0e66e52138b62844059133214f34b762 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 May 2020 04:42:34 +0200 Subject: [PATCH 02/12] Macros, generic skill implementations. --- .../skills/{skills.dm => defines.dm} | 62 +++++++++++------ code/__DEFINES/skills/helpers.dm | 44 ++++++++++++ code/_onclick/item_attack.dm | 56 +++++++++++---- code/datums/mind.dm | 3 +- code/datums/skills/_skill.dm | 69 ++++++++++++------- code/datums/skills/_skill_holder.dm | 37 ++++++++-- code/datums/skills/engineering.dm | 3 +- code/datums/skills/medical.dm | 1 + code/datums/wires/_wires.dm | 37 ++++++++-- code/datums/wires/airalarm.dm | 1 + code/datums/wires/airlock.dm | 5 +- code/datums/wires/apc.dm | 1 + code/datums/wires/autolathe.dm | 1 + code/datums/wires/emitter.dm | 2 + code/datums/wires/explosive.dm | 2 + code/datums/wires/microwave.dm | 2 + code/datums/wires/mulebot.dm | 1 + code/datums/wires/particle_accelerator.dm | 2 + code/datums/wires/r_n_d.dm | 1 + code/datums/wires/radio.dm | 2 + code/datums/wires/robot.dm | 2 + code/datums/wires/suit_storage_unit.dm | 2 + code/datums/wires/syndicatebomb.dm | 2 + code/datums/wires/tesla_coil.dm | 1 + code/datums/wires/vending.dm | 1 + code/game/machinery/camera/camera_assembly.dm | 3 +- code/game/machinery/constructable_frame.dm | 1 - code/game/machinery/doors/firedoor.dm | 3 +- code/game/machinery/firealarm.dm | 4 +- code/game/machinery/shieldgen.dm | 5 +- code/game/mecha/mecha_defense.dm | 3 +- code/game/objects/items.dm | 18 ++++- .../objects/items/grenades/chem_grenade.dm | 3 +- .../game/objects/items/stacks/sheets/glass.dm | 2 +- code/game/objects/structures/ai_core.dm | 2 +- code/game/objects/structures/barsigns.dm | 3 +- .../objects/structures/windoor_assembly.dm | 3 +- .../atmospherics/machinery/airalarm.dm | 5 +- code/modules/clothing/under/_under.dm | 2 +- code/modules/hydroponics/plant_genes.dm | 3 +- code/modules/jobs/job_types/_job.dm | 2 +- code/modules/jobs/job_types/ai.dm | 2 + .../jobs/job_types/atmospheric_technician.dm | 4 ++ code/modules/jobs/job_types/chief_engineer.dm | 3 + code/modules/jobs/job_types/cyborg.dm | 2 + code/modules/jobs/job_types/roboticist.dm | 4 ++ .../jobs/job_types/station_engineer.dm | 3 + code/modules/mining/ores_coins.dm | 3 +- .../mob/living/carbon/carbon_defense.dm | 6 +- .../mob/living/carbon/human/species.dm | 15 +--- .../modules/mob/living/silicon/robot/robot.dm | 13 ++-- .../living/simple_animal/bot/construction.dm | 5 +- .../modular_computers/hardware/_hardware.dm | 3 +- code/modules/power/apc.dm | 20 +++--- code/modules/power/cable.dm | 4 +- code/modules/power/floodlight.dm | 3 +- code/modules/power/lighting.dm | 3 +- .../particle_accelerator.dm | 3 +- .../particle_accelerator/particle_control.dm | 3 +- code/modules/power/smes.dm | 5 +- .../projectiles/guns/ballistic/revolver.dm | 3 +- .../surgery/bodyparts/robot_bodyparts.dm | 15 ++-- code/modules/surgery/surgery_step.dm | 9 ++- tgstation.dme | 3 +- 64 files changed, 358 insertions(+), 178 deletions(-) rename code/__DEFINES/skills/{skills.dm => defines.dm} (51%) create mode 100644 code/__DEFINES/skills/helpers.dm diff --git a/code/__DEFINES/skills/skills.dm b/code/__DEFINES/skills/defines.dm similarity index 51% rename from code/__DEFINES/skills/skills.dm rename to code/__DEFINES/skills/defines.dm index d8c37bec59..00859bbd40 100644 --- a/code/__DEFINES/skills/skills.dm +++ b/code/__DEFINES/skills/defines.dm @@ -1,4 +1,3 @@ -#define GET_SKILL_DATUM(path) GLOB.skill_datums[path] /// true/false #define SKILL_PROGRESSION_BINARY 1 @@ -6,6 +5,8 @@ #define SKILL_PROGRESSION_NUMERICAL 2 /// Enum #define SKILL_PROGRESSION_ENUM 3 +/// Levels +#define SKILL_PROGRESSION_LEVEL 4 /// Max value of skill for numerical skills @@ -13,7 +14,35 @@ /// Min value of skill for numerical skills #define SKILL_NUMERICAL_MIN 0 -// Values for experience skills +// Standard values for job starting skills + +#define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX + +// Standard values for job starting skill affinities + +#define STARTING_SKILL_AFFINITY_SURGERY_MEDICAL 1.2 + +#define STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO 1.2 + +// Standard values for skill gain (this is multiplied by affinity) + +#define DEF_SKILL_GAIN 1 +#define SKILL_GAIN_SURGERY_PER_STEP 0.25 + +///Items skill_flags and other defines +#define SKILL_USE_TOOL (1<<0) +#define SKILL_TRAINING_TOOL (1<<1) +#define SKILL_ATTACK_MOB (1<<2) +#define SKILL_TRAIN_ATTACK_MOB (1<<3) +#define SKILL_ATTACK_OBJ (1<<4) +#define SKILL_TRAIN_ATTACK_OBJ (1<<5) + +///competency_threshold index defines +#define THRESHOLD_COMPETENT 1 +#define THRESHOLD_EXPERT 2 +#define THRESHOLD_MASTER 3 + +/// Level/Experience skills defines. #define STD_XP_LVL_UP 100 #define STD_XP_LVL_MULTI 2 #define STD_MAX_LVL 4 @@ -24,27 +53,18 @@ #define DORF_XP_LVL_MULTI 100 #define DORF_MAX_LVL 20 // Dabbling, novice, adequate, [...], legendary +3, legendary +4, legendary +5 -//How experience levels are calculated. -#define XP_LEVEL(std, multi, lvl) (std * (multi**lvl)) -#define DORF_XP_LEVEL(std, extra, lvl) (std*lvl+extra*(lvl*(lvl/2+0.5))) - //level up methods defines #define STANDARD_LEVEL_UP "standard_level_up" #define DWARFY_LEVEL_UP "dwarfy_level_up" -// Standard values for job starting skills +//job skill level defines +#define JOB_SKILL_UNTRAINED 0 +#define JOB_SKILL_BASIC 1 +#define JOB_SKILL_TRAINED 2 +#define JOB_SKILL_EXPERT 3 +#define JOB_SKILL_MASTER 4 -#define STARTING_SKILL_SURGERY_MEDICAL 35 //out of SKILL_NUMERICAL_MAX - -// Standard values for job starting skill affinities - -#define STARTING_SKILL_AFFINITY_SURGERY_MEDICAL 1.2 - -// Standard values for skill gain (this is multiplied by affinity) - -#define SKILL_GAIN_SURGERY_PER_STEP 0.25 - -// Misc - -/// 40% speedup at 100 skill -#define SURGERY_SKILL_SPEEDUP_NUMERICAL_SCALE(number) clamp(number / 250, 1, 2) +//other skill level defines, not an exhaustive catalogue, only contains be most relevant ones. +#define DORF_SKILL_COMPETENT 3 +#define DORF_SKILL_EXPERT 8 +#define DORF_SKILL_MASTER 12 diff --git a/code/__DEFINES/skills/helpers.dm b/code/__DEFINES/skills/helpers.dm new file mode 100644 index 0000000000..165b9091ae --- /dev/null +++ b/code/__DEFINES/skills/helpers.dm @@ -0,0 +1,44 @@ +/** + *Generic delay calculation macro for various delayed actions. + *The skill to check must be an instance, not a path or list. + */ +#define SKILL_MODIFIER(to_check, holder, target, threshold) \ + var/___value;\ + switch(to_check.progression_type){\ + if(SKILL_PROGRESSION_LEVEL){\ + ___value = LAZYACCESS(holder.skill_levels, to_check.type)\ + } else {\ + ___value = LAZYACCESS(holder.skills, to_check.type)\ + }\ + }\ + target /= (1+(___value-to_check.competency_thresholds[threshold])*to_check.competency_mults[threshold]) + +/// This is the one that accepts typepaths and lists. +#define LIST_SKILL_MODIFIER(to_check, holder, target, threshold) \ + if(!islist(to_check)){\ + SKILL_MODIFIER(GLOB.skill_datums[to_check], holder, target, threshold)\ + } else {\ + var/___sum = 0;\ + var/list/___L = to_check;\ + for(var/_S in ___L){\ + var/___value;\ + var/datum/skill/___S = GLOB.skill_datums[_S];\ + switch(___S.progression_type){\ + if(SKILL_PROGRESSION_LEVEL){\ + ___value = LAZYACCESS(holder.skill_levels, ___S.type)\ + } else {\ + ___value = LAZYACCESS(holder.skills, ___S.type)\ + }\ + }\ + ___sum += (1+(___value - ___S.competency_thresholds[threshold])*___S.competency_mults[threshold])\ + }\ + target /= (___sum/length(___L))\ + } + +//How experience levels are calculated. +#define XP_LEVEL(std, multi, lvl) (std*((multi**lvl)/(multi-1))-std/(multi-1)) //don't use 1 as multi, you'll get division by zero errors +#define DORF_XP_LEVEL(std, extra, lvl) (std*lvl+extra*(lvl*(lvl/2+0.5))) + +//More experience value getter macros +#define GET_STANDARD_LVL(lvl) XP_LEVEL(STD_XP_LVL_UP, STD_XP_LVL_MULTI, lvl) +#define GET_DORF_LVL(lvl) DORF_XP_LEVEL(DORF_XP_LVL_UP, DORF_XP_LVL_MULTI, lvl) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 98db89a100..dbcf171663 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -111,26 +111,30 @@ return /obj/attacked_by(obj/item/I, mob/living/user) - if(I.force) + var/totitemdamage = I.force + if(I.used_skills && user.mind) + if(I.skill_flags & SKILL_ATTACK_OBJ) + LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, totitemdamage, I.skill_difficulty) + if(I.skill_flags & SKILL_TRAIN_ATTACK_OBJ) + if(!islist(I.used_skills)) + user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain) + else + for(var/skill in used_skills) + user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain) + if(totitemdamage) visible_message("[user] has hit [src] with [I]!", null, null, COMBAT_MESSAGE_RANGE) //only witnesses close by and the victim see a hit message. log_combat(user, src, "attacked", I) - take_damage(I.force, I.damtype, "melee", 1) + take_damage(totitemdamage, I.damtype, "melee", 1) /mob/living/attacked_by(obj/item/I, mob/living/user) - //CIT CHANGES START HERE - combatmode and resting checks - var/totitemdamage = I.force - if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) - totitemdamage *= 0.5 - if(!CHECK_MOBILITY(user, MOBILITY_STAND)) - totitemdamage *= 0.5 - //CIT CHANGES END HERE + var/totitemdamage = calculate_item_force(I, user, TRUE) if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS) return FALSE send_item_attack_message(I, user) - I.do_stagger_action(src, user) + I.do_stagger_action(src, user, totitemdamage) if(I.force) - apply_damage(totitemdamage, I.damtype) //CIT CHANGE - replaces I.force with totitemdamage + apply_damage(totitemdamage, I.damtype) if(I.damtype == BRUTE) if(prob(33)) I.add_mob_blood(src) @@ -146,6 +150,28 @@ else return ..() +/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user, pre_attack = FALSE) + . = I.force + if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) + . *= 0.5 + if(!CHECK_MOBILITY(user, MOBILITY_STAND)) + . *= 0.5 + if(!pre_attack || !user.mind || !I.used_skills) + return + if(. && I.skill_flags & SKILL_ATTACK_MOB) + LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, ., I.skill_difficulty) + if(I.skill_flags & SKILL_TRAIN_ATTACK_MOB) + if(!islist(I.used_skills)) + user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain) + else + for(var/skill in used_skills) + user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain) + +/mob/living/carbon/proc/pre_attacked_by(obj/item/I, mob/living/user, pre_attack = FALSE) + . = ..() + if(!(combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) + . *= 1.5 + // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. /obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters) @@ -183,18 +209,18 @@ return total_mass || w_class * 1.25 /// How long this staggers for. 0 and negatives supported. -/obj/item/proc/melee_stagger_duration() +/obj/item/proc/melee_stagger_duration(force_override) if(!isnull(stagger_force)) return stagger_force /// totally not an untested, arbitrary equation. - return clamp((1.5 + (w_class/7.5)) * (force / 2), 0, 10 SECONDS) + return clamp((1.5 + (w_class/7.5)) * ((force_override || force) / 2), 0, 10 SECONDS) -/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user) +/obj/item/proc/do_stagger_action(mob/living/target, mob/living/user, force_override) if(!CHECK_BITFIELD(target.status_flags, CANSTAGGER)) return FALSE if(target.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) target.do_staggered_animation() - var/duration = melee_stagger_duration() + var/duration = melee_stagger_duration(force_override) if(!duration) //0 return FALSE else if(duration > 0) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 728c4fb51b..54fcbbc6aa 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -67,7 +67,7 @@ var/datum/skill_holder/skill_holder /datum/mind/New(var/key) - skill_holder = new + skill_holder = new(src) src.key = key soulOwner = src martial_art = default_martial_art @@ -80,6 +80,7 @@ if(antag_datum.delete_on_mind_deletion) qdel(i) antag_datums = null + QDEL_NULL(skill_holder) return ..() /datum/mind/proc/get_language_holder() diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm index f7225283cd..039afacfa5 100644 --- a/code/datums/skills/_skill.dm +++ b/code/datums/skills/_skill.dm @@ -1,4 +1,4 @@ -GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) +GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /proc/init_skill_datums() . = list() @@ -10,12 +10,12 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) .[S.type] = S /proc/sanitize_skill_value(path, value) - var/datum/skill/S = GET_SKILL_DATUM(path) + var/datum/skill/S = GLOB.skill_datums[path] // don't check, if we runtime let it happen. return S.sanitize_value(value) /proc/is_skill_value_greater(path, existing, new_value) - var/datum/skill/S = GET_SKILL_DATUM(path) + var/datum/skill/S = GLOB.skill_datums[path] // don't check, if we runtime let it happen. return S.is_value_greater(existing, new_value) @@ -33,6 +33,10 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) var/progression_type /// Abstract type var/abstract_type = /datum/skill + /// skill threshold used in generic skill modifiers calculations. + var/list/competency_thresholds = list(0, 0, 0) + /// Multiplier of the difference of the holder skill value and the selected threshold. + var/list/competency_mults = list(0, 0, 0) /** * Ensures what someone's setting as a value for this skill is valid. @@ -44,7 +48,7 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) * Sets the new value of this skill in the holder skills list. * As well as possible feedback messages or secondary effects on value change, that's on you. */ -/datum/skill/proc/set_skill(datum/skill_holder/H, value, mob/owner) +/datum/skill/proc/set_skill_value(datum/skill_holder/H, value, mob/owner) H.skills[type] = value /** @@ -67,6 +71,8 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) /datum/skill/binary abstract_type = /datum/skill/binary progression_type = SKILL_PROGRESSION_BINARY + competency_thresholds = list(FALSE, TRUE, TRUE) + competency_mults = list(0.5, 0.5, 0.5) /datum/skill/binary/sanitize_value(new_value) return new_value? TRUE : FALSE @@ -103,22 +109,23 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) /** * Classing r p g styled skills, tiered by lvl, and current/nextlvl experience. */ -/datum/skill/experience - abstract_type = /datum/skill/experience +/datum/skill/level + abstract_type = /datum/skill/level + progression_type = SKILL_PROGRESSION_LEVEL var/standard_xp_lvl_up = STD_XP_LVL_UP //the standard required to level up. def: 100 var/xp_lvl_multiplier = STD_XP_LVL_UP //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.) - var/max_lvl = STD_MAX_LVL + var/max_levels = STD_MAX_LVL var/level_up_method = STANDARD_LEVEL_UP //how levels are calculated. var/list/levels = list() //level thresholds, if associative, these will be preceded by tiers such as "novice" or "trained" var/associative = FALSE //See above. var/unskilled_tier = "Unskilled" //Only relevant for associative experience levels //Builds the levels list. -/datum/skill/experience/New() +/datum/skill/level/New() . = ..() var/max_assoc = "" var/max_assoc_start = 1 - for(var/lvl in 1 to max_lvl) + for(var/lvl in 1 to max_levels) var/value switch(level_up_method) if(STANDARD_LEVEL_UP) @@ -143,41 +150,57 @@ GLOBAL_LIST_INIT(skill_datums, init_skill_datums()) levels["[max_assoc] +[max_assoc_start++]"] = value levels[key] = value +/datum/skill/level/sanitize_value(new_value) + return max(new_value, 0) -/datum/skill/experience/sanitize_value(new_value) - return round(max(new_value, 0)) - -/datum/skill/experience/set_skill(datum/skill_holder/H, value, mob/owner) - var/old_value = H.skills[type] +/datum/skill/level/set_skill_value(datum/skill_holder/H, value, datum/mind/M, silent = FALSE) H.skills[type] = value - if(value > old_value) + var/new_level + for(var/k in levels) + if(value < (associative ? levels[k] : k)) + break + new_level++ + var/old_level = LAZYACCESS(H.skill_levels, type) + LAZYSET(H.skill_levels, type, new_level) + . = new_level - old_level + if(silent || !(M?.current)) + return + if(. > 0) + to_chat(M.current, "I feel like I've become more proficient at [name]!") + else if(. < 0) + to_chat(M.current, "I feel like I've become worse at [name]!") -/datum/skill/experience/standard_render_value(value) +/datum/skill/level/standard_render_value(value) var/current_lvl = associative ? unskilled_tier : 0 var/current_lvl_xp_sum = 0 var/next_lvl_xp_sum - for(var/lvl in 1 to max_lvl) + for(var/lvl in 1 to max_levels) next_lvl_xp_sum = associative ? levels[levels[lvl]] : levels[lvl] if(value < next_lvl_xp_sum) break current_lvl_xp_sum = next_lvl_xp_sum - current_lvl = associative ? levels[lvl] : current_lvl+1 + current_lvl = associative ? levels[lvl] : lvl+1 return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp_sum])[value > next_lvl_xp_sum ? " \[MAX!\]" : ""]" -/datum/skill/experience/job - levels = ("Basic", "Trained", "Experienced", "Master") +/datum/skill/level/job + levels = list("Basic", "Trained", "Experienced", "Master") + competency_thresholds = list(JOB_SKILL_TRAINED, JOB_SKILL_EXPERT, JOB_SKILL_MASTER) + competency_mults = list(0.15, 0.1, 0.1) associative = TRUE //quite the reference, no? -/datum/skill/experience/dwarfy - abstract_type = /datum/skill/experience/dwarfy +/datum/skill/level/dwarfy + abstract_type = /datum/skill/level/dwarfy standard_xp_lvl_up = DORF_XP_LVL_UP xp_lvl_multiplier = DORF_XP_LVL_MULTI - max_lvl = DORF_MAX_LVL + max_levels = DORF_MAX_LVL + level_up_method = DWARFY_LEVEL_UP levels = list("Novice", "Adequate", "Competent", "Skilled", "Proficient", "Talented", "Adept", "Expert", "Professional", "Accomplished", "Great", "Master", "High Master", "Grand Master", "Legendary") + competency_thresholds = list(DORF_SKILL_COMPETENT, DORF_SKILL_EXPERT, DORF_SKILL_MASTER) + competency_mults = list(0.15, 0.1, 0.08) associative = TRUE unskilled_tier = "Dabbling" diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm index 71744b7d43..d1b6b8bd0d 100644 --- a/code/datums/skills/_skill_holder.dm +++ b/code/datums/skills/_skill_holder.dm @@ -2,10 +2,18 @@ * Skill holder datums */ /datum/skill_holder + var/datum/mind/owner /// Our list of skills and values. Lazylist. Associative. Keys are datum typepaths to the skill. var/list/skills /// Same as [skills] but affinities, which are multiplied to increase amount when gaining skills. var/list/skill_affinities + /// Let's say we want to get a specific skill "level" without looping through a proc everytime. + /// Only supported by skills with tiers or levels. + var/list/skill_levels + +/datum/skill_holder/New(datum/mind/M) + . = ..() + owner = M /** * Grabs the value of a skill. @@ -17,6 +25,16 @@ return null return skills[skill] +/** + * Grabs the level of a skill. Only supported by skills with tiers or levels. + */ +/datum/skill_holder/proc/get_skill_level(skill) + if(!ispath(skill)) + CRASH("Invalid get_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. + if(!skill_levels) + return 0 + return skill_levels[skill] + /** * Grabs our affinity for a skill. !!This is a multiplier!! */ @@ -33,37 +51,42 @@ /** * Sets the value of a skill. */ -/datum/skill_holder/proc/set_skill_value(skill, value, owner) +/datum/skill_holder/proc/set_skill_value(skill, value, silent = FALSE) if(!ispath(skill, /datum/skill)) CRASH("Invalid set_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. - var/datum/skill/S = GET_SKILL_DATUM(path) + var/datum/skill/S = GLOB.skill_datums[skill] value = S.sanitize_value(value) if(!isnull(value)) LAZYINITLIST(skills) - S.set_skill(src, value, owner) + S.set_skill_value(src, value, owner, silent) return TRUE return FALSE /** * Boosts a skill to a value if not aobve */ -/datum/skill_holder/proc/boost_skill_value_to(skill, value, mob/owner) +/datum/skill_holder/proc/boost_skill_value_to(skill, value, silent = FALSE) var/current = get_skill_value(skill) if(!is_skill_value_greater(skill, current, value)) return FALSE - set_skill_value(skill, value, owner) + set_skill_value(skill, value, silent) return TRUE /** * Automatic skill increase, multiplied by skill affinity if existing. * Only works if skill is numerical. */ -/datum/skill_holder/proc/auto_gain_experience(skill, value, mob/owner) +/datum/skill_holder/proc/auto_gain_experience(skill, value, maximum, silent = FALSE) if(!ispath(skill, /datum/skill/numerical)) CRASH("You cannot auto increment a non numerical skill!") var/current = get_skill_value(skill) var/affinity = get_skill_affinity(skill) - boost_skill_value_to(skill, current + (value * affinity), owner) + var/target_value = current + (value * affinity) + if(maximum) + target_value = max(target_value, maximum) + if(target_value == maximum) //no more experience to gain, early return. + return + boost_skill_value_to(skill, target_value, silent) /** * Generates a HTML readout of our skills. diff --git a/code/datums/skills/engineering.dm b/code/datums/skills/engineering.dm index c06accea77..b3eeb9d57d 100644 --- a/code/datums/skills/engineering.dm +++ b/code/datums/skills/engineering.dm @@ -1,3 +1,4 @@ -/datum/skill/experience/job/wiring +/datum/skill/level/job/wiring name = "Wiring" desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor." + competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER) diff --git a/code/datums/skills/medical.dm b/code/datums/skills/medical.dm index 3b67cacb04..1b0774b0ce 100644 --- a/code/datums/skills/medical.dm +++ b/code/datums/skills/medical.dm @@ -1,3 +1,4 @@ /datum/skill/numerical/surgery name = "Surgery" desc = "How proficient you are at doing surgery." + competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100. diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index ad24126e45..fc31cb9286 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -33,6 +33,9 @@ var/list/assemblies = list() // List of attached assemblies. var/randomize = 0 // If every instance of these wires should be random. // Prevents wires from showing up in station blueprints + var/req_knowledge = INFINITY //wiring skill level on which the functions are revealed. + var/req_skill = JOB_SKILL_BASIC //used in user's cutting/pulsing/mending speed calculations. + var/list/current_users //list of untrained people currently interacting with this set of wires. /datum/wires/New(atom/holder) ..() @@ -130,8 +133,20 @@ cut_wires += wire on_cut(wire, mend = FALSE) -/datum/wires/proc/cut_color(color) +/datum/wires/proc/cut_color(color, mob/living/user) + LAZYINITLIST(current_users) + if(current_users[user]) + return FALSE + if(req_skill && user?.mind) + var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) + if(level_diff > 0) + to_chat(user, "You begin cutting [holder]'s [color] wire...") + if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user)) + return FALSE + user.mind?.skill_holder.auto_gain_experience(/datum/skill/level/job/wiring, DEF_SKILL_GAIN*level_diff) + to_chat(user, "You cut [holder]'s [color] wire.") cut(get_wire(color)) + return TRUE /datum/wires/proc/cut_random() cut(wires[rand(1, wires.len)]) @@ -146,7 +161,19 @@ on_pulse(wire, user) /datum/wires/proc/pulse_color(color, mob/living/user) + LAZYINITLIST(current_users) + if(current_users[user]) + return FALSE + if(req_skill && user?.mind) + var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) + if(level_diff > 0) + to_chat(user, "You begin pulsing [holder]'s [color] wire...") + if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user)) + return FALSE + user.mind?.skill_holder.auto_gain_experience(/datum/skill/level/job/wiring, DEF_SKILL_GAIN*level_diff) + to_chat(user, "You pulse [holder]'s [color] wire.") pulse(get_wire(color), user) + return TRUE /datum/wires/proc/pulse_assembly(obj/item/assembly/S) for(var/color in assemblies) @@ -224,7 +251,7 @@ var/reveal_wires = FALSE // Admin ghost can see a purpose of each wire. - if(IsAdminGhost(user)) + if(IsAdminGhost(user) || user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) >= req_knowledge) reveal_wires = TRUE // Same for anyone with an abductor multitool. @@ -259,18 +286,16 @@ if("cut") I = L.is_holding_tool_quality(TOOL_WIRECUTTER) if(I || IsAdminGhost(usr)) - if(I && holder) + if(cut_color(target_wire) && I && holder) I.play_tool_sound(holder, 20) - cut_color(target_wire) . = TRUE else to_chat(L, "You need wirecutters!") if("pulse") I = L.is_holding_tool_quality(TOOL_MULTITOOL) if(I || IsAdminGhost(usr)) - if(I && holder) + if(pulse_color(target_wire, L) && I && holder) I.play_tool_sound(holder, 20) - pulse_color(target_wire, L) . = TRUE else to_chat(L, "You need a multitool!") diff --git a/code/datums/wires/airalarm.dm b/code/datums/wires/airalarm.dm index 0c4715e27e..dae92d3c42 100644 --- a/code/datums/wires/airalarm.dm +++ b/code/datums/wires/airalarm.dm @@ -1,6 +1,7 @@ /datum/wires/airalarm holder_type = /obj/machinery/airalarm proper_name = "Air Alarm" + req_knowledge = JOB_SKILL_MASTER /datum/wires/airalarm/New(atom/holder) wires = list( diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index b6699540c3..c2b5db9540 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -52,10 +52,11 @@ /datum/wires/airlock/interactable(mob/user) var/obj/machinery/door/airlock/A = holder + if(!A.panel_open) + return FALSE if(!A.hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100)) return FALSE - if(A.panel_open) - return TRUE + return TRUE /datum/wires/airlock/get_status() var/obj/machinery/door/airlock/A = holder diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm index dc126f612e..997c77aa51 100644 --- a/code/datums/wires/apc.dm +++ b/code/datums/wires/apc.dm @@ -1,6 +1,7 @@ /datum/wires/apc holder_type = /obj/machinery/power/apc proper_name = "APC" + req_knowledge = JOB_SKILL_MASTER /datum/wires/apc/New(atom/holder) wires = list( diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm index f83bab5910..01e87228d4 100644 --- a/code/datums/wires/autolathe.dm +++ b/code/datums/wires/autolathe.dm @@ -1,6 +1,7 @@ /datum/wires/autolathe holder_type = /obj/machinery/autolathe proper_name = "Autolathe" + req_knowledge = JOB_SKILL_EXPERT /datum/wires/autolathe/New(atom/holder) wires = list( diff --git a/code/datums/wires/emitter.dm b/code/datums/wires/emitter.dm index d0e1352c0e..6d82a7db5a 100644 --- a/code/datums/wires/emitter.dm +++ b/code/datums/wires/emitter.dm @@ -1,6 +1,8 @@ /datum/wires/emitter holder_type = /obj/machinery/power/emitter + req_knowledge = JOB_SKILL_TRAINED + req_skill = JOB_SKILL_UNTRAINED /datum/wires/emitter/New(atom/holder) wires = list(WIRE_ZAP,WIRE_HACK) diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm index 3d1ed8b746..dc4db9e85d 100644 --- a/code/datums/wires/explosive.dm +++ b/code/datums/wires/explosive.dm @@ -15,6 +15,7 @@ /datum/wires/explosive/c4 holder_type = /obj/item/grenade/plastic/c4 randomize = TRUE //Same behaviour since no wire actually disarms it + req_skill = JOB_SKILL_UNTRAINED /datum/wires/explosive/c4/interactable(mob/user) var/obj/item/grenade/plastic/c4/P = holder @@ -29,6 +30,7 @@ /datum/wires/explosive/pizza holder_type = /obj/item/pizzabox randomize = TRUE + req_skill = JOB_SKILL_MASTER /datum/wires/explosive/pizza/New(atom/holder) wires = list( diff --git a/code/datums/wires/microwave.dm b/code/datums/wires/microwave.dm index 8c74abfa46..c6e6aa13b5 100644 --- a/code/datums/wires/microwave.dm +++ b/code/datums/wires/microwave.dm @@ -1,6 +1,8 @@ /datum/wires/microwave holder_type = /obj/machinery/microwave proper_name = "Microwave" + req_knowledge = JOB_SKILL_TRAINED + req_skill = JOB_SKILL_UNTRAINED /datum/wires/microwave/New(atom/holder) wires = list( diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm index a452b46830..988487727b 100644 --- a/code/datums/wires/mulebot.dm +++ b/code/datums/wires/mulebot.dm @@ -1,6 +1,7 @@ /datum/wires/mulebot holder_type = /mob/living/simple_animal/bot/mulebot randomize = TRUE + req_knowledge = JOB_SKILL_MASTER /datum/wires/mulebot/New(atom/holder) wires = list( diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm index af89f0d6f1..b782e589dd 100644 --- a/code/datums/wires/particle_accelerator.dm +++ b/code/datums/wires/particle_accelerator.dm @@ -1,6 +1,8 @@ /datum/wires/particle_accelerator/control_box holder_type = /obj/machinery/particle_accelerator/control_box proper_name = "Particle Accelerator" + req_knowledge = JOB_SKILL_EXPERT + req_skill = JOB_SKILL_TRAINED /datum/wires/particle_accelerator/control_box/New(atom/holder) wires = list( diff --git a/code/datums/wires/r_n_d.dm b/code/datums/wires/r_n_d.dm index ea61c1779e..25d3b73fe0 100644 --- a/code/datums/wires/r_n_d.dm +++ b/code/datums/wires/r_n_d.dm @@ -1,6 +1,7 @@ /datum/wires/rnd holder_type = /obj/machinery/rnd randomize = TRUE + req_knowledge = JOB_SKILL_EXPERT /datum/wires/rnd/New(atom/holder) wires = list( diff --git a/code/datums/wires/radio.dm b/code/datums/wires/radio.dm index a1118da6d7..5db6ddd186 100644 --- a/code/datums/wires/radio.dm +++ b/code/datums/wires/radio.dm @@ -1,6 +1,8 @@ /datum/wires/radio holder_type = /obj/item/radio proper_name = "Radio" + req_knowledge = JOB_SKILL_TRAINED + req_skill = JOB_SKILL_UNTRAINED /datum/wires/radio/New(atom/holder) wires = list( diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index aa7c3cc4c3..6ede0415da 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -1,6 +1,8 @@ /datum/wires/robot holder_type = /mob/living/silicon/robot randomize = TRUE + req_knowledge = JOB_SKILL_MASTER + req_skill = JOB_SKILL_TRAINED /datum/wires/robot/New(atom/holder) wires = list( diff --git a/code/datums/wires/suit_storage_unit.dm b/code/datums/wires/suit_storage_unit.dm index eb7781203b..4387d0dc76 100644 --- a/code/datums/wires/suit_storage_unit.dm +++ b/code/datums/wires/suit_storage_unit.dm @@ -1,6 +1,8 @@ /datum/wires/suit_storage_unit holder_type = /obj/machinery/suit_storage_unit proper_name = "Suit Storage Unit" + req_knowledge = JOB_SKILL_TRAINED + req_skill = JOB_SKILL_UNTRAINED /datum/wires/suit_storage_unit/New(atom/holder) wires = list( diff --git a/code/datums/wires/syndicatebomb.dm b/code/datums/wires/syndicatebomb.dm index 53c1a1b9bc..8e1cf5002f 100644 --- a/code/datums/wires/syndicatebomb.dm +++ b/code/datums/wires/syndicatebomb.dm @@ -1,6 +1,8 @@ /datum/wires/syndicatebomb holder_type = /obj/machinery/syndicatebomb randomize = TRUE + req_skill = JOB_SKILL_EXPERT //good luck, wannabe hero. + /datum/wires/syndicatebomb/New(atom/holder) wires = list( diff --git a/code/datums/wires/tesla_coil.dm b/code/datums/wires/tesla_coil.dm index fa858a9a8f..68fe8e72fc 100644 --- a/code/datums/wires/tesla_coil.dm +++ b/code/datums/wires/tesla_coil.dm @@ -2,6 +2,7 @@ /datum/wires/tesla_coil randomize = 1 //Only one wire don't need blueprints holder_type = /obj/machinery/power/tesla_coil + req_knowledge = JOB_SKILL_TRAINED /datum/wires/tesla_coil/New(atom/holder) wires = list(WIRE_ZAP) diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm index 114791e873..6c7e59c24c 100644 --- a/code/datums/wires/vending.dm +++ b/code/datums/wires/vending.dm @@ -1,6 +1,7 @@ /datum/wires/vending holder_type = /obj/machinery/vending proper_name = "Vending Unit" + req_knowledge = JOB_SKILL_EXPERT /datum/wires/vending/New(atom/holder) wires = list( diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 1766391709..b6af0600e4 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -48,8 +48,7 @@ if(2) // State 2 if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = W - if(C.use(2)) + if(W.use_tool(src, user, 0, 2)) to_chat(user, "You add wires to the assembly.") state = 3 else diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index b007bc0161..5ee8223625 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -83,7 +83,6 @@ if(istype(P, /obj/item/stack/cable_coil)) if(!P.tool_start_check(user, amount=5)) return - to_chat(user, "You start to add cables to the frame...") if(P.use_tool(src, user, 20, volume=50, amount=5)) to_chat(user, "You add cables to the frame.") diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 1b83bb4b96..28b9796bb6 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -400,12 +400,11 @@ "You begin adding wires to [src]...") playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1) if(do_after(user, 60, target = src)) - if(constructionStep != CONSTRUCTION_GUTTED || B.get_amount() < 5 || !B) + if(constructionStep != CONSTRUCTION_GUTTED || !B.use_tool(src, user, 0, 5)) return user.visible_message("[user] adds wires to [src].", \ "You wire [src].") playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1) - B.use(5) constructionStep = CONSTRUCTION_WIRES_EXPOSED update_icon() return diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index f4f308c490..4a0042e1da 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -205,11 +205,9 @@ return if(1) if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/coil = W - if(coil.get_amount() < 5) + if(!W.use_tool(src, user, 0, 5)) to_chat(user, "You need more cable for this!") else - coil.use(5) buildstage = 2 to_chat(user, "You wire \the [src].") update_icon() diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 34db7b0e08..6793d361b5 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -160,10 +160,7 @@ to_chat(user, "You need one length of cable to repair [src]!") return to_chat(user, "You begin to replace the wires...") - if(do_after(user, 30, target = src)) - if(coil.get_amount() < 1) - return - coil.use(1) + if(W.use_tool(src, user, 30, 1)) obj_integrity = max_integrity stat &= ~BROKEN to_chat(user, "You repair \the [src].") diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm index 581283d339..53768fe9a9 100644 --- a/code/game/mecha/mecha_defense.dm +++ b/code/game/mecha/mecha_defense.dm @@ -220,8 +220,7 @@ return else if(istype(W, /obj/item/stack/cable_coil)) if(state == 3 && (internal_damage & MECHA_INT_SHORT_CIRCUIT)) - var/obj/item/stack/cable_coil/CC = W - if(CC.use(2)) + if(W.use_tool(src, user, 0, 2)) clearInternalDamage(MECHA_INT_SHORT_CIRCUIT) to_chat(user, "You replace the fused wires.") else diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index c8e5b15f72..9d3cc8293b 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -132,6 +132,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder! + ///Skills vars + var/used_skills //path/s of skill/s exercised when using this item. + var/skill_flags = NONE //better defines which tasks the the skill/s is/are exercised on. + var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general. + var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item. + /obj/item/Initialize() if (attack_verb) @@ -783,7 +789,7 @@ 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) +/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_gain_mult = 1, max_level = INFINITY) // 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)) @@ -795,6 +801,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) play_tool_sound(target, volume) if(delay) + if(user.mind && used_skills && skill_flags & SKILL_USE_TOOL) + LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, delay, skill_difficulty) + // Create a callback with checks that would be called every tick by do_after. var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks) @@ -819,6 +828,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(delay >= MIN_TOOL_SOUND_DELAY) play_tool_sound(target, volume) + if(user.mind && used_skills && skill_flags & SKILL_TRAINING_TOOL && skill_gain_mult) + if(!islist(used_skills)) + user.mind.skill_holder.boost_skill_value_to(used_skills, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) + else + for(var/skill in used_skills) + user.mind.skill_holder.boost_skill_value_to(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) + return TRUE // Called before use_tool if there is a delay, or by use_tool if there isn't. diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm index acd71c57ac..91dde2899d 100644 --- a/code/game/objects/items/grenades/chem_grenade.dm +++ b/code/game/objects/items/grenades/chem_grenade.dm @@ -97,8 +97,7 @@ to_chat(user, "You add [A] to the [initial(name)] assembly.") else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = I - if (C.use(1)) + if (I.use_tool(src, user, 0, 1, max_level = JOB_SKILL_BASIC)) det_time = 50 // In case the cable_coil was removed and readded. stage_change(WIRED) to_chat(user, "You rig the [initial(name)] assembly.") diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index c8ee6b05c7..1648598c4e 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -69,7 +69,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ if (get_amount() < 1 || CC.get_amount() < 5) to_chat(user, "You attach wire to the [name].") var/obj/item/stack/light_w/new_tile = new(user.loc) diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm index 3e35c12314..1090bae9f8 100644 --- a/code/game/objects/structures/ai_core.dm +++ b/code/game/objects/structures/ai_core.dm @@ -131,7 +131,7 @@ if(C.get_amount() >= 5) playsound(loc, 'sound/items/deconstruct.ogg', 50, 1) to_chat(user, "You start to add cables to the frame...") - if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use(5)) + if(do_after(user, 20, target = src) && state == SCREWED_CORE && C.use_tool(src, user, 0, 5)) to_chat(user, "You add cables to the frame.") state = CABLED_CORE update_icon() diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm index d2fff9649d..821409c26b 100644 --- a/code/game/objects/structures/barsigns.dm +++ b/code/game/objects/structures/barsigns.dm @@ -84,7 +84,6 @@ panel_open = FALSE else if(istype(I, /obj/item/stack/cable_coil) && panel_open) - var/obj/item/stack/cable_coil/C = I if(obj_flags & EMAGGED) //Emagged, not broken by EMP to_chat(user, "Sign has been damaged beyond repair!") return @@ -92,7 +91,7 @@ to_chat(user, "This sign is functioning properly!") return - if(C.use(2)) + if(I.use_tool(src, user, 0, 2)) to_chat(user, "You replace the burnt wiring.") broken = FALSE else diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 04c3909696..4544cab3da 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -169,8 +169,7 @@ if(do_after(user, 40, target = src)) if(!src || !anchored || src.state != "01") return - var/obj/item/stack/cable_coil/CC = W - if(!CC.use(1)) + if(!W.use_tool(src, user, 0, 1)) to_chat(user, "You need more cable to do this!") return to_chat(user, "You wire the windoor.") diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index a4617462fe..0838c7b091 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -786,9 +786,8 @@ return user.visible_message("[user.name] wires the air alarm.", \ "You start wiring the air alarm...") - if (do_after(user, 20, target = src)) - if (cable.get_amount() >= 5 && buildstage == 1) - cable.use(5) + if (W.use_tool(src, user, 20, 5)) + if (buildstage == 1) to_chat(user, "You wire the air alarm.") wires.repair() aidisabled = 0 diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 0d08b59be9..11fdb47eb6 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -32,7 +32,7 @@ /obj/item/clothing/under/attackby(obj/item/I, mob/user, params) if((has_sensor == BROKEN_SENSORS) && istype(I, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/C = I - C.use(1) + I.use_tool(src, user, 0, 1) has_sensor = HAS_SENSORS to_chat(user,"You repair the suit sensors on [src] with [C].") return 1 diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index ef2eff707f..b18f4396d6 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -392,8 +392,7 @@ /datum/plant_gene/trait/battery/on_attackby(obj/item/reagent_containers/food/snacks/grown/G, obj/item/I, mob/user) if(istype(I, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = I - if(C.use(5)) + if(I.use_tool(src, user, 0, 5, max_level = JOB_SKILL_EXPERT)) to_chat(user, "You add some cable to [G] and slide it inside the battery encasing.") var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc) pocell.icon_state = G.icon_state diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index e40c278e92..e10f009cec 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -174,7 +174,7 @@ if(!starting_skills) return for(var/skill in starting_skills) - M.skill_holder.boost_skill_value_to(skill, starting_skills[skill]) + M.skill_holder.boost_skill_value_to(skill, starting_skills[skill], TRUE) //silent // do wipe affinities though M.skill_holder.skill_affinities = list() for(var/skill in skill_affinities) diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm index efe574ab66..1395b90b39 100644 --- a/code/modules/jobs/job_types/ai.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -17,6 +17,8 @@ var/do_special_check = TRUE threat = 5 + starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC)) + /datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, datum/outfit/outfit_override, client/preference_source = null) if(visualsOnly) CRASH("dynamic preview is unsupported") diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm index 019e50799e..770cbe3bda 100644 --- a/code/modules/jobs/job_types/atmospheric_technician.dm +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -17,6 +17,10 @@ ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM) minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_EMERGENCY_STORAGE, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM) + + starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC)) + skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) + display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN threat = 0.5 diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index 0d70e872ac..bd4732f3c3 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -27,6 +27,9 @@ ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED)) + skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) + display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity) threat = 2 diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm index f84bd0d8d6..d88d888aec 100644 --- a/code/modules/jobs/job_types/cyborg.dm +++ b/code/modules/jobs/job_types/cyborg.dm @@ -12,6 +12,8 @@ exp_requirements = 120 exp_type = EXP_TYPE_CREW + starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC)) + display_order = JOB_DISPLAY_ORDER_CYBORG /datum/job/cyborg/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source = null) diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index f9f1d20d3b..d9e891f057 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -16,6 +16,10 @@ access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS) minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) + starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED)) + skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) + + display_order = JOB_DISPLAY_ORDER_ROBOTICIST threat = 1 diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm index 66ddc90e9b..c5280d72db 100644 --- a/code/modules/jobs/job_types/station_engineer.dm +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -18,6 +18,9 @@ minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) + starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED)) + skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) + display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER threat = 1 diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index c7c34b0389..a0c2cc73e8 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -364,12 +364,11 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ /obj/item/coin/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/CC = W if(string_attached) to_chat(user, "There already is a string attached to this coin!") return - if (CC.use(1)) + if (W.use_tool(src, user, 0, 1, max_level = JOB_SKILL_BASIC)) add_overlay("coin_string_overlay") string_attached = 1 to_chat(user, "You attach a string to the coin.") diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 9c4f0316b7..42e702c5d9 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -9,7 +9,7 @@ if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses var/obj/item/clothing/glasses/GFP = src.glasses number += GFP.flash_protect - + if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask var/obj/item/clothing/mask/MFP = src.wear_mask number += MFP.flash_protect @@ -77,15 +77,13 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded) /mob/living/carbon/attacked_by(obj/item/I, mob/living/user) - //CIT CHANGES START HERE - combatmode and resting checks - var/totitemdamage = I.force + var/totitemdamage = pre_attacked_by(I, user, TRUE) if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) totitemdamage *= 0.5 if(!CHECK_MOBILITY(user, MOBILITY_STAND)) totitemdamage *= 0.5 if(!(combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) totitemdamage *= 1.5 - //CIT CHANGES END HERE var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected) if((user != src) && (run_block(I, totitemdamage, "the [I]", ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone) & BLOCK_SUCCESS)) return FALSE diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 683c3e18fd..124f862244 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1712,9 +1712,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) disarm(M, H, attacker_style) /datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H) + var/totitemdamage = H.pre_attacked_by(I, user, TRUE) // Allows you to put in item-specific reactions based on species if(user != H) - if(H.run_block(I, I.force, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone) & BLOCK_SUCCESS) + if(H.run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone) & BLOCK_SUCCESS) return 0 if(H.check_martial_melee_block()) H.visible_message("[H] blocks [I]!") @@ -1730,16 +1731,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/armor_block = H.run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].",I.armour_penetration) armor_block = min(90,armor_block) //cap damage reduction at 90% var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) - //CIT CHANGES START HERE - combatmode and resting checks - var/totitemdamage = I.force - if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) - totitemdamage *= 0.5 - if(!CHECK_MOBILITY(user, MOBILITY_STAND)) - totitemdamage *= 0.5 - if(istype(H)) - if(!(H.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) - totitemdamage *= 1.5 - //CIT CHANGES END HERE var/weakness = H.check_weakness(I, user) apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H) //CIT CHANGE - replaces I.force with totitemdamage @@ -1747,7 +1738,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) I.do_stagger_action(H, user) - if(!I.force) + if(!totitemdamage) return 0 //item force is zero //dismemberment diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index b389e386d4..508dc67dd7 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -427,24 +427,23 @@ else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed) user.changeNext_move(CLICK_CD_MELEE) - var/obj/item/stack/cable_coil/coil = W if (getFireLoss() > 0 || getToxLoss() > 0) - if(src == user && coil.use(1)) + if(src == user) to_chat(user, "You start fixing yourself...") - if(!do_after(user, 50, target = src)) + if(!W.use_tool(src, user, 50, 1, max_level = JOB_SKILL_TRAINED)) + to_chat(user, "You need more cable to repair [src]!") return adjustFireLoss(-10) adjustToxLoss(-10) - if (coil.use(1)) + else to_chat(user, "You start fixing [src]...") - if(!do_after(user, 30, target = src)) + if(!W.use_tool(src, user, 30, 1)) + to_chat(user, "You need more cable to repair [src]!") return adjustFireLoss(-30) adjustToxLoss(-30) updatehealth() user.visible_message("[user] has fixed some of the burnt wires on [src].", "You fix some of the burnt wires on [src].") - else - to_chat(user, "You need more cable to repair [src]!") else to_chat(user, "The wires seem fine, there's no need to fix them.") diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 6c4680a477..08fffc2cf8 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -147,9 +147,8 @@ to_chat(user, "You need one length of cable to wire the ED-209!") return to_chat(user, "You start to wire [src]...") - if(do_after(user, 40, target = src)) - if(coil.get_amount() >= 1 && build_step == 6) - coil.use(1) + if(coil.use_tool(src, user, 40, 1)) + if(build_step == 6) to_chat(user, "You wire [src].") name = "wired ED-209 assembly" build_step++ diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm index 744db1572f..37f3fc434e 100644 --- a/code/modules/modular_computers/hardware/_hardware.dm +++ b/code/modules/modular_computers/hardware/_hardware.dm @@ -41,11 +41,10 @@ // Cable coil. Works as repair method, but will probably require multiple applications and more cable. if(istype(I, /obj/item/stack/cable_coil)) - var/obj/item/stack/S = I if(obj_integrity == max_integrity) to_chat(user, "\The [src] doesn't seem to require repairs.") return 1 - if(S.use(1)) + if(I.use_tool(src, user, 0, 1)) to_chat(user, "You patch up \the [src] with a bit of \the [I].") obj_integrity = min(obj_integrity + 10, max_integrity) return 1 diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7eabeafcb1..977a6484b7 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -593,19 +593,15 @@ user.visible_message("[user.name] adds cables to the APC frame.", \ "You start adding cables to the APC frame...") playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) - if(do_after(user, 20, target = src)) - if (C.get_amount() < 10 || !C) + if(C.use_tool(src, user, 20, 10) && !terminal && opened && has_electronics) + var/turf/T = get_turf(src) + var/obj/structure/cable/N = T.get_cable_node() + if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE)) + do_sparks(5, TRUE, src) return - if (C.get_amount() >= 10 && !terminal && opened && has_electronics) - var/turf/T = get_turf(src) - var/obj/structure/cable/N = T.get_cable_node() - if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE)) - do_sparks(5, TRUE, src) - return - C.use(10) - to_chat(user, "You add cables to the APC frame.") - make_terminal() - terminal.connect_to_network() + to_chat(user, "You add cables to the APC frame.") + make_terminal() + terminal.connect_to_network() else if (istype(W, /obj/item/electronics/apc) && opened) if (has_electronics) to_chat(user, "There is already a board inside the [src]!") diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index eecc1394de..1e2650d17f 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -495,6 +495,8 @@ By design, d1 is the smallest direction and d2 is the highest full_w_class = WEIGHT_CLASS_SMALL grind_results = list(/datum/reagent/copper = 2) //2 copper per cable in the coil usesound = 'sound/items/deconstruct.ogg' + used_skills = /datum/skill/level/job/wiring + skill_flags = SKILL_USE_TOOL|SKILL_TRAINING_TOOL /obj/item/stack/cable_coil/cyborg is_cyborg = 1 @@ -576,8 +578,6 @@ By design, d1 is the smallest direction and d2 is the highest amount += extra update_icon() - - /////////////////////////////////////////////// // Cable laying procedures ////////////////////////////////////////////// diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm index 9fb1a1ce7d..e0b3f5f316 100644 --- a/code/modules/power/floodlight.dm +++ b/code/modules/power/floodlight.dm @@ -15,8 +15,7 @@ state = FLOODLIGHT_NEEDS_WIRES desc = "A bare metal frame looking vaguely like a floodlight. Requires wiring." else if(istype(O, /obj/item/stack/cable_coil) && (state == FLOODLIGHT_NEEDS_WIRES)) - var/obj/item/stack/S = O - if(S.use(5)) + if(O.use_tool(src, user, 0, 5)) to_chat(user, "You wire [src].") name = "wired [name]" desc = "A bare metal frame looking vaguely like a floodlight. Requires securing with a screwdriver." diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 7ad9f3a6ce..2f7f9ad729 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -118,8 +118,7 @@ return if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/coil = W - if(coil.use(1)) + if(W.use_tool(src, user, 0, 1, max_level = JOB_SKILL_TRAINED)) icon_state = "[fixture_type]-construct-stage2" stage = 2 user.visible_message("[user.name] adds wires to [src].", \ diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm index 59792b6539..e33116b02c 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm @@ -79,8 +79,7 @@ construction_state = PA_CONSTRUCTION_UNSECURED did_something = TRUE else if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/CC = W - if(CC.use(1)) + if(W.use_tool(src, user, 0, 1)) user.visible_message("[user.name] adds wires to the [name].", \ "You add some wires.") construction_state = PA_CONSTRUCTION_PANEL_OPEN diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index af83f7ebca..957ceb986f 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -288,8 +288,7 @@ construction_state = PA_CONSTRUCTION_UNSECURED did_something = TRUE else if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/CC = W - if(CC.use(1)) + if(W.use_tool(src, user, 0, 1)) user.visible_message("[user.name] adds wires to the [name].", \ "You add some wires.") construction_state = PA_CONSTRUCTION_PANEL_OPEN diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 41ed28f0a5..85999707a2 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -125,15 +125,12 @@ to_chat(user, "You start building the power terminal...") playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) - if(do_after(user, 20, target = src) && C.get_amount() >= 10) - if(C.get_amount() < 10 || !C) - return + if(C.use_tool(src, user, 20, 10)) var/obj/structure/cable/N = T.get_cable_node() //get the connecting node cable, if there's one if (prob(50) && electrocute_mob(usr, N, N, 1, TRUE)) //animate the electrocution if uncautious and unlucky do_sparks(5, TRUE, src) return - C.use(10) user.visible_message(\ "[user.name] has built a power terminal.",\ "You build the power terminal.") diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index b43ac3057a..afe2b9ca3e 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -331,8 +331,7 @@ /obj/item/gun/ballistic/revolver/doublebarrel/improvised/attackby(obj/item/A, mob/user, params) ..() if(istype(A, /obj/item/stack/cable_coil) && !sawn_off) - var/obj/item/stack/cable_coil/C = A - if(C.use(10)) + if(A.use_tool(src, user, 0, 10, max_level = JOB_SKILL_BASIC)) slot_flags = ITEM_SLOT_BACK to_chat(user, "You tie the lengths of cable to the shotgun, making a sling.") slung = TRUE diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index a3f8b883b4..39e660203e 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -19,7 +19,7 @@ flags_1 = CONDUCT_1 icon_state = "borg_l_arm" status = BODYPART_ROBOTIC - + brute_reduction = 2 burn_reduction = 1 @@ -40,7 +40,7 @@ flags_1 = CONDUCT_1 icon_state = "borg_r_arm" status = BODYPART_ROBOTIC - + brute_reduction = 2 burn_reduction = 1 @@ -61,7 +61,7 @@ flags_1 = CONDUCT_1 icon_state = "borg_l_leg" status = BODYPART_ROBOTIC - + brute_reduction = 2 burn_reduction = 1 @@ -82,7 +82,7 @@ flags_1 = CONDUCT_1 icon_state = "borg_r_leg" status = BODYPART_ROBOTIC - + brute_reduction = 2 burn_reduction = 1 @@ -102,7 +102,7 @@ flags_1 = CONDUCT_1 icon_state = "borg_chest" status = BODYPART_ROBOTIC - + brute_reduction = 2 burn_reduction = 1 @@ -131,8 +131,7 @@ if(src.wired) to_chat(user, "You have already inserted wire!") return - var/obj/item/stack/cable_coil/coil = W - if (coil.use(1)) + if (W.use_tool(src, user, 0, 1)) src.wired = 1 to_chat(user, "You insert the wire.") else @@ -164,7 +163,7 @@ flags_1 = CONDUCT_1 icon_state = "borg_head" status = BODYPART_ROBOTIC - + brute_reduction = 5 burn_reduction = 4 diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index 7127b41ee3..23dffdea87 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -58,10 +58,9 @@ return FALSE if(tool) speed_mod = tool.toolspeed - var/skill_mod = 1 - if(user?.mind?.skill_holder) - skill_mod = SURGERY_SKILL_SPEEDUP_NUMERICAL_SCALE(user.mind.skill_holder.get_skill_value(/datum/skill/numerical/surgery)) - if(do_after(user, time * speed_mod * skill_mod, target = target)) + if(user.mind) + SKILL_MODIFIER(GLOB.skill_datums[/datum/skill/numerical/surgery], user.mind.skill_holder, speed_mod, THRESHOLD_COMPETENT) + if(do_after(user, time * speed_mod, target = target)) var/prob_chance = 100 if(implement_type) //this means it isn't a require hand or any item step. prob_chance = implements[implement_type] @@ -69,7 +68,7 @@ if((prob(prob_chance) || (iscyborg(user) && !silicons_obey_prob)) && chem_check(target) && !try_to_fail) if(success(user, target, target_zone, tool, surgery)) - user?.mind?.skill_holder?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP) + user.mind?.skill_holder.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP) advance = TRUE else if(failure(user, target, target_zone, tool, surgery)) diff --git a/tgstation.dme b/tgstation.dme index 68ae7669f3..8245ef02f4 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -125,7 +125,8 @@ #include "code\__DEFINES\dcs\signals.dm" #include "code\__DEFINES\flags\shields.dm" #include "code\__DEFINES\misc\return_values.dm" -#include "code\__DEFINES\skills\skills.dm" +#include "code\__DEFINES\skills\defines.dm" +#include "code\__DEFINES\skills\helpers.dm" #include "code\__HELPERS\_cit_helpers.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm" From 0adca2d9b85767efc17fb05ceabf32c6205f16e9 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 May 2020 04:45:43 +0200 Subject: [PATCH 03/12] Oh. --- code/_onclick/item_attack.dm | 10 +++++----- code/modules/mob/living/carbon/carbon_defense.dm | 2 +- code/modules/mob/living/carbon/human/species.dm | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index dbcf171663..17d1e07d91 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -114,7 +114,7 @@ var/totitemdamage = I.force if(I.used_skills && user.mind) if(I.skill_flags & SKILL_ATTACK_OBJ) - LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, totitemdamage, I.skill_difficulty) + LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, totitemdamage, I.skill_difficulty) if(I.skill_flags & SKILL_TRAIN_ATTACK_OBJ) if(!islist(I.used_skills)) user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain) @@ -128,7 +128,7 @@ take_damage(totitemdamage, I.damtype, "melee", 1) /mob/living/attacked_by(obj/item/I, mob/living/user) - var/totitemdamage = calculate_item_force(I, user, TRUE) + var/totitemdamage = calculate_item_force(I, user) if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS) return FALSE send_item_attack_message(I, user) @@ -150,7 +150,7 @@ else return ..() -/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user, pre_attack = FALSE) +/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user) . = I.force if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) . *= 0.5 @@ -159,7 +159,7 @@ if(!pre_attack || !user.mind || !I.used_skills) return if(. && I.skill_flags & SKILL_ATTACK_MOB) - LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, ., I.skill_difficulty) + LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, ., I.skill_difficulty) if(I.skill_flags & SKILL_TRAIN_ATTACK_MOB) if(!islist(I.used_skills)) user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain) @@ -167,7 +167,7 @@ for(var/skill in used_skills) user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain) -/mob/living/carbon/proc/pre_attacked_by(obj/item/I, mob/living/user, pre_attack = FALSE) +/mob/living/carbon/pre_attacked_by(obj/item/I, mob/living/user) . = ..() if(!(combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) . *= 1.5 diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 42e702c5d9..f1d3cf0356 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -77,7 +77,7 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded) /mob/living/carbon/attacked_by(obj/item/I, mob/living/user) - var/totitemdamage = pre_attacked_by(I, user, TRUE) + var/totitemdamage = pre_attacked_by(I, user) if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) totitemdamage *= 0.5 if(!CHECK_MOBILITY(user, MOBILITY_STAND)) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 124f862244..71cdcd3f38 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1712,7 +1712,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) disarm(M, H, attacker_style) /datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H) - var/totitemdamage = H.pre_attacked_by(I, user, TRUE) + var/totitemdamage = H.pre_attacked_by(I, user) // Allows you to put in item-specific reactions based on species if(user != H) if(H.run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone) & BLOCK_SUCCESS) From c34655d0940cef922da6f236e506e185ac96337b Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 May 2020 04:48:49 +0200 Subject: [PATCH 04/12] Uh uh. --- code/modules/mob/living/carbon/carbon_defense.dm | 2 +- code/modules/mob/living/carbon/human/species.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index f1d3cf0356..03bfd87376 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -92,7 +92,7 @@ affecting = bodyparts[1] SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) send_item_attack_message(I, user, affecting.name) - I.do_stagger_action(src, user) + I.do_stagger_action(src, user, totitemdamage) if(I.force) apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 71cdcd3f38..8221134276 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1736,7 +1736,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) H.send_item_attack_message(I, user, hit_area) - I.do_stagger_action(H, user) + I.do_stagger_action(H, user, totitemdamage) if(!totitemdamage) return 0 //item force is zero From 791b05871f5effdcd13e1cb3260f958a2f64f5f0 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 May 2020 05:24:40 +0200 Subject: [PATCH 05/12] Hey. --- code/_onclick/item_attack.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 17d1e07d91..36a718b4b5 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -117,9 +117,9 @@ LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, totitemdamage, I.skill_difficulty) if(I.skill_flags & SKILL_TRAIN_ATTACK_OBJ) if(!islist(I.used_skills)) - user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain) + user.mind.skill_holder.boost_skill_value_to(I.used_skills, I.skill_gain) else - for(var/skill in used_skills) + for(var/skill in I.used_skills) user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain) if(totitemdamage) visible_message("[user] has hit [src] with [I]!", null, null, COMBAT_MESSAGE_RANGE) @@ -128,7 +128,7 @@ take_damage(totitemdamage, I.damtype, "melee", 1) /mob/living/attacked_by(obj/item/I, mob/living/user) - var/totitemdamage = calculate_item_force(I, user) + var/totitemdamage = pre_attacked_by(I, user) if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS) return FALSE send_item_attack_message(I, user) @@ -156,15 +156,15 @@ . *= 0.5 if(!CHECK_MOBILITY(user, MOBILITY_STAND)) . *= 0.5 - if(!pre_attack || !user.mind || !I.used_skills) + if(!user.mind || !I.used_skills) return if(. && I.skill_flags & SKILL_ATTACK_MOB) LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, ., I.skill_difficulty) if(I.skill_flags & SKILL_TRAIN_ATTACK_MOB) if(!islist(I.used_skills)) - user.mind.skill_holder.boost_skill_value_to(used_skills, I.skill_gain) + user.mind.skill_holder.boost_skill_value_to(I.used_skills, I.skill_gain) else - for(var/skill in used_skills) + for(var/skill in I.used_skills) user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain) /mob/living/carbon/pre_attacked_by(obj/item/I, mob/living/user) From 001109cfcd745589ac06c032b88a5ba2f869f193 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 May 2020 20:58:44 +0200 Subject: [PATCH 06/12] About ready. --- code/__DEFINES/combat.dm | 9 +++++ code/__DEFINES/skills/defines.dm | 3 ++ code/__DEFINES/skills/helpers.dm | 40 ++++++++++--------- code/_onclick/item_attack.dm | 50 ++++++++++++++---------- code/datums/skills/_skill.dm | 34 ++++++++-------- code/datums/skills/_skill_holder.dm | 19 +++++---- code/datums/wires/_wires.dm | 10 +++-- code/game/objects/items.dm | 18 ++++----- code/game/objects/items/melee/misc.dm | 2 +- code/game/objects/items/stunbaton.dm | 2 +- code/game/objects/items/toys.dm | 5 +-- code/modules/mob/living/carbon/carbon.dm | 2 +- code/modules/power/cable.dm | 3 +- 13 files changed, 111 insertions(+), 86 deletions(-) diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 7de162207d..74ce8519a2 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -248,6 +248,15 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. #define TOTAL_MASS_TOY_SWORD 1.5 +//stamina cost defines. +#define STAM_COST_ATTACK_OBJ_MULT 1.2 +#define STAM_COST_ATTACK_MOB_MULT 0.8 +#define STAM_COST_BATON_MOB_MULT 1 +#define STAM_COST_NO_COMBAT_MULT 1.25 +#define STAM_COST_W_CLASS_MULT 1.25 +#define STAM_COST_THROW_MULT 2 + + //bullet_act() return values #define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting. #define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting. diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm index 00859bbd40..58b51b88e7 100644 --- a/code/__DEFINES/skills/defines.dm +++ b/code/__DEFINES/skills/defines.dm @@ -36,6 +36,9 @@ #define SKILL_TRAIN_ATTACK_MOB (1<<3) #define SKILL_ATTACK_OBJ (1<<4) #define SKILL_TRAIN_ATTACK_OBJ (1<<5) +#define SKILL_STAMINA_COST (1<<6) //Influences the stamina cost from weapon usage. +#define SKILL_THROW_STAM_COST (1<<7) +#define SKILL_COMBAT_MODE (1<<8) //The user must have combat mode on. ///competency_threshold index defines #define THRESHOLD_COMPETENT 1 diff --git a/code/__DEFINES/skills/helpers.dm b/code/__DEFINES/skills/helpers.dm index 165b9091ae..88ad481e87 100644 --- a/code/__DEFINES/skills/helpers.dm +++ b/code/__DEFINES/skills/helpers.dm @@ -13,26 +13,28 @@ }\ target /= (1+(___value-to_check.competency_thresholds[threshold])*to_check.competency_mults[threshold]) -/// This is the one that accepts typepaths and lists. -#define LIST_SKILL_MODIFIER(to_check, holder, target, threshold) \ - if(!islist(to_check)){\ - SKILL_MODIFIER(GLOB.skill_datums[to_check], holder, target, threshold)\ - } else {\ - var/___sum = 0;\ - var/list/___L = to_check;\ - for(var/_S in ___L){\ - var/___value;\ - var/datum/skill/___S = GLOB.skill_datums[_S];\ - switch(___S.progression_type){\ - if(SKILL_PROGRESSION_LEVEL){\ - ___value = LAZYACCESS(holder.skill_levels, ___S.type)\ - } else {\ - ___value = LAZYACCESS(holder.skills, ___S.type)\ - }\ - }\ - ___sum += (1+(___value - ___S.competency_thresholds[threshold])*___S.competency_mults[threshold])\ +/// This is the one that accepts typepaths and lists. if flags are enabled, an associative value check will be done. +#define LIST_SKILL_MODIFIER(list, holder, target, threshold, flags, bad_flags) \ + var/___sum = 0;\ + var/___divisor = 0;\ + for(var/_S in list){\ + if((flags && !(list[_S] & (flags))) || (bad_flags && list[_S] & (bad_flags))){\ + continue\ }\ - target /= (___sum/length(___L))\ + var/___value;\ + var/datum/skill/___S = GLOB.skill_datums[_S];\ + switch(___S.progression_type){\ + if(SKILL_PROGRESSION_LEVEL){\ + ___value = LAZYACCESS(holder.skill_levels, ___S.type)\ + } else {\ + ___value = LAZYACCESS(holder.skills, ___S.type)\ + }\ + }\ + ___sum += (1+(___value - ___S.competency_thresholds[threshold])*___S.competency_mults[threshold]);\ + ___divisor++\ + }\ + if(___divisor){\ + target /= (___sum/___divisor)\ } //How experience levels are calculated. diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 36a718b4b5..cdbab52d15 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -91,7 +91,7 @@ log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") add_fingerprint(user) - user.adjustStaminaLossBuffered(getweight()*0.8)//CIT CHANGE - makes attacking things cause stamina loss + user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_MOB_MULT))//CIT CHANGE - makes attacking things cause stamina loss //the equivalent of the standard version of attack() but for object targets. /obj/item/proc/attack_obj(obj/O, mob/living/user) @@ -102,7 +102,7 @@ if(IS_STAMCRIT(user)) // CIT CHANGE - makes it impossible to attack in stamina softcrit to_chat(user, "You're too exhausted.") // CIT CHANGE - ditto return // CIT CHANGE - ditto - user.adjustStaminaLossBuffered(getweight()*1.2)//CIT CHANGE - makes attacking things cause stamina loss + user.adjustStaminaLossBuffered(getweight(user, STAM_COST_ATTACK_OBJ_MULT))//CIT CHANGE - makes attacking things cause stamina loss user.changeNext_move(CLICK_CD_MELEE) user.do_attack_animation(O) O.attacked_by(src, user) @@ -112,15 +112,17 @@ /obj/attacked_by(obj/item/I, mob/living/user) var/totitemdamage = I.force + var/bad_flag = NONE + if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user)) + totitemdamage *= 0.5 + bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills. if(I.used_skills && user.mind) - if(I.skill_flags & SKILL_ATTACK_OBJ) - LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, totitemdamage, I.skill_difficulty) - if(I.skill_flags & SKILL_TRAIN_ATTACK_OBJ) - if(!islist(I.used_skills)) - user.mind.skill_holder.boost_skill_value_to(I.used_skills, I.skill_gain) - else - for(var/skill in I.used_skills) - user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain) + if(totitemdamage) + LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_flag) + for(var/skill in I.used_skills) + if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ)) + continue + user.mind.skill_holder.auto_gain_experience(skill, I.skill_gain) if(totitemdamage) visible_message("[user] has hit [src] with [I]!", null, null, COMBAT_MESSAGE_RANGE) //only witnesses close by and the victim see a hit message. @@ -152,20 +154,20 @@ /mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user) . = I.force - if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) + var/bad_flag = NONE + if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user)) . *= 0.5 + bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills. if(!CHECK_MOBILITY(user, MOBILITY_STAND)) . *= 0.5 if(!user.mind || !I.used_skills) return - if(. && I.skill_flags & SKILL_ATTACK_MOB) - LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, ., I.skill_difficulty) - if(I.skill_flags & SKILL_TRAIN_ATTACK_MOB) - if(!islist(I.used_skills)) - user.mind.skill_holder.boost_skill_value_to(I.used_skills, I.skill_gain) - else - for(var/skill in I.used_skills) - user.mind.skill_holder.boost_skill_value_to(skill, I.skill_gain) + if(.) + LIST_SKILL_MODIFIER(I.used_skills, user.mind.skill_holder, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_flag) + for(var/skill in I.used_skills) + if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB)) + continue + user.mind.skill_holder.auto_gain_experience(skill, I.skill_gain) /mob/living/carbon/pre_attacked_by(obj/item/I, mob/living/user) . = ..() @@ -205,8 +207,14 @@ return 1 /// How much stamina this takes to swing this is not for realism purposes hecc off. -/obj/item/proc/getweight() - return total_mass || w_class * 1.25 +/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = NONE) + . = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier + var/bad_flag = NONE + if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) + . *= STAM_COST_NO_COMBAT_MULT + bad_flag |= SKILL_COMBAT_MODE + if(used_skills && user.mind) + LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, ., skill_difficulty, SKILL_STAMINA_COST|flags, bad_flag) /// How long this staggers for. 0 and negatives supported. /obj/item/proc/melee_stagger_duration(force_override) diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm index 039afacfa5..acfa44389e 100644 --- a/code/datums/skills/_skill.dm +++ b/code/datums/skills/_skill.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /// Our description var/desc /// Color of the name as shown in the html readout - var/name_color = "#000000" + var/name_color = "#FFFFFF" /// Our progression type var/progression_type /// Abstract type @@ -62,7 +62,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /** * Standard value "render" */ -/datum/skill/proc/standard_render_value(value) +/datum/skill/proc/standard_render_value(value, level) return value // Just saying, the choice to use different sub-parent-types is to force coders to resolve issues as I won't be implementing custom procs to grab skill levels in a certain context. @@ -77,7 +77,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /datum/skill/binary/sanitize_value(new_value) return new_value? TRUE : FALSE -/datum/skill/binary/standard_render_value(value) +/datum/skill/binary/standard_render_value(value, level) return value? "Yes" : "No" /datum/skill/numerical @@ -93,7 +93,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /datum/skill/numerical/sanitize_value(new_value) return clamp(new_value, min_value, max_value) -/datum/skill/numerical/standard_render_value(value) +/datum/skill/numerical/standard_render_value(value, level) return display_as_percent? "[round(value/max_value/100, 0.01)]%" : "[value] / [max_value]" /datum/skill/enum @@ -113,7 +113,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) abstract_type = /datum/skill/level progression_type = SKILL_PROGRESSION_LEVEL var/standard_xp_lvl_up = STD_XP_LVL_UP //the standard required to level up. def: 100 - var/xp_lvl_multiplier = STD_XP_LVL_UP //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.) + var/xp_lvl_multiplier = STD_XP_LVL_MULTI //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.) var/max_levels = STD_MAX_LVL var/level_up_method = STANDARD_LEVEL_UP //how levels are calculated. var/list/levels = list() //level thresholds, if associative, these will be preceded by tiers such as "novice" or "trained" @@ -132,7 +132,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) value = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl) if(DWARFY_LEVEL_UP) value = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl) - value = round(value) + value = round(value, 1) if(!associative) levels += value continue @@ -142,7 +142,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) var/key = LAZYACCESS(levels, lvl) if(!key) if(lvl == 1) //You dun goof it. - stack_trace("Skill datum [src] was set to have an associative levels list despite the latted having no key.") + stack_trace("Skill datum [src] was set to have an associative levels list despite the latter having no key value.") associative = FALSE levels += value continue @@ -170,18 +170,18 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) else if(. < 0) to_chat(M.current, "I feel like I've become worse at [name]!") -/datum/skill/level/standard_render_value(value) - var/current_lvl = associative ? unskilled_tier : 0 +/datum/skill/level/standard_render_value(value, level) + var/current_lvl = associative ? (!level ? unskilled_tier : levels[level]) : level var/current_lvl_xp_sum = 0 - var/next_lvl_xp_sum - for(var/lvl in 1 to max_levels) - next_lvl_xp_sum = associative ? levels[levels[lvl]] : levels[lvl] - if(value < next_lvl_xp_sum) - break - current_lvl_xp_sum = next_lvl_xp_sum - current_lvl = associative ? levels[lvl] : lvl+1 + if(level) + current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level] + var/next_index = max(max_levels, level+1) + var/next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index] + if(next_lvl_xp > current_lvl_xp_sum) + next_lvl_xp -= current_lvl_xp_sum - return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp_sum])[value > next_lvl_xp_sum ? " \[MAX!\]" : ""]" + + return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp])[level == max_levels ? " \[MAX!\]" : ""]" /datum/skill/level/job levels = list("Basic", "Trained", "Experienced", "Master") diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm index db9a84bb05..8b72b5c96d 100644 --- a/code/datums/skills/_skill_holder.dm +++ b/code/datums/skills/_skill_holder.dm @@ -29,8 +29,8 @@ * Grabs the level of a skill. Only supported by skills with tiers or levels. */ /datum/skill_holder/proc/get_skill_level(skill) - if(!ispath(skill)) - CRASH("Invalid get_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. + if(!ispath(skill, /datum/skill)) + CRASH("Invalid get_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. if(!skill_levels) return 0 return skill_levels[skill] @@ -39,8 +39,8 @@ * Grabs our affinity for a skill. !!This is a multiplier!! */ /datum/skill_holder/proc/get_skill_affinity(skill) - if(!ispath(skill)) - CRASH("Invalid get_skill_affinity call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. + if(!ispath(skill, /datum/skill)) + CRASH("Invalid get_skill_affinity call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. var/affinity = LAZYACCESS(skill_affinities, skill) if(isnull(affinity)) return 1 @@ -51,7 +51,7 @@ */ /datum/skill_holder/proc/set_skill_value(skill, value, silent = FALSE) if(!ispath(skill, /datum/skill)) - CRASH("Invalid set_skill_value call. Use typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. + CRASH("Invalid set_skill_value call. Use skill typepaths.") //until a time when we somehow need text ids for dynamic skills, I'm enforcing this. var/datum/skill/S = GLOB.skill_datums[skill] value = S.sanitize_value(value) if(!isnull(value)) @@ -75,8 +75,11 @@ * Only works if skill is numerical. */ /datum/skill_holder/proc/auto_gain_experience(skill, value, maximum, silent = FALSE) - if(!ispath(skill, /datum/skill/numerical)) - CRASH("You cannot auto increment a non numerical skill!") + if(!ispath(skill, /datum/skill)) + CRASH("Invalid set_skill_value call. Use skill typepaths.") + var/datum/skill/S = GLOB.skill_datums[skill] + if(S.progression_type != SKILL_PROGRESSION_NUMERICAL && S.progression_type != SKILL_PROGRESSION_LEVEL) + CRASH("You cannot auto increment a non numerical(experience skill!") var/current = get_skill_value(skill) var/affinity = get_skill_affinity(skill) var/target_value = current + (value * affinity) @@ -95,6 +98,6 @@ out += "" for(var/path in skills) var/datum/skill/S = GLOB.skill_datums[path] - out += "" + out += "" out += "
SkillValue
[S.name][S.standard_render_value(skills[path])]
[S.name][S.standard_render_value(skills[path], LAZYACCESS(skill_levels, path) || 0)]
" return out.Join("") diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index fc31cb9286..d2f719c50c 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -140,10 +140,12 @@ if(req_skill && user?.mind) var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) if(level_diff > 0) + LAZYSET(current_users, user, TRUE) to_chat(user, "You begin cutting [holder]'s [color] wire...") if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user)) + LAZYREMOVE(current_users, user) return FALSE - user.mind?.skill_holder.auto_gain_experience(/datum/skill/level/job/wiring, DEF_SKILL_GAIN*level_diff) + LAZYREMOVE(current_users, user) to_chat(user, "You cut [holder]'s [color] wire.") cut(get_wire(color)) return TRUE @@ -167,10 +169,12 @@ if(req_skill && user?.mind) var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) if(level_diff > 0) + LAZYSET(current_users, user, TRUE) to_chat(user, "You begin pulsing [holder]'s [color] wire...") if(!do_after(user, 1.5 SECONDS * level_diff, target = holder) || !interactable(user)) + LAZYREMOVE(current_users, user) return FALSE - user.mind?.skill_holder.auto_gain_experience(/datum/skill/level/job/wiring, DEF_SKILL_GAIN*level_diff) + LAZYREMOVE(current_users, user) to_chat(user, "You pulse [holder]'s [color] wire.") pulse(get_wire(color), user) return TRUE @@ -286,7 +290,7 @@ if("cut") I = L.is_holding_tool_quality(TOOL_WIRECUTTER) if(I || IsAdminGhost(usr)) - if(cut_color(target_wire) && I && holder) + if(cut_color(target_wire, L) && I && holder) I.play_tool_sound(holder, 20) . = TRUE else diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index c0c8f449e8..e781b6859c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -133,8 +133,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder! ///Skills vars - var/used_skills //path/s of skill/s exercised when using this item. - var/skill_flags = NONE //better defines which tasks the the skill/s is/are exercised on. + var/list/used_skills //list of skills exercised when using this item. An associated bitfield indicates how the skill is exercised. var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general. var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item. @@ -801,8 +800,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) play_tool_sound(target, volume) if(delay) - if(user.mind && used_skills && skill_flags & SKILL_USE_TOOL) - LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, delay, skill_difficulty) + if(user.mind && used_skills) + LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, delay, skill_difficulty, SKILL_USE_TOOL, NONE) // Create a callback with checks that would be called every tick by do_after. var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks) @@ -828,12 +827,11 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(delay >= MIN_TOOL_SOUND_DELAY) play_tool_sound(target, volume) - if(user.mind && used_skills && skill_flags & SKILL_TRAINING_TOOL && skill_gain_mult) - if(!islist(used_skills)) - user.mind.skill_holder.boost_skill_value_to(used_skills, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) - else - for(var/skill in used_skills) - user.mind.skill_holder.boost_skill_value_to(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) + if(user.mind && used_skills && skill_gain_mult) + for(var/skill in used_skills) + if(!(used_skills[skill] & SKILL_TRAINING_TOOL)) + continue + user.mind.skill_holder.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) return TRUE diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index c2db529675..3504ed2f50 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -325,7 +325,7 @@ else target.LAssailant = WEAKREF(user) cooldown_check = world.time + cooldown - user.adjustStaminaLossBuffered(getweight())//CIT CHANGE - makes swinging batons cost stamina + user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT)) else var/wait_desc = get_wait_description() if(wait_desc) diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 0fc47f649a..8a817f6d62 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -163,7 +163,7 @@ if(status) if(baton_stun(M, user, disarming)) user.do_attack_animation(M) - user.adjustStaminaLossBuffered(getweight()) //CIT CHANGE - makes stunbatonning others cost stamina + user.adjustStaminaLossBuffered(getweight(user, STAM_COST_BATON_MOB_MULT)) else if(user.a_intent != INTENT_HARM) //they'll try to bash in the last proc. M.visible_message("[user] has prodded [M] with [src]. Luckily it was off.", \ "[user] has prodded you with [src]. Luckily it was off") diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 9291b72467..722f6178bc 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -241,11 +241,13 @@ playsound(user, activation_sound, transform_volume, 1) w_class = WEIGHT_CLASS_BULKY AddElement(/datum/element/sword_point) + total_mass = total_mass_on else to_chat(user, "[deactivation_message]") playsound(user, deactivation_sound, transform_volume, 1) w_class = WEIGHT_CLASS_SMALL RemoveElement(/datum/element/sword_point) + total_mass = initial(total_mass) update_icon() add_fingerprint(user) @@ -287,9 +289,6 @@ else return ..() -/obj/item/toy/sword/getweight() - return (active ? total_mass_on : total_mass) || w_class *1.25 - /obj/item/toy/sword/cx name = "\improper DX Non-Euplastic LightSword" desc = "A deluxe toy replica of an energy sword. Realistic visuals and sounds! Ages 8 and up." diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 69c81229a7..821b432ea5 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -199,7 +199,7 @@ to_chat(src, "You set [I] down gently on the ground.") return - adjustStaminaLossBuffered(I.getweight()*2)//CIT CHANGE - throwing items shall be more tiring than swinging em. Doubly so. + adjustStaminaLossBuffered(I.getweight(src, STAM_COST_THROW_MULT, SKILL_THROW_STAM_COST)) if(thrown_thing) visible_message("[src] has thrown [thrown_thing].") diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 1e2650d17f..a633f83b2b 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -495,8 +495,7 @@ By design, d1 is the smallest direction and d2 is the highest full_w_class = WEIGHT_CLASS_SMALL grind_results = list(/datum/reagent/copper = 2) //2 copper per cable in the coil usesound = 'sound/items/deconstruct.ogg' - used_skills = /datum/skill/level/job/wiring - skill_flags = SKILL_USE_TOOL|SKILL_TRAINING_TOOL + used_skills = list(/datum/skill/level/job/wiring = SKILL_USE_TOOL|SKILL_TRAINING_TOOL) /obj/item/stack/cable_coil/cyborg is_cyborg = 1 From 81dde7debd1f1553a94d6f896f61024fad6dae4f Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 May 2020 21:04:19 +0200 Subject: [PATCH 07/12] Obligatory. --- code/_onclick/item_attack.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index cdbab52d15..88e0ad8627 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -209,6 +209,8 @@ /// How much stamina this takes to swing this is not for realism purposes hecc off. /obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = NONE) . = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier + if(!user) + return var/bad_flag = NONE if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) . *= STAM_COST_NO_COMBAT_MULT From 91d6faaf21a2d40f24f2c5c3beec8197ee67355b Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Tue, 5 May 2020 21:06:53 +0200 Subject: [PATCH 08/12] more obligatory changes. --- code/_onclick/item_attack.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 88e0ad8627..4d00b877a0 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -207,7 +207,7 @@ return 1 /// How much stamina this takes to swing this is not for realism purposes hecc off. -/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = NONE) +/obj/item/proc/getweight(mob/living/user, multiplier = 1, flags = SKILL_STAMINA_COST) . = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier if(!user) return @@ -216,7 +216,7 @@ . *= STAM_COST_NO_COMBAT_MULT bad_flag |= SKILL_COMBAT_MODE if(used_skills && user.mind) - LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, ., skill_difficulty, SKILL_STAMINA_COST|flags, bad_flag) + LIST_SKILL_MODIFIER(used_skills, user.mind.skill_holder, ., skill_difficulty, flags, bad_flag) /// How long this staggers for. 0 and negatives supported. /obj/item/proc/melee_stagger_duration(force_override) From 835753a02db657cd0e825a475bc12464389109cc Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Fri, 8 May 2020 02:14:07 +0200 Subject: [PATCH 09/12] ! --- code/datums/components/mood.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index cd9e89a5d8..d32d0d4f2e 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -201,7 +201,7 @@ if(old_sanity > 1 && sanity == 1) RegisterSignal(master, COMSIG_MOB_SKILL_GET_AFFINITY, .proc/on_get_skill_affinity) - else if(old_sanity == 1 && sanity < 1) + else if(old_sanity == 1 && sanity > 1) UnregisterSignal(master, COMSIG_MOB_SKILL_GET_AFFINITY) //update_mood_icon() From ddb50e2845597f4c677d12f7c17d22dcbb232b3d Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Fri, 8 May 2020 02:24:49 +0200 Subject: [PATCH 10/12] colors. --- code/__DEFINES/colors.dm | 1 + code/datums/skills/_skill.dm | 2 +- code/datums/skills/engineering.dm | 1 + code/datums/skills/medical.dm | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index cc2cd8834a..3d15412efe 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -43,6 +43,7 @@ #define COLOR_RED_GRAY "#B4696A" #define COLOR_PALE_BLUE_GRAY "#98C5DF" #define COLOR_PALE_GREEN_GRAY "#B7D993" +#define COLOR_PALE_ORANGE "#FFC066" #define COLOR_PALE_RED_GRAY "#D59998" #define COLOR_PALE_PURPLE_GRAY "#CBB1CA" #define COLOR_PURPLE_GRAY "#AE8CA8" diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm index 459a47a06c..f52945536f 100644 --- a/code/datums/skills/_skill.dm +++ b/code/datums/skills/_skill.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /// Our description var/desc /// Color of the name as shown in the html readout - var/name_color = "#FFFFFF" + var/name_color = "#F0F0F0" // White on dark surface. /// Our progression type var/progression_type /// Abstract type diff --git a/code/datums/skills/engineering.dm b/code/datums/skills/engineering.dm index 4cae3f9f63..59c9436e46 100644 --- a/code/datums/skills/engineering.dm +++ b/code/datums/skills/engineering.dm @@ -1,5 +1,6 @@ /datum/skill/level/job/wiring name = "Wiring" desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor." + name_color = COLOR_PALE_ORANGE competency_thresholds = list(JOB_SKILL_BASIC, JOB_SKILL_EXPERT, JOB_SKILL_MASTER) skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD|SKILL_USE_TOOL|SKILL_TRAINING_TOOL diff --git a/code/datums/skills/medical.dm b/code/datums/skills/medical.dm index 1b0774b0ce..aaae1236a6 100644 --- a/code/datums/skills/medical.dm +++ b/code/datums/skills/medical.dm @@ -1,4 +1,5 @@ /datum/skill/numerical/surgery name = "Surgery" desc = "How proficient you are at doing surgery." + name_color = COLOR_PALE_BLUE_GRAY competency_mults = list(0.025, 0.025, 0.025) // 60% surgery speed up at max value of 100. From 4041fce0f7473706fdb09c14acb45aecda87bce7 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Fri, 8 May 2020 02:30:57 +0200 Subject: [PATCH 11/12] whops. --- code/datums/wires/airlock.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index 60ccf891dd..2b13344cc6 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -1,7 +1,7 @@ /datum/wires/airlock holder_type = /obj/machinery/door/airlock proper_name = "Generic Airlock" - req_skill = JOB_SKILL_UNSKILLED //Training wheel, as per request. + req_skill = JOB_SKILL_UNTRAINED //Training wheel, as per request. var/wiretype /datum/wires/airlock/secure From 3dfef3c393c1cc83c70fdbca4e013f92fbc70895 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Fri, 8 May 2020 02:50:14 +0200 Subject: [PATCH 12/12] . --- code/game/objects/items.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d40f01959f..949ed050f5 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -134,7 +134,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) ///Skills vars //list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item. - var/list/datum/skill/used_skills. + var/list/datum/skill/used_skills var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general. var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item.