diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index c12c9b57713..19c87f3b4e0 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -370,3 +370,18 @@ GLOBAL_LIST_INIT(arm_zones, list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) #define COMBO_STEPS "steps" /// The proc the combo calls #define COMBO_PROC "proc" + +///Checks If the target can be moved at all by shoving them +#define SHOVE_CAN_MOVE (1<<0) +///If the target can be shoved into something something with perhaps special interactions. +#define SHOVE_CAN_HIT_SOMETHING (1<<1) +///Keeps knockdowns at bay for the target +#define SHOVE_KNOCKDOWN_BLOCKED (1<<2) +///If the target can be briefly paralized by shoving them once again after knocking them down. +#define SHOVE_CAN_KICK_SIDE (1<<3) +///Whether the staggered status effect can be applied on the target +#define SHOVE_CAN_STAGGER (1<<4) +///If the target could move, but didn't because there's an obstacle in the path. +#define SHOVE_BLOCKED (1<<5) +///If the obstacle is an object at the border of the turf (so no signal from being sent to the other turf) +#define SHOVE_DIRECTIONAL_BLOCKED (1<<6) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index fe7673ee3ca..8b73010b8f9 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -13,13 +13,6 @@ ///Called from /mob/living/carbon/help_shake_act on the helper, after any hugs have ocurred. (mob/living/helped) #define COMSIG_CARBON_HELPED "carbon_helped_someone" -///Before a carbon mob is shoved, sent to the turf we're trying to shove onto (mob/living/carbon/shover, mob/living/carbon/target) -#define COMSIG_CARBON_DISARM_PRESHOVE "carbon_disarm_preshove" - #define COMSIG_CARBON_ACT_SOLID (1<<0) //Tells disarm code to act as if the mob was shoved into something solid, even we we're not -///When a carbon mob is disarmed, this is sent to the turf we're trying to shove onto (mob/living/carbon/shover, mob/living/carbon/target, shove_blocked) -#define COMSIG_CARBON_DISARM_COLLIDE "carbon_disarm_collision" - #define COMSIG_CARBON_SHOVE_HANDLED (1<<0) - ///When a carbon slips. Called on /turf/open/handle_slip() #define COMSIG_ON_CARBON_SLIP "carbon_slip" // /mob/living/carbon physiology signals @@ -125,8 +118,6 @@ ///Applied preferences to a human #define COMSIG_HUMAN_PREFS_APPLIED "human_prefs_applied" -///Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted) -#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" ///Whenever EquipRanked is called, called after job is set #define COMSIG_JOB_RECEIVED "job_received" ///from /mob/living/carbon/human/proc/set_coretemperature(): (oldvalue, newvalue) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index b1838793e98..7ac77efcaa7 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -228,6 +228,15 @@ #define COMSIG_LIVING_CHECK_BLOCK "living_check_block" #define SUCCESSFUL_BLOCK (1<<0) +///Hit by successful disarm attack (mob/living/attacker, zone_targeted, item/weapon) +#define COMSIG_LIVING_DISARM_HIT "living_disarm_hit" +///Before a living mob is shoved, sent to the turf we're trying to shove onto (mob/living/shover, mob/living/target) +#define COMSIG_LIVING_DISARM_PRESHOVE "living_disarm_preshove" + #define COMSIG_LIVING_ACT_SOLID (1<<0) //Tells disarm code to act as if the mob was shoved into something solid, even we we're not +///When a living mob is disarmed, this is sent to the turf we're trying to shove onto (mob/living/shover, mob/living/target, shove_blocked) +#define COMSIG_LIVING_DISARM_COLLIDE "living_disarm_collision" + #define COMSIG_LIVING_SHOVE_HANDLED (1<<0) + /// Sent on a mob from /datum/component/mob_chain when component is attached with it as the "front" : (mob/living/basic/tail) #define COMSIG_MOB_GAINED_CHAIN_TAIL "living_gained_chain_tail" /// Sent on a mob from /datum/component/mob_chain when component is detached from it as the "front" : (mob/living/basic/tail) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index b3149b82719..25efe87272f 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -444,7 +444,7 @@ #define COMPONENT_SECONDARY_CONTINUE_ATTACK_CHAIN (1<<1) #define COMPONENT_SECONDARY_CALL_NORMAL_ATTACK_CHAIN (1<<2) /// From base of [/obj/item/proc/attack_secondary()]: (atom/target, mob/user, params) -#define COMSIG_ITEM_ATTACK_SECONDARY "item_pre_attack_secondary" +#define COMSIG_ITEM_ATTACK_SECONDARY "item_attack_secondary" ///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters) #define COMSIG_ITEM_AFTERATTACK "item_afterattack" /// Flag for when /afterattack potentially acts on an item. @@ -462,6 +462,10 @@ /// from base of obj/item/failedEmbed() #define COMSIG_ITEM_FAILED_EMBED "item_failed_embed" +/// from base of datum/element/disarm_attack/secondary_attack(), used to prevent shoving: (victim, user, send_message) +#define COMSIG_ITEM_CAN_DISARM_ATTACK "item_pre_disarm_attack" + #define COMPONENT_BLOCK_ITEM_DISARM_ATTACK (1<<0) + ///from /obj/item/assembly/proc/pulsed(mob/pulser) #define COMSIG_ASSEMBLY_PULSED "assembly_pulsed" diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 9427328fcc2..8ace303b843 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -68,28 +68,26 @@ #define VOICEBOX_TOGGLABLE (1<<6) /// The voicebox is currently turned off. #define VOICEBOX_DISABLED (1<<7) -/// Prevents shovies against a dense object from knocking the wearer down. -#define BLOCKS_SHOVE_KNOCKDOWN (1<<8) /// Prevents knock-off from things like hat-throwing. -#define SNUG_FIT (1<<9) +#define SNUG_FIT (1<<8) /// Hats with negative effects when worn (i.e the tinfoil hat). -#define ANTI_TINFOIL_MANEUVER (1<<10) +#define ANTI_TINFOIL_MANEUVER (1<<9) /// Clothes that cause a larger notification when placed on a person. -#define DANGEROUS_OBJECT (1<<11) +#define DANGEROUS_OBJECT (1<<10) /// Clothes that use large icons, for applying the proper overlays like blood -#define LARGE_WORN_ICON (1<<12) +#define LARGE_WORN_ICON (1<<11) /// Clothes that block speech (i.e the muzzle). Can be applied to any clothing piece. -#define BLOCKS_SPEECH (1<<13) +#define BLOCKS_SPEECH (1<<12) /// prevents from placing on plasmaman helmet or modsuit hat holder -#define STACKABLE_HELMET_EXEMPT (1<<14) +#define STACKABLE_HELMET_EXEMPT (1<<13) /// Prevents plasmamen from igniting when wearing this -#define PLASMAMAN_PREVENT_IGNITION (1<<15) +#define PLASMAMAN_PREVENT_IGNITION (1<<14) /// Usable as casting clothes by wizards (matters for suits, glasses and headwear) -#define CASTING_CLOTHES (1<<16) +#define CASTING_CLOTHES (1<<15) ///Moths can't eat the clothing that has this flag. -#define INEDIBLE_CLOTHING (1<<17) +#define INEDIBLE_CLOTHING (1<<16) /// Headgear/helmet allows internals -#define HEADINTERNALS (1<<18) +#define HEADINTERNALS (1<<17) /// Integrity defines for clothing (not flags but close enough) #define CLOTHING_PRISTINE 0 // We have no damage on the clothing diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index af171751f33..132f8d91487 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -211,6 +211,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BLOOD_DEFICIENCY "blood_deficiency" #define TRAIT_JOLLY "jolly" #define TRAIT_NOCRITDAMAGE "no_crit" +/// Prevents shovies against a dense object from knocking them down. +#define TRAIT_SHOVE_KNOCKDOWN_BLOCKED "shove_knockdown_blocked" +/// Prevents staggering. +#define TRAIT_NO_STAGGER "no_stagger" +/// Getting hit by thrown movables won't push you away +#define TRAIT_NO_THROW_HITPUSH "no_throw_hitpush" ///Added to mob or mind, changes the icons of the fish shown in the minigame UI depending on the possible reward. #define TRAIT_REVEAL_FISH "reveal_fish" diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 89c0b4e1c4d..ccfffecd7eb 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -83,7 +83,6 @@ DEFINE_BITFIELD(car_traits, list( DEFINE_BITFIELD(clothing_flags, list( "ANTI_TINFOIL_MANEUVER" = ANTI_TINFOIL_MANEUVER, - "BLOCKS_SHOVE_KNOCKDOWN" = BLOCKS_SHOVE_KNOCKDOWN, "BLOCKS_SPEECH" = BLOCKS_SPEECH, "BLOCK_GAS_SMOKE_EFFECT" = BLOCK_GAS_SMOKE_EFFECT, "CASTING_CLOTHES" = CASTING_CLOTHES, diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 98275fe8231..5eda73a12f4 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -52,6 +52,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NO_MANIFEST_CONTENTS_ERROR" = TRAIT_NO_MANIFEST_CONTENTS_ERROR, "TRAIT_NO_MISSING_ITEM_ERROR" = TRAIT_NO_MISSING_ITEM_ERROR, + "TRAIT_NO_THROW_HITPUSH" = TRAIT_NO_THROW_HITPUSH, "TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE, "TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT" = TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT, "TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN, @@ -328,6 +329,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_SLIP_SLIDE" = TRAIT_NO_SLIP_SLIDE, "TRAIT_NO_SLIP_WATER" = TRAIT_NO_SLIP_WATER, "TRAIT_NO_SOUL" = TRAIT_NO_SOUL, + "TRAIT_NO_STAGGER" = TRAIT_NO_STAGGER, "TRAIT_NO_STRIP" = TRAIT_NO_STRIP, "TRAIT_NO_TRANSFORM" = TRAIT_NO_TRANSFORM, "TRAIT_NO_TWOHANDING" = TRAIT_NO_TWOHANDING, @@ -393,6 +395,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SHAVED" = TRAIT_SHAVED, "TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES, "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, + "TRAIT_SHOVE_KNOCKDOWN_BLOCKED" = TRAIT_SHOVE_KNOCKDOWN_BLOCKED, "TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG, "TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS, "TRAIT_SIXTHSENSE" = TRAIT_SIXTHSENSE, diff --git a/code/datums/components/gunpoint.dm b/code/datums/components/gunpoint.dm index cb8dfb1ec8d..ed4142f41ce 100644 --- a/code/datums/components/gunpoint.dm +++ b/code/datums/components/gunpoint.dm @@ -45,7 +45,7 @@ COMSIG_LIVING_START_PULL), PROC_REF(trigger_reaction)) RegisterSignal(targ, COMSIG_ATOM_EXAMINE, PROC_REF(examine_target)) RegisterSignal(targ, COMSIG_LIVING_PRE_MOB_BUMP, PROC_REF(block_bumps_target)) - RegisterSignals(targ, list(COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_GET_PULLED), PROC_REF(cancel)) + RegisterSignals(targ, list(COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_GET_PULLED), PROC_REF(cancel)) RegisterSignals(weapon, list(COMSIG_ITEM_DROPPED, COMSIG_ITEM_EQUIPPED), PROC_REF(cancel)) var/distance = min(get_dist(shooter, target), 1) // treat 0 distance as adjacent @@ -88,7 +88,7 @@ RegisterSignals(parent, list(COMSIG_LIVING_START_PULL, COMSIG_MOVABLE_BUMP), PROC_REF(check_bump)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine)) RegisterSignal(parent, COMSIG_LIVING_PRE_MOB_BUMP, PROC_REF(block_bumps_parent)) - RegisterSignal(parent, COMSIG_HUMAN_DISARM_HIT, PROC_REF(cancel)) + RegisterSignal(parent, COMSIG_LIVING_DISARM_HIT, PROC_REF(cancel)) /datum/component/gunpoint/UnregisterFromParent() UnregisterSignal(parent, COMSIG_MOVABLE_MOVED) @@ -98,7 +98,7 @@ UnregisterSignal(parent, list(COMSIG_LIVING_START_PULL, COMSIG_MOVABLE_BUMP)) UnregisterSignal(parent, COMSIG_ATOM_EXAMINE) UnregisterSignal(parent, COMSIG_LIVING_PRE_MOB_BUMP) - UnregisterSignal(parent, COMSIG_HUMAN_DISARM_HIT) + UnregisterSignal(parent, COMSIG_LIVING_DISARM_HIT) ///If the shooter bumps the target, cancel the holdup to avoid cheesing and forcing the charged shot /datum/component/gunpoint/proc/check_bump(atom/B, atom/A) diff --git a/code/datums/components/knockoff.dm b/code/datums/components/knockoff.dm index b5563433c72..db72072789c 100644 --- a/code/datums/components/knockoff.dm +++ b/code/datums/components/knockoff.dm @@ -29,11 +29,11 @@ var/obj/item/item_parent = parent if(ismob(item_parent.loc)) - UnregisterSignal(item_parent.loc, list(COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN)) + UnregisterSignal(item_parent.loc, list(COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN)) -/// Signal proc for [COMSIG_HUMAN_DISARM_HIT] on the mob who's equipped our parent +/// Signal proc for [COMSIG_LIVING_DISARM_HIT] on the mob who's equipped our parent /// Rolls a chance for knockoff whenever we're disarmed -/datum/component/knockoff/proc/on_equipped_mob_disarm(mob/living/carbon/human/source, mob/living/attacker, zone) +/datum/component/knockoff/proc/on_equipped_mob_disarm(mob/living/source, mob/living/attacker, zone, obj/item/weapon) SIGNAL_HANDLER if(!istype(source)) @@ -85,10 +85,10 @@ return if(slots_knockoffable && !(slot & slots_knockoffable)) - UnregisterSignal(equipper, list(COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN)) + UnregisterSignal(equipper, list(COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN)) return - RegisterSignal(equipper, COMSIG_HUMAN_DISARM_HIT, PROC_REF(on_equipped_mob_disarm), TRUE) + RegisterSignal(equipper, COMSIG_LIVING_DISARM_HIT, PROC_REF(on_equipped_mob_disarm), TRUE) RegisterSignal(equipper, COMSIG_LIVING_STATUS_KNOCKDOWN, PROC_REF(on_equipped_mob_knockdown), TRUE) /// Signal proc for [COMSIG_ITEM_DROPPED] @@ -96,4 +96,4 @@ /datum/component/knockoff/proc/on_dropped(datum/source, mob/living/dropper) SIGNAL_HANDLER - UnregisterSignal(dropper, list(COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN)) + UnregisterSignal(dropper, list(COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN)) diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index 9f8bb9227e0..520fa161b69 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -400,7 +400,7 @@ defense_mod += 2 if(tackle_target.mob_negates_gravity()) defense_mod += 1 - if(tackle_target.is_shove_knockdown_blocked()) // riot armor and such + if(HAS_TRAIT(tackle_target, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) // riot armor and such defense_mod += 5 var/obj/item/organ/external/tail/lizard/el_tail = tackle_target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) @@ -451,7 +451,7 @@ attack_mod += 15 human_sacker.adjustStaminaLoss(100) //AHAHAHAHAHAHAHAHA - if(human_sacker.is_shove_knockdown_blocked()) // tackling with riot specialized armor, like riot armor, is effective but tiring + if(HAS_TRAIT(human_sacker, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) // tackling with riot specialized armor, like riot armor, is effective but tiring attack_mod += 2 human_sacker.adjustStaminaLoss(20) diff --git a/code/datums/elements/disarm_attack.dm b/code/datums/elements/disarm_attack.dm new file mode 100644 index 00000000000..a788cd9f35e --- /dev/null +++ b/code/datums/elements/disarm_attack.dm @@ -0,0 +1,35 @@ +///An element that allows items to be used to shove people around just like right-clicking would. +/datum/element/disarm_attack + +/datum/element/disarm_attack/Attach(datum/target) + . = ..() + if(!isitem(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_ITEM_ATTACK_SECONDARY, PROC_REF(secondary_attack)) + RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(examine)) + +/datum/element/disarm_attack/Detach(datum/source) + UnregisterSignal(source, list(COMSIG_ATOM_EXAMINE, COMSIG_ITEM_ATTACK_SECONDARY)) + return ..() + +/datum/element/disarm_attack/proc/secondary_attack(obj/item/source, mob/living/victim, mob/living/user, params) + SIGNAL_HANDLER + if(!user.can_disarm(victim) || !can_disarm_attack(source, victim, user)) + return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN + if(victim.check_block(source, 0, "the [source.name]", MELEE_ATTACK, 0)) + return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN + user.disarm(victim, source) + user.changeNext_move(source.secondary_attack_speed || source.attack_speed) + return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN + +///check if the item conditions for the disarm action are met. +/datum/element/disarm_attack/proc/can_disarm_attack(obj/item/source, mob/living/victim, mob/living/user, message = TRUE) + if(SEND_SIGNAL(source, COMSIG_ITEM_CAN_DISARM_ATTACK, victim, user, message) & COMPONENT_BLOCK_ITEM_DISARM_ATTACK) + return FALSE + return TRUE + +/datum/element/disarm_attack/proc/examine(obj/item/source, mob/user, list/examine_list) + SIGNAL_HANDLER + if(can_disarm_attack(source, user, user, FALSE)) + examine_list += span_notice("You can use it to shove people with right-click.") diff --git a/code/datums/status_effects/debuffs/staggered.dm b/code/datums/status_effects/debuffs/staggered.dm index 0ffde66b1f1..89cf4943c19 100644 --- a/code/datums/status_effects/debuffs/staggered.dm +++ b/code/datums/status_effects/debuffs/staggered.dm @@ -10,7 +10,7 @@ /datum/status_effect/staggered/on_apply() //you can't stagger the dead. - if(owner.stat == DEAD) + if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_NO_STAGGER)) return FALSE RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(clear_staggered)) @@ -31,10 +31,12 @@ /datum/status_effect/staggered/tick(seconds_between_ticks) //you can't stagger the dead - in case somehow you die mid-stagger - if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_FAKEDEATH)) + if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_NO_STAGGER)) + qdel(src) return - else - owner.do_stagger_animation() + if(HAS_TRAIT(owner, TRAIT_FAKEDEATH)) + return + owner.do_stagger_animation() /// Helper proc that causes the mob to do a stagger animation. /// Doesn't change significantly, just meant to represent swaying back and forth diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0f21f9c5fd0..47c0ecdfa54 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1255,9 +1255,11 @@ return hit_atom.hitby(src, throwingdatum=throwingdatum, hitpush=hitpush) /atom/movable/hitby(atom/movable/hitting_atom, skipcatch, hitpush = TRUE, blocked, datum/thrownthing/throwingdatum) + if(HAS_TRAIT(src, TRAIT_NO_THROW_HITPUSH)) + hitpush = FALSE if(!anchored && hitpush && (!throwingdatum || (throwingdatum.force >= (move_resist * MOVE_FORCE_PUSH_RATIO)))) step(src, hitting_atom.dir) - ..() + return ..() /atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE) if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY)) diff --git a/code/game/objects/items/pillow.dm b/code/game/objects/items/pillow.dm index 5364905bdc9..928f1a373bb 100644 --- a/code/game/objects/items/pillow.dm +++ b/code/game/objects/items/pillow.dm @@ -31,6 +31,7 @@ force_unwielded = 5, \ force_wielded = 10, \ ) + AddElement(/datum/element/disarm_attack) var/static/list/slapcraft_recipe_list = list(\ /datum/crafting_recipe/pillow_suit, /datum/crafting_recipe/pillow_hood,\ diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index ef434c1993d..b711bb63d45 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -35,6 +35,10 @@ fire = 80 acid = 70 +/obj/item/shield/Initialize(mapload) + . = ..() + AddElement(/datum/element/disarm_attack) + /obj/item/shield/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(transparent && (hitby.pass_flags & PASSGLASS)) return FALSE @@ -57,21 +61,32 @@ if(0 to 25) . += span_warning("It's falling apart!") -/obj/item/shield/proc/shatter(mob/living/carbon/human/owner) - playsound(owner, shield_break_sound, 50) - new shield_break_leftover(get_turf(src)) - /obj/item/shield/proc/on_shield_block(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) if(!breakable_by_damage || (damage_type != BRUTE && damage_type != BURN)) return TRUE - if (atom_integrity <= damage) - var/turf/owner_turf = get_turf(owner) - owner_turf.visible_message(span_warning("[hitby] destroys [src]!")) - shatter(owner) - qdel(src) - return FALSE - take_damage(damage) - return TRUE + var/penetration = 0 + var/armor_flag = MELEE + if(isprojectile(hitby)) + var/obj/projectile/bang_bang = hitby + armor_flag = bang_bang.armor_flag + penetration = bang_bang.armour_penetration + else if(isitem(hitby)) + var/obj/item/weapon = hitby + penetration = weapon.armour_penetration + else if(isanimal(hitby)) + var/mob/living/simple_animal/critter = hitby + penetration = critter.armour_penetration + else if(isbasicmob(hitby)) + var/mob/living/basic/critter = hitby + penetration = critter.armour_penetration + take_damage(damage, damage_type, armor_flag, armour_penetration = penetration) + +/obj/item/shield/atom_destruction(damage_flag) + playsound(src, shield_break_sound, 50) + new shield_break_leftover(get_turf(src)) + if(isliving(loc)) + loc.balloon_alert(loc, "shield broken!") + return ..() /obj/item/shield/buckler name = "wooden buckler" @@ -100,9 +115,14 @@ armor_type = /datum/armor/none max_integrity = 30 +/datum/armor/item_shield/riot + melee = 80 + bullet = 20 + laser = 20 + /obj/item/shield/riot name = "riot shield" - desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder." + desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder, less so bullets and laser beams." icon_state = "riot" inhand_icon_state = "riot" custom_materials = list(/datum/material/glass= SHEET_MATERIAL_AMOUNT * 3.75, /datum/material/iron= HALF_SHEET_MATERIAL_AMOUNT) @@ -110,6 +130,7 @@ max_integrity = 75 shield_break_sound = 'sound/effects/glassbr3.ogg' shield_break_leftover = /obj/item/shard + armor_type = /datum/armor/item_shield/riot /obj/item/shield/riot/Initialize(mapload) . = ..() @@ -177,7 +198,9 @@ QDEL_NULL(embedded_flash) return ..() -/obj/item/shield/riot/flash/attack(mob/living/target_mob, mob/user) +/obj/item/shield/riot/flash/attack(mob/living/target_mob, mob/living/user) + if(user.combat_mode) + return ..() flash_away(user, target_mob) /obj/item/shield/riot/flash/attack_self(mob/living/carbon/user) @@ -275,6 +298,7 @@ clumsy_check = !can_clumsy_use, \ ) RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) + RegisterSignal(src, COMSIG_ITEM_CAN_DISARM_ATTACK, PROC_REF(can_disarm_attack)) /obj/item/shield/energy/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_TRANSFORM_ACTIVE)) @@ -302,6 +326,13 @@ playsound(src, active ? 'sound/weapons/saberon.ogg' : 'sound/weapons/saberoff.ogg', 35, TRUE) return COMPONENT_NO_DEFAULT_MESSAGE +/obj/item/shield/energy/proc/can_disarm_attack(datum/source, mob/living/victim, mob/living/user, send_message = TRUE) + SIGNAL_HANDLER + if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) + if(send_message) + balloon_alert(user, "activate it first!") + return COMPONENT_BLOCK_ITEM_DISARM_ATTACK + /obj/item/shield/energy/advanced name = "advanced combat energy shield" desc = "A hardlight shield capable of reflecting all energy projectiles, as well las providing well-rounded defense from most all other attacks. \ @@ -338,6 +369,7 @@ ) RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) + RegisterSignal(src, COMSIG_ITEM_CAN_DISARM_ATTACK, PROC_REF(can_disarm_attack)) /obj/item/shield/riot/tele/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_TRANSFORM_ACTIVE)) @@ -358,4 +390,11 @@ playsound(src, 'sound/weapons/batonextend.ogg', 50, TRUE) return COMPONENT_NO_DEFAULT_MESSAGE +/obj/item/shield/riot/tele/proc/can_disarm_attack(datum/source, mob/living/victim, mob/living/user, send_message = TRUE) + SIGNAL_HANDLER + if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) + if(send_message) + balloon_alert(user, "extend it first!") + return COMPONENT_BLOCK_ITEM_DISARM_ATTACK + #undef BATON_BASH_COOLDOWN diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index d00c2becbe2..b3d3c7085bd 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -145,7 +145,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) populate_contents_immediate() var/static/list/loc_connections = list( - COMSIG_CARBON_DISARM_COLLIDE = PROC_REF(locker_carbon), + COMSIG_LIVING_DISARM_COLLIDE = PROC_REF(locker_living), COMSIG_ATOM_MAGICALLY_UNLOCKED = PROC_REF(on_magic_unlock), ) AddElement(/datum/element/connect_loc, loc_connections) @@ -1160,11 +1160,11 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /obj/structure/closet/return_temperature() return -/obj/structure/closet/proc/locker_carbon(datum/source, mob/living/carbon/shover, mob/living/carbon/target, shove_blocked) +/obj/structure/closet/proc/locker_living(datum/source, mob/living/shover, mob/living/target, shove_flags, obj/item/weapon) SIGNAL_HANDLER if(!opened && (locked || welded)) //Yes this could be less code, no I don't care return - if(!opened && !shove_blocked) + if(!opened && ((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED))) return var/was_opened = opened if(!toggle()) @@ -1174,18 +1174,12 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) else target.Knockdown(SHOVE_KNOCKDOWN_SOLID) update_icon() - if(target == shover) - target.visible_message(span_danger("[target.name] shoves [target.p_them()]self into [src]!"), - null, - span_hear("You hear shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, shover) - to_chat(shover, span_notice("You shove yourself into [src]!")) - else - target.visible_message(span_danger("[shover.name] shoves [target.name] into [src]!"), - span_userdanger("You're shoved into [src] by [shover.name]!"), - span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, shover) - to_chat(src, span_danger("You shove [target.name] into [src]!")) - log_combat(shover, target, "shoved", "into [src] (locker/crate)") - return COMSIG_CARBON_SHOVE_HANDLED + target.visible_message(span_danger("[shover.name] shoves [target.name] into [src]!"), + span_userdanger("You're shoved into [src] by [shover.name]!"), + span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, shover) + to_chat(src, span_danger("You shove [target.name] into [src]!")) + log_combat(shover, target, "shoved", "into [src] (locker/crate)[weapon ? " with [weapon]" : ""]") + return COMSIG_LIVING_SHOVE_HANDLED /// Signal proc for [COMSIG_ATOM_MAGICALLY_UNLOCKED]. Unlock and open up when we get knock casted. /obj/structure/closet/proc/on_magic_unlock(datum/source, datum/action/cooldown/spell/aoe/knock/spell, atom/caster) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index f9178684768..9131607c6c4 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -47,7 +47,7 @@ make_climbable() var/static/list/loc_connections = list( - COMSIG_CARBON_DISARM_COLLIDE = PROC_REF(table_carbon), + COMSIG_LIVING_DISARM_COLLIDE = PROC_REF(table_living), ) AddElement(/datum/element/connect_loc, loc_connections) @@ -323,17 +323,17 @@ return TRUE return FALSE -/obj/structure/table/proc/table_carbon(datum/source, mob/living/carbon/shover, mob/living/carbon/target, shove_blocked) +/obj/structure/table/proc/table_living(datum/source, mob/living/shover, mob/living/target, shove_flags, obj/item/weapon) SIGNAL_HANDLER - if(!shove_blocked) + if((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED)) return target.Knockdown(SHOVE_KNOCKDOWN_TABLE) 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, 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)") - return COMSIG_CARBON_SHOVE_HANDLED + log_combat(shover, target, "shoved", "onto [src] (table)[weapon ? " with [weapon]" : ""]") + return COMSIG_LIVING_SHOVE_HANDLED /obj/structure/table/greyscale icon = 'icons/obj/smooth_structures/table_greyscale.dmi' diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index e660e95b72e..02e04557f42 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -72,7 +72,7 @@ ) RegisterSignals(src, list( COMSIG_MOB_CLIENT_PRE_MOVE, - COMSIG_HUMAN_DISARM_HIT, + COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_GET_PULLED, COMSIG_MOVABLE_TELEPORTING, COMSIG_ATOM_DIR_CHANGE, @@ -83,7 +83,7 @@ SIGNAL_HANDLER UnregisterSignal(src, list( COMSIG_MOB_CLIENT_PRE_MOVE, - COMSIG_HUMAN_DISARM_HIT, + COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_GET_PULLED, COMSIG_MOVABLE_TELEPORTING, COMSIG_ATOM_DIR_CHANGE, diff --git a/code/modules/basketball/basketball.dm b/code/modules/basketball/basketball.dm index 9fe176715db..77c3214fe56 100644 --- a/code/modules/basketball/basketball.dm +++ b/code/modules/basketball/basketball.dm @@ -48,7 +48,7 @@ RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(movement_effect)) RegisterSignal(user, COMSIG_MOB_EMOTED("spin"), PROC_REF(on_spin)) - RegisterSignal(user, COMSIG_HUMAN_DISARM_HIT, PROC_REF(on_equipped_mob_disarm)) + RegisterSignal(user, COMSIG_LIVING_DISARM_HIT, PROC_REF(on_equipped_mob_disarm)) RegisterSignal(user, COMSIG_LIVING_STATUS_KNOCKDOWN, PROC_REF(on_equipped_mob_knockdown)) /obj/item/toy/basketball/proc/remove_ball_effects() @@ -57,7 +57,7 @@ // unlike on_equip, this signal is triggered after the ball is removed from hands // so we can just use is_holding_item_of_type() proc to check for multiple balls if(!wielder.is_holding_item_of_type(/obj/item/toy/basketball)) - UnregisterSignal(wielder, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_EMOTED("spin"), COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_MOB_THROW)) + UnregisterSignal(wielder, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_EMOTED("spin"), COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_MOB_THROW)) wielder = null @@ -99,12 +99,9 @@ /// Used to calculate our disarm chance based on stamina, direction, and spinning /// Note - monkeys use attack_paw() and never trigger this signal (so they always have 100% disarm) -/obj/item/toy/basketball/proc/on_equipped_mob_disarm(mob/living/baller, mob/living/stealer, zone) +/obj/item/toy/basketball/proc/on_equipped_mob_disarm(mob/living/baller, mob/living/stealer, zone, obj/item/weapon) SIGNAL_HANDLER - if(!istype(baller)) - return - // spinning gives you a lower disarm chance but it drains stamina var/disarm_chance = HAS_TRAIT(baller, TRAIT_SPINNING) ? 35 : 50 // ballers stamina results in lower disarm, stealer stamina results in higher disarm diff --git a/code/modules/cargo/markets/market_items/misc.dm b/code/modules/cargo/markets/market_items/misc.dm index d2b70704e7a..0953a73e0ac 100644 --- a/code/modules/cargo/markets/market_items/misc.dm +++ b/code/modules/cargo/markets/market_items/misc.dm @@ -50,6 +50,14 @@ stock_max = 2 availability_prob = 30 +/datum/market_item/misc/shove_blocker + name = "MOD Bulwark Module" + desc = "You have no idea how much effort it took us to extract this module from that damn safeguard MODsuit last shift." + price_min = CARGO_CRATE_VALUE * 4 + price_max = CARGO_CRATE_VALUE * 5.75 + stock_max = 1 + availability_prob = 25 + /datum/market_item/misc/holywater name = "Flask of holy water" desc = "Father Lootius' own brand of ready-made holy water." diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index df9db74b88b..ef10536341e 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -280,9 +280,9 @@ cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS armor_type = /datum/armor/armor_riot - clothing_flags = BLOCKS_SHOVE_KNOCKDOWN strip_delay = 80 equip_delay_other = 60 + clothing_traits = list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED) /datum/armor/armor_riot melee = 50 @@ -379,13 +379,15 @@ armor_type = /datum/armor/armor_swat strip_delay = 120 resistance_flags = FIRE_PROOF | ACID_PROOF - clothing_flags = BLOCKS_SHOVE_KNOCKDOWN | THICKMATERIAL + clothing_flags = THICKMATERIAL cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT_OFF heat_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT slowdown = 0.7 body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + clothing_traits = list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED) + //All of the armor below is mostly unused diff --git a/code/modules/mob/living/basic/basic_defense.dm b/code/modules/mob/living/basic/basic_defense.dm index 69370ed49be..646cabe339d 100644 --- a/code/modules/mob/living/basic/basic_defense.dm +++ b/code/modules/mob/living/basic/basic_defense.dm @@ -4,31 +4,7 @@ return TRUE if(LAZYACCESS(modifiers, RIGHT_CLICK)) - if(user.move_force < move_resist) - return - user.do_attack_animation(src, ATTACK_EFFECT_DISARM) - playsound(src, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) - var/shove_dir = get_dir(user, src) - if(!Move(get_step(src, shove_dir), shove_dir)) - log_combat(user, src, "shoved", "failing to move it") - user.visible_message( - span_danger("[user.name] [response_disarm_continuous] [src]!"), - span_danger("You [response_disarm_simple] [src]!"), - span_hear("You hear aggressive shuffling!"), - COMBAT_MESSAGE_RANGE, - list(src), - ) - to_chat(src, span_userdanger("You're shoved by [user.name]!")) - return TRUE - log_combat(user, src, "shoved", "pushing it") - user.visible_message( - span_danger("[user.name] [response_disarm_continuous] [src], pushing [p_them()]!"), - span_danger("You [response_disarm_simple] [src], pushing [p_them()]!"), - span_hear("You hear aggressive shuffling!"), - COMBAT_MESSAGE_RANGE, - list(src), - ) - to_chat(src, span_userdanger("You're pushed by [user.name]!")) + user.disarm(src) return TRUE if(!user.combat_mode) @@ -63,6 +39,19 @@ updatehealth() return TRUE +/mob/living/basic/get_shoving_message(mob/living/shover, obj/item/weapon, shove_flags) + if(weapon) // no "gently pushing aside" if you're pressing a shield at them. + return ..() + var/moved = !(shove_flags & SHOVE_BLOCKED) + shover.visible_message( + span_danger("[shover.name] [response_disarm_continuous] [src][moved ? ", pushing [p_them()]" : ""]!"), + span_danger("You [response_disarm_simple] [src][moved ? ", pushing [p_them()]" : ""]!"), + span_hear("You hear aggressive shuffling!"), + COMBAT_MESSAGE_RANGE, + list(src), + ) + to_chat(src, span_userdanger("You're [moved ? "pushed" : "shoved"] by [shover.name]!")) + /mob/living/basic/attack_hulk(mob/living/carbon/human/user) . = ..() if(!.) diff --git a/code/modules/mob/living/carbon/alien/adult/adult_defense.dm b/code/modules/mob/living/carbon/alien/adult/adult_defense.dm index b4a119d5aba..d89f6de30d6 100644 --- a/code/modules/mob/living/carbon/alien/adult/adult_defense.dm +++ b/code/modules/mob/living/carbon/alien/adult/adult_defense.dm @@ -15,11 +15,8 @@ to_chat(user, span_danger("You [hitverb] [src]!")) /mob/living/carbon/alien/adult/attack_hand(mob/living/carbon/human/user, list/modifiers) - if(!..() || !user.combat_mode) - return - if(LAZYACCESS(modifiers, RIGHT_CLICK)) - if(stat < UNCONSCIOUS) - user.disarm(src) + . = ..() + if(.) return TRUE var/damage = rand(1, 9) if (prob(90)) @@ -41,7 +38,6 @@ span_danger("You avoid [user]'s punch!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) to_chat(user, span_warning("Your punch misses [src]!")) - /mob/living/carbon/alien/adult/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect) if(!no_effect && !visual_effect_icon) visual_effect_icon = ATTACK_EFFECT_CLAW diff --git a/code/modules/mob/living/carbon/alien/adult/queen.dm b/code/modules/mob/living/carbon/alien/adult/queen.dm index f2093738eac..1a08d2446d2 100644 --- a/code/modules/mob/living/carbon/alien/adult/queen.dm +++ b/code/modules/mob/living/carbon/alien/adult/queen.dm @@ -18,6 +18,8 @@ . = ..() // as a wise man once wrote: "pull over that ass too fat" REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + // that'd be a too cheeky shield bashing strat + ADD_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED, INNATE_TRAIT) AddComponent(/datum/component/seethrough_mob) /mob/living/carbon/alien/adult/royal/on_lying_down(new_lying_angle) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index 9388dcea560..3717cfcb89a 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -44,22 +44,22 @@ In all, this is a lot like the monkey code. /N /mob/living/carbon/alien/attack_hand(mob/living/carbon/human/user, list/modifiers) . = ..() - if(.) //to allow surgery to return properly. - return FALSE - - var/martial_result = user.apply_martial_art(src, modifiers) - if (martial_result != MARTIAL_ATTACK_INVALID) - return martial_result - - if(user.combat_mode) - if(LAZYACCESS(modifiers, RIGHT_CLICK)) - user.do_attack_animation(src, ATTACK_EFFECT_DISARM) - return TRUE - user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) + if(.) return TRUE + + if(LAZYACCESS(modifiers, RIGHT_CLICK)) + user.disarm(src) + return TRUE + if(user.combat_mode) + user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) else help_shake_act(user) + return TRUE +/mob/living/carbon/alien/get_shove_flags(mob/living/shover, obj/item/weapon) + . = ..() + if(isnull(weapon) || stat != CONSCIOUS) + . &= ~(SHOVE_CAN_MOVE|SHOVE_CAN_HIT_SOMETHING|SHOVE_CAN_STAGGER) /mob/living/carbon/alien/attack_paw(mob/living/carbon/human/user, list/modifiers) if(..()) diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm index 3fa78271d6f..62dd4f88b21 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm @@ -1,24 +1,26 @@ /mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/user, list/modifiers) - if(..()) - var/damage = rand(1, 9) - if (prob(90)) - playsound(loc, SFX_PUNCH, 25, TRUE, -1) - log_combat(user, src, "attacked") - visible_message(span_danger("[user] kicks [src]!"), \ - span_userdanger("[user] kicks you!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You kick [src]!")) - if ((stat != DEAD) && (damage > 4.9)) - Unconscious(rand(100,200)) + . = ..() + if(.) + return TRUE + var/damage = rand(1, 9) + if (prob(90)) + playsound(loc, SFX_PUNCH, 25, TRUE, -1) + log_combat(user, src, "attacked") + visible_message(span_danger("[user] kicks [src]!"), \ + span_userdanger("[user] kicks you!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, user) + to_chat(user, span_danger("You kick [src]!")) + if ((stat != DEAD) && (damage > 4.9)) + Unconscious(rand(100,200)) - var/obj/item/bodypart/affecting = get_bodypart(get_random_valid_zone(user.zone_selected)) - apply_damage(damage, BRUTE, affecting) - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1) - visible_message(span_danger("[user]'s kick misses [src]!"), \ - span_danger("You avoid [user]'s kick!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_warning("Your kick misses [src]!")) + var/obj/item/bodypart/affecting = get_bodypart(get_random_valid_zone(user.zone_selected)) + apply_damage(damage, BRUTE, affecting) + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1) + visible_message(span_danger("[user]'s kick misses [src]!"), \ + span_danger("You avoid [user]'s kick!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) + to_chat(user, span_warning("Your kick misses [src]!")) /mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user) . = ..() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index f4e7a6aa766..0c261c9f156 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -5,11 +5,6 @@ register_context() GLOB.carbon_list += src - var/static/list/loc_connections = list( - COMSIG_CARBON_DISARM_PRESHOVE = PROC_REF(disarm_precollide), - COMSIG_CARBON_DISARM_COLLIDE = PROC_REF(disarm_collision), - ) - AddElement(/datum/element/connect_loc, loc_connections) ADD_TRAIT(src, TRAIT_CAN_HOLD_ITEMS, INNATE_TRAIT) // Carbons are assumed to be innately capable of having arms, we check their arms count instead /mob/living/carbon/Destroy() @@ -1377,24 +1372,6 @@ if(mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)) AddComponent(/datum/component/rot, 6 MINUTES, 10 MINUTES, 1) -/mob/living/carbon/proc/disarm_precollide(datum/source, mob/living/carbon/shover, mob/living/carbon/target) - SIGNAL_HANDLER - if(can_be_shoved_into) - return COMSIG_CARBON_ACT_SOLID - -/mob/living/carbon/proc/disarm_collision(datum/source, mob/living/carbon/shover, mob/living/carbon/target, shove_blocked) - SIGNAL_HANDLER - if(src == target || LAZYFIND(target.buckled_mobs, src) || !can_be_shoved_into) - return - target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) - if(!is_shove_knockdown_blocked()) - Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) - target.visible_message(span_danger("[shover] shoves [target.name] into [name]!"), - span_userdanger("You're shoved into [name] by [shover]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) - to_chat(src, span_danger("You shove [target.name] into [name]!")) - log_combat(shover, target, "shoved", addition = "into [name]") - return COMSIG_CARBON_SHOVE_HANDLED - /** * This proc is used to determine whether or not the mob can handle touching an acid affected object. */ diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index a2faacb9a94..01d45b0686d 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -148,10 +148,9 @@ /mob/living/carbon/attack_drone_secondary(mob/living/basic/drone/user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -//ATTACK HAND IGNORING PARENT RETURN VALUE /mob/living/carbon/attack_hand(mob/living/carbon/human/user, list/modifiers) - if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, user, modifiers) & COMPONENT_CANCEL_ATTACK_CHAIN) - . = TRUE + . = ..() + for(var/thing in diseases) var/datum/disease/D = thing if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) @@ -162,13 +161,8 @@ if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) ContactContractDisease(D) - for(var/datum/surgery/operations as anything in surgeries) - if(user.combat_mode) - break - if(body_position != LYING_DOWN && (operations.surgery_flags & SURGERY_REQUIRE_RESTING)) - continue - if(operations.next_step(user, modifiers)) - return TRUE + if(.) + return TRUE for(var/datum/wound/wounds as anything in all_wounds) if(wounds.try_handling(user)) @@ -234,97 +228,6 @@ return dam_zone -/** - * Attempt to disarm the target mob. - * Will shove the target mob back, and drop them if they're in front of something dense - * or another carbon. -*/ -/mob/living/carbon/proc/disarm(mob/living/carbon/target) - do_attack_animation(target, ATTACK_EFFECT_DISARM) - playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) - if (ishuman(target)) - var/mob/living/carbon/human/human_target = target - human_target.w_uniform?.add_fingerprint(src) - - SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, src, zone_selected) - var/shove_dir = get_dir(loc, target.loc) - var/turf/target_shove_turf = get_step(target.loc, shove_dir) - var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied - var/turf/target_old_turf = target.loc - - //Are we hitting anything? or - if(SEND_SIGNAL(target_shove_turf, COMSIG_CARBON_DISARM_PRESHOVE) & COMSIG_CARBON_ACT_SOLID) - shove_blocked = TRUE - else - target.Move(target_shove_turf, shove_dir) - if(get_turf(target) == target_old_turf) - shove_blocked = TRUE - - if(!shove_blocked) - target.setGrabState(GRAB_PASSIVE) - - if(target.IsKnockdown() && !target.IsParalyzed()) //KICK HIM IN THE NUTS - target.Paralyze(SHOVE_CHAIN_PARALYZE) - target.visible_message(span_danger("[name] kicks [target.name] onto [target.p_their()] side!"), - span_userdanger("You're kicked onto your side by [name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) - to_chat(src, span_danger("You kick [target.name] onto [target.p_their()] side!")) - addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living, SetKnockdown), 0), SHOVE_CHAIN_PARALYZE) - log_combat(src, target, "kicks", "onto their side (paralyzing)") - - var/directional_blocked = FALSE - var/can_hit_something = (!target.is_shove_knockdown_blocked() && !target.buckled) - - //Directional checks to make sure that we're not shoving through a windoor or something like that - if(shove_blocked && can_hit_something && (shove_dir in GLOB.cardinals)) - var/target_turf = get_turf(target) - for(var/obj/obj_content in target_turf) - if(obj_content.flags_1 & ON_BORDER_1 && obj_content.dir == shove_dir && obj_content.density) - directional_blocked = TRUE - break - if(target_turf != target_shove_turf && !directional_blocked) //Make sure that we don't run the exact same check twice on the same tile - for(var/obj/obj_content in target_shove_turf) - if(obj_content.flags_1 & ON_BORDER_1 && obj_content.dir == REVERSE_DIR(shove_dir) && obj_content.density) - directional_blocked = TRUE - break - - if(can_hit_something) - //Don't hit people through windows, ok? - if(!directional_blocked && SEND_SIGNAL(target_shove_turf, COMSIG_CARBON_DISARM_COLLIDE, src, target, shove_blocked) & COMSIG_CARBON_SHOVE_HANDLED) - return - if(directional_blocked || shove_blocked) - target.Knockdown(SHOVE_KNOCKDOWN_SOLID) - target.visible_message(span_danger("[name] shoves [target.name], knocking [target.p_them()] down!"), - span_userdanger("You're knocked down from a shove by [name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) - to_chat(src, span_danger("You shove [target.name], knocking [target.p_them()] down!")) - log_combat(src, target, "shoved", "knocking them down") - return - - target.visible_message(span_danger("[name] shoves [target.name]!"), - span_userdanger("You're shoved by [name]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, src) - to_chat(src, span_danger("You shove [target.name]!")) - - //Take their lunch money - var/target_held_item = target.get_active_held_item() - var/append_message = "" - if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) //It's too expensive we'll get caught - target_held_item = null - - if(target_held_item && target.get_timed_status_effect_duration(/datum/status_effect/staggered)) - target.dropItemToGround(target_held_item) - append_message = "causing [target.p_them()] to drop [target_held_item]" - target.visible_message(span_danger("[target.name] drops \the [target_held_item]!"), - span_warning("You drop \the [target_held_item]!"), null, COMBAT_MESSAGE_RANGE) - - target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) - - log_combat(src, target, "shoved", append_message) - -/mob/living/carbon/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this - for (var/obj/item/clothing/clothing in get_equipped_items()) - if(clothing.clothing_flags & BLOCKS_SHOVE_KNOCKDOWN) - return TRUE - return FALSE - /mob/living/carbon/blob_act(obj/structure/blob/B) if (stat == DEAD) return @@ -798,4 +701,10 @@ organs -= organ_type GLOB.bioscrambler_valid_organs = organs +/mob/living/carbon/get_shove_flags(mob/living/shover, obj/item/weapon) + . = ..() + . |= SHOVE_CAN_STAGGER + if(IsKnockdown() && !IsParalyzed()) + . |= SHOVE_CAN_KICK_SIDE + #undef SHAKE_ANIMATION_OFFSET diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 4d71c556736..4791c818e1a 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -29,6 +29,8 @@ AddElement(/datum/element/strippable, GLOB.strippable_human_items, TYPE_PROC_REF(/mob/living/carbon/human/, should_strip)) var/static/list/loc_connections = list( COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + COMSIG_LIVING_DISARM_PRESHOVE = PROC_REF(disarm_precollide), + COMSIG_LIVING_DISARM_COLLIDE = PROC_REF(disarm_collision), ) AddElement(/datum/element/connect_loc, loc_connections) GLOB.human_list += src diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 094a812a0ab..5dfe6a7a4fa 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -129,12 +129,31 @@ apply_damage(15, BRUTE, wound_bonus=10) /mob/living/carbon/human/attack_hand(mob/user, list/modifiers) - if(..()) //to allow surgery to return properly. - return + . = ..() + if(.) + return TRUE if(ishuman(user)) var/mob/living/carbon/human/H = user dna.species.spec_attack_hand(H, src, null, modifiers) +/mob/living/carbon/human/proc/disarm_precollide(datum/source, mob/living/shover, mob/living/target, obj/item/weapon) + SIGNAL_HANDLER + return COMSIG_LIVING_ACT_SOLID + +/mob/living/carbon/human/proc/disarm_collision(datum/source, mob/living/shover, mob/living/target, shove_flags, obj/item/weapon) + SIGNAL_HANDLER + if(src == target || LAZYFIND(target.buckled_mobs, src) || !iscarbon(target)) + return + if(!(shove_flags & SHOVE_KNOCKDOWN_BLOCKED)) + target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) + if(!HAS_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) + Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) + target.visible_message(span_danger("[shover] shoves [target.name] into [name]!"), + span_userdanger("You're shoved into [name] by [shover]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) + to_chat(src, span_danger("You shove [target.name] into [name]!")) + log_combat(shover, target, "shoved", addition = "into [name][weapon ? " with [weapon]" : ""]") + return COMSIG_LIVING_SHOVE_HANDLED + /mob/living/carbon/human/attack_paw(mob/living/carbon/human/user, list/modifiers) var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) var/obj/item/bodypart/affecting = get_bodypart(get_random_valid_zone(dam_zone)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 17f8cdad23a..01c2ed409ff 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -371,9 +371,8 @@ return martial_result if(LAZYACCESS(modifiers, RIGHT_CLICK)) - if (user != src && iscarbon(src)) - user.disarm(src) - return TRUE + user.disarm(src) + return TRUE if (!user.combat_mode) return FALSE if(HAS_TRAIT(user, TRAIT_PACIFISM)) @@ -615,6 +614,116 @@ ricocheting_projectile.set_angle(new_angle_s) return TRUE +/** + * Attempt to disarm the target mob. Some items might let you do it, also carbon can do it with right click. + * Will shove the target mob back, and drop them if they're in front of something dense + * or another carbon. +*/ +/mob/living/proc/disarm(mob/living/target, obj/item/weapon) + if(!can_disarm(target)) + return + var/shove_flags = target.get_shove_flags(src, weapon) + if(weapon) + do_attack_animation(target, used_item = weapon) + playsound(target, 'sound/effects/glassbash.ogg', 50, TRUE, -1) + else + do_attack_animation(target, ATTACK_EFFECT_DISARM) + playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) + if (ishuman(target) && isnull(weapon)) + var/mob/living/carbon/human/human_target = target + human_target.w_uniform?.add_fingerprint(src) + + SEND_SIGNAL(target, COMSIG_LIVING_DISARM_HIT, src, zone_selected, weapon) + var/shove_dir = get_dir(loc, target.loc) + var/turf/target_shove_turf = get_step(target.loc, shove_dir) + var/turf/target_old_turf = target.loc + + //Are we hitting anything? or + if(shove_flags & SHOVE_CAN_MOVE) + if(SEND_SIGNAL(target_shove_turf, COMSIG_LIVING_DISARM_PRESHOVE, src, target, weapon) & COMSIG_LIVING_ACT_SOLID) + shove_flags |= SHOVE_BLOCKED + else + target.Move(target_shove_turf, shove_dir) + if(get_turf(target) == target_old_turf) + shove_flags |= SHOVE_BLOCKED + + if(!(shove_flags & SHOVE_BLOCKED)) + target.setGrabState(GRAB_PASSIVE) + + //Directional checks to make sure that we're not shoving through a windoor or something like that + if((shove_flags & SHOVE_BLOCKED) && (shove_dir in GLOB.cardinals)) + var/target_turf = get_turf(target) + for(var/obj/obj_content in target_turf) + if(obj_content.flags_1 & ON_BORDER_1 && obj_content.dir == shove_dir && obj_content.density) + shove_flags |= SHOVE_DIRECTIONAL_BLOCKED + break + if(target_turf != target_shove_turf && !(shove_flags && SHOVE_DIRECTIONAL_BLOCKED)) //Make sure that we don't run the exact same check twice on the same tile + for(var/obj/obj_content in target_shove_turf) + if(obj_content.flags_1 & ON_BORDER_1 && obj_content.dir == REVERSE_DIR(shove_dir) && obj_content.density) + shove_flags |= SHOVE_DIRECTIONAL_BLOCKED + break + + if(shove_flags & SHOVE_CAN_HIT_SOMETHING) + //Don't hit people through windows, ok? + if(!(shove_flags & SHOVE_DIRECTIONAL_BLOCKED) && (SEND_SIGNAL(target_shove_turf, COMSIG_LIVING_DISARM_COLLIDE, src, target, shove_flags, weapon) & COMSIG_LIVING_SHOVE_HANDLED)) + return + if((shove_flags & SHOVE_BLOCKED) && !(shove_flags & (SHOVE_KNOCKDOWN_BLOCKED|SHOVE_CAN_KICK_SIDE))) + target.Knockdown(SHOVE_KNOCKDOWN_SOLID) + target.visible_message(span_danger("[name] shoves [target.name], knocking [target.p_them()] down!"), + span_userdanger("You're knocked down from a shove by [name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) + to_chat(src, span_danger("You shove [target.name], knocking [target.p_them()] down!")) + log_combat(src, target, "shoved", "knocking them down[weapon ? " with [weapon]" : ""]") + return + + if(shove_flags & SHOVE_CAN_KICK_SIDE) //KICK HIM IN THE NUTS + target.Paralyze(SHOVE_CHAIN_PARALYZE) + target.visible_message(span_danger("[name] kicks [target.name] onto [target.p_their()] side!"), + span_userdanger("You're kicked onto your side by [name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) + to_chat(src, span_danger("You kick [target.name] onto [target.p_their()] side!")) + addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living, SetKnockdown), 0), SHOVE_CHAIN_PARALYZE) + log_combat(src, target, "kicks", "onto their side (paralyzing)") + return + + target.get_shoving_message(src, weapon, shove_flags) + + //Take their lunch money + var/target_held_item = target.get_active_held_item() + var/append_message = weapon ? " with [weapon]" : "" + if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) //It's too expensive we'll get caught + target_held_item = null + + if(target_held_item && target.get_timed_status_effect_duration(/datum/status_effect/staggered)) + target.dropItemToGround(target_held_item) + append_message = "causing [target.p_them()] to drop [target_held_item]" + target.visible_message(span_danger("[target.name] drops \the [target_held_item]!"), + span_warning("You drop \the [target_held_item]!"), null, COMBAT_MESSAGE_RANGE) + + if(shove_flags & SHOVE_CAN_STAGGER) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) + + log_combat(src, target, "shoved", append_message) + +///Check if the universal conditions for disarming/shoving are met. +/mob/living/proc/can_disarm(mob/living/target) + if(body_position != STANDING_UP || src == target || loc == target.loc) + return FALSE + return TRUE + +///Check if there's anything that could stop the knockdown from being shoved into something or someone. +/mob/living/proc/get_shove_flags(mob/living/shover, obj/item/weapon) + if(shover.move_force >= move_resist) + . |= SHOVE_CAN_MOVE + if(!buckled) + . |= SHOVE_CAN_HIT_SOMETHING + if(HAS_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) + . |= SHOVE_KNOCKDOWN_BLOCKED + +///Send the chat feedback message for shoving +/mob/living/proc/get_shoving_message(mob/living/shover, obj/item/weapon, shove_flags) + visible_message(span_danger("[shover] shoves [name][weapon ? " with [weapon]" : ""]!"), + span_userdanger("You're shoved by [shover][weapon ? " with [weapon]" : ""]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, shover) + to_chat(shover, span_danger("You shove [name][weapon ? " with [weapon]" : ""]!")) + /mob/living/proc/check_block(atom/hit_by, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0, damage_type = BRUTE) if(SEND_SIGNAL(src, COMSIG_LIVING_CHECK_BLOCK, hit_by, damage, attack_text, attack_type, armour_penetration, damage_type) & SUCCESSFUL_BLOCK) return TRUE diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 44e8583b86f..722b92835c8 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -229,6 +229,11 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real step_away(src, user, 15) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), src, get_turf(user), 15), 3) +/mob/living/silicon/robot/get_shove_flags(mob/living/shover, obj/item/weapon) + . = ..() + if(isnull(weapon) || stat != CONSCIOUS) + . &= ~(SHOVE_CAN_MOVE|SHOVE_CAN_HIT_SOMETHING) + /mob/living/silicon/robot/welder_act(mob/living/user, obj/item/tool) if(user.combat_mode && usr != src) return FALSE diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 8a0c793103f..e17ba69550d 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -75,6 +75,7 @@ TRAIT_MADNESS_IMMUNE, TRAIT_MARTIAL_ARTS_IMMUNE, TRAIT_NOFIRE_SPREAD, + TRAIT_SHOVE_KNOCKDOWN_BLOCKED, ) add_traits(traits_to_apply, ROUNDSTART_TRAIT) diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index ac04f02f953..f1561c2941b 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -56,25 +56,30 @@ span_userdanger("[user] punches you!"), null, COMBAT_MESSAGE_RANGE, user) to_chat(user, span_danger("You punch [src]!")) -//ATTACK HAND IGNORING PARENT RETURN VALUE /mob/living/silicon/attack_hand(mob/living/carbon/human/user, list/modifiers) - . = FALSE - if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, user, modifiers) & COMPONENT_CANCEL_ATTACK_CHAIN) - . = TRUE + . = ..() + if(.) + return TRUE + + if(LAZYACCESS(modifiers, RIGHT_CLICK)) + user.disarm(src) + return TRUE + if(has_buckled_mobs() && !user.combat_mode) user_unbuckle_mob(buckled_mobs[1], user) + return TRUE + if(user.combat_mode) + user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) + playsound(src.loc, 'sound/effects/bang.ogg', 10, TRUE) + visible_message(span_danger("[user] punches [src], but doesn't leave a dent!"), \ + span_warning("[user] punches you, but doesn't leave a dent!"), null, COMBAT_MESSAGE_RANGE, user) + to_chat(user, span_danger("You punch [src], but don't leave a dent!")) + return TRUE else - if(user.combat_mode) - user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - playsound(src.loc, 'sound/effects/bang.ogg', 10, TRUE) - visible_message(span_danger("[user] punches [src], but doesn't leave a dent!"), \ - span_warning("[user] punches you, but doesn't leave a dent!"), null, COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You punch [src], but don't leave a dent!")) - else - visible_message(span_notice("[user] pets [src]."), \ - span_notice("[user] pets you."), null, null, user) - to_chat(user, span_notice("You pet [src].")) - SEND_SIGNAL(user, COMSIG_MOB_PAT_BORG) + visible_message(span_notice("[user] pets [src]."), span_notice("[user] pets you."), null, null, user) + to_chat(user, span_notice("You pet [src].")) + SEND_SIGNAL(user, COMSIG_MOB_PAT_BORG) + return TRUE /mob/living/silicon/check_block(atom/hitby, damage, attack_text, attack_type, armour_penetration, damage_type, attack_flag) . = ..() diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm index afe4c00db4d..2fea2871c03 100644 --- a/code/modules/mob/living/simple_animal/animal_defense.dm +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -4,21 +4,7 @@ return TRUE if(LAZYACCESS(modifiers, RIGHT_CLICK)) - if(user.move_force < move_resist) - return - user.do_attack_animation(src, ATTACK_EFFECT_DISARM) - playsound(src, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) - var/shove_dir = get_dir(user, src) - if(!Move(get_step(src, shove_dir), shove_dir)) - log_combat(user, src, "shoved", "failing to move it") - user.visible_message(span_danger("[user.name] shoves [src]!"), - span_danger("You shove [src]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) - to_chat(src, span_userdanger("You're shoved by [user.name]!")) - return TRUE - log_combat(user, src, "shoved", "pushing it") - user.visible_message(span_danger("[user.name] shoves [src], pushing [p_them()]!"), - span_danger("You shove [src], pushing [p_them()]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src)) - to_chat(src, span_userdanger("You're pushed by [user.name]!")) + user.disarm(src) return TRUE if(!user.combat_mode) @@ -44,6 +30,19 @@ updatehealth() return TRUE +/mob/living/simple_animal/get_shoving_message(mob/living/shover, obj/item/weapon, shove_flags) + if(weapon) // no "gently pushing aside" if you're pressing a shield at them. + return ..() + var/moved = !(shove_flags & SHOVE_BLOCKED) + shover.visible_message( + span_danger("[shover.name] [response_disarm_continuous] [src][moved ? ", pushing [p_them()]" : ""]!"), + span_danger("You [response_disarm_simple] [src][moved ? ", pushing [p_them()]" : ""]!"), + span_hear("You hear aggressive shuffling!"), + COMBAT_MESSAGE_RANGE, + list(src), + ) + to_chat(src, span_userdanger("You're [moved ? "pushed" : "shoved"] by [shover.name]!")) + /mob/living/simple_animal/attack_hulk(mob/living/carbon/human/user) . = ..() if(!.) diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 5e579723f78..4d8f8b4c6b7 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -760,6 +760,7 @@ armor_type = /datum/armor/mod_theme_safeguard resistance_flags = FIRE_PROOF max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + inbuilt_modules = list(/obj/item/mod/module/shove_blocker/locked) slowdown_inactive = 0.75 slowdown_active = 0.25 allowed_suit_storage = list( @@ -1772,7 +1773,7 @@ UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), CHESTPLATE_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCKS_SHOVE_KNOCKDOWN, + UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), GAUNTLETS_FLAGS = list( diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 3e4b89e6a52..3bcd0751ce4 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -558,6 +558,7 @@ /obj/item/mod/module/magboot/advanced, /obj/item/mod/module/jetpack/advanced, /obj/item/mod/module/anomaly_locked/kinesis/admin, + /obj/item/mod/module/shove_blocker, ) default_pins = list( /obj/item/mod/module/stealth/ninja, diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index b3527125fd2..6df1d9d0a6f 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -424,7 +424,7 @@ if(oldgroup == newgroup) return - + sorted_creatures[oldgroup] -= creature sorted_creatures[newgroup] += creature @@ -578,3 +578,22 @@ #undef SHOOTING_ASSISTANT_OFF #undef STORMTROOPER_MODE #undef SHARPSHOOTER_MODE + +/obj/item/mod/module/anti_stagger + name = "MOD bulwark module" + desc = "Layers upon layers of shock dampening plates, just to stop you from getting shoved into a wall by an angry mob." + icon_state = "bulwark" + complexity = 3 + incompatible_modules = list(/obj/item/mod/module/shove_blocker) + +/obj/item/mod/module/shove_blocker/on_suit_activation() + mod.wearer.add_traits(list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) + +/obj/item/mod/module/shove_blocker/on_suit_deactivation(deleting = FALSE) + mod.wearer.remove_traits(list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) + +/obj/item/mod/module/shove_blocker/locked + name = "superglued MOD bulwark module" + desc = "Layers upon layers of shock dampening plates, just to stop you from getting shoved into a wall by an angry mob. Good luck removing this one." + removable = FALSE + complexity = 0 diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index a16e5add1bb..1976a61376f 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -61,7 +61,7 @@ RegisterSignal(src, COMSIG_RAT_INTERACT, PROC_REF(on_rat_rummage)) RegisterSignal(src, COMSIG_STORAGE_DUMP_CONTENT, PROC_REF(on_storage_dump)) var/static/list/loc_connections = list( - COMSIG_CARBON_DISARM_COLLIDE = PROC_REF(trash_carbon), + COMSIG_LIVING_DISARM_COLLIDE = PROC_REF(trash_living), COMSIG_TURF_RECEIVE_SWEEPED_ITEMS = PROC_REF(ready_for_trash), ) AddElement(/datum/element/connect_loc, loc_connections) @@ -551,17 +551,17 @@ return COMPONENT_RAT_INTERACTED /// Handles a carbon mob getting shoved into the disposal bin -/obj/machinery/disposal/proc/trash_carbon(datum/source, mob/living/carbon/shover, mob/living/carbon/target, shove_blocked) +/obj/machinery/disposal/proc/trash_living(datum/source, mob/living/shover, mob/living/target, shove_flags, obj/item/weapon) SIGNAL_HANDLER - if(!shove_blocked) + if((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED)) return target.Knockdown(SHOVE_KNOCKDOWN_SOLID) target.forceMove(src) target.visible_message(span_danger("[shover.name] shoves [target.name] into \the [src]!"), - span_userdanger("You're shoved into \the [src] by [target.name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) + span_userdanger("You're shoved into \the [src] by [target.name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, shover) to_chat(src, span_danger("You shove [target.name] into \the [src]!")) - log_combat(shover, target, "shoved", "into [src] (disposal bin)") - return COMSIG_CARBON_SHOVE_HANDLED + log_combat(shover, target, "shoved", "into [src] (disposal bin)[weapon ? " with [weapon]" : ""]") + return COMSIG_LIVING_SHOVE_HANDLED ///Called when a push broom is trying to sweep items onto the turf this object is standing on. Garbage will be moved inside. /obj/machinery/disposal/proc/ready_for_trash(datum/source, obj/item/pushbroom/broom, mob/user, list/items_to_sweep) diff --git a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm index 50659115872..bd30318a722 100644 --- a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm +++ b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm @@ -88,12 +88,12 @@ crystalize_timer_id = addtimer(CALLBACK(src, PROC_REF(crystalize), victim), CRYSTALIZE_PRE_WAIT_TIME, TIMER_STOPPABLE) - RegisterSignal(victim, COMSIG_HUMAN_DISARM_HIT, PROC_REF(reset_crystalizing)) + RegisterSignal(victim, COMSIG_LIVING_DISARM_HIT, PROC_REF(reset_crystalizing)) RegisterSignal(victim, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine), override = TRUE) RegisterSignal(victim, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_take_damage)) ///Ran when disarmed, prevents the ethereal from reviving -/obj/item/organ/internal/heart/ethereal/proc/reset_crystalizing(mob/living/defender, mob/living/attacker, zone) +/obj/item/organ/internal/heart/ethereal/proc/reset_crystalizing(mob/living/defender, mob/living/attacker, zone, obj/item/weapon) SIGNAL_HANDLER defender.visible_message( span_notice("The crystals on [defender] are gently broken off."), @@ -120,7 +120,7 @@ ///Stop the crystalization process, unregistering any signals and resetting any variables. /obj/item/organ/internal/heart/ethereal/proc/stop_crystalization_process(mob/living/ethereal, succesful = FALSE) - UnregisterSignal(ethereal, COMSIG_HUMAN_DISARM_HIT) + UnregisterSignal(ethereal, COMSIG_LIVING_DISARM_HIT) UnregisterSignal(ethereal, COMSIG_ATOM_EXAMINE) UnregisterSignal(ethereal, COMSIG_MOB_APPLY_DAMAGE) diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi index f1d19c29da1..eb4b0c536ce 100644 Binary files a/icons/obj/clothing/modsuit/mod_modules.dmi and b/icons/obj/clothing/modsuit/mod_modules.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 121a7a69017..acdcf97e8b9 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1381,6 +1381,7 @@ #include "code\datums\elements\dextrous.dm" #include "code\datums\elements\diggable.dm" #include "code\datums\elements\digitalcamo.dm" +#include "code\datums\elements\disarm_attack.dm" #include "code\datums\elements\door_pryer.dm" #include "code\datums\elements\drag_pickup.dm" #include "code\datums\elements\dryable.dm"