mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
## About The Pull Request 1. Penbang A flashbang disguised as a pen. Clicking the pen arms the flashbang and has no other visual or audio tell besides the pen clicking. The fuse's length is based on the angle the pen cap is twisted. Works as a normal pen otherwise. 2. Camera Flash A camera with a high power flash. Clicking on an adjacent target will flash them, ie, as a handheld flash. Works as a normal camera otherwise - no tell. 3. Dagger Boot A pair of jackboots with a blade embedded in them. Makes your kicks sharp, meaning they will cause bleeding. Looks like normal jackboots otherwise, though has a tell on double-examine 4. Monster Cube Box A box containing 5 monster cubes, which spawn into a random monster when wet. Monsters include Migos, Carps, Bears, Spiders, Wolves... 5. Spider Bite Scroll A martial art focused around kicks and grabs. - Punches against standing, staggered targets will instead kick them, applying the bonus accuracy and damage that you'd expect from a kick. (Also combos with the dagger boots) - All kicks have a chance to disarm the target's active weapon. Chance increases per sequential kick. - Grants you the innate ability to tackle. This form of tackling has a very high skill modifier, meaning you are very likely to get a positive outcome (or at least, not fail). You also get up fast from it. - Your grabs are 20% harder to escape from and deal an additional 10 stam damage on fail. ## Why It's Good For The Game 1, 2, 3: Just some random flavorful items, giving them some more toys to use to complete bounties. 4: Shenanigans, for people who just wanna do "funny thing" instead of focusing on big loot. 5: I figured it would fill a fun niche: Spies are commonly depicted as martial artists, and the only martial arts they can obtain is Krav Maga (it's not unique to Spies) and Sleeping Carp (it's not unique to Spies). This gives them their own thing that people may look forward to acquiring and playing around with. As for the design of it, I wanted to add something that synergizes with one of the other other items, so in the field if you notice both of them pop up you really want to go for both. The rest of the design I just filled in as vaguely useful and flavorful tools a spy might want for kidnapping or detaining people: Better grabs, tackling, and disarms. Then I just went with the flavor of it being something the Spider Clan used to teach to their Spies / Ninjas, kinda like an analog to the real life Ninjutsu. (Maybe we can give it to Space Ninjas as well later... since it doesn't especially benefit Ninjas in any way.) ## Changelog 🆑 Melbert add: Adds 5 rewards to the Spy item pool: Penbang, Camera Flash, Dagger-Boot, Monster Cube Box, and the Spider Bite martial art /🆑
343 lines
16 KiB
Plaintext
343 lines
16 KiB
Plaintext
#define STRONG_PUNCH_COMBO "HH"
|
|
#define LAUNCH_KICK_COMBO "HD"
|
|
#define DROP_KICK_COMBO "DD"
|
|
|
|
/datum/martial_art/the_sleeping_carp
|
|
name = "The Sleeping Carp"
|
|
id = MARTIALART_SLEEPINGCARP
|
|
help_verb = /mob/living/proc/sleeping_carp_help
|
|
display_combos = TRUE
|
|
/// List of traits applied to users of this martial art.
|
|
var/list/scarp_traits = list(TRAIT_NOGUNS, TRAIT_TOSS_GUN_HARD, TRAIT_HARDLY_WOUNDED, TRAIT_NODISMEMBER, TRAIT_HEAVY_SLEEPER)
|
|
|
|
/datum/martial_art/the_sleeping_carp/activate_style(mob/living/new_holder)
|
|
. = ..()
|
|
new_holder.add_traits(scarp_traits, SLEEPING_CARP_TRAIT)
|
|
RegisterSignal(new_holder, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
|
|
RegisterSignal(new_holder, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile))
|
|
new_holder.faction |= FACTION_CARP //:D
|
|
new_holder.grant_language(/datum/language/carptongue, ALL, type)
|
|
|
|
/datum/martial_art/the_sleeping_carp/deactivate_style(mob/living/remove_from)
|
|
remove_from.remove_traits(scarp_traits, SLEEPING_CARP_TRAIT)
|
|
UnregisterSignal(remove_from, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_PRE_BULLET_ACT))
|
|
remove_from.faction -= FACTION_CARP //:(
|
|
remove_from.remove_language(/datum/language/carptongue, ALL, type)
|
|
return ..()
|
|
|
|
/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/attacker, mob/living/defender)
|
|
if(findtext(streak,STRONG_PUNCH_COMBO))
|
|
reset_streak()
|
|
return strongPunch(attacker, defender)
|
|
|
|
if(findtext(streak,LAUNCH_KICK_COMBO))
|
|
reset_streak()
|
|
return launchKick(attacker, defender)
|
|
|
|
if(findtext(streak,DROP_KICK_COMBO))
|
|
reset_streak()
|
|
return dropKick(attacker, defender)
|
|
|
|
return FALSE
|
|
|
|
///Gnashing Teeth: Harm Harm, consistent 20 force punch on every second harm punch
|
|
/datum/martial_art/the_sleeping_carp/proc/strongPunch(mob/living/attacker, mob/living/defender)
|
|
// this var is so that the strong punch is always aiming for the body part the user is targeting and not trying to apply to the chest before deviating
|
|
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
|
|
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
|
var/atk_verb = pick("precisely kick", "brutally chop", "cleanly hit", "viciously slam")
|
|
defender.visible_message(
|
|
span_danger("[attacker] [atk_verb]s [defender]!"),
|
|
span_userdanger("[attacker] [atk_verb]s you!"),
|
|
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
|
null,
|
|
attacker,
|
|
)
|
|
to_chat(attacker, span_danger("You [atk_verb] [defender]!"))
|
|
playsound(defender, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1)
|
|
log_combat(attacker, defender, "strong punched (Sleeping Carp)")
|
|
defender.apply_damage(20, attacker.get_attack_type(), affecting)
|
|
return TRUE
|
|
|
|
///Crashing Wave Kick: Harm Disarm combo, throws people seven tiles backwards
|
|
/datum/martial_art/the_sleeping_carp/proc/launchKick(mob/living/attacker, mob/living/defender)
|
|
attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK)
|
|
defender.visible_message(
|
|
span_warning("[attacker] kicks [defender] square in the chest, sending them flying!"),
|
|
span_userdanger("You are kicked square in the chest by [attacker], sending you flying!"),
|
|
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
|
COMBAT_MESSAGE_RANGE,
|
|
attacker,
|
|
)
|
|
playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
|
var/atom/throw_target = get_edge_target_turf(defender, attacker.dir)
|
|
defender.throw_at(throw_target, 7, 4, attacker)
|
|
defender.apply_damage(15, attacker.get_attack_type(), BODY_ZONE_CHEST, wound_bonus = CANT_WOUND)
|
|
log_combat(attacker, defender, "launchkicked (Sleeping Carp)")
|
|
return TRUE
|
|
|
|
///Keelhaul: Disarm Disarm combo, knocks people down and deals substantial stamina damage, and also discombobulates them. Knocks objects out of their hands if they're already on the ground.
|
|
/datum/martial_art/the_sleeping_carp/proc/dropKick(mob/living/attacker, mob/living/defender)
|
|
attacker.do_attack_animation(defender, ATTACK_EFFECT_KICK)
|
|
playsound(attacker, 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
|
if(defender.body_position == STANDING_UP)
|
|
defender.Knockdown(4 SECONDS)
|
|
defender.visible_message(span_warning("[attacker] kicks [defender] in the head, sending them face first into the floor!"), \
|
|
span_userdanger("You are kicked in the head by [attacker], sending you crashing to the floor!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
|
else
|
|
defender.drop_all_held_items()
|
|
defender.visible_message(span_warning("[attacker] kicks [defender] in the head!"), \
|
|
span_userdanger("You are kicked in the head by [attacker]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, attacker)
|
|
defender.apply_damage(40, STAMINA)
|
|
defender.adjust_dizzy_up_to(10 SECONDS, 10 SECONDS)
|
|
defender.adjust_temp_blindness_up_to(2 SECONDS, 10 SECONDS)
|
|
log_combat(attacker, defender, "dropkicked (Sleeping Carp)")
|
|
return TRUE
|
|
|
|
/datum/martial_art/the_sleeping_carp/grab_act(mob/living/attacker, mob/living/defender)
|
|
if(!can_deflect(attacker)) //allows for deniability
|
|
return MARTIAL_ATTACK_INVALID
|
|
|
|
if(defender.check_block(attacker, 0, "[attacker]'s grab", UNARMED_ATTACK))
|
|
return MARTIAL_ATTACK_FAIL
|
|
|
|
add_to_streak("G", defender)
|
|
if(check_streak(attacker, defender))
|
|
return MARTIAL_ATTACK_SUCCESS
|
|
|
|
var/grab_log_description = "grabbed"
|
|
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
|
playsound(defender, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1)
|
|
if(defender.stat != DEAD && !defender.IsUnconscious() && defender.getStaminaLoss() >= 80) //We put our target to sleep.
|
|
defender.visible_message(
|
|
span_danger("[attacker] carefully pinch a nerve in [defender]'s neck, knocking them out cold!"),
|
|
span_userdanger("[attacker] pinches something in your neck, and you fall unconscious!"),
|
|
)
|
|
grab_log_description = "grabbed and nerve pinched"
|
|
defender.Unconscious(10 SECONDS)
|
|
defender.apply_damage(20, STAMINA)
|
|
log_combat(attacker, defender, "[grab_log_description] (Sleeping Carp)")
|
|
return MARTIAL_ATTACK_INVALID // normal grab
|
|
|
|
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/attacker, mob/living/defender)
|
|
if(attacker.grab_state == GRAB_KILL \
|
|
&& attacker.zone_selected == BODY_ZONE_HEAD \
|
|
&& attacker.pulling == defender \
|
|
&& defender.stat != DEAD \
|
|
)
|
|
var/obj/item/bodypart/head = defender.get_bodypart(BODY_ZONE_HEAD)
|
|
if(!isnull(head))
|
|
playsound(defender, 'sound/effects/wounds/crack1.ogg', 100)
|
|
defender.visible_message(
|
|
span_danger("[attacker] snaps the neck of [defender]!"),
|
|
span_userdanger("Your neck is snapped by [attacker]!"),
|
|
span_hear("You hear a sickening snap!"),
|
|
ignored_mobs = attacker
|
|
)
|
|
to_chat(attacker, span_danger("In a swift motion, you snap the neck of [defender]!"))
|
|
log_combat(attacker, defender, "snapped neck")
|
|
defender.apply_damage(100, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND)
|
|
if(!HAS_TRAIT(defender, TRAIT_NODEATH))
|
|
defender.death()
|
|
defender.investigate_log("has had [defender.p_their()] neck snapped by [attacker].", INVESTIGATE_DEATHS)
|
|
return MARTIAL_ATTACK_SUCCESS
|
|
|
|
var/atk_verb = pick("kick", "chop", "hit", "slam")
|
|
var/final_damage = rand(10, 15)
|
|
if(defender.check_block(attacker, final_damage, "[attacker]'s [atk_verb]", UNARMED_ATTACK))
|
|
return MARTIAL_ATTACK_FAIL
|
|
|
|
add_to_streak("H", defender)
|
|
if(check_streak(attacker, defender))
|
|
return MARTIAL_ATTACK_SUCCESS
|
|
|
|
var/obj/item/bodypart/affecting = defender.get_bodypart(defender.get_random_valid_zone(attacker.zone_selected))
|
|
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
|
defender.visible_message(
|
|
span_danger("[attacker] [atk_verb]s [defender]!"),
|
|
span_userdanger("[attacker] [atk_verb]s you!"),
|
|
span_hear("You hear a sickening sound of flesh hitting flesh!"),
|
|
null,
|
|
attacker,
|
|
)
|
|
to_chat(attacker, span_danger("You [atk_verb] [defender]!"))
|
|
defender.apply_damage(final_damage, attacker.get_attack_type(), affecting, wound_bonus = CANT_WOUND)
|
|
playsound(defender, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1)
|
|
log_combat(attacker, defender, "punched (Sleeping Carp)")
|
|
return MARTIAL_ATTACK_SUCCESS
|
|
|
|
/datum/martial_art/the_sleeping_carp/disarm_act(mob/living/attacker, mob/living/defender)
|
|
if(!can_deflect(attacker)) //allows for deniability
|
|
return MARTIAL_ATTACK_INVALID
|
|
if(defender.check_block(attacker, 0, attacker.name, UNARMED_ATTACK))
|
|
return MARTIAL_ATTACK_FAIL
|
|
|
|
add_to_streak("D", defender)
|
|
if(check_streak(attacker, defender))
|
|
return MARTIAL_ATTACK_SUCCESS
|
|
|
|
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
|
|
playsound(defender, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1)
|
|
defender.apply_damage(20, STAMINA)
|
|
log_combat(attacker, defender, "disarmed (Sleeping Carp)")
|
|
return MARTIAL_ATTACK_INVALID // normal disarm
|
|
|
|
/datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user)
|
|
if(!can_use(carp_user) || !carp_user.combat_mode)
|
|
return FALSE
|
|
if(INCAPACITATED_IGNORING(carp_user, INCAPABLE_GRAB)) //NO STUN
|
|
return FALSE
|
|
if(!(carp_user.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE
|
|
return FALSE
|
|
if(HAS_TRAIT(carp_user, TRAIT_HULK)) //NO HULK
|
|
return FALSE
|
|
if(!isturf(carp_user.loc)) //NO MOTHERFLIPPIN MECHS!
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/martial_art/the_sleeping_carp/proc/hit_by_projectile(mob/living/carp_user, obj/projectile/hitting_projectile, def_zone)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!can_deflect(carp_user))
|
|
return NONE
|
|
|
|
carp_user.visible_message(
|
|
span_danger("[carp_user] effortlessly swats [hitting_projectile] aside! [carp_user.p_They()] can block bullets with [carp_user.p_their()] bare hands!"),
|
|
span_userdanger("You deflect [hitting_projectile]!"),
|
|
)
|
|
playsound(carp_user, SFX_BULLET_MISS, 75, TRUE)
|
|
hitting_projectile.firer = carp_user
|
|
hitting_projectile.set_angle(rand(0, 360))//SHING
|
|
return COMPONENT_BULLET_PIERCED
|
|
|
|
///Signal from getting attacked with an item, for a special interaction with touch spells
|
|
/datum/martial_art/the_sleeping_carp/proc/on_attackby(mob/living/carp_user, obj/item/attack_weapon, mob/attacker, list/modifiers)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!istype(attack_weapon, /obj/item/melee/touch_attack))
|
|
return
|
|
if(!can_deflect(carp_user))
|
|
return
|
|
var/obj/item/melee/touch_attack/touch_weapon = attack_weapon
|
|
carp_user.visible_message(
|
|
span_danger("[carp_user] carefully dodges [attacker]'s [touch_weapon]!"),
|
|
span_userdanger("You take great care to remain untouched by [attacker]'s [touch_weapon]!"),
|
|
)
|
|
return COMPONENT_NO_AFTERATTACK
|
|
|
|
/// Verb added to humans who learn the art of the sleeping carp.
|
|
/mob/living/proc/sleeping_carp_help()
|
|
set name = "Recall Teachings"
|
|
set desc = "Remember the martial techniques of the Sleeping Carp clan."
|
|
set category = "Sleeping Carp"
|
|
|
|
to_chat(usr, span_info("<b><i>You retreat inward and recall the teachings of the Sleeping Carp...</i></b>\n\
|
|
[span_notice("Gnashing Teeth")]: Punch Punch. Deal additional damage every second (consecutive) punch! Very good chance to wound!\n\
|
|
[span_notice("Crashing Wave Kick")]: Punch Shove. Launch your opponent away from you with incredible force!\n\
|
|
[span_notice("Keelhaul")]: Shove Shove. Nonlethally kick an opponent to the floor, knocking them down, discombobulating them and dealing substantial stamina damage. If they're already prone, disarm them as well.\n\
|
|
[span_notice("Grabs and Shoves")]: While in combat mode, your typical grab and shove do decent stamina damage. If you grab someone who has substantial amounts of stamina damage, you knock them out!\n\
|
|
<span class='notice'>While in combat mode (and not stunned, not a hulk, and not in a mech), you can reflect all projectiles that come your way, sending them back at the people who fired them! \n\
|
|
Also, you are more resilient against suffering wounds in combat, and your limbs cannot be dismembered. This grants you extra staying power during extended combat, especially against slashing and other bleeding weapons. \n\
|
|
You are not invincible, however- while you may not suffer debilitating wounds often, you must still watch your health and should have appropriate medical supplies for use during downtime. \n\
|
|
In addition, your training has imbued you with a loathing of guns, and you can no longer use them.</span>"))
|
|
|
|
|
|
/obj/item/staff/bostaff
|
|
name = "bo staff"
|
|
desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate."
|
|
force = 10
|
|
w_class = WEIGHT_CLASS_BULKY
|
|
slot_flags = ITEM_SLOT_BACK
|
|
throwforce = 20
|
|
throw_speed = 2
|
|
attack_verb_continuous = list("smashes", "slams", "whacks", "thwacks")
|
|
attack_verb_simple = list("smash", "slam", "whack", "thwack")
|
|
icon = 'icons/obj/weapons/staff.dmi'
|
|
icon_state = "bostaff0"
|
|
base_icon_state = "bostaff"
|
|
icon_angle = -135
|
|
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
|
|
block_chance = 50
|
|
|
|
/obj/item/staff/bostaff/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/two_handed, \
|
|
force_unwielded = 10, \
|
|
force_wielded = 24, \
|
|
)
|
|
|
|
/obj/item/staff/bostaff/update_icon_state()
|
|
icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]"
|
|
return ..()
|
|
|
|
/obj/item/staff/bostaff/attack(mob/target, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
add_fingerprint(user)
|
|
if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
|
|
to_chat(user, span_warning("You club yourself over the head with [src]."))
|
|
user.Paralyze(6 SECONDS)
|
|
if(ishuman(user))
|
|
var/mob/living/carbon/human/H = user
|
|
H.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD)
|
|
else
|
|
user.take_bodypart_damage(2*force)
|
|
return
|
|
if(iscyborg(target))
|
|
return ..()
|
|
if(!isliving(target))
|
|
return ..()
|
|
var/mob/living/carbon/C = target
|
|
if(C.stat)
|
|
to_chat(user, span_warning("It would be dishonorable to attack a foe while they cannot retaliate."))
|
|
return
|
|
if(LAZYACCESS(modifiers, RIGHT_CLICK))
|
|
if(!HAS_TRAIT(src, TRAIT_WIELDED))
|
|
return ..()
|
|
if(!ishuman(target))
|
|
return ..()
|
|
var/mob/living/carbon/human/H = target
|
|
var/list/fluffmessages = list("club", "smack", "broadside", "beat", "slam")
|
|
H.visible_message(span_warning("[user] [pick(fluffmessages)]s [H] with [src]!"), \
|
|
span_userdanger("[user] [pick(fluffmessages)]s you with [src]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, user)
|
|
to_chat(user, span_danger("You [pick(fluffmessages)] [H] with [src]!"))
|
|
playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, TRUE, -1)
|
|
H.adjustStaminaLoss(rand(13,20))
|
|
if(prob(10))
|
|
H.visible_message(span_warning("[H] collapses!"), \
|
|
span_userdanger("Your legs give out!"))
|
|
H.Paralyze(8 SECONDS)
|
|
if(H.staminaloss && !H.IsSleeping())
|
|
var/total_health = (H.health - H.staminaloss)
|
|
if(total_health <= HEALTH_THRESHOLD_CRIT && !H.stat)
|
|
H.visible_message(span_warning("[user] delivers a heavy hit to [H]'s head, knocking [H.p_them()] out cold!"), \
|
|
span_userdanger("You're knocked unconscious by [user]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, user)
|
|
to_chat(user, span_danger("You deliver a heavy hit to [H]'s head, knocking [H.p_them()] out cold!"))
|
|
H.SetSleeping(60 SECONDS)
|
|
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 150)
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/staff/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
|
|
if(!HAS_TRAIT(src, TRAIT_WIELDED))
|
|
return ..()
|
|
return FALSE
|
|
|
|
/obj/item/clothing/gloves/the_sleeping_carp
|
|
name = "carp gloves"
|
|
desc = "These gloves are capable of making people use The Sleeping Carp."
|
|
icon_state = "black"
|
|
greyscale_colors = COLOR_BLACK
|
|
cold_protection = HANDS
|
|
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
|
heat_protection = HANDS
|
|
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
|
|
resistance_flags = NONE
|
|
|
|
/obj/item/clothing/gloves/the_sleeping_carp/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/martial_art_giver, /datum/martial_art/the_sleeping_carp)
|
|
|
|
#undef STRONG_PUNCH_COMBO
|
|
#undef LAUNCH_KICK_COMBO
|
|
#undef DROP_KICK_COMBO
|