Macros, generic skill implementations.

This commit is contained in:
Ghommie
2020-05-05 04:42:34 +02:00
parent 87389243e6
commit 643ef48f0e
64 changed files with 358 additions and 178 deletions
+46 -23
View File
@@ -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, "<span class='nicegreen'>I feel like I've become more proficient at [name]!</span>")
else if(. < 0)
to_chat(M.current, "<span class='warning'>I feel like I've become worse at [name]!</span>")
/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"
+30 -7
View File
@@ -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.
+2 -1
View File
@@ -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)
+1
View File
@@ -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.