From 536381d308c7a11ad3c502c46b3ca256cd283003 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 13 Dec 2023 20:21:27 -0600 Subject: [PATCH] Fitness rebalance and improvements - mood, fireman carry, and longer workouts (#79584) ## About The Pull Request So after getting feedback on fitness I've decided to make some balance changes: - ~~Every level of fitness now increases max hp. At max legendary fitness, all the hp bonuses combined results in a total of +25 max hp~~ - Fitness now decreases the time it takes to firemany carry by 0.33 seconds per level. (At max fitness, this means a decrease of 2 seconds) - Exercise status effect triggers the exercise mood event and goes away when the exercise status effect is gone - The better your fitness level, the more happiness you gain from the mood event - Decreased the fitness timers and effects by half and tweaked a few other values - Increased the nutrition cost of working out - Removed doubles metabolism exercise effect I'd also like this test merged to see if anymore minor tweaks need to be made. ## Why It's Good For The Game Fitness effects on gameplay were pretty underwhelming. This was deliberate since there is a concern about prisoners being able to abuse it in quite a lot of scenarios. ~~Adding a small boost to max hp is nice given that the downside is a bigger target.~~ Another problem was that the double metabolism rate resulted in a lot of the diet effects being metabolised before you could convert them into exercise gains. So this was removed. People would also hit their bench max rather quickly and then spend a long duration sleeping. Ideally I wanted people to spend more time working out than sleeping, so I halved the duration values so it takes them longer to achieve maxxing out. ## Changelog :cl: balance: Fitness level decreases the time it takes to firemany carry someone. Fitness level determines how much of a positive mood the workout grants. Working out is now more difficult and requires more nutrition. balance: Exercise no longer triggers double metabolism. /:cl: --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- .../mood_events/generic_positive_events.dm | 7 ++- code/datums/skills/fitness.dm | 18 +++++--- code/datums/status_effects/buffs.dm | 46 +++++++++++-------- .../objects/structures/gym/punching_bag.dm | 3 +- .../objects/structures/gym/weight_machine.dm | 31 +++++++++---- code/modules/mob/living/carbon/carbon.dm | 1 - code/modules/mob/living/carbon/human/human.dm | 15 ++++-- strings/tips.txt | 1 + 8 files changed, 79 insertions(+), 43 deletions(-) diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 4ca06dd8aae..e37ab4bde2b 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -57,8 +57,11 @@ /datum/mood_event/exercise description = "Working out releases those endorphins!" - mood_change = 2 - timeout = 5 MINUTES + mood_change = 1 + +/datum/mood_event/exercise/add_effects(fitness_level) + mood_change = fitness_level // the more fit you are, the more you like to work out + return ..() /datum/mood_event/pet_animal description = "Animals are adorable! I can't stop petting them!" diff --git a/code/datums/skills/fitness.dm b/code/datums/skills/fitness.dm index a7c49a481ac..c306548303e 100644 --- a/code/datums/skills/fitness.dm +++ b/code/datums/skills/fitness.dm @@ -3,17 +3,21 @@ title = "Fitness" desc = "Twinkle twinkle little star, hit the gym and lift the bar." /// The skill value modifier effects the max duration that is possible for /datum/status_effect/exercised - modifiers = list(SKILL_VALUE_MODIFIER = list(2 MINUTES, 3 MINUTES, 4 MINUTES, 5 MINUTES, 6 MINUTES, 7 MINUTES, 10 MINUTES)) + modifiers = list(SKILL_VALUE_MODIFIER = list(1 MINUTES, 1.5 MINUTES, 2 MINUTES, 2.5 MINUTES, 3 MINUTES, 3.5 MINUTES, 5 MINUTES)) + /// How much bigger your mob becomes per level (these effects don't stack together) + var/static/size_boost = list(0, 1/16, 1/8, 3/16, 2/8, 3/8, 4/8) // skill_item_path - your mob sprite gets bigger to showoff so we don't get a special item /datum/skill/fitness/level_gained(datum/mind/mind, new_level, old_level, silent) . = ..() - var/size_boost = (new_level == SKILL_LEVEL_LEGENDARY) ? 0.25 : 0.05 - var/gym_size = RESIZE_DEFAULT_SIZE + size_boost - mind.current.update_transform(gym_size) + var/old_gym_size = RESIZE_DEFAULT_SIZE + size_boost[old_level] + var/new_gym_size = RESIZE_DEFAULT_SIZE + size_boost[new_level] + + mind.current.update_transform(new_gym_size / old_gym_size) /datum/skill/fitness/level_lost(datum/mind/mind, new_level, old_level, silent) . = ..() - var/size_boost = (new_level == SKILL_LEVEL_LEGENDARY) ? 0.25 : 0.05 - var/gym_size = RESIZE_DEFAULT_SIZE + size_boost - mind.current.update_transform(RESIZE_DEFAULT_SIZE / gym_size) + var/old_gym_size = RESIZE_DEFAULT_SIZE + size_boost[old_level] + var/new_gym_size = RESIZE_DEFAULT_SIZE + size_boost[new_level] + + mind.current.update_transform(new_gym_size / old_gym_size) diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 10b3370bbf3..6cd180ab597 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -162,31 +162,33 @@ /datum/status_effect/exercised id = "Exercised" - duration = 30 SECONDS + duration = 15 SECONDS status_type = STATUS_EFFECT_REFRESH // New effects will add to total duration alert_type = null processing_speed = STATUS_EFFECT_NORMAL_PROCESS alert_type = /atom/movable/screen/alert/status_effect/exercised /// Having any of these reagents in your system extends the duration var/static/list/supplementary_reagents_bonus = list( - /datum/reagent/consumable/ethanol/protein_blend = 30 SECONDS, // protein shakes are very robust - /datum/reagent/inverse/oxandrolone = 25 SECONDS, - /datum/reagent/consumable/eggwhite = 20 SECONDS, - /datum/reagent/consumable/eggyolk = 15 SECONDS, - /datum/reagent/consumable/nutriment/protein = 15 SECONDS, - /datum/reagent/consumable/nutriment/vitamin = 10 SECONDS, - /datum/reagent/consumable/rice = 10 SECONDS, - /datum/reagent/consumable/milk = 10 SECONDS, - /datum/reagent/consumable/soymilk = 5 SECONDS, // darn vegans! - /datum/reagent/consumable/nutraslop = 5 SECONDS, // prison food to bulk up with + /datum/reagent/consumable/ethanol/protein_blend = 10 SECONDS, // protein shakes are very robust + /datum/reagent/inverse/oxandrolone = 8 SECONDS, + /datum/reagent/consumable/nutriment/protein = 5 SECONDS, + /datum/reagent/consumable/nutriment/vitamin = 4 SECONDS, + /datum/reagent/consumable/milk = 4 SECONDS, + /datum/reagent/consumable/rice = 3 SECONDS, + // keep in mind you can eat a raw egg to acquire both these reagents at the same time + /datum/reagent/consumable/eggwhite = 3 SECONDS, + /datum/reagent/consumable/eggyolk = 2 SECONDS, + // weak workout food + /datum/reagent/consumable/nutraslop = 2 SECONDS, // prison food to bulk up with + /datum/reagent/consumable/soymilk = 1 SECONDS, // darn vegans! // time for the bad stuff - /datum/reagent/consumable/sugar = -5 SECONDS, - /datum/reagent/consumable/monkey_energy = -5 SECONDS, - /datum/reagent/consumable/nutriment/fat = -5 SECONDS, + /datum/reagent/consumable/sugar = -1 SECONDS, + /datum/reagent/consumable/monkey_energy = -1 SECONDS, // the marketing was a lie + /datum/reagent/consumable/nutriment/fat = -1 SECONDS, ) /datum/status_effect/exercised/proc/workout_duration(mob/living/new_owner, bonus_time) - if(!bonus_time || !new_owner.mind) + if(!bonus_time || !new_owner.mind || !iscarbon(new_owner)) return 0 SECONDS var/modifier = 1 @@ -207,7 +209,7 @@ if(new_owner.reagents.has_reagent(workout_reagent)) food_boost += supplementary_reagents_bonus[workout_reagent] - var/skill_level_boost = (new_owner.mind.get_skill_level(/datum/skill/fitness) - 1) * 5 SECONDS + var/skill_level_boost = (new_owner.mind.get_skill_level(/datum/skill/fitness) - 1) * 2 SECONDS bonus_time = (bonus_time + food_boost + skill_level_boost) * modifier var/exhaustion_limit = new_owner.mind.get_skill_modifier(/datum/skill/fitness, SKILL_VALUE_MODIFIER) + world.time @@ -219,15 +221,21 @@ return bonus_time -/datum/status_effect/exercised/tick(seconds_between_ticks) - owner.reagents.metabolize(owner, seconds_between_ticks * SSMOBS_DT, 0) // doubles the metabolization rate - /datum/status_effect/exercised/on_creation(mob/living/new_owner, bonus_time) duration += workout_duration(new_owner, bonus_time) return ..() /datum/status_effect/exercised/refresh(mob/living/new_owner, bonus_time) duration += workout_duration(new_owner, bonus_time) + new_owner.clear_mood_event("exercise") // we need to reset the old mood event in case our fitness skill changes + new_owner.add_mood_event("exercise", /datum/mood_event/exercise, new_owner.mind.get_skill_level(/datum/skill/fitness)) + +/datum/status_effect/exercised/on_apply() + owner.add_mood_event("exercise", /datum/mood_event/exercise, owner.mind.get_skill_level(/datum/skill/fitness)) + return ..() + +/datum/status_effect/exercised/on_remove() + owner.clear_mood_event("exercise") /atom/movable/screen/alert/status_effect/exercised name = "Exercise" diff --git a/code/game/objects/structures/gym/punching_bag.dm b/code/game/objects/structures/gym/punching_bag.dm index 9219153d026..9c67bd89cfc 100644 --- a/code/game/objects/structures/gym/punching_bag.dm +++ b/code/game/objects/structures/gym/punching_bag.dm @@ -51,8 +51,9 @@ if(istype(boxing_gloves)) stamina_exhaustion = 2 + if(!iscarbon(user)) + return user.adjustStaminaLoss(stamina_exhaustion) - user.add_mood_event("exercise", /datum/mood_event/exercise) user.mind?.adjust_experience(/datum/skill/fitness, 0.1) user.apply_status_effect(/datum/status_effect/exercised) diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index 56b96e5bbd8..055c9788c95 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -1,5 +1,5 @@ #define WORKOUT_XP 5 -#define EXERCISE_STATUS_DURATION 20 SECONDS +#define EXERCISE_STATUS_DURATION 15 SECONDS #define SAFE_DRUNK_LEVEL 39 /obj/structure/weightmachine @@ -22,6 +22,9 @@ ///message when drunk user fails to use the machine var/drunk_message = "You try for a new record and pull through! Through a muscle that is." + // the total reps you can do before you hit stamcrit based on fitness level + var/static/list/total_workout_reps = list(3, 4, 4, 5, 6, 6, 7) + ///List of messages picked when using the machine. var/static/list/more_weight = list( "pushing it to the limit!", @@ -127,12 +130,12 @@ else user.balloon_alert(user, pick(finished_message)) - user.adjust_nutrition(-3) // feel the burn - user.add_mood_event("exercise", /datum/mood_event/exercise) + user.adjust_nutrition(-5) // feel the burn - // remember the real xp gain is from sleeping after working out - user.mind.adjust_experience(/datum/skill/fitness, WORKOUT_XP) - user.apply_status_effect(/datum/status_effect/exercised, EXERCISE_STATUS_DURATION) + if(iscarbon(user)) + // remember the real xp gain is from sleeping after working out + user.mind.adjust_experience(/datum/skill/fitness, WORKOUT_XP) + user.apply_status_effect(/datum/status_effect/exercised, EXERCISE_STATUS_DURATION) end_workout() @@ -141,6 +144,9 @@ STOP_PROCESSING(SSobj, src) icon_state = initial(icon_state) +/// roughly 8 seconds for 1 workout rep +#define WORKOUT_LENGTH 8 + /obj/structure/weightmachine/process(seconds_per_tick) if(!has_buckled_mobs()) end_workout() @@ -149,15 +155,22 @@ flick_overlay_view(workout, 0.8 SECONDS) flick("[base_icon_state]-u", src) var/mob/living/user = buckled_mobs[1] - animate(user, pixel_y = pixel_shift_y, time = 4) + animate(user, pixel_y = pixel_shift_y, time = WORKOUT_LENGTH * 0.5) playsound(user, 'sound/machines/creak.ogg', 60, TRUE) - animate(pixel_y = user.base_pixel_y, time = 4) + animate(pixel_y = user.base_pixel_y, time = WORKOUT_LENGTH * 0.5) - var/stamina_exhaustion = 5 - (user.mind.get_skill_level(/datum/skill/fitness) * 0.5) + if(!iscarbon(user) || isnull(user.mind)) + return TRUE + // the amount of workouts you can do before you hit stamcrit + var/workout_reps = total_workout_reps[user.mind.get_skill_level(/datum/skill/fitness)] + // total stamina drain of 1 workout calculated based on the workout length + var/stamina_exhaustion = FLOOR(user.maxHealth / workout_reps / WORKOUT_LENGTH, 0.1) user.adjustStaminaLoss(stamina_exhaustion * seconds_per_tick) return TRUE +#undef WORKOUT_LENGTH + /** * Weight lifter subtype */ diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 4af52b7f3ed..a073122ad6b 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -792,7 +792,6 @@ if(hud_used?.spacesuit) hud_used.spacesuit.icon_state = "spacesuit_[cell_state]" - /mob/living/carbon/set_health(new_value) . = ..() if(. > hardcrit_threshold) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6bfbc97b731..ce4f93d99c1 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -890,12 +890,19 @@ return var/carrydelay = 5 SECONDS //if you have latex you are faster at grabbing - var/skills_space = "" //cobby told me to do this + var/skills_space + var/fitness_level = mind.get_skill_level(/datum/skill/fitness) - 1 if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY)) - carrydelay = 3 SECONDS - skills_space = " very quickly" + carrydelay -= 2 SECONDS else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY)) - carrydelay = 4 SECONDS + carrydelay -= 1 SECONDS + + // can remove up to 2 seconds at legendary + carrydelay -= fitness_level * (1/3) SECONDS + + if(carrydelay <= 3 SECONDS) + skills_space = " very quickly" + else if(carrydelay <= 4 SECONDS) skills_space = " quickly" visible_message(span_notice("[src] starts[skills_space] lifting [target] onto [p_their()] back..."), diff --git a/strings/tips.txt b/strings/tips.txt index df4e9e3e195..2a777f28304 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -252,6 +252,7 @@ When hacking doors, cutting and mending a "test light wire" will restore power t When in doubt about technical issues, clear your cache (byond launcher > cogwheel > preferences > game prefs), update your BYOND, and relog. When placing floor tiles in space, you don't need to place down lattice if there is a piece of plating nearby. Where the space map levels connect is randomized every round, but are otherwise kept consistent within rounds. Remember that they are not necessarily bidirectional! +Working out improves your fitness which increases your size and faster times to fireman carry. Remember that a quality diet and sleep are essential! You can catch thrown items by toggling on your throw mode with an empty hand active. You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this. You can cheat games by baking dice in microwaves to make them loaded. Cards can be seen with x-ray vision or be marked with either a pen or crayon to gain an edge.