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