Skill calculation fixes, tweaks, antag and brain damage modifiers. (#12302)

* Skill calculation fixes, tweaks, antag and brain damage modifiers.

* Experience through patience.

* Priority Fix etcetera.
This commit is contained in:
Ghom
2020-05-21 03:42:58 +02:00
committed by GitHub
parent a7053a978f
commit 7f38e0714b
19 changed files with 181 additions and 114 deletions
+13 -13
View File
@@ -20,18 +20,20 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
var/desc
/// Color of the name as shown in the html readout
var/name_color = "#F0F0F0" // White on dark surface.
/// Our progression type
/// Our progression type. These are mostly used to skip typechecks overhead, don't go around messing with these.
var/progression_type
/// Abstract type
var/abstract_type = /datum/skill
/// List of max levels. Only used in level skills, but present here for helper macros.
var/max_levels = INFINITY
/// skill threshold used in generic skill competency 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)
/// In which way this skil can affect or be affected through actions and skill modifiers.
var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD
/// skill threshold used in generic skill competency operations.
var/list/competency_thresholds
/// Base multiplier used in skill competency operations.
var/base_multiplier = 1
/// Value added to the base multiplier depending on overall competency compared to maximum value/level.
var/competency_multiplier = 1
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
/**
* Ensures what someone's setting as a value for this skill is valid.
@@ -66,8 +68,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, 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)
competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE)
/datum/skill/binary/sanitize_value(new_value)
return new_value? TRUE : FALSE
@@ -78,6 +79,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/numerical
abstract_type = /datum/skill/numerical
progression_type = SKILL_PROGRESSION_NUMERICAL
competency_thresholds = list(THRESHOLD_COMPETENT = 25, THRESHOLD_EXPERT = 50, THRESHOLD_MASTER = 75)
/// Max value of this skill
var/max_value = 100
/// Min value of this skill
@@ -180,8 +182,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
/datum/skill/level/job
abstract_type = /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)
competency_thresholds = list(THRESHOLD_COMPETENT = JOB_SKILL_TRAINED, THRESHOLD_EXPERT = JOB_SKILL_EXPERT, THRESHOLD_MASTER = JOB_SKILL_MASTER)
associative = TRUE
//quite the reference, no?
@@ -195,7 +196,6 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
"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)
competency_thresholds = list(THRESHOLD_COMPETENT = DORF_SKILL_COMPETENT, THRESHOLD_EXPERT = DORF_SKILL_EXPERT, THRESHOLD_MASTER = DORF_SKILL_MASTER)
associative = TRUE
unskilled_tier = "Dabbling"
+31 -14
View File
@@ -122,16 +122,22 @@
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
/datum/mind/proc/action_skill_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
var/mod
var/datum/skill/S = GLOB.skill_datums[skill]
if(!S)
return
return value
var/mod = S.base_multiplier
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
mod = get_skill_level(S.type)
var/datum/skill/level/L = S
var/skill_lvl = get_skill_level(L.type)
mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[threshold]-skill_lvl, 0))*L.competency_multiplier
if(SKILL_PROGRESSION_NUMERICAL)
var/datum/skill/numerical/N = S
var/skill_val = get_skill_value(N.type)
mod += skill_val/(N.max_value+max(N.competency_thresholds[threshold]-skill_val, 0))*N.competency_multiplier
else
mod = get_skill_value(S.type)
mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
var/comp_threshold = S.competency_thresholds[threshold]
mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
. = modifier_is_multiplier ? value*mod : value/mod
/**
@@ -139,12 +145,12 @@
* Args:
* * item/I : the item used in this action. its used_skills list variable contains the skills exercised with it.
* * value : the value to modify, may be a delay, damage, probability.
* * flags : the required flags that each skill (either in I.used_skills or the skill datum skill_flags) must have to influence
* * traits : the required traits each skill (either in I.used_skills or the skill datum skill_traits) must have to influence
* * the value.
* * bad_flags : the opposite of the above, skills that must not be present to impact the value.
* * bad_traits : the opposite of the above.
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
/datum/mind/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
/datum/mind/proc/item_action_skills_mod(obj/item/I, value, traits, bad_traits, modifier_is_multiplier = TRUE)
. = value
var/sum = 0
var/divisor = 0
@@ -152,16 +158,27 @@
var/datum/skill/S = GLOB.skill_datums[k]
if(!S)
continue
var/our_flags = (I.used_skills[k]|S.skill_flags)
if((flags && !(our_flags & flags)) || (bad_flags && our_flags & bad_flags))
var/our_traits = S.skill_traits
var/item_traits = I.used_skills[k]
if(item_traits)
our_traits |= item_traits
if((traits && !(our_traits[traits] || length(our_traits & traits))) || (bad_traits && (our_traits[bad_traits] || length(our_traits & bad_traits))))
continue
var/mod
var/mod = S.base_multiplier
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
mod = get_skill_level(S.type)
var/datum/skill/level/L = S
var/skill_lvl = get_skill_level(L.type)
mod += skill_lvl/(L.max_levels+max(L.competency_thresholds[I.skill_difficulty]-skill_lvl, 0))*L.competency_multiplier
if(SKILL_PROGRESSION_NUMERICAL)
var/datum/skill/numerical/N = S
var/skill_val = get_skill_value(N.type)
mod += skill_val/(N.max_value+max(N.competency_thresholds[I.skill_difficulty]-skill_val, 0))*N.competency_multiplier
else
mod = get_skill_value(S.type)
sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
var/comp_threshold = S.competency_thresholds[I.skill_difficulty]
mod += (comp_threshold ? (get_skill_value(S.type) / comp_threshold) : get_skill_value(S.type))*S.competency_multiplier
sum += mod
divisor++
if(divisor)
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
+29 -11
View File
@@ -9,11 +9,13 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
/datum/skill_modifier
/// flags for this skill modifier.
var/modifier_flags = NONE
/// target skills, can be a specific skill typepath or a set of skill flags.
var/target_skills = NONE
/// target skills, can be a specific skill typepath or a list of skill traits.
var/target_skills = /datum/skill
/// the GLOB.potential_skills_per_mod key generated on runtime. You shouldn't be var-editing it.
var/target_skills_key
/// The identifier key this skill modifier is associated with.
var/identifier
/// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags flags.
/// skill affinity modifier, can be a multiplier or addendum, depending on the modifier_flags.
var/affinity_mod = 1
/// skill value modifier, see above.
var/value_mod = 1
@@ -38,21 +40,25 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
CRASH("Skill modifier identifier \"[identifier]\" already taken.")
GLOB.skill_modifiers[identifier] = src
if(ispath(target_skills))
target_skills_key = target_skills
var/list/mod_L = GLOB.potential_mods_per_skill[target_skills]
if(!mod_L)
mod_L = GLOB.potential_mods_per_skill[target_skills] = list()
else
BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE)
mod_L[identifier] = src
GLOB.potential_skills_per_mod["[target_skills]"] = list(target_skills)
else //Should be a bitfield.
var/list/L = GLOB.potential_skills_per_mod["[target_skills]"]
GLOB.potential_skills_per_mod[target_skills_key] = list(target_skills)
else //Should be a list.
var/list/T = target_skills
T = sortTim(target_skills, /proc/cmp_text_asc) //Sort the list contents alphabetically.
target_skills_key = T.Join("-")
var/list/L = GLOB.potential_skills_per_mod[target_skills_key]
if(!L)
L = list()
for(var/path in GLOB.skill_datums)
if(GLOB.skill_datums[path].skill_flags & target_skills)
if(GLOB.skill_datums[path].skill_traits & target_skills)
L += path
GLOB.potential_skills_per_mod["[target_skills]"] = L
GLOB.potential_skills_per_mod[target_skills_key] = L
for(var/path in L)
var/list/mod_L = GLOB.potential_mods_per_skill[path]
if(!mod_L)
@@ -62,7 +68,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
mod_L[identifier] = src
/datum/skill_modifier/Destroy()
for(var/path in GLOB.potential_skills_per_mod["[target_skills]"])
for(var/path in GLOB.potential_skills_per_mod[target_skills_key])
var/mod_L = GLOB.potential_mods_per_skill[path]
mod_L -= identifier
if(!length(mod_L))
@@ -96,7 +102,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
LAZYINITLIST(skill_holder.skill_affinity_mods)
if(M.modifier_flags & MODIFIER_SKILL_LEVEL)
LAZYINITLIST(skill_holder.skill_level_mods)
for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
if(M.modifier_flags & MODIFIER_SKILL_VALUE)
ADD_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values, get_skill_value(path, FALSE))
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY)
@@ -127,7 +133,7 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(!skill_holder.skill_value_mods && !skill_holder.skill_affinity_mods && !skill_holder.skill_level_mods)
return
for(var/path in GLOB.potential_skills_per_mod["[M.target_skills]"])
for(var/path in GLOB.potential_skills_per_mod[M.target_skills_key])
if(M.modifier_flags & MODIFIER_SKILL_VALUE && skill_holder.skill_value_mods)
REMOVE_MOD_STEP(skill_holder.skill_value_mods, path, skill_holder.original_values)
if(M.modifier_flags & MODIFIER_SKILL_AFFINITY && skill_holder.skill_affinity_mods)
@@ -155,6 +161,18 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
if(MODIFIER_TARGET_AFFINITY)
mod = affinity_mod
if(modifier_flags & MODIFIER_USE_THRESHOLDS && istext(mod))
var/datum/skill/S = GLOB.skill_datums[skillpath]
if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL)
var/datum/skill/level/L = S
switch(L.level_up_method)
if(STANDARD_LEVEL_UP)
mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
if(DWARFY_LEVEL_UP)
mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
else
mod = S.competency_thresholds[mod]
var/diff = 0
if(modifier_flags & (MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_HANDICAP))
if(modifier_flags & MODIFIER_SKILL_VIRTUE)
+1 -2
View File
@@ -2,5 +2,4 @@
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
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
+1 -1
View File
@@ -2,4 +2,4 @@
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.
competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier.
+2 -2
View File
@@ -1,8 +1,8 @@
/datum/skill_modifier/bad_mood
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = SKILL_USE_MOOD
target_skills = list(SKILL_SANITY)
/datum/skill_modifier/great_mood
modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
target_skills = SKILL_TRAIN_MOOD
target_skills = list(SKILL_SANITY)
affinity_mod = 1.2
+13
View File
@@ -0,0 +1,13 @@
/datum/skill_modifier/brain_damage
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
value_mod = 0.85
level_mod = 0.85
affinity_mod = 0.85
/datum/skill_modifier/heavy_brain_damage
target_skills = list(SKILL_INTELLIGENCE)
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS
priority = MODIFIER_SKILL_PRIORITY_LOW
value_mod = THRESHOLD_COMPETENT
level_mod = THRESHOLD_COMPETENT