Files
GS13NG/code/datums/skills/_skill_holder.dm
T

172 lines
6.4 KiB
Plaintext

/**
* 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.
*/
/datum/skill_holder/proc/get_skill_value(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(!skills)
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, /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]
/**
* Grabs our affinity for a skill. !!This is a multiplier!!
*/
/datum/skill_holder/proc/get_skill_affinity(skill)
. = 1
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))
. = affinity
var/list/wrapped = list(.)
SEND_SIGNAL(owner.current, COMSIG_MOB_SKILL_GET_AFFINITY, skill, wrapped)
. = wrapped[1]
/**
* Sets the value of a skill.
*/
/datum/skill_holder/proc/set_skill_value(skill, value, silent = FALSE)
if(!ispath(skill, /datum/skill))
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))
LAZYINITLIST(skills)
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, silent = FALSE)
var/current = get_skill_value(skill)
if(!is_skill_value_greater(skill, current, value))
return FALSE
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, maximum, silent = FALSE)
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)
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)
/**
* Generic value modifier proc that uses one skill.
* Args:
* * value : the value to modify, may be a delay, damage, probability.
* * threshold : The difficulty of the action, in short. Refer to __DEFINES/skills/defines.dm for the defines.
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
/datum/skill_holder/proc/action_skills_mod(skill, value, threshold, modifier_is_multiplier = TRUE)
var/mod
var/datum/skill/S = GLOB.skill_datums[skill]
if(!S)
return
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
mod = LAZYACCESS(skill_levels, S.type)
else
mod = LAZYACCESS(skills, S.type)
mod = (1+(mod-S.competency_thresholds[threshold])*S.competency_mults[threshold])
var/list/comsig_values = list(mod)
SEND_SIGNAL(owner.current, COMSIG_MOB_ACTION_SKILL_MOD, args, comsig_values)
mod = comsig_values[MOD_VALUES_SKILL_MOD]
. = modifier_is_multiplier ? value*mod : value/mod
/**
* Generic value modifier proc that uses several skills, intended for items.
* 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
* * the value.
* * bad_flags : the opposite of the above, skills that must not be present to impact the value.
* * modifier_is_multiplier : wheter the modifier is a multiplier or a divisor.
*/
/datum/skill_holder/proc/item_action_skills_mod(obj/item/I, value, flags = NONE, bad_flags = NONE, modifier_is_multiplier = TRUE)
. = value
var/sum = 0
var/divisor = 0
var/list/checked_skills
for(var/k in I.used_skills)
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))
continue
var/mod
switch(S.progression_type)
if(SKILL_PROGRESSION_LEVEL)
mod = LAZYACCESS(skill_levels, S.type)
else
mod = LAZYACCESS(skills, S.type)
sum += 1+(mod - S.competency_thresholds[I.skill_difficulty])*S.competency_mults[I.skill_difficulty]
LAZYADD(checked_skills, S)
var/list/comsig_values = list(sum, divisor, checked_skills)
SEND_SIGNAL(owner.current, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD, args, comsig_values)
sum = comsig_values[MOD_VALUES_ITEM_SKILLS_SUM]
divisor = comsig_values[MOD_VALUES_ITEM_SKILLS_DIV]
if(divisor)
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
/**
* Generates a HTML readout of our skills.
* Port to tgui-next when?
*/
/datum/skill_holder/proc/html_readout()
var/list/out = list("<center><h1>Skills</h1></center><hr>")
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
for(var/path in skills)
var/datum/skill/S = GLOB.skill_datums[path]
out += "<tr><td><font color='[S.name_color]'>[S.name]</font></td><td>[S.standard_render_value(skills[path], LAZYACCESS(skill_levels, path) || 0)]</td></tr>"
out += "</table>"
return out.Join("")