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 && ( + + + + + + )} +
+
+
+ ))} +
+
+
+ ); +};