diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm
index abe0038e2858..cc2bd6df1e5a 100644
--- a/code/__DEFINES/food.dm
+++ b/code/__DEFINES/food.dm
@@ -160,8 +160,10 @@ GLOBAL_LIST_INIT(food_buffs, list(
))
/// Food quality change according to species diet
-#define DISLIKED_FOOD_QUALITY_CHANGE -2
-#define LIKED_FOOD_QUALITY_CHANGE 2
+#define DISLIKED_FOOD_QUALITY_CHANGE -1.5
+#define LIKED_FOOD_QUALITY_CHANGE 1.5
+/// Threshold for food to be considered gross
+#define GROSS_FOOD_QUALITY_THRESHOLD -2
/// Threshold for food to give a toxic reaction
#define TOXIC_FOOD_QUALITY_THRESHOLD -8
/// Food is dangerous to consume
diff --git a/code/__DEFINES/living.dm b/code/__DEFINES/living.dm
index 5400fd50ed47..1c7fdad7e89a 100644
--- a/code/__DEFINES/living.dm
+++ b/code/__DEFINES/living.dm
@@ -100,6 +100,8 @@
#define TRAIT_NO_GRAB_SPEED_PENALTY "no_grab_speed_penalty"
/// Doesn't let a mob shift this atom around with move_pulled
#define TRAIT_NO_MOVE_PULL "no_move_pull"
+/// Does not harm patients when undergoing CPR
+#define TRAIT_CPR_CERTIFIED "cpr_certified"
/// Boosts the heart rate of the mob
#define TRAIT_HEART_RATE_BOOST "heart_rate_boost"
diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm
index d00eb55eb868..c65e005109d5 100644
--- a/code/__DEFINES/skills.dm
+++ b/code/__DEFINES/skills.dm
@@ -49,3 +49,8 @@
//while using the SKILLCHIP_RESTRICTED_CATEGORIES flag
/// General related skillchip category
#define SKILLCHIP_CATEGORY_GENERAL "general"
+
+/// Always print this skill in print_skills
+#define SKILL_ALWAYS_PRINT (1<<0)
+/// Skill is is physical, not mental, and doesn't apply through skillchips or mindswaps
+#define SKILL_PHYSICAL (1<<1)
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 908e60220c8b..a9daeaeab989 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -709,6 +709,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_FOOD_SILVER "food_silver"
/// If this item's been made by a chef instead of being map-spawned or admin-spawned or such
#define TRAIT_FOOD_CHEF_MADE "food_made_by_chef"
+/// If this item is microwaved or cooked, it won't gain TRAIT_FOOD_CHEF_MADE unless it already had it
+#define TRAIT_FOOD_MUST_INHERIT_CHEF_MADE "food_must_inherit_chef_made"
/// This atom has a quality_food_ingredient element attached
#define TRAIT_QUALITY_FOOD_INGREDIENT "quality_food_ingredient"
/// The items needs two hands to be carried
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index b21bcd887e40..1f10dcf7346e 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -20,12 +20,13 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_FISHING_SPOT" = TRAIT_FISHING_SPOT,
"TRAIT_FOOD_CHEF_MADE" = TRAIT_FOOD_CHEF_MADE,
"TRAIT_FOOD_FRIED" = TRAIT_FOOD_FRIED,
- "TRAIT_GOT_DAMPENED" = TRAIT_GOT_DAMPENED,
- "TRAIT_QUALITY_FOOD_INGREDIENT" = TRAIT_QUALITY_FOOD_INGREDIENT,
+ "TRAIT_FOOD_MUST_INHERIT_CHEF_MADE" = TRAIT_FOOD_MUST_INHERIT_CHEF_MADE,
"TRAIT_FOOD_SILVER" = TRAIT_FOOD_SILVER,
+ "TRAIT_GOT_DAMPENED" = TRAIT_GOT_DAMPENED,
"TRAIT_KEEP_TOGETHER" = TRAIT_KEEP_TOGETHER,
"TRAIT_LIGHTING_DEBUGGED" = TRAIT_LIGHTING_DEBUGGED,
"TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION" = TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION,
+ "TRAIT_QUALITY_FOOD_INGREDIENT" = TRAIT_QUALITY_FOOD_INGREDIENT,
"TRAIT_RECENTLY_COINED" = TRAIT_RECENTLY_COINED,
"TRAIT_RUSTY" = TRAIT_RUSTY,
"TRAIT_SPINNING" = TRAIT_SPINNING,
diff --git a/code/controllers/subsystem/skills.dm b/code/controllers/subsystem/skills.dm
index 0ece2ac2aaa9..d1327e716750 100644
--- a/code/controllers/subsystem/skills.dm
+++ b/code/controllers/subsystem/skills.dm
@@ -6,9 +6,17 @@ SUBSYSTEM_DEF(skills)
name = "Skills"
flags = SS_NO_FIRE
///Dictionary of skill.type || skill ref
- var/list/all_skills = list()
+ var/list/datum/skill/all_skills = list()
///List of level names with index corresponding to skill level
- var/list/level_names = list("None", "Novice", "Apprentice", "Journeyman", "Expert", "Master", "Legendary") //List of skill level names. Note that indexes can be accessed like so: level_names[SKILL_LEVEL_NOVICE]
+ var/list/level_names = list(
+ SKILL_LEVEL_NONE = "Untrained",
+ SKILL_LEVEL_NOVICE = "Novice",
+ SKILL_LEVEL_APPRENTICE = "Apprentice",
+ SKILL_LEVEL_JOURNEYMAN = "Journeyman",
+ SKILL_LEVEL_EXPERT = "Expert",
+ SKILL_LEVEL_MASTER = "Master",
+ SKILL_LEVEL_LEGENDARY = "Legendary",
+ )
/datum/controller/subsystem/skills/Initialize()
InitializeSkills()
diff --git a/code/datums/components/bakeable.dm b/code/datums/components/bakeable.dm
index a745be2b1a57..4be4a29dc918 100644
--- a/code/datums/components/bakeable.dm
+++ b/code/datums/components/bakeable.dm
@@ -11,8 +11,9 @@
///Time spent baking so far
var/current_bake_time = 0
- /// REF() to the mind which placed us in an oven
- var/who_baked_us
+ // NON-MODULE CHANGE
+ /// WEAKREF() to the mind which placed us in an oven
+ var/datum/weakref/who_baked_us
/// Reagents that should be added to the result
var/list/added_reagents
@@ -53,8 +54,8 @@
/datum/component/bakeable/proc/on_baking_start(datum/source, atom/used_oven, mob/baker)
SIGNAL_HANDLER
- if(baker && baker.mind)
- who_baked_us = REF(baker.mind)
+ // NON-MODULE CHANGE
+ who_baked_us = WEAKREF(baker?.mind)
///Ran every time an item is baked by something
/datum/component/bakeable/proc/on_bake(datum/source, atom/used_oven, seconds_per_tick = 1)
@@ -80,8 +81,8 @@
if(added_reagents) // Add any new reagents that should be added
baked_result.reagents.add_reagent_list(added_reagents)
- if(who_baked_us)
- ADD_TRAIT(baked_result, TRAIT_FOOD_CHEF_MADE, who_baked_us)
+ // NON-MODULE CHANGE
+ handle_chef_made_food(baked_result, original_object, who_baked_us?.resolve())
if(original_object.custom_materials)
baked_result.set_custom_materials(original_object.custom_materials, 1)
diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm
index 0b95c28586f9..0c36f9f32d38 100644
--- a/code/datums/components/food/edible.dm
+++ b/code/datums/components/food/edible.dm
@@ -228,22 +228,29 @@ Behavior that's still missing from this component that original food items had t
examine_list += span_warning("You may die from eating this meal.")
else if (quality <= TOXIC_FOOD_QUALITY_THRESHOLD)
examine_list += span_warning("You find this meal disgusting!")
- else
+ // NON-MODULE CHANGE
+ else if (quality <= GROSS_FOOD_QUALITY_THRESHOLD)
examine_list += span_warning("You find this meal inedible.")
+ else
+ examine_list += span_notice("You find this meal shoddy.")
if(owner.reagents.total_volume > 0)
var/purity = owner.reagents.get_average_purity(/datum/reagent/consumable)
switch(purity)
if(0 to 0.2)
examine_list += span_warning("It is made of terrible ingredients shortening the effect...")
+ // NON-MODULE CHANGE
if(0.2 to 0.4)
- examine_list += span_warning("It is made of synthetic ingredients shortening the effect.")
+ examine_list += span_warning("It is made of poor ingredients shortening the effect.")
if(0.4 to 0.6)
examine_list += span_notice("It is made of average quality ingredients.")
if(0.6 to 0.8)
examine_list += span_green("It is made of organic ingredients prolonging the effect.")
if(0.8 to 1)
examine_list += span_green("It is made of finest ingredients prolonging the effect!")
+ // NON-MODULE CHANGE
+ if(1 to 1.5)
+ examine_list += span_green("A master chef using the finest ingredients to make this meal, prolonging the effect!")
var/datum/mind/mind = user.mind
if(mind && HAS_TRAIT_FROM(owner, TRAIT_FOOD_CHEF_MADE, REF(mind)))
@@ -569,25 +576,30 @@ Behavior that's still missing from this component that original food items had t
gourmand.add_mood_event("toxic_food", /datum/mood_event/disgusting_food)
return
- if(food_quality < 0)
- to_chat(gourmand,span_notice("That didn't taste very good..."))
+ // NON-MODULE CHANGE
+ if(food_quality <= GROSS_FOOD_QUALITY_THRESHOLD)
+ to_chat(gourmand, span_notice("That didn't taste very good..."))
gourmand.adjust_disgust(11 + 15 * fraction)
gourmand.add_mood_event("gross_food", /datum/mood_event/gross_food)
return
-
+ // NON-MODULE CHANGE
+ if(food_quality < 0)
+ to_chat(gourmand, span_notice("That could've been better."))
+ gourmand.add_mood_event("gross_food", /datum/mood_event/bad_food)
+ return
+ // NON-MODULE CHANGE
if(food_quality == 0)
+ to_chat(gourmand, span_notice("That's a mediocre meal."))
+ gourmand.add_mood_event("mid_food", /datum/mood_event/mid_food)
return // meh
- food_quality = min(food_quality, FOOD_QUALITY_TOP)
+ // NON-MODULE CHANGES
var/atom/owner = parent
- var/timeout_mod = owner.reagents.get_average_purity(/datum/reagent/consumable) * 2 // mood event duration is 100% at average purity of 50%
- var/datum/mood_event/event = GLOB.food_quality_events[food_quality]
- event = new event.type
- event.timeout *= timeout_mod
- gourmand.add_mood_event("quality_food", event)
+ var/timeout_mod = owner.reagents.get_average_purity(/datum/reagent/consumable) * 1.5 // mood event duration is 100% at average purity of 50%
+ gourmand.add_mood_event("quality_food", GLOB.food_quality_events[food_quality], timeout_mod)
gourmand.adjust_disgust(-5 + -2 * food_quality * fraction)
var/quality_label = GLOB.food_quality_description[food_quality]
- to_chat(gourmand, span_notice("That's \an [quality_label] meal."))
+ to_chat(gourmand, span_notice("That's \an [quality_label] meal."))
/// Get the complexity of the crafted food
/datum/component/edible/proc/get_recipe_complexity()
@@ -603,6 +615,13 @@ Behavior that's still missing from this component that original food items had t
/datum/component/edible/proc/get_perceived_food_quality(mob/living/carbon/human/eater)
var/food_quality = get_recipe_complexity()
+ // NON-MODULE CHANGE
+ if(HAS_MIND_TRAIT(eater, TRAIT_SNOB))
+ if(food_quality <= FOOD_QUALITY_VERYGOOD)
+ food_quality -= 0.5
+ else
+ food_quality += 0.5
+
if(HAS_TRAIT(parent, TRAIT_FOOD_SILVER)) // it's not real food
if(!isjellyperson(eater)) //if you aren't a jellyperson, it makes you sick no matter how nice it looks
return TOXIC_FOOD_QUALITY_THRESHOLD
@@ -612,25 +631,36 @@ Behavior that's still missing from this component that original food items had t
var/special_reaction = check_liked.Invoke(eater)
switch(special_reaction) //return early for special foods
if(FOOD_LIKED)
- return LIKED_FOOD_QUALITY_CHANGE
+ // NON-MODULE CHANGE
+ return round(LIKED_FOOD_QUALITY_CHANGE * 1.25)
if(FOOD_DISLIKED)
- return DISLIKED_FOOD_QUALITY_CHANGE
+ // NON-MODULE CHANGE
+ return round(DISLIKED_FOOD_QUALITY_CHANGE * 1.25)
if(FOOD_TOXIC)
return TOXIC_FOOD_QUALITY_THRESHOLD
if(FOOD_ALLERGIC)
return FOOD_QUALITY_DANGEROUS
- if(ishuman(eater))
- if(foodtypes & eater.get_allergic_foodtypes())
- return FOOD_QUALITY_DANGEROUS
- if(count_matching_foodtypes(foodtypes, eater.get_toxic_foodtypes())) //if the food is toxic, we don't care about anything else
- return TOXIC_FOOD_QUALITY_THRESHOLD
- if(HAS_TRAIT(eater, TRAIT_AGEUSIA)) //if you can't taste it, it doesn't taste good
- return 0
- food_quality += DISLIKED_FOOD_QUALITY_CHANGE * count_matching_foodtypes(foodtypes, eater.get_disliked_foodtypes())
- food_quality += LIKED_FOOD_QUALITY_CHANGE * count_matching_foodtypes(foodtypes, eater.get_liked_foodtypes())
-
- return food_quality
+ // NON-MODULE CHANGES
+ if(HAS_TRAIT(eater, TRAIT_AGEUSIA)) //if you can't taste it, it doesn't taste good
+ return 0
+ if(foodtypes & eater.get_allergic_foodtypes())
+ return FOOD_QUALITY_DANGEROUS
+ if(count_matching_foodtypes(foodtypes, eater.get_toxic_foodtypes())) //if the food is toxic, we don't care about anything else
+ return TOXIC_FOOD_QUALITY_THRESHOLD
+ food_quality += DISLIKED_FOOD_QUALITY_CHANGE * count_matching_foodtypes(foodtypes, eater.get_disliked_foodtypes())
+ food_quality += LIKED_FOOD_QUALITY_CHANGE * count_matching_foodtypes(foodtypes, eater.get_liked_foodtypes())
+
+ // NON-MODULE CHANGES
+ var/obj/item/food = parent
+ var/reagent_quality_mod = INFINITY
+ for(var/datum/reagent/consumable/nutri in food.reagents?.reagent_list)
+ reagent_quality_mod = min(reagent_quality_mod, nutri.data?["quality_modifier"] || 0)
+
+ if(reagent_quality_mod != INFINITY)
+ food_quality += reagent_quality_mod
+
+ return min(floor(food_quality), FOOD_QUALITY_TOP)
/// Get the number of matching food types in provided bitfields
/datum/component/edible/proc/count_matching_foodtypes(bitfield_one, bitfield_two)
diff --git a/code/datums/components/grillable.dm b/code/datums/components/grillable.dm
index f584808a1f3b..14ca7ff48cb3 100644
--- a/code/datums/components/grillable.dm
+++ b/code/datums/components/grillable.dm
@@ -10,8 +10,9 @@
var/current_cook_time = 0
///Do we use the large steam sprite?
var/use_large_steam_sprite = FALSE
- /// REF() to the mind which placed us on the griddle
- var/who_placed_us
+ // NON-MODULE CHANGE
+ /// WEAKREF() to the mind which placed us on the griddle
+ var/datum/weakref/who_placed_us
/// Reagents that should be added to the result
var/list/added_reagents
@@ -59,8 +60,8 @@
/datum/component/grillable/proc/on_grill_placed(datum/source, mob/griller)
SIGNAL_HANDLER
- if(griller && griller.mind)
- who_placed_us = REF(griller.mind)
+ // NON-MODULE CHANGE
+ who_placed_us = WEAKREF(griller?.mind)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
@@ -110,8 +111,8 @@
grilled_result.reagents.add_reagent_list(added_reagents)
SEND_SIGNAL(parent, COMSIG_ITEM_GRILLED, grilled_result)
- if(who_placed_us)
- ADD_TRAIT(grilled_result, TRAIT_FOOD_CHEF_MADE, who_placed_us)
+ // NON-MODULE CHANGE
+ handle_chef_made_food(grilled_result, parent, who_placed_us?.resolve())
grill_source.visible_message("[parent] turns into \a [grilled_result]!")
grilled_result.pixel_x = original_object.pixel_x
diff --git a/code/datums/elements/dryable.dm b/code/datums/elements/dryable.dm
index 583c74764eec..bbba59912748 100644
--- a/code/datums/elements/dryable.dm
+++ b/code/datums/elements/dryable.dm
@@ -29,13 +29,15 @@
if(dry_result == dried_atom.type)//if the dried type is the same as our currrent state, don't bother creating a whole new item, just re-color it.
var/atom/movable/resulting_atom = dried_atom
resulting_atom.add_atom_colour(dried_color, FIXED_COLOUR_PRIORITY)
- apply_dried_status(resulting_atom, drying_user)
+ // NON-MODULE CHANGE
+ apply_dried_status(resulting_atom, drying_user?.resolve(), source)
return
else if(isstack(source)) //Check if its a sheet
var/obj/item/stack/itemstack = dried_atom
for(var/i in 1 to itemstack.amount)
var/atom/movable/resulting_atom = new dry_result(source.loc)
- apply_dried_status(resulting_atom, drying_user)
+ // NON-MODULE CHANGE
+ apply_dried_status(resulting_atom, drying_user?.resolve(), source)
qdel(source)
return
else if(istype(source, /obj/item/food) && ispath(dry_result, /obj/item/food))
@@ -43,16 +45,18 @@
var/obj/item/food/resulting_food = new dry_result(source.loc)
resulting_food.reagents.clear_reagents()
source_food.reagents.trans_to(resulting_food, source_food.reagents.total_volume)
- apply_dried_status(resulting_food, drying_user)
+ // NON-MODULE CHANGE
+ apply_dried_status(resulting_food, drying_user?.resolve(), source)
qdel(source)
return
else
var/atom/movable/resulting_atom = new dry_result(source.loc)
- apply_dried_status(resulting_atom, drying_user)
+ // NON-MODULE CHANGE
+ apply_dried_status(resulting_atom, drying_user?.resolve(), source)
qdel(source)
-/datum/element/dryable/proc/apply_dried_status(atom/target, datum/weakref/drying_user)
+/datum/element/dryable/proc/apply_dried_status(atom/target, datum/mind/chef, atom/source)
ADD_TRAIT(target, TRAIT_DRIED, ELEMENT_TRAIT(type))
- var/datum/mind/user_mind = drying_user?.resolve()
- if(drying_user && istype(target, /obj/item/food))
- ADD_TRAIT(target, TRAIT_FOOD_CHEF_MADE, REF(user_mind))
+ // NON-MODULE CHANGE
+ if(istype(chef) && istype(target, /obj/item/food))
+ handle_chef_made_food(target, source, chef, 0.25)
diff --git a/code/datums/elements/food/microwavable.dm b/code/datums/elements/food/microwavable.dm
index 5fdd4c084add..d7db0af015a3 100644
--- a/code/datums/elements/food/microwavable.dm
+++ b/code/datums/elements/food/microwavable.dm
@@ -53,8 +53,7 @@
if(added_reagents) // Add any new reagents that should be added
result.reagents.add_reagent_list(added_reagents)
- if(microwaver && microwaver.mind)
- ADD_TRAIT(result, TRAIT_FOOD_CHEF_MADE, REF(microwaver.mind))
+ handle_chef_made_food(result, source, microwaver?.mind, 0.75)
qdel(source)
diff --git a/code/datums/mind/skills.dm b/code/datums/mind/skills.dm
index 474291d5ae0d..2897ebe649fa 100644
--- a/code/datums/mind/skills.dm
+++ b/code/datums/mind/skills.dm
@@ -1,6 +1,6 @@
/datum/mind/proc/init_known_skills()
for (var/type in GLOB.skill_types)
- known_skills[type] = list(SKILL_LEVEL_NONE, 0)
+ known_skills[type] = list(SKILL_LVL = SKILL_LEVEL_NONE, SKILL_EXP = 0)
///Return the amount of EXP needed to go to the next level. Returns 0 if max level
/datum/mind/proc/exp_needed_to_level_up(skill)
@@ -9,10 +9,18 @@
return 0
return SKILL_EXP_LIST[lvl+1] - known_skills[skill][SKILL_EXP]
-///Adjust experience of a specific skill
-/datum/mind/proc/adjust_experience(skill, amt, silent = FALSE, force_old_level = 0)
+///
+/**
+ * Adjust experience of a specific skill
+ *
+ * * skill: The skill to adjust, typepath
+ * * amt: The amount to adjust the skill by
+ * * silent: If TRUE, don't send messages to the player
+ * * force_old_level: If set to any skill level, we will act as if the skill was at that level before the adjustment, rather than their current level
+ */
+/datum/mind/proc/adjust_experience(skill, amt, silent = FALSE, force_old_level)
var/datum/skill/S = GetSkillRef(skill)
- var/old_level = force_old_level ? force_old_level : known_skills[skill][SKILL_LVL] //Get current level of the S skill
+ var/old_level = force_old_level || known_skills[skill][SKILL_LVL] //Get current level of the S skill
experience_multiplier = initial(experience_multiplier)
for(var/key in experience_multiplier_reasons)
experience_multiplier += experience_multiplier_reasons[key]
@@ -47,8 +55,21 @@
///Gets the skill's singleton and returns the result of its get_skill_modifier
/datum/mind/proc/get_skill_modifier(skill, modifier)
- var/datum/skill/S = GetSkillRef(skill)
- return S.get_skill_modifier(modifier, known_skills[skill][SKILL_LVL])
+ if(!SSskills.initialized)
+ return 1
+ return SSskills.all_skills[skill].get_skill_modifier(modifier, known_skills[skill][SKILL_LVL])
+
+/// Gets the skill's singleton and returns the result of its get_skill_modifier
+/// If the mind is null, assume as little experience as possible ([SKILL_LEVEL_NONE])
+/mob/proc/get_skill_modifier(skill, modifier)
+ if(!SSskills.initialized)
+ return 1
+ if(isnull(mind))
+ return SSskills.all_skills[skill].get_skill_modifier(modifier, SKILL_LEVEL_NONE)
+ return mind.get_skill_modifier(skill, modifier)
+
+/mob/living/carbon/human/dummy/get_skill_modifier(skill, modifier)
+ return 1
///Gets the player's current level number from the relevant skill
/datum/mind/proc/get_skill_level(skill)
@@ -58,21 +79,28 @@
/datum/mind/proc/get_skill_exp(skill)
return known_skills[skill][SKILL_EXP]
+/// Gets the what name the player's current level of the skill corresponds to
/datum/mind/proc/get_skill_level_name(skill)
- var/level = get_skill_level(skill)
- return SSskills.level_names[level]
+ return SSskills.level_names[get_skill_level(skill)]
/datum/mind/proc/print_levels(user)
var/list/shown_skills = list()
- for(var/i in known_skills)
- if(known_skills[i][SKILL_LVL] > SKILL_LEVEL_NONE) //Do we actually have a level in this?
- shown_skills += i
+ var/list/untrained_skills = list()
+ for(var/datum/skill/known_skill as anything in known_skills)
+ if(known_skills[known_skill][SKILL_LVL] > SKILL_LEVEL_NONE) //Do we actually have a level in this?
+ shown_skills += known_skill
+ else if(initial(known_skill.skill_flags) & SKILL_ALWAYS_PRINT)
+ untrained_skills += known_skill
+
if(!length(shown_skills))
- to_chat(user, span_notice("You don't seem to have any particularly outstanding skills."))
+ to_chat(user, examine_block(span_notice("You don't have any particularly outstanding skills.")))
return
- var/msg = "[span_info("Your skills")]\n"
- for(var/i in shown_skills)
- var/datum/skill/the_skill = i
- msg += "[initial(the_skill.name)] - [get_skill_level_name(the_skill)]\n"
- msg += ""
- to_chat(user, examine_block(msg))
+
+ var/list/skill_strings = list()
+ for(var/datum/skill/shown_skill as anything in shown_skills)
+ skill_strings += span_notice("• [initial(shown_skill.name)] - [get_skill_level_name(shown_skill)]")
+ for(var/datum/skill/shown_skill as anything in untrained_skills)
+ skill_strings += span_smallnoticeital("• [initial(shown_skill.name)] - [get_skill_level_name(shown_skill)]")
+
+ sortTim(skill_strings, GLOBAL_PROC_REF(cmp_text_asc))
+ to_chat(user, examine_block("[span_info("Your skills:")]
[jointext(skill_strings, "
")]"))
diff --git a/code/datums/mood_events/food_events.dm b/code/datums/mood_events/food_events.dm
index e64d975902ea..fa9484a397b8 100644
--- a/code/datums/mood_events/food_events.dm
+++ b/code/datums/mood_events/food_events.dm
@@ -27,10 +27,19 @@
timeout = 5 MINUTES
var/quality = FOOD_QUALITY_NORMAL
-/datum/mood_event/food/New(mob/M, ...)
- . = ..()
- mood_change = 2 + 2 * quality
- description = "That food was [GLOB.food_quality_description[quality]]."
+// NON-MODULE CHANGE
+/datum/mood_event/food/add_effects(timeout_mod = 1)
+ timeout *= timeout_mod
+ mood_change = floor(quality * 1.34)
+ if(HAS_MIND_TRAIT(owner, TRAIT_SNOB))
+ if(quality <= FOOD_QUALITY_VERYGOOD)
+ mood_change -= 1
+ description = "That food was [GLOB.food_quality_description[quality]], but I expect better."
+ else
+ mood_change += 1
+ description = "That food was [GLOB.food_quality_description[quality]]. Perfection!"
+ else
+ description = "That food was [GLOB.food_quality_description[quality]]."
/datum/mood_event/food/nice
quality = FOOD_QUALITY_NICE
@@ -50,6 +59,28 @@
/datum/mood_event/food/top
quality = FOOD_QUALITY_TOP
+// NON-MODULE CHANGE
+/datum/mood_event/mid_food
+ timeout = 5 MINUTES
+ description = "That's some shockingly mediocre food."
+ mood_change = 0
+
+/datum/mood_event/mid_food/add_effects()
+ if(HAS_MIND_TRAIT(owner, TRAIT_SNOB))
+ mood_change = -2
+ description = "That's some shockingly mediocre food - I expect better!"
+
+// NON-MODULE CHANGE
+/datum/mood_event/bad_food
+ timeout = 5 MINUTES
+ description = "That food wasn't very good, but at least it didn't make me sick."
+ mood_change = -2
+
+/datum/mood_event/bad_food/add_effects()
+ if(HAS_MIND_TRAIT(owner, TRAIT_SNOB))
+ mood_change = -4
+ description = "That food wasn't very good. I expect better!"
+
/datum/mood_event/pacifist_eating_fish_item
description = "I shouldn't be eating living creatures..."
mood_change = -1 //The disgusting food moodlet already has a pretty big negative value, this is just for context.
diff --git a/code/datums/quirks/positive_quirks/settler.dm b/code/datums/quirks/positive_quirks/settler.dm
index 7f3615272612..70a4ecff90ee 100644
--- a/code/datums/quirks/positive_quirks/settler.dm
+++ b/code/datums/quirks/positive_quirks/settler.dm
@@ -29,7 +29,7 @@
var/mob/living/carbon/human/human_quirkholder = quirk_holder
human_quirkholder.set_mob_height(HUMAN_HEIGHT_SHORTEST)
human_quirkholder.add_movespeed_modifier(/datum/movespeed_modifier/settler)
- human_quirkholder.physiology.hunger_mod *= 0.5 //good for you, shortass, you don't get hungry nearly as often
+ human_quirkholder.physiology.hunger_mod *= 0.75 //good for you, shortass, you don't get hungry nearly as often
human_quirkholder.add_traits(settler_traits, QUIRK_TRAIT)
/datum/quirk/item_quirk/settler/remove()
@@ -38,5 +38,5 @@
var/mob/living/carbon/human/human_quirkholder = quirk_holder
human_quirkholder.set_mob_height(HUMAN_HEIGHT_MEDIUM)
human_quirkholder.remove_movespeed_modifier(/datum/movespeed_modifier/settler)
- human_quirkholder.physiology.hunger_mod *= 2
+ human_quirkholder.physiology.hunger_mod /= 0.75
human_quirkholder.remove_traits(settler_traits, QUIRK_TRAIT)
diff --git a/code/datums/skills/_skill.dm b/code/datums/skills/_skill.dm
index 30acf90381f0..e143aef9b89e 100644
--- a/code/datums/skills/_skill.dm
+++ b/code/datums/skills/_skill.dm
@@ -1,41 +1,63 @@
GLOBAL_LIST_INIT(skill_types, subtypesof(/datum/skill))
/datum/skill
- var/name = "Skilling"
- var/title = "Skiller"
- var/desc = "the art of doing things"
- ///Dictionary of modifier type - list of modifiers (indexed by level). 7 entries in each list for all 7 skill levels.
- var/modifiers = list(SKILL_SPEED_MODIFIER = list(1, 1, 1, 1, 1, 1, 1)) //Dictionary of modifier type - list of modifiers (indexed by level). 7 entries in each list for all 7 skill levels.
- ///List Path pointing to the skill item reward that will appear when a user finishes leveling up a skill
+ /// String, required, the name of the skill
+ var/name
+ /// String, required, the title of the skill, e.g. "Surgeon" or "Miner"
+ var/title
+ /// String, required, Some flavor blurb relating to the skill
+ var/blurb
+ /// String, optional, how a user can be expected to earn this skill
+ var/earned_by
+ /// String, optional, what this skill generally does to improve the user's abilities
+ var/grants_you
+ /// String, optional, what this skill does to improve the user's abilities at higher levels
+ var/higher_levels_grant_you
+ /// Dictionary of modifier type - list of modifiers (indexed by level).
+ var/list/modifiers = list(
+ SKILL_SPEED_MODIFIER = list(
+ SKILL_LEVEL_NONE = 1,
+ SKILL_LEVEL_NOVICE = 1,
+ SKILL_LEVEL_APPRENTICE = 1,
+ SKILL_LEVEL_JOURNEYMAN = 1,
+ SKILL_LEVEL_EXPERT = 1,
+ SKILL_LEVEL_MASTER = 1,
+ SKILL_LEVEL_LEGENDARY = 1,
+ ),
+ )
+ /// Flags relating to this skill
+ var/skill_flags = NONE
+ /// Typepath of skill item reward that will appear when a user finishes leveling up a skill
var/skill_item_path
- ///List associating different messages that appear on level up with different levels
- var/list/levelUpMessages = list()
- ///List associating different messages that appear on level up with different levels
- var/list/levelDownMessages = list()
+ /// List associating different messages that appear on level up with different levels
+ var/list/level_up_messages
+ /// List associating different messages that appear on level up with different levels
+ var/list/level_down_messages
+/// Getter for some modifier at a certain level
/datum/skill/proc/get_skill_modifier(modifier, level)
return modifiers[modifier][level] //Levels range from 1 (None) to 7 (Legendary)
-/**
- * new: sets up some lists.
- *
- *Can't happen in the datum's definition because these lists are not constant expressions
- */
+
/datum/skill/New()
. = ..()
- levelUpMessages = list(span_nicegreen("What the hell is [name]? Tell an admin if you see this message."), //This first index shouldn't ever really be used
- span_nicegreen("I'm starting to figure out what [name] really is!"),
- span_nicegreen("I'm getting a little better at [name]!"),
- span_nicegreen("I'm getting much better at [name]!"),
- span_nicegreen("I feel like I've become quite proficient at [name]!"),
- span_nicegreen("After lots of practice, I've begun to truly understand the intricacies and surprising depth behind [name]. I now consider myself a master [title]."),
- span_nicegreen("Through incredible determination and effort, I've reached the peak of my [name] abiltities. I'm finally able to consider myself a legendary [title]!") )
- levelDownMessages = list(span_nicegreen("I have somehow completely lost all understanding of [name]. Please tell an admin if you see this."),
- span_nicegreen("I'm starting to forget what [name] really even is. I need more practice..."),
- span_nicegreen("I'm getting a little worse at [name]. I'll need to keep practicing to get better at it..."),
- span_nicegreen("I'm getting a little worse at [name]..."),
- span_nicegreen("I'm losing my [name] expertise ...."),
- span_nicegreen("I feel like I'm losing my mastery of [name]."),
- span_nicegreen("I feel as though my legendary [name] skills have deteriorated. I'll need more intense training to recover my lost skills.") )
+ level_up_messages = list(
+ SKILL_LEVEL_NONE = "", // Everyone starts at NONE, you can't go up to it
+ SKILL_LEVEL_NOVICE = span_nicegreen("I'm starting to figure out what [name] really is!"),
+ SKILL_LEVEL_APPRENTICE = span_nicegreen("I'm getting a little better at [name]!"),
+ SKILL_LEVEL_JOURNEYMAN = span_nicegreen("I'm getting much better at [name]!"),
+ SKILL_LEVEL_EXPERT = span_nicegreen("I feel like I've become quite proficient at [name]!"),
+ SKILL_LEVEL_MASTER = span_nicegreen("After lots of practice, I've begun to truly understand the intricacies and surprising depth behind [name]. I now consider myself a master [title]."),
+ SKILL_LEVEL_LEGENDARY = span_nicegreen("Through incredible determination and effort, I've reached the peak of my [name] abiltities. I'm finally able to consider myself a legendary [title]!"),
+ )
+ level_down_messages = list(
+ SKILL_LEVEL_NONE = span_nicegreen("I have somehow completely lost all understanding of [name]."),
+ SKILL_LEVEL_NOVICE = span_nicegreen("I'm starting to forget what [name] really even is. I need more practice..."),
+ SKILL_LEVEL_APPRENTICE = span_nicegreen("I'm getting a little worse at [name]. I'll need to keep practicing to get better at it..."),
+ SKILL_LEVEL_JOURNEYMAN = span_nicegreen("I'm getting a little worse at [name]..."),
+ SKILL_LEVEL_EXPERT = span_nicegreen("I'm losing my [name] expertise ...."),
+ SKILL_LEVEL_MASTER = span_nicegreen("I feel like I'm losing my mastery of [name]."),
+ SKILL_LEVEL_LEGENDARY = span_nicegreen("I feel as though my legendary [name] skills have deteriorated. I'll need more intense training to recover my lost skills."),
+ )
/**
* level_gained: Gives skill levelup messages to the user
@@ -48,16 +70,18 @@ GLOBAL_LIST_INIT(skill_types, subtypesof(/datum/skill))
* * silent - Silences the announcement if TRUE
*/
/datum/skill/proc/level_gained(datum/mind/mind, new_level, old_level, silent)
- if(silent)
+ if(new_level == SKILL_LEVEL_NONE)
+ CRASH("Someone tried to level up to NONE skill level, wtf")
+ if(silent || new_level == old_level)
return
- to_chat(mind.current, levelUpMessages[new_level]) //new_level will be a value from 1 to 6, so we get appropriate message from the 6-element levelUpMessages list
+ to_chat(mind.current, level_up_messages[new_level]) //new_level will be a value from 1 to 6, so we get appropriate message from the 6-element level_up_messages list
/**
* level_lost: See level_gained, same idea but fires on skill level-down
*/
/datum/skill/proc/level_lost(datum/mind/mind, new_level, old_level, silent)
- if(silent)
+ if(silent || new_level == old_level)
return
- to_chat(mind.current, levelDownMessages[old_level]) //old_level will be a value from 1 to 6, so we get appropriate message from the 6-element levelUpMessages list
+ to_chat(mind.current, level_down_messages[old_level]) //old_level will be a value from 1 to 6, so we get appropriate message from the 6-element level_up_messages list
/**
* try_skill_reward: Checks to see if a user is eligable for a tangible reward for reaching a certain skill level
@@ -71,9 +95,8 @@ GLOBAL_LIST_INIT(skill_types, subtypesof(/datum/skill))
if (new_level != SKILL_LEVEL_LEGENDARY)
return
if (!ispath(skill_item_path))
- to_chat(mind.current, span_nicegreen("My legendary [name] skill is quite impressive, though it seems the Professional [title] Association doesn't have any status symbols to commemorate my abilities with. I should let Centcom know of this travesty, maybe they can do something about it."))
return
- if (LAZYFIND(mind.skills_rewarded, src.type))
+ if (LAZYFIND(mind.skills_rewarded, type))
to_chat(mind.current, span_nicegreen("It seems the Professional [title] Association won't send me another status symbol."))
return
podspawn(list(
@@ -82,5 +105,6 @@ GLOBAL_LIST_INIT(skill_types, subtypesof(/datum/skill))
"spawn" = skill_item_path,
"delays" = list(POD_TRANSIT = 150, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30)
))
- to_chat(mind.current, span_nicegreen("My legendary skill has attracted the attention of the Professional [title] Association. It seems they are sending me a status symbol to commemorate my abilities."))
- LAZYADD(mind.skills_rewarded, src.type)
+ to_chat(mind.current, span_nicegreen("My legendary skill has attracted the attention of the Professional [title] Association. \
+ It seems they are sending me a status symbol to commemorate my abilities."))
+ LAZYADD(mind.skills_rewarded, type)
diff --git a/code/datums/skills/athletics.dm b/code/datums/skills/athletics.dm
index 2ef336e5ba9b..6d12d8a15a60 100644
--- a/code/datums/skills/athletics.dm
+++ b/code/datums/skills/athletics.dm
@@ -1,27 +1,35 @@
/datum/skill/athletics
name = "Athletics"
title = "Athlete"
- desc = "Twinkle twinkle little star, hit the gym and lift the bar."
+ blurb = "Twinkle twinkle little star, hit the gym and lift the bar."
+ earned_by = "exercising on the machines in the station's recreation area"
+ grants_you = "greater ease of grabbing, grappling, and carrying others"
+ higher_levels_grant_you = "the ability to exercise for longer periods of time"
// The skill value modifier effects the max duration that is possible for /datum/status_effect/exercised; The rands modifier determines block probability and crit probability while boxing against boxers
modifiers = list(
SKILL_VALUE_MODIFIER = list(
- 1 MINUTES,
- 1.5 MINUTES,
- 2 MINUTES,
- 2.5 MINUTES,
- 3 MINUTES,
- 3.5 MINUTES,
+ 1 MINUTES,
+ 1.5 MINUTES,
+ 2 MINUTES,
+ 2.5 MINUTES,
+ 3 MINUTES,
+ 3.5 MINUTES,
5 MINUTES
- ),
+ ),
SKILL_RANDS_MODIFIER = list(
- 0,
- 5,
- 10,
- 15,
- 20,
- 30,
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 30,
50
)
)
-
skill_item_path = /obj/item/clothing/gloves/boxing/golden
+ skill_flags = SKILL_ALWAYS_PRINT|SKILL_PHYSICAL
+
+/datum/skill/athletics/New()
+ . = ..()
+ level_up_messages[SKILL_LEVEL_MASTER] = span_nicegreen("After lots of exercise, I've begun to truly understand the surprising depth behind [name].")
+ level_up_messages[SKILL_LEVEL_LEGENDARY] = span_nicegreen("Through incredible determination and effort, I've reached the peak of my Athletic abilities.")
diff --git a/code/datums/skills/bartending.dm b/code/datums/skills/bartending.dm
new file mode 100644
index 000000000000..51ea61a57c61
--- /dev/null
+++ b/code/datums/skills/bartending.dm
@@ -0,0 +1,69 @@
+/datum/skill/bartending
+ name = "Mixology"
+ title = "Mixologist"
+ blurb = "It's time to mix drinks and change lives."
+ earned_by = "mixing drinks"
+ // grants_you = "tastier drinks"
+ modifiers = list()
+
+/**
+ * Grants xp to the user for initiating a reaction
+ *
+ * * mixer - The user who initiated the reaction, asserted to have a mind
+ */
+/datum/reagents/proc/award_mixing_exp(datum/chemical_reaction/reaction, amount_created = 10)
+ var/lastkey = my_atom?.fingerprintslast
+ if(!lastkey)
+ return
+ var/mob/living/mixer = get_mob_by_ckey(lastkey)
+ if(!istype(mixer) || mixer.incapacitated(ALL) || isnull(mixer.mind) || !is_in_sight(mixer, my_atom))
+ return
+
+ if(reaction.reaction_tags & REACTION_TAG_DRINK)
+ var/xp_mod = (amount_created / 50)
+ if(reaction.reaction_tags & REACTION_TAG_EASY)
+ mixer.mind.adjust_experience(/datum/skill/bartending, 10 * xp_mod)
+ else if(reaction.reaction_tags & REACTION_TAG_MODERATE)
+ mixer.mind.adjust_experience(/datum/skill/bartending, 25 * xp_mod)
+ else if(reaction.reaction_tags & REACTION_TAG_HARD)
+ mixer.mind.adjust_experience(/datum/skill/bartending, 50 * xp_mod)
+
+ if(reaction.reaction_tags & REACTION_TAG_FOOD)
+ var/xp_mod = (amount_created / 50)
+ if(istype(reaction, /datum/chemical_reaction/food))
+ var/datum/chemical_reaction/food/food_reaction = reaction
+ if(food_reaction.resulting_food_path)
+ xp_mod *= 5 // bonus for making actual food
+
+ if(reaction.reaction_tags & REACTION_TAG_EASY)
+ mixer.mind.adjust_experience(/datum/skill/cooking, 10 * xp_mod)
+ else if(reaction.reaction_tags & REACTION_TAG_MODERATE)
+ mixer.mind.adjust_experience(/datum/skill/cooking, 25 * xp_mod)
+ else if(reaction.reaction_tags & REACTION_TAG_HARD)
+ mixer.mind.adjust_experience(/datum/skill/cooking, 50 * xp_mod)
+
+ if(reaction.reaction_tags & (REACTION_TAG_DRUG|REACTION_TAG_HEALING))
+ var/xp_mod = (amount_created / 50)
+ if(reaction.reaction_tags & REACTION_TAG_EASY)
+ mixer.mind.adjust_experience(/datum/skill/chemistry, 10 * xp_mod)
+ else if(reaction.reaction_tags & REACTION_TAG_MODERATE)
+ mixer.mind.adjust_experience(/datum/skill/chemistry, 25 * xp_mod)
+ else if(reaction.reaction_tags & REACTION_TAG_HARD)
+ mixer.mind.adjust_experience(/datum/skill/chemistry, 50 * xp_mod)
+
+// This blows
+/datum/chemical_reaction/drink/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
+ . = ..()
+ holder.award_mixing_exp(src, created_volume)
+
+/datum/chemical_reaction/food/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
+ . = ..()
+ holder.award_mixing_exp(src, created_volume)
+
+/datum/chemical_reaction/medicine/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
+ . = ..()
+ holder.award_mixing_exp(src, created_volume)
+
+/datum/chemical_reaction/drug/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
+ . = ..()
+ holder.award_mixing_exp(src, created_volume)
diff --git a/code/datums/skills/chemistry.dm b/code/datums/skills/chemistry.dm
new file mode 100644
index 000000000000..caea3153ed83
--- /dev/null
+++ b/code/datums/skills/chemistry.dm
@@ -0,0 +1,8 @@
+/datum/skill/chemistry
+ name = "Chemistry"
+ title = "Chemist"
+ blurb = "I am in my element."
+ earned_by = "mixing medicines and drugs"
+ // grants_you = "more effective medicines and drugs"
+ modifiers = list()
+ skill_flags = SKILL_ALWAYS_PRINT
diff --git a/code/datums/skills/cleaning.dm b/code/datums/skills/cleaning.dm
index b3ccad7eb4cb..752a832d95da 100644
--- a/code/datums/skills/cleaning.dm
+++ b/code/datums/skills/cleaning.dm
@@ -1,6 +1,20 @@
/datum/skill/cleaning
name = "Cleaning"
title = "Cleaner"
- desc = "It’s not who I am underneath, but what I mop up that defines me."
- modifiers = list(SKILL_SPEED_MODIFIER = list(1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.36)) //speed also touches probability in using up a soap's charge
+ blurb = "It's not who I am underneath, but what I mop up that defines me."
+ earned_by = "cleaning grime and blood"
+ grants_you = "an improved proficiency with cleaning tools"
+ modifiers = list(
+ // speed also touches probability in using up a soap's charge
+ SKILL_SPEED_MODIFIER = list(
+ SKILL_LEVEL_NONE = 1.1,
+ SKILL_LEVEL_NOVICE = 1,
+ SKILL_LEVEL_APPRENTICE = 0.9,
+ SKILL_LEVEL_JOURNEYMAN = 0.8,
+ SKILL_LEVEL_EXPERT = 0.7,
+ SKILL_LEVEL_MASTER = 0.6,
+ SKILL_LEVEL_LEGENDARY = 0.5,
+ ),
+ )
skill_item_path = /obj/item/clothing/neck/cloak/skill_reward/cleaning
+ skill_flags = SKILL_ALWAYS_PRINT
diff --git a/code/datums/skills/cooking.dm b/code/datums/skills/cooking.dm
new file mode 100644
index 000000000000..4736fc91e545
--- /dev/null
+++ b/code/datums/skills/cooking.dm
@@ -0,0 +1,58 @@
+/datum/skill/cooking
+ name = "Cooking"
+ title = "Chef"
+ blurb = "Anyone can cook."
+ earned_by = "cooking and mixing food"
+ grants_you = "tastier food"
+ modifiers = list(
+ // modifiers food reagent purity in cooked products
+ // with poor skill, you make fantastic ingredients good, and mediocre ingredients bad
+ // but with high skill, you can make bad ingredients good, and the best is even better
+ SKILL_VALUE_MODIFIER = list(
+ SKILL_LEVEL_NONE = 0.75,
+ SKILL_LEVEL_NOVICE = 0.9,
+ SKILL_LEVEL_APPRENTICE = 1,
+ SKILL_LEVEL_JOURNEYMAN = 1,
+ SKILL_LEVEL_EXPERT = 1.1,
+ SKILL_LEVEL_MASTER = 1.2,
+ SKILL_LEVEL_LEGENDARY = 1.3,
+ ),
+ // flat addition to food quality
+ // with poor skill "nice" food becomes "normal"
+ // but with high skill "nice" food becomes "very nice" or even "fantastic"
+ SKILL_RANDS_MODIFIER = list(
+ SKILL_LEVEL_NONE = -1,
+ SKILL_LEVEL_NOVICE = 0,
+ SKILL_LEVEL_APPRENTICE = 0,
+ SKILL_LEVEL_JOURNEYMAN = 0.5,
+ SKILL_LEVEL_EXPERT = 1,
+ SKILL_LEVEL_MASTER = 1.5,
+ SKILL_LEVEL_LEGENDARY = 2,
+ ),
+ )
+
+/// Mark a food item as "made by a chef", modify its quality
+/proc/handle_chef_made_food(obj/item/food, obj/item/source, datum/mind/chef, xp_mod = 1)
+ modify_food_quality(food, chef)
+ if(isnull(chef))
+ return
+ if(HAS_TRAIT(source, TRAIT_FOOD_MUST_INHERIT_CHEF_MADE) && !HAS_TRAIT(source, TRAIT_FOOD_CHEF_MADE))
+ return
+ ADD_TRAIT(food, TRAIT_FOOD_CHEF_MADE, REF(chef))
+ chef.adjust_experience(/datum/skill/cooking, min(25, 5 * xp_mod))
+
+/// When given some item with reagents (normally food),
+/// modifies the quality of the reagents according to the passed chef's mind's cooking skill
+/proc/modify_food_quality(obj/item/food, datum/mind/chef)
+ if(isnull(food?.reagents))
+ return
+
+ var/purity_modifier = chef?.get_skill_modifier(/datum/skill/cooking, SKILL_VALUE_MODIFIER) || 1
+ var/quality_modifier = chef?.get_skill_modifier(/datum/skill/cooking, SKILL_RANDS_MODIFIER) || -1
+
+ for(var/datum/reagent/consumable/nutri in food.reagents.reagent_list)
+ // purity in food models how quality the ingredient is
+ // we reduce the purtiy based on the chef's skill to model wasting quality parts of the ingredients
+ nutri.purity *= purity_modifier
+ // we store this in the reagent data to read it later
+ LAZYSET(nutri.data, "quality_modifier", quality_modifier)
diff --git a/code/datums/skills/cybernetic.dm b/code/datums/skills/cybernetic.dm
new file mode 100644
index 000000000000..5b9ebabf6445
--- /dev/null
+++ b/code/datums/skills/cybernetic.dm
@@ -0,0 +1,19 @@
+/datum/skill/cybernetics
+ name = "Cybernetics"
+ title = "Cyberneticist"
+ blurb = "From the moment I realized the weakness of flesh, it disgusted me. I craved a better way to be."
+ earned_by = "installing and repairing cybernetic implants"
+ grants_you = "less pain when installing cybernetic implants on yourself and others"
+ modifiers = list(
+ // amount of pain to reduce when installing cybernetic implants
+ SKILL_VALUE_MODIFIER = list(
+ SKILL_LEVEL_NONE = -10,
+ SKILL_LEVEL_NOVICE = 0,
+ SKILL_LEVEL_APPRENTICE = 0,
+ SKILL_LEVEL_JOURNEYMAN = 10,
+ SKILL_LEVEL_EXPERT = 20,
+ SKILL_LEVEL_MASTER = 30,
+ SKILL_LEVEL_LEGENDARY = 50,
+ ),
+ )
+ skill_flags = SKILL_ALWAYS_PRINT
diff --git a/code/datums/skills/electrics.dm b/code/datums/skills/electrics.dm
new file mode 100644
index 000000000000..d0851729697d
--- /dev/null
+++ b/code/datums/skills/electrics.dm
@@ -0,0 +1,28 @@
+/datum/skill/electronics
+ name = "Electronics"
+ title = "Electrical Engineer"
+ blurb = "Hack the planet! Or, y'know, do your job."
+ grants_you = "reduced chance of being shocked when hacking or messing with cables"
+ higher_levels_grant_you = "innate knowledge of airlock and APC wiring"
+ modifiers = list(
+ SKILL_PROBS_MODIFIER = list(
+ SKILL_LEVEL_NONE = 0,
+ SKILL_LEVEL_NOVICE = 0,
+ SKILL_LEVEL_APPRENTICE = 10,
+ SKILL_LEVEL_JOURNEYMAN = 20,
+ SKILL_LEVEL_EXPERT = 30,
+ SKILL_LEVEL_MASTER = 40,
+ SKILL_LEVEL_LEGENDARY = 50,
+ ),
+ )
+ skill_flags = SKILL_ALWAYS_PRINT
+
+/datum/skill/electronics/level_gained(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ if(new_level >= SKILL_LEVEL_EXPERT)
+ ADD_TRAIT(mind, TRAIT_KNOW_ENGI_WIRES, type)
+
+/datum/skill/electronics/level_lost(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ if(old_level >= SKILL_LEVEL_EXPERT && new_level < SKILL_LEVEL_EXPERT)
+ REMOVE_TRAIT(mind, TRAIT_KNOW_ENGI_WIRES, type)
diff --git a/code/datums/skills/eva.dm b/code/datums/skills/eva.dm
new file mode 100644
index 000000000000..aaf8242c8869
--- /dev/null
+++ b/code/datums/skills/eva.dm
@@ -0,0 +1,51 @@
+/datum/skill/eva
+ name = "EVA"
+ title = "EVA Training"
+ blurb = "Space is long and dark and empty."
+ grants_you = "more effective use of EVA gear"
+ modifiers = list(
+ // EVA gear speed modifier
+ SKILL_SPEED_MODIFIER = list(
+ SKILL_LEVEL_NONE = 1.1,
+ SKILL_LEVEL_NOVICE = 1,
+ SKILL_LEVEL_APPRENTICE = 1,
+ SKILL_LEVEL_JOURNEYMAN = 0.9,
+ SKILL_LEVEL_EXPERT = 0.8,
+ SKILL_LEVEL_MASTER = 0.75,
+ SKILL_LEVEL_LEGENDARY = 0.5,
+ ),
+ )
+ skill_flags = SKILL_ALWAYS_PRINT
+
+/datum/skill/eva/level_gained(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ mind.current?.update_equipment_speed_mods()
+
+/datum/skill/eva/level_lost(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ mind.current?.update_equipment_speed_mods()
+
+/// Getter for item slowdown
+/obj/item/proc/get_slowdown(mob/living/for_who)
+ return slowdown
+
+/obj/item/clothing/suit/space/get_slowdown(mob/living/for_who)
+ return slowdown * for_who.get_skill_modifier(/datum/skill/eva, SKILL_SPEED_MODIFIER)
+
+/obj/item/clothing/head/helmet/space/get_slowdown(mob/living/for_who)
+ return slowdown * for_who.get_skill_modifier(/datum/skill/eva, SKILL_SPEED_MODIFIER)
+
+/obj/item/clothing/head/mod/get_slowdown(mob/living/for_who)
+ return slowdown * for_who.get_skill_modifier(/datum/skill/eva, SKILL_SPEED_MODIFIER)
+
+/obj/item/clothing/suit/mod/get_slowdown(mob/living/for_who)
+ return slowdown * for_who.get_skill_modifier(/datum/skill/eva, SKILL_SPEED_MODIFIER)
+
+/obj/item/clothing/shoes/mod/get_slowdown(mob/living/for_who)
+ return slowdown * for_who.get_skill_modifier(/datum/skill/eva, SKILL_SPEED_MODIFIER)
+
+/obj/item/clothing/gloves/mod/get_slowdown(mob/living/for_who)
+ return slowdown * for_who.get_skill_modifier(/datum/skill/eva, SKILL_SPEED_MODIFIER)
+
+/obj/item/mod/control/get_slowdown(mob/living/for_who)
+ return slowdown * for_who.get_skill_modifier(/datum/skill/eva, SKILL_SPEED_MODIFIER)
diff --git a/code/datums/skills/firearms.dm b/code/datums/skills/firearms.dm
new file mode 100644
index 000000000000..46046058ffd3
--- /dev/null
+++ b/code/datums/skills/firearms.dm
@@ -0,0 +1,43 @@
+/datum/skill/firearms
+ name = "Firearms"
+ title = "Gunner"
+ blurb = "Did I fire six shots or only five? I lost count."
+ earned_by = "training at the firing range (or shooting people)"
+ grants_you = "reduced accuracy penalties when using firearms while wounded"
+ modifiers = list(
+ SKILL_RANDS_MODIFIER = list(
+ SKILL_LEVEL_NONE = 5,
+ SKILL_LEVEL_NOVICE = 0,
+ SKILL_LEVEL_APPRENTICE = -5,
+ SKILL_LEVEL_JOURNEYMAN = -5,
+ SKILL_LEVEL_EXPERT = -10,
+ SKILL_LEVEL_MASTER = -10,
+ SKILL_LEVEL_LEGENDARY = -20,
+ ),
+ )
+ skill_flags = SKILL_ALWAYS_PRINT
+
+/**
+ * Awards firearms XP to the firer of a projectile.
+ * Grants up to 100 xp
+ *
+ * * max_skill_level - If the firer's skill level is beyond this, no XP is awarded (equal is fine)
+ */
+/obj/projectile/proc/award_firearms_exp(max_skill_level = SKILL_LEVEL_LEGENDARY)
+ if(!isliving(firer))
+ return
+ var/mob/living/firer_mob = firer
+ if(isnull(firer_mob.mind) || firer_mob.mind.get_skill_level(/datum/skill/firearms) > max_skill_level)
+ return
+ var/xp_gain = 0
+ if(istype(fired_from, /obj/item/gun/energy))
+ var/obj/item/gun/energy/lasgun = fired_from
+ var/obj/item/ammo_casing/energy/lasgun_ammo = lasgun.ammo_type[lasgun.select]
+ xp_gain = istype(lasgun_ammo) ? clamp(lasgun_ammo.e_cost * 0.34, 0, 100) : 30
+ else if(istype(fired_from, /obj/item/gun/ballistic))
+ var/obj/item/gun/ballistic/balgun = fired_from
+ xp_gain = clamp(200 / (balgun.magazine?.max_ammo || 10), 0, 100)
+ if(xp_gain <= 0)
+ return
+ // closer hits give less xp, encourage actually aiming and not standing right by the target
+ firer_mob.mind.adjust_experience(/datum/skill/firearms, xp_gain * clamp(get_dist(firer, src) / 10, 0.2, 1.2))
diff --git a/code/datums/skills/fishing.dm b/code/datums/skills/fishing.dm
index 93c1a57d4417..6d4f1597cab6 100644
--- a/code/datums/skills/fishing.dm
+++ b/code/datums/skills/fishing.dm
@@ -5,16 +5,28 @@
/datum/skill/fishing
name = "Fishing"
title = "Angler"
- desc = "How empty and alone you are on this barren Earth."
- modifiers = list(SKILL_VALUE_MODIFIER = list(1, 0, -1, -3, -5, -7, -10))
+ blurb = "How empty and alone you are on this barren Earth."
+ earned_by = "attempting a fishing challenge"
+ grants_you = "reduced difficulty in fishing challenges"
+ modifiers = list(
+ SKILL_VALUE_MODIFIER = list(
+ SKILL_LEVEL_NONE = 1,
+ SKILL_LEVEL_NOVICE = 1,
+ SKILL_LEVEL_APPRENTICE = 0,
+ SKILL_LEVEL_JOURNEYMAN = -1,
+ SKILL_LEVEL_EXPERT = -2,
+ SKILL_LEVEL_MASTER = -4,
+ SKILL_LEVEL_LEGENDARY = -6,
+ ),
+ )
skill_item_path = /obj/item/clothing/head/soft/fishing_hat
/datum/skill/fishing/New()
. = ..()
- levelUpMessages[SKILL_LEVEL_NOVICE] = span_nicegreen("I'm starting to figure out what [name] really is! I can guess a fish size and weight at a glance.")
- levelUpMessages[SKILL_LEVEL_APPRENTICE] = span_nicegreen("I'm getting a little better at [name]! I can tell if a fish is hungry, dying and otherwise.")
- levelUpMessages[SKILL_LEVEL_JOURNEYMAN] = span_nicegreen("I feel like I've become quite proficient at [name]! I can tell what fishes I can catch at any given fishing spot.")
- levelUpMessages[SKILL_LEVEL_MASTER] = span_nicegreen("I've begun to truly understand the surprising depth behind [name]. As a master [title], I can guess what I'm going to catch now!")
+ level_up_messages[SKILL_LEVEL_NOVICE] = span_nicegreen("I'm starting to figure out what [name] really is! I can guess a fish size and weight at a glance.")
+ level_up_messages[SKILL_LEVEL_APPRENTICE] = span_nicegreen("I'm getting a little better at [name]! I can tell if a fish is hungry, dying and otherwise.")
+ level_up_messages[SKILL_LEVEL_JOURNEYMAN] = span_nicegreen("I feel like I've become quite proficient at [name]! I can tell what fishes I can catch at any given fishing spot.")
+ level_up_messages[SKILL_LEVEL_MASTER] = span_nicegreen("I've begun to truly understand the surprising depth behind [name]. As a master [title], I can guess what I'm going to catch now!")
/datum/skill/fishing/level_gained(datum/mind/mind, new_level, old_level, silent)
. = ..()
diff --git a/code/datums/skills/gaming.dm b/code/datums/skills/gaming.dm
index 75d90f3d8c0d..34111cfc5c00 100644
--- a/code/datums/skills/gaming.dm
+++ b/code/datums/skills/gaming.dm
@@ -1,13 +1,34 @@
/datum/skill/gaming
name = "Gaming"
title = "Gamer"
- desc = "My proficiency as a gamer. This helps me beat bosses with ease, powergame in Orion Trail, and makes me wanna slam some gamer fuel."
- modifiers = list(SKILL_PROBS_MODIFIER = list(0, 5, 10, 15, 15, 20, 25),
- SKILL_RANDS_MODIFIER = list(0, 1, 2, 3, 4, 5, 7))
+ blurb = "I'm a gamer, I have lots of lives."
+ earned_by = "winning arcade games (earning achievements also helps)"
+ grants_you = "greater skill in arcade games"
+ higher_levels_grant_you = "a taste for gamer fuel"
+ modifiers = list(
+ SKILL_PROBS_MODIFIER = list(
+ SKILL_LEVEL_NONE = 0,
+ SKILL_LEVEL_NOVICE = 5,
+ SKILL_LEVEL_APPRENTICE = 10,
+ SKILL_LEVEL_JOURNEYMAN = 15,
+ SKILL_LEVEL_EXPERT = 15,
+ SKILL_LEVEL_MASTER = 20,
+ SKILL_LEVEL_LEGENDARY = 25,
+ ),
+ SKILL_RANDS_MODIFIER = list(
+ SKILL_LEVEL_NONE = 0,
+ SKILL_LEVEL_NOVICE = 1,
+ SKILL_LEVEL_APPRENTICE = 2,
+ SKILL_LEVEL_JOURNEYMAN = 3,
+ SKILL_LEVEL_EXPERT = 4,
+ SKILL_LEVEL_MASTER = 5,
+ SKILL_LEVEL_LEGENDARY = 7,
+ ),
+ )
skill_item_path = /obj/item/clothing/neck/cloak/skill_reward/gaming
/datum/skill/gaming/New()
. = ..()
- levelUpMessages[1] = span_nicegreen("I'm starting to get a hang of the controls of these games...")
- levelUpMessages[4] = span_nicegreen("I'm starting to pick up the meta of these arcade games. If I were to minmax the optimal strat and accentuate my playstyle around well-refined tech...")
- levelUpMessages[6] = span_nicegreen("Through incredible determination and effort, I've reached the peak of my [name] abilities. I wonder how I can become any more powerful... Maybe gamer fuel would actually help me play better..?")
+ level_up_messages[SKILL_LEVEL_NOVICE] = span_nicegreen("I'm starting to get a hang of the controls of these games...")
+ level_up_messages[SKILL_LEVEL_JOURNEYMAN] = span_nicegreen("I'm starting to pick up the meta of these arcade games. If I were to minmax the optimal strat and accentuate my playstyle around well-refined tech...")
+ level_up_messages[SKILL_LEVEL_MASTER] = span_nicegreen("Through incredible determination and effort, I've reached the peak of my [name] abilities. I wonder how I can become any more powerful... Maybe gamer fuel would actually help me play better..?")
diff --git a/code/datums/skills/hydroponics.dm b/code/datums/skills/hydroponics.dm
new file mode 100644
index 000000000000..b9f6e8e935de
--- /dev/null
+++ b/code/datums/skills/hydroponics.dm
@@ -0,0 +1,7 @@
+/datum/skill/botany
+ name = "Botany"
+ title = "Botanist"
+ blurb = "We grow or we die."
+ earned_by = "growing plants"
+ higher_levels_grant_you = "guaranteed seed samples from plants with zero yield \
+ and safety around bees without a suit"
diff --git a/code/datums/skills/mechanics.dm b/code/datums/skills/mechanics.dm
new file mode 100644
index 000000000000..ca7b7d1be349
--- /dev/null
+++ b/code/datums/skills/mechanics.dm
@@ -0,0 +1,6 @@
+/datum/skill/mechanics
+ name = "Mechanics"
+ title = "Mechanical Engineer"
+ blurb = "I solve problems. Not problems like 'What is beauty?'... I solve practical problems."
+ earned_by = "repairing and building machines"
+ skill_flags = SKILL_ALWAYS_PRINT
diff --git a/code/datums/skills/medical.dm b/code/datums/skills/medical.dm
new file mode 100644
index 000000000000..28b86fafd2ba
--- /dev/null
+++ b/code/datums/skills/medical.dm
@@ -0,0 +1,29 @@
+/datum/skill/first_aid
+ name = "First Aid"
+ title = "Medic"
+ blurb = "A stitch in time saves nine."
+ earned_by = "healing members of the crew with sutures or bandages"
+ grants_you = "an improved proficiency medical tools such as sutures or bandages"
+ higher_levels_grant_you = "the ability do CPR without harming the patient"
+ modifiers = list(
+ SKILL_SPEED_MODIFIER = list(
+ SKILL_LEVEL_NONE = 1.15,
+ SKILL_LEVEL_NOVICE = 1,
+ SKILL_LEVEL_APPRENTICE = 1,
+ SKILL_LEVEL_JOURNEYMAN = 0.9,
+ SKILL_LEVEL_EXPERT = 0.9,
+ SKILL_LEVEL_MASTER = 0.8,
+ SKILL_LEVEL_LEGENDARY = 0.75,
+ ),
+ )
+ skill_flags = SKILL_ALWAYS_PRINT
+
+/datum/skill/first_aid/level_gained(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ if(new_level >= SKILL_LEVEL_JOURNEYMAN)
+ ADD_TRAIT(mind, TRAIT_CPR_CERTIFIED, type)
+
+/datum/skill/first_aid/level_lost(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ if(old_level >= SKILL_LEVEL_JOURNEYMAN && new_level < SKILL_LEVEL_JOURNEYMAN)
+ REMOVE_TRAIT(mind, TRAIT_CPR_CERTIFIED, type)
diff --git a/code/datums/skills/mining.dm b/code/datums/skills/mining.dm
index db79c2801a4c..950b40a784aa 100644
--- a/code/datums/skills/mining.dm
+++ b/code/datums/skills/mining.dm
@@ -1,6 +1,29 @@
/datum/skill/mining
name = "Mining"
title = "Miner"
- desc = "A dwarf's biggest skill, after drinking."
- modifiers = list(SKILL_SPEED_MODIFIER = list(1, 0.95, 0.9, 0.85, 0.75, 0.6, 0.5),SKILL_PROBS_MODIFIER=list(10, 15, 20, 25, 30, 35, 40))
+ blurb = "A dwarf's biggest skill, after drinking."
+ earned_by = "mining rare minerals"
+ grants_you = "an improved proficiency with mining tools"
+ higher_levels_grant_you = "the ability to see the contents of nearby rocks when mining"
+ modifiers = list(
+ SKILL_SPEED_MODIFIER = list(
+ SKILL_LEVEL_NONE = 1.1,
+ SKILL_LEVEL_NOVICE = 1,
+ SKILL_LEVEL_APPRENTICE = 0.9,
+ SKILL_LEVEL_JOURNEYMAN = 0.85,
+ SKILL_LEVEL_EXPERT = 0.75,
+ SKILL_LEVEL_MASTER = 0.6,
+ SKILL_LEVEL_LEGENDARY = 0.5,
+ ),
+ SKILL_PROBS_MODIFIER = list(
+ SKILL_LEVEL_NONE = 0,
+ SKILL_LEVEL_NOVICE = 0,
+ SKILL_LEVEL_APPRENTICE = 0,
+ SKILL_LEVEL_JOURNEYMAN = 20,
+ SKILL_LEVEL_EXPERT = 30,
+ SKILL_LEVEL_MASTER = 40,
+ SKILL_LEVEL_LEGENDARY = 50,
+ ),
+ )
skill_item_path = /obj/item/clothing/neck/cloak/skill_reward/mining
+ skill_flags = SKILL_ALWAYS_PRINT
diff --git a/code/datums/skills/piloting.dm b/code/datums/skills/piloting.dm
new file mode 100644
index 000000000000..8c9d69443d65
--- /dev/null
+++ b/code/datums/skills/piloting.dm
@@ -0,0 +1,27 @@
+/datum/skill/piloting
+ name = "Piloting"
+ title = "Pilot"
+ blurb = "Call the navigator, set course, and go!"
+ grants_you = "improved control over mechas and vehicles"
+ modifiers = list(
+ // reduces change of internal damage when taking damage in a mecha
+ SKILL_PROBS_MODIFIER = list(
+ SKILL_LEVEL_NONE = -5,
+ SKILL_LEVEL_NOVICE = -2.5,
+ SKILL_LEVEL_APPRENTICE = 0,
+ SKILL_LEVEL_JOURNEYMAN = 2,
+ SKILL_LEVEL_EXPERT = 4,
+ SKILL_LEVEL_MASTER = 5,
+ SKILL_LEVEL_LEGENDARY = 10,
+ ),
+ // affects turn speed. (not normal speed because that's kinda scary)
+ SKILL_SPEED_MODIFIER = list(
+ SKILL_LEVEL_NONE = 0.3,
+ SKILL_LEVEL_NOVICE = 0.2,
+ SKILL_LEVEL_APPRENTICE = 0,
+ SKILL_LEVEL_JOURNEYMAN = -0.1,
+ SKILL_LEVEL_EXPERT = -0.2,
+ SKILL_LEVEL_MASTER = -0.3,
+ SKILL_LEVEL_LEGENDARY = -0.5,
+ )
+ )
diff --git a/code/datums/skills/robotics.dm b/code/datums/skills/robotics.dm
new file mode 100644
index 000000000000..53ef42d9b713
--- /dev/null
+++ b/code/datums/skills/robotics.dm
@@ -0,0 +1,6 @@
+/datum/skill/robotics
+ name = "Robotics"
+ title = "Roboticist"
+ blurb = "We have the technology. We can rebuild him."
+ earned_by = "building and repairing cyborgs and robots"
+ skill_flags = SKILL_ALWAYS_PRINT
diff --git a/code/datums/skills/surgery.dm b/code/datums/skills/surgery.dm
new file mode 100644
index 000000000000..83559796dabe
--- /dev/null
+++ b/code/datums/skills/surgery.dm
@@ -0,0 +1,43 @@
+/datum/skill/surgery
+ name = "Surgery"
+ title = "Surgeon"
+ blurb = "Your capability to split someone's brain in two with a pen."
+ earned_by = "completing surgeries, though apprentices and above will only gain experience from operating on crewmembers. \
+ Autopsies will also give training regardless of skill level (with a bonus for non-human, non-monkey species)"
+ grants_you = "an improved proficiency with surgical tools"
+ higher_levels_grant_you = "the ability to perform more complex surgeries with worse (or improvised) tools and greater knowledge of entrails"
+ modifiers = list(
+ // modifier to surgery speed
+ SKILL_SPEED_MODIFIER = list(
+ SKILL_LEVEL_NONE = 1.15,
+ SKILL_LEVEL_NOVICE = 1.1,
+ SKILL_LEVEL_APPRENTICE = 1,
+ SKILL_LEVEL_JOURNEYMAN = 0.9,
+ SKILL_LEVEL_EXPERT = 0.9,
+ SKILL_LEVEL_MASTER = 0.8,
+ SKILL_LEVEL_LEGENDARY = 0.75,
+ ),
+ // flat modifier on tool effectiveness used in surgery
+ // note that this also affects surgery speed (so +10 roughly corresponds to a 0.9x speed modifier),
+ // but only surgeries that use items (which in practice, only excludes surgeries like "stomach pump")
+ SKILL_VALUE_MODIFIER = list(
+ SKILL_LEVEL_NONE = -10,
+ SKILL_LEVEL_NOVICE = 0,
+ SKILL_LEVEL_APPRENTICE = 0,
+ SKILL_LEVEL_JOURNEYMAN = 0,
+ SKILL_LEVEL_EXPERT = 10,
+ SKILL_LEVEL_MASTER = 10,
+ SKILL_LEVEL_LEGENDARY = 25,
+ ),
+ )
+ skill_flags = SKILL_ALWAYS_PRINT
+
+/datum/skill/surgery/level_gained(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ if(new_level >= SKILL_LEVEL_EXPERT)
+ ADD_TRAIT(mind, TRAIT_ENTRAILS_READER, type)
+
+/datum/skill/surgery/level_lost(datum/mind/mind, new_level, old_level, silent)
+ . = ..()
+ if(old_level >= SKILL_LEVEL_EXPERT && new_level < SKILL_LEVEL_EXPERT)
+ REMOVE_TRAIT(mind, TRAIT_ENTRAILS_READER, type)
diff --git a/code/datums/wires/airalarm.dm b/code/datums/wires/airalarm.dm
index 00291609871c..77a6cd81e7a0 100644
--- a/code/datums/wires/airalarm.dm
+++ b/code/datums/wires/airalarm.dm
@@ -56,7 +56,8 @@
var/obj/machinery/airalarm/A = holder
switch(wire)
if(WIRE_POWER) // Short out forever.
- A.shock(usr, 50)
+ // NON-MODULE CHANGE
+ A.shock(usr, 50 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
A.shorted = !mend
A.update_appearance()
if(WIRE_IDSCAN)
diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm
index 34467465b205..8a54f2afb719 100644
--- a/code/datums/wires/airlock.dm
+++ b/code/datums/wires/airlock.dm
@@ -139,7 +139,8 @@
if(WIRE_SHOCK) // Pulse to shock the door for 10 ticks.
if(!A.secondsElectrified)
A.set_electrified(MACHINE_DEFAULT_ELECTRIFY_TIME, usr)
- A.shock(usr, 100)
+ // NON-MODULE CHANGE
+ A.shock(usr, 100 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
@@ -169,15 +170,15 @@
A.regainMainPower()
else
A.loseMainPower()
- if(isliving(usr))
- A.shock(usr, 50)
+ // NON-MODULE CHANGE
+ A.shock(usr, 50 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_BACKUP1, WIRE_BACKUP2) // Cut to lose backup power, repair all to gain backup power.
if(mend && !is_cut(WIRE_BACKUP1) && !is_cut(WIRE_BACKUP2))
A.regainBackupPower()
else
A.loseBackupPower()
- if(isliving(usr))
- A.shock(usr, 50)
+ // NON-MODULE CHANGE
+ A.shock(usr, 50 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_BOLTS) // Cut to engage bolts, mend does nothing.
if(!mend)
A.bolt()
@@ -201,7 +202,8 @@
else
if(A.secondsElectrified != MACHINE_ELECTRIFIED_PERMANENT)
A.set_electrified(MACHINE_ELECTRIFIED_PERMANENT, usr)
- A.shock(usr, 100)
+ // NON-MODULE CHANGE
+ A.shock(usr, 100 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_SAFETY) // Cut to disable safeties, mend to re-enable.
A.safe = mend
if (!isnull(source))
@@ -214,8 +216,8 @@
A.lights = mend
A.update_appearance()
if(WIRE_ZAP1, WIRE_ZAP2) // Ouch.
- if(isliving(usr))
- A.shock(usr, 50)
+ // NON-MODULE CHANGE
+ A.shock(usr, 50 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_UNRESTRICTED_EXIT) // If this wire is cut, the unrestricted helper goes away. If you mend it, it'll go "haywire" and pick a new direction at random. Might have to cut/mend a time or two to get the direction you want.
if(!A.unres_sensor) //only works if the "sensor" is installed (a variable that we assign to the door either upon creation of a door with unrestricted directions, or if an unrestricted helper is added to a door in mapping)
return
@@ -228,7 +230,8 @@
/datum/wires/airlock/can_reveal_wires(mob/user)
- if(HAS_TRAIT(user, TRAIT_KNOW_ENGI_WIRES))
+ // NON-MODULE CHANGE
+ if(HAS_MIND_TRAIT(user, TRAIT_KNOW_ENGI_WIRES))
return TRUE
return ..()
diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm
index 50847df99437..d4f8b8561f2f 100644
--- a/code/datums/wires/apc.dm
+++ b/code/datums/wires/apc.dm
@@ -80,14 +80,16 @@
A.shorted = FALSE
else
A.shorted = TRUE
- A.shock(usr, 50)
+ // NON-MODULE CHANGE
+ A.shock(usr, 50 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_INTERFACE)
A.locked = !mend
if(WIRE_AI) // Disable AI control.
A.aidisabled = !mend
/datum/wires/apc/can_reveal_wires(mob/user)
- if(HAS_TRAIT(user, TRAIT_KNOW_ENGI_WIRES))
+ // NON-MODULE CHANGE
+ if(HAS_MIND_TRAIT(user, TRAIT_KNOW_ENGI_WIRES))
return TRUE
return ..()
diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm
index 75c3a3687602..69b603777484 100644
--- a/code/datums/wires/autolathe.dm
+++ b/code/datums/wires/autolathe.dm
@@ -47,4 +47,5 @@
if(WIRE_DISABLE)
A.disabled = !mend
if(WIRE_ZAP)
- A.shock(usr, 50)
+ // NON-MODULE CHANGE
+ A.shock(usr, 50 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
diff --git a/code/datums/wires/mecha.dm b/code/datums/wires/mecha.dm
index 07bc11901481..633c79706be8 100644
--- a/code/datums/wires/mecha.dm
+++ b/code/datums/wires/mecha.dm
@@ -73,6 +73,7 @@
return FALSE
/datum/wires/mecha/can_reveal_wires(mob/user)
- if(HAS_TRAIT(user, TRAIT_KNOW_ROBO_WIRES))
+ // NON-MODULE CHANGE
+ if(HAS_MIND_TRAIT(user, TRAIT_KNOW_ROBO_WIRES))
return TRUE
return ..()
diff --git a/code/datums/wires/mod.dm b/code/datums/wires/mod.dm
index 09274880367a..30b34e6952e2 100644
--- a/code/datums/wires/mod.dm
+++ b/code/datums/wires/mod.dm
@@ -57,6 +57,7 @@
return ..()
/datum/wires/mod/can_reveal_wires(mob/user)
- if(HAS_TRAIT(user, TRAIT_KNOW_ROBO_WIRES))
+ // NON-MODULE CHANGE
+ if(HAS_MIND_TRAIT(user, TRAIT_KNOW_ROBO_WIRES))
return TRUE
return ..()
diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm
index cf8d9b238867..222b53746089 100644
--- a/code/datums/wires/robot.dm
+++ b/code/datums/wires/robot.dm
@@ -105,7 +105,8 @@
log_silicon("[key_name(usr)] reset [key_name(R)]'s module via wire")
/datum/wires/robot/can_reveal_wires(mob/user)
- if(HAS_TRAIT(user, TRAIT_KNOW_ROBO_WIRES))
+ // NON-MODULE CHANGE
+ if(HAS_MIND_TRAIT(user, TRAIT_KNOW_ROBO_WIRES))
return TRUE
return ..()
diff --git a/code/datums/wires/roulette.dm b/code/datums/wires/roulette.dm
index f93bc3416999..d1a0cdf061f4 100644
--- a/code/datums/wires/roulette.dm
+++ b/code/datums/wires/roulette.dm
@@ -33,8 +33,8 @@
var/obj/machinery/roulette/R = holder
switch(wire)
if(WIRE_SHOCK)
- if(isliving(usr))
- R.shock(usr, 50)
+ // NON-MODULE CHANGE
+ R.shock(usr, 50 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_BOLTS) // Pulse to toggle bolts (but only raise if power is on).
if(!R.on)
return
@@ -44,8 +44,8 @@
R.audible_message(span_warning("Owner reset!"))
R.locked = FALSE
if(WIRE_PRIZEVEND)
- if(isliving(usr))
- R.shock(usr, 70)
+ // NON-MODULE CHANGE
+ R.shock(usr, 70- usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(R.locked)
return
R.audible_message(span_warning("Unauthorized prize vend detected! Locking down machine!"))
@@ -55,8 +55,8 @@
var/obj/machinery/roulette/R = holder
switch(wire)
if(WIRE_SHOCK)
- if(isliving(usr))
- R.shock(usr, 60)
+ // NON-MODULE CHANGE
+ R.shock(usr, 60- usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(mend)
R.on = TRUE
else
@@ -66,13 +66,12 @@
return
R.set_anchored(TRUE)
if(WIRE_RESETOWNER)
- if(isliving(usr))
- R.shock(usr, 70)
+ // NON-MODULE CHANGE
+ R.shock(usr, 70- usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(WIRE_PRIZEVEND)
- if(isliving(usr))
- R.shock(usr, 75)
+ // NON-MODULE CHANGE
+ R.shock(usr, 75- usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
if(R.locked)
return
R.audible_message(span_warning("Unauthorized prize vend detected! Locking down machine!"))
R.prize_theft(0.10)
-
diff --git a/code/datums/wires/suit_storage_unit.dm b/code/datums/wires/suit_storage_unit.dm
index 26ab49763dd8..31b01d745a03 100644
--- a/code/datums/wires/suit_storage_unit.dm
+++ b/code/datums/wires/suit_storage_unit.dm
@@ -32,8 +32,8 @@
if(WIRE_SAFETY)
SSU.safeties = !SSU.safeties
if(WIRE_ZAP)
- if(usr)
- SSU.shock(usr)
+ // NON-MODULE CHANGE
+ SSU.shock(usr, 100 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
/datum/wires/suit_storage_unit/on_cut(wire, mend, source)
var/obj/machinery/suit_storage_unit/SSU = holder
@@ -43,5 +43,5 @@
if(WIRE_SAFETY)
SSU.safeties = mend
if(WIRE_ZAP)
- if(usr)
- SSU.shock(usr)
+ // NON-MODULE CHANGE
+ SSU.shock(usr, 100 - usr.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER))
diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm
index 4e037f3e24b3..72c5850d3d9f 100644
--- a/code/datums/wires/vending.dm
+++ b/code/datums/wires/vending.dm
@@ -28,8 +28,10 @@
if(!..())
return FALSE
var/obj/machinery/vending/vending_machine = holder
- if(!issilicon(user) && vending_machine.seconds_electrified && vending_machine.shock(user, 100))
- return FALSE
+ if(vending_machine.seconds_electrified)
+ // NON-MODULE CHANGE
+ if(vending_machine.shock(user, 100 - user.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER)))
+ return FALSE
if(vending_machine.panel_open)
return TRUE
diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm
index 901ebeb3a378..048184374e45 100644
--- a/code/game/atom/_atom.dm
+++ b/code/game/atom/_atom.dm
@@ -686,8 +686,7 @@
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ATOM_CREATEDBY_PROCESSING, original_atom, chosen_option)
- if(user.mind)
- ADD_TRAIT(src, TRAIT_FOOD_CHEF_MADE, REF(user.mind))
+ handle_chef_made_food(src, original_atom, user.mind)
///Connect this atom to a shuttle
/atom/proc/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 24769984ea99..9cb82a0bb374 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -1130,17 +1130,13 @@
if(!delay && !tool_start_check(user, amount))
return
- var/skill_modifier = 1
-
- if(tool_behaviour == TOOL_MINING && ishuman(user))
- if(user.mind)
- skill_modifier = user.mind.get_skill_modifier(/datum/skill/mining, SKILL_SPEED_MODIFIER)
-
- if(user.mind.get_skill_level(/datum/skill/mining) >= SKILL_LEVEL_JOURNEYMAN && prob(user.mind.get_skill_modifier(/datum/skill/mining, SKILL_PROBS_MODIFIER))) // we check if the skill level is greater than Journeyman and then we check for the probality for that specific level.
- mineral_scan_pulse(get_turf(user), SKILL_LEVEL_JOURNEYMAN - 2) //SKILL_LEVEL_JOURNEYMAN = 3 So to get range of 1+ we have to subtract 2 from it,.
-
- delay *= toolspeed * skill_modifier
+ // NON-MODULE CHANGE
+ if(tool_behaviour == TOOL_MINING && user.mind)
+ delay *= user.mind.get_skill_modifier(/datum/skill/mining, SKILL_SPEED_MODIFIER)
+ if(prob(user.mind.get_skill_modifier(/datum/skill/mining, SKILL_PROBS_MODIFIER)))
+ mineral_scan_pulse(get_turf(user), 2)
+ delay *= toolspeed
// Play tool sound at the beginning of tool usage.
play_tool_sound(target, volume)
diff --git a/code/game/objects/items/food/donkpocket.dm b/code/game/objects/items/food/donkpocket.dm
index d4b4636f15c9..1e3b1d037a1c 100644
--- a/code/game/objects/items/food/donkpocket.dm
+++ b/code/game/objects/items/food/donkpocket.dm
@@ -25,6 +25,11 @@
/// The reagents that most child types add when microwaved. Needed because you can't override static lists.
var/static/list/child_added_reagents = list(/datum/reagent/medicine/omnizine = 2)
+// NON-MODULE CHANGE
+/obj/item/food/donkpocket/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_FOOD_MUST_INHERIT_CHEF_MADE, INNATE_TRAIT)
+
/obj/item/food/donkpocket/make_bakeable()
AddComponent(/datum/component/bakeable, warm_type, rand(baking_time_short, baking_time_long), TRUE, TRUE, added_reagents)
diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm
index 8886735f215f..03e381fab726 100644
--- a/code/game/objects/items/food/misc.dm
+++ b/code/game/objects/items/food/misc.dm
@@ -119,9 +119,21 @@
// We override the parent procs here to prevent burned messes from cooking into burned messes.
/obj/item/food/badrecipe/make_grillable()
return
+
/obj/item/food/badrecipe/make_bakeable()
return
+// Everyone thinks bad recipes are toxic unless you like gross food.
+/obj/item/food/badrecipe/make_edible()
+ . = ..()
+ AddComponent(/datum/component/edible, check_liked = CALLBACK(src, PROC_REF(check_liked)))
+
+/obj/item/food/badrecipe/proc/check_liked(mob/living/carbon/human/consumer)
+ if(consumer.get_liked_foodtypes() & GROSS)
+ return null
+ // ignores Ageusia
+ return FOOD_TOXIC
+
/obj/item/food/badrecipe/moldy
name = "moldy mess"
desc = "A rancid, disgusting culture of mold and ants. Somewhere under there, at some point, there was food."
diff --git a/code/game/objects/items/food/packaged.dm b/code/game/objects/items/food/packaged.dm
index b9f3065a2d2d..304c4fa4cdce 100644
--- a/code/game/objects/items/food/packaged.dm
+++ b/code/game/objects/items/food/packaged.dm
@@ -232,6 +232,11 @@
/// What reagents should be added when this item is warmed?
var/static/list/added_reagents = list(/datum/reagent/medicine/omnizine = 3)
+// NON-MODULE CHANGE
+/obj/item/food/ready_donk/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_FOOD_MUST_INHERIT_CHEF_MADE, INNATE_TRAIT)
+
/obj/item/food/ready_donk/make_bakeable()
AddComponent(/datum/component/bakeable, warm_type, rand(15 SECONDS, 20 SECONDS), TRUE, TRUE, added_reagents)
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 7d64c7d15aa3..3d5ba51e2e46 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -21,11 +21,6 @@
. |= bullethole_overlays
/obj/item/target/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit = FALSE)
- if(prob(25))
- return ..() // RNG change to just not leave a mark, like walls
- if(length(overlays) > 35)
- return ..() // Too many bullets, we're done here
-
// Projectiles which do not deal damage will not leave dent / scorch mark graphics.
// However we snowflake some projectiles to leave them anyway, because they're appropriate.
var/static/list/always_leave_marks
@@ -40,6 +35,11 @@
var/is_generic_projectile = !is_type_in_typecache(hitting_projectile, always_leave_marks)
if(is_generic_projectile && (is_invalid_damage || is_safe))
return ..() // Don't bother unless it's real shit
+ hitting_projectile.award_firearms_exp(SKILL_LEVEL_JOURNEYMAN)
+ if(prob(25))
+ return ..() // RNG change to just not leave a mark, like walls
+ if(length(overlays) > 35)
+ return ..() // Too many bullets, we're done here
var/p_x = hitting_projectile.p_x + pick(0, 0, 0, 0, 0, -1, 1) // really ugly way of coding "sometimes offset p_x!"
var/p_y = hitting_projectile.p_y + pick(0, 0, 0, 0, 0, -1, 1)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 128f854450d6..250cafc28e38 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -130,9 +130,10 @@
span_notice("You begin applying [src] on yourself..."),
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
)
+ // NON-MODULE CHANGE
if(!do_after(
user,
- self_delay * (auto_change_zone ? 1 : 0.9),
+ self_delay * (auto_change_zone ? 1 : 0.9) * (user.get_skill_modifier(/datum/skill/first_aid, SKILL_SPEED_MODIFIER)),
patient,
extra_checks = CALLBACK(src, PROC_REF(can_heal), patient, user, healed_zone),
))
@@ -149,9 +150,10 @@
span_notice("You begin applying [src] on [patient]..."),
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
)
+ // NON-MODULE CHANGE
if(!do_after(
user,
- other_delay * (auto_change_zone ? 1 : 0.9),
+ other_delay * (auto_change_zone ? 1 : 0.9) * (user.get_skill_modifier(/datum/skill/first_aid, SKILL_SPEED_MODIFIER)),
patient,
extra_checks = CALLBACK(src, PROC_REF(can_heal), patient, user, healed_zone),
))
@@ -178,6 +180,8 @@
else
CRASH("Stack medical item healing a non-carbon, non-animal mob [patient] ([patient.type])")
+ // NON-MODULE CHANGE
+ user.mind?.adjust_experience(/datum/skill/first_aid, user == patient ? 5 : 8)
log_combat(user, patient, "healed", src)
if(!use(1) || !repeating || amount <= 0)
var/atom/alert_loc = QDELETED(src) ? user : src
@@ -460,7 +464,8 @@
// gauze is only relevant for wounds, which are handled in the wounds themselves
/obj/item/stack/medical/gauze/try_heal(mob/living/patient, mob/living/user, healed_zone, silent, auto_change_zone)
var/obj/item/bodypart/limb = patient.get_bodypart(healed_zone)
- var/treatment_delay = (user == patient ? self_delay : other_delay)
+ // NON-MODULE CHANGE
+ var/treatment_delay = (user == patient ? self_delay : other_delay) * (user.get_skill_modifier(/datum/skill/first_aid, SKILL_SPEED_MODIFIER))
var/any_scanned = FALSE
for(var/datum/wound/woundies as anything in limb.wounds)
if(HAS_TRAIT(woundies, TRAIT_WOUND_SCANNED))
diff --git a/code/game/objects/items/storage/boxes/job_boxes.dm b/code/game/objects/items/storage/boxes/job_boxes.dm
index b64a225676db..b5d55ae72151 100644
--- a/code/game/objects/items/storage/boxes/job_boxes.dm
+++ b/code/game/objects/items/storage/boxes/job_boxes.dm
@@ -289,13 +289,25 @@
desc = "Contains spares of every science job skillchip."
/obj/item/storage/box/skillchips/science/PopulateContents()
- new/obj/item/skillchip/job/roboticist(src)
- new/obj/item/skillchip/job/roboticist(src)
+ // new/obj/item/skillchip/job/roboticist(src)
+ // new/obj/item/skillchip/job/roboticist(src)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/roboticist)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/roboticist)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/roboticist)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/scientist)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/scientist)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/scientist)
/obj/item/storage/box/skillchips/engineering
name = "box of engineering job skillchips"
desc = "Contains spares of every engineering job skillchip."
/obj/item/storage/box/skillchips/engineering/PopulateContents()
- new/obj/item/skillchip/job/engineer(src)
- new/obj/item/skillchip/job/engineer(src)
+ // new/obj/item/skillchip/job/engineer(src)
+ // new/obj/item/skillchip/job/engineer(src)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/station_engineer)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/station_engineer)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/station_engineer)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/atmospheric_technician)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/atmospheric_technician)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/atmospheric_technician)
diff --git a/code/modules/admin/skill_panel.dm b/code/modules/admin/skill_panel.dm
index ec80768276dc..a3a2aa6b705c 100644
--- a/code/modules/admin/skill_panel.dm
+++ b/code/modules/admin/skill_panel.dm
@@ -22,18 +22,29 @@
/datum/skill_panel/ui_data(mob/user) //Sends info about the skills to UI
. = list()
- if(user?.mind)
- for (var/type in GLOB.skill_types)
- var/datum/skill/S = GetSkillRef(type)
- var/lvl_num = targetmind.get_skill_level(type)
- var/lvl_name = uppertext(targetmind.get_skill_level_name(type))
- var/exp = targetmind.get_skill_exp(type)
- var/xp_prog_to_level = targetmind.exp_needed_to_level_up(type)
- var/xp_req_to_level = 0
- if (xp_prog_to_level)//is it even possible to level up?
- xp_req_to_level = SKILL_EXP_LIST[lvl_num+1] - SKILL_EXP_LIST[lvl_num]
- var/exp_percent = exp / SKILL_EXP_LIST[SKILL_LEVEL_LEGENDARY]
- .["skills"] += list(list("playername" = targetmind.current, "path" = type, "name" = S.name, "desc" = S.desc, "lvlnum" = lvl_num, "lvl" = lvl_name, "exp" = exp, "exp_prog" = xp_req_to_level - xp_prog_to_level, "exp_req" = xp_req_to_level, "exp_percent" = exp_percent, "max_exp" = SKILL_EXP_LIST[length(SKILL_EXP_LIST)]))
+ for (var/type in GLOB.skill_types)
+ var/datum/skill/S = GetSkillRef(type)
+ var/lvl_num = targetmind.get_skill_level(type)
+ var/lvl_name = uppertext(targetmind.get_skill_level_name(type))
+ var/exp = targetmind.get_skill_exp(type)
+ var/xp_prog_to_level = targetmind.exp_needed_to_level_up(type)
+ var/xp_req_to_level = 0
+ if (xp_prog_to_level)//is it even possible to level up?
+ xp_req_to_level = SKILL_EXP_LIST[lvl_num+1] - SKILL_EXP_LIST[lvl_num]
+ var/exp_percent = exp / SKILL_EXP_LIST[SKILL_LEVEL_LEGENDARY]
+ .["skills"] += list(list(
+ "playername" = targetmind.current,
+ "path" = type,
+ "name" = S.name,
+ "desc" = S.blurb,
+ "lvlnum" = lvl_num,
+ "lvl" = lvl_name,
+ "exp" = exp,
+ "exp_prog" = xp_req_to_level - xp_prog_to_level,
+ "exp_req" = xp_req_to_level,
+ "exp_percent" = exp_percent,
+ "max_exp" = SKILL_EXP_LIST[length(SKILL_EXP_LIST)],
+ ))
/datum/skill_panel/ui_act(action, params)
. = ..()
diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm
index e067c96889bf..697f5953be95 100644
--- a/code/modules/admin/verbs/ert.dm
+++ b/code/modules/admin/verbs/ert.dm
@@ -243,6 +243,15 @@
ert_operative.mind.add_antag_datum(ert_antag,ert_team)
ert_operative.mind.set_assigned_role(SSjob.GetJobType(ert_antag.ert_job_path))
+ // future melbert todo - tie to ert jobs, make ert jobs not one datum
+ ert_operative.mind.set_level(/datum/skill/electronics, SKILL_LEVEL_MASTER, silent = TRUE)
+ ert_operative.mind.set_level(/datum/skill/eva, SKILL_LEVEL_MASTER, silent = TRUE)
+ ert_operative.mind.set_level(/datum/skill/firearms, SKILL_LEVEL_MASTER, silent = TRUE)
+ ert_operative.mind.set_level(/datum/skill/first_aid, SKILL_LEVEL_MASTER, silent = TRUE)
+ ert_operative.mind.set_level(/datum/skill/athletics, SKILL_LEVEL_EXPERT, silent = TRUE)
+ ert_operative.mind.set_level(/datum/skill/mechanics, SKILL_LEVEL_MASTER, silent = TRUE)
+ ert_operative.mind.set_level(/datum/skill/surgery, SKILL_LEVEL_MASTER, silent = TRUE)
+ ert_operative.mind.set_level(/datum/skill/piloting, SKILL_LEVEL_EXPERT, silent = TRUE)
//Logging and cleanup
ert_operative.log_message("has been selected as \a [ert_antag.name].", LOG_GAME)
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index 3f533ce5d311..1b4267f302df 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -85,6 +85,15 @@
/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
add_team_hud(mob_override || owner.current, /datum/antagonist/nukeop)
+ // future melbert todo - tie to nukeop jobs
+ owner.set_level(/datum/skill/electronics, SKILL_LEVEL_MASTER, silent = TRUE)
+ owner.set_level(/datum/skill/eva, SKILL_LEVEL_MASTER, silent = TRUE)
+ owner.set_level(/datum/skill/firearms, SKILL_LEVEL_MASTER, silent = TRUE)
+ owner.set_level(/datum/skill/first_aid, SKILL_LEVEL_MASTER, silent = TRUE)
+ owner.set_level(/datum/skill/athletics, SKILL_LEVEL_EXPERT, silent = TRUE)
+ owner.set_level(/datum/skill/mechanics, SKILL_LEVEL_MASTER, silent = TRUE)
+ owner.set_level(/datum/skill/surgery, SKILL_LEVEL_MASTER, silent = TRUE)
+ owner.set_level(/datum/skill/piloting, SKILL_LEVEL_EXPERT, silent = TRUE)
/datum/antagonist/nukeop/proc/assign_nuke()
if(nuke_team && !nuke_team.tracked_nuke)
diff --git a/code/modules/bitrunning/job.dm b/code/modules/bitrunning/job.dm
index c0b5ab6d4da6..cf59da482a9a 100644
--- a/code/modules/bitrunning/job.dm
+++ b/code/modules/bitrunning/job.dm
@@ -31,6 +31,11 @@
rpg_title = "Recluse"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/electronics = SKILL_LEVEL_NOVICE,
+ /datum/skill/gaming = SKILL_LEVEL_APPRENTICE,
+ )
+
/datum/outfit/job/bitrunner
name = "Bitrunner"
jobtype = /datum/job/bitrunner
diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm
index afdfed8005d8..0a70e0928000 100644
--- a/code/modules/bitrunning/server/obj_generation.dm
+++ b/code/modules/bitrunning/server/obj_generation.dm
@@ -39,6 +39,13 @@
/obj/machinery/quantum_server/proc/generate_avatar(obj/structure/hololadder/wayout, datum/outfit/netsuit)
var/mob/living/carbon/human/avatar = new(wayout.loc)
+ avatar.mind_initialize()
+ avatar.mind.set_level(/datum/skill/eva, SKILL_LEVEL_MASTER, silent = TRUE)
+ avatar.mind.set_level(/datum/skill/firearms, SKILL_LEVEL_MASTER, silent = TRUE)
+ avatar.mind.set_level(/datum/skill/first_aid, SKILL_LEVEL_MASTER, silent = TRUE)
+ avatar.mind.set_level(/datum/skill/fishing, SKILL_LEVEL_JOURNEYMAN, silent = TRUE)
+ avatar.mind.set_level(/datum/skill/athletics, SKILL_LEVEL_EXPERT, silent = TRUE)
+
var/outfit_path = generated_domain.forced_outfit || netsuit
var/datum/outfit/to_wear = new outfit_path()
diff --git a/code/modules/food_and_drinks/machinery/deep_fryer.dm b/code/modules/food_and_drinks/machinery/deep_fryer.dm
index e694521ed449..a040b58e00e3 100644
--- a/code/modules/food_and_drinks/machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/machinery/deep_fryer.dm
@@ -182,8 +182,8 @@ GLOBAL_LIST_INIT(oilfry_blacklisted_items, typecacheof(list(
// Give them reagents to put frying oil in
if(isnull(frying.reagents))
frying.create_reagents(50, INJECTABLE)
- if(user.mind)
- ADD_TRAIT(frying, TRAIT_FOOD_CHEF_MADE, REF(user.mind))
+ // NON-MODULE CHANGE
+ handle_chef_made_food(frying, frying, user.mind, 0.25)
SEND_SIGNAL(frying, COMSIG_ITEM_ENTERED_FRYER)
flick("fryer_start", src) // NON-MODULE CHANGE
diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm
index 35c86bd48c43..c8c13e057606 100644
--- a/code/modules/food_and_drinks/recipes/food_mixtures.dm
+++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm
@@ -4,8 +4,14 @@
/datum/crafting_recipe/food/on_craft_completion(mob/user, atom/result)
SHOULD_CALL_PARENT(TRUE)
. = ..()
- if(istype(result) && !isnull(user.mind))
- ADD_TRAIT(result, TRAIT_FOOD_CHEF_MADE, REF(user.mind))
+ // NON-MODULE CHANGE
+ if(istype(result))
+ var/complexity = 1
+ if(istype(result, /obj/item/food))
+ var/obj/item/food/food = result
+ complexity = food.crafting_complexity
+
+ handle_chef_made_food(result, result, user.mind, complexity)
/datum/crafting_recipe/food/New()
. = ..()
diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm
index 521afd6b5390..c6cfd175958e 100644
--- a/code/modules/hydroponics/beekeeping/beebox.dm
+++ b/code/modules/hydroponics/beekeeping/beebox.dm
@@ -10,17 +10,18 @@
/mob/proc/bee_friendly()
return 0
-
-
+// NON-MODULE CHANGE
/mob/living/carbon/human/bee_friendly()
- if(dna && dna.species && dna.species.id == SPECIES_PODPERSON) //bees pollinate plants, duh.
- return 1
- if (wear_suit && head && isclothing(wear_suit) && isclothing(head))
+ if(ispodperson(src)) //bees pollinate plants, duh.
+ return TRUE
+ if(mind?.get_skill_level(/datum/skill/botany) >= SKILL_LEVEL_LEGENDARY)
+ return TRUE
+ if (isclothing(wear_suit) && isclothing(head))
var/obj/item/clothing/CS = wear_suit
var/obj/item/clothing/CH = head
if (CS.clothing_flags & CH.clothing_flags & THICKMATERIAL)
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/structure/beebox
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 0a46dd715b87..5030e3f0f0b8 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -121,7 +121,9 @@
. += span_notice("- [reagent_gene.get_name()] -")
/// Copy all the variables from one seed to a new instance of the same seed and return it.
-/obj/item/seeds/proc/Copy()
+// NON-MODULE CHANGE
+/obj/item/seeds/proc/Copy() as /obj/item/seeds
+ RETURN_TYPE(/obj/item/seeds)
var/obj/item/seeds/copy_seed = new type(null, TRUE)
// Copy all the stats
copy_seed.lifespan = lifespan
@@ -247,8 +249,15 @@
return
t_amount++
product_name = parent.myseed.plantname
+
+ // NON-MODULE CHANGE
if(product_count >= 1)
SSblackbox.record_feedback("tally", "food_harvested", product_count, product_name)
+ user.mind?.adjust_experience(/datum/skill/botany, 0.5 * rarity * (yield / MAX_PLANT_YIELD) * (potency / MAX_PLANT_POTENCY))
+
+ else if(product_count == 0 && user.mind?.get_skill_level(/datum/skill/botany) >= SKILL_LEVEL_MASTER)
+ Copy().forceMove(output_loc)
+
parent.update_tray(user, product_count)
return result
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 4fdd2e27ce69..1812dc2d4121 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -135,6 +135,9 @@
/// Minimal character age for this job
var/required_character_age
+ /// List of [typepath] to [base skill level] that this job starts with
+ var/list/base_skills
+
/// Priority for the job on the crew monitor.
var/crewmonitor_priority
@@ -164,6 +167,9 @@
if(liver && length(liver_traits))
liver.add_traits(liver_traits, JOB_TRAIT)
+ for(var/skill in base_skills)
+ spawned.mind.set_level(skill, base_skills[skill], silent = TRUE)
+
if(!ishuman(spawned))
return
diff --git a/code/modules/jobs/job_types/assistant/assistant.dm b/code/modules/jobs/job_types/assistant/assistant.dm
index 7bc80f7bb0e1..1ada99c68dd3 100644
--- a/code/modules/jobs/job_types/assistant/assistant.dm
+++ b/code/modules/jobs/job_types/assistant/assistant.dm
@@ -37,6 +37,12 @@ Assistant
rpg_title = "Lout"
config_tag = "ASSISTANT"
+ base_skills = list(
+ /datum/skill/electronics = SKILL_LEVEL_NOVICE,
+ /datum/skill/mechanics = SKILL_LEVEL_NOVICE,
+ /datum/skill/botany = SKILL_LEVEL_NOVICE,
+ )
+
/datum/job/assistant/get_outfit(consistent, title)
if(consistent)
return /datum/outfit/job/assistant/always_grey
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
index 82be5719f575..9abca3d2577a 100644
--- a/code/modules/jobs/job_types/atmospheric_technician.dm
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -39,6 +39,13 @@
job_flags = STATION_JOB_FLAGS
rpg_title = "Aeromancer"
+ base_skills = list(
+ /datum/skill/electronics = SKILL_LEVEL_NOVICE,
+ /datum/skill/eva = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/mechanics = SKILL_LEVEL_EXPERT,
+ )
+
/datum/outfit/job/atmos
name = "Atmospheric Technician"
jobtype = /datum/job/atmospheric_technician
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index 682523e841a4..a6449f18db15 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -35,6 +35,13 @@
job_flags = STATION_JOB_FLAGS
rpg_title = "Tavernkeeper"
+ base_skills = list(
+ /datum/skill/bartending = SKILL_LEVEL_EXPERT,
+ /datum/skill/cooking = SKILL_LEVEL_NOVICE,
+ /datum/skill/firearms = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE, // one (wo)man bouncer
+ )
+
/datum/job/bartender/award_service(client/winner, award)
winner.give_award(award, winner.mob)
diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm
index 8e28f92eb0ac..88058b626437 100644
--- a/code/modules/jobs/job_types/botanist.dm
+++ b/code/modules/jobs/job_types/botanist.dm
@@ -41,6 +41,12 @@
job_flags = STATION_JOB_FLAGS
rpg_title = "Gardener"
+ base_skills = list(
+ /datum/skill/botany = SKILL_LEVEL_EXPERT,
+ /datum/skill/chemistry = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/cooking = SKILL_LEVEL_NOVICE,
+ )
+
/datum/outfit/job/botanist
name = "Botanist"
jobtype = /datum/job/botanist
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index a239d1f9fcdd..ce4bec5d8516 100644
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -48,6 +48,12 @@
voice_of_god_power = 1.4 //Command staff has authority
+ base_skills = list(
+ /datum/skill/eva = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/firearms = SKILL_LEVEL_MASTER,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ )
/datum/job/captain/get_captaincy_announcement(mob/living/captain)
return "Captain [captain.real_name] on deck!"
diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm
index c544f8852292..3d9efdcd05de 100644
--- a/code/modules/jobs/job_types/cargo_technician.dm
+++ b/code/modules/jobs/job_types/cargo_technician.dm
@@ -34,6 +34,13 @@
rpg_title = "Merchantman"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/electronics = SKILL_LEVEL_NOVICE,
+ /datum/skill/firearms = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/mechanics = SKILL_LEVEL_NOVICE,
+ /datum/skill/piloting = SKILL_LEVEL_NOVICE, // ripley
+ )
title_options = list(
"Mail Carrier",
)
diff --git a/code/modules/jobs/job_types/chaplain/chaplain.dm b/code/modules/jobs/job_types/chaplain/chaplain.dm
index 295bb6f28de6..1b6ffea9487c 100644
--- a/code/modules/jobs/job_types/chaplain/chaplain.dm
+++ b/code/modules/jobs/job_types/chaplain/chaplain.dm
@@ -36,6 +36,13 @@
job_tone = "holy"
+ // future todo : grant these skills when selecting a sect, not by default.
+ base_skills = list(
+ /datum/skill/firearms = SKILL_LEVEL_APPRENTICE, // chaplain gun
+ /datum/skill/first_aid = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/cybernetics = SKILL_LEVEL_APPRENTICE, // robot sect
+ /datum/skill/botany = SKILL_LEVEL_APPRENTICE,
+ )
title_options = list(
"Magister",
)
@@ -129,4 +136,4 @@
satchel = /obj/item/storage/backpack/cultpack
chameleon_extras = /obj/item/stamp/chap
- skillchips = list(/obj/item/skillchip/entrails_reader)
+ // skillchips = list(/obj/item/skillchip/entrails_reader)
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index a50ed6fcdcbf..ddc002d90d55 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -37,6 +37,11 @@
rpg_title = "Alchemist"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/surgery = SKILL_LEVEL_NOVICE,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/chemistry = SKILL_LEVEL_EXPERT,
+ )
title_options = list(
"Pharmacist",
)
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index 66200d081205..132df68c2087 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -48,6 +48,13 @@
voice_of_god_power = 1.4 //Command staff has authority
+ base_skills = list(
+ /datum/skill/electronics = SKILL_LEVEL_MASTER,
+ /datum/skill/eva = SKILL_LEVEL_EXPERT,
+ /datum/skill/firearms = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/mechanics = SKILL_LEVEL_MASTER,
+ )
/datum/job/chief_engineer/after_spawn(mob/living/spawned, client/player_client)
. = ..()
@@ -82,7 +89,7 @@
box = /obj/item/storage/box/survival/engineer
chameleon_extras = /obj/item/stamp/head/ce
- skillchips = list(/obj/item/skillchip/job/engineer)
+ // skillchips = list(/obj/item/skillchip/job/engineer)
pda_slot = ITEM_SLOT_LPOCKET
/datum/outfit/job/ce/mod
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index a030a1898e46..9dbbed3e2d2c 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -46,6 +46,16 @@
voice_of_god_power = 1.4 //Command staff has authority
+ base_skills = list(
+ /datum/skill/chemistry = SKILL_LEVEL_EXPERT,
+ /datum/skill/cleaning = SKILL_LEVEL_NOVICE,
+ /datum/skill/cybernetics = SKILL_LEVEL_EXPERT,
+ /datum/skill/eva = SKILL_LEVEL_NOVICE,
+ /datum/skill/firearms = SKILL_LEVEL_NOVICE,
+ /datum/skill/first_aid = SKILL_LEVEL_MASTER,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/surgery = SKILL_LEVEL_MASTER,
+ )
/datum/job/chief_medical_officer/get_captaincy_announcement(mob/living/captain)
return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!"
@@ -81,7 +91,7 @@
/obj/item/gun/syringe,
/obj/item/stamp/head/cmo,
)
- skillchips = list(/obj/item/skillchip/entrails_reader)
+ // skillchips = list(/obj/item/skillchip/entrails_reader)
/datum/outfit/job/cmo/mod
name = "Chief Medical Officer (MODsuit)"
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
index d786d26d13f0..f80c514088d6 100644
--- a/code/modules/jobs/job_types/clown.dm
+++ b/code/modules/jobs/job_types/clown.dm
@@ -73,7 +73,7 @@
box = /obj/item/storage/box/survival/hug
chameleon_extras = /obj/item/stamp/clown
implants = list(/obj/item/implant/sad_trombone)
- skillchips = list(/obj/item/skillchip/job/clown)
+ // skillchips = list(/obj/item/skillchip/job/clown)
/datum/outfit/job/clown/mod
name = "Clown (MODsuit)"
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
index 852589aac0f3..0f13a041cbcf 100644
--- a/code/modules/jobs/job_types/cook.dm
+++ b/code/modules/jobs/job_types/cook.dm
@@ -48,6 +48,13 @@
rpg_title = "Tavern Chef"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/bartending = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/botany = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/cooking = SKILL_LEVEL_EXPERT, // not all NT chefs are gordon ramsay
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ )
+
/datum/job/cook/award_service(client/winner, award)
winner.give_award(award, winner.mob)
diff --git a/code/modules/jobs/job_types/coroner.dm b/code/modules/jobs/job_types/coroner.dm
index e72f9eaedc61..36846d4de007 100644
--- a/code/modules/jobs/job_types/coroner.dm
+++ b/code/modules/jobs/job_types/coroner.dm
@@ -43,6 +43,12 @@
rpg_title = "Undertaker"
+ base_skills = list(
+ /datum/skill/surgery = SKILL_LEVEL_EXPERT,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ )
+
/datum/outfit/job/coroner
name = "Coroner"
jobtype = /datum/job/coroner
@@ -71,4 +77,4 @@
duffelbag = /obj/item/storage/backpack/duffelbag/coroner
messenger = /obj/item/storage/backpack/messenger/coroner
- skillchips = list(/obj/item/skillchip/entrails_reader)
+ // skillchips = list(/obj/item/skillchip/entrails_reader)
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
index 5e41e016a2fc..60478b82c7b9 100644
--- a/code/modules/jobs/job_types/curator.dm
+++ b/code/modules/jobs/job_types/curator.dm
@@ -42,6 +42,11 @@
"Librarian",
)
+ base_skills = list(
+ /datum/skill/eva = SKILL_LEVEL_EXPERT,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ )
+
/datum/outfit/job/curator
name = "Curator"
jobtype = /datum/job/curator
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index 2a735333813f..ee20d3ce80bf 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -49,6 +49,12 @@
job_tone = "objection"
+ base_skills = list(
+ /datum/skill/firearms = SKILL_LEVEL_EXPERT,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/surgery = SKILL_LEVEL_NOVICE,
+ )
/datum/outfit/job/detective
name = "Detective"
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
index 3a3bb465e809..5475c64114af 100644
--- a/code/modules/jobs/job_types/head_of_personnel.dm
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -43,6 +43,9 @@
job_flags = STATION_JOB_FLAGS | HEAD_OF_STAFF_JOB_FLAGS
voice_of_god_power = 1.4 //Command staff has authority
+ base_skills = list(
+ /datum/skill/firearms = SKILL_LEVEL_APPRENTICE,
+ )
/datum/job/head_of_personnel/get_captaincy_announcement(mob/living/captain)
return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!"
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index 3e06f43d50e9..958a1cc0ae23 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -39,6 +39,13 @@
voice_of_god_power = 1.4 //Command staff has authority
+ base_skills = list(
+ /datum/skill/eva = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/firearms = SKILL_LEVEL_MASTER,
+ /datum/skill/first_aid = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/piloting = SKILL_LEVEL_APPRENTICE,
+ )
/datum/job/head_of_security/get_captaincy_announcement(mob/living/captain)
return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!"
diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm
index 0cb2fbf6a9e7..bf3837708d92 100644
--- a/code/modules/jobs/job_types/janitor.dm
+++ b/code/modules/jobs/job_types/janitor.dm
@@ -33,6 +33,13 @@
job_tone = "slip"
+ base_skills = list(
+ /datum/skill/cleaning = SKILL_LEVEL_NOVICE, // i'd make this higher, but i think grinding cleaning skill IS janitor's gameplay
+ /datum/skill/firearms = SKILL_LEVEL_APPRENTICE, // garbage day
+ /datum/skill/chemistry = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ )
+
/datum/outfit/job/janitor
name = "Janitor"
jobtype = /datum/job/janitor
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index f5ef7e3511c2..f3ad49d96dc9 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -42,6 +42,14 @@
rpg_title = "Cleric"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/chemistry = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/cleaning = SKILL_LEVEL_NOVICE,
+ /datum/skill/cybernetics = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/first_aid = SKILL_LEVEL_EXPERT,
+ /datum/skill/surgery = SKILL_LEVEL_EXPERT,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ )
/datum/outfit/job/doctor
name = "Medical Doctor"
@@ -63,7 +71,7 @@
box = /obj/item/storage/box/survival/medical
chameleon_extras = /obj/item/gun/syringe
- skillchips = list(/obj/item/skillchip/entrails_reader)
+ // skillchips = list(/obj/item/skillchip/entrails_reader)
/datum/outfit/job/doctor/nurse
name = "Nurse"
diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm
index 3413135d1506..7451aea61367 100644
--- a/code/modules/jobs/job_types/paramedic.dm
+++ b/code/modules/jobs/job_types/paramedic.dm
@@ -38,6 +38,13 @@
rpg_title = "Corpse Runner"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/chemistry = SKILL_LEVEL_NOVICE,
+ /datum/skill/eva = SKILL_LEVEL_EXPERT,
+ /datum/skill/first_aid = SKILL_LEVEL_EXPERT,
+ /datum/skill/surgery = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ )
/datum/outfit/job/paramedic
name = "Paramedic"
diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm
index f1f2a97d8ecf..d83fd8e9d170 100644
--- a/code/modules/jobs/job_types/prisoner.dm
+++ b/code/modules/jobs/job_types/prisoner.dm
@@ -25,6 +25,11 @@
rpg_title = "Defeated Miniboss"
job_flags = STATION_JOB_FLAGS | JOB_CANNOT_OPEN_SLOTS & ~JOB_REOPEN_ON_ROUNDSTART_LOSS
+ base_skills = list(
+ /datum/skill/botany = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ )
+
/datum/job/prisoner/New()
. = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED, PROC_REF(handle_prisoner_joining))
diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm
index a8b9bfb2ca84..811ff01e3796 100644
--- a/code/modules/jobs/job_types/quartermaster.dm
+++ b/code/modules/jobs/job_types/quartermaster.dm
@@ -38,6 +38,11 @@
voice_of_god_power = 1.4 //Command staff has authority
ignore_human_authority = TRUE
+ base_skills = list(
+ /datum/skill/firearms = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ )
+
/datum/outfit/job/quartermaster
name = "Quartermaster"
jobtype = /datum/job/quartermaster
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
index 9377365e5490..ccf994bc7624 100644
--- a/code/modules/jobs/job_types/research_director.dm
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -47,6 +47,17 @@
voice_of_god_power = 1.4 //Command staff has authority
+ base_skills = list(
+ /datum/skill/chemistry = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/cybernetics = SKILL_LEVEL_MASTER,
+ /datum/skill/electronics = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/eva = SKILL_LEVEL_NOVICE,
+ /datum/skill/firearms = SKILL_LEVEL_NOVICE,
+ /datum/skill/mechanics = SKILL_LEVEL_NOVICE,
+ /datum/skill/robotics = SKILL_LEVEL_EXPERT,
+ /datum/skill/surgery = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/piloting = SKILL_LEVEL_JOURNEYMAN,
+ )
/datum/job/research_director/get_captaincy_announcement(mob/living/captain)
return "Due to staffing shortages, newly promoted Acting Captain [captain.real_name] on deck!"
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
index 4e64001196f6..acf12b03a2f3 100644
--- a/code/modules/jobs/job_types/roboticist.dm
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -38,6 +38,16 @@
rpg_title = "Necromancer"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/cybernetics = SKILL_LEVEL_EXPERT,
+ /datum/skill/electronics = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/eva = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ /datum/skill/mechanics = SKILL_LEVEL_NOVICE,
+ /datum/skill/piloting = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/robotics = SKILL_LEVEL_EXPERT,
+ /datum/skill/surgery = SKILL_LEVEL_JOURNEYMAN,
+ )
/datum/job/roboticist/New()
. = ..()
@@ -59,7 +69,7 @@
duffelbag = /obj/item/storage/backpack/duffelbag/science
pda_slot = ITEM_SLOT_LPOCKET
- skillchips = list(/obj/item/skillchip/job/roboticist)
+ // skillchips = list(/obj/item/skillchip/job/roboticist)
/datum/outfit/job/roboticist/mod
name = "Roboticist (MODsuit)"
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index 72d145bd2961..8d18bf7ebd75 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -39,6 +39,11 @@
job_tone = "boom"
+ base_skills = list(
+ /datum/skill/surgery = SKILL_LEVEL_NOVICE,
+ /datum/skill/mechanics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/chemistry = SKILL_LEVEL_JOURNEYMAN,
+ )
/datum/outfit/job/scientist
name = "Scientist"
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index d13edc9bbb85..6f2d31416307 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -43,6 +43,14 @@
rpg_title = "Guard"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/eva = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/firearms = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/piloting = SKILL_LEVEL_APPRENTICE,
+ )
+
/datum/job/security_officer/get_titles(only_selectable = FALSE)
. = ..()
if(!only_selectable)
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
index dca51b2463a0..63b932d6c7a6 100644
--- a/code/modules/jobs/job_types/shaft_miner.dm
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -28,6 +28,14 @@
rpg_title = "Adventurer"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/eva = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/firearms = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/mining = SKILL_LEVEL_NOVICE, // i'd make this higher, but i think grinding mining skill IS mining's gameplay
+ /datum/skill/piloting = SKILL_LEVEL_NOVICE,
+ )
/datum/outfit/job/miner
name = "Shaft Miner"
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index 0a4c4009d13d..7f5027ffc575 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -43,6 +43,12 @@
rpg_title = "Crystallomancer"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/electronics = SKILL_LEVEL_EXPERT,
+ /datum/skill/mechanics = SKILL_LEVEL_EXPERT,
+ /datum/skill/eva = SKILL_LEVEL_EXPERT,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ )
/datum/outfit/job/engineer
name = "Station Engineer"
@@ -68,7 +74,7 @@
box = /obj/item/storage/box/survival/engineer
pda_slot = ITEM_SLOT_LPOCKET
- skillchips = list(/obj/item/skillchip/job/engineer)
+ // skillchips = list(/obj/item/skillchip/job/engineer)
/datum/outfit/job/engineer/gloved
name = "Station Engineer (Gloves)"
diff --git a/code/modules/jobs/job_types/station_trait/bridge_assistant.dm b/code/modules/jobs/job_types/station_trait/bridge_assistant.dm
index a86ac83d6149..d2fdb63168da 100644
--- a/code/modules/jobs/job_types/station_trait/bridge_assistant.dm
+++ b/code/modules/jobs/job_types/station_trait/bridge_assistant.dm
@@ -35,6 +35,11 @@
job_flags = STATION_JOB_FLAGS | STATION_TRAIT_JOB_FLAGS
ignore_human_authority = TRUE
+ base_skills = list(
+ /datum/skill/firearms = SKILL_LEVEL_NOVICE,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ )
+
/datum/job/bridge_assistant/after_spawn(mob/living/spawned, client/player_client)
. = ..()
ADD_TRAIT(spawned, TRAIT_NO_TWOHANDING, JOB_TRAIT)
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index 6fd101975edf..049ccf766dca 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -41,6 +41,12 @@
rpg_title = "Plague Doctor"
job_flags = STATION_JOB_FLAGS
+ base_skills = list(
+ /datum/skill/chemistry = SKILL_LEVEL_EXPERT,
+ /datum/skill/cleaning = SKILL_LEVEL_NOVICE,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/surgery = SKILL_LEVEL_APPRENTICE,
+ )
/datum/outfit/job/virologist
name = "Virologist"
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index 96135196a1f9..e732f8a976fe 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -41,6 +41,12 @@
rpg_title = "Jailor"
job_flags = STATION_JOB_FLAGS | JOB_BOLD_SELECT_TEXT
+ base_skills = list(
+ /datum/skill/firearms = SKILL_LEVEL_EXPERT,
+ /datum/skill/first_aid = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ )
+
/datum/outfit/job/warden
name = "Warden"
jobtype = /datum/job/warden
diff --git a/code/modules/library/skill_learning/job_skillchips/_job.dm b/code/modules/library/skill_learning/job_skillchips/_job.dm
index 87f2d47ac9cd..4572baae4d6b 100644
--- a/code/modules/library/skill_learning/job_skillchips/_job.dm
+++ b/code/modules/library/skill_learning/job_skillchips/_job.dm
@@ -9,3 +9,73 @@
slot_use = 2
#undef SKILLCHIP_CATEGORY_JOB
+
+/obj/item/skillchip/job/skills
+ skill_icon = FA_ICON_BRIEFCASE
+ /// Asooc list skillchip typepath => amount of exp to give
+ var/list/exp_to_give = list()
+
+/obj/item/skillchip/job/skills/Initialize(mapload, is_removable, job_type)
+ . = ..()
+ if(isnull(job_type))
+ return INITIALIZE_HINT_QDEL
+ var/datum/job/job_datum = SSjob.GetJobType(job_type)
+ if(!length(job_datum.base_skills))
+ stack_trace("Skill job skillchip on a job with no skills, USELESS. (job type: [job_type])")
+ return INITIALIZE_HINT_QDEL
+
+ name = "[job_datum.title] Skillchip"
+ desc = "A basic skillchip designed to give you the foundational skills needed to perform the duties of a [job_datum.title]."
+
+ var/list/skill_names = list()
+ for(var/datum/skill/skill as anything in job_datum.base_skills)
+ if(initial(skill.skill_flags) & SKILL_PHYSICAL)
+ continue
+ exp_to_give[skill] = SKILL_EXP_LIST[job_datum.base_skills[skill]]
+ skill_names += initial(skill.name)
+
+ skill_name = "[job_datum.title] Basics"
+ skill_description = "Grants you greater abilities in [english_list(skill_names)]."
+
+ activate_message = span_notice("You feel like a real [job_datum.title]!")
+ deactivate_message = span_notice("You no longer feel like a [job_datum.title].")
+
+/obj/item/skillchip/job/skills/on_activate(mob/living/carbon/user, silent)
+ . = ..()
+ give_skills(user.mind)
+ RegisterSignal(user, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF, PROC_REF(mind_lost))
+ RegisterSignal(user, COMSIG_MOB_MIND_TRANSFERRED_INTO, PROC_REF(mind_gained))
+
+/obj/item/skillchip/job/skills/on_deactivate(mob/living/carbon/user, silent)
+ . = ..()
+ remove_skills(user.mind)
+ UnregisterSignal(user, COMSIG_MOB_MIND_TRANSFERRED_OUT_OF)
+ UnregisterSignal(user, COMSIG_MOB_MIND_TRANSFERRED_INTO)
+
+/obj/item/skillchip/job/skills/proc/give_skills(datum/mind/to_who)
+ if(isnull(to_who))
+ return
+ for(var/skill in exp_to_give)
+ to_who.set_experience(skill, max(to_who.get_skill_exp(skill), exp_to_give[skill]), TRUE)
+
+/obj/item/skillchip/job/skills/proc/remove_skills(datum/mind/from_who)
+ if(isnull(from_who))
+ return
+ for(var/skill in exp_to_give)
+ from_who.adjust_experience(skill, -exp_to_give[skill], TRUE)
+
+/obj/item/skillchip/job/skills/proc/mind_lost(mob/living/old_mind, mob/living/new_mind)
+ SIGNAL_HANDLER
+ remove_skills(old_mind)
+ give_skills(new_mind)
+
+/obj/item/skillchip/job/skills/proc/mind_gained(mob/living/new_mind, mob/living/old_mind)
+ SIGNAL_HANDLER
+ remove_skills(old_mind)
+ give_skills(new_mind)
+
+// For admins
+/obj/item/skillchip/job/skills/engineering
+
+/obj/item/skillchip/job/skills/engineering/Initialize(mapload, is_removable, job_type)
+ return ..(mapload, is_removable, /datum/job/station_engineer)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 2825d51dc082..2c4dd128afcc 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -105,6 +105,7 @@
if(!hitting_projectile.is_hostile_projectile())
return BULLET_ACT_HIT
+ hitting_projectile.award_firearms_exp(isnull(mind) ? SKILL_LEVEL_JOURNEYMAN : SKILL_LEVEL_LEGENDARY)
// we need a second, silent armor check to actually know how much to reduce damage taken, as opposed to
// on [/atom/proc/bullet_act] where it's just to pass it to the projectile's on_hit().
var/armor_check = min(ARMOR_MAX_BLOCK, check_projectile_armor(def_zone, hitting_projectile, is_silent = TRUE))
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c77111dd8117..17114c212566 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1476,13 +1476,13 @@
var/immutable_speedies = 0
for(var/obj/item/thing in get_equipped_speed_mod_items())
if(thing.item_flags & IMMUTABLE_SLOW)
- immutable_speedies += thing.slowdown
+ immutable_speedies += thing.get_slowdown(src) // NON-MODULE CHANGE
else
- speedies += thing.slowdown
+ speedies += thing.get_slowdown(src) // NON-MODULE CHANGE
//if we have TRAIT_STURDY_FRAME, we reduce our overall speed penalty UNLESS that penalty would be a negative value, and therefore a speed boost.
if(speedies > 0 && HAS_TRAIT(src, TRAIT_STURDY_FRAME))
- speedies *= 0.2
+ speedies *= 0.8 // NON-MODULE CHANGE
if(immutable_speedies)
add_or_update_variable_movespeed_modifier(
diff --git a/code/modules/modular_computers/file_system/programs/skill_tracker.dm b/code/modules/modular_computers/file_system/programs/skill_tracker.dm
index bd208dcef524..f0c5e3d2bf81 100644
--- a/code/modules/modular_computers/file_system/programs/skill_tracker.dm
+++ b/code/modules/modular_computers/file_system/programs/skill_tracker.dm
@@ -29,14 +29,17 @@
var/list/skilldata = list(
"name" = skill.name,
- "desc" = skill.desc,
+ "blurb" = skill.blurb,
+ "earned_by" = skill.earned_by,
+ "grants_you" = skill.grants_you,
+ "higher_levels_grant_you" = skill.higher_levels_grant_you,
"title" = skill.title,
"lvl_name" = lvl_name
)
if (exp && xp_req_to_level)
skilldata["progress_percent"] = (xp_req_to_level-xp_prog_to_level)/xp_req_to_level
skilldata["overall_percent"] = exp / SKILL_EXP_LIST[length(SKILL_EXP_LIST)]
- if (lvl_num >= length(SKILL_EXP_LIST) && !(type in targetmind.skills_rewarded))
+ if (lvl_num >= length(SKILL_EXP_LIST) && !(type in targetmind.skills_rewarded) && ispath(skill.skill_item_path))
skilldata["reward"] = TRUE
skills[++skills.len] = skilldata
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index e2c9fd86d58a..94fedc0e60df 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -179,7 +179,8 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
if(T.underfloor_accessibility < UNDERFLOOR_INTERACTABLE)
return
if(W.tool_behaviour == TOOL_WIRECUTTER)
- if (shock(user, 50))
+ // NON-MODULE CHANGE
+ if (shock(user, 50 - user.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER)))
return
user.visible_message(span_notice("[user] cuts the cable."), span_notice("You cut the cable."))
investigate_log("was cut by [key_name(usr)] in [AREACOORD(src)]", INVESTIGATE_WIRES)
@@ -188,7 +189,8 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
else if(W.tool_behaviour == TOOL_MULTITOOL)
to_chat(user, get_power_info())
- shock(user, 5, 0.2)
+ // NON-MODULE CHANGE
+ shock(user, 5 - user.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER), 0.2)
add_fingerprint(user)
@@ -622,7 +624,8 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
use(1)
- if(C.shock(user, 50))
+ // NON-MODULE CHANGE
+ if(C.shock(user, 50 - user.get_skill_modifier(/datum/skill/electronics, SKILL_PROBS_MODIFIER)))
if(prob(50)) //fail
C.deconstruct()
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 22d3c398fb4a..2da8fc6c6bd0 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -118,7 +118,7 @@
data = taste_amounts
/datum/reagent/consumable/nutriment/get_taste_description(mob/living/taster)
- return data
+ return LAZYLEN(data) ? data - "quality_modifier" : null // NON-MODULE CHANGE
/datum/reagent/consumable/nutriment/vitamin
name = "Vitamin"
diff --git a/code/modules/surgery/autopsy.dm b/code/modules/surgery/autopsy.dm
index 42ed52bb6cac..2c72c040b9bd 100644
--- a/code/modules/surgery/autopsy.dm
+++ b/code/modules/surgery/autopsy.dm
@@ -33,17 +33,29 @@
span_notice("[user] uses [tool] on [target]'s chest."),
)
-/datum/surgery_step/autopsy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/autopsy_scanner/tool, datum/surgery/surgery, default_display_results = FALSE)
+/datum/surgery_step/autopsy/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/autopsy_scanner/tool, datum/surgery/surgery, default_display_results = FALSE)
+ // NON-MODULE CHANGE
+ var/xp_given = 200 // some alien species
+ if(isalien(target))
+ xp_given *= 2.5 // truly foreign
+ if(ishumanbasic(target) || isfelinid(target) || ismonkey(target))
+ xp_given *= 0.25 // well documented
+ if(HAS_TRAIT(target, TRAIT_SURGICALLY_ANALYZED))
+ xp_given *= 0 // this body has already been cut open! useless
+
ADD_TRAIT(target, TRAIT_DISSECTED, AUTOPSY_TRAIT)
- if(!HAS_TRAIT(src, TRAIT_SURGICALLY_ANALYZED))
- ADD_TRAIT(target, TRAIT_SURGICALLY_ANALYZED, AUTOPSY_TRAIT)
+ ADD_TRAIT(target, TRAIT_SURGICALLY_ANALYZED, AUTOPSY_TRAIT)
+
tool.scan_cadaver(user, target)
var/obj/machinery/computer/operating/operating_computer = surgery.locate_operating_computer(get_turf(target))
if (!isnull(operating_computer))
SEND_SIGNAL(operating_computer, COMSIG_OPERATING_COMPUTER_AUTOPSY_COMPLETE, target)
- if(HAS_MIND_TRAIT(user, TRAIT_MORBID) && ishuman(user))
- var/mob/living/carbon/human/morbid_weirdo = user
- morbid_weirdo.add_mood_event("morbid_dissection_success", /datum/mood_event/morbid_dissection_success)
+
+ if(HAS_MIND_TRAIT(user, TRAIT_MORBID))
+ user.add_mood_event("morbid_dissection_success", /datum/mood_event/morbid_dissection_success)
+ xp_given *= 1.5 // truly something worth seeing!
+
+ user.mind?.adjust_experience(/datum/skill/surgery, xp_given)
return ..()
/datum/surgery_step/autopsy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm
index 4a63a741d67d..744bfac22cc8 100644
--- a/code/modules/surgery/prosthetic_replacement.dm
+++ b/code/modules/surgery/prosthetic_replacement.dm
@@ -115,6 +115,10 @@
pain_message = "You feel synthetic sensation wash from your [parse_zone(target_zone)], which you can feel again!",
mechanical_surgery = TRUE,
)
+ // NON-MODULE CHANGE
+ target.cause_pain(bodypart_to_attach.body_zone, -1 * user.get_skill_modifier(/datum/skill/cybernetics, SKILL_VALUE_MODIFIER))
+ if(IS_ROBOTIC_LIMB(bodypart_to_attach))
+ user.mind?.adjust_experience(/datum/skill/cybernetics, 100)
return
else
var/obj/item/bodypart/bodypart_to_attach = target.newBodyPart(target_zone)
@@ -134,6 +138,7 @@
pain_message = "You feel a strange sensation from your new [parse_zone(target_zone)].",
mechanical_surgery = TRUE,
)
+ user.mind?.adjust_experience(/datum/skill/cybernetics, 200)
if(istype(tool, /obj/item/chainsaw))
qdel(tool)
var/obj/item/chainsaw/mounted_chainsaw/new_arm = new(target)
diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm
index 63f73559a2c9..da6d918ac98b 100644
--- a/code/modules/surgery/surgery_step.dm
+++ b/code/modules/surgery/surgery_step.dm
@@ -93,8 +93,12 @@
if(check_morbid_curiosity(user, tool, surgery))
speed_mod *= SURGERY_SPEED_MORBID_CURIOSITY
+ // NON-MODULE CHANGE
if(implement_type && (implements[implement_type] > 0)) //this means it isn't a require hand or any item step.
- speed_mod *= (1 / (implements[implement_type] / 100.0))
+ speed_mod *= (1 / ((implements[implement_type] + user.get_skill_modifier(/datum/skill/surgery, SKILL_VALUE_MODIFIER)) / 100.0))
+
+ // NON-MODULE CHANGE
+ speed_mod *= user.get_skill_modifier(/datum/skill/surgery, SKILL_SPEED_MODIFIER)
speed_mod *= surgery.speed_modifier
@@ -119,6 +123,9 @@
if((prob(100-fail_prob) || (iscyborg(user) && !silicons_obey_prob)) && chem_check_result && !try_to_fail)
if(success(user, target, target_zone, tool, surgery))
+ // NON-MODULE CHANGE
+ if(user.mind && (target.mind || user.mind.get_skill_level(/datum/skill/surgery) <= SKILL_LEVEL_NOVICE) && !iscyborg(user)) // by default, you only gain surgery xp for operating on players. no monkey grinding
+ user.mind.adjust_experience(/datum/skill/surgery, time * 0.5) // 1 xp per 2 second of surgery - 50 xp for brain surgery
play_success_sound(user, target, target_zone, tool, surgery)
advance = TRUE
else
diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm
index f0acc84381ee..799235e47e33 100644
--- a/code/modules/vehicles/mecha/_mecha.dm
+++ b/code/modules/vehicles/mecha/_mecha.dm
@@ -905,3 +905,16 @@
act.button_icon_state = "mech_lights_off"
balloon_alert(occupant, "lights [mecha_flags & LIGHTS_ON ? "on":"off"]")
act.build_all_button_icons()
+
+/obj/vehicle/sealed/mecha/proc/get_driver_skill(category)
+ var/best_piloting_skill = null
+ for(var/mob/living/driver in return_drivers())
+ var/driver_skill = driver.get_skill_modifier(/datum/skill/piloting, category)
+ if(category == SKILL_SPEED_MODIFIER)
+ driver_skill *= -1 // lower is better for speed
+ if(isnull(best_piloting_skill) || driver_skill > best_piloting_skill)
+ best_piloting_skill = driver_skill
+
+ if(category == SKILL_SPEED_MODIFIER)
+ best_piloting_skill *= -1 // revert speed back
+ return best_piloting_skill || 0
diff --git a/code/modules/vehicles/mecha/mecha_damage.dm b/code/modules/vehicles/mecha/mecha_damage.dm
index 8a06aaf298fa..ef57535cf8cb 100644
--- a/code/modules/vehicles/mecha/mecha_damage.dm
+++ b/code/modules/vehicles/mecha/mecha_damage.dm
@@ -26,7 +26,7 @@
/obj/vehicle/sealed/mecha/proc/try_deal_internal_damage(damage)
if(damage < internal_damage_threshold)
return
- if(!prob(internal_damage_probability))
+ if(!prob(internal_damage_probability - get_driver_skill(SKILL_PROBS_MODIFIER)))
return
var/internal_damage_to_deal = possible_int_damage
internal_damage_to_deal &= ~internal_damage
diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm
index 375b47e59bbd..2be33bdac4e5 100644
--- a/code/modules/vehicles/mecha/mecha_movement.dm
+++ b/code/modules/vehicles/mecha/mecha_movement.dm
@@ -130,6 +130,9 @@
if(dir != direction && !(mecha_flags & QUIET_TURNS) && !step_silent)
playsound(src,turnsound,40,TRUE)
setDir(direction)
+ // sets move cd again, accounting for skill this time
+ var/turn_speed = movedelay + get_driver_skill(SKILL_SPEED_MODIFIER)
+ COOLDOWN_START(src, cooldown_vehicle_move, turn_speed)
if(keyheld || !pivot_step) //If we pivot step, we don't return here so we don't just come to a stop
return TRUE
diff --git a/maplestation.dme b/maplestation.dme
index 810417f44853..64288e54292d 100644
--- a/maplestation.dme
+++ b/maplestation.dme
@@ -1793,10 +1793,23 @@
#include "code\datums\shuttles\whiteship.dm"
#include "code\datums\skills\_skill.dm"
#include "code\datums\skills\athletics.dm"
+#include "code\datums\skills\bartending.dm"
+#include "code\datums\skills\chemistry.dm"
#include "code\datums\skills\cleaning.dm"
+#include "code\datums\skills\cooking.dm"
+#include "code\datums\skills\cybernetic.dm"
+#include "code\datums\skills\electrics.dm"
+#include "code\datums\skills\eva.dm"
+#include "code\datums\skills\firearms.dm"
#include "code\datums\skills\fishing.dm"
#include "code\datums\skills\gaming.dm"
+#include "code\datums\skills\hydroponics.dm"
+#include "code\datums\skills\mechanics.dm"
+#include "code\datums\skills\medical.dm"
#include "code\datums\skills\mining.dm"
+#include "code\datums\skills\piloting.dm"
+#include "code\datums\skills\robotics.dm"
+#include "code\datums\skills\surgery.dm"
#include "code\datums\station_traits\_station_trait.dm"
#include "code\datums\station_traits\admin_panel.dm"
#include "code\datums\station_traits\job_traits.dm"
diff --git a/maplestation_modules/code/__DEFINES/_module_defines.dm b/maplestation_modules/code/__DEFINES/_module_defines.dm
index 34266b33578b..4fb2560091e2 100644
--- a/maplestation_modules/code/__DEFINES/_module_defines.dm
+++ b/maplestation_modules/code/__DEFINES/_module_defines.dm
@@ -14,8 +14,6 @@
/// Essentially a buffed version of TRAIT_VIRUS_RESISTANCE, but not as strong as TRAIT_VIRUS_IMMUNE.
/// Outright prevents contraction of disease, but if you do get sick, you're not immune to it.
#define TRAIT_VIRUS_CONTACT_IMMUNE "virus_contact_immune"
-/// Does not harm patients when undergoing CPR
-#define TRAIT_CPR_CERTIFIED "cpr_certified"
/// Defines for speech sounds
#define SOUND_NORMAL "normal"
diff --git a/maplestation_modules/code/datums/pain/pain.dm b/maplestation_modules/code/datums/pain/pain.dm
index bd4efc0871e4..62673ab41698 100644
--- a/maplestation_modules/code/datums/pain/pain.dm
+++ b/maplestation_modules/code/datums/pain/pain.dm
@@ -582,11 +582,11 @@
if(-INFINITY to 0)
pass()
if(1)
- to_chat(parent, span_userdanger("You feel your heart beat irregularly."))
+ to_chat(parent, span_userdanger("Your pulse starts to feel irregular."))
if(2)
- to_chat(parent, span_userdanger("You feel your heart skip a beat."))
+ to_chat(parent, span_userdanger("Your heart skips a beat."))
else
- to_chat(parent, span_userdanger("You feel your body shutting down!"))
+ to_chat(parent, span_userdanger("Your body starts shutting down!"))
else
heart_attack_counter = 0
@@ -623,6 +623,11 @@
penalty += chest.get_modified_pain() * 0.5
penalty += head?.get_modified_pain() * 0.5 // HARS guard
penalty /= 3
+ // Factor in firearms skill
+ if(penalty > 0)
+ penalty += user.get_skill_modifier(/datum/skill/firearms, SKILL_RANDS_MODIFIER)
+ if(penalty <= 0)
+ return
// Applying min and max
bonus_spread_values[MIN_BONUS_SPREAD_INDEX] += floor(penalty / 3)
bonus_spread_values[MAX_BONUS_SPREAD_INDEX] += floor(penalty)
diff --git a/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm b/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm
index 15e397704b56..777a6dc09b8c 100644
--- a/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm
@@ -50,6 +50,13 @@
rpg_title = "Royal Guard"
crewmonitor_priority = 9 // after cap, right before sec
+ base_skills = list(
+ /datum/skill/firearms = SKILL_LEVEL_MASTER,
+ /datum/skill/first_aid = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/piloting = SKILL_LEVEL_APPRENTICE,
+ )
+
/datum/outfit/job/asset_protection
name = "Asset Protection"
jobtype = /datum/job/asset_protection
diff --git a/maplestation_modules/code/modules/jobs/job_types/assistant.dm b/maplestation_modules/code/modules/jobs/job_types/assistant.dm
index 6f2d981cd32a..301350f7f3db 100644
--- a/maplestation_modules/code/modules/jobs/job_types/assistant.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/assistant.dm
@@ -2,6 +2,23 @@
/datum/job/assistant
departments_bitflags = DEPARTMENT_BITFLAG_ASSISTANT
+/datum/job/assistant/after_spawn(mob/living/spawned, client/player_client)
+ . = ..()
+ var/list/skill_pool = list(
+ /datum/skill/athletics,
+ /datum/skill/bartending,
+ /datum/skill/chemistry,
+ /datum/skill/cleaning,
+ /datum/skill/cooking,
+ /datum/skill/electronics,
+ /datum/skill/firearms,
+ /datum/skill/first_aid,
+ /datum/skill/mechanics,
+ /datum/skill/surgery,
+ )
+ for(var/i in 1 to rand(3, floor(length(skill_pool) * 0.5))) // give a few random skills to work with
+ spawned.mind.adjust_experience(pick_n_take(skill_pool), round(rand(100, 750), 50), TRUE)
+
// This is done for loadouts, otherwise unique uniforms would be deleted.
/datum/outfit/job/assistant
uniform = null
diff --git a/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm b/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm
index 49bcfe5c97ce..d45bcb840b64 100644
--- a/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm
@@ -63,6 +63,14 @@
rpg_title = "Guildperson"
crewmonitor_priority = 60.1 // after HOP, before rest of service
+ base_skills = list(
+ /datum/skill/cleaning = SKILL_LEVEL_NOVICE,
+ /datum/skill/firearms = SKILL_LEVEL_NOVICE,
+ /datum/skill/first_aid = SKILL_LEVEL_NOVICE,
+ /datum/skill/bartending = SKILL_LEVEL_NOVICE,
+ /datum/skill/cooking = SKILL_LEVEL_NOVICE,
+ )
+
/datum/outfit/job/bridge_officer
name = "Bridge Officer"
jobtype = /datum/job/bridge_officer
diff --git a/maplestation_modules/code/modules/jobs/job_types/ordnance_tech.dm b/maplestation_modules/code/modules/jobs/job_types/ordnance_tech.dm
index 7de7f987ae3b..3f5bc54f927d 100644
--- a/maplestation_modules/code/modules/jobs/job_types/ordnance_tech.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/ordnance_tech.dm
@@ -45,6 +45,11 @@
rpg_title = "Dwarven Miner"
crewmonitor_priority = 35
+ base_skills = list(
+ /datum/skill/surgery = SKILL_LEVEL_NOVICE,
+ /datum/skill/mechanics = SKILL_LEVEL_APPRENTICE,
+ )
+
/datum/outfit/job/scientist/ordnance_tech
name = "Ordnance Technician"
suit = /obj/item/clothing/suit/toggle/labcoat/toxic
diff --git a/maplestation_modules/code/modules/jobs/job_types/stowaway.dm b/maplestation_modules/code/modules/jobs/job_types/stowaway.dm
index 6946170645ca..6f4aa98e5efc 100644
--- a/maplestation_modules/code/modules/jobs/job_types/stowaway.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/stowaway.dm
@@ -1,3 +1,12 @@
+#define STOWAWAY_SKILLS list( \
+ /datum/skill/athletics, \
+ /datum/skill/chemistry, \
+ /datum/skill/electronics, \
+ /datum/skill/firearms, \
+ /datum/skill/first_aid, \
+ /datum/skill/mechanics, \
+)
+
/datum/job/stowaway
title = "Stowaway"
description = "Sneak aboard the station, end up worse off than you had it before. \
@@ -39,6 +48,10 @@
[span_notice("(If you would like to be provided an optional, random backstory, with more or less equipment: [backstory_ref].)")]\
"))
+ var/list/skill_pool = STOWAWAY_SKILLS
+ for(var/i in 1 to rand(3, length(skill_pool) - 1)) // give a few random skills to work with
+ spawned.mind.adjust_experience(pick_n_take(skill_pool), round(rand(100, 750), 50), TRUE)
+
// Applied to fresh stowaways to give them an option of getting a random backstory
/datum/status_effect/backstory
id = "stowaway_backstory"
@@ -55,10 +68,14 @@
if(SSticker.current_state != GAME_STATE_PLAYING)
return
+ for(var/skill in STOWAWAY_SKILLS) // wipe out existing rng skills
+ owner.mind.set_level(skill, SKILL_LEVEL_NONE, TRUE)
+
var/backstory_gist
var/backstory_suggested_goal
var/backstory_equipment
var/list/backstory_equipment_items
+ var/list/backstory_skills
var/mob/living/carbon/human/stowaway = owner
switch(rand(1, 7))
@@ -76,6 +93,11 @@
/obj/item/clothing/gloves/color/yellow = ITEM_SLOT_BACKPACK,
)
backstory_equipment = "A toolbelt and some insulated gloves."
+ backstory_skills = list(
+ /datum/skill/athletics = SKILL_LEVEL_NOVICE,
+ /datum/skill/mechanics = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/electronics = SKILL_LEVEL_JOURNEYMAN,
+ )
if(3)
var/old_boss = pick_list(COMPANY_FILE, "bad_companies")
@@ -88,6 +110,11 @@
(stowaway.jumpsuit_style == PREF_SKIRT ? /obj/item/clothing/under/syndicate/skirt : /obj/item/clothing/under/syndicate) = ITEM_SLOT_BACKPACK,
)
backstory_equipment = "A syndicate turtleneck and mask, and some insulated combat gloves."
+ backstory_skills = list(
+ /datum/skill/athletics = SKILL_LEVEL_APPRENTICE,
+ /datum/skill/firearms = SKILL_LEVEL_JOURNEYMAN,
+ /datum/skill/first_aid = SKILL_LEVEL_APPRENTICE,
+ )
if(4)
var/old_boss = pick_list(COMPANY_FILE, "good_companies")
@@ -109,6 +136,7 @@
)
list_clear_nulls(backstory_equipment_items) // if the job doesn't have a head/shoes/whatever, don't spawn it
backstory_equipment = "Your old uniform."
+ backstory_skills = old_job.base_skills
if(6)
backstory_gist = "You woke up randomly in the maintenance tunnels, with no memory of who you are or how you got here."
@@ -120,14 +148,16 @@
backstory_suggested_goal = "Find a new life on board the station."
- var/final_info = "[backstory_gist]\n\n[backstory_suggested_goal]"
+ var/final_info = "[backstory_gist]
[backstory_suggested_goal]"
if(length(backstory_equipment_items) && backstory_equipment)
- final_info += span_notice("\n\nAdditional equipment: [backstory_equipment]")
+ final_info += span_notice("
Additional equipment: [backstory_equipment]")
to_chat(owner, examine_block(span_infoplain(final_info)))
for(var/thing in backstory_equipment_items)
owner.equip_to_slot_if_possible(new thing(owner.loc), backstory_equipment_items[thing], disable_warning = TRUE, redraw_mob = FALSE, initial = TRUE)
+ for(var/skill in backstory_skills)
+ owner.mind.set_level(skill, backstory_skills[skill], TRUE)
qdel(src)
@@ -200,6 +230,8 @@
trim_state = "trim_stationengineer" // for posterity, doesn't show anyways
department_color = COLOR_ASSISTANT_GRAY
+#undef STOWAWAY_SKILLS
+
// Old toolbox subtype that spawns with a multitool
/obj/item/storage/toolbox/mechanical/old/multitool
diff --git a/maplestation_modules/code/modules/jobs/job_types/xenobiologist.dm b/maplestation_modules/code/modules/jobs/job_types/xenobiologist.dm
index 70acc0863d20..92716a13c92e 100644
--- a/maplestation_modules/code/modules/jobs/job_types/xenobiologist.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/xenobiologist.dm
@@ -50,6 +50,11 @@
rpg_title = "Beast Tamer"
crewmonitor_priority = 34
+ base_skills = list(
+ /datum/skill/surgery = SKILL_LEVEL_NOVICE,
+ /datum/skill/chemistry = SKILL_LEVEL_JOURNEYMAN,
+ )
+
/datum/outfit/job/scientist/xenobiologist
name = "Xenobiologist"
suit = /obj/item/clothing/suit/toggle/labcoat/xenobio
diff --git a/maplestation_modules/code/modules/library/skill_learning/job_skillchips/medbay.dm b/maplestation_modules/code/modules/library/skill_learning/job_skillchips/medbay.dm
index 561d5d3f83df..f3c631337d43 100644
--- a/maplestation_modules/code/modules/library/skill_learning/job_skillchips/medbay.dm
+++ b/maplestation_modules/code/modules/library/skill_learning/job_skillchips/medbay.dm
@@ -12,28 +12,23 @@
auto_traits = list(TRAIT_CPR_CERTIFIED)
complexity = 0 // it's pretty minor, all things considered
-/datum/outfit/job/doctor/New()
- . = ..()
- LAZYADD(skillchips, /obj/item/skillchip/job/cpr)
-
-/datum/outfit/job/paramedic/New()
- . = ..()
- LAZYADD(skillchips, /obj/item/skillchip/job/cpr)
-
-/datum/outfit/job/cmo/New()
- . = ..()
- LAZYADD(skillchips, /obj/item/skillchip/job/cpr)
-
/obj/item/storage/box/skillchips/medbay
name = "box of medbay skillchips"
desc = "Contains spares of every medical job skillchip."
/obj/item/storage/box/skillchips/medbay/PopulateContents()
- new /obj/item/skillchip/job/cpr(src)
- new /obj/item/skillchip/job/cpr(src)
- new /obj/item/skillchip/job/cpr(src)
- new /obj/item/skillchip/job/cpr(src)
- new /obj/item/skillchip/entrails_reader(src)
+ // new /obj/item/skillchip/job/cpr(src)
+ // new /obj/item/skillchip/job/cpr(src)
+ // new /obj/item/skillchip/job/cpr(src)
+ // new /obj/item/skillchip/job/cpr(src)
+// new /obj/item/skillchip/entrails_reader(src)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/chemist)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/chemist)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/coroner)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/doctor)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/doctor)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/paramedic)
+ new /obj/item/skillchip/job/skills(src, null, /datum/job/virologist)
/obj/structure/closet/secure_closet/chief_medical/PopulateContents()
. = ..()
diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/cpr.dm b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/cpr.dm
index 6d744297e45e..11f4a1281820 100644
--- a/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/cpr.dm
+++ b/maplestation_modules/code/modules/mob/living/carbon/human/heart_rework/cpr.dm
@@ -133,7 +133,7 @@
target.share_blood_on_touch(src)
// check panic state
- var/cpr_certified = HAS_TRAIT(src, TRAIT_CPR_CERTIFIED)
+ var/cpr_certified = HAS_MIND_TRAIT(src, TRAIT_CPR_CERTIFIED)
var/should_panic = beat >= BEATS_PER_CPR_CYCLE + 1 && target.get_bpm() <= 0
if(panicking)
if(!should_panic)
diff --git a/tgstation.dme b/tgstation.dme
index 240a4d88b036..d09562f524a0 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1795,10 +1795,22 @@
#include "code\datums\shuttles\whiteship.dm"
#include "code\datums\skills\_skill.dm"
#include "code\datums\skills\athletics.dm"
+#include "code\datums\skills\bartending.dm"
+#include "code\datums\skills\chemistry.dm"
#include "code\datums\skills\cleaning.dm"
+#include "code\datums\skills\cooking.dm"
+#include "code\datums\skills\cybernetic.dm"
+#include "code\datums\skills\electrics.dm"
+#include "code\datums\skills\eva.dm"
+#include "code\datums\skills\firearms.dm"
#include "code\datums\skills\fishing.dm"
#include "code\datums\skills\gaming.dm"
+#include "code\datums\skills\hydroponics.dm"
+#include "code\datums\skills\mechanics.dm"
+#include "code\datums\skills\medical.dm"
#include "code\datums\skills\mining.dm"
+#include "code\datums\skills\robotics.dm"
+#include "code\datums\skills\surgery.dm"
#include "code\datums\station_traits\_station_trait.dm"
#include "code\datums\station_traits\admin_panel.dm"
#include "code\datums\station_traits\job_traits.dm"
diff --git a/tgui/packages/tgui/interfaces/NtosSkillTracker.jsx b/tgui/packages/tgui/interfaces/NtosSkillTracker.jsx
deleted file mode 100644
index b2eedb6c7caa..000000000000
--- a/tgui/packages/tgui/interfaces/NtosSkillTracker.jsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import {
- AnimatedNumber,
- BlockQuote,
- Button,
- ProgressBar,
- Section,
- Table,
-} from 'tgui-core/components';
-
-import { useBackend } from '../backend';
-import { NtosWindow } from '../layouts';
-
-export const NtosSkillTracker = (props) => {
- const { act, data } = useBackend();
- const { skills = {} } = data;
- return (
-
-
-
- {skills.map((skill, idx) => (
-
- {skill.desc}
-
-
-
-
- Level
-
- Level Progress
- Overall Progress
-
-
-
- {skill.lvl_name}
-
-
- {skill.progress_percent ? (
-
-
- %
-
- ) : (
- '—'
- )}
-
-
- {skill.overall_percent ? (
-
-
- %
-
- ) : (
- '—'
- )}
-
-
- {!!skill.reward && (
-
-
-
-
-
- )}
-
-
-
- ))}
-
-
-
- );
-};
diff --git a/tgui/packages/tgui/interfaces/NtosSkillTracker.tsx b/tgui/packages/tgui/interfaces/NtosSkillTracker.tsx
new file mode 100644
index 000000000000..3be09e915f7e
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/NtosSkillTracker.tsx
@@ -0,0 +1,135 @@
+import {
+ AnimatedNumber,
+ BlockQuote,
+ Button,
+ ProgressBar,
+ Section,
+ Table,
+} from 'tgui-core/components';
+import { BooleanLike } from 'tgui-core/react';
+
+import { useBackend } from '../backend';
+import { NtosWindow } from '../layouts';
+
+type Data = {
+ skills: Skill[];
+};
+
+type Skill = {
+ name: string;
+ title: string;
+ blurb: string;
+ earned_by?: string;
+ grants_you?: string;
+ higher_levels_grant_you?: string;
+ lvl_name: string;
+ progress_percent: number;
+ overall_percent: number;
+ reward: BooleanLike;
+};
+
+export const NtosSkillTracker = () => {
+ const { act, data } = useBackend();
+ const { skills } = data;
+
+ return (
+
+
+
+ {skills
+ .sort((a, b) => (a.name > b.name ? 1 : -1))
+ .map((skill, idx) => (
+
+
+ {skill.blurb}
+
+ {!!skill.earned_by && (
+
+ {'>'} Earned by {skill.earned_by}.
+
+ )}
+ {!!skill.grants_you && (
+
+ {'>'} Grants you {skill.grants_you}.
+
+ )}
+ {!!skill.higher_levels_grant_you && (
+
+ {'>'} At higher levels, you gain{' '}
+ {skill.higher_levels_grant_you}.
+
+ )}
+
+
+
+
+ Level
+
+ Level Progress
+
+ Overall Progress
+
+
+
+
+ {skill.lvl_name}
+
+
+ {skill.progress_percent ? (
+
+
+ %
+
+ ) : (
+ '—'
+ )}
+
+
+ {skill.overall_percent ? (
+
+
+ %
+
+ ) : (
+ '—'
+ )}
+
+
+ {!!skill.reward && (
+
+
+
+
+
+ )}
+
+
+
+ ))}
+
+
+
+ );
+};