From 234687c5c848b14f522f1df8cb9c8d9eb7566495 Mon Sep 17 00:00:00 2001 From: kevinz000 <2003111+kevinz000@users.noreply.github.com> Date: Sat, 11 Apr 2020 05:10:07 -0700 Subject: [PATCH] do_after_advanced --- code/__DEFINES/flags/do_after.dm | 32 ++ code/__HELPERS/do_after.dm | 329 ++++++++++++++++++ code/__HELPERS/mobs.dm | 166 --------- code/modules/keybindings/bindings_mob.dm | 17 +- .../mob/living/carbon/human/human_defines.dm | 4 +- .../modules/mob/living/living_active_block.dm | 51 ++- .../modules/mob/living/living_active_parry.dm | 1 + .../mob/living/living_blocking_parrying.dm | 2 + tgstation.dme | 2 + 9 files changed, 431 insertions(+), 173 deletions(-) create mode 100644 code/__DEFINES/flags/do_after.dm create mode 100644 code/__HELPERS/do_after.dm diff --git a/code/__DEFINES/flags/do_after.dm b/code/__DEFINES/flags/do_after.dm new file mode 100644 index 0000000000..ffef70afbb --- /dev/null +++ b/code/__DEFINES/flags/do_after.dm @@ -0,0 +1,32 @@ +/// Requires absolute stillness from the user +#define DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER (1<<0) +/// Requires absolute stillness from the target +#define DO_AFTER_DISALLOW_MOVING_ABSOLUTE_TARGET (1<<1) +/// Requires that the user is on a turf. +#define DO_AFTER_REQUIRES_USER_ON_TURF (1<<2) +/// Requires relative stillness to our target via dx and dy coordinate difference but only if both are spacedrifting. Specify DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY to say otherwise. +#define DO_AFTER_DISALLOW_MOVING_RELATIVE (1<<3) +/// Breaks if active hand item changes. Requires a tool be specified, otherwise defaults to active item +#define DO_AFTER_DISALLOW_ACTIVE_ITEM_CHANGE (1<<4) +/// Breaks if the user has no free hands. If a tool is specified, allows that as well. +#define DO_AFTER_REQUIRE_FREE_HAND_OR_TOOL (1<<5) +/// Do not display progressbar. +#define DO_AFTER_NO_PROGRESSBAR (1<<6) +/// Do not check do_after_coefficient() +#define DO_AFTER_NO_COEFFICIENT (1<<7) +/// For relative stillness, allow non spacedrift relative movement +#define DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY (1<<8) + +/// Ignores checks. +#define DO_AFTER_PROCEED 2 +/// Uses all other checks +#define DO_AFTER_CONTINUE NONE +/// Breaks +#define DO_AFTER_STOP 1 + +/// Stage - initiating a do_after +#define DO_AFTER_STARTING 1 +/// Stage - main loop of a do_after +#define DO_AFTER_PROGRESSING 2 +/// Stage - Last check of a do_after +#define DO_AFTER_FINISHING 3 diff --git a/code/__HELPERS/do_after.dm b/code/__HELPERS/do_after.dm new file mode 100644 index 0000000000..f9d54dd676 --- /dev/null +++ b/code/__HELPERS/do_after.dm @@ -0,0 +1,329 @@ +/** + * Higher overhead "advanced" version of do_after. + * @params + * - atom/user is the atom doing the action or the "physical" user + * - delay is time in deciseconds + * - atom/target is the atom the action is being done to, defaults to user + * - do_after_flags see __DEFINES/flags/do_after.dm for details. + * - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool). + * Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING + * If it returns DO_AFTER_STOP, this breaks. + * If it returns nothing, all other checks are done. + * If it returns DO_AFTER_PROCEED, all other checks are ignored. + * - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob. + * - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob. + * - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this. + * - obj/item/tool - The tool we're using. See do_after flags for details. + */ +#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, world.time - starttime, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initiailly_held_item, tool) +#define CHECK_FLAG_FAILURE ((required_mobility_flags || required_combat_flags) && (!living_user || !CHECK_ALL_MOBILITY(living_user, required_mobility_flags) || !CHECK_ALL_BITFIELDS(living_user.combat_flags, required_combat_flags))) +#define TIMELEFT (world.time - starttime) +/proc/do_after_advanced(atom/user, delay, atom/target, do_after_flags, datum/callback/extra_checks, required_mobility_flags, required_combat_flags, mob/living/mob_redirect, obj/item/tool) + // CHECK AND SET VARIABLES + if(!user) + return FALSE + if(!target) + target = user + if((user.loc == null) || (target.loc == null)) + return FALSE + var/mob/living/living_user = mob_redirect + if(!living_user && isliving(user)) + living_user = user + var/stage = DO_AFTER_STARTING + var/startlocuser = user.loc + var/startloctarget = target.loc + var/turf/userturf = get_turf(user) + var/turf/targetturf = get_turf(target) + if(!userturf || !targetturf) + return FALSE + if((do_after_flags & DO_AFTER_REQUIRES_USER_ON_TURF) && !isturf(user.loc)) + return FALSE + var/starttime = world.time + var/endtime = world.time + delay + var/obj/item/initially_held_item = mob_redirect?.get_active_held_item() + if(!(do_after_flags & DO_AFTER_NO_COEFFICIENT) && living_user) + delay *= living_user.do_after_coefficient() + var/drifting = user.Process_Spacemove(NONE) && user.inertia_dir + var/initial_dx = targetturf.x - userturf.x + var/initial_dy = targetturf.y - userturf.y + var/dx = initial_dx + var/dy = initial_dy + // DO OUR STARTING CHECKS + var/cb_return + INVOKE_CALLBACK + if(cb_return == DO_AFTER_STOP) + return FALSE + else if(cb_return != DO_AFTER_PROCEED) + if(CHECK_FLAG_FAILURE) + return FALSE + // SETUP LOOP + var/datum/progressbar/progbar + if(living_user) + if(!(do_after_flags & DO_AFTER_NO_PROGRESSBAR)) + progbar = new(living_user, delay, target) + // MAIN LOOP + . = TRUE + var/obj/item/held + var/locchanged + var/ctu + var/ctt + while(world.time < endtime) + stoplag(1) + progbar?.update(TIMELEFT) + if(QDELETED(user) || QDELETED(target) || (user.loc == null) || (target.loc == null)) + . = FALSE + break + INVOKE_CALLBACK + if(cb_return == DO_AFTER_STOP) + . = FALSE + break + else if(cb_return == DO_AFTER_PROCEED) + continue + // otherwise, go through our normal checks. + if(((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER) && (user.loc != startlocuser)) || ((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_TARGET) && (target.loc != startloctarget))) + . = FALSE + break + else if(do_after_flags & DO_AFTER_DISALLOW_MOVING_RELATIVE) + ctu = get_turf(user) + ctt = get_turf(target) + locchanged = (user_turf != ctu) || (target_turf != ctt) + userturf = ctu + targetturf = ctt + dx = targetturf.x - userturf.x + dy = targetturf.y - userturf.y + if((dx != initial_dx) || (dy != initial_dy)) + . = FALSE + break + if(loc_changed && !drifting && !(do_after_flags & DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY)) + . = FALSE + break + if(!user.inertia_dir) + drifting = FALSE + if((do_after_flags & DO_AFTER_REQUIRES_USER_ON_TURF) && !isturf(user.loc)) + return FALSE + if(CHECK_FLAG_FAILURE) + . = FALSE + break + held = living_user?.get_active_held_item() + if((do_after_flags & DO_AFTER_DISALLOW_ACTIVE_ITEM_CHANGE) && (held != (tool || initially_held_item))) + . = FALSE + break + if((do_after_flags & DO_AFTER_REQUIRE_FREE_HAND_OR_TOOL) && (!living_user?.is_holding(tool) && !length(living_user?.get_empty_held_indexes()))) + . = FALSE + break + + // CLEANUP + qdel(progbar) + // If we failed, just return. + if(!.) + return FALSE + // DO FINISHING CHECKS + if(QDELETED(user) || QDELETED(target)) + return FALSE + INVOKE_CALLBACK + if(cb_return == DO_AFTER_STOP) + return FALSE + else if(cb_return != DO_AFTER_PROCEED) + if(CHECK_FLAG_FAILURE) + return FALSE + if(((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER) && (user.loc != startlocuser)) || ((do_after_flags & DO_AFTER_DISALLOW_MOVING_ABSOLUTE_TARGET) && (target.loc != startloctarget))) + . = FALSE + break + else if(do_after_flags & DO_AFTER_DISALLOW_MOVING_RELATIVE) + ctu = get_turf(user) + ctt = get_turf(target) + locchanged = (user_turf != ctu) || (target_turf != ctt) + userturf = ctu + targetturf = ctt + dx = targetturf.x - userturf.x + dy = targetturf.y - userturf.y + if((dx != initial_dx) || (dy != initial_dy)) + . = FALSE + break + if(loc_changed && !drifting && !(do_after_flags & DO_AFTER_ALLOW_NONSPACEDRIFT_RELATIVITY)) + . = FALSE + break + if((do_after_flags & DO_AFTER_REQUIRES_USER_ON_TURF) && !isturf(user.loc)) + return FALSE + held = living_user?.get_active_held_item() + if((do_after_flags & DO_AFTER_DISALLOW_ACTIVE_ITEM_CHANGE) && (held != (tool || initially_held_item))) + . = FALSE + break + if((do_after_flags & DO_AFTER_REQUIRE_FREE_HAND_OR_TOOL) && (!living_user?.is_holding(tool) && !length(living_user?.get_empty_held_indexes()))) + . = FALSE + break + +/// Requires absolute stillness in the user +#define DO_AFTER_DISALLOW_MOVING_ABSOLUTE_USER (1<<0) +/// Requires relative stillness to our target +#define DO_AFTER_DISALLOW_MOVING_RELATIVE_TARGET (1<<1) + +#undef INVOKE_CALLBACK +#undef CHECK_FLAG_FAILURE + +/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = 0) + if(!user || !target) + return 0 + var/user_loc = user.loc + + var/drifting = 0 + if(!user.Process_Spacemove(0) && user.inertia_dir) + drifting = 1 + + var/target_loc = target.loc + + var/holding = user.get_active_held_item() + var/datum/progressbar/progbar + if (progress) + progbar = new(user, time, target) + + var/endtime = world.time+time + var/starttime = world.time + . = 1 + while (world.time < endtime) + stoplag(1) + if (progress) + progbar.update(world.time - starttime) + if(QDELETED(user) || QDELETED(target)) + . = 0 + break + if(uninterruptible) + continue + + if(drifting && !user.inertia_dir) + drifting = 0 + user_loc = user.loc + + if((!drifting && user.loc != user_loc) || target.loc != target_loc || (!ignorehelditem && user.get_active_held_item() != holding) || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke())) + . = 0 + break + if (progress) + qdel(progbar) + + +//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action +/mob/proc/break_do_after_checks(list/checked_health, check_clicks) + if(check_clicks && next_move > world.time) + return FALSE + return TRUE + +//pass a list in the format list("health" = mob's health var) to check health during this +/mob/living/break_do_after_checks(list/checked_health, check_clicks) + if(islist(checked_health)) + if(health < checked_health["health"]) + return FALSE + checked_health["health"] = health + return ..() + +/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE)) + if(!user) + return 0 + var/atom/Tloc = null + if(target && !isturf(target)) + Tloc = target.loc + + var/atom/Uloc = user.loc + + var/drifting = 0 + if(!user.Process_Spacemove(0) && user.inertia_dir) + drifting = 1 + + var/holding = user.get_active_held_item() + + var/holdingnull = 1 //User's hand started out empty, check for an empty hand + if(holding) + holdingnull = 0 //Users hand started holding something, check to see if it's still holding that + + delay *= user.do_after_coefficent() + + var/datum/progressbar/progbar + if (progress) + progbar = new(user, delay, target) + + var/endtime = world.time + delay + var/starttime = world.time + . = 1 + var/mob/living/L = isliving(user) && user //evals to last thing eval'd + while (world.time < endtime) + stoplag(1) + if (progress) + progbar.update(world.time - starttime) + + if(drifting && !user.inertia_dir) + drifting = 0 + Uloc = user.loc + + if(L && !CHECK_ALL_MOBILITY(L, required_mobility_flags)) + . = 0 + break + + if(QDELETED(user) || user.stat || (!drifting && user.loc != Uloc) || (extra_checks && !extra_checks.Invoke())) + . = 0 + break + + if(!QDELETED(Tloc) && (QDELETED(target) || Tloc != target.loc)) + if((Uloc != Tloc || Tloc != user) && !drifting) + . = 0 + break + + if(needhand) + //This might seem like an odd check, but you can still need a hand even when it's empty + //i.e the hand is used to pull some item/tool out of the construction + if(!holdingnull) + if(!holding) + . = 0 + break + if(user.get_active_held_item() != holding) + . = 0 + break + if (progress) + qdel(progbar) + +/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1 + . = 1 + return + +/proc/do_after_mob(mob/user, var/list/targets, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks) + if(!user || !targets) + return 0 + if(!islist(targets)) + targets = list(targets) + var/user_loc = user.loc + + var/drifting = 0 + if(!user.Process_Spacemove(0) && user.inertia_dir) + drifting = 1 + + var/list/originalloc = list() + for(var/atom/target in targets) + originalloc[target] = target.loc + + var/holding = user.get_active_held_item() + var/datum/progressbar/progbar + if(progress) + progbar = new(user, time, targets[1]) + + var/endtime = world.time + time + var/starttime = world.time + . = 1 + mainloop: + while(world.time < endtime) + stoplag(1) + if(progress) + progbar.update(world.time - starttime) + if(QDELETED(user) || !targets) + . = 0 + break + if(uninterruptible) + continue + + if(drifting && !user.inertia_dir) + drifting = 0 + user_loc = user.loc + + for(var/atom/target in targets) + if((!drifting && user_loc != user.loc) || QDELETED(target) || originalloc[target] != target.loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke())) + . = 0 + break mainloop + if(progbar) + qdel(progbar) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index febd333578..1d5f360581 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -304,172 +304,6 @@ GLOBAL_LIST_EMPTY(species_list) else return "unknown" -/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = 0) - if(!user || !target) - return 0 - var/user_loc = user.loc - - var/drifting = 0 - if(!user.Process_Spacemove(0) && user.inertia_dir) - drifting = 1 - - var/target_loc = target.loc - - var/holding = user.get_active_held_item() - var/datum/progressbar/progbar - if (progress) - progbar = new(user, time, target) - - var/endtime = world.time+time - var/starttime = world.time - . = 1 - while (world.time < endtime) - stoplag(1) - if (progress) - progbar.update(world.time - starttime) - if(QDELETED(user) || QDELETED(target)) - . = 0 - break - if(uninterruptible) - continue - - if(drifting && !user.inertia_dir) - drifting = 0 - user_loc = user.loc - - if((!drifting && user.loc != user_loc) || target.loc != target_loc || (!ignorehelditem && user.get_active_held_item() != holding) || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke())) - . = 0 - break - if (progress) - qdel(progbar) - - -//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action -/mob/proc/break_do_after_checks(list/checked_health, check_clicks) - if(check_clicks && next_move > world.time) - return FALSE - return TRUE - -//pass a list in the format list("health" = mob's health var) to check health during this -/mob/living/break_do_after_checks(list/checked_health, check_clicks) - if(islist(checked_health)) - if(health < checked_health["health"]) - return FALSE - checked_health["health"] = health - return ..() - -/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE)) - if(!user) - return 0 - var/atom/Tloc = null - if(target && !isturf(target)) - Tloc = target.loc - - var/atom/Uloc = user.loc - - var/drifting = 0 - if(!user.Process_Spacemove(0) && user.inertia_dir) - drifting = 1 - - var/holding = user.get_active_held_item() - - var/holdingnull = 1 //User's hand started out empty, check for an empty hand - if(holding) - holdingnull = 0 //Users hand started holding something, check to see if it's still holding that - - delay *= user.do_after_coefficent() - - var/datum/progressbar/progbar - if (progress) - progbar = new(user, delay, target) - - var/endtime = world.time + delay - var/starttime = world.time - . = 1 - var/mob/living/L = isliving(user) && user //evals to last thing eval'd - while (world.time < endtime) - stoplag(1) - if (progress) - progbar.update(world.time - starttime) - - if(drifting && !user.inertia_dir) - drifting = 0 - Uloc = user.loc - - if(L && !CHECK_ALL_MOBILITY(L, required_mobility_flags)) - . = 0 - break - - if(QDELETED(user) || user.stat || (!drifting && user.loc != Uloc) || (extra_checks && !extra_checks.Invoke())) - . = 0 - break - - if(!QDELETED(Tloc) && (QDELETED(target) || Tloc != target.loc)) - if((Uloc != Tloc || Tloc != user) && !drifting) - . = 0 - break - - if(needhand) - //This might seem like an odd check, but you can still need a hand even when it's empty - //i.e the hand is used to pull some item/tool out of the construction - if(!holdingnull) - if(!holding) - . = 0 - break - if(user.get_active_held_item() != holding) - . = 0 - break - if (progress) - qdel(progbar) - -/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1 - . = 1 - return - -/proc/do_after_mob(mob/user, var/list/targets, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks) - if(!user || !targets) - return 0 - if(!islist(targets)) - targets = list(targets) - var/user_loc = user.loc - - var/drifting = 0 - if(!user.Process_Spacemove(0) && user.inertia_dir) - drifting = 1 - - var/list/originalloc = list() - for(var/atom/target in targets) - originalloc[target] = target.loc - - var/holding = user.get_active_held_item() - var/datum/progressbar/progbar - if(progress) - progbar = new(user, time, targets[1]) - - var/endtime = world.time + time - var/starttime = world.time - . = 1 - mainloop: - while(world.time < endtime) - stoplag(1) - if(progress) - progbar.update(world.time - starttime) - if(QDELETED(user) || !targets) - . = 0 - break - if(uninterruptible) - continue - - if(drifting && !user.inertia_dir) - drifting = 0 - user_loc = user.loc - - for(var/atom/target in targets) - if((!drifting && user_loc != user.loc) || QDELETED(target) || originalloc[target] != target.loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying || (extra_checks && !extra_checks.Invoke())) - . = 0 - break mainloop - if(progbar) - qdel(progbar) /proc/is_species(A, species_datum) . = FALSE diff --git a/code/modules/keybindings/bindings_mob.dm b/code/modules/keybindings/bindings_mob.dm index 36b4775c34..95a883dda7 100644 --- a/code/modules/keybindings/bindings_mob.dm +++ b/code/modules/keybindings/bindings_mob.dm @@ -10,12 +10,18 @@ else stop_pulling() return - if("Insert", "G") - a_intent_change(INTENT_HOTKEY_RIGHT) + if("Insert") + if(client.keys_held["Ctrl"]) + keybind_toggle_active_blocking() + return + else + keybind_parry() + return + if("G") + keybind_parry() return if("F") - a_intent_change(INTENT_HOTKEY_LEFT) - return + keybind_start_active_blocking() if("X", "Northeast") // Northeast is Page-up swap_hand() return @@ -91,4 +97,7 @@ if("Alt") toggle_move_intent() return + if("F") + keybind_stop_active_blocking() + return return ..() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 68c312b19c..04e9e56244 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -11,7 +11,9 @@ status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER blocks_emissive = EMISSIVE_BLOCK_UNIQUE - + + active_block_enabled = TRUE + //Hair colour and style var/hair_color = "000" var/hair_style = "Bald" diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index 3fff9a9c03..b5cdd8c556 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -2,6 +2,10 @@ /mob/living /// Whether or not the user is actively blocking. var/active_blocking = FALSE + /// Whether or not we can actively block. Disabled by default since a lot of mobs do not support stamina damage. Imagine a dextrous guardian with a shield.. + var/active_block_enabled = FALSE + /// Whether or not we are in the process of raising our shield/whatever. + var/active_block_starting = FALSE /// The item the user is actively blocking with if any. var/obj/item/active_block_item @@ -52,7 +56,7 @@ /mob/living/get_standard_pixel_x_offset() . = ..() - if(active_blocking) + if(active_blocking || active_block_starting) if(dir & EAST) . += 12 if(dir & WEST) @@ -60,12 +64,55 @@ /mob/living/get_standard_pixel_y_offset() . = ..() - if(active_blocking) + if(active_blocking || active_block_starting) if(dir & NORTH) . += 12 if(dir & SOUTH) . -= 12 +/** + * Proc called by keybindings to toggle active blocking. + */ +/mob/living/proc/keybind_toggle_active_blocking() + if(active_blocking) + return keybind_stop_active_blocking() + else + return keybind_start_active_blocking() + +/** + * Proc called by keybindings to start active blocking. + */ +/mob/living/proc/keybind_start_active_blocking() + if(active_blocking || active_block_starting) + return FALSE + if(!CHECK_BITFIELD(combat_flags, COMBAT_FLAG_COMBAT_ACTIVE)) + to_chat(src, "You must be in combat mode to actively block!") + return FALSE + var/obj/item/I = get_active_held_item() + if(!I) + to_chat(src, "You can't block with your bare hands!") + return + if(!(I.item_flags & ITEM_CAN_BLOCK)) + to_chat(src, "[I] is not capable of actively being used to block!") + return + var/datum/block_parry_data/data = get_block_parry_data(I.block_parry_data) + var/delay = data.block_start_delay + active_block_starting = TRUE + animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = delay, FALSE, SINE_EASING | EASE_IN) + if(!do_after_advanced(src, delay, src, DO_AFTER_REQUIRES_USER_ON_TURF|DO_AFTER_NO_COEFFICIENT|DO_AFTER_DISALLOW_ACTIVE_ITEM_CHANGE, null, MOBILITY_USE, COMBAT_FLAG_COMBAT_ACTIVE, null, I)) + to_chat(src, "You fail to raise [src].") + animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN, ANIMATION_END_NOW) + return + active_block_starting = FALSe + start_active_blocking(I) + +/** + * Proc called by keybindings to stop active blocking. + */ +/mob/living/proc/keybind_stop_active_blocking() + stop_active_blocking(FALSE) + 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/datum/block_parry_data/data = get_block_parry_data(block_parry_data) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index e69de29bb2..8ba203d59c 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -0,0 +1 @@ +/mob/living/proc/keybind_parry() diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 7359d07cb0..83de7d65c7 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -47,6 +47,8 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/block_lock_attacking = TRUE /// The priority we get in [mob/do_run_block()] while we're being used to parry. var/block_active_priority = BLOCK_PRIORITY_ACTIVE_BLOCK + /// Windup before we have our blocking active. + var/block_start_delay = 5 /// Amount of "free" damage blocking absorbs var/block_damage_absorption = 10 diff --git a/tgstation.dme b/tgstation.dme index 502103ab79..33a25f6345 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -124,6 +124,7 @@ #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" +#include "code\__DEFINES\flags\do_after.dm" #include "code\__HELPERS\_cit_helpers.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm" @@ -134,6 +135,7 @@ #include "code\__HELPERS\custom_holoforms.dm" #include "code\__HELPERS\dates.dm" #include "code\__HELPERS\dna.dm" +#include "code\__HELPERS\do_after.dm" #include "code\__HELPERS\donator_groupings.dm" #include "code\__HELPERS\files.dm" #include "code\__HELPERS\game.dm"