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:
@@ -27,25 +27,27 @@
|
||||
#define DEF_SKILL_GAIN 1
|
||||
#define SKILL_GAIN_SURGERY_PER_STEP 0.25
|
||||
|
||||
#define SKILL_AFFINITY_MOOD_BONUS 1.25
|
||||
//An extra point for each few seconds of delay when using a tool. Before the multiplier.
|
||||
#define SKILL_GAIN_DELAY_DIVISOR 3 SECONDS
|
||||
|
||||
///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)
|
||||
#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.
|
||||
#define SKILL_USE_MOOD (1<<9) //Is the skill negatively affected by bad mood.
|
||||
#define SKILL_TRAIN_MOOD (1<<10) //Is this skill training affected by good mood.
|
||||
///Items skill_traits and other defines
|
||||
#define SKILL_USE_TOOL "use_tool"
|
||||
#define SKILL_TRAINING_TOOL "training_tool"
|
||||
#define SKILL_ATTACK_MOB "attack_mob"
|
||||
#define SKILL_TRAIN_ATTACK_MOB "train_attack_mob"
|
||||
#define SKILL_ATTACK_OBJ "attack_obj"
|
||||
#define SKILL_TRAIN_ATTACK_OBJ "train_attack_obj"
|
||||
#define SKILL_STAMINA_COST "stamina_cost" //Influences the stamina cost from weapon usage.
|
||||
#define SKILL_THROW_STAM_COST "throw_stam_cost"
|
||||
#define SKILL_COMBAT_MODE "combat_mode" //The user must have combat mode on.
|
||||
#define SKILL_SANITY "sanity" //Is the skill affected by (in)sanity.
|
||||
#define SKILL_INTELLIGENCE "intelligence" //Is the skill affected by brain damage?
|
||||
|
||||
///competency_threshold index defines
|
||||
#define THRESHOLD_COMPETENT 1
|
||||
#define THRESHOLD_EXPERT 2
|
||||
#define THRESHOLD_MASTER 3
|
||||
///competency_threshold defines
|
||||
#define THRESHOLD_UNTRAINED "untrained"
|
||||
#define THRESHOLD_COMPETENT "competent"
|
||||
#define THRESHOLD_EXPERT "expert"
|
||||
#define THRESHOLD_MASTER "master"
|
||||
|
||||
/// Level/Experience skills defines.
|
||||
#define STD_XP_LVL_UP 100
|
||||
@@ -88,11 +90,14 @@
|
||||
#define MODIFIER_SKILL_BODYBOUND (1<<6)
|
||||
///Adds the difference of the current value and the value stored at the time the modifier was added to the result.
|
||||
#define MODIFIER_SKILL_ORIGIN_DIFF (1<<7)
|
||||
///Will this skill use competency thresholds instead of preset values
|
||||
#define MODIFIER_USE_THRESHOLDS (1<<8)
|
||||
|
||||
#define MODIFIER_TARGET_VALUE "value"
|
||||
#define MODIFIER_TARGET_LEVEL "level"
|
||||
#define MODIFIER_TARGET_AFFINITY "affinity"
|
||||
|
||||
///Ascending priority defines.
|
||||
#define MODIFIER_SKILL_PRIORITY_LOW 100
|
||||
#define MODIFIER_SKILL_PRIORITY_DEF 50
|
||||
#define MODIFIER_SKILL_PRIORITY_MAX 100 //max priority, meant for job/antag modifiers so they don't null out any debuff
|
||||
#define MODIFIER_SKILL_PRIORITY_MAX 1 //max priority, meant for job/antag modifiers so they don't null out other (de)buffs
|
||||
@@ -112,13 +112,13 @@
|
||||
|
||||
/obj/attacked_by(obj/item/I, mob/living/user)
|
||||
var/totitemdamage = I.force
|
||||
var/bad_flag = NONE
|
||||
var/bad_trait
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
|
||||
totitemdamage *= 0.5
|
||||
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(I.used_skills && user.mind)
|
||||
if(totitemdamage)
|
||||
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_flag)
|
||||
totitemdamage = user.mind.item_action_skills_mod(I, totitemdamage, I.skill_difficulty, SKILL_ATTACK_OBJ, bad_trait)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ))
|
||||
continue
|
||||
@@ -154,16 +154,16 @@
|
||||
|
||||
/mob/living/proc/pre_attacked_by(obj/item/I, mob/living/user)
|
||||
. = I.force
|
||||
var/bad_flag = NONE
|
||||
var/bad_trait
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && iscarbon(user))
|
||||
. *= 0.5
|
||||
bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
bad_trait = SKILL_COMBAT_MODE //blacklist combat skills.
|
||||
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
|
||||
. *= 0.5
|
||||
if(!user.mind || !I.used_skills)
|
||||
return
|
||||
if(.)
|
||||
. = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_flag)
|
||||
. = user.mind.item_action_skills_mod(I, ., I.skill_difficulty, SKILL_ATTACK_MOB, bad_trait)
|
||||
for(var/skill in I.used_skills)
|
||||
if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB))
|
||||
continue
|
||||
@@ -207,16 +207,16 @@
|
||||
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 = SKILL_STAMINA_COST)
|
||||
/obj/item/proc/getweight(mob/living/user, multiplier = 1, trait = SKILL_STAMINA_COST)
|
||||
. = (total_mass || w_class * STAM_COST_W_CLASS_MULT) * multiplier
|
||||
if(!user)
|
||||
return
|
||||
var/bad_flag = NONE
|
||||
var/bad_trait
|
||||
if(iscarbon(user) && !(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
. *= STAM_COST_NO_COMBAT_MULT
|
||||
bad_flag |= SKILL_COMBAT_MODE
|
||||
bad_trait = SKILL_COMBAT_MODE
|
||||
if(used_skills && user.mind)
|
||||
. = user.mind.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE)
|
||||
. = user.mind.item_action_skills_mod(src, ., skill_difficulty, trait, bad_trait, FALSE)
|
||||
|
||||
/// How long this staggers for. 0 and negatives supported.
|
||||
/obj/item/proc/melee_stagger_duration(force_override)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -135,7 +135,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/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general.
|
||||
var/skill_difficulty = THRESHOLD_UNTRAINED //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()
|
||||
@@ -805,7 +805,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
|
||||
if(delay)
|
||||
if(user.mind && used_skills)
|
||||
delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, NONE, FALSE)
|
||||
delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, null, FALSE)
|
||||
|
||||
// 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)
|
||||
@@ -831,11 +831,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_gain_mult)
|
||||
var/gain = skill_gain + delay/SKILL_GAIN_DELAY_DIVISOR
|
||||
for(var/skill in used_skills)
|
||||
if(!(used_skills[skill] & SKILL_TRAINING_TOOL))
|
||||
if(!(SKILL_TRAINING_TOOL in used_skills[skill]))
|
||||
continue
|
||||
user.mind.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
|
||||
user.mind.auto_gain_experience(skill, gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
|
||||
var/threat = 0 // Amount of threat this antag poses, for dynamic mode
|
||||
|
||||
var/list/skill_modifiers
|
||||
|
||||
/datum/antagonist/New()
|
||||
GLOB.antagonists += src
|
||||
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
|
||||
@@ -68,15 +70,19 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
//Proc called when the datum is given to a mind.
|
||||
/datum/antagonist/proc/on_gain()
|
||||
if(owner && owner.current)
|
||||
if(!silent)
|
||||
greet()
|
||||
apply_innate_effects()
|
||||
give_antag_moodies()
|
||||
remove_blacklisted_quirks()
|
||||
if(is_banned(owner.current) && replace_banned)
|
||||
replace_banned_player()
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
|
||||
if(!(owner?.current))
|
||||
return
|
||||
if(!silent)
|
||||
greet()
|
||||
apply_innate_effects()
|
||||
give_antag_moodies()
|
||||
remove_blacklisted_quirks()
|
||||
if(is_banned(owner.current) && replace_banned)
|
||||
replace_banned_player()
|
||||
if(skill_modifiers)
|
||||
for(var/A in skill_modifiers)
|
||||
ADD_SINGLETON_SKILL_MODIFIER(owner, A, type)
|
||||
SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src)
|
||||
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
if(!M)
|
||||
@@ -99,6 +105,8 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
clear_antag_moodies()
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
for(var/A in skill_modifiers)
|
||||
owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type))
|
||||
if(!silent && owner.current)
|
||||
farewell()
|
||||
var/datum/team/team = get_team()
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
landmark_type = /obj/effect/landmark/abductor/agent
|
||||
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
|
||||
show_in_antagpanel = TRUE
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
|
||||
|
||||
/datum/antagonist/abductor/scientist
|
||||
name = "Abductor Scientist"
|
||||
@@ -29,6 +30,7 @@
|
||||
landmark_type = /obj/effect/landmark/abductor/scientist
|
||||
greet_text = "Use your experimental console and surgical equipment to monitor your agent and experiment upon abducted humans."
|
||||
show_in_antagpanel = TRUE
|
||||
skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery)
|
||||
|
||||
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
|
||||
if(!new_team)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
antagpanel_category = "Clockcult"
|
||||
job_rank = ROLE_SERVANT_OF_RATVAR
|
||||
antag_moodlet = /datum/mood_event/cult
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
|
||||
var/datum/action/innate/hierophant/hierophant_network = new
|
||||
threat = 3
|
||||
var/datum/team/clockcult/clock_team
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
/datum/antagonist/ert/engineer
|
||||
role = "Engineer"
|
||||
outfit = /datum/outfit/ert/engineer
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
|
||||
|
||||
/datum/antagonist/ert/engineer/amber
|
||||
outfit = /datum/outfit/ert/engineer/alert
|
||||
@@ -61,6 +62,7 @@
|
||||
/datum/antagonist/ert/medic
|
||||
role = "Medical Officer"
|
||||
outfit = /datum/outfit/ert/medic
|
||||
skill_modifiers = list(/datum/skill_modifier/job/affinity/surgery)
|
||||
|
||||
/datum/antagonist/ert/medic/amber
|
||||
outfit = /datum/outfit/ert/medic/alert
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
job_rank = ROLE_OPERATIVE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
threat = 10
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
|
||||
var/datum/team/nuclear/nuke_team
|
||||
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
|
||||
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
antagpanel_category = "Traitor"
|
||||
job_rank = ROLE_TRAITOR
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring/basic)
|
||||
var/special_role = ROLE_TRAITOR
|
||||
var/employer = "The Syndicate"
|
||||
var/give_objectives = TRUE
|
||||
|
||||
@@ -51,6 +51,12 @@
|
||||
var/datum/brain_trauma/BT = X
|
||||
BT.owner = owner
|
||||
BT.on_gain()
|
||||
if(damage > BRAIN_DAMAGE_MILD)
|
||||
var/datum/skill_modifier/S
|
||||
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C, S)
|
||||
if(damage > BRAIN_DAMAGE_SEVERE)
|
||||
var/datum/skill_modifier/S
|
||||
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C, S)
|
||||
|
||||
//Update the body's icon so it doesnt appear debrained anymore
|
||||
C.update_hair()
|
||||
@@ -66,6 +72,8 @@
|
||||
if((!QDELETED(src) || C) && !no_id_transfer)
|
||||
transfer_identity(C)
|
||||
if(C)
|
||||
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, C)
|
||||
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, C)
|
||||
C.update_hair()
|
||||
|
||||
/obj/item/organ/brain/prepare_eat()
|
||||
@@ -219,31 +227,6 @@
|
||||
Insert(C)
|
||||
else
|
||||
..()
|
||||
/* TO BE REMOVED, KEPT IN CASE OF BUGS
|
||||
/obj/item/organ/brain/proc/get_brain_damage()
|
||||
var/brain_damage_threshold = max_integrity * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER
|
||||
var/offset_integrity = obj_integrity - (max_integrity - brain_damage_threshold)
|
||||
. = round((1 - (offset_integrity / brain_damage_threshold)) * BRAIN_DAMAGE_DEATH, DAMAGE_PRECISION)
|
||||
|
||||
/obj/item/organ/brain/proc/adjust_brain_damage(amount, maximum)
|
||||
var/adjusted_amount
|
||||
if(amount >= 0 && maximum)
|
||||
var/brainloss = get_brain_damage()
|
||||
var/new_brainloss = clamp(brainloss + amount, 0, maximum)
|
||||
if(brainloss > new_brainloss) //brainloss is over the cap already
|
||||
return 0
|
||||
adjusted_amount = new_brainloss - brainloss
|
||||
else
|
||||
adjusted_amount = amount
|
||||
|
||||
adjusted_amount = round(adjusted_amount * BRAIN_DAMAGE_INTEGRITY_MULTIPLIER, DAMAGE_PRECISION)
|
||||
if(adjusted_amount)
|
||||
if(adjusted_amount >= DAMAGE_PRECISION)
|
||||
take_damage(adjusted_amount)
|
||||
else if(adjusted_amount <= -DAMAGE_PRECISION)
|
||||
obj_integrity = min(max_integrity, obj_integrity-adjusted_amount)
|
||||
. = adjusted_amount
|
||||
*/
|
||||
|
||||
/obj/item/organ/brain/applyOrganDamage(var/d, var/maximum = maxHealth)
|
||||
. = ..()
|
||||
@@ -261,18 +244,28 @@
|
||||
. = ..()
|
||||
//if we're not more injured than before, return without gambling for a trauma
|
||||
if(damage <= prev_damage)
|
||||
if(damage < prev_damage && owner)
|
||||
if(prev_damage > BRAIN_DAMAGE_MILD && damage <= BRAIN_DAMAGE_MILD)
|
||||
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner)
|
||||
if(prev_damage > BRAIN_DAMAGE_SEVERE && damage <= BRAIN_DAMAGE_SEVERE)
|
||||
REMOVE_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner)
|
||||
return
|
||||
damage_delta = damage - prev_damage
|
||||
if(damage > BRAIN_DAMAGE_MILD)
|
||||
if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_MILD)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% //learn how to do your bloody math properly goddamnit
|
||||
gain_trauma_type(BRAIN_TRAUMA_MILD)
|
||||
if(prev_damage <= BRAIN_DAMAGE_MILD && owner)
|
||||
var/datum/skill_modifier/S
|
||||
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/brain_damage, null, owner, S)
|
||||
if(damage > BRAIN_DAMAGE_SEVERE)
|
||||
if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_SEVERE)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1%
|
||||
if(prob(20))
|
||||
gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
|
||||
else
|
||||
gain_trauma_type(BRAIN_TRAUMA_SEVERE)
|
||||
|
||||
if(prev_damage <= BRAIN_DAMAGE_SEVERE && owner)
|
||||
var/datum/skill_modifier/S
|
||||
ADD_SKILL_MODIFIER_BODY(/datum/skill_modifier/heavy_brain_damage, null, owner, S)
|
||||
if (owner)
|
||||
if(owner.stat < UNCONSCIOUS) //conscious or soft-crit
|
||||
var/brain_message
|
||||
|
||||
@@ -57,10 +57,11 @@
|
||||
surgery.step_in_progress = FALSE
|
||||
return FALSE
|
||||
if(tool)
|
||||
speed_mod = tool.toolspeed
|
||||
speed_mod = tool.toolspeed //faster tools mean faster surgeries, but also less experience.
|
||||
if(user.mind)
|
||||
speed_mod = user.mind.action_skill_mod(/datum/skill/numerical/surgery, speed_mod, THRESHOLD_COMPETENT, FALSE)
|
||||
if(do_after(user, time * speed_mod, target = target))
|
||||
speed_mod = user.mind.action_skill_mod(/datum/skill/numerical/surgery, speed_mod, THRESHOLD_UNTRAINED, FALSE)
|
||||
var/delay = time * speed_mod
|
||||
if(do_after(user, delay, 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]
|
||||
@@ -68,7 +69,10 @@
|
||||
|
||||
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?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP)
|
||||
var/multi = (delay/SKILL_GAIN_DELAY_DIVISOR)
|
||||
if(repeatable)
|
||||
multi *= 0.5 //Spammable surgeries award less experience.
|
||||
user.mind?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP * multi)
|
||||
advance = TRUE
|
||||
else
|
||||
if(failure(user, target, target_zone, tool, surgery))
|
||||
|
||||
@@ -595,6 +595,7 @@
|
||||
#include "code\datums\skills\medical.dm"
|
||||
#include "code\datums\skills\modifiers\job.dm"
|
||||
#include "code\datums\skills\modifiers\mood.dm"
|
||||
#include "code\datums\skills\modifiers\organs.dm"
|
||||
#include "code\datums\status_effects\buffs.dm"
|
||||
#include "code\datums\status_effects\debuffs.dm"
|
||||
#include "code\datums\status_effects\gas.dm"
|
||||
|
||||
Reference in New Issue
Block a user