ok bet
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user