mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
## About The Pull Request Title. I'm moving a few monkey features away from the species and into its bodyparts and organs. I plan on following up with another PR for the various `ismonkey()` in the code, as these are necessary changes for a niche thing I'm ultimately working on. Also one carp organ and one stoat organ both had bits of code made redundant by available traits. This takes care of them. Also removed the passwindow_on/off and passtable_on/off procs. We can just register the associated trait signals on init for living mobs (plus they were being misused on non-mobs). ## Why It's Good For The Game Less code associated directly to the species and more to its body parts and organs, which is basically something we've been doing for a few years ~~(also I need it for skeletonized monkeys)~~. ## Changelog N/A
204 lines
8.5 KiB
Plaintext
204 lines
8.5 KiB
Plaintext
/// Component which allows mobs to be smashed onto this surface like a wrestling move
|
|
/datum/element/table_smash
|
|
element_flags = ELEMENT_BESPOKE
|
|
argument_hash_start_idx = 2
|
|
/// If true, mobs will be placed gently on the table even if they're in an aggressive grab
|
|
var/gentle_push
|
|
/// Passed proc call path for what to do after smashing harmfully into our 'table'-like obj
|
|
var/after_smash_proccall
|
|
|
|
/datum/element/table_smash/Attach(datum/target, gentle_push = FALSE, after_smash_proccall)
|
|
. = ..()
|
|
if (!isobj(target))
|
|
return ELEMENT_INCOMPATIBLE
|
|
|
|
src.gentle_push = gentle_push
|
|
src.after_smash_proccall = after_smash_proccall
|
|
|
|
RegisterSignal(target, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_interaction))
|
|
RegisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_item_interaction))
|
|
|
|
var/static/list/loc_connections = list(
|
|
COMSIG_LIVING_DISARM_COLLIDE = TYPE_PROC_REF(/obj/structure, on_disarm_shoved_into),
|
|
)
|
|
target.AddElement(/datum/element/connect_loc, loc_connections)
|
|
|
|
/datum/element/table_smash/Detach(datum/source, ...)
|
|
. = ..()
|
|
UnregisterSignal(source, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ITEM_INTERACTION))
|
|
|
|
/// Called when someone clicks on our surface
|
|
/datum/element/table_smash/proc/on_interaction(datum/source, mob/user)
|
|
SIGNAL_HANDLER
|
|
|
|
var/obj/source_obj = source
|
|
if (!source_obj.Adjacent(user) || !user.pulling)
|
|
return
|
|
|
|
if (!isliving(user.pulling))
|
|
if (!(user.pulling.pass_flags & PASSTABLE))
|
|
return
|
|
|
|
user.Move_Pulled(source_obj)
|
|
|
|
if (user.pulling.loc == source_obj.loc)
|
|
user.visible_message(span_notice("[user] places [user.pulling] onto [source_obj]."),
|
|
span_notice("You place [user.pulling] onto [source_obj]."))
|
|
user.stop_pulling()
|
|
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
var/mob/living/pushed_mob = user.pulling
|
|
if (pushed_mob.buckled)
|
|
if (pushed_mob.buckled == source_obj)
|
|
//Already buckled to the object, you probably meant to unbuckle them
|
|
return
|
|
|
|
to_chat(user, span_warning("[pushed_mob] is buckled to [pushed_mob.buckled]!"))
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
INVOKE_ASYNC(src, PROC_REF(perform_table_smash), source_obj, user)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
/// We have a mob being pressed onto the table, but how strongly?
|
|
/datum/element/table_smash/proc/perform_table_smash(obj/structure/table/table, mob/living/user)
|
|
var/mob/living/pushed_mob = user.pulling
|
|
if (user.combat_mode)
|
|
switch(user.grab_state)
|
|
if (GRAB_PASSIVE)
|
|
to_chat(user, span_warning("You need a better grip to do that!"))
|
|
return
|
|
if (GRAB_AGGRESSIVE)
|
|
if (gentle_push)
|
|
tableplace(user, pushed_mob, table)
|
|
else
|
|
tablepush(user, pushed_mob, table)
|
|
if (GRAB_NECK to GRAB_KILL)
|
|
tablelimbsmash(user, pushed_mob, table)
|
|
else
|
|
pushed_mob.visible_message(span_notice("[user] begins to place [pushed_mob] onto [table]..."), \
|
|
span_userdanger("[user] begins to place [pushed_mob] onto [table]..."))
|
|
if (do_after(user, 3.5 SECONDS, target = pushed_mob))
|
|
tableplace(user, pushed_mob, table)
|
|
else
|
|
return
|
|
|
|
user.stop_pulling()
|
|
|
|
/// Called when someone clicks on our surface with an item
|
|
/datum/element/table_smash/proc/on_item_interaction(obj/structure/table/table, mob/living/user, obj/item/item, modifiers)
|
|
SIGNAL_HANDLER
|
|
if (!istype(item, /obj/item/riding_offhand))
|
|
return NONE
|
|
|
|
var/obj/item/riding_offhand/riding_item = item
|
|
var/mob/living/carried_mob = riding_item.rider
|
|
if (carried_mob == user) //Piggyback user.
|
|
return NONE
|
|
|
|
INVOKE_ASYNC(src, PROC_REF(riding_offhand_act), user, item, table)
|
|
return ITEM_INTERACT_BLOCKING
|
|
|
|
/// Called when someone clicks on our surface using a fireman's carry
|
|
/datum/element/table_smash/proc/riding_offhand_act(mob/living/user, obj/item/riding_offhand/riding_item, obj/structure/table/table)
|
|
var/mob/living/carried_mob = riding_item.rider
|
|
if (user.combat_mode)
|
|
user.unbuckle_mob(carried_mob)
|
|
tablelimbsmash(user, carried_mob)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
var/tableplace_delay = 3.5 SECONDS
|
|
var/skills_space = ""
|
|
if (HAS_TRAIT(user, TRAIT_QUICKER_CARRY))
|
|
tableplace_delay = 2 SECONDS
|
|
skills_space = " expertly"
|
|
else if (HAS_TRAIT(user, TRAIT_QUICK_CARRY))
|
|
tableplace_delay = 2.75 SECONDS
|
|
skills_space = " quickly"
|
|
|
|
var/obj/item/organ/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 [table]..."),
|
|
span_userdanger("[user] begins to[skills_space] place [carried_mob] onto [table]..."))
|
|
if (!do_after(user, tableplace_delay, target = carried_mob))
|
|
return ITEM_INTERACT_BLOCKING
|
|
user.unbuckle_mob(carried_mob)
|
|
tableplace(user, carried_mob, table)
|
|
return ITEM_INTERACT_SUCCESS
|
|
|
|
/// Gently place the mob onto the table
|
|
/datum/element/table_smash/proc/tableplace(mob/living/user, mob/living/pushed_mob, obj/structure/table/table)
|
|
pushed_mob.forceMove(table.loc)
|
|
pushed_mob.set_resting(TRUE, TRUE)
|
|
pushed_mob.visible_message(span_notice("[user] places [pushed_mob] onto [table]."), \
|
|
span_notice("[user] places [pushed_mob] onto [table]."))
|
|
log_combat(user, pushed_mob, "placed", null, "onto [table]")
|
|
|
|
/// Aggressively smash the mob onto the table
|
|
/datum/element/table_smash/proc/tablepush(mob/living/user, mob/living/pushed_mob, obj/structure/table/table)
|
|
if (HAS_TRAIT(user, TRAIT_PACIFISM))
|
|
to_chat(user, span_danger("Throwing [pushed_mob] onto the table might hurt them!"))
|
|
return
|
|
|
|
var/passtable_key = REF(user)
|
|
ADD_TRAIT(pushed_mob, TRAIT_PASSTABLE, passtable_key)
|
|
for (var/obj/obj in user.loc.contents)
|
|
if (!obj.CanAllowThrough(pushed_mob))
|
|
return
|
|
|
|
pushed_mob.Move(table.loc)
|
|
REMOVE_TRAIT(pushed_mob, TRAIT_PASSTABLE, passtable_key)
|
|
if (pushed_mob.loc != table.loc) //Something prevented the tabling
|
|
return
|
|
|
|
pushed_mob.Knockdown(3 SECONDS)
|
|
pushed_mob.apply_damage(10, BRUTE)
|
|
pushed_mob.apply_damage(40, STAMINA)
|
|
playsound(pushed_mob, 'sound/effects/tableslam.ogg', 90, TRUE)
|
|
pushed_mob.visible_message(span_danger("[user] slams [pushed_mob] onto \the [table]!"), \
|
|
span_userdanger("[user] slams you onto \the [table]!"))
|
|
log_combat(user, pushed_mob, "tabled", null, "onto [table]")
|
|
pushed_mob.add_mood_event("table", /datum/mood_event/table)
|
|
SEND_SIGNAL(user, COMSIG_LIVING_TABLE_SLAMMING, pushed_mob, table)
|
|
if(after_smash_proccall)
|
|
call(table, after_smash_proccall)(pushed_mob)
|
|
|
|
/// Even more aggressively smash a single part of a mob onto the table
|
|
/datum/element/table_smash/proc/tablelimbsmash(mob/living/user, mob/living/pushed_mob, obj/structure/table/table)
|
|
pushed_mob.Knockdown(3 SECONDS)
|
|
var/obj/item/bodypart/banged_limb = pushed_mob.get_bodypart(user.zone_selected) || pushed_mob.get_bodypart(BODY_ZONE_HEAD)
|
|
var/extra_wound = 0
|
|
if (HAS_TRAIT(user, TRAIT_HULK))
|
|
extra_wound = 20
|
|
pushed_mob.apply_damage(30, BRUTE, banged_limb, wound_bonus = extra_wound)
|
|
pushed_mob.apply_damage(60, STAMINA)
|
|
playsound(pushed_mob, 'sound/effects/bang.ogg', 90, TRUE)
|
|
pushed_mob.visible_message(span_danger("[user] smashes [pushed_mob]'s [banged_limb.plaintext_zone] against \the [table]!"),
|
|
span_userdanger("[user] smashes your [banged_limb.plaintext_zone] against \the [table]"))
|
|
log_combat(user, pushed_mob, "head slammed", null, "against [table]")
|
|
pushed_mob.add_mood_event("table", /datum/mood_event/table_limbsmash, banged_limb)
|
|
table.take_damage(50)
|
|
SEND_SIGNAL(user, COMSIG_LIVING_TABLE_LIMB_SLAMMING, pushed_mob, table)
|
|
if(after_smash_proccall)
|
|
call(table, after_smash_proccall)(pushed_mob)
|
|
|
|
/// Called when someone is shoved into our tile
|
|
/obj/structure/proc/on_disarm_shoved_into(datum/source, mob/living/shover, mob/living/target, shove_flags, obj/item/weapon)
|
|
SIGNAL_HANDLER
|
|
if((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED))
|
|
return
|
|
target.Knockdown(SHOVE_KNOCKDOWN_TABLE, daze_amount = 3 SECONDS)
|
|
target.visible_message(span_danger("[shover.name] shoves [target.name] onto \the [src]!"),
|
|
span_userdanger("You're shoved onto \the [src] by [shover.name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, shover)
|
|
to_chat(shover, span_danger("You shove [target.name] onto \the [src]!"))
|
|
target.throw_at(src, 1, 1, null, FALSE) //1 speed throws with no spin are basically just forcemoves with a hard collision check
|
|
log_combat(shover, target, "shoved", "onto [src] (table)[weapon ? " with [weapon]" : ""]")
|
|
after_smash(target)
|
|
return COMSIG_LIVING_SHOVE_HANDLED
|
|
|
|
/// Called after someone is harmfully smashed onto us
|
|
/obj/structure/proc/after_smash(mob/living/smashed_onto)
|
|
return // This is mostly for our children
|