diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 8901d2d8e858e..c75793dfe34b6 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -86,6 +86,7 @@ #define ORGAN_SLOT_MONSTER_CORE "monstercore" #define ORGAN_SLOT_RIGHT_ARM_AUG "r_arm_device" #define ORGAN_SLOT_LEFT_ARM_AUG "l_arm_device" //This one ignores alphabetical order cause the arms should be together +#define ORGAN_SLOT_SPINE "spine" #define ORGAN_SLOT_STOMACH "stomach" #define ORGAN_SLOT_STOMACH_AID "stomach_aid" #define ORGAN_SLOT_THRUSTERS "thrusters" diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm index a1e30cd142f00..93f1bc924c288 100644 --- a/code/__DEFINES/research/anomalies.dm +++ b/code/__DEFINES/research/anomalies.dm @@ -1,6 +1,6 @@ // Max amounts of cores you can make #define MAX_CORES_BLUESPACE 3 -#define MAX_CORES_GRAVITATIONAL 8 +#define MAX_CORES_GRAVITATIONAL 6 #define MAX_CORES_FLUX 8 #define MAX_CORES_VORTEX 1 #define MAX_CORES_PYRO 8 diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index 657d555b366ed..b8621d382f6fb 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -405,6 +405,10 @@ if(el_tail && (el_tail.wag_flags & WAG_WAGGING)) // lizard tail wagging is robust and can swat away assailants! defense_mod += 1 + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = tackle_target.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + defense_mod += potential_spine.strength_bonus + // OF-FENSE var/mob/living/carbon/sacker = parent var/sacker_drunkenness = sacker.get_drunk_amount() @@ -437,6 +441,10 @@ if(sacker_wing) attack_mod += 2 + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = sacker.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + attack_mod += potential_spine.strength_bonus + if(ishuman(sacker)) var/mob/living/carbon/human/human_sacker = sacker @@ -500,6 +508,10 @@ if(HAS_TRAIT(user, TRAIT_HEAD_INJURY_BLOCKED)) oopsie_mod -= 6 + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = user.get_organ_slot(ORGAN_SLOT_SPINE) // Can't snap that spine if it's made of metal. + if(istype(potential_spine)) + oopsie_mod -= potential_spine.strength_bonus + if(HAS_TRAIT(user, TRAIT_CLUMSY)) oopsie_mod += 6 //honk! diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm index 4e6400163a34b..5c24aaf45b7b2 100644 --- a/code/datums/martial/boxing.dm +++ b/code/datums/martial/boxing.dm @@ -98,6 +98,11 @@ if(honor_check(defender)) var/strength_bonus = HAS_TRAIT(attacker, TRAIT_STRENGTH) ? 2 : 0 //Investing into genetic strength improvements makes you a better boxer + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = attacker.get_organ_slot(ORGAN_SLOT_SPINE) //Getting a cyberspine also pushes you further than just mere meat + if(istype(potential_spine)) + strength_bonus *= potential_spine.strength_bonus + damage += round(athletics_skill * check_streak(attacker, defender) + strength_bonus) grant_experience = TRUE diff --git a/code/game/objects/items/climbingrope.dm b/code/game/objects/items/climbingrope.dm index 693f850be2a98..e68e508771248 100644 --- a/code/game/objects/items/climbingrope.dm +++ b/code/game/objects/items/climbingrope.dm @@ -50,7 +50,19 @@ playsound(user_turf, 'sound/effects/picaxe1.ogg', 50) var/list/effects = list(new /obj/effect/temp_visual/climbing_hook(target, away_dir), new /obj/effect/temp_visual/climbing_hook(user_turf, away_dir)) - if(do_after(user, climb_time, target)) + // Our climbers athletics ability + var/fitness_level = user.mind?.get_skill_level(/datum/skill/athletics) + + // Misc bonuses to the climb speed. + var/misc_multiplier = 1 + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = user.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + misc_multiplier *= potential_spine.athletics_boost_multiplier + + var/final_climb_time = (climb_time - fitness_level) * misc_multiplier + + if(do_after(user, final_climb_time, target)) user.forceMove(target) uses-- diff --git a/code/game/objects/structures/gym/punching_bag.dm b/code/game/objects/structures/gym/punching_bag.dm index 03a64725ab5e3..59ccf6f23c2c3 100644 --- a/code/game/objects/structures/gym/punching_bag.dm +++ b/code/game/objects/structures/gym/punching_bag.dm @@ -58,6 +58,10 @@ if (is_heavy_gravity) stamina_exhaustion *= 1.5 + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = user.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + stamina_exhaustion *= potential_spine.athletics_boost_multiplier + if(HAS_TRAIT(user, TRAIT_STRENGTH)) //The strong get reductions to stamina damage taken while exercising stamina_exhaustion *= 0.5 diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index 3c531f0488929..352ef65ff0050 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -171,10 +171,14 @@ 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) - + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = user.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + stamina_exhaustion *= potential_spine.athletics_boost_multiplier + 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 diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm index ef6ea9d433e8f..314539aa2b412 100644 --- a/code/game/objects/structures/ladders.dm +++ b/code/game/objects/structures/ladders.dm @@ -105,7 +105,20 @@ /obj/structure/ladder/proc/start_travelling(mob/user, going_up) show_initial_fluff_message(user, going_up) - if(do_after(user, travel_time, target = src, interaction_key = DOAFTER_SOURCE_CLIMBING_LADDER)) + + // Our climbers athletics ability + var/fitness_level = user.mind?.get_skill_level(/datum/skill/athletics) + + // Misc bonuses to the climb speed. + var/misc_multiplier = 1 + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = user.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + misc_multiplier *= potential_spine.athletics_boost_multiplier + + var/final_travel_time = (travel_time - fitness_level) * misc_multiplier + + if(do_after(user, final_travel_time, target = src, interaction_key = DOAFTER_SOURCE_CLIMBING_LADDER)) travel(user, going_up) /// The message shown when the player starts climbing the ladder diff --git a/code/game/objects/structures/lavaland/gulag_vent.dm b/code/game/objects/structures/lavaland/gulag_vent.dm index b564908cdc6c1..c269c5213e71a 100644 --- a/code/game/objects/structures/lavaland/gulag_vent.dm +++ b/code/game/objects/structures/lavaland/gulag_vent.dm @@ -30,7 +30,14 @@ var/mob/living/living_user = user occupied = TRUE living_user.balloon_alert_to_viewers("hauling...") - var/succeeded = do_after(living_user, 8 SECONDS, src) + + var/boulder_lift_speed = 8 SECONDS + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = living_user.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + boulder_lift_speed *= potential_spine.athletics_boost_multiplier + + var/succeeded = do_after(living_user, boulder_lift_speed, src) occupied = FALSE if (!succeeded) return diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 69c6aca505f36..546b6ad796827 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -275,6 +275,11 @@ else if(HAS_TRAIT(user, TRAIT_QUICK_CARRY)) tableplace_delay = 2.75 SECONDS skills_space = " quickly" + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = user.get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + tableplace_delay *= potential_spine.athletics_boost_multiplier + carried_mob.visible_message(span_notice("[user] begins to[skills_space] place [carried_mob] onto [src]..."), span_userdanger("[user] begins to[skills_space] place [carried_mob] onto [src]...")) if(do_after(user, tableplace_delay, target = carried_mob)) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 696b2b5c4a7fc..35e15cc04537f 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -195,6 +195,11 @@ span_danger("You [verb_text] [thrown_thing][power_throw_text]")) log_message("has thrown [thrown_thing] [power_throw_text]", LOG_ATTACK) var/extra_throw_range = HAS_TRAIT(src, TRAIT_THROWINGARM) ? 2 : 0 + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + extra_throw_range += potential_spine.added_throw_range + newtonian_move(get_dir(target, src)) thrown_thing.safe_throw_at(target, thrown_thing.throw_range + extra_throw_range, max(1,thrown_thing.throw_speed + power_throw), src, null, null, null, move_force) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 1dd47f8060426..94df3d3c4333b 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -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/athletics) - 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)) @@ -924,6 +924,10 @@ // can remove up to 2 seconds at legendary carrydelay -= fitness_level * (1/3) SECONDS + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + carrydelay *= potential_spine.athletics_boost_multiplier + if(carrydelay <= 3 SECONDS) skills_space = " very quickly" else if(carrydelay <= 4 SECONDS) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c7a0c034ac5aa..2873dab1a71bc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -62,6 +62,12 @@ . = SEND_SIGNAL(src, COMSIG_LIVING_Z_IMPACT, levels, impacted_turf) if(. & ZIMPACT_CANCEL_DAMAGE) return . + // multiplier for the damage taken from falling + var/damage_softening_multiplier = 1 + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + damage_softening_multiplier *= potential_spine.athletics_boost_multiplier // If you are incapped, you probably can't brace yourself var/can_help_themselves = !incapacitated(IGNORE_RESTRAINTS) @@ -108,7 +114,7 @@ new /obj/effect/temp_visual/mook_dust(impacted_turf) if(body_position == STANDING_UP) - var/damage_for_each_leg = round(incoming_damage / 2) + var/damage_for_each_leg = round((incoming_damage / 2) * damage_softening_multiplier) apply_damage(damage_for_each_leg, BRUTE, BODY_ZONE_L_LEG, wound_bonus = -2.5 * levels) apply_damage(damage_for_each_leg, BRUTE, BODY_ZONE_R_LEG, wound_bonus = -2.5 * levels) else @@ -678,6 +684,13 @@ /mob/living/proc/get_up(instant = FALSE) set waitfor = FALSE + + var/get_up_time = 1 SECONDS + + var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + get_up_time *= potential_spine.athletics_boost_multiplier + if(!instant && !do_after(src, 1 SECONDS, src, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM), extra_checks = CALLBACK(src, TYPE_PROC_REF(/mob/living, rest_checks_callback)), interaction_key = DOAFTER_SOURCE_GETTING_UP, hidden = TRUE)) return if(resting || body_position == STANDING_UP || HAS_TRAIT(src, TRAIT_FLOORED)) diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index cbd05593a3c11..27dbbca1d179c 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -566,6 +566,24 @@ ) departmental_flags = DEPARTMENT_BITFLAG_MEDICAL +/datum/design/cyberimp_herculean + name = "Herculean Gravitronic Spinal Implant" + desc = "This gravitronic spinal interface allows the user to reduce the impact of gravity on their body, effectively improving athletic performance." + id = "ci-herculean" + build_type = PROTOLATHE | AWAY_LATHE | MECHFAB + construction_time = 4 SECONDS + materials = list( + /datum/material/iron =SMALL_MATERIAL_AMOUNT*5, + /datum/material/titanium=SMALL_MATERIAL_AMOUNT*3, + /datum/material/gold=SMALL_MATERIAL_AMOUNT*3, + /datum/material/diamond =SMALL_MATERIAL_AMOUNT*5, + ) + build_path = /obj/item/organ/internal/cyberimp/chest/spine + category = list( + RND_CATEGORY_CYBERNETICS + RND_SUBCATEGORY_CYBERNETICS_IMPLANTS_HEALTH + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL + /datum/design/cyberimp_nutriment name = "Nutriment Pump Implant" desc = "This implant will synthesize and pump into your bloodstream a small amount of nutriment when you are starving." diff --git a/code/modules/research/techweb/nodes/cyborg_nodes.dm b/code/modules/research/techweb/nodes/cyborg_nodes.dm index 447ee2dc7f3b9..0a4fa91429484 100644 --- a/code/modules/research/techweb/nodes/cyborg_nodes.dm +++ b/code/modules/research/techweb/nodes/cyborg_nodes.dm @@ -152,6 +152,7 @@ "ci-breather", "ci-nutriment", "ci-thrusters", + "ci-herculean", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS) diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index 24aadfeca14f6..046c84200d1eb 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -260,3 +260,60 @@ deactivate(silent = TRUE) return FALSE + +/obj/item/organ/internal/cyberimp/chest/spine + name = "\improper Herculean gravitronic spinal implant" + desc = "This gravitronic spinal interface is able to improve the athletics of a user, allowing them greater physical ability. \ + Contains a slot which can be upgraded with a gravity anomaly core, improving its performance." + implant_color = "#15704c" + slot = ORGAN_SLOT_SPINE + /// How much faster does the spinal implant improve our lifting speed, workout ability, reducing falling damage and improving climbing and standing speed + var/athletics_boost_multiplier = 0.8 + /// How much additional throwing range does our spinal implant grant us. + var/added_throw_range = 2 + /// How much additional boxing damage and tackling power do we add? + var/strength_bonus = 4 + /// Whether or not a gravity anomaly core has been installed, improving the effectiveness of the spinal implant. + var/core_applied = FALSE + /// The overlay for our implant to indicate that, yes, this person has an implant inserted. + var/mutable_appearance/stone_overlay + +/obj/item/organ/internal/cyberimp/chest/spine/emp_act(severity) + . = ..() + if(!owner || . & EMP_PROTECT_SELF) + return + to_chat(owner, span_warning("You feel sheering pain as your body is crushed like a soda can!")) + owner.apply_damage(20/severity, BRUTE, def_zone = BODY_ZONE_CHEST) + +/obj/item/organ/internal/cyberimp/chest/spine/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) + . = ..() + stone_overlay = mutable_appearance(icon = 'icons/effects/effects.dmi', icon_state = "stone") + organ_owner.add_overlay(stone_overlay) + if(core_applied) + organ_owner.AddElement(/datum/element/forced_gravity, 1) + +/obj/item/organ/internal/cyberimp/chest/spine/on_mob_remove(mob/living/carbon/organ_owner, special) + . = ..() + if(stone_overlay) + organ_owner.cut_overlay(stone_overlay) + stone_overlay = null + if(core_applied) + organ_owner.RemoveElement(/datum/element/forced_gravity, 1) + +/obj/item/organ/internal/cyberimp/chest/spine/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(core_applied) + user.balloon_alert(user, "core already installed!") + return ITEM_INTERACT_BLOCKING + + if(istype(tool, /obj/item/assembly/signaler/anomaly/grav)) + user.balloon_alert(user, "core installed.") + athletics_boost_multiplier = 0.25 + added_throw_range += 2 + strength_bonus += 4 + core_applied = TRUE + name = "\improper Atlas gravitonic spinal implant" + desc = "This gravitronic spinal interface is able to improve the athletics of a user, allowing them greater physical ability. \ + This one has been improved through the installation of a gravity anomaly core, allowing for personal gravity manipulation." + qdel(tool) + return ITEM_INTERACT_SUCCESS diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 1b6e8d68e3682..633004afacad2 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ