diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index c74a8cdb05..8706e96562 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -185,27 +185,6 @@ #define COMSIG_MOB_SPELL_CAN_CAST "mob_spell_can_cast" //from base of /obj/effect/proc_holder/spell/can_cast(): (spell) -#define COMSIG_MOB_ACTION_SKILL_MOD "mob_action_skill_mod" //from base of /datum/skill_holder/action_skills_mod() : (proc args list, list/mod_values) - #define ACTION_SKILL_MOD_SKILL 1 //redundancy. - #define ACTION_SKILL_MOD_VALUE 2 - #define ACTION_SKILL_MOD_THRESHOLD 3 - #define ACTION_SKILL_MOD_IS_MULTI 4 - //other mod values, kept separate from the args - #define MOD_VALUES_SKILL_MOD 1 - -#define COMSIG_MOB_ITEM_ACTION_SKILLS_MOD "mob_item_action_skills_mod" //from base of /datum/skill_holder/item_action_skills_mod() : (proc args list, mod_values) - #define ITEM_SKILLS_MOD_ITEM 1 //redundancy - #define ITEM_SKILLS_MOD_VALUE 2 - #define ITEM_SKILLS_MOD_FLAGS 3 - #define ITEM_SKILLS_MOD_BAD_FLAGS 4 - #define ITEM_SKILLS_MOD_IS_MULTI 5 - //other mod values, kept separate from the args - #define MOD_VALUES_ITEM_SKILLS_SUM 1 - #define MOD_VALUES_ITEM_SKILLS_DIV 2 - #define MOD_VALUES_ITEM_SKILLS_CHECKED 3 - -#define COMSIG_MOB_SKILL_GET_AFFINITY "mob_skill_get_affinity" //from base of /datum/skill_holder/get_skill_affinity(): (skill_path, list/return_value) - // /mob/living signals #define COMSIG_LIVING_REGENERATE_LIMBS "living_regenerate_limbs" //from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs) #define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living) diff --git a/code/__DEFINES/skills/defines.dm b/code/__DEFINES/skills/defines.dm index 73be86e128..9127b4e3dd 100644 --- a/code/__DEFINES/skills/defines.dm +++ b/code/__DEFINES/skills/defines.dm @@ -20,9 +20,7 @@ // Standard values for job starting skill affinities -#define STARTING_SKILL_AFFINITY_SURGERY_MEDICAL 1.2 - -#define STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO 1.2 +#define STARTING_SKILL_AFFINITY_DEF_JOB 1.2 // Standard values for skill gain (this is multiplied by affinity) @@ -75,3 +73,26 @@ #define DORF_SKILL_COMPETENT 3 #define DORF_SKILL_EXPERT 8 #define DORF_SKILL_MASTER 12 + +/// Skill modifier defines and flags. +#define MODIFIER_SKILL_VALUE (1<<0) +#define MODIFIER_SKILL_AFFINITY (1<<1) +#define MODIFIER_SKILL_LEVEL (1<<2) +///makes the skill modifier a multiplier, not an addendum. +#define MODIFIER_SKILL_MULT (1<<3) +///Sets the skill to the defined value if lower than that. Highly reccomended you don't use it with MODIFIER_SKILL_MULT. +#define MODIFIER_SKILL_VIRTUE (1<<4) +///Does the opposite of the above. combining both effectively results in the skill being locked to the specified value. +#define MODIFIER_SKILL_HANDICAP (1<<5) +///Makes it untransferred by mind.transfer_to() +#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) + +#define MODIFIER_TARGET_VALUE "value" +#define MODIFIER_TARGET_LEVEL "level" +#define MODIFIER_TARGET_AFFINITY "affinity" + +///Ascending priority defines. +#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 diff --git a/code/__DEFINES/skills/helpers.dm b/code/__DEFINES/skills/helpers.dm index 23669b3739..1a39dbd9e0 100644 --- a/code/__DEFINES/skills/helpers.dm +++ b/code/__DEFINES/skills/helpers.dm @@ -6,3 +6,25 @@ //More experience value getter macros #define GET_STANDARD_LVL(lvl) XP_LEVEL(STD_XP_LVL_UP, STD_XP_LVL_MULTI, lvl) #define GET_DORF_LVL(lvl) DORF_XP_LEVEL(DORF_XP_LVL_UP, DORF_XP_LVL_MULTI, lvl) + +#define IS_SKILL_VALUE_GREATER(path, existing, new_value) GLOB.skill_datums[path].is_value_greater(existing, new_value) + +#define SANITIZE_SKILL_VALUE(path, value) GLOB.skill_datums[path].sanitize_value(value) + +///Doesn't automatically round the value. +#define SANITIZE_SKILL_LEVEL(path, lvl) clamp(lvl, 0, GLOB.skill_datums[path].max_levels) + +/** + * A simple universal comsig for body bound skill modifiers. + * Technically they are still bound to the mind, but other signal procs will take care of adding and removing the modifier + * from/to new/old minds. + */ +#define ADD_SKILL_MODIFIER_BODY(mod, body) \ + mod.RegisterSignal(body, COMSIG_MOB_ON_NEW_MIND, /datum/skill_modifier.proc/on_mob_new_mind, TRUE) + +///Macro used when adding generic singleton skill modifiers. +#define ADD_SINGLETON_SKILL_MODIFIER(mind, path, id) \ + if(!GLOB.skill_modifiers[id]){\ + new path(id)\ + };\ + mind.add_skill_modifier(id ? "[path]&[id]" : path) \ No newline at end of file diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index ad977ec493..38c2439019 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -37,6 +37,7 @@ * TYPECONT: The typepath of the contents of the list * COMPARE: The object to compare against, usualy the same as INPUT * COMPARISON: The variable on the objects to compare + * COMPTYPE: How the current bin item to compare against COMPARE is fetched. By key or value. */ #define BINARY_INSERT(INPUT, LIST, TYPECONT, COMPARE, COMPARISON, COMPTYPE) \ do {\ diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index f0b38f994d..ccbfab6b43 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -118,11 +118,11 @@ bad_flag |= SKILL_COMBAT_MODE //blacklist combat skills. if(I.used_skills && user.mind) if(totitemdamage) - totitemdamage = user.mind.skill_holder.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_flag) for(var/skill in I.used_skills) if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_OBJ)) continue - user.mind.skill_holder.auto_gain_experience(skill, I.skill_gain) + user.mind.auto_gain_experience(skill, I.skill_gain) if(totitemdamage) visible_message("[user] has hit [src] with [I]!", null, null, COMBAT_MESSAGE_RANGE) //only witnesses close by and the victim see a hit message. @@ -163,11 +163,11 @@ if(!user.mind || !I.used_skills) return if(.) - . = user.mind.skill_holder.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_flag) for(var/skill in I.used_skills) if(!(I.used_skills[skill] & SKILL_TRAIN_ATTACK_MOB)) continue - user.mind.skill_holder.auto_gain_experience(skill, I.skill_gain) + user.mind.auto_gain_experience(skill, I.skill_gain) /mob/living/carbon/pre_attacked_by(obj/item/I, mob/living/user) . = ..() @@ -216,7 +216,7 @@ . *= STAM_COST_NO_COMBAT_MULT bad_flag |= SKILL_COMBAT_MODE if(used_skills && user.mind) - . = user.mind.skill_holder.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE) + . = user.mind.item_action_skills_mod(src, ., skill_difficulty, flags, bad_flag, FALSE) /// How long this staggers for. 0 and negatives supported. /obj/item/proc/melee_stagger_duration(force_override) diff --git a/code/controllers/subsystem/moods.dm b/code/controllers/subsystem/moods.dm deleted file mode 100644 index f6b6ffcb40..0000000000 --- a/code/controllers/subsystem/moods.dm +++ /dev/null @@ -1,4 +0,0 @@ -PROCESSING_SUBSYSTEM_DEF(mood) - name = "Mood" - flags = SS_NO_INIT | SS_BACKGROUND - priority = 20 diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index 23a81716b8..6ce7842273 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -1,3 +1,4 @@ +#define ECSTATIC_SANITY_PEN -1 #define SLIGHT_INSANITY_PEN 1 #define MINOR_INSANITY_PEN 5 #define MAJOR_INSANITY_PEN 10 @@ -13,29 +14,39 @@ var/list/datum/mood_event/mood_events = list() var/insanity_effect = 0 //is the owner being punished for low mood? If so, how much? var/obj/screen/mood/screen_obj + var/datum/skill_modifier/bad_mood/malus + var/datum/skill_modifier/great_mood/bonus + var/static/malus_id = 0 + var/static/bonus_id = 0 /datum/component/mood/Initialize() if(!isliving(parent)) return COMPONENT_INCOMPATIBLE - START_PROCESSING(SSmood, src) + var/mob/living/owner = parent + if(owner.stat != DEAD) + START_PROCESSING(SSdcs, src) RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event) RegisterSignal(parent, COMSIG_CLEAR_MOOD_EVENT, .proc/clear_event) RegisterSignal(parent, COMSIG_MODIFY_SANITY, .proc/modify_sanity) RegisterSignal(parent, COMSIG_LIVING_REVIVE, .proc/on_revive) RegisterSignal(parent, COMSIG_MOB_HUD_CREATED, .proc/modify_hud) - var/mob/living/owner = parent + RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/stop_processing) + if(owner.hud_used) modify_hud() var/datum/hud/hud = owner.hud_used hud.show_hud(hud.hud_version) /datum/component/mood/Destroy() - STOP_PROCESSING(SSmood, src) + STOP_PROCESSING(SSdcs, src) unmodify_hud() return ..() +/datum/component/mood/proc/stop_processing() + STOP_PROCESSING(SSdcs, src) + /datum/component/mood/proc/print_mood(mob/user) var/msg = "*---------*\nYour current mood\n" msg += "My mental status: " //Long term @@ -127,7 +138,7 @@ else screen_obj.icon_state = "mood[mood_level]" -/datum/component/mood/process() //Called on SSmood process +/datum/component/mood/process() //Called on SSdcs process if(QDELETED(parent)) // workaround to an obnoxious sneaky periodical runtime. qdel(src) return @@ -167,7 +178,6 @@ else if(sanity > maximum && amount > sanity - 0.5) amount = sanity - 0.5 - var/old_sanity = sanity // Disturbed stops you from getting any more sane if(HAS_TRAIT(master, TRAIT_UNSTABLE)) sanity = min(amount,sanity) @@ -196,27 +206,41 @@ master.remove_movespeed_modifier(MOVESPEED_ID_SANITY) sanity_level = 2 if(SANITY_GREAT+1 to INFINITY) - setInsanityEffect(0) + setInsanityEffect(ECSTATIC_SANITY_PEN) //It's not a penalty but w/e master.remove_movespeed_modifier(MOVESPEED_ID_SANITY) sanity_level = 1 - if(old_sanity > 1 && sanity == 1) - RegisterSignal(master, COMSIG_MOB_SKILL_GET_AFFINITY, .proc/on_get_skill_affinity) - else if(old_sanity == 1 && sanity > 1) - UnregisterSignal(master, COMSIG_MOB_SKILL_GET_AFFINITY) - //update_mood_icon() /datum/component/mood/proc/setInsanityEffect(newval)//More code so that the previous proc works if(newval == insanity_effect) return - //var/mob/living/master = parent - //master.crit_threshold = (master.crit_threshold - insanity_effect) + newval - if(!insanity_effect && newval) - RegisterSignal(parent, COMSIG_MOB_ACTION_SKILL_MOD, .proc/on_mob_action_skill_mod) - RegisterSignal(parent, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD, .proc/on_item_action_skills_mod) - else if(insanity_effect && !newval) - UnregisterSignal(parent, list(COMSIG_MOB_ACTION_SKILL_MOD, COMSIG_MOB_ITEM_ACTION_SKILLS_MOD)) + + var/mob/living/L = parent + var/apply_malus = newval >= SLIGHT_INSANITY_PEN + var/apply_bonus = !apply_malus && newval <= ECSTATIC_SANITY_PEN + if(apply_malus) + if(!malus) + malus = new(malus_id++) + var/debuff = 1 - (SANITY_DISTURBED - sanity) * MOOD_INSANITY_MALUS + malus.value_mod = malus.level_mod = debuff + if(!L.mind) + ADD_SKILL_MODIFIER_BODY(malus, L) + else + L.mind.add_skill_modifier(malus.identifier) + else if(malus) + QDEL_NULL(malus) + + if(apply_bonus) + if(!bonus) + bonus = new(bonus_id++) + if(!L.mind) + ADD_SKILL_MODIFIER_BODY(bonus, L) + else + L.mind.add_skill_modifier(bonus.identifier) + else if(bonus) + QDEL_NULL(bonus) + insanity_effect = newval /datum/component/mood/proc/modify_sanity(datum/source, amount, minimum = SANITY_INSANE, maximum = SANITY_AMAZING) @@ -294,46 +318,15 @@ if(0 to NUTRITION_LEVEL_STARVING) add_event(null, "nutrition", /datum/mood_event/starving) -///Called when parent is ahealed. +///Called when parent is revived. /datum/component/mood/proc/on_revive(datum/source, full_heal) + START_PROCESSING(SSdcs, src) if(!full_heal) return remove_temp_moods() setSanity(initial(sanity)) -/datum/component/mood/proc/on_mob_action_skill_mod(mob/source, list/skill_args, list/mod_values) - var/datum/skill/S = GLOB.skill_datums[skill_args[ACTION_SKILL_MOD_SKILL]] - if(!(S.skill_flags & SKILL_USE_MOOD)) - return - var/debuff = 1 - (SANITY_DISTURBED - sanity) * MOOD_INSANITY_MALUS - mod_values[MOD_VALUES_SKILL_MOD] *= skill_args[ACTION_SKILL_MOD_IS_MULTI] ? debuff : 1/debuff - -/datum/component/mood/proc/on_item_action_skills_mod(mob/source, list/skill_args, list/mod_values) - if(skill_args[ITEM_SKILLS_MOD_BAD_FLAGS] & SKILL_USE_MOOD) - return - var/divisor = mod_values[MOD_VALUES_ITEM_SKILLS_DIV] - if(!divisor) - return - var/obj/item/I = skill_args[ITEM_SKILLS_MOD_ITEM] - var/list/L = mod_values[MOD_VALUES_ITEM_SKILLS_CHECKED] - var/skills_len = length(L) - var/affected_skills = skills_len - for(var/k in L) - var/datum/skill/S = k - var/our_flags = I.used_skills[S.type]|S.skill_flags - if(!(our_flags & SKILL_USE_MOOD)) - affected_skills-- - if(!affected_skills) - return - var/debuff = 1 - (SANITY_DISTURBED - sanity) * MOOD_INSANITY_MALUS * (affected_skills/skills_len) - mod_values[MOD_VALUES_ITEM_SKILLS_SUM] *= skill_args[ITEM_SKILLS_MOD_IS_MULTI] ? debuff : 1/debuff - -/datum/component/mood/proc/on_get_skill_affinity(mob/source, skill_path, list/return_value) - var/datum/skill/S = GLOB.skill_datums[skill_path] - if(!S || !(S.skill_flags & SKILL_TRAIN_MOOD)) - return - return_value[1] *= SKILL_AFFINITY_MOOD_BONUS - +#undef ECSTATIC_SANITY_PEN #undef SLIGHT_INSANITY_PEN #undef MINOR_INSANITY_PEN #undef MAJOR_INSANITY_PEN diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 54fcbbc6aa..ee8762e9da 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -67,7 +67,7 @@ var/datum/skill_holder/skill_holder /datum/mind/New(var/key) - skill_holder = new(src) + skill_holder = new() src.key = key soulOwner = src martial_art = default_martial_art diff --git a/code/datums/skills/_check_skills.dm b/code/datums/skills/_check_skills.dm index d9dc6dad3d..a94c7c95ba 100644 --- a/code/datums/skills/_check_skills.dm +++ b/code/datums/skills/_check_skills.dm @@ -12,5 +12,5 @@ to_chat(usr, "How do you check the skills of [(usr == src)? "yourself when you are" : "something"] without the capability for skills? (PROBABLY A BUG, PRESS F1.)") return var/datum/browser/B = new(usr, "skilldisplay_[REF(src)]", "Skills of [src]") - B.set_content(mind.skill_holder.html_readout()) + B.set_content(mind.skill_html_readout()) B.open() diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm index f52945536f..04ed7bdc59 100644 --- a/code/datums/skills/_skill.dm +++ b/code/datums/skills/_skill.dm @@ -9,19 +9,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) S = new path .[S.type] = S -/proc/sanitize_skill_value(path, value) - 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 = GLOB.skill_datums[path] - // don't check, if we runtime let it happen. - return S.is_value_greater(existing, new_value) - /** * Skill datums */ + /datum/skill /// Our name var/name @@ -33,11 +24,13 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) var/progression_type /// Abstract type var/abstract_type = /datum/skill - /// skill threshold used in generic skill modifiers calculations. + /// 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. + /// In which way this skil can affect or be affected through actions and skill modifiers. var/skill_flags = SKILL_USE_MOOD|SKILL_TRAIN_MOOD /** @@ -114,9 +107,9 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) /datum/skill/level abstract_type = /datum/skill/level progression_type = SKILL_PROGRESSION_LEVEL + max_levels = STD_MAX_LVL var/standard_xp_lvl_up = STD_XP_LVL_UP //the standard required to level up. def: 100 var/xp_lvl_multiplier = STD_XP_LVL_MULTI //standard required level up exp multiplier. def: 2 (100, 200, 400, 800 etc.) - 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. @@ -182,7 +175,6 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums()) if(next_lvl_xp > current_lvl_xp_sum) next_lvl_xp -= current_lvl_xp_sum - return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp])[level == max_levels ? " \[MAX!\]" : ""]" /datum/skill/level/job diff --git a/code/datums/skills/_skill_holder.dm b/code/datums/skills/_skill_holder.dm index e252b4c9c6..0ce2c2b9db 100644 --- a/code/datums/skills/_skill_holder.dm +++ b/code/datums/skills/_skill_holder.dm @@ -1,8 +1,8 @@ /** * Skill holder datums + * All procs are tied to the mind, since they are always expected to have a skill holder anyway. */ /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. @@ -10,66 +10,87 @@ /// 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 + /// current skill modifiers lists, per value, affinity, level. + var/list/skill_value_mods + var/list/skill_affinity_mods + var/list/skill_level_mods + /// List of all current skill modifiers, so we don't add the same ones twice. + var/list/all_current_skill_modifiers + /// List of original values stored at the time a modifier with the MODIFIER_SKILL_ORIGIN_DIFF enabled was added. + var/list/original_values + var/list/original_affinities + var/list/original_levels /** * Grabs the value of a skill. */ -/datum/skill_holder/proc/get_skill_value(skill) +/datum/mind/proc/get_skill_value(skill, apply_modifiers = TRUE) 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) + if(!(skill_holder?.skills)) return null - return skills[skill] + else + . = skill_holder.skills[skill] + if(apply_modifiers && skill_holder.skill_value_mods) + var/L = LAZYACCESS(skill_holder.skill_value_mods, skill) + for(var/k in L) + var/datum/skill_modifier/M = GLOB.skill_modifiers[k] + . = M.apply_modifier(., skill, skill_holder, MODIFIER_TARGET_VALUE) /** * Grabs the level of a skill. Only supported by skills with tiers or levels. */ -/datum/skill_holder/proc/get_skill_level(skill) +/datum/mind/proc/get_skill_level(skill, apply_modifiers = TRUE, round = FALSE) 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] + if(!skill_holder.skill_levels) + . = 0 + else + . = skill_holder.skill_levels[skill] || 0 + if(apply_modifiers && skill_holder.skill_level_mods) + var/L = LAZYACCESS(skill_holder.skill_level_mods, skill) + for(var/k in L) + var/datum/skill_modifier/M = GLOB.skill_modifiers[k] + . = M.apply_modifier(., skill, skill_holder, MODIFIER_TARGET_LEVEL) + . = SANITIZE_SKILL_LEVEL(skill, round ? round(.) : .) /** * Grabs our affinity for a skill. !!This is a multiplier!! */ -/datum/skill_holder/proc/get_skill_affinity(skill) +/datum/mind/proc/get_skill_affinity(skill, apply_modifiers = TRUE) . = 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) + var/affinity = LAZYACCESS(skill_holder.skill_affinities, skill) if(!isnull(affinity)) . = affinity - var/list/wrapped = list(.) - SEND_SIGNAL(owner.current, COMSIG_MOB_SKILL_GET_AFFINITY, skill, wrapped) - . = wrapped[1] + if(apply_modifiers && skill_holder.skill_affinity_mods) + var/L = LAZYACCESS(skill_holder.skill_affinity_mods, skill) + for(var/k in L) + var/datum/skill_modifier/M = GLOB.skill_modifiers[k] + . = M.apply_modifier(., skill, skill_holder, MODIFIER_TARGET_AFFINITY) /** * Sets the value of a skill. */ -/datum/skill_holder/proc/set_skill_value(skill, value, silent = FALSE) +/datum/mind/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) + LAZYINITLIST(skill_holder.skills) + S.set_skill_value(skill_holder, value, src, 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)) +/datum/mind/proc/boost_skill_value_to(skill, value, silent = FALSE, current) + current = current || get_skill_value(skill, FALSE) + if(!IS_SKILL_VALUE_GREATER(skill, current, value)) return FALSE set_skill_value(skill, value, silent) return TRUE @@ -78,20 +99,20 @@ * 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) +/datum/mind/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/current = get_skill_value(skill, FALSE) 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) + boost_skill_value_to(skill, target_value, silent, current) /** * Generic value modifier proc that uses one skill. @@ -100,22 +121,17 @@ * * 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) +/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 switch(S.progression_type) if(SKILL_PROGRESSION_LEVEL) - mod = LAZYACCESS(skill_levels, S.type) + mod = get_skill_level(S.type) else - mod = LAZYACCESS(skills, S.type) + mod = get_skill_value(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 /** @@ -128,11 +144,10 @@ * * 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) +/datum/mind/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) @@ -143,17 +158,10 @@ var/mod switch(S.progression_type) if(SKILL_PROGRESSION_LEVEL) - mod = LAZYACCESS(skill_levels, S.type) + mod = get_skill_level(S.type) else - mod = LAZYACCESS(skills, S.type) + mod = get_skill_value(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) @@ -161,11 +169,13 @@ * Generates a HTML readout of our skills. * Port to tgui-next when? */ -/datum/skill_holder/proc/html_readout() +/datum/mind/proc/skill_html_readout() var/list/out = list("

Skills


") out += "" - for(var/path in skills) + for(var/path in skill_holder.skills) var/datum/skill/S = GLOB.skill_datums[path] - out += "" + var/skill_value = get_skill_value(path) + var/skill_level = get_skill_level(path, round = TRUE) + out += "" out += "
SkillValue
[S.name][S.standard_render_value(skills[path], LAZYACCESS(skill_levels, path) || 0)]
[S.name][S.standard_render_value(skill_value, skill_level)]
" return out.Join("") diff --git a/code/datums/skills/_skill_modifier.dm b/code/datums/skills/_skill_modifier.dm new file mode 100644 index 0000000000..b6ad27c070 --- /dev/null +++ b/code/datums/skills/_skill_modifier.dm @@ -0,0 +1,176 @@ +GLOBAL_LIST_EMPTY_TYPED(skill_modifiers, /datum/skill_modifier) +GLOBAL_LIST_EMPTY(potential_skills_per_mod) +GLOBAL_LIST_EMPTY(potential_mods_per_skill) + +/** + * Base skill modifier datum, used to modify a player skills without directly touching their values, levels and affinity + * and cause lots of edge cases. These are fairly simple overall... make a subtype though, don't use this one. + */ +/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 = ALL + /// 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. + var/affinity_mod = 1 + /// skill value modifier, see above. + var/value_mod = 1 + /// skill level modifier, see above. + var/level_mod = 1 + /// Priority of this skill modifier compared to other ones. + var/priority = MODIFIER_SKILL_PRIORITY_DEF + +/datum/skill_modifier/New(id) + identifier = type + if(id) + identifier = "[type]&[id]" + var/dupe = 0 + while(GLOB.skill_modifiers[identifier]) + identifier = "[type]&[id][++dupe]" + GLOB.skill_modifiers[identifier] = src + + if(ispath(target_skills)) + var/list/mod_L = GLOB.potential_mods_per_skill[target_skills] + if(!mod_L) + GLOB.potential_mods_per_skill[target_skills] = list(identifier = src) + 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]"] + if(!L) + L = list() + for(var/path in GLOB.skill_datums) + if(GLOB.skill_datums[path].skill_flags & target_skills) + L += path + GLOB.potential_skills_per_mod["[target_skills]"] = L + for(var/path in L) + var/list/mod_L = GLOB.potential_mods_per_skill[path] + if(!mod_L) + GLOB.potential_mods_per_skill[path] = list(identifier = src) + else + BINARY_INSERT(identifier, mod_L, datum/skill_modifier, src, priority, COMPARE_VALUE) + mod_L[identifier] = src + +/datum/skill_modifier/Destroy() + for(var/A in GLOB.potential_skills_per_mod["[target_skills]"]) + LAZYREMOVEASSOC(GLOB.potential_mods_per_skill, A, identifier) + GLOB.potential_skills_per_mod -= "[target_skills]" + GLOB.skill_modifiers -= src + return ..() + +#define ADD_MOD_STEP(L, P, O, G) \ + var/__L = L[P];\ + if(!__L){\ + L[P] = list(id)\ + } else {\ + L[P] = GLOB.potential_mods_per_skill[P] & (__L + id)\ + }\ + if(M.modifier_flags & MODIFIER_SKILL_ORIGIN_DIFF){\ + LAZYADDASSOC(O, id, P = G)\ + } + +/datum/mind/proc/add_skill_modifier(id) + if(skill_holder.all_current_skill_modifiers[id]) + return + var/datum/skill_modifier/M = GLOB.skill_modifiers[id] + if(!M) + CRASH("Invalid add_skill_modifier id: [id].") + if(M.modifier_flags & MODIFIER_SKILL_BODYBOUND && !current) + CRASH("Body-bound skill modifier [M] was tried to be added to a mob-less mind.") + + if(M.modifier_flags & MODIFIER_SKILL_VALUE) + LAZYINITLIST(skill_holder.skill_value_mods) + if(M.modifier_flags & MODIFIER_SKILL_AFFINITY) + 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]"]) + 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) + ADD_MOD_STEP(skill_holder.skill_affinity_mods, path, skill_holder.original_affinities, get_skill_affinity(path, FALSE)) + if(M.modifier_flags & MODIFIER_SKILL_LEVEL) + ADD_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels, get_skill_level(path, FALSE)) + LAZYSET(skill_holder.all_current_skill_modifiers, id, TRUE) + + if(M.modifier_flags & MODIFIER_SKILL_BODYBOUND) + M.RegisterSignal(src, COMSIG_MIND_TRANSFER, /datum/skill_modifier.proc/on_mind_transfer) + ADD_SKILL_MODIFIER_BODY(M, current) + RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/on_skill_modifier_deletion) + +#undef ADD_MOD_STEP + +#define REMOVE_MOD_STEP(L, P, O)\ + LAZYREMOVEASSOC(L, P, id);\ + if(M.modifier_flags & MODIFIER_SKILL_ORIGIN_DIFF){\ + LAZYREMOVEASSOC(O, id, P)\ + } + +/datum/mind/proc/remove_skill_modifier(id, mind_transfer = FALSE) + if(!LAZYACCESS(skill_holder.all_current_skill_modifiers, id)) + return + var/datum/skill_modifier/M = GLOB.skill_modifiers[id] + if(!M) + CRASH("Invalid remove_skill_modifier id: [id].") + + 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]"]) + 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) + REMOVE_MOD_STEP(skill_holder.skill_affinity_mods, path, skill_holder.original_affinities) + if(M.modifier_flags & MODIFIER_SKILL_LEVEL) + REMOVE_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels) + LAZYREMOVE(skill_holder.all_current_skill_modifiers, id) + + if(!mind_transfer && M.modifier_flags & MODIFIER_SKILL_BODYBOUND) + M.UnregisterSignal(src, COMSIG_MIND_TRANSFER) + M.UnregisterSignal(current, list(COMSIG_MOB_ON_NEW_MIND)) + UnregisterSignal(M, COMSIG_PARENT_QDELETING) + +#undef REMOVE_MOD_STEP + +/datum/mind/proc/on_skill_modifier_deletion(datum/skill_modifier/source) + remove_skill_modifier(source.identifier) + +/datum/skill_modifier/proc/apply_modifier(value, skillpath, datum/skill_holder/H, method = MODIFIER_TARGET_VALUE) + . = value + var/mod = value_mod + switch(method) + if(MODIFIER_TARGET_LEVEL) + mod = level_mod + if(MODIFIER_TARGET_AFFINITY) + mod = affinity_mod + + if(modifier_flags & (MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_HANDICAP)) + if(modifier_flags & MODIFIER_SKILL_VIRTUE) + . = max(., mod) + if(modifier_flags & MODIFIER_SKILL_HANDICAP) + . = min(., mod) + else if(modifier_flags & MODIFIER_SKILL_MULT) + . *= mod + else + . += mod + + if(modifier_flags & MODIFIER_SKILL_ORIGIN_DIFF) + var/list/to_access = H.original_values + switch(method) + if(MODIFIER_TARGET_LEVEL) + to_access = H.original_levels + if(MODIFIER_TARGET_AFFINITY) + to_access = H.original_affinities + . += value - LAZYACCESS(to_access[identifier], skillpath) + +///Body bound modifier signal procs. +/datum/skill_modifier/proc/on_mind_transfer(datum/mind/source, mob/new_character, mob/old_character) + source.remove_skill_modifier(identifier, TRUE) + UnregisterSignal(source, COMSIG_MIND_TRANSFER) + +/datum/skill_modifier/proc/on_mob_new_mind(mob/source) + source.mind.add_skill_modifier(identifier) + RegisterSignal(source.mind, COMSIG_MIND_TRANSFER, /datum/skill_modifier.proc/on_mind_transfer) diff --git a/code/datums/skills/modifiers/job.dm b/code/datums/skills/modifiers/job.dm new file mode 100644 index 0000000000..45475fb9db --- /dev/null +++ b/code/datums/skills/modifiers/job.dm @@ -0,0 +1,34 @@ +/// Jobbie level skill modifiers. + +/datum/skill_modifier/job + modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_ORIGIN_DIFF + priority = MODIFIER_SKILL_PRIORITY_MAX + +/datum/skill_modifier/job + level_mod = JOB_SKILL_TRAINED + +/datum/skill_modifier/job/surgery + target_skills = /datum/skill/numerical/surgery + value_mod = STARTING_SKILL_SURGERY_MEDICAL + +/datum/skill_modifier/job/affinity + modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_VIRTUE + affinity_mod = STARTING_SKILL_AFFINITY_DEF_JOB + +/datum/skill_modifier/job/affinity/surgery + target_skills = /datum/skill/numerical/surgery + +/datum/skill_modifier/job/affinity/wiring + target_skills = /datum/skill/level/job/wiring + +/// Level skill modifiers below. +/datum/skill_modifier/job/level/New(id) + if(level_mod) + value_mod = GET_STANDARD_LVL(level_mod) + ..() + +/datum/skill_modifier/job/level/wiring + target_skills = /datum/skill/level/job/wiring + +/datum/skill_modifier/job/level/wiring/basic + level_mod = JOB_SKILL_BASIC diff --git a/code/datums/skills/modifiers/mood.dm b/code/datums/skills/modifiers/mood.dm new file mode 100644 index 0000000000..2ab74bdbbb --- /dev/null +++ b/code/datums/skills/modifiers/mood.dm @@ -0,0 +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 + +/datum/skill_modifier/great_mood + modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND + target_skills = SKILL_TRAIN_MOOD + affinity_mod = 1.2 diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index d2f719c50c..e020afa47a 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -138,7 +138,7 @@ if(current_users[user]) return FALSE if(req_skill && user?.mind) - var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) + var/level_diff = req_skill - user.mind.get_skill_level(/datum/skill/level/job/wiring) if(level_diff > 0) LAZYSET(current_users, user, TRUE) to_chat(user, "You begin cutting [holder]'s [color] wire...") @@ -167,7 +167,7 @@ if(current_users[user]) return FALSE if(req_skill && user?.mind) - var/level_diff = req_skill - user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) + var/level_diff = req_skill - user.mind.get_skill_level(/datum/skill/level/job/wiring) if(level_diff > 0) LAZYSET(current_users, user, TRUE) to_chat(user, "You begin pulsing [holder]'s [color] wire...") @@ -255,7 +255,7 @@ var/reveal_wires = FALSE // Admin ghost can see a purpose of each wire. - if(IsAdminGhost(user) || user.mind.skill_holder.get_skill_level(/datum/skill/level/job/wiring) >= req_knowledge) + if(IsAdminGhost(user) || user.mind.get_skill_level(/datum/skill/level/job/wiring) >= req_knowledge) reveal_wires = TRUE // Same for anyone with an abductor multitool. diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 949ed050f5..dde56e8278 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -802,7 +802,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(delay) if(user.mind && used_skills) - delay = user.mind.skill_holder.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, NONE, 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) @@ -832,7 +832,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) for(var/skill in used_skills) if(!(used_skills[skill] & SKILL_TRAINING_TOOL)) continue - user.mind.skill_holder.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) + user.mind.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level)) return TRUE diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 26736ddff1..df54df5c7d 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -1025,8 +1025,6 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null v = SSnpcpool if("SSmobs") v = SSmobs - if("SSmood") - v = SSmood if("SSquirks") v = SSquirks if("SSwet_floors") diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index e10f009cec..426e5136c9 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -66,10 +66,8 @@ // How much threat this job is worth in dynamic. Is subtracted if the player's not an antag, added if they are. var/threat = 0 - /// Starting skill levels. - var/list/starting_skills - /// Skill affinities to set - var/list/skill_affinities + /// Starting skill modifiers. + var/list/starting_modifiers //Only override this proc //H is usually a human unless an /equip override transformed it @@ -171,15 +169,10 @@ to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.") /datum/job/proc/standard_assign_skills(datum/mind/M) - if(!starting_skills) + if(!starting_modifiers) return - for(var/skill in starting_skills) - M.skill_holder.boost_skill_value_to(skill, starting_skills[skill], TRUE) //silent - // do wipe affinities though - M.skill_holder.skill_affinities = list() - for(var/skill in skill_affinities) - M.skill_holder.skill_affinities[skill] = skill_affinities[skill] - UNSETEMPTY(M.skill_holder.skill_affinities) //if we didn't set any. + for(var/mod in starting_modifiers) + ADD_SINGLETON_SKILL_MODIFIER(M, mod, null) /datum/outfit/job name = "Standard Gear" diff --git a/code/modules/jobs/job_types/ai.dm b/code/modules/jobs/job_types/ai.dm index 1395b90b39..a7401791ab 100644 --- a/code/modules/jobs/job_types/ai.dm +++ b/code/modules/jobs/job_types/ai.dm @@ -17,7 +17,7 @@ var/do_special_check = TRUE threat = 5 - starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC)) + starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic) /datum/job/ai/equip(mob/living/carbon/human/H, visualsOnly, announce, latejoin, datum/outfit/outfit_override, client/preference_source = null) if(visualsOnly) diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm index 42c6afaed8..fc104809c3 100644 --- a/code/modules/jobs/job_types/atmospheric_technician.dm +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -18,8 +18,7 @@ minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_EMERGENCY_STORAGE, ACCESS_CONSTRUCTION, ACCESS_MINERAL_STOREROOM) - starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC)) - skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) + starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic, /datum/skill_modifier/job/affinity/wiring) display_order = JOB_DISPLAY_ORDER_ATMOSPHERIC_TECHNICIAN threat = 0.5 diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm index 571785526b..f3144ff027 100644 --- a/code/modules/jobs/job_types/chemist.dm +++ b/code/modules/jobs/job_types/chemist.dm @@ -19,8 +19,7 @@ display_order = JOB_DISPLAY_ORDER_CHEMIST threat = 1.5 - starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL) - skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL) + starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery) /datum/outfit/job/chemist name = "Chemist" diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index bd4732f3c3..c40b3ab821 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -27,8 +27,7 @@ ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED)) - skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) + starting_modifiers = list(/datum/skill_modifier/job/level/wiring, /datum/skill_modifier/job/affinity/wiring) display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity) diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 478c33551d..2f115d0166 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -29,8 +29,7 @@ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity) threat = 2 - starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL) - skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL) + starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery) /datum/outfit/job/cmo name = "Chief Medical Officer" diff --git a/code/modules/jobs/job_types/cyborg.dm b/code/modules/jobs/job_types/cyborg.dm index d88d888aec..4f74542b2a 100644 --- a/code/modules/jobs/job_types/cyborg.dm +++ b/code/modules/jobs/job_types/cyborg.dm @@ -12,7 +12,7 @@ exp_requirements = 120 exp_type = EXP_TYPE_CREW - starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_BASIC)) + starting_modifiers = list(/datum/skill_modifier/job/level/wiring/basic) display_order = JOB_DISPLAY_ORDER_CYBORG diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm index 4fb989f6e8..f14032348b 100644 --- a/code/modules/jobs/job_types/geneticist.dm +++ b/code/modules/jobs/job_types/geneticist.dm @@ -19,7 +19,7 @@ display_order = JOB_DISPLAY_ORDER_GENETICIST threat = 1.5 - starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL) + starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery) /datum/outfit/job/geneticist name = "Geneticist" diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index 0e8b2e645b..d77a56d933 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -17,8 +17,7 @@ display_order = JOB_DISPLAY_ORDER_MEDICAL_DOCTOR threat = 0.5 - starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL) - skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL) + starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery) /datum/outfit/job/doctor name = "Medical Doctor" diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm index e8098daddc..e35fa34cb4 100644 --- a/code/modules/jobs/job_types/paramedic.dm +++ b/code/modules/jobs/job_types/paramedic.dm @@ -19,8 +19,7 @@ threat = 0.5 - starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL) - skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL) + starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery) /datum/outfit/job/paramedic name = "Paramedic" diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index d9e891f057..c6684bb7b1 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -16,9 +16,7 @@ access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS) minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM) - starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED)) - skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) - + starting_modifiers = list(/datum/skill_modifier/job/level/wiring, /datum/skill_modifier/job/affinity/wiring) display_order = JOB_DISPLAY_ORDER_ROBOTICIST threat = 1 diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm index c5280d72db..cc974b5086 100644 --- a/code/modules/jobs/job_types/station_engineer.dm +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -18,8 +18,7 @@ minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM) - starting_skills = list(/datum/skill/level/job/wiring = GET_STANDARD_LVL(JOB_SKILL_TRAINED)) - skill_affinities = list(/datum/skill/level/job/wiring = STARTING_SKILL_AFFINITY_WIRING_ENGI_ROBO) + starting_modifiers = list(/datum/skill_modifier/job/level/wiring, /datum/skill_modifier/job/affinity/wiring) display_order = JOB_DISPLAY_ORDER_STATION_ENGINEER diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm index 78f0ba4272..177d8e2b76 100644 --- a/code/modules/jobs/job_types/virologist.dm +++ b/code/modules/jobs/job_types/virologist.dm @@ -20,8 +20,7 @@ threat = 1.5 - starting_skills = list(/datum/skill/numerical/surgery = STARTING_SKILL_SURGERY_MEDICAL) - skill_affinities = list(/datum/skill/numerical/surgery = STARTING_SKILL_AFFINITY_SURGERY_MEDICAL) + starting_modifiers = list(/datum/skill_modifier/job/surgery, /datum/skill_modifier/job/affinity/surgery) /datum/outfit/job/virologist name = "Virologist" diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index f574b0aea3..57661901ae 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -59,7 +59,7 @@ if(tool) speed_mod = tool.toolspeed if(user.mind) - speed_mod = user.mind.skill_holder.action_skills_mod(/datum/skill/numerical/surgery, speed_mod, THRESHOLD_COMPETENT, FALSE) + 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)) var/prob_chance = 100 if(implement_type) //this means it isn't a require hand or any item step. @@ -68,7 +68,7 @@ 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?.skill_holder.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP) + user.mind?.auto_gain_experience(/datum/skill/numerical/surgery, SKILL_GAIN_SURGERY_PER_STEP) advance = TRUE else if(failure(user, target, target_zone, tool, surgery)) diff --git a/tgstation.dme b/tgstation.dme index dc02385b48..c05877a983 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -289,7 +289,6 @@ #include "code\controllers\subsystem\minimaps.dm" #include "code\controllers\subsystem\minor_mapping.dm" #include "code\controllers\subsystem\mobs.dm" -#include "code\controllers\subsystem\moods.dm" #include "code\controllers\subsystem\nightshift.dm" #include "code\controllers\subsystem\npcpool.dm" #include "code\controllers\subsystem\overlays.dm" @@ -583,8 +582,11 @@ #include "code\datums\skills\_check_skills.dm" #include "code\datums\skills\_skill.dm" #include "code\datums\skills\_skill_holder.dm" +#include "code\datums\skills\_skill_modifier.dm" #include "code\datums\skills\engineering.dm" #include "code\datums\skills\medical.dm" +#include "code\datums\skills\modifiers\job.dm" +#include "code\datums\skills\modifiers\mood.dm" #include "code\datums\status_effects\buffs.dm" #include "code\datums\status_effects\debuffs.dm" #include "code\datums\status_effects\gas.dm"