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 += "
| Skill | Value |
"
for(var/path in skills)
var/datum/skill/S = GLOB.skill_datums[path]
- out += "| [S.name] | [S.standard_render_value(skills[path])] |
"
+ out += "| [S.name] | [S.standard_render_value(skills[path])] |
"
out += "
"
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 += "| Skill | Value |
"
for(var/path in skills)
var/datum/skill/S = GLOB.skill_datums[path]
- out += "| [S.name] | [S.standard_render_value(skills[path])] |
"
+ out += "| [S.name] | [S.standard_render_value(skills[path], LAZYACCESS(skill_levels, path) || 0)] |
"
out += "
"
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.