diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index a1bb4122a8..42199174e7 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -290,7 +290,7 @@ #define COMSIG_LIVING_ACTIVE_BLOCK_START "active_block_start" //from base of mob/living/keybind_start_active_blocking(): (obj/item/blocking_item, list/backup_items) #define COMPONENT_PREVENT_BLOCK_START 1 -#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items) +#define COMSIG_LIVING_ACTIVE_PARRY_START "active_parry_start" //from base of mob/living/initiate_parry_sequence(): (parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override) #define COMPONENT_PREVENT_PARRY_START 1 //ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS! diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm index c069649848..a558abbfe8 100644 --- a/code/modules/clothing/gloves/miscellaneous.dm +++ b/code/modules/clothing/gloves/miscellaneous.dm @@ -161,6 +161,68 @@ return NO_AUTO_CLICKDELAY_HANDLING | ATTACK_IGNORE_ACTION +/obj/item/clothing/gloves/fingerless/ablative + name = "ablative armwraps" + desc = "Armwraps made out of a highly durable, reflective metal. Has the side effect of absorbing shocks." + siemens_coefficient = 0 + icon_state = "ablative_armwraps" + item_state = "ablative_armwraps" + block_parry_data = /datum/block_parry_data/ablative_armwraps + var/wornonce = FALSE + +/obj/item/clothing/gloves/fingerless/ablative/proc/get_component_parry_data(datum/source, parrying_method, datum/parrying_item_mob_or_art, list/backup_items, list/override) + if(parrying_method && !(parrying_method == UNARMED_PARRY)) + return + override[src] = ITEM_PARRY + +/obj/item/clothing/gloves/fingerless/ablative/equipped(mob/user, slot) + . = ..() + if(current_equipped_slot == SLOT_GLOVES) + RegisterSignal(user, COMSIG_LIVING_ACTIVE_PARRY_START, .proc/get_component_parry_data) + wornonce = TRUE + +/obj/item/clothing/gloves/fingerless/ablative/dropped(mob/user) + . = ..() + if(wornonce) + UnregisterSignal(user, COMSIG_LIVING_ACTIVE_PARRY_START) + wornonce = FALSE + +/obj/item/clothing/gloves/fingerless/ablative/can_active_parry(mob/user) + var/mob/living/carbon/human/H = user + if(!istype(H)) + return FALSE + return src == H.gloves + +/obj/item/clothing/gloves/fingerless/ablative/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/block_return, parry_efficiency, parry_time) + . = ..() + if(parry_efficiency > 0) + owner.visible_message("[owner] deflects \the [object] with their armwraps!") + +/datum/block_parry_data/ablative_armwraps + parry_stamina_cost = 4 + parry_attack_types = ATTACK_TYPE_UNARMED | ATTACK_TYPE_PROJECTILE | ATTACK_TYPE_TACKLE | ATTACK_TYPE_THROWN | ATTACK_TYPE_MELEE + parry_flags = NONE + + parry_time_windup = 0 + parry_time_spindown = 0 + parry_time_active = 7.5 + + parry_time_perfect = 1 + parry_time_perfect_leeway = 7.5 + parry_imperfect_falloff_percent = 20 + parry_efficiency_perfect = 100 + parry_time_perfect_leeway_override = list( + TEXT_ATTACK_TYPE_MELEE = 1 + ) + + parry_efficiency_considered_successful = 0.01 + parry_efficiency_to_counterattack = INFINITY // no auto counter + parry_max_attacks = INFINITY + parry_failed_cooldown_duration = 2.25 SECONDS + parry_failed_stagger_duration = 2.25 SECONDS + parry_cooldown = 0 + parry_failed_clickcd_duration = 0 + /obj/item/clothing/gloves/botanic_leather name = "botanist's leather gloves" desc = "These leather gloves protect against thorns, barbs, prickles, spikes and other harmful objects of floral origin. They're also quite warm." diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 8d1ee38de6..c0423286c1 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -2,7 +2,7 @@ /** * Determines if we can actively parry. */ -/obj/item/proc/can_active_parry() +/obj/item/proc/can_active_parry(mob/user) return block_parry_data && (item_flags & ITEM_CAN_PARRY) /** @@ -29,7 +29,7 @@ var/datum/block_parry_data/data var/datum/tool var/method - if(using_item?.can_active_parry()) + if(using_item?.can_active_parry(src)) data = using_item.block_parry_data method = ITEM_PARRY tool = using_item @@ -50,9 +50,20 @@ using_item = backup method = ITEM_PARRY var/list/other_items = list() - if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items) & COMPONENT_PREVENT_PARRY_START) + var/list/override = list() + if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items, override) & COMPONENT_PREVENT_PARRY_START) to_chat(src, "Something is preventing you from parrying!") return + if(length(override)) + var/datum/thing = override[1] + var/_method = override[thing] + if(_method == ITEM_PARRY) + using_item = thing + method = ITEM_PARRY + data = using_item.block_parry_data + else if(_method == UNARMED_PARRY) + method = UNARMED_PARRY + data = thing if(!using_item && !method && length(other_items)) using_item = other_items[1] method = ITEM_PARRY @@ -94,7 +105,7 @@ */ /mob/living/proc/find_backup_parry_item() for(var/obj/item/I in held_items - get_active_held_item()) - if(I.can_active_parry()) + if(I.can_active_parry(src)) return I /** @@ -231,7 +242,7 @@ var/efficiency = data.get_parry_efficiency(attack_type, get_parry_time()) switch(parrying) if(ITEM_PARRY) - if(!active_parry_item.can_active_parry()) + if(!active_parry_item.can_active_parry(src)) return BLOCK_NONE . = active_parry_item.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, get_parry_time()) if(UNARMED_PARRY) @@ -243,6 +254,18 @@ if(efficiency <= 0) // Do not allow automatically handled/standardized parries that increase damage for now. return . |= BLOCK_SHOULD_PARTIAL_MITIGATE + if(efficiency >= data.parry_efficiency_perfect) + . |= data.perfect_parry_block_return_flags + if(data.perfect_parry_block_return_list) + return_list |= data.perfect_parry_block_return_list + else if(efficiency >= data.parry_efficiency_considered_successful) + . |= data.imperfect_parry_block_return_flags + if(data.imperfect_parry_block_return_list) + return_list |= data.imperfect_parry_block_return_list + else + . |= data.failed_parry_block_return_flags + if(data.failed_parry_block_return_list) + return_list |= data.failed_parry_block_return_list if(isnull(return_list[BLOCK_RETURN_MITIGATION_PERCENT])) // if one of the on_active_parry procs overrode. We don't have to worry about interference since parries are the first thing checked in the [do_run_block()] sequence. return_list[BLOCK_RETURN_MITIGATION_PERCENT] = clamp(efficiency, 0, 100) // do not allow > 100% or < 0% for now. if((return_list[BLOCK_RETURN_MITIGATION_PERCENT] >= 100) || (damage <= 0)) diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index e290956873..9e974177e5 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -157,6 +157,16 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Parry cooldown post-parry if failed. This is ADDED to parry_cooldown!!! var/parry_failed_cooldown_duration = 0 SECONDS + // Advanced + /// Flags added to return value + var/perfect_parry_block_return_flags = NONE + var/imperfect_parry_block_return_flags = NONE + var/failed_parry_block_return_flags = NONE + /// List appended to block return + var/perfect_parry_block_return_list + var/imperfect_parry_block_return_list + var/failed_parry_block_return_list + /** * Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag. */ diff --git a/code/modules/uplink/uplink_items/uplink_clothing.dm b/code/modules/uplink/uplink_items/uplink_clothing.dm index 6163e5722a..de15b16b68 100644 --- a/code/modules/uplink/uplink_items/uplink_clothing.dm +++ b/code/modules/uplink/uplink_items/uplink_clothing.dm @@ -104,3 +104,10 @@ desc = "An eyepatch that connects itself to your eye socket, enhancing your shooting to an impossible degree, allowing your bullets to ricochet far more often than usual." item = /obj/item/clothing/glasses/eyepatch/syndicate cost = 8 + +/datum/uplink_item/device_tools/ablative_armwraps + name = "Ablative Armwraps" + desc = "A pair of highly reinforced armwraps allowing the user to parry almost anything. Fully reflects projectiles, no downsides to failing, but is very hard to parry melee with." + cost = 6 + item = /obj/item/clothing/gloves/fingerless/ablative + exclude_modes = list(/datum/game_mode/nuclear) diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index b95c377e12..406b0fe62a 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index 0feb6a75db..629b989520 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ