mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
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:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user