Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor rework to preternis liquidator #22657

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
240 changes: 169 additions & 71 deletions yogstation/code/datums/martial/stealth.dm
Original file line number Diff line number Diff line change
@@ -1,93 +1,173 @@
///hidden dagger
#define PRE_DAGGER_COMBO "HH"
#define DAGGER_COMBO "HHG"
///injection
#define PRE_INJECTION_COMBO "DG"
#define INJECTION_COMBO "ID"
#define DAGGER_COMBO "HH"
///fingergun
#define FINGERGUN_COMBO "HDD"
#define FINGERGUN_COMBO "HG"

/datum/martial_art/liquidator
name = "Liquidator"
id = MARTIALART_LIQUIDATOR
help_verb = /mob/living/carbon/human/proc/preternis_martial_help
/// List of chemicals and how much is injected, will inject in descending order based on if a target has at least half the designated amount
var/list/injection_chems = list(
/datum/reagent/toxin/sodium_thiopental = 10,
/datum/reagent/toxin/cyanide = 5
)
/// Chem injected if no other chem is valid
var/datum/reagent/default_chem = /datum/reagent/toxin/cyanide

/datum/martial_art/liquidator/can_use(mob/living/carbon/human/H)
return ispreternis(H)
if(!H.combat_mode)
return FALSE
if(!ispreternis(H))
return FALSE
return TRUE

/datum/martial_art/liquidator/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return
if(findtext(streak, FINGERGUN_COMBO)) //prioritize the gun combo because the dagger combo can combo into itself
fingergun(A,D)
streak = ""
return TRUE //don't upgrade the grab

if(findtext(streak, DAGGER_COMBO))
hidden_knife(A,D)
return TRUE

/datum/martial_art/liquidator/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(A.combat_mode && A!=D && (can_use(A))) // A!=D prevents grabbing yourself
add_to_streak("G",D)
if(check_streak(A,D)) //if a combo is made no grab upgrade is done
return TRUE
if(!can_use(A))
return FALSE
else
if(A == D)
return FALSE

add_to_streak("G",D)
if(check_streak(A,D)) //if a combo is made no grab upgrade is done (QoL rather than stealth)
return TRUE
return FALSE

/datum/martial_art/liquidator/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE

add_to_streak("H",D)
if(check_streak(A,D))
if(check_streak(A,D)) //stab doesn't seem like anything
return TRUE
return FALSE ///We need it work like a generic, non martial art attack


/datum/martial_art/liquidator/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!(can_use(A)))
return FALSE
add_to_streak("D",D)
if(check_streak(A,D))
return TRUE
return FALSE ///Same as with harm_act

/datum/martial_art/liquidator/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return
if(findtext(streak, PRE_DAGGER_COMBO))
return hidden_knife(A,D)
var/datum/reagent/picked_chem = default_chem
var/amount = injection_chems[picked_chem]

if(findtext(streak, PRE_INJECTION_COMBO))
inject_one(A,D)
return TRUE
if(findtext(streak, INJECTION_COMBO))
inject_two(A,D)
return TRUE

if(findtext(streak, FINGERGUN_COMBO))
fingergun(A,D)
return FALSE
for(var/i in injection_chems)
var/has_reagent = D.reagents.get_reagent_amount(i)
if(has_reagent <= (injection_chems[i]/2))
picked_chem = i
amount = injection_chems[i]
break

/datum/martial_art/liquidator/proc/hidden_knife(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(findtext(streak, DAGGER_COMBO))
var/selected_zone = A.zone_selected
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(selected_zone))
var/armor_block = D.run_armor_check(affecting, MELEE, armour_penetration = 40)
D.apply_damage(A.get_punchdamagehigh() * 2 + 10, BRUTE, selected_zone, armor_block, sharpness = SHARP_EDGED) //30 damage
to_chat(A, span_warning("You stab [D] with a hidden blade!"))
to_chat(D, span_userdanger("You are suddenly stabbed with a blade!"))
streak = ""
return TRUE
else
var/selected_zone = A.zone_selected
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(selected_zone))
var/armor_block = D.run_armor_check(affecting, MELEE, armour_penetration = 10)
D.apply_damage(A.get_punchdamagehigh() * 1.5 + 5, STAMINA, affecting, armor_block) //20 stamina
D.apply_damage(A.get_punchdamagehigh() / 2, BRUTE, affecting, armor_block) //5 brute
return FALSE //Because it is a stealthy martial art, we need it to work like... a normal shove, so people nearby couldn't understand so easy that you know a martial art.


/datum/martial_art/liquidator/proc/inject_one(mob/living/carbon/human/A, mob/living/carbon/human/D)
D.reagents.add_reagent(/datum/reagent/toxin/sodium_thiopental, 8)
to_chat(A, span_warning("You inject sodium thiopental into [D]!"))
D.reagents.add_reagent(picked_chem, amount)
to_chat(A, span_warning("You inject [initial(picked_chem.name)] into [D]!"))
to_chat(D, span_notice("You feel a tiny prick."))
streak = "I"

/datum/martial_art/liquidator/proc/inject_two(mob/living/carbon/human/A, mob/living/carbon/human/D)
D.reagents.add_reagent(/datum/reagent/toxin/cyanide, 5)
to_chat(A, span_warning("You inject cyanide into [D]!"))
to_chat(D, span_notice("You feel a tiny prick."))
streak = ""
return FALSE //always looks like a generic push

//////////////////////////////////////////////////////////////////////////////////
//------------------------------Hidden knife------------------------------------//
//////////////////////////////////////////////////////////////////////////////////
/datum/martial_art/liquidator/proc/hidden_knife(mob/living/carbon/human/user, mob/living/carbon/human/target)
/**
* Literally just copy pasted all this from /proc/disarm in _species.dm
* we are pretending to be a shove
*/
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)

var/shove_dir = get_dir(user.loc, target.loc)
var/turf/target_shove_turf = get_step(target.loc, shove_dir)
var/mob/living/carbon/human/target_collateral_human
var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied

//Thank you based whoneedsspace
target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents
var/bothstanding = target_collateral_human && (target.mobility_flags & MOBILITY_STAND) && (target_collateral_human.mobility_flags & MOBILITY_STAND)
if(target_collateral_human && bothstanding)
shove_blocked = TRUE
else
target.Move(target_shove_turf, shove_dir)
if(get_turf(target) != target_shove_turf)
shove_blocked = TRUE

if(shove_blocked && !target.is_shove_knockdown_blocked() && !target.buckled)
var/directional_blocked = FALSE
if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that
var/target_turf = get_turf(target)
for(var/obj/O in target_turf)
if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density)
directional_blocked = TRUE
break
if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile
for(var/obj/O in target_shove_turf)
if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density)
directional_blocked = TRUE
break
if(!bothstanding || directional_blocked)
var/obj/item/I = target.get_active_held_item()
if(target.dropItemToGround(I))
user.visible_message(span_danger("[user.name] shoves [target.name], disarming them!"), span_danger("You shove [target.name], disarming them!"), null, COMBAT_MESSAGE_RANGE)
log_combat(user, target, "liquidator hidden knife shove", "disarming them")
else if(bothstanding)
target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
if(!target_collateral_human.is_shove_knockdown_blocked())
target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
user.visible_message(span_danger("[user.name] shoves [target.name] into [target_collateral_human.name]!"), span_danger("You shove [target.name] into [target_collateral_human.name]!"), null, COMBAT_MESSAGE_RANGE)
log_combat(user, target, "liquidator hidden knife shove", "into [target_collateral_human.name]")
else
user.visible_message(span_danger("[user.name] shoves [target.name]!"), null, null, COMBAT_MESSAGE_RANGE)
var/target_held_item = target.get_active_held_item()
var/knocked_item = FALSE

if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
target_held_item = null

if(!target.has_movespeed_modifier(MOVESPEED_ID_SHOVE))
target.add_movespeed_modifier(MOVESPEED_ID_SHOVE, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
if(target_held_item)
target.visible_message(span_danger("[target.name]'s grip on \the [target_held_item] loosens!"), span_danger("Your grip on \the [target_held_item] loosens!"), null, COMBAT_MESSAGE_RANGE)
addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
else if(target_held_item)
target.dropItemToGround(target_held_item)
knocked_item = TRUE
target.visible_message(span_danger("[target.name] drops \the [target_held_item]!!"), span_danger("You drop \the [target_held_item]!!"), null, COMBAT_MESSAGE_RANGE)
var/append_message = ""
if(target_held_item)
if(knocked_item)
append_message = "causing them to drop [target_held_item]"
else
append_message = "loosening their grip on [target_held_item]"
log_combat(user, target, "liquidator hidden knife shove", append_message)



/**
* The actual martial art stuff
*/

var/selected_zone = target.get_bodypart(user.zone_selected) ? user.zone_selected : BODY_ZONE_CHEST //check if the zone exists, if not, default to chest

var/armor_block = target.run_armor_check(selected_zone, MELEE, armour_penetration = 40)
target.apply_damage(user.get_punchdamagehigh() * 4, BRUTE, selected_zone, armor_block, -100, 100, SHARP_POINTY) //28 damage by default TWENTY EIGHT STAB WOUNDS (not gonna wound, unless the target has no armour)
if(shove_blocked) //if they're getting pushed into a wall or another person, they're probably down for the count, GET THEM
user.changeNext_move(CLICK_CD_RANGE) //stab stab stab stab stab stab stab stab

// Stab sounds only play to you and the target
user.playsound_local(target, 'sound/weapons/sword2.ogg', 30, FALSE)
target.playsound_local(target, 'sound/weapons/sword2.ogg', 30, FALSE)

to_chat(user, span_warning("You stab [target] with a hidden blade!"))
to_chat(target, span_userdanger("You are suddenly stabbed with a blade!"))

/*---------------------------------------------------------------

Expand All @@ -99,8 +179,8 @@
gun.gun_owner = A
A.put_in_hands(gun)
to_chat(A, span_notice("You extract a hidden gun from your hand."))
D.Paralyze(1 SECONDS)
streak = ""
D.Stun(1 SECONDS)
A.changeNext_move(CLICK_CD_RANGE) //it's just pulling out a gun, not actually grabbing them, so have a shorter cooldown

/obj/item/gun/ballistic/automatic/pistol/martial
desc = "A concelated version of a stechkin APS pistol, that comes with special Preternis upgrade modules."
Expand All @@ -114,6 +194,10 @@
/obj/item/ammo_box/magazine/m10mm/martial
max_ammo = 1

/obj/item/gun/ballistic/automatic/pistol/martial/pre_attack(atom/target, mob/living/user, params) //prevents using this as a melee weapon, and allows its use in point blank while in combat mode
afterattack(target, user, FALSE, params) //call afterattack so the gun still shoots
return TRUE //prevent the regular attack

/obj/item/gun/ballistic/automatic/pistol/martial/eject_magazine(mob/user, display_message = TRUE, obj/item/ammo_box/magazine/tac_load = null)
return FALSE

Expand All @@ -127,6 +211,10 @@
ADD_TRAIT(src, TRAIT_NODROP, "martial")
RegisterSignal(src, COMSIG_ITEM_PREDROPPED, PROC_REF(on_drop))

/obj/item/gun/ballistic/automatic/pistol/martial/Destroy()
UnregisterSignal(src, COMSIG_ITEM_PREDROPPED)
return ..()

/obj/item/gun/ballistic/automatic/pistol/martial/attack_self(mob/living/user)
on_drop()

Expand All @@ -137,10 +225,11 @@
qdel(src)

/obj/item/gun/ballistic/automatic/pistol/martial/proc/on_drop()
if(QDELETED(src))
return
to_chat(gun_owner, span_notice("You decide that it isn't the best time to use [src]"))
qdel(src)


/*---------------------------------------------------------------

end of fingergun section
Expand All @@ -150,14 +239,23 @@
set name = "Refresh Data"
set desc = "You try to remember some basic actions from your covert combat module."
set category = "Remnant Liquidator"
to_chat(usr, "<b><i>You try to remember some basic actions from your covert combat module.</i></b>")
var/list/combined_msg = list()

var/datum/martial_art/liquidator/helper = new()

combined_msg += "<b><i>You try to remember some basic actions from your covert combat module.</i></b>"

combined_msg += "[span_notice("Hidden Blade")]: Harm Harm. You shove the target while stabbing them with a concealed blade, dealing considerable brute damage. Can infinitely combo with itself."
combined_msg += "[span_notice("Finger gun")]: Harm Grab. Briefly stun your target and place a stealthy version of a stechkin in your hand."

combined_msg += "[span_notice("Injection")]: Your disarm intent will inject chemicals in a determined order."
combined_msg += span_notice("<i>A chemical will only be injected if the target has under half the amount of injected units in them.</i>")
for(var/datum/reagent/chemical as anything in helper.injection_chems)
combined_msg += "[initial(chemical.name)]: [helper.injection_chems[chemical]]u."
combined_msg += span_notice("If none of the above chemicals are injected, you will default to [helper.injection_chems[helper.default_chem]]u of [initial(helper.default_chem.name)].")

to_chat(usr, "[span_notice("Hidden Blade")]: Harm Harm Grab. The second strike will deal 20 stamina and 5 brute damage, and finishing the combo will make you stab the victim with a hidden blade, dealing 30 brute damage.")
to_chat(usr, "[span_notice("Injection")]: Disarm Grab Disarm. The second and third input will silently inject 8 units of sodium thiopental and 5 units of cyanide respectively.")
to_chat(usr, "[span_notice("Finger gun")]: Harm Disarm Disarm. Finishing the combo will paralyse your target and place a stealthy version of a stechkin in your hand.")
to_chat(usr, examine_block(combined_msg.Join("\n")))
qdel(helper)

#undef PRE_DAGGER_COMBO
#undef DAGGER_COMBO
#undef PRE_INJECTION_COMBO
#undef INJECTION_COMBO
#undef FINGERGUN_COMBO
Loading