From fa9c1dfd6cca42db10224e2071b257a2f7ca9d59 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Mon, 23 Mar 2020 16:05:22 -0700
Subject: [PATCH 01/96] start
---
.../mob/living/living_blocking_parrying.dm | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 code/modules/mob/living/living_blocking_parrying.dm
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
new file mode 100644
index 0000000000..7b6f4db5e8
--- /dev/null
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -0,0 +1,57 @@
+// yell at me later for file naming
+// This file contains stuff relating to the new directional blocking and parry system.
+/mob/living
+ var/obj/item/blocking_item
+ var/parrying = FALSE
+ var/parry_frame = 0
+
+/datum/block_parry_data
+
+/obj/item
+ /// From a point of reference of someone facing NORTH. Put in DOWN to block attacks from our tile.
+ var/can_block_directions = list(NORTHWEST, NORTH, NORTHEAST)
+ /// Defense flags, see __DEFINES/flags.dm
+ var/defense_flags = NONE
+
+/obj/item/Initialize(mapload)
+
+ return ..()
+
+/// This item can be used to parry. Only a basic check.
+#define ITEM_DEFENSE_CAN_PARRY (1<<0)
+/// This item can be used in the directional blocking system. Only a basic check.
+#define ITEM_DEFENSE_CAN_BLOCK (1<<1)
+
+/**
+ * Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
+ */
+/obj/item/proc/blockable_directions()
+ return list()
+
+/**
+ * Checks if we can block from a specific direction from our direction.
+ *
+ * @params
+ * * our_dir - our direction.
+ * * their_dir - their direction. Must be a single direction, or NONE for an attack from the same tile.
+ */
+/obj/item/proc/can_block_direction(our_dir, their_dir)
+ if(our_dir != NORTH)
+ var/turn_angle = dir2angle(our_dir)
+ // dir2angle(), ss13 proc is clockwise so dir2angle(EAST) == 90
+ // turn(), byond proc is counterclockwise so turn(NORTH, 90) == WEST
+ if(their_dir == NONE)
+ return (DOWN in blockable_directions())
+ return (their_dir in blockable_directions())
+
+/**
+ * can_block_direction but for "compound" directions to check all of them and return the number of directions that were blocked.
+ *
+ * @params
+ * * our_dir - our direction.
+ * * their_dirs - list of their directions as we cannot use bitfields here.
+ */
+/obj/item/proc/can_block_directions_multiple(our_dir, list/their_dirs)
+ . = 0
+ for(var/i in their_dirs)
+ . += can_block_direction(our_dir, i)
From d139234c6de2408af17fea335d8cfb69f75a7acb Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Mon, 23 Mar 2020 16:06:40 -0700
Subject: [PATCH 02/96] my smooth brain hurts
---
code/modules/mob/living/living_blocking_parrying.dm | 1 +
1 file changed, 1 insertion(+)
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 7b6f4db5e8..ff5e86c525 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -40,6 +40,7 @@
var/turn_angle = dir2angle(our_dir)
// dir2angle(), ss13 proc is clockwise so dir2angle(EAST) == 90
// turn(), byond proc is counterclockwise so turn(NORTH, 90) == WEST
+ their_dir = turn(their_dir, turn_angle)
if(their_dir == NONE)
return (DOWN in blockable_directions())
return (their_dir in blockable_directions())
From 2e0992dbb9920f37db8ad64d7783066f358bb4be Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Tue, 24 Mar 2020 19:29:54 -0700
Subject: [PATCH 03/96] k
---
code/__DEFINES/combat/block_parry.dm | 24 +++++++++++++++++++
.../mob/living/living_blocking_parrying.dm | 17 ++++++-------
2 files changed, 33 insertions(+), 8 deletions(-)
create mode 100644 code/__DEFINES/combat/block_parry.dm
diff --git a/code/__DEFINES/combat/block_parry.dm b/code/__DEFINES/combat/block_parry.dm
new file mode 100644
index 0000000000..bfbce5f7d6
--- /dev/null
+++ b/code/__DEFINES/combat/block_parry.dm
@@ -0,0 +1,24 @@
+// We can't determine things like NORTHEAST vs NORTH *and* EAST without making our own flags :(
+#define BLOCK_DIR_NORTH (1<<0)
+#define BLOCK_DIR_NORTHEAST (1<<1)
+#define BLCOK_DIR_NORTHWEST (1<<2)
+#define BLOCK_DIR_WEST (1<<3)
+#define BLOCK_DIR_EAST (1<<4)
+#define BLOCK_DIR_SOUTH (1<<5)
+#define BLOCK_DIR_SOUTHEAST (1<<6)
+#define BLOCK_DIR_SOUTHWEST (1<<7)
+#define BLOCK_DIR_ONTOP (1<<8)
+
+GLOBAL_LIST_INIT(dir2blockdir, list(
+ "[NORTH]" = "[BLOCK_DIR_NORTH]",
+ "[NORTHEAST]" = "[BLOCK_DIR_NORTHEAST]",
+ "[NORTHWEST]" = "[BLOCK_DIR_NORTHWEST]",
+ "[WEST]" = "[BLOCK_DIR_WEST]",
+ "[EAST]" = "[BLOCK_DIR_EAST]",
+ "[SOUTH]" = "[BLOCK_DIR_SOUTH]",
+ "[SOUTHEAST]" = "[BLOCK_DIR_SOUTHEAST]",
+ "[SOUTHWEST]" = "[BLOCK_DIR_SOUTHWEST]",
+ "[NONE]" = "[BLOCK_DIR_ONTOP]",
+ ))
+
+#define DIR2BLOCKDIR(d) (GLOB.dir2blockdir["[d]"])
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index ff5e86c525..5f69ed289c 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -7,9 +7,10 @@
/datum/block_parry_data
+
/obj/item
- /// From a point of reference of someone facing NORTH. Put in DOWN to block attacks from our tile.
- var/can_block_directions = list(NORTHWEST, NORTH, NORTHEAST)
+ /// See defines.
+ var/can_block_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST
/// Defense flags, see __DEFINES/flags.dm
var/defense_flags = NONE
@@ -17,16 +18,18 @@
return ..()
-/// This item can be used to parry. Only a basic check.
+/// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all.
#define ITEM_DEFENSE_CAN_PARRY (1<<0)
-/// This item can be used in the directional blocking system. Only a basic check.
+/// This item can be used in the directional blocking system. Only a basic check used to determine if we should proceed with directional block handling at all.
#define ITEM_DEFENSE_CAN_BLOCK (1<<1)
+
+
/**
* Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
*/
/obj/item/proc/blockable_directions()
- return list()
+ return can_block_directions
/**
* Checks if we can block from a specific direction from our direction.
@@ -41,9 +44,7 @@
// dir2angle(), ss13 proc is clockwise so dir2angle(EAST) == 90
// turn(), byond proc is counterclockwise so turn(NORTH, 90) == WEST
their_dir = turn(their_dir, turn_angle)
- if(their_dir == NONE)
- return (DOWN in blockable_directions())
- return (their_dir in blockable_directions())
+ return (DIR2BLOCKDIR(their_dir) in blockable_directions())
/**
* can_block_direction but for "compound" directions to check all of them and return the number of directions that were blocked.
From 1a7e812d55ab521cb520429c05d3ac6488a70ebc Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Tue, 24 Mar 2020 19:51:23 -0700
Subject: [PATCH 04/96] wip
---
.../mob/living/living_blocking_parrying.dm | 45 ++++++++++++++++---
tgstation.dme | 2 +
2 files changed, 42 insertions(+), 5 deletions(-)
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 5f69ed289c..d95a4d7028 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -5,17 +5,52 @@
var/parrying = FALSE
var/parry_frame = 0
+
+GLOBAL_LIST_EMPTY(block_parry_data)
+
+/proc/get_block_parry_data(type_or_id)
+ if(ispath(type_or_id))
+ . = GLOB.block_parry_data["[type_or_id]"]
+ if(!.)
+ . = GLOB.block_parry_data["[type_or_id]"] = new type_or_id
+ else //text id
+ return GLOB.block_parry_data["[type_or_id]"]
+
+/proc/set_block_parry_data(id, datum/block_parry_data/data)
+ if(ispath(id))
+ CRASH("Path-fetching of block parry data is only to grab static data, do not attempt to modify global caches of paths. Use string IDs.")
+ GLOB.block_parry_data["[id]"] = data
+
+/// Carries data like list data that would be a waste of memory if we initialized the list on every /item as we can cache datums easier.
/datum/block_parry_data
+ /////////// BLOCKING ////////////
+ /// See defines.
+ var/can_block_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST
+ /// See defines.
+ var/block_flags = BLOCK_FLAGS_DEFAULT
+ /// Our slowdown added while blocking
+ var/block_slowdown = 2
+ /// Clickdelay added to user after block ends
+ var/block_end_click_cd_add = 4
+ /// Default damage-to-stamina coefficient, higher is better.
+ var/block_efficiency = 2
+ /// Override damage-to-stamina coefficient, higher is better, this should be list(ATTACK_TYPE_DEFINE = coefficient_number)
+ var/list/attack_type_block_efficiency
+
+
+ /////////// PARRYING ////////////
+
/obj/item
- /// See defines.
- var/can_block_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST
- /// Defense flags, see __DEFINES/flags.dm
+ /// Defense flags, see defines.
var/defense_flags = NONE
+ /// Our block parry data. Should be set in init, or something.
+ var/datum/block_parry_data/block_parry_data
+
/obj/item/Initialize(mapload)
-
+ block_parry_data = get_block_parry_data(/datum/block_parry_data)
return ..()
/// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all.
@@ -29,7 +64,7 @@
* Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
*/
/obj/item/proc/blockable_directions()
- return can_block_directions
+ return block_parry_data.can_block_directions
/**
* Checks if we can block from a specific direction from our direction.
diff --git a/tgstation.dme b/tgstation.dme
index 2c3b192290..593a6b3141 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -117,6 +117,7 @@
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\wall_dents.dm"
#include "code\__DEFINES\wires.dm"
+#include "code\__DEFINES\combat\block_parry.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals.dm"
@@ -2205,6 +2206,7 @@
#include "code\modules\mob\living\life.dm"
#include "code\modules\mob\living\living.dm"
#include "code\modules\mob\living\living_block.dm"
+#include "code\modules\mob\living\living_blocking_parrying.dm"
#include "code\modules\mob\living\living_combat.dm"
#include "code\modules\mob\living\living_defense.dm"
#include "code\modules\mob\living\living_defines.dm"
From 4a84736eff7f7ccf4b92bb83f2c033d60c3e7687 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Tue, 24 Mar 2020 19:57:04 -0700
Subject: [PATCH 05/96] more
---
.../mob/living/living_blocking_parrying.dm | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index d95a4d7028..2ed88aa2b4 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -39,7 +39,20 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/////////// PARRYING ////////////
-
+ /// Parry windup duration in deciseconds
+ var/parry_time_windup = 2
+ /// Parry spooldown duration in deciseconds
+ var/parry_time_spooldown = 3
+ /// Main parry window in deciseconds
+ var/parry_time_active = 5
+ /// Perfect parry window in deciseconds from the main window. 3 with main 5 = perfect on third decisecond of main window.
+ var/parry_time_perfect = 2.5
+ /// Time on both sides of perfect parry that still counts as well, perfect
+ var/parry_time_perfect_leeway = 0.5
+ /// Parry "efficiency" falloff in percent per decisecond once perfect window is over.
+ var/parry_imperfect_falloff_percent = 20
+ /// Efficiency in percent on perfect parry.
+ var/parry_efficiency_perfect = 120
/obj/item
From 0774bca2f4bc09685d2423ee995ed79cdedd7a60 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Wed, 25 Mar 2020 20:51:42 -0700
Subject: [PATCH 06/96] wew
---
.../mob/living/living_blocking_parrying.dm | 44 +++++++++++++++----
1 file changed, 36 insertions(+), 8 deletions(-)
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 2ed88aa2b4..08b739be75 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -32,11 +32,36 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/block_slowdown = 2
/// Clickdelay added to user after block ends
var/block_end_click_cd_add = 4
- /// Default damage-to-stamina coefficient, higher is better.
- var/block_efficiency = 2
- /// Override damage-to-stamina coefficient, higher is better, this should be list(ATTACK_TYPE_DEFINE = coefficient_number)
- var/list/attack_type_block_efficiency
+ /// Disallow attacking during block
+ var/block_lock_attacking = TRUE
+ /// Amount of "free" damage blocking absorbs
+ var/block_damage_absorption = 10
+ /// Override absorption, list(ATTACK_TYPE_DEFINE = absorption), see [block_damage_absorption]
+ var/list/block_damage_absorption_override
+
+ /// Ratio of damage block above absorption amount, coefficient, lower is better, this is multiplied by damage to determine how much is blocked.
+ var/block_damage_multiplier = 0.5
+ /// Override damage overrun efficiency, list(ATTACK_TYPE_DEFINE = absorption), see [block_damage_efficiency]
+ var/list/block_damage_multiplier_override
+
+ /// Upper bound of damage block, anything above this will go right through.
+ var/block_damage_limit = 80
+ /// Override upper bound of damage block, list(ATTACK_TYPE_DEFINE = absorption), see [block_damage_limit]
+ var/list/block_damage_limit_override
+
+ /// Default damage-to-stamina coefficient, higher is better. This is based on amount of damage BLOCKED, not initial damage, to prevent damage from "double dipping".
+ var/block_stamina_efficiency = 2
+ /// Override damage-to-stamina coefficient, see [block_efficiency], this should be list(ATTACK_TYPE_DEFINE = coefficient_number)
+ var/list/block_stamina_efficiency_override
+
+ /// Ratio of stamina incurred by blocking that goes to the arm holding the object instead of the chest. Has no effect if this is not held in hand.
+ var/block_stamina_limb_ratio = 0.5
+ /// Override stamina limb ratio, list(ATTACK_TYPE_DEFINE = absorption), see [block_stamina_limb_ratio]
+ var/list/block_stamina_limb_ratio
+
+ /// Stamina dealt directly via adjustStaminaLoss() per SECOND of block.
+ var/block_stamina_cost_per_second = 1.5
/////////// PARRYING ////////////
/// Parry windup duration in deciseconds
@@ -48,13 +73,16 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Perfect parry window in deciseconds from the main window. 3 with main 5 = perfect on third decisecond of main window.
var/parry_time_perfect = 2.5
/// Time on both sides of perfect parry that still counts as well, perfect
- var/parry_time_perfect_leeway = 0.5
+ var/parry_time_perfect_leeway = 1
+ /// [parry_time_perfect_leeway] override for attack types, list(ATTACK_TYPE_DEFINE = deciseconds)
+ var/list/parry_time_perfect_leeway_override
/// Parry "efficiency" falloff in percent per decisecond once perfect window is over.
var/parry_imperfect_falloff_percent = 20
+ /// [parry_imperfect_falloff_percent] override for attack types, list(ATTACK_TYPE_DEFINE = deciseconds)
+ var/list/parry_time_imperfect_falloff_percent_override
/// Efficiency in percent on perfect parry.
var/parry_efficiency_perfect = 120
-
/obj/item
/// Defense flags, see defines.
var/defense_flags = NONE
@@ -102,6 +130,6 @@ GLOBAL_LIST_EMPTY(block_parry_data)
* * their_dirs - list of their directions as we cannot use bitfields here.
*/
/obj/item/proc/can_block_directions_multiple(our_dir, list/their_dirs)
- . = 0
+ . = FALSE
for(var/i in their_dirs)
- . += can_block_direction(our_dir, i)
+ . |= can_block_direction(our_dir, i)
From 13a8e7a777ebe7fcf187ae0a08829bdea8e0433d Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Wed, 25 Mar 2020 21:06:01 -0700
Subject: [PATCH 07/96] k
---
code/__DEFINES/combat.dm | 51 ------------------
code/__DEFINES/combat/block.dm | 54 +++++++++++++++++++
.../mob/living/living_blocking_parrying.dm | 5 +-
3 files changed, 58 insertions(+), 52 deletions(-)
create mode 100644 code/__DEFINES/combat/block.dm
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index fb361364d4..241cbf8eb6 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -255,54 +255,3 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting.
#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default.
#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs.
-
-/// Bitflags for check_block() and handle_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
-/// Attack was not blocked
-#define BLOCK_NONE NONE
-/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
-#define BLOCK_SUCCESS (1<<1)
-
-/// The below are for "metadata" on "how" the attack was blocked.
-
-/// Attack was and should be redirected according to list argument REDIRECT_METHOD (NOTE: the SHOULD here is important, as it says "the thing blocking isn't handling the reflecting for you so do it yourself"!)
-#define BLOCK_SHOULD_REDIRECT (1<<2)
-/// Attack was redirected (whether by us or by SHOULD_REDIRECT flagging for automatic handling)
-#define BLOCK_REDIRECTED (1<<3)
-/// Attack was blocked by something like a shield.
-#define BLOCK_PHYSICAL_EXTERNAL (1<<4)
-/// Attack was blocked by something worn on you.
-#define BLOCK_PHYSICAL_INTERNAL (1<<5)
-/// Attack outright missed because the target dodged. Should usually be combined with redirection passthrough or something (see martial arts)
-#define BLOCK_TARGET_DODGED (1<<7)
-/// Meta-flag for run_block/do_run_block : By default, BLOCK_SUCCESS tells do_run_block() to assume the attack is completely blocked and not continue the block chain. If this is present, it will continue to check other items in the chain rather than stopping.
-#define BLOCK_CONTINUE_CHAIN (1<<8)
-
-/// For keys in associative list/block_return as we don't want to saturate our (somewhat) limited flags.
-#define BLOCK_RETURN_REDIRECT_METHOD "REDIRECT_METHOD"
- /// Pass through victim
- #define REDIRECT_METHOD_PASSTHROUGH "passthrough"
- /// Deflect at randomish angle
- #define REDIRECT_METHOD_DEFLECT "deflect"
- /// reverse 180 angle, basically (as opposed to "realistic" wall reflections)
- #define REDIRECT_METHOD_REFLECT "reflect"
- /// "do not taser the bad man with the desword" - actually aims at the firer/attacker rather than just reversing
- #define REDIRECT_METHOD_RETURN_TO_SENDER "no_you"
-
-/// These keys are generally only applied to the list if real_attack is FALSE. Used incase we want to make "smarter" mob AI in the future or something.
-/// Tells the caller how likely from 0 (none) to 100 (always) we are to reflect energy projectiles
-#define BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE "reflect_projectile_chance"
-/// Tells the caller how likely we are to block attacks from 0 to 100 in general
-#define BLOCK_RETURN_NORMAL_BLOCK_CHANCE "normal_block_chance"
-/// Tells the caller about how many hits we can soak on average before our blocking fails.
-#define BLOCK_RETURN_BLOCK_CAPACITY "block_capacity"
-
-/// Default if the above isn't set in the list.
-#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT
-
-/// Block priorities
-#define BLOCK_PRIORITY_HELD_ITEM 100
-#define BLOCK_PRIORITY_CLOTHING 50
-#define BLOCK_PRIORITY_WEAR_SUIT 75
-#define BLOCK_PRIORITY_UNIFORM 25
-
-#define BLOCK_PRIORITY_DEFAULT BLOCK_PRIORITY_HELD_ITEM
diff --git a/code/__DEFINES/combat/block.dm b/code/__DEFINES/combat/block.dm
new file mode 100644
index 0000000000..71ba20b22b
--- /dev/null
+++ b/code/__DEFINES/combat/block.dm
@@ -0,0 +1,54 @@
+// Don't ask why there's block_parry.dm and this. This is for the run_block() system, which is the "parent" system of the directional block and parry systems.
+
+/// Bitflags for check_block() and handle_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
+/// Attack was not blocked
+#define BLOCK_NONE NONE
+/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
+#define BLOCK_SUCCESS (1<<1)
+
+/// The below are for "metadata" on "how" the attack was blocked.
+
+/// Attack was and should be redirected according to list argument REDIRECT_METHOD (NOTE: the SHOULD here is important, as it says "the thing blocking isn't handling the reflecting for you so do it yourself"!)
+#define BLOCK_SHOULD_REDIRECT (1<<2)
+/// Attack was redirected (whether by us or by SHOULD_REDIRECT flagging for automatic handling)
+#define BLOCK_REDIRECTED (1<<3)
+/// Attack was blocked by something like a shield.
+#define BLOCK_PHYSICAL_EXTERNAL (1<<4)
+/// Attack was blocked by something worn on you.
+#define BLOCK_PHYSICAL_INTERNAL (1<<5)
+/// Attack outright missed because the target dodged. Should usually be combined with redirection passthrough or something (see martial arts)
+#define BLOCK_TARGET_DODGED (1<<7)
+/// Meta-flag for run_block/do_run_block : By default, BLOCK_SUCCESS tells do_run_block() to assume the attack is completely blocked and not continue the block chain. If this is present, it will continue to check other items in the chain rather than stopping.
+#define BLOCK_CONTINUE_CHAIN (1<<8)
+
+/// For keys in associative list/block_return as we don't want to saturate our (somewhat) limited flags.
+#define BLOCK_RETURN_REDIRECT_METHOD "REDIRECT_METHOD"
+ /// Pass through victim
+ #define REDIRECT_METHOD_PASSTHROUGH "passthrough"
+ /// Deflect at randomish angle
+ #define REDIRECT_METHOD_DEFLECT "deflect"
+ /// reverse 180 angle, basically (as opposed to "realistic" wall reflections)
+ #define REDIRECT_METHOD_REFLECT "reflect"
+ /// "do not taser the bad man with the desword" - actually aims at the firer/attacker rather than just reversing
+ #define REDIRECT_METHOD_RETURN_TO_SENDER "no_you"
+
+/// These keys are generally only applied to the list if real_attack is FALSE. Used incase we want to make "smarter" mob AI in the future or something.
+/// Tells the caller how likely from 0 (none) to 100 (always) we are to reflect energy projectiles
+#define BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE "reflect_projectile_chance"
+/// Tells the caller how likely we are to block attacks from 0 to 100 in general
+#define BLOCK_RETURN_NORMAL_BLOCK_CHANCE "normal_block_chance"
+/// Tells the caller about how many hits we can soak on average before our blocking fails.
+#define BLOCK_RETURN_BLOCK_CAPACITY "block_capacity"
+
+/// Default if the above isn't set in the list.
+#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT
+
+/// Block priorities. Higher means it's checked sooner.
+#define BLOCK_PRIORITY_ACTIVE_PARRY 300
+#define BLOCK_PRIORITY_ACTIVE_BLOCK 200
+#define BLOCK_PRIORITY_HELD_ITEM 100
+#define BLOCK_PRIORITY_CLOTHING 50
+#define BLOCK_PRIORITY_WEAR_SUIT 75
+#define BLOCK_PRIORITY_UNIFORM 25
+
+#define BLOCK_PRIORITY_DEFAULT BLOCK_PRIORITY_HELD_ITEM
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 08b739be75..3ee5431eb6 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -34,6 +34,8 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/block_end_click_cd_add = 4
/// Disallow attacking during block
var/block_lock_attacking = TRUE
+ /// The priority we get in [mob/do_run_block()] while we're being used.
+ var/block_active_priority = BLOCK_PRIORITY_ACTIVE_BLOCK
/// Amount of "free" damage blocking absorbs
var/block_damage_absorption = 10
@@ -58,7 +60,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Ratio of stamina incurred by blocking that goes to the arm holding the object instead of the chest. Has no effect if this is not held in hand.
var/block_stamina_limb_ratio = 0.5
/// Override stamina limb ratio, list(ATTACK_TYPE_DEFINE = absorption), see [block_stamina_limb_ratio]
- var/list/block_stamina_limb_ratio
+ var/list/block_stamina_limb_ratio_override
/// Stamina dealt directly via adjustStaminaLoss() per SECOND of block.
var/block_stamina_cost_per_second = 1.5
@@ -90,6 +92,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/datum/block_parry_data/block_parry_data
+
/obj/item/Initialize(mapload)
block_parry_data = get_block_parry_data(/datum/block_parry_data)
return ..()
From 825adfa29ffac4769a00ba78b6927a311d19b068 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Wed, 25 Mar 2020 21:23:54 -0700
Subject: [PATCH 08/96] whew
---
code/__DEFINES/combat/block.dm | 1 +
code/__DEFINES/{ => flags}/flags.dm | 0
.../{obj_flags.dm => flags/item_flags.dm} | 22 +++----------
code/__DEFINES/flags/obj_flags.dm | 15 +++++++++
code/__HELPERS/cmp.dm | 2 +-
code/game/objects/items.dm | 6 ++++
.../mob/living/carbon/human/human_block.dm | 9 +++--
code/modules/mob/living/living_block.dm | 27 +++++++++++----
.../mob/living/living_blocking_parrying.dm | 33 ++++++++++---------
.../chemistry/reagents/alcohol_reagents.dm | 4 +--
10 files changed, 74 insertions(+), 45 deletions(-)
rename code/__DEFINES/{ => flags}/flags.dm (100%)
rename code/__DEFINES/{obj_flags.dm => flags/item_flags.dm} (74%)
create mode 100644 code/__DEFINES/flags/obj_flags.dm
diff --git a/code/__DEFINES/combat/block.dm b/code/__DEFINES/combat/block.dm
index 71ba20b22b..d3c6d1e90e 100644
--- a/code/__DEFINES/combat/block.dm
+++ b/code/__DEFINES/combat/block.dm
@@ -44,6 +44,7 @@
#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT
/// Block priorities. Higher means it's checked sooner.
+// THESE MUST NEVER BE 0! Block code uses ! instead of isnull for the speed boost.
#define BLOCK_PRIORITY_ACTIVE_PARRY 300
#define BLOCK_PRIORITY_ACTIVE_BLOCK 200
#define BLOCK_PRIORITY_HELD_ITEM 100
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags/flags.dm
similarity index 100%
rename from code/__DEFINES/flags.dm
rename to code/__DEFINES/flags/flags.dm
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/flags/item_flags.dm
similarity index 74%
rename from code/__DEFINES/obj_flags.dm
rename to code/__DEFINES/flags/item_flags.dm
index d78de86d25..6b754a5956 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/flags/item_flags.dm
@@ -1,20 +1,3 @@
-// Flags for the obj_flags var on /obj
-
-
-#define EMAGGED (1<<0)
-#define IN_USE (1<<1) //If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
-#define CAN_BE_HIT (1<<2) //can this be bludgeoned by items?
-#define BEING_SHOCKED (1<<3) //Whether this thing is currently (already) being shocked by a tesla
-#define DANGEROUS_POSSESSION (1<<4) //Admin possession yes/no
-#define ON_BLUEPRINTS (1<<5) //Are we visible on the station blueprints at roundstart?
-#define UNIQUE_RENAME (1<<6) //can you customize the description/name of the thing?
-#define USES_TGUI (1<<7) //put on things that use tgui on ui_interact instead of custom/old UI.
-#define FROZEN (1<<8)
-#define SHOVABLE_ONTO (1<<9) //called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
-#define BLOCK_Z_FALL (1<<10)
-
-// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
-
// Flags for the item_flags var on /obj/item
#define BEING_REMOVED (1<<0)
@@ -30,6 +13,11 @@
#define SURGICAL_TOOL (1<<10) //Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes)
#define NO_UNIFORM_REQUIRED (1<<11) //Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
#define NO_ATTACK_CHAIN_SOFT_STAMCRIT (1<<12) //Entirely blocks melee_attack_chain() if user is soft stamcritted. Uses getStaminaLoss() to check at this point in time. THIS DOES NOT BLOCK RANGED AFTERATTACK()S, ONLY MELEE RANGE AFTERATTACK()S.
+/// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all.
+#define ITEM_CAN_PARRY (1<<0)
+/// This item can be used in the directional blocking system. Only a basic check used to determine if we should proceed with directional block handling at all.
+#define ITEM_CAN_BLOCK (1<<1)
+
// Flags for the clothing_flags var on /obj/item/clothing
diff --git a/code/__DEFINES/flags/obj_flags.dm b/code/__DEFINES/flags/obj_flags.dm
new file mode 100644
index 0000000000..ebb9b4bda0
--- /dev/null
+++ b/code/__DEFINES/flags/obj_flags.dm
@@ -0,0 +1,15 @@
+// Flags for the obj_flags var on /obj
+
+#define EMAGGED (1<<0)
+#define IN_USE (1<<1) //If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
+#define CAN_BE_HIT (1<<2) //can this be bludgeoned by items?
+#define BEING_SHOCKED (1<<3) //Whether this thing is currently (already) being shocked by a tesla
+#define DANGEROUS_POSSESSION (1<<4) //Admin possession yes/no
+#define ON_BLUEPRINTS (1<<5) //Are we visible on the station blueprints at roundstart?
+#define UNIQUE_RENAME (1<<6) //can you customize the description/name of the thing?
+#define USES_TGUI (1<<7) //put on things that use tgui on ui_interact instead of custom/old UI.
+#define FROZEN (1<<8)
+#define SHOVABLE_ONTO (1<<9) //called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check.
+#define BLOCK_Z_FALL (1<<10)
+
+// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index 9b877e8fb0..5fb4d05d42 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -104,7 +104,7 @@ GLOBAL_VAR_INIT(cmp_field, "name")
var/a_sign = num2sign(initial(A.value) * -1)
var/b_sign = num2sign(initial(B.value) * -1)
- // Neutral traits go last.
+ // Neutral traits go last
if(a_sign == 0)
a_sign = 2
if(b_sign == 0)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index ed08386f81..50a8273dbb 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -107,6 +107,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
+ /* Our block parry data. Should be set in init, or something if you are using it.
+ * This won't be accessed without ITEM_CAN_BLOCK or ITEM_CAN_PARRY so do not set it unless you have to to save memory.
+ * If you decide it's a good idea to leave this unset while turning the flags on, you will runtime. Enjoy.
+ */
+ var/datum/block_parry_data/block_parry_data
+
/obj/item/Initialize()
if (attack_verb)
diff --git a/code/modules/mob/living/carbon/human/human_block.dm b/code/modules/mob/living/carbon/human/human_block.dm
index b1a5153ce5..e95d932cc1 100644
--- a/code/modules/mob/living/carbon/human/human_block.dm
+++ b/code/modules/mob/living/carbon/human/human_block.dm
@@ -1,8 +1,11 @@
/mob/living/carbon/human/get_blocking_items()
. = ..()
if(wear_suit)
- . += wear_suit
+ if(!.[wear_suit])
+ .[wear_suit] = wear_suit.block_priority
if(w_uniform)
- . += w_uniform
+ if(!.[wear_uniform])
+ .[wear_uniform] = wear_uniform.block_priority
if(wear_neck)
- . += wear_neck
+ if(!.[wear_neck])
+ .[wear_neck] = wear_neck.block_priority
diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm
index d9e3309e47..f8b62349e6 100644
--- a/code/modules/mob/living/living_block.dm
+++ b/code/modules/mob/living/living_block.dm
@@ -51,31 +51,46 @@
if((. & BLOCK_SUCCESS) && !(. & BLOCK_CONTINUE_CHAIN))
return
var/list/obj/item/tocheck = get_blocking_items()
- sortTim(tocheck, /proc/cmp_item_block_priority_asc)
+ sortTim(tocheck, /proc/cmp_numeric_asc, TRUE)
// i don't like this
var/block_chance_modifier = round(damage / -3)
if(real_attack)
for(var/obj/item/I in tocheck)
// i don't like this too
var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
- var/results = I.run_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
+ var/results
+ if(I == active_parry_item)
+ results = I.active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
+ else if(I == active_block_item)
+ results = I.active_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
+ else
+ results = I.run_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
. |= results
if((results & BLOCK_SUCCESS) && !(results & BLOCK_CONTINUE_CHAIN))
break
else
for(var/obj/item/I in tocheck)
// i don't like this too
- var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
- I.check_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
+ if(I == active_block_item) //block is long termed enough we give a damn. parry, not so much.
+ I.check_active_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
+ else
+ var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
+ I.check_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
-/// Gets an unsortedlist of objects to run block checks on.
+/// Gets an unsortedlist of objects to run block checks on. List must have associative values for priorities!
/mob/living/proc/get_blocking_items()
. = list()
+ if(active_block_item)
+ .[active_block_item] = active_block_item.block_parry_data.block_active_priority
+ if(active_parry_item)
+ .[active_parry_item] = active_parry_item.block_parry_data.parry_active_priority
for(var/obj/item/I in held_items)
// this is a bad check but i am not removing it until a better catchall is made
if(istype(I, /obj/item/clothing))
continue
- . |= I
+ if(.[I]) //don't override block/parry.
+ continue
+ .[I] = I.block_priority
/obj/item
/// The 0% to 100% chance for the default implementation of random block rolls.
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 3ee5431eb6..cc6bae8054 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -1,7 +1,8 @@
// yell at me later for file naming
// This file contains stuff relating to the new directional blocking and parry system.
/mob/living
- var/obj/item/blocking_item
+ var/obj/item/active_block_item
+ var/obj/item/active_parry_item
var/parrying = FALSE
var/parry_frame = 0
@@ -34,7 +35,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/block_end_click_cd_add = 4
/// Disallow attacking during block
var/block_lock_attacking = TRUE
- /// The priority we get in [mob/do_run_block()] while we're being used.
+ /// The priority we get in [mob/do_run_block()] while we're being used to parry.
var/block_active_priority = BLOCK_PRIORITY_ACTIVE_BLOCK
/// Amount of "free" damage blocking absorbs
@@ -66,6 +67,8 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/block_stamina_cost_per_second = 1.5
/////////// PARRYING ////////////
+ /// Prioriry for [mob/do_run_block()] while we're being used to parry.
+ var/parry_active_priority = BLOCK_PRIORITY_ACTIVE_PARRY
/// Parry windup duration in deciseconds
var/parry_time_windup = 2
/// Parry spooldown duration in deciseconds
@@ -85,24 +88,22 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Efficiency in percent on perfect parry.
var/parry_efficiency_perfect = 120
-/obj/item
- /// Defense flags, see defines.
- var/defense_flags = NONE
- /// Our block parry data. Should be set in init, or something.
- var/datum/block_parry_data/block_parry_data
+/obj/item/proc/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
+ return
+ /// Yadda yadda WIP access block/parry data...
-/obj/item/Initialize(mapload)
- block_parry_data = get_block_parry_data(/datum/block_parry_data)
- return ..()
-
-/// This item can be used to parry. Only a basic check used to determine if we should proceed with parry chain at all.
-#define ITEM_DEFENSE_CAN_PARRY (1<<0)
-/// This item can be used in the directional blocking system. Only a basic check used to determine if we should proceed with directional block handling at all.
-#define ITEM_DEFENSE_CAN_BLOCK (1<<1)
-
+/obj/item/proc/active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!CHECK_BITFIELD(item_flags, ITEM_CAN_PARRY))
+ return
+ /// Yadda yadda WIP access block/parry data...
+/obj/item/proc/check_active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
+ return
+ /// Yadda yadda WIP access block/parry data...
/**
* Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index b7f32421aa..a18dcc6210 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -1646,7 +1646,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "pina_colada"
glass_name = "Pina Colada"
glass_desc = "If you like pina coladas, and getting caught in the rain... well, you'll like this drink."
-
+
/datum/reagent/consumable/ethanol/grasshopper
name = "Grasshopper"
description = "A fresh and sweet dessert shooter. Difficult to look manly while drinking this."
@@ -2354,7 +2354,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/hotlime_miami/on_mob_life(mob/living/carbon/M)
M.set_drugginess(50)
M.adjustStaminaLoss(-2)
- return ..()
+ return ..()
/datum/reagent/consumable/ethanol/fruit_wine
name = "Fruit Wine"
From b1a6d41b4f838b333298425f842290137b2f924c Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 10:58:15 -0700
Subject: [PATCH 09/96] dme
---
tgstation.dme | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/tgstation.dme b/tgstation.dme
index 593a6b3141..05bc4b848a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -47,7 +47,6 @@
#include "code\__DEFINES\events.dm"
#include "code\__DEFINES\exports.dm"
#include "code\__DEFINES\fantasy_affixes.dm"
-#include "code\__DEFINES\flags.dm"
#include "code\__DEFINES\food.dm"
#include "code\__DEFINES\footsteps.dm"
#include "code\__DEFINES\hud.dm"
@@ -75,7 +74,6 @@
#include "code\__DEFINES\movespeed_modification.dm"
#include "code\__DEFINES\nanites.dm"
#include "code\__DEFINES\networks.dm"
-#include "code\__DEFINES\obj_flags.dm"
#include "code\__DEFINES\pinpointers.dm"
#include "code\__DEFINES\pipe_construction.dm"
#include "code\__DEFINES\pool.dm"
@@ -117,10 +115,14 @@
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\wall_dents.dm"
#include "code\__DEFINES\wires.dm"
+#include "code\__DEFINES\combat\block.dm"
#include "code\__DEFINES\combat\block_parry.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals.dm"
+#include "code\__DEFINES\flags\flags.dm"
+#include "code\__DEFINES\flags\item_flags.dm"
+#include "code\__DEFINES\flags\obj_flags.dm"
#include "code\__HELPERS\_cit_helpers.dm"
#include "code\__HELPERS\_lists.dm"
#include "code\__HELPERS\_logging.dm"
From 92b809634b8426f621548fbb632e46fa5c8be8cc Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 11:32:18 -0700
Subject: [PATCH 10/96] k
---
code/__DEFINES/combat/block_parry.dm | 2 +-
code/modules/mob/living/carbon/human/human_block.dm | 4 ++--
code/modules/mob/living/living_block.dm | 2 +-
code/modules/mob/living/living_blocking_parrying.dm | 2 --
4 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/code/__DEFINES/combat/block_parry.dm b/code/__DEFINES/combat/block_parry.dm
index bfbce5f7d6..ad58c51039 100644
--- a/code/__DEFINES/combat/block_parry.dm
+++ b/code/__DEFINES/combat/block_parry.dm
@@ -1,7 +1,7 @@
// We can't determine things like NORTHEAST vs NORTH *and* EAST without making our own flags :(
#define BLOCK_DIR_NORTH (1<<0)
#define BLOCK_DIR_NORTHEAST (1<<1)
-#define BLCOK_DIR_NORTHWEST (1<<2)
+#define BLOCK_DIR_NORTHWEST (1<<2)
#define BLOCK_DIR_WEST (1<<3)
#define BLOCK_DIR_EAST (1<<4)
#define BLOCK_DIR_SOUTH (1<<5)
diff --git a/code/modules/mob/living/carbon/human/human_block.dm b/code/modules/mob/living/carbon/human/human_block.dm
index e95d932cc1..4ba7e95564 100644
--- a/code/modules/mob/living/carbon/human/human_block.dm
+++ b/code/modules/mob/living/carbon/human/human_block.dm
@@ -4,8 +4,8 @@
if(!.[wear_suit])
.[wear_suit] = wear_suit.block_priority
if(w_uniform)
- if(!.[wear_uniform])
- .[wear_uniform] = wear_uniform.block_priority
+ if(!.[w_uniform])
+ .[w_uniform] = w_uniform.block_priority
if(wear_neck)
if(!.[wear_neck])
.[wear_neck] = wear_neck.block_priority
diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm
index f8b62349e6..29cd7be888 100644
--- a/code/modules/mob/living/living_block.dm
+++ b/code/modules/mob/living/living_block.dm
@@ -71,10 +71,10 @@
else
for(var/obj/item/I in tocheck)
// i don't like this too
+ var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
if(I == active_block_item) //block is long termed enough we give a damn. parry, not so much.
I.check_active_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
else
- var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
I.check_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
/// Gets an unsortedlist of objects to run block checks on. List must have associative values for priorities!
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index cc6bae8054..412fe8ea82 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -27,8 +27,6 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/////////// BLOCKING ////////////
/// See defines.
var/can_block_directions = BLOCK_DIR_NORTH | BLOCK_DIR_NORTHEAST | BLOCK_DIR_NORTHWEST
- /// See defines.
- var/block_flags = BLOCK_FLAGS_DEFAULT
/// Our slowdown added while blocking
var/block_slowdown = 2
/// Clickdelay added to user after block ends
From 289d581e6652facc16f7bdc50466993ef3974b42 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 12:19:09 -0700
Subject: [PATCH 11/96] ok bet
---
code/__DEFINES/combat/block.dm | 8 +
code/__DEFINES/movespeed_modification.dm | 4 +-
code/__DEFINES/traits.dm | 4 +
code/_onclick/click.dm | 3 +
code/game/objects/items.dm | 2 +
code/modules/mob/inventory.dm | 1 +
.../modules/mob/living/living_active_block.dm | 143 ++++++++++++++++++
.../modules/mob/living/living_active_parry.dm | 0
code/modules/mob/living/living_block.dm | 23 ---
.../mob/living/living_blocking_parrying.dm | 66 ++------
code/modules/mob/mob.dm | 7 +
tgstation.dme | 2 +
12 files changed, 188 insertions(+), 75 deletions(-)
create mode 100644 code/modules/mob/living/living_active_block.dm
create mode 100644 code/modules/mob/living/living_active_parry.dm
diff --git a/code/__DEFINES/combat/block.dm b/code/__DEFINES/combat/block.dm
index d3c6d1e90e..0391656506 100644
--- a/code/__DEFINES/combat/block.dm
+++ b/code/__DEFINES/combat/block.dm
@@ -20,6 +20,8 @@
#define BLOCK_TARGET_DODGED (1<<7)
/// Meta-flag for run_block/do_run_block : By default, BLOCK_SUCCESS tells do_run_block() to assume the attack is completely blocked and not continue the block chain. If this is present, it will continue to check other items in the chain rather than stopping.
#define BLOCK_CONTINUE_CHAIN (1<<8)
+/// Attack should change the amount of damage incurred. This means something calling run_block() has to handle it!
+#define BLOCK_CHANGE_DAMAGE (1<<9)
/// For keys in associative list/block_return as we don't want to saturate our (somewhat) limited flags.
#define BLOCK_RETURN_REDIRECT_METHOD "REDIRECT_METHOD"
@@ -39,6 +41,12 @@
#define BLOCK_RETURN_NORMAL_BLOCK_CHANCE "normal_block_chance"
/// Tells the caller about how many hits we can soak on average before our blocking fails.
#define BLOCK_RETURN_BLOCK_CAPACITY "block_capacity"
+/// Tells the caller we got blocked by active directional block.
+#define BLOCK_RETURN_ACTIVE_BLOCK "active_block"
+/// Tells the caller our damage mitigation for their attack.
+#define BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED "damage_mitigated"
+/// For [BLOCK_CHANGE_DAMAGE]. Set damage to this.
+#define BLOCK_RETURN_SET_DAMAGE_TO "set_damage_to"
/// Default if the above isn't set in the list.
#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT
diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm
index 76c326cec0..0c073b85d7 100644
--- a/code/__DEFINES/movespeed_modification.dm
+++ b/code/__DEFINES/movespeed_modification.dm
@@ -78,4 +78,6 @@
#define MOVESPEED_ID_COLD "COLD"
#define MOVESPEED_ID_HUNGRY "HUNGRY"
#define MOVESPEED_ID_DAMAGE_SLOWDOWN "DAMAGE"
-#define MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING "FLYING"
\ No newline at end of file
+#define MOVESPEED_ID_DAMAGE_SLOWDOWN_FLYING "FLYING"
+
+#define MOVESPEED_ID_ACTIVE_BLOCK "ACTIVE_BLOCK"
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 4f4b7c6baa..a053db7575 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -278,3 +278,7 @@
#define CLOWNOP_TRAIT "clown-op"
#define MEGAFAUNA_TRAIT "megafauna"
#define DEATHSQUAD_TRAIT "deathsquad"
+/// This trait is added by the active directional block system.
+#define ACTIVE_BLOCK_TRAIT "active_block"
+/// This trait is added by the parry system.
+#define ACTIVE_PARRY_TRAIT "active_parry"
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index e8a57bb257..586758a279 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -17,6 +17,9 @@
// eg: 10*0.5 = 5 deciseconds of delay
// DOES NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
+/mob/proc/timeToNextMove()
+ return max(0, next_move - world.time)
+
/mob/proc/changeNext_move(num)
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 50a8273dbb..25ddefb817 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -367,6 +367,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return ITALICS | REDUCE_RANGE
/obj/item/proc/dropped(mob/user)
+ SHOULD_CALL_PARENT(TRUE)
for(var/X in actions)
var/datum/action/A = X
A.Remove(user)
@@ -378,6 +379,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
+ SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user)
item_flags |= IN_INVENTORY
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 9f7d2067de..1c518c251c 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -334,6 +334,7 @@
else
I.forceMove(newloc)
I.dropped(src)
+ on_item_dropped(I)
return TRUE
//Outdated but still in use apparently. This should at least be a human proc.
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
new file mode 100644
index 0000000000..9a67772ec8
--- /dev/null
+++ b/code/modules/mob/living/living_active_block.dm
@@ -0,0 +1,143 @@
+// Active directional block system. Shared code is in [living_blocking_parrying.dm]
+/mob/living
+ /// Whether or not the user is actively blocking.
+ var/active_blocking = FALSE
+ /// The item the user is actively blocking with.
+ var/obj/item/active_block_item
+
+/mob/living/on_item_dropped(obj/item/I)
+ if(I == active_block_item)
+ stop_active_blocking()
+ return ..()
+
+/mob/living/proc/stop_active_blocking()
+ active_blocking = FALSE
+ active_block_item = null
+ REMOVE_TRAIT(TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT)
+ remove_movespeed_modifier(MOVESPEED_ID_ACTIVE_BLOCK)
+ if(timeToNextMove() < I.block_parry_data.block_end_click_cd_add)
+ changeNext_move(I.block_parry_data.block_end_click_cd_add)
+ active_block_effect_end()
+ return TRUE
+
+/mob/living/proc/start_active_blocking(obj/item/I)
+ if(active_blocking)
+ return FALSE
+ if(!(I in held_items))
+ return FALSE
+ if(!istype(I.block_parry_data)) //Typecheck because if an admin/coder screws up varediting or something we do not want someone being broken forever, the CRASH logs feedback so we know what happened.
+ CRASH("start_active_blocking called with an item with no valid block_parry_data: [I.block_parry_data]!")
+ active_blocking = TRUE
+ active_block_item = I
+ if(I.block_parry_data.block_lock_attacking)
+ ADD_TRAIT(TRAIT_MOBILITY_NOMOVE, ACTIVE_BLOCK_TRAIT)
+ add_movespeed_modifier(MOVESPEED_ID_ACTIVE_BLOCK, TRUE, 100, override = TRUE, multiplicative_slowdown = I.block_parry_data.block_slowdown, blacklisted_movetypes = FLOATING)
+ active_block_effect_start()
+ return TRUE
+
+/// The amount of damage that is blocked.
+/obj/item/proc/active_block_damage_mitigation(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ var/absorption = block_damage_absorption_override[attack_type]
+ var/efficiency = block_damage_damage_multiplier_override[attack_type]
+ var/limit = block_damage_limit_override[attack_type]
+ // must use isnulls to handle 0's.
+ if(isnull(absorption))
+ absorption = block_damage_absorption
+ if(isnull(efficiency))
+ efficiency = block_damage_damage_multiplier
+ if(isnull(limit))
+ limit = block_damage_limit
+ // now we calculate damage to reduce.
+ var/final_damage = 0
+ // apply limit
+ if(damage > limit) //clamp and apply overrun
+ final_damage += (damage - limit)
+ damage = limit
+ // apply absorption
+ damage -= min(absorption, damage) //this way if damage is less than absorption it 0's properly.
+ // apply multiplier to remaining
+ final_damage += (damage * efficiency)
+ return final_damage
+
+/// Amount of stamina from damage blocked. Note that the damage argument is damage_blocked.
+/obj/item/proc/active_block_stamina_cost(mob/living/owner, atom/object, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ var/efficiency = block_stamina_efficiency_override[attack_type]
+ if(isnull(efficiency))
+ efficiency = block_stamina_efficiency
+ return damage_blocked / efficiency
+
+/// Apply the stamina damage to our user, notice how damage argument is stamina_amount.
+/obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ var/held_index = owner.get_held_index_of_item(src)
+ var/obj/item/bodypart/BP = owner.hand_bodyparts[held_index]
+ if(!BP?.body_zone)
+ return owner.adjustStaminaLossBuffered(stamina_amount) //nah
+ var/zone = BP.body_zone
+ var/stamina_to_zone = block_stamina_limb_ratio * stamina_amount
+ var/stamina_to_chest = stamina_amount - stamina_to_zone
+ var/stamina_buffered = stamina_to_chest * block_stamina_buffer_ratio
+ stamina_to_chest -= stamina_buffered
+ owner.apply_damage(stamina_to_zone, STAMINA, zone)
+ owner.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST)
+ owner.adjustStaminaLossBuffered(stamina_buffered)
+
+/obj/item/proc/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
+ return
+ if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
+ return
+ var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object))
+ if(!can_block_direction(owner.dir, incoming_direction))
+ return
+ block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE
+ var/damage_mitigated = active_block_damage_mitigation(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
+ var/final_damage = max(0, damage - damage_mitigated)
+ var/stamina_cost = active_block_stamina_cost(owner, object, final_damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
+ active_block_do_stamina_damage(owner, object, stamina_cost, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
+ block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED] = damage_mitigated
+ block_return[BLOCK_RETURN_SET_DAMAGE_TO] = final_damage
+ . = BLOCK_CHANGE_DAMAGE
+ if(final_damage <= 0)
+ . |= BLOCK_SUCCESS //full block
+
+/obj/item/proc/check_active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
+ return
+ var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object))
+ if(!can_block_direction(owner.dir, incoming_direction))
+ return
+ block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE
+ block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATION] = active_block_damage_mitigation(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
+
+/**
+ * Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
+ */
+/obj/item/proc/blockable_directions()
+ return block_parry_data.can_block_directions
+
+/**
+ * Checks if we can block from a specific direction from our direction.
+ *
+ * @params
+ * * our_dir - our direction.
+ * * their_dir - their direction. Must be a single direction, or NONE for an attack from the same tile.
+ */
+/obj/item/proc/can_block_direction(our_dir, their_dir)
+ if(our_dir != NORTH)
+ var/turn_angle = dir2angle(our_dir)
+ // dir2angle(), ss13 proc is clockwise so dir2angle(EAST) == 90
+ // turn(), byond proc is counterclockwise so turn(NORTH, 90) == WEST
+ their_dir = turn(their_dir, turn_angle)
+ return (DIR2BLOCKDIR(their_dir) in blockable_directions())
+
+/**
+ * can_block_direction but for "compound" directions to check all of them and return the number of directions that were blocked.
+ *
+ * @params
+ * * our_dir - our direction.
+ * * their_dirs - list of their directions as we cannot use bitfields here.
+ */
+/obj/item/proc/can_block_directions_multiple(our_dir, list/their_dirs)
+ . = FALSE
+ for(var/i in their_dirs)
+ . |= can_block_direction(our_dir, i)
diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm
index 29cd7be888..dea23435b2 100644
--- a/code/modules/mob/living/living_block.dm
+++ b/code/modules/mob/living/living_block.dm
@@ -1,28 +1,5 @@
// This file has a weird name, but it's for anything related to the checks for shields, blocking, dodging, and similar "stop this attack before it actually impacts the target" as opposed to "defend once it has hit".
-/*
-/// Bitflags for check_block() and handle_block(). Meant to be combined. You can be hit and still reflect, for example, if you do not use BLOCK_SUCCESS.
-/// Attack was not blocked
-#define BLOCK_NONE NONE
-/// Attack was blocked, do not do damage. THIS FLAG MUST BE THERE FOR DAMAGE/EFFECT PREVENTION!
-#define BLOCK_SUCCESS (1<<1)
-
-/// The below are for "metadata" on "how" the attack was blocked.
-
-/// Attack was and should be reflected (NOTE: the SHOULD here is important, as it says "the thing blocking isn't handling the reflecting for you so do it yourself"!)
-#define BLOCK_SHOULD_REFLECT (1<<2)
-/// Attack was manually redirected (including reflected) by any means by the defender. For when YOU are handling the reflection, rather than the thing hitting you. (see sleeping carp)
-#define BLOCK_REDIRECTED (1<<3)
-/// Attack was blocked by something like a shield.
-#define BLOCK_PHYSICAL_EXTERNAL (1<<4)
-/// Attack was blocked by something worn on you.
-#define BLOCK_PHYSICAL_INTERNAL (1<<5)
-/// Attack should pass through. Like SHOULD_REFLECT but for.. well, passing through harmlessly.
-#define BLOCK_SHOULD_PASSTHROUGH (1<<6)
-/// Attack outright missed because the target dodged. Should usually be combined with SHOULD_PASSTHROUGH or something (see martial arts)
-#define BLOCK_TARGET_DODGED (1<<7)
-*/
-
///Check whether or not we can block, without "triggering" a block. Basically run checks without effects like depleting shields. Wrapper for do_run_block(). The arguments on that means the same as for this.
/mob/living/proc/check_block(atom/object, damage, attack_text = "the attack", attack_type, armour_penetration, mob/attacker, def_zone, list/return_list)
return do_run_block(FALSE, object, damage, attack_text, attack_type, armour_penetration, attacker, check_zone(def_zone), return_list)
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 412fe8ea82..4e42d2383c 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -1,11 +1,12 @@
// yell at me later for file naming
// This file contains stuff relating to the new directional blocking and parry system.
/mob/living
- var/obj/item/active_block_item
- var/obj/item/active_parry_item
+ /// Whether ot not the user is in the middle of an active parry.
var/parrying = FALSE
- var/parry_frame = 0
-
+ /// The itme the user is currently parrying with.
+ var/obj/item/active_parry_item
+ /// world.time of parry action start
+ var/parry_start_time = 0
GLOBAL_LIST_EMPTY(block_parry_data)
@@ -51,17 +52,23 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Override upper bound of damage block, list(ATTACK_TYPE_DEFINE = absorption), see [block_damage_limit]
var/list/block_damage_limit_override
+ /*
+ * NOTE: Overrides for attack types for most the block_stamina variables were removed,
+ * because at the time of writing nothing needed to use it. Add them if you need it,
+ * it should be pretty easy, just copy [active_block_damage_mitigation]
+ * for how to override with list.
+ */
+
/// Default damage-to-stamina coefficient, higher is better. This is based on amount of damage BLOCKED, not initial damage, to prevent damage from "double dipping".
var/block_stamina_efficiency = 2
/// Override damage-to-stamina coefficient, see [block_efficiency], this should be list(ATTACK_TYPE_DEFINE = coefficient_number)
var/list/block_stamina_efficiency_override
-
/// Ratio of stamina incurred by blocking that goes to the arm holding the object instead of the chest. Has no effect if this is not held in hand.
var/block_stamina_limb_ratio = 0.5
- /// Override stamina limb ratio, list(ATTACK_TYPE_DEFINE = absorption), see [block_stamina_limb_ratio]
- var/list/block_stamina_limb_ratio_override
+ /// Ratio of stamina incurred by chest (so after [block_stamina_limb_ratio] runs) that is buffered.
+ var/block_stamina_buffer_ratio = 1
- /// Stamina dealt directly via adjustStaminaLoss() per SECOND of block.
+ /// Stamina dealt directly via adjustStaminaLossBuffered() per SECOND of block.
var/block_stamina_cost_per_second = 1.5
/////////// PARRYING ////////////
@@ -86,52 +93,9 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Efficiency in percent on perfect parry.
var/parry_efficiency_perfect = 120
-
-
-/obj/item/proc/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
- return
- /// Yadda yadda WIP access block/parry data...
-
/obj/item/proc/active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_PARRY))
return
/// Yadda yadda WIP access block/parry data...
-/obj/item/proc/check_active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
- return
- /// Yadda yadda WIP access block/parry data...
-/**
- * Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
- */
-/obj/item/proc/blockable_directions()
- return block_parry_data.can_block_directions
-
-/**
- * Checks if we can block from a specific direction from our direction.
- *
- * @params
- * * our_dir - our direction.
- * * their_dir - their direction. Must be a single direction, or NONE for an attack from the same tile.
- */
-/obj/item/proc/can_block_direction(our_dir, their_dir)
- if(our_dir != NORTH)
- var/turn_angle = dir2angle(our_dir)
- // dir2angle(), ss13 proc is clockwise so dir2angle(EAST) == 90
- // turn(), byond proc is counterclockwise so turn(NORTH, 90) == WEST
- their_dir = turn(their_dir, turn_angle)
- return (DIR2BLOCKDIR(their_dir) in blockable_directions())
-
-/**
- * can_block_direction but for "compound" directions to check all of them and return the number of directions that were blocked.
- *
- * @params
- * * our_dir - our direction.
- * * their_dirs - list of their directions as we cannot use bitfields here.
- */
-/obj/item/proc/can_block_directions_multiple(our_dir, list/their_dirs)
- . = FALSE
- for(var/i in their_dirs)
- . |= can_block_direction(our_dir, i)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 5225534cee..83845801cf 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1000,3 +1000,10 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
for(var/obj/item/I in held_items)
if(I.item_flags & SLOWS_WHILE_IN_HAND)
. += I.slowdown
+
+/**
+ * Mostly called by doUnEquip()
+ * Like item dropped() on mob side.
+ */
+/mob/proc/on_item_dropped(obj/item/I)
+ return
diff --git a/tgstation.dme b/tgstation.dme
index 05bc4b848a..89200716a5 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2207,6 +2207,8 @@
#include "code\modules\mob\living\emote.dm"
#include "code\modules\mob\living\life.dm"
#include "code\modules\mob\living\living.dm"
+#include "code\modules\mob\living\living_active_block.dm"
+#include "code\modules\mob\living\living_active_parry.dm"
#include "code\modules\mob\living\living_block.dm"
#include "code\modules\mob\living\living_blocking_parrying.dm"
#include "code\modules\mob\living\living_combat.dm"
From 2fd129b74be7b13054febaa1a1cf143d26762d7a Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 12:19:26 -0700
Subject: [PATCH 12/96] macros
---
code/modules/mob/living/living_active_block.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 9a67772ec8..e3cb3b0314 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -13,7 +13,7 @@
/mob/living/proc/stop_active_blocking()
active_blocking = FALSE
active_block_item = null
- REMOVE_TRAIT(TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT)
remove_movespeed_modifier(MOVESPEED_ID_ACTIVE_BLOCK)
if(timeToNextMove() < I.block_parry_data.block_end_click_cd_add)
changeNext_move(I.block_parry_data.block_end_click_cd_add)
@@ -30,7 +30,7 @@
active_blocking = TRUE
active_block_item = I
if(I.block_parry_data.block_lock_attacking)
- ADD_TRAIT(TRAIT_MOBILITY_NOMOVE, ACTIVE_BLOCK_TRAIT)
+ ADD_TRAIT(src, TRAIT_MOBILITY_NOMOVE, ACTIVE_BLOCK_TRAIT)
add_movespeed_modifier(MOVESPEED_ID_ACTIVE_BLOCK, TRUE, 100, override = TRUE, multiplicative_slowdown = I.block_parry_data.block_slowdown, blacklisted_movetypes = FLOATING)
active_block_effect_start()
return TRUE
From 555702c1d7ca1f7cb36923d74784c14e98ef37e6 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 12:28:05 -0700
Subject: [PATCH 13/96] flag define precedence
---
.../{flags/flags.dm => _flags/_flags.dm} | 0
.../__DEFINES/{flags => _flags}/item_flags.dm | 0
code/__DEFINES/{flags => _flags}/obj_flags.dm | 0
.../modules/mob/living/living_active_block.dm | 51 ++++++++++---------
tgstation.dme | 6 +--
5 files changed, 31 insertions(+), 26 deletions(-)
rename code/__DEFINES/{flags/flags.dm => _flags/_flags.dm} (100%)
rename code/__DEFINES/{flags => _flags}/item_flags.dm (100%)
rename code/__DEFINES/{flags => _flags}/obj_flags.dm (100%)
diff --git a/code/__DEFINES/flags/flags.dm b/code/__DEFINES/_flags/_flags.dm
similarity index 100%
rename from code/__DEFINES/flags/flags.dm
rename to code/__DEFINES/_flags/_flags.dm
diff --git a/code/__DEFINES/flags/item_flags.dm b/code/__DEFINES/_flags/item_flags.dm
similarity index 100%
rename from code/__DEFINES/flags/item_flags.dm
rename to code/__DEFINES/_flags/item_flags.dm
diff --git a/code/__DEFINES/flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm
similarity index 100%
rename from code/__DEFINES/flags/obj_flags.dm
rename to code/__DEFINES/_flags/obj_flags.dm
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index e3cb3b0314..5c6102a1a1 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -11,6 +11,7 @@
return ..()
/mob/living/proc/stop_active_blocking()
+ var/obj/item/I = active_block_item
active_blocking = FALSE
active_block_item = null
REMOVE_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT)
@@ -37,16 +38,16 @@
/// The amount of damage that is blocked.
/obj/item/proc/active_block_damage_mitigation(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/absorption = block_damage_absorption_override[attack_type]
- var/efficiency = block_damage_damage_multiplier_override[attack_type]
- var/limit = block_damage_limit_override[attack_type]
+ var/absorption = block_parry_data.block_damage_absorption_override[attack_type]
+ var/efficiency = block_parry_data.block_damage_multiplier_override[attack_type]
+ var/limit = block_parry_data.block_damage_limit_override[attack_type]
// must use isnulls to handle 0's.
if(isnull(absorption))
- absorption = block_damage_absorption
+ absorption = block_parry_data.block_damage_absorption
if(isnull(efficiency))
- efficiency = block_damage_damage_multiplier
+ efficiency = block_parry_data.block_damage_damage_multiplier
if(isnull(limit))
- limit = block_damage_limit
+ limit = block_parry_data.block_damage_limit
// now we calculate damage to reduce.
var/final_damage = 0
// apply limit
@@ -61,32 +62,36 @@
/// Amount of stamina from damage blocked. Note that the damage argument is damage_blocked.
/obj/item/proc/active_block_stamina_cost(mob/living/owner, atom/object, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/efficiency = block_stamina_efficiency_override[attack_type]
+ var/efficiency = block_parry_data.block_stamina_efficiency_override[attack_type]
if(isnull(efficiency))
- efficiency = block_stamina_efficiency
+ efficiency = block_parry_data.block_stamina_efficiency
return damage_blocked / efficiency
/// Apply the stamina damage to our user, notice how damage argument is stamina_amount.
/obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/held_index = owner.get_held_index_of_item(src)
- var/obj/item/bodypart/BP = owner.hand_bodyparts[held_index]
- if(!BP?.body_zone)
- return owner.adjustStaminaLossBuffered(stamina_amount) //nah
- var/zone = BP.body_zone
- var/stamina_to_zone = block_stamina_limb_ratio * stamina_amount
- var/stamina_to_chest = stamina_amount - stamina_to_zone
- var/stamina_buffered = stamina_to_chest * block_stamina_buffer_ratio
- stamina_to_chest -= stamina_buffered
- owner.apply_damage(stamina_to_zone, STAMINA, zone)
- owner.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST)
- owner.adjustStaminaLossBuffered(stamina_buffered)
+ if(iscarbon(owner))
+ var/mob/living/carbon/C = owner
+ var/held_index = C.get_held_index_of_item(src)
+ var/obj/item/bodypart/BP = C.hand_bodyparts[held_index]
+ if(!BP?.body_zone)
+ return C.adjustStaminaLossBuffered(stamina_amount) //nah
+ var/zone = BP.body_zone
+ var/stamina_to_zone = block_parry_data.block_stamina_limb_ratio * stamina_amount
+ var/stamina_to_chest = stamina_amount - stamina_to_zone
+ var/stamina_buffered = stamina_to_chest * block_parry_data.block_stamina_buffer_ratio
+ stamina_to_chest -= stamina_buffered
+ C.apply_damage(stamina_to_zone, STAMINA, zone)
+ C.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST)
+ C.adjustStaminaLossBuffered(stamina_buffered)
+ else
+ owner.adjustStaminaLossBuffered(stamina_amount)
/obj/item/proc/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
return
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
return
- var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object))
+ var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object), src)
if(!can_block_direction(owner.dir, incoming_direction))
return
block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE
@@ -103,11 +108,11 @@
/obj/item/proc/check_active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
return
- var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object))
+ var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object), src)
if(!can_block_direction(owner.dir, incoming_direction))
return
block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE
- block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATION] = active_block_damage_mitigation(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
+ block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED] = active_block_damage_mitigation(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
/**
* Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
diff --git a/tgstation.dme b/tgstation.dme
index 89200716a5..3a055f026a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -115,14 +115,14 @@
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\wall_dents.dm"
#include "code\__DEFINES\wires.dm"
+#include "code\__DEFINES\_flags\_flags.dm"
+#include "code\__DEFINES\_flags\item_flags.dm"
+#include "code\__DEFINES\_flags\obj_flags.dm"
#include "code\__DEFINES\combat\block.dm"
#include "code\__DEFINES\combat\block_parry.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals.dm"
-#include "code\__DEFINES\flags\flags.dm"
-#include "code\__DEFINES\flags\item_flags.dm"
-#include "code\__DEFINES\flags\obj_flags.dm"
#include "code\__HELPERS\_cit_helpers.dm"
#include "code\__HELPERS\_lists.dm"
#include "code\__HELPERS\_logging.dm"
From 940cdd13b0abaeeb898521dad6a6e6e44be8023b Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 12:29:43 -0700
Subject: [PATCH 14/96] compile
---
code/modules/mob/living/living_active_block.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 5c6102a1a1..51ba75755d 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -45,7 +45,7 @@
if(isnull(absorption))
absorption = block_parry_data.block_damage_absorption
if(isnull(efficiency))
- efficiency = block_parry_data.block_damage_damage_multiplier
+ efficiency = block_parry_data.block_damage_multiplier
if(isnull(limit))
limit = block_parry_data.block_damage_limit
// now we calculate damage to reduce.
From 4391fc3714f03d6b9088905db5f05556885f1aa8 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 12:51:17 -0700
Subject: [PATCH 15/96] pixel shifting
---
.../living/carbon/alien/humanoid/humanoid.dm | 18 +++++++-------
code/modules/mob/living/carbon/carbon.dm | 5 ++--
.../modules/mob/living/living_active_block.dm | 24 ++++++++++++++++++-
3 files changed, 33 insertions(+), 14 deletions(-)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index 048b5062ec..a3b801f4b9 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -76,20 +76,18 @@
return TRUE
/mob/living/carbon/alien/humanoid/get_standard_pixel_y_offset(lying = 0)
+ . = ..()
if(leaping)
- return -32
- else if(custom_pixel_y_offset)
- return custom_pixel_y_offset
- else
- return initial(pixel_y)
+ . -= 32
+ if(custom_pixel_y_offset)
+ . += custom_pixel_y_offset
/mob/living/carbon/alien/humanoid/get_standard_pixel_x_offset(lying = 0)
+ . = ..()
if(leaping)
- return -32
- else if(custom_pixel_x_offset)
- return custom_pixel_x_offset
- else
- return initial(pixel_x)
+ . -= 32
+ if(custom_pixel_x_offset)
+ . += custom_pixel_x_offset
/mob/living/carbon/alien/humanoid/get_permeability_protection(list/target_zones)
return 0.8
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 938f6531f1..f9630e4c66 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -431,10 +431,9 @@
return TRUE
/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
+ . = ..()
if(lying)
- return -6
- else
- return initial(pixel_y)
+ . -= 6
/mob/living/carbon/proc/accident(obj/item/I)
if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 51ba75755d..90f77b13ff 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -2,7 +2,7 @@
/mob/living
/// Whether or not the user is actively blocking.
var/active_blocking = FALSE
- /// The item the user is actively blocking with.
+ /// The item the user is actively blocking with if any.
var/obj/item/active_block_item
/mob/living/on_item_dropped(obj/item/I)
@@ -36,6 +36,28 @@
active_block_effect_start()
return TRUE
+/// Visual effect setup for starting a directional block
+/mob/living/proc/active_block_effect_start()
+
+/// Visual effect cleanup for starting a directional block
+/mob/living/proc/active_block_effect_end()
+
+/mob/living/get_standard_pixel_x_offset()
+ . = ..()
+ if(active_blocking)
+ if(dir & EAST)
+ . += 12
+ if(dir & WEST)
+ . -= 12
+
+/mob/living/get_standard_pixel_y_offset()
+ . = ..()
+ if(active_blocking)
+ if(dir & NORTH)
+ . += 12
+ if(dir & SOUTH)
+ . -= 12
+
/// The amount of damage that is blocked.
/obj/item/proc/active_block_damage_mitigation(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
var/absorption = block_parry_data.block_damage_absorption_override[attack_type]
From 135ca27281b263bcf8123b9dea62f2161725542c Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 13:08:05 -0700
Subject: [PATCH 16/96] parry
---
code/__DEFINES/combat/block.dm | 1 -
code/__DEFINES/combat/block_parry.dm | 10 ++++++
code/datums/martial/_martial.dm | 4 +++
.../modules/mob/living/living_active_block.dm | 3 ++
code/modules/mob/living/living_block.dm | 5 +--
.../mob/living/living_blocking_parrying.dm | 34 +++++++++++++++----
6 files changed, 48 insertions(+), 9 deletions(-)
diff --git a/code/__DEFINES/combat/block.dm b/code/__DEFINES/combat/block.dm
index 0391656506..2877d983f3 100644
--- a/code/__DEFINES/combat/block.dm
+++ b/code/__DEFINES/combat/block.dm
@@ -53,7 +53,6 @@
/// Block priorities. Higher means it's checked sooner.
// THESE MUST NEVER BE 0! Block code uses ! instead of isnull for the speed boost.
-#define BLOCK_PRIORITY_ACTIVE_PARRY 300
#define BLOCK_PRIORITY_ACTIVE_BLOCK 200
#define BLOCK_PRIORITY_HELD_ITEM 100
#define BLOCK_PRIORITY_CLOTHING 50
diff --git a/code/__DEFINES/combat/block_parry.dm b/code/__DEFINES/combat/block_parry.dm
index ad58c51039..730d3da8e9 100644
--- a/code/__DEFINES/combat/block_parry.dm
+++ b/code/__DEFINES/combat/block_parry.dm
@@ -22,3 +22,13 @@ GLOBAL_LIST_INIT(dir2blockdir, list(
))
#define DIR2BLOCKDIR(d) (GLOB.dir2blockdir["[d]"])
+
+/// ""types"" of parry "items"
+#define UNARMED_PARRY "unarmed"
+#define MARTIAL_PARRY "martial"
+#define ITEM_PARRY "item"
+
+/// Parry phase we're in
+#define PARRY_WINDUP "windup"
+#define PARRY_ACTIVE "main"
+#define PARRY_SPINDOWN "spindown"
diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm
index 7b7975bedb..0b5caaa414 100644
--- a/code/datums/martial/_martial.dm
+++ b/code/datums/martial/_martial.dm
@@ -10,6 +10,10 @@
var/help_verb
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
+ /// Can we be used to unarmed parry?
+ var/can_martial_parry = FALSE
+ /// Set this variable to something not null, this'll be the preferred unarmed parry in most cases if [can_martial_parry] is TRUE.
+ var/datum/block_parry_data/block_parry_data
/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
return FALSE
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 90f77b13ff..5a3aeb2387 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -126,6 +126,9 @@
. = BLOCK_CHANGE_DAMAGE
if(final_damage <= 0)
. |= BLOCK_SUCCESS //full block
+ owner.visible_message("[owner] blocks \the [attack_text] with [src]!")
+ else
+ owner.visible_message("[owner] dampens \the [attack_text] with [src]!")
/obj/item/proc/check_active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm
index dea23435b2..5e60285d04 100644
--- a/code/modules/mob/living/living_block.dm
+++ b/code/modules/mob/living/living_block.dm
@@ -23,6 +23,9 @@
* return_list - If something wants to grab things from what items/whatever put into list/block_return on obj/item/run_block and the comsig, pass in a list so you can grab anything put in it after block runs.
*/
/mob/living/proc/do_run_block(real_attack = TRUE, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
+ . = run_parry(real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) //Parry - Highest priority!
+ if((. & BLOCK_SUCCESS) && !(. & BLOCK_CONTINUE_CHAIN))
+ return
// Component signal block runs have highest priority.. for now.
. = SEND_SIGNAL(src, COMSIG_LIVING_RUN_BLOCK, real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)
if((. & BLOCK_SUCCESS) && !(. & BLOCK_CONTINUE_CHAIN))
@@ -59,8 +62,6 @@
. = list()
if(active_block_item)
.[active_block_item] = active_block_item.block_parry_data.block_active_priority
- if(active_parry_item)
- .[active_parry_item] = active_parry_item.block_parry_data.parry_active_priority
for(var/obj/item/I in held_items)
// this is a bad check but i am not removing it until a better catchall is made
if(istype(I, /obj/item/clothing))
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 4e42d2383c..5d100f9280 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -1,12 +1,18 @@
// yell at me later for file naming
// This file contains stuff relating to the new directional blocking and parry system.
/mob/living
- /// Whether ot not the user is in the middle of an active parry.
+ /// Whether ot not the user is in the middle of an active parry. Set to [UNARMED_PARRY], [ITEM_PARRY], [MARTIAL_PARRY] if parrying.
var/parrying = FALSE
- /// The itme the user is currently parrying with.
+ /// The itme the user is currently parrying with, if any.
var/obj/item/active_parry_item
/// world.time of parry action start
var/parry_start_time = 0
+ /// Whether or not we can unarmed parry
+ var/parry_while_unarmed = FALSE
+ /// Should we prioritize martial art parrying when unarmed?
+ var/parry_prioritize_martial = TRUE
+ /// Our block_parry_data for unarmed blocks/parries. Currently only used for parrying, as unarmed block isn't implemented yet.
+ var/datum/block_parry_data/block_parry_data
GLOBAL_LIST_EMPTY(block_parry_data)
@@ -73,11 +79,12 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/////////// PARRYING ////////////
/// Prioriry for [mob/do_run_block()] while we're being used to parry.
- var/parry_active_priority = BLOCK_PRIORITY_ACTIVE_PARRY
+ // None - Parry is always highest priority!
+
/// Parry windup duration in deciseconds
var/parry_time_windup = 2
- /// Parry spooldown duration in deciseconds
- var/parry_time_spooldown = 3
+ /// Parry spindown duration in deciseconds
+ var/parry_time_spindown = 3
/// Main parry window in deciseconds
var/parry_time_active = 5
/// Perfect parry window in deciseconds from the main window. 3 with main 5 = perfect on third decisecond of main window.
@@ -87,7 +94,7 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// [parry_time_perfect_leeway] override for attack types, list(ATTACK_TYPE_DEFINE = deciseconds)
var/list/parry_time_perfect_leeway_override
/// Parry "efficiency" falloff in percent per decisecond once perfect window is over.
- var/parry_imperfect_falloff_percent = 20
+ var/parry_time_imperfect_falloff_percent = 20
/// [parry_imperfect_falloff_percent] override for attack types, list(ATTACK_TYPE_DEFINE = deciseconds)
var/list/parry_time_imperfect_falloff_percent_override
/// Efficiency in percent on perfect parry.
@@ -98,4 +105,19 @@ GLOBAL_LIST_EMPTY(block_parry_data)
return
/// Yadda yadda WIP access block/parry data...
+/// same return values as normal blocking, called with absolute highest priority in the block "chain".
+/mob/living/proc/run_parry(real_attack = TRUE, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
+
+/// Gets the datum/block_parry_data we're going to use to parry.
+/mob/living/proc/get_parry_data()
+ if(parrying == ITEM_PARRY)
+ return active_parry_item.block_parry_data
+ else if(parrying == UNARMED_PARRY)
+ return block_parry_data
+ else if(parrying == MARTIAL_PARRY)
+ return mind.martial_art.block_parry_data
+
+#define UNARMED_PARRY
+#define MARTIAL_PARRY
+#define ITEM_PARRY
From 8fe064da747814f8682491786283d1aa143b8530 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 14:13:18 -0700
Subject: [PATCH 17/96] save memory..
---
code/__DEFINES/combat/block_parry.dm | 23 +++++-
code/datums/martial/_martial.dm | 2 +-
code/game/objects/items.dm | 1 +
.../modules/mob/living/living_active_block.dm | 40 +++++-----
.../mob/living/living_blocking_parrying.dm | 75 ++++++++++++++-----
5 files changed, 101 insertions(+), 40 deletions(-)
diff --git a/code/__DEFINES/combat/block_parry.dm b/code/__DEFINES/combat/block_parry.dm
index 730d3da8e9..87e9fed8ff 100644
--- a/code/__DEFINES/combat/block_parry.dm
+++ b/code/__DEFINES/combat/block_parry.dm
@@ -29,6 +29,23 @@ GLOBAL_LIST_INIT(dir2blockdir, list(
#define ITEM_PARRY "item"
/// Parry phase we're in
-#define PARRY_WINDUP "windup"
-#define PARRY_ACTIVE "main"
-#define PARRY_SPINDOWN "spindown"
+#define NOT_PARRYING 0
+#define PARRY_WINDUP 1
+#define PARRY_ACTIVE 2
+#define PARRY_SPINDOWN 3
+
+/// Parry effects.
+/// List association must be one of the things underneath
+#define PARRY_REFLEX_COUNTERATTACK "reflex_counter"
+ // Uses active_parry_reflex_counter() on the mob (if unarmed)/item/martial art used to parry.
+ #define PARRY_COUNTERATTACK_PROC "proc"
+ // Automatically melee attacks back normally, LMB equivalent action of an harm intent attack.
+ #define PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN "default"
+/// No list association
+#define PARRY_DISARM_ATTACKER "disarm_attacker"
+/// List association should be duration or null for just plain knockdown.
+#define PARRY_KNOCKDOWN_ATTACKER "knockdown_attacker"
+/// List association should be duration.
+#define PARRY_STAGGER_ATTACKER "stagger_attacker"
+/// List association should be amount to increase clickcd of attacker to.
+#define PARRY_CLICKCD_ATTACKER "clickcd_attacker"
diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm
index 0b5caaa414..9dbe106ee3 100644
--- a/code/datums/martial/_martial.dm
+++ b/code/datums/martial/_martial.dm
@@ -12,7 +12,7 @@
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
/// Can we be used to unarmed parry?
var/can_martial_parry = FALSE
- /// Set this variable to something not null, this'll be the preferred unarmed parry in most cases if [can_martial_parry] is TRUE.
+ /// Set this variable to something not null, this'll be the preferred unarmed parry in most cases if [can_martial_parry] is TRUE. YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
var/datum/block_parry_data/block_parry_data
/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 25ddefb817..5814fe71d5 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -110,6 +110,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/* Our block parry data. Should be set in init, or something if you are using it.
* This won't be accessed without ITEM_CAN_BLOCK or ITEM_CAN_PARRY so do not set it unless you have to to save memory.
* If you decide it's a good idea to leave this unset while turning the flags on, you will runtime. Enjoy.
+ * If this is set to a path, it'll run get_block_parry_data(path). YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
*/
var/datum/block_parry_data/block_parry_data
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 5a3aeb2387..d96e6fb10a 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -16,8 +16,9 @@
active_block_item = null
REMOVE_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT)
remove_movespeed_modifier(MOVESPEED_ID_ACTIVE_BLOCK)
- if(timeToNextMove() < I.block_parry_data.block_end_click_cd_add)
- changeNext_move(I.block_parry_data.block_end_click_cd_add)
+ var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ if(timeToNextMove() < I.data.block_end_click_cd_add)
+ changeNext_move(I.data.block_end_click_cd_add)
active_block_effect_end()
return TRUE
@@ -26,13 +27,14 @@
return FALSE
if(!(I in held_items))
return FALSE
- if(!istype(I.block_parry_data)) //Typecheck because if an admin/coder screws up varediting or something we do not want someone being broken forever, the CRASH logs feedback so we know what happened.
- CRASH("start_active_blocking called with an item with no valid block_parry_data: [I.block_parry_data]!")
+ var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ if(!istype(I.data)) //Typecheck because if an admin/coder screws up varediting or something we do not want someone being broken forever, the CRASH logs feedback so we know what happened.
+ CRASH("start_active_blocking called with an item with no valid data: [I.data]!")
active_blocking = TRUE
active_block_item = I
- if(I.block_parry_data.block_lock_attacking)
+ if(I.data.block_lock_attacking)
ADD_TRAIT(src, TRAIT_MOBILITY_NOMOVE, ACTIVE_BLOCK_TRAIT)
- add_movespeed_modifier(MOVESPEED_ID_ACTIVE_BLOCK, TRUE, 100, override = TRUE, multiplicative_slowdown = I.block_parry_data.block_slowdown, blacklisted_movetypes = FLOATING)
+ add_movespeed_modifier(MOVESPEED_ID_ACTIVE_BLOCK, TRUE, 100, override = TRUE, multiplicative_slowdown = I.data.block_slowdown, blacklisted_movetypes = FLOATING)
active_block_effect_start()
return TRUE
@@ -60,16 +62,17 @@
/// The amount of damage that is blocked.
/obj/item/proc/active_block_damage_mitigation(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/absorption = block_parry_data.block_damage_absorption_override[attack_type]
- var/efficiency = block_parry_data.block_damage_multiplier_override[attack_type]
- var/limit = block_parry_data.block_damage_limit_override[attack_type]
+ var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ var/absorption = data.block_damage_absorption_override[attack_type]
+ var/efficiency = data.block_damage_multiplier_override[attack_type]
+ var/limit = data.block_damage_limit_override[attack_type]
// must use isnulls to handle 0's.
if(isnull(absorption))
- absorption = block_parry_data.block_damage_absorption
+ absorption = data.block_damage_absorption
if(isnull(efficiency))
- efficiency = block_parry_data.block_damage_multiplier
+ efficiency = data.block_damage_multiplier
if(isnull(limit))
- limit = block_parry_data.block_damage_limit
+ limit = data.block_damage_limit
// now we calculate damage to reduce.
var/final_damage = 0
// apply limit
@@ -84,13 +87,15 @@
/// Amount of stamina from damage blocked. Note that the damage argument is damage_blocked.
/obj/item/proc/active_block_stamina_cost(mob/living/owner, atom/object, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/efficiency = block_parry_data.block_stamina_efficiency_override[attack_type]
+ var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ var/efficiency = data.block_stamina_efficiency_override[attack_type]
if(isnull(efficiency))
- efficiency = block_parry_data.block_stamina_efficiency
+ efficiency = data.block_stamina_efficiency
return damage_blocked / efficiency
/// Apply the stamina damage to our user, notice how damage argument is stamina_amount.
/obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
if(iscarbon(owner))
var/mob/living/carbon/C = owner
var/held_index = C.get_held_index_of_item(src)
@@ -98,9 +103,9 @@
if(!BP?.body_zone)
return C.adjustStaminaLossBuffered(stamina_amount) //nah
var/zone = BP.body_zone
- var/stamina_to_zone = block_parry_data.block_stamina_limb_ratio * stamina_amount
+ var/stamina_to_zone = data.block_stamina_limb_ratio * stamina_amount
var/stamina_to_chest = stamina_amount - stamina_to_zone
- var/stamina_buffered = stamina_to_chest * block_parry_data.block_stamina_buffer_ratio
+ var/stamina_buffered = stamina_to_chest * data.block_stamina_buffer_ratio
stamina_to_chest -= stamina_buffered
C.apply_damage(stamina_to_zone, STAMINA, zone)
C.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST)
@@ -143,7 +148,8 @@
* Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
*/
/obj/item/proc/blockable_directions()
- return block_parry_data.can_block_directions
+ var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ return data.can_block_directions
/**
* Checks if we can block from a specific direction from our direction.
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 5d100f9280..99903485f0 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -11,18 +11,20 @@
var/parry_while_unarmed = FALSE
/// Should we prioritize martial art parrying when unarmed?
var/parry_prioritize_martial = TRUE
- /// Our block_parry_data for unarmed blocks/parries. Currently only used for parrying, as unarmed block isn't implemented yet.
+ /// Our block_parry_data for unarmed blocks/parries. Currently only used for parrying, as unarmed block isn't implemented yet. YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
var/datum/block_parry_data/block_parry_data
GLOBAL_LIST_EMPTY(block_parry_data)
-/proc/get_block_parry_data(type_or_id)
- if(ispath(type_or_id))
- . = GLOB.block_parry_data["[type_or_id]"]
+/proc/get_block_parry_data(datum/block_parry_data/type_id_datum)
+ if(istype(type_id_datum))
+ return type_id_datum
+ if(ispath(type_id_datum))
+ . = GLOB.block_parry_data["[type_id_datum]"]
if(!.)
- . = GLOB.block_parry_data["[type_or_id]"] = new type_or_id
+ . = GLOB.block_parry_data["[type_id_datum]"] = new type_id_datum
else //text id
- return GLOB.block_parry_data["[type_or_id]"]
+ return GLOB.block_parry_data["[type_id_datum]"]
/proc/set_block_parry_data(id, datum/block_parry_data/data)
if(ispath(id))
@@ -81,43 +83,78 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Prioriry for [mob/do_run_block()] while we're being used to parry.
// None - Parry is always highest priority!
- /// Parry windup duration in deciseconds
+ /// Parry windup duration in deciseconds. 0 to this is windup, afterwards is main stage.
var/parry_time_windup = 2
- /// Parry spindown duration in deciseconds
+ /// Parry spindown duration in deciseconds. main stage end to this is the spindown stage, afterwards the parry fully ends.
var/parry_time_spindown = 3
- /// Main parry window in deciseconds
+ /// Main parry window in deciseconds. This is between [parry_time_windup] and [parry_time_spindown]
var/parry_time_active = 5
- /// Perfect parry window in deciseconds from the main window. 3 with main 5 = perfect on third decisecond of main window.
+ /// Perfect parry window in deciseconds from the start of the main window. 3 with main 5 = perfect on third decisecond of main window.
var/parry_time_perfect = 2.5
- /// Time on both sides of perfect parry that still counts as well, perfect
+ /// Time on both sides of perfect parry that still counts as part of the perfect window.
var/parry_time_perfect_leeway = 1
/// [parry_time_perfect_leeway] override for attack types, list(ATTACK_TYPE_DEFINE = deciseconds)
var/list/parry_time_perfect_leeway_override
/// Parry "efficiency" falloff in percent per decisecond once perfect window is over.
- var/parry_time_imperfect_falloff_percent = 20
+ var/parry_imperfect_falloff_percent = 20
/// [parry_imperfect_falloff_percent] override for attack types, list(ATTACK_TYPE_DEFINE = deciseconds)
- var/list/parry_time_imperfect_falloff_percent_override
+ var/list/parry_imperfect_falloff_percent_override
/// Efficiency in percent on perfect parry.
var/parry_efficiency_perfect = 120
+ /// Flags for things like what kind of counter we do if successful and such
+ var/parry_flags = PARRY_FLAGS_DEFAULT
/obj/item/proc/active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_PARRY))
return
/// Yadda yadda WIP access block/parry data...
+/mob/living/proc/get_parry_stage()
+ if(!parrying)
+ return NOT_PARRYING
+ var/datum/block_parry_data/data = get_parry_data()
+ var/windup_end = data.parry_time_windup
+ var/active_end = windup + data.parry_time_active
+ var/spindown_end = active + data.parry_time_spindown
+ switch(get_parry_time())
+ if(0 to windup_end)
+ return PARRY_WINDUP
+ if(windup_end to active_end)
+ return PARRY_ACTIVE
+ if(active_end to spindown_end)
+ return PARRY_SPINDOWN
+ return NOT_PARRYING
+
+/mob/living/proc/get_parry_efficiency(attack_type)
+ var/datum/block_parry_data/data = get_parry_data()
+ if(get_parry_stage() != PARRY_ACTIVE)
+ return 0
+ var/difference = abs(get_parry_time() - (data.parry_time_perfect + data.parry_time_windup)
+ var/leeway = data.parry_time_perfect_leeway_override[attack_type]
+ if(isnull(leeway))
+ leeway = data.parry_time_perfect_leeway
+ difference -= leeway
+ . = data.parry_efficiency_perfect
+ if(difference <= 0)
+ return
+ var/falloff = data.parry_imperfect_falloff_percent_override[attack_type]
+ if(isnull(falloff))
+ falloff = data.parry_imperfect_falloff_percent
+ . -= falloff * difference
+
+/mob/living/proc/get_parry_time()
+ return world.time - parry_start_time
+
/// same return values as normal blocking, called with absolute highest priority in the block "chain".
/mob/living/proc/run_parry(real_attack = TRUE, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
/// Gets the datum/block_parry_data we're going to use to parry.
/mob/living/proc/get_parry_data()
if(parrying == ITEM_PARRY)
- return active_parry_item.block_parry_data
+ return get_block_parry_data(active_parry_item.block_parry_data)
else if(parrying == UNARMED_PARRY)
- return block_parry_data
+ return get_block_parry_data(block_parry_data)
else if(parrying == MARTIAL_PARRY)
- return mind.martial_art.block_parry_data
+ return get_block_parry_data(mind.martial_art.block_parry_data)
-#define UNARMED_PARRY
-#define MARTIAL_PARRY
-#define ITEM_PARRY
From ba713508ce639eade87c4f071ffb09a6ddc3f972 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 14:19:54 -0700
Subject: [PATCH 18/96] counterattacking?
---
code/modules/mob/living/living_block.dm | 7 +++--
.../mob/living/living_blocking_parrying.dm | 31 +++++++++++++++++--
2 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm
index 5e60285d04..498243e00d 100644
--- a/code/modules/mob/living/living_block.dm
+++ b/code/modules/mob/living/living_block.dm
@@ -23,9 +23,10 @@
* return_list - If something wants to grab things from what items/whatever put into list/block_return on obj/item/run_block and the comsig, pass in a list so you can grab anything put in it after block runs.
*/
/mob/living/proc/do_run_block(real_attack = TRUE, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
- . = run_parry(real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) //Parry - Highest priority!
- if((. & BLOCK_SUCCESS) && !(. & BLOCK_CONTINUE_CHAIN))
- return
+ if(real_attack)
+ . = run_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) //Parry - Highest priority!
+ if((. & BLOCK_SUCCESS) && !(. & BLOCK_CONTINUE_CHAIN))
+ return
// Component signal block runs have highest priority.. for now.
. = SEND_SIGNAL(src, COMSIG_LIVING_RUN_BLOCK, real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)
if((. & BLOCK_SUCCESS) && !(. & BLOCK_CONTINUE_CHAIN))
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 99903485f0..9c9c72bfab 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -101,8 +101,10 @@ GLOBAL_LIST_EMPTY(block_parry_data)
var/list/parry_imperfect_falloff_percent_override
/// Efficiency in percent on perfect parry.
var/parry_efficiency_perfect = 120
- /// Flags for things like what kind of counter we do if successful and such
- var/parry_flags = PARRY_FLAGS_DEFAULT
+ /// Parry data.
+ var/list/parry_data = list(
+ PARRY_REFLEX_COUNTERATTACK = PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN
+ )
/obj/item/proc/active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_PARRY))
@@ -146,7 +148,30 @@ GLOBAL_LIST_EMPTY(block_parry_data)
return world.time - parry_start_time
/// same return values as normal blocking, called with absolute highest priority in the block "chain".
-/mob/living/proc/run_parry(real_attack = TRUE, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
+/mob/living/proc/run_parry(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
+
+/// Run counterattack if any
+/mob/living/proc/run_parry_countereffects(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
+ var/datum/block_parry_data = get_parry_data()
+ if(data.parry_data[PARRY_REFLEX_COUNTERATTACK])
+ switch(data.parry_data[PARRY_REFLEX_COUNTERATTACK])
+ if(PARRY_COUNTERATTACK_PROC)
+
+ if(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN)
+ switch(parrying)
+ if(ITEM_PARRY)
+
+ if(UNARMED_PARRY)
+
+ if(MARTIAL_PARRY)
+
+ if(data.parry_data[PARRY_DISARM_ATTACKER])
+
+ if(data.parry_data[PARRY_KNOCKDOWN_ATTACKER])
+
+ if(data.parry_data[PARRY_STAGGER_ATTACKER])
+
+ if(data.parry_data[PARRY_CLICKCD_ATTACKER])
/// Gets the datum/block_parry_data we're going to use to parry.
/mob/living/proc/get_parry_data()
From afda58dbf6ddd4de27babb99ce86bbd3b6b9cb60 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 14:50:03 -0700
Subject: [PATCH 19/96] sounds1
---
sound/block_parry/block_wood1.ogg | Bin 0 -> 10321 bytes
sound/block_parry/block_wood2.ogg | Bin 0 -> 11774 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 sound/block_parry/block_wood1.ogg
create mode 100644 sound/block_parry/block_wood2.ogg
diff --git a/sound/block_parry/block_wood1.ogg b/sound/block_parry/block_wood1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..a01f3dbe0161d2c7d859aeeb860b43cb8aabbe61
GIT binary patch
literal 10321
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
T=}*8Qh*Kb(>RUpW5%7NiMs8yq
literal 0
HcmV?d00001
diff --git a/sound/block_parry/block_wood2.ogg b/sound/block_parry/block_wood2.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..62ca5be397a4fbe775b64a36114501fa4610e68c
GIT binary patch
literal 11774
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
literal 0
HcmV?d00001
From e6fd72e5eb5e2e2df1e785b5c98f2248793c887d Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Thu, 26 Mar 2020 14:54:49 -0700
Subject: [PATCH 20/96] k
---
sound/block_parry/block_wood2.ogg | Bin 11774 -> 11514 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/sound/block_parry/block_wood2.ogg b/sound/block_parry/block_wood2.ogg
index 62ca5be397a4fbe775b64a36114501fa4610e68c..398a59e24863d4c3b872300dc91b86cab33d0798 100644
GIT binary patch
delta 2447
zcmV;A32^rQTl!fVPiJRS00IC200000003wY00000002k~A2g8~E(~Z7000310016d
zJPxr`6%Pz(4*&oH0000+?10C!bq}}@A!rW(00RI30GwaQBox@x+A}iM+TtWJGc)7l
z%*f!`(U7xJAe;k#6otVYq`P9ZmdJjxo0Y>s*TH13rC|P~tN8#4HZnd6U|bXczS?yD
zQi>Zji-`*NEUh4W0d!+H?DyNAv1E2qut7(UQ?Z9>
zdB-~?%CfTw@TGI=(~o$vE3*K&$%9ESIgO1X5BE5i-ZrMLjrphJX+BIRD=zTIM+{@YnCAJXN0(eos1#MsC89@Fa$ya2P=2P*
z=5DyXUV-wpj3v5rrZ31Gr5x1B#ty6u3z%%)Muy9Oaa1u!XW$}e1q($^mYi+mI}a_-
z)1o#mN_l#~+9HA!W{Z{rPd(JMj4M^Y7Z4H@&@CQ!fBQIEgFFWE%e6>HxS7ngE7hnJ
zJA_a0(mj;(=I1f_2WEK}sZ?g)TMk^6St|fkB1u=$l9`~)O#&k!$qhseCHi39r&$`>
z+CC<1u2gt}
zWg?ld=QRq~Ne@igqC6=O^X@pIP&q6@&+xMy7#XbD?9L**==uxhW@_rIH%y2
z(u8v^n~Rdt0Ho1LJWKa&e8vchtg*p>Z)l7yd&N9g#mNR5N>Scx4#?7dfS0BxBmmw=
zywy~qB)Oo1^=u_O#tks3v}7lLYi%7@qR4
zRj~OXqj4F0KaMZcMBvP%)*7M~?e`dG4ONSjE5TRyEQknN0O`M_KTj_)>9xC}(6v3a
zuFxGkKifLCu6&tfINhYZa?|T&$*hFX(3n9a@Ov8WEB8sUFABFM>TsTa5U#qfYRRsv
z(@@-`rg4XH3X`Bb$qi{c**^<}TP@eP+1;C*iz^YbDV*oQuh!M4o08o0j}D*#K4v^y
zD+dAqI5Sal5HNb#rd(+)8ww<|bB6Dz&->=fCyx(ir2Y5v(~ZwY{>k3#o1eMirZMIu
z?B7XR#v4i(om5mqJu29LH*(yEgQKZvWN9l645Rk5bxvH4gy6eLN)C=d6tPMltH
zyXW38loyI>LE`hgrju%X-?J?V*p!$swHlg09wjF&GA>L6nM;g+13LajtZ77;`b86p
zaL?EETbSKuz@)~uOeM}!%(xiRANtJHl5TtRus?It
zJf#MUx^@#Kf2v!$@tn?cU7#hjw4&Tv(SFzSN5LCis%8@02tSexmF1JyXxX#9w~}*l
zb1$Uqt#Xkyh=gr_BGJMQtSiNZ2tI{w8Bz824ld`{IplFg%&vb8X4s^jsR{ITkyg5s
zQM?4Ci($q~q$HSmoKNRhI=SRjf3>SLSHSl0`&Y_@ALvIjek;RAfb(A5inGqrg>`@C`o-);W3y+U2O
z`|NjHcFRszlWlxXK+pzB0ya-{FOCPFyoSc=k^&uyJv1up~G1u^tZ=BkfOswLNlxu{ld$&v`Z~%g-|FQGE3YA<6YA^
zs%aNWVRd0<*o9>X>rXE*1_1tbEc4pO3R5FeEHUB^bh8SC!+{v30g#L(149K;Aju34E&IH2pOJYm3-Q!QfN(#0R
z6`KLJ?_K=|19n+=1N0-8Rh-4sSh*Eh&iy^LNIhSBZXo~ctN;-TFR~xm1;;%auaSX(
zmBw-XRUSz`T=?w=o%Z{X24P6kjPVB6FjYtxU0Dn-{M>(=VHKDoA8-SAS%f2*8rbo-
zP?Ya~*DUq38vhy8B9}{|ZH@rXtf{
zp7v8k(r5b%VozAhmm%+uV}m)efGJ?OpL6~qyDUK77X5JmCvg3BQA78vu^3gpV~0yL
Nr^NqVmRdv*pa8?gvjqSE
delta 2709
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
Date: Fri, 27 Mar 2020 21:10:02 -0700
Subject: [PATCH 21/96] sound effects + block pixelshift visuals
---
code/modules/mob/living/living_active_block.dm | 15 +++++++++++----
.../mob/living/living_blocking_parrying.dm | 3 +++
sound/block_parry/block_metal1.ogg | Bin 0 -> 10612 bytes
sound/block_parry/block_metal2.ogg | Bin 0 -> 9412 bytes
sound/block_parry/sfx-parry.ogg | Bin 0 -> 22373 bytes
5 files changed, 14 insertions(+), 4 deletions(-)
create mode 100644 sound/block_parry/block_metal1.ogg
create mode 100644 sound/block_parry/block_metal2.ogg
create mode 100644 sound/block_parry/sfx-parry.ogg
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index d96e6fb10a..c0d62f3a49 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -40,9 +40,13 @@
/// Visual effect setup for starting a directional block
/mob/living/proc/active_block_effect_start()
+ visible_message("[src] raises their [active_block_item], dropping into a defensive stance!")
+ animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_OUT)
/// Visual effect cleanup for starting a directional block
/mob/living/proc/active_block_effect_end()
+ visible_message("[src] lowers their [active_block_item].")
+ animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN)
/mob/living/get_standard_pixel_x_offset()
. = ..()
@@ -62,7 +66,7 @@
/// The amount of damage that is blocked.
/obj/item/proc/active_block_damage_mitigation(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ var/datum/block_parry_data/data = get_block_parry_data(block_parry_data)
var/absorption = data.block_damage_absorption_override[attack_type]
var/efficiency = data.block_damage_multiplier_override[attack_type]
var/limit = data.block_damage_limit_override[attack_type]
@@ -87,7 +91,7 @@
/// Amount of stamina from damage blocked. Note that the damage argument is damage_blocked.
/obj/item/proc/active_block_stamina_cost(mob/living/owner, atom/object, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ var/datum/block_parry_data/data = get_block_parry_data(block_parry_data)
var/efficiency = data.block_stamina_efficiency_override[attack_type]
if(isnull(efficiency))
efficiency = data.block_stamina_efficiency
@@ -95,7 +99,7 @@
/// Apply the stamina damage to our user, notice how damage argument is stamina_amount.
/obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
- var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ var/datum/block_parry_data/data = get_block_parry_data(block_parry_data)
if(iscarbon(owner))
var/mob/living/carbon/C = owner
var/held_index = C.get_held_index_of_item(src)
@@ -121,6 +125,7 @@
var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object), src)
if(!can_block_direction(owner.dir, incoming_direction))
return
+ var/datum/block_parry_data/data = get_block_parry_data(block_parry_data)
block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE
var/damage_mitigated = active_block_damage_mitigation(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
var/final_damage = max(0, damage - damage_mitigated)
@@ -134,6 +139,8 @@
owner.visible_message("[owner] blocks \the [attack_text] with [src]!")
else
owner.visible_message("[owner] dampens \the [attack_text] with [src]!")
+ if(length(data.block_sounds))
+ playsound(loc, pickweight(data.block_sounds), 75, TRUE)
/obj/item/proc/check_active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!CHECK_BITFIELD(item_flags, ITEM_CAN_BLOCK))
@@ -148,7 +155,7 @@
* Gets the list of directions we can block. Include DOWN to block attacks from our same tile.
*/
/obj/item/proc/blockable_directions()
- var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data)
+ var/datum/block_parry_data/data = get_block_parry_data(block_parry_data)
return data.can_block_directions
/**
diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm
index 9c9c72bfab..eb722973f0 100644
--- a/code/modules/mob/living/living_blocking_parrying.dm
+++ b/code/modules/mob/living/living_blocking_parrying.dm
@@ -79,6 +79,9 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Stamina dealt directly via adjustStaminaLossBuffered() per SECOND of block.
var/block_stamina_cost_per_second = 1.5
+ /// Sounds for blocking
+ var/list/block_sounds = list('sound/block_parry/block_metal1.ogg' = 1, 'sound/block_parry/block_metal1.ogg' = 1)
+
/////////// PARRYING ////////////
/// Prioriry for [mob/do_run_block()] while we're being used to parry.
// None - Parry is always highest priority!
diff --git a/sound/block_parry/block_metal1.ogg b/sound/block_parry/block_metal1.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..c0f98249cd3bd9124e11ba976e88d847da1cebff
GIT binary patch
literal 10612
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
literal 0
HcmV?d00001
diff --git a/sound/block_parry/sfx-parry.ogg b/sound/block_parry/sfx-parry.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..3429031bd94d9a78e47a5b689cc10be342127e2d
GIT binary patch
literal 22373
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