Rocky DLXIII: Fitness to Athletics, Athletics skill influences Boxing against Boxers, Boxing overhaul, Evil Boxing (#82611)

## About The Pull Request

### Changes Fitness skill to Athletics skill; Removes the sprite growth
as the only meaningful reward

Basically just a rebranding so that it is more broad in its concept. It
isn't just about peak physique. It's about how you can apply it too.

Reaching Legendary rewards you with the Golden Gloves.

### Boxing Overhaul

I started it in this pr here
https://github.com/tgstation/tgstation/pull/80635

But this is a more significant overhaul of boxing from the ground up.
Namely, it now is majorly influenced by the Athletics skill, and also
more thoroughly aligns with conventional punching in its current state.
However, a major component of this is that boxing's breadth of mechanics
is only relevant when used against another boxer. Non-boxer targets are
only ever going to get smacked by a stamina punch, as it is currently
(and more or less the same values too). Additionally, boxers cannot
punch someone who is either unconscious or in stamina crit, so it can't
be used to maintain stamcrit.

- Boxing now has a One-Two Punch mechanic. Swapping between the left and
right mouse buttons to punch and maintaining this causes every second
punch to do more damage (to boxers). Breaking this chain by punching
with the same button twice will cause you to lose damage (against
boxers).

- Boxing now can have crits occur below 50 stamina damage (against
boxers). However, to knock someone out clean, the target must be
staggered from a previous crit first. (Or I guess be staggered at all,
maybe their shoelaces were tied or something). Crit probabilities are
determined by adding your Athletics probability skill bonuses to your
unarmed effectiveness, and then reduced by the targets own Athletics
skill bonuses. It is hard for two athletes to knock each other out in
one blow. It is trivial for a legendary boxer to knock out a novice in a
single punch. Cybernetically enhanced boxers are dangerously effective
at boxing.

- Boxers can block other boxers by using throw mode, but the chances of
doing so is based on Athletics skill bonuses. A successful block causes
the attacker to take stamina damage (as does the blocker, but less so).

- Participating in boxing increases the Athletics skill. Your gains are
probably slower than normal training, but you at least get some reward
for doing so. Only relevant if your opponent is a boxer. Get a sparring
partner!

### Evil Boxing (Admin Only)

So this is all well and good, but what if you're a scoundrel with no
care for the other person in this equation? Well, that's where Evil
Boxing comes in. Evil Boxing has absolutely no restrictions at all, and
can freely use its boxing abilities against anyone. Even non-boxers. You
can even grab people! Wow, what a scumbag. I bet you even king hit
people. Thankfully, only an admin can make you into an Evil Boxer.

### Strength and Stimmed Mutations now benefit Exercising and Boxing
(against boxers)

Both mutations have a flimsy increase to instability of 5 because of how
incredibly particular the bonus is.

Strength now reduces the amount of stamina damage inflicted via
exercising by half. Strength also adds a +2 damage bonus on boxing
punches while boxing against boxers (this doesn't influence normal
unarmed attacks whatsoever, or boxing against nonboxers). Obviously,
evil boxers just get this benefit against everyone because they're
knaves.

Stimmed increases the duration of the exercised status effect by one
factor. (That is, if you have no other modifiers, it will double the
duration on its own)

## Why It's Good For The Game

@Jacquerel was racking their brain trying to come up with an alternative
to the skill rewards of Fitness. At the moment, sprite growth is not
only a really bad bonus (it does literally nothing but make you big, and
thus is actually a detriment due to how intrusive sprite size is with
interaction, and plays weird with other sprite changing effects), but
isn't really all that interesting for all the effort put in.

Problem is, how do you make Fitness meaningful without making it a
powergame mechanic? Simple! You make it applicable to a really niche,
self-contained but still utilized game mechanic that is engaging to
participate in and makes you meaningfully very good in it. AND scratches
that power scaling itch that many players have.

Boxing is reasonably self-contained as is, but pretty bland due to how
old it is. While maintaining that self-contained nature, I hoped to
expand the interactivity of boxing a little bit by giving it a small
mini-game in of itself. And also introduce ways to simulate the idea of
boxing a bit better.

The idea of being an Evil Boxer is funny. For every Rocky, there is a
[Insert Rocky Villain Here that isn't Creed]. But in this case, it's
probably some Syndicate douchebag looking to punch clowns into a coma
and inspire the mime to take up shadowboxing in revenge.

## Changelog
🆑
add: Replaces Fitness with Athletics; same skill, but now more
specifically applicable to boxing.
add: Athletics does not increase sprite size.
balance: Overhauls Boxing to add a lot more depth to the interactions.
Only applicable to other boxers, however. You can still punch the snot
out of non-boxers though. But only up to stamcrit or unconsciousness. No
hitting someone who can't fight back!
balance: Adds Evil Boxing, which is the evil and fucked up version of
boxing that you kill people with and are allowed to flout the sacred
rules of boxing as you please. Everyone is a victim!
/🆑
This commit is contained in:
necromanceranne
2024-04-22 16:43:58 +01:00
committed by GitHub
parent 1e78db8471
commit ca2ff33292
18 changed files with 362 additions and 90 deletions
+1
View File
@@ -1,6 +1,7 @@
//Martial arts defines
#define MARTIALART_BOXING "boxing"
#define MARTIALART_EVIL_BOXING "evil boxing"
#define MARTIALART_CQC "CQC"
#define MARTIALART_KRAVMAGA "krav maga"
#define MARTIALART_MUSHPUNCH "mushroom punch"
+9
View File
@@ -520,6 +520,15 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Prevents you from twohanding weapons.
#define TRAIT_NO_TWOHANDING "no_twohanding"
/// Improves boxing damage against boxers and athletics experience gain
#define TRAIT_STRENGTH "strength"
/// Increases the duration of having exercised
#define TRAIT_STIMMED "stimmed"
/// Indicates that the target is able to be boxed at a boxer's full power.
#define TRAIT_BOXING_READY "boxing_ready"
/// Halves the time of tying a tie.
#define TRAIT_FAST_TYING "fast_tying"
+1
View File
@@ -137,6 +137,7 @@
#define LOCKED_HELMET_TRAIT "locked-helmet"
#define NINJA_SUIT_TRAIT "ninja-suit"
#define SLEEPING_CARP_TRAIT "sleeping_carp"
#define BOXING_TRAIT "boxing"
#define TIMESTOP_TRAIT "timestop"
#define LIFECANDLE_TRAIT "lifecandle"
#define VENTCRAWLING_TRAIT "ventcrawling"
+3
View File
@@ -495,6 +495,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION,
"TRAIT_DISCO_DANCER" = TRAIT_DISCO_DANCER,
"TRAIT_MAFIAINITIATE" = TRAIT_MAFIAINITIATE,
"TRAIT_STRENGTH" = TRAIT_STRENGTH,
"TRAIT_STIMMED" = TRAIT_STIMMED,
"TRAIT_BOXING_READY" = TRAIT_BOXING_READY,
),
/obj/item = list(
"TRAIT_APC_SHOCKING" = TRAIT_APC_SHOCKING,
+238 -54
View File
@@ -1,87 +1,271 @@
#define LEFT_RIGHT_COMBO "DH"
#define RIGHT_LEFT_COMBO "HD"
#define LEFT_LEFT_COMBO "HH"
#define RIGHT_RIGHT_COMBO "DD"
/datum/martial_art/boxing
name = "Boxing"
id = MARTIALART_BOXING
pacifist_style = TRUE
///Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions
var/honorable_boxer = TRUE
/// List of traits applied to users of this martial art.
var/list/boxing_traits = list(TRAIT_BOXING_READY)
/// Balloon alert cooldown for warning our boxer to alternate their blows to get more damage
COOLDOWN_DECLARE(warning_cooldown)
/datum/martial_art/boxing/teach(mob/living/new_holder, make_temporary)
if(!ishuman(new_holder))
return FALSE
new_holder.add_traits(boxing_traits, BOXING_TRAIT)
RegisterSignal(new_holder, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(check_block))
return ..()
/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/attacker, mob/living/defender)
attacker.balloon_alert(attacker, "can't disarm while boxing!")
return MARTIAL_ATTACK_FAIL
/datum/martial_art/boxing/on_remove(mob/living/remove_from)
remove_from.remove_traits(boxing_traits, BOXING_TRAIT)
UnregisterSignal(remove_from, list(COMSIG_LIVING_CHECK_BLOCK))
return ..()
/datum/martial_art/boxing/grab_act(mob/living/carbon/human/attacker, mob/living/defender)
attacker.balloon_alert(attacker, "can't grab while boxing!")
return MARTIAL_ATTACK_FAIL
///Unlike most instances of this proc, this is actually called in _proc/tussle()
///Returns a multiplier on our skill damage bonus.
/datum/martial_art/boxing/proc/check_streak(mob/living/attacker, mob/living/defender)
var/combo_multiplier = 1
if(findtext(streak, LEFT_LEFT_COMBO) || findtext(streak, RIGHT_RIGHT_COMBO))
reset_streak()
if(COOLDOWN_FINISHED(src, warning_cooldown))
COOLDOWN_START(src, warning_cooldown, 2 SECONDS)
attacker.balloon_alert(attacker, "weak combo, alternate your hits!")
return combo_multiplier * 0.5
if(findtext(streak, LEFT_RIGHT_COMBO) || findtext(streak, RIGHT_LEFT_COMBO))
reset_streak()
return combo_multiplier * 1.5
return combo_multiplier
/datum/martial_art/boxing/disarm_act(mob/living/attacker, mob/living/defender)
if(honor_check(defender))
add_to_streak("D", defender)
tussle(attacker, defender, "right hook", "right hooked")
return MARTIAL_ATTACK_SUCCESS
/datum/martial_art/boxing/grab_act(mob/living/attacker, mob/living/defender)
if(honorable_boxer)
attacker.balloon_alert(attacker, "no grabbing while boxing!")
return MARTIAL_ATTACK_FAIL
return MARTIAL_ATTACK_INVALID //UNLESS YOU'RE EVIL
/datum/martial_art/boxing/harm_act(mob/living/attacker, mob/living/defender)
if(honor_check(defender))
add_to_streak("H", defender)
tussle(attacker, defender, "left hook", "left hooked")
return MARTIAL_ATTACK_SUCCESS
// Our only boxing move, which occurs on literally all attacks; the tussle. However, quite a lot morphs the results of this proc. Combos, unlike most martial arts attacks, are checked in this proc rather than our standard unarmed procs
/datum/martial_art/boxing/proc/tussle(mob/living/attacker, mob/living/defender, atk_verb = "blind jab", atk_verbed = "blind jabbed")
if(honorable_boxer) //Being a good sport, you never hit someone on the ground or already knocked down. It shows you're the better person.
if(defender.body_position == LYING_DOWN && defender.getStaminaLoss() >= 100 || defender.IsUnconscious()) //If they're in stamcrit or unconscious, don't bloody punch them
attacker.balloon_alert(attacker, "unsportsmanlike behaviour!")
return FALSE
/datum/martial_art/boxing/harm_act(mob/living/carbon/human/attacker, mob/living/defender)
var/obj/item/bodypart/arm/active_arm = attacker.get_active_hand()
//The values between which damage is rolled for punches
var/lower_force = active_arm.unarmed_damage_low
var/upper_force = active_arm.unarmed_damage_high
//Determines knockout potential and armor penetration (if that matters)
var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness
//Determines attack sound based on attacker arm
var/attack_sound = active_arm.unarmed_attack_sound
// Out athletics skill is added as a damage bonus
var/athletics_skill = attacker.mind?.get_skill_level(/datum/skill/athletics)
// If true, grants experience for punching; we only gain experience if we punch another boxer.
var/grant_experience = FALSE
// What type of damage does our kind of boxing do? Defaults to STAMINA, unless you're performing EVIL BOXING
var/damage_type = honorable_boxer ? STAMINA : attacker.get_attack_type()
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
var/damage = rand(5, 8) + active_arm.unarmed_damage_low
var/atk_verb = pick("left hook", "right hook", "straight punch")
if(damage <= 0)
playsound(defender, active_arm.unarmed_miss_sound, 25, TRUE, -1)
defender.visible_message(
span_warning("[attacker]'s [atk_verb] misses [defender]!"),
span_danger("You avoid [attacker]'s [atk_verb]!"),
span_hear("You hear a swoosh!"),
COMBAT_MESSAGE_RANGE,
attacker,
)
to_chat(attacker, span_warning("Your [atk_verb] misses [defender]!"))
log_combat(attacker, defender, "attempted to hit", atk_verb)
return MARTIAL_ATTACK_FAIL
//Determines damage dealt on a punch. Against a boxing defender, we apply our skill bonus.
var/damage = rand(lower_force, upper_force)
if(defender.check_block(attacker, damage, "[attacker]'s [atk_verb]", UNARMED_ATTACK))
return MARTIAL_ATTACK_FAIL
if(honor_check(defender))
var/strength_bonus = HAS_TRAIT(attacker, TRAIT_STRENGTH) ? 2 : 0 //Investing into genetic strength improvements makes you a better boxer
damage += round(athletics_skill * check_streak(attacker, defender) + strength_bonus)
grant_experience = TRUE
var/current_atk_verb = atk_verb
var/current_atk_verbed = atk_verbed
if(is_detective_job(attacker.mind?.assigned_role)) //In short: discombobulate
current_atk_verb = "discombobulate"
current_atk_verbed = "discombulated"
// Similar to a normal punch, should we have a value of 0 for our lower force, we simply miss outright.
if(!lower_force)
playsound(defender.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1)
defender.visible_message(span_warning("[attacker]'s [current_atk_verb] misses [defender]!"), \
span_danger("You avoid [attacker]'s [current_atk_verb]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, attacker)
to_chat(attacker, span_warning("Your [current_atk_verb] misses [defender]!"))
log_combat(attacker, defender, "attempted to hit", current_atk_verb)
return FALSE
if(defender.check_block(attacker, damage, "[attacker]'s [current_atk_verb]", UNARMED_ATTACK))
return FALSE
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
var/armor_block = defender.run_armor_check(affecting, MELEE)
var/armor_block = defender.run_armor_check(affecting, MELEE, armour_penetration = base_unarmed_effectiveness)
playsound(defender, attack_sound, 25, TRUE, -1)
playsound(defender, active_arm.unarmed_attack_sound, 25, TRUE, -1)
defender.visible_message(
span_danger("[attacker] [atk_verb]ed [defender]!"),
span_userdanger("You're [atk_verb]ed by [attacker]!"),
span_danger("[attacker] [current_atk_verbed] [defender]!"),
span_userdanger("You're [current_atk_verbed] by [attacker]!"),
span_hear("You hear a sickening sound of flesh hitting flesh!"),
COMBAT_MESSAGE_RANGE,
attacker,
)
to_chat(attacker, span_danger("You [atk_verb]ed [defender]!"))
defender.apply_damage(damage, STAMINA, affecting, armor_block)
to_chat(attacker, span_danger("You [current_atk_verbed] [defender]!"))
defender.apply_damage(damage, damage_type, affecting, armor_block)
log_combat(attacker, defender, "punched (boxing) ")
if(defender.getStaminaLoss() > 50 && istype(defender.mind?.martial_art, /datum/martial_art/boxing))
var/knockout_prob = defender.getStaminaLoss() + rand(-15, 15)
if(defender.stat != DEAD && prob(knockout_prob))
defender.visible_message(
span_danger("[attacker] knocks [defender] out with a haymaker!"),
span_userdanger("You're knocked unconscious by [attacker]!"),
span_hear("You hear a sickening sound of flesh hitting flesh!"),
COMBAT_MESSAGE_RANGE,
attacker,
)
to_chat(attacker, span_danger("You knock [defender] out with a haymaker!"))
defender.apply_effect(20 SECONDS, EFFECT_KNOCKDOWN, armor_block)
defender.SetSleeping(10 SECONDS)
log_combat(attacker, defender, "knocked out (boxing) ")
return MARTIAL_ATTACK_SUCCESS
if(grant_experience)
skill_experience_adjustment(attacker, (damage/lower_force))
if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs
return TRUE
//Determine our attackers athletics level as a knockout probability bonus
var/attacker_athletics_skill = (attacker.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + base_unarmed_effectiveness)
// Defender boxing skill and armor block are used as a defense here. This has already factored in base_unarmed_effectiveness from the attacker
var/defender_athletics_skill = clamp(defender.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER), 0, 100)
//Determine our final probability, using a clamp to stop any prob() weirdness.
var/final_knockout_probability = clamp(round(attacker_athletics_skill - defender_athletics_skill), 0 , 100)
if(!prob(final_knockout_probability))
return TRUE
if(defender.get_timed_status_effect_duration(/datum/status_effect/staggered))
defender.visible_message(
span_danger("[attacker] knocks [defender] out with a haymaker!"),
span_userdanger("You're knocked unconscious by [attacker]!"),
span_hear("You hear a sickening sound of flesh hitting flesh!"),
COMBAT_MESSAGE_RANGE,
attacker,
)
to_chat(attacker, span_danger("You knock [defender] out with a haymaker!"))
defender.apply_effect(20 SECONDS, EFFECT_KNOCKDOWN, armor_block)
defender.SetSleeping(10 SECONDS)
log_combat(attacker, defender, "knocked out (boxing) ")
else
defender.visible_message(
span_danger("[attacker] staggers [defender] with a haymaker!"),
span_userdanger("You're nearly knocked off your feet by [attacker]!"),
span_hear("You hear a sickening sound of flesh hitting flesh!"),
COMBAT_MESSAGE_RANGE,
attacker,
)
defender.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS)
to_chat(attacker, span_danger("You stagger [defender] with a haymaker!"))
log_combat(attacker, defender, "staggered (boxing) ")
playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE)
new /obj/effect/temp_visual/crit(get_turf(defender))
skill_experience_adjustment(attacker, (damage/lower_force)) //double experience for a successful crit
return TRUE
/// Returns whether whoever is checked by this proc is complying with the rules of boxing. The boxer cannot block non-boxers, and cannot apply their scariest moves against non-boxers.
/datum/martial_art/boxing/proc/honor_check(mob/living/possible_boxer)
if(!honorable_boxer)
return TRUE //You scoundrel!!
if(!HAS_TRAIT(possible_boxer, TRAIT_BOXING_READY))
return FALSE
return TRUE
/// Handles our instances of experience gain while boxing. It also applies the exercised status effect.
/datum/martial_art/boxing/proc/skill_experience_adjustment(mob/living/boxer, experience_value)
//Boxing in heavier gravity gives you more experience
var/gravity_modifier = boxer.has_gravity() > STANDARD_GRAVITY ? 1 : 0.5
//You gotta sleep before you get any experience!
boxer.mind?.adjust_experience(/datum/skill/athletics, experience_value * gravity_modifier)
boxer.apply_status_effect(/datum/status_effect/exercised)
/// Handles our blocking signals, similar to hit_reaction() on items. Only blocks while the boxer is in throw mode.
/datum/martial_art/boxing/proc/check_block(mob/living/boxer, atom/movable/hitby, damage, attack_text, attack_type, ...)
SIGNAL_HANDLER
if(!can_use(boxer) || !boxer.throw_mode || boxer.incapacitated(IGNORE_GRAB))
return NONE
if(attack_type != UNARMED_ATTACK)
return NONE
//Determines unarmed defense against boxers using our current active arm.
var/obj/item/bodypart/arm/active_arm = boxer.get_active_hand()
var/base_unarmed_effectiveness = active_arm.unarmed_effectiveness
// Out athletics skill is added to our block potential
var/athletics_skill_rands = boxer.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER)
var/block_chance = base_unarmed_effectiveness + athletics_skill_rands
var/block_text = pick("block", "evade")
if(!prob(block_chance))
return NONE
var/mob/living/attacker = GET_ASSAILANT(hitby)
if(!honor_check(attacker))
return NONE
if(istype(attacker) && boxer.Adjacent(attacker))
attacker.apply_damage(10, STAMINA)
boxer.apply_damage(5, STAMINA)
boxer.visible_message(
span_danger("[boxer] [block_text]s [attack_text]!"),
span_userdanger("You [block_text] [attack_text]!"),
)
if(block_text == "evade")
playsound(boxer.loc, active_arm.unarmed_miss_sound, 25, TRUE, -1)
skill_experience_adjustment(boxer, 1) //just getting hit a bunch doesn't net you much experience
return SUCCESSFUL_BLOCK
/datum/martial_art/boxing/can_use(mob/living/martial_artist)
if(!ishuman(martial_artist))
return FALSE
return ..()
/obj/item/clothing/gloves/boxing
/// Evil Boxing; for sick, evil scoundrels. Has no honor, making it more lethal (therefore unable to be used by pacifists).
/// Grants Strength and Stimmed to speed up any experience gain.
/obj/item/clothing/gloves/boxing/Initialize(mapload)
. = ..()
var/static/list/slapcraft_recipe_list = list(/datum/crafting_recipe/extendohand_l, /datum/crafting_recipe/extendohand_r)
/datum/martial_art/boxing/evil
name = "Evil Boxing"
id = MARTIALART_EVIL_BOXING
pacifist_style = FALSE
honorable_boxer = FALSE
boxing_traits = list(TRAIT_BOXING_READY, TRAIT_STRENGTH, TRAIT_STIMMED)
AddComponent(
/datum/component/slapcrafting,\
slapcraft_recipes = slapcraft_recipe_list,\
)
AddComponent(/datum/component/martial_art_giver, /datum/martial_art/boxing)
#undef LEFT_RIGHT_COMBO
#undef RIGHT_LEFT_COMBO
#undef LEFT_LEFT_COMBO
#undef RIGHT_RIGHT_COMBO
+27
View File
@@ -267,15 +267,42 @@
desc = "The user's muscles slightly expand."
quality = POSITIVE
text_gain_indication = "<span class='notice'>You feel strong.</span>"
instability = 5
difficulty = 16
/datum/mutation/human/strong/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(.)
return
ADD_TRAIT(owner, TRAIT_STRENGTH, GENETIC_MUTATION)
/datum/mutation/human/strong/on_losing(mob/living/carbon/human/owner)
. = ..()
if(.)
return
REMOVE_TRAIT(owner, TRAIT_STRENGTH, GENETIC_MUTATION)
/datum/mutation/human/stimmed
name = "Stimmed"
desc = "The user's chemical balance is more robust."
quality = POSITIVE
text_gain_indication = "<span class='notice'>You feel stimmed.</span>"
instability = 5
difficulty = 16
/datum/mutation/human/stimmed/on_acquiring(mob/living/carbon/human/owner)
. = ..()
if(.)
return
ADD_TRAIT(owner, TRAIT_STIMMED, GENETIC_MUTATION)
/datum/mutation/human/stimmed/on_losing(mob/living/carbon/human/owner)
. = ..()
if(.)
return
REMOVE_TRAIT(owner, TRAIT_STIMMED, GENETIC_MUTATION)
/datum/mutation/human/insulated
name = "Insulated"
desc = "The affected person does not conduct electricity."
+27
View File
@@ -0,0 +1,27 @@
/datum/skill/athletics
name = "Athletics"
title = "Athlete"
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; 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,
5 MINUTES
),
SKILL_RANDS_MODIFIER = list(
0,
5,
10,
15,
20,
30,
50
)
)
skill_item_path = /obj/item/clothing/gloves/boxing/golden
-23
View File
@@ -1,23 +0,0 @@
/datum/skill/fitness
name = "Fitness"
title = "Powerlifter"
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(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/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/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)
+7 -4
View File
@@ -195,6 +195,9 @@
if(HAS_TRAIT(new_owner, TRAIT_HULK))
modifier += 0.5
if(HAS_TRAIT(new_owner, TRAIT_STIMMED)) // Naturally produces stimulants to help get you PUMPED
modifier += 1
if(HAS_TRAIT(new_owner, TRAIT_FAT)) // less xp until you get into shape
modifier -= 0.5
@@ -209,10 +212,10 @@
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) * 2 SECONDS
var/skill_level_boost = (new_owner.mind.get_skill_level(/datum/skill/athletics) - 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
var/exhaustion_limit = new_owner.mind.get_skill_modifier(/datum/skill/athletics, SKILL_VALUE_MODIFIER) + world.time
if(duration + bonus_time >= exhaustion_limit)
duration = exhaustion_limit
to_chat(new_owner, span_userdanger("Your muscles are exhausted! Might be a good idea to sleep..."))
@@ -228,10 +231,10 @@
/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))
new_owner.add_mood_event("exercise", /datum/mood_event/exercise, new_owner.mind.get_skill_level(/datum/skill/athletics))
/datum/status_effect/exercised/on_apply()
owner.add_mood_event("exercise", /datum/mood_event/exercise, owner.mind.get_skill_level(/datum/skill/fitness))
owner.add_mood_event("exercise", /datum/mood_event/exercise, owner.mind.get_skill_level(/datum/skill/athletics))
return ..()
/datum/status_effect/exercised/on_remove()
@@ -224,7 +224,7 @@
var/datum/status_effect/exercised/exercised = carbon_owner.has_status_effect(/datum/status_effect/exercised)
if(exercised && carbon_owner.mind)
// the better you sleep, the more xp you gain
carbon_owner.mind.adjust_experience(/datum/skill/fitness, seconds_between_ticks * sleep_quality * SLEEP_QUALITY_WORKOUT_MULTIPLER)
carbon_owner.mind.adjust_experience(/datum/skill/athletics, seconds_between_ticks * sleep_quality * SLEEP_QUALITY_WORKOUT_MULTIPLER)
carbon_owner.adjust_timed_status_effect(-1 * seconds_between_ticks * sleep_quality * SLEEP_QUALITY_WORKOUT_MULTIPLER, /datum/status_effect/exercised)
if(prob(2))
to_chat(carbon_owner, span_notice("You feel your fitness improving!"))
@@ -57,9 +57,12 @@
stamina_exhaustion = 2
if (is_heavy_gravity)
stamina_exhaustion *= 1.5
if(HAS_TRAIT(user, TRAIT_STRENGTH)) //The strong get reductions to stamina damage taken while exercising
stamina_exhaustion *= 0.5
user.adjustStaminaLoss(stamina_exhaustion)
user.mind?.adjust_experience(/datum/skill/fitness, is_heavy_gravity ? 0.2 : 0.1)
user.mind?.adjust_experience(/datum/skill/athletics, is_heavy_gravity ? 0.2 : 0.1)
user.apply_status_effect(/datum/status_effect/exercised)
/obj/structure/punching_bag/wrench_act_secondary(mob/living/user, obj/item/tool)
@@ -109,7 +109,7 @@
if(do_after(user, 8 SECONDS, src) && user.has_gravity())
// with enough dedication, even clowns can overcome their handicaps
var/clumsy_chance = 30 - (user.mind.get_skill_level(/datum/skill/fitness) * 5)
var/clumsy_chance = 30 - (user.mind.get_skill_level(/datum/skill/athletics) * 5)
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(clumsy_chance))
playsound(src, 'sound/effects/bang.ogg', 50, TRUE)
to_chat(user, span_warning("Your hand slips, causing the [name] to smash you!"))
@@ -135,7 +135,7 @@
if(iscarbon(user))
var/gravity_modifier = user.has_gravity() > STANDARD_GRAVITY ? 2 : 1
// remember the real xp gain is from sleeping after working out
user.mind.adjust_experience(/datum/skill/fitness, WORKOUT_XP * gravity_modifier)
user.mind.adjust_experience(/datum/skill/athletics, WORKOUT_XP * gravity_modifier)
user.apply_status_effect(/datum/status_effect/exercised, EXERCISE_STATUS_DURATION)
end_workout()
@@ -168,9 +168,13 @@
return TRUE // No weight? I could do this all day
var/gravity_modifier = affected_gravity > STANDARD_GRAVITY ? 0.75 : 1
// 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)] * gravity_modifier
var/workout_reps = total_workout_reps[user.mind.get_skill_level(/datum/skill/athletics)] * gravity_modifier
// total stamina drain of 1 workout calculated based on the workout length
var/stamina_exhaustion = FLOOR(user.maxHealth / workout_reps / WORKOUT_LENGTH, 0.1)
if(HAS_TRAIT(user, TRAIT_STRENGTH)) //The strong get reductions to stamina damage taken while exercising
stamina_exhaustion *= 0.5
user.adjustStaminaLoss(stamina_exhaustion * seconds_per_tick)
return TRUE
@@ -34,9 +34,10 @@
occupied = FALSE
if (!succeeded)
return
living_user.mind?.adjust_experience(/datum/skill/fitness, 10)
var/stamina_damage_to_inflict = HAS_TRAIT(user, TRAIT_STRENGTH) ? 60 : 120 //Decreases the amount of stamina damage inflicted by half if you're STRONG
living_user.mind?.adjust_experience(/datum/skill/athletics, 10)
living_user.apply_status_effect(/datum/status_effect/exercised)
new spawned_boulder(get_turf(living_user))
living_user.visible_message(span_notice("[living_user] hauls a boulder out of [src]."))
living_user.apply_damage(120, STAMINA)
living_user.apply_damage(stamina_damage_to_inflict, STAMINA)
playsound(src, 'sound/weapons/genhit.ogg', vol = 50, vary = TRUE)
+32
View File
@@ -6,6 +6,25 @@
equip_delay_other = 60
species_exception = list(/datum/species/golem) // now you too can be a golem boxing champion
clothing_traits = list(TRAIT_CHUNKYFINGERS)
/// Determines the version of boxing (or any martial art for that matter) that the boxing gloves gives
var/style_to_give = /datum/martial_art/boxing
/obj/item/clothing/gloves/boxing/Initialize(mapload)
. = ..()
var/static/list/slapcraft_recipe_list = list(/datum/crafting_recipe/extendohand_l, /datum/crafting_recipe/extendohand_r)
AddComponent(
/datum/component/slapcrafting,\
slapcraft_recipes = slapcraft_recipe_list,\
)
AddComponent(/datum/component/martial_art_giver, style_to_give)
/obj/item/clothing/gloves/boxing/evil
name = "evil boxing gloves"
desc = "These strange gloves radiate an unsually evil aura."
greyscale_colors = "#21211f"
style_to_give = /datum/martial_art/boxing/evil
/obj/item/clothing/gloves/boxing/green
icon_state = "boxinggreen"
@@ -18,3 +37,16 @@
/obj/item/clothing/gloves/boxing/yellow
icon_state = "boxingyellow"
greyscale_colors = "#d2a800"
/obj/item/clothing/gloves/boxing/golden
name = "golden gloves"
desc = "The reigning champ of the station!"
icon_state = "boxinggold"
custom_materials = list(/datum/material/gold = SHEET_MATERIAL_AMOUNT*1) //LITERALLY GOLD
material_flags = MATERIAL_EFFECTS | MATERIAL_AFFECT_STATISTICS
equip_delay_other = 120
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE
/obj/item/clothing/gloves/boxing/golden/Initialize(mapload)
. = ..()
AddElement(/datum/element/skill_reward, /datum/skill/athletics)
@@ -915,7 +915,7 @@
var/carrydelay = 5 SECONDS //if you have latex you are faster at grabbing
var/skills_space
var/fitness_level = mind.get_skill_level(/datum/skill/fitness) - 1
var/fitness_level = mind.get_skill_level(/datum/skill/athletics) - 1
if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY))
carrydelay -= 2 SECONDS
else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY))
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

+1 -1
View File
@@ -1774,9 +1774,9 @@
#include "code\datums\shuttles\starfury.dm"
#include "code\datums\shuttles\whiteship.dm"
#include "code\datums\skills\_skill.dm"
#include "code\datums\skills\athletics.dm"
#include "code\datums\skills\cleaning.dm"
#include "code\datums\skills\fishing.dm"
#include "code\datums\skills\fitness.dm"
#include "code\datums\skills\gaming.dm"
#include "code\datums\skills\mining.dm"
#include "code\datums\station_traits\_station_trait.dm"