--- tags: Appended, Combat, Abstract title: "Combat: Blocking and Parrying (Kevinz)" --- ## Combat: Blocking and Parrying (Kevinz) (and a check_shields() refactor for those who know what that is) ### Basic Premise For the longest time, and by longest I mean "forever" combat on /tg/station involving things like shields and blocking have been either an all or nothing affair (see energy projectiles vs deshields or hardsuit shielding in general), or a RNG percentage chance based thing (see just about every type of shield in the game.) Everyone probably has their own thoughts on how much of the game should be based on RNG rolls rather than the cold hard inflexibility of mathematical damage calculations (In fact, I'm more for the former in certain, specific cases), but overall the whole blocking system as a whole I believe can be made to be far more *engaging* in gameplay. You don't have to do anything with a shield usually; You just hold it, and the game will go through your hand, suit, and uniform slots looking for stuff that can be used to block. No interaction needed rather than holding. This is where the proposed new system comes in: Something to replace **some** of the old RNG block (and some other forms, potentially) system the codebase has ran on with a more active form of mitigation. ### Requirements The system requires some form of (rapidly) regenerating resource/stat on each player to be balanced. This resource must not be tied to health, and optimally, will not be the stamina system that is already in place as that is tied to incoming damage. Optimally, I'd want this resource to be something unaffected for the most part by all but a few types of incoming attacks/factors, and be not too impacted by health and stamina damage. Something like a special action buffer. This is needed to balance out blocking/parrying as while parrying (more on that later) has somewhat of a system to make missing a parry penalize you and somewhat of an anti spam system already, blocking can be done infinitely as long as you don't hit crit without an action buffer or similar, and on the codebase this system was initially developed for both draw from the action buffer to limit how much it can be used (as parries, for one, do not have that many hard cooldowns if you do not miss your parry, and hard cooldowns are kind of weird anyways in practice). ### Control Scheme Both blocking/parrying can be bound to individual rebindable hotkeys. Parrying itself will be a timed action triggered by a keypressto initiate the sequence. Blocking can be easily made to allow both hold-down control and press to toggle control since it is a variable length action controlled entirely by how long the user wants to block. ### Documentation A wiki article will be expected to be written eventually(tm) about the feature, but: `/datum/block_parry_data`, the metadata holder itself, will have procs needed to render its variables in a relatively user readable format, with descriptions of what each variable does. **Players will be able to access this by examining an item that supports the system. If said item supports the system, they will get a button in chat to press to bring up a window with all of this rendered.** - This can be slightly confusing to people due to the entire thing being kind of just raw variable names with descriptions, but it's better than the frankly undoable expectation of having every item documented on wiki with exact values, or expecting people to codedive for everything. - The overhead for this is nil, other than people having to deal with my terrible UI design skills every time they open the window. ### Code structure check_shields() and similar things will be refactored into a system with all checks for shields/blocking/anything ran ultimately into a single proc, do_run_block(), with variants being run_block() and check_block(), one for situations where a physical attack is being ran, and the latter for things like checking if a target has block/how much block it has. The latter can be useful for cases like smarter mob AI, as running it will tell you exactly (if it's implemented right on blocking objects) how likely the target is to block something/how much block a target has/are they parrying/etc. For blocking and parrying itself, all data for that will be held in a new datum, `/datum/block_parry_data`. It will be cached like armor datums and accessed using a global proc that looks up an unique ID of the datum OR typepath from a list, and return it. If it doens't exist and it's a typepath, the datum will be made and cached in the global cache list of said datums. This is to have the best possible memory efficiency, as items themselves in most cases will just have their `block_parry_data` variable set to a typepath which is fetched when active block/parry sequences and procs are being ran. - Disclaimer: The data datum is very much uh.. variable hell. I counted 37 variables on it last I checked. This is just so the highest number of situations can be built into the variable editing itself, rather than require people override procs. The reason this uses IDs and typepaths instead of pure typepaths is for the same reason as movespeed modifiers; Unlike atmospheric gases/chemicals/similar, these are things that will reasonably have use cases in the future for runtime modification, and I do not want to lock in a system that doesn't support that. #### Misc - New component signal for run/check parry - Custom component behavior? Shield components? Shielding datums? - I can finally do my peacekeeper cyborg shields?? - Potentially new component signals for getting things to block/parry with - New block return flag values, block return list, blocking as a system is far more fleshed out as a framework requiring less snowflake code (probably depends on your definition of snowflake), more centralized - Blocks supporting (obviously considering this is kind of required for block/parry) partial mitigation/set damage to instead of flat out yes/no pass/fail - Block priorities - Items can now set what priority they have in the block check chain - Example: Outerwear/shields intercepting before uniform, etc - NO MORE HARDCODED HANDS/UNIFORM/SUIT BLOCK FOR THE LOVE OF ALL THAT IS HOLY - The reactive teleport armor will no longer delete bullets you teleport out of the way from - I care about this, obviously. And now that all the nitty gritty's written, the actual features: ### Blocking #### Basics - **As of right now, this system, unlike parrying, only works for held items. Martial arts/innate living mob blocking is not supported yet.** - Variable length action on supporting items. Drains action buffer/stamina/whatever turns out to be the right call as a resource needed to keep it active. - No RNG involved in general, everything is based on fully customizable numbers - This will highly vary in implementation, but the general idea that I have is this will not, at all, other than in specific and very niche cases, give full damage immunity. Unlike RNG block, this will be more for blocking percentages of damages to absorb attacks rather than fully mitigating them. - This might change, I say this because I do not know of a good way to balance full damage block yet. It might work, the system, once again, is full customizable, both blocking and parrying, and people can do whatever with it they want. - And I don't want to deal with screaming ;) - Which there will be anyways - A lot of it. #### Directional Shielding On the codebase this was designed for, you have combat mode (I know tg has something written on hackmd for it). Blocking is directional for the most part: You must be facing the right direction towards the attacker to block attacks with shields. I made exceptions for things like deswords but this was how it was for the most part. This works terribly, however, without a system to turn to your mouse pointer in combat mode or something, but, like everything else, this is highly customizable. I'm putting it here to indicate the original design having it, and the system fully supporting this. #### User feedback - People blocking attacks actively get pixel shifted in a direction. - Starting and ending the block makes messages. - If someone wants to get sprites, be my guest, but I am not a spriter and I really don't want to have to codersprite this. - Chat message for successful blocks/blocked attacks - SOUNDS! CLANG! #### Starting/stopping/holding Some items will need a short delay of hold-down with a key to block so it's not instant and has setup time. Blocking in general slows you down and prevents you from attacking while it's active. Deactivating is instant. #### Misc A short list of other capabilities the system has outside of the above and the below (damage calcs): - Use x buffer/stamina per second of block - Only working on certain attack types - Being more/less effective on certain attack types - Special behavior if someone is knocked down on the ground - Currently this defaults to taking more stamina/buffer per block but also allowing you to block melee from any direction - This is, for the most part, not going to be an advantage for the person who's downed. - Locking the blocker from making attacks for x deciseconds after the block stops #### Damage calculations Simple: - Damage absorption - Damage multiplier - Damage limit - Efficiency How it works: 1. When an attack comes in, a final running total of damage to set it to is set up at 0 2. Any damage above the damage limit is taken away from the original damage and added to the running total 3. Any damage in the absorption limit is taken away from the original damage and tossed 4. Any damage left is multiplied by the damage multiplier and added to the running total 5. The final running total is now the new damage for the attack. This is set in the return list that procs for attack handling reads from. 6. The damage blocked is calculated from this and the original attack damage, and converted into stamina/whatever damage/use, divided by the `block_efficiency` coefficient. 7. This is transferred to the user 8. The attack proceeds with the new final damage, unless it is 0 or below, in which case the attack is considered `BLOCK_SUCCESS`, completely blocked. 9. **This might need adjustments (depending on how things go), as under this, all disarms and grabs are always blocked, as well as things like stunbatons as they are all considered 0 damage attacks.** ### Parrying #### Basics - **This system, like blocking, is fully customizable and includes *plenty* of hook points for items, martial arts, and more.** - **Unlike blocking, this has full support for mobs with innate parrying abilities, as well as !!MARTIAL ARTS!!** - Parrying is a timed action initiated by the player. - Highish risk, highish reward - Succeeding a parry is going to be bad for the attacker - Failing a parry is going to be bad for the defender - More on this later #### User feedback - Parrying makes a chat message when it's initiated, when attacks are parried, and when it ends - The chat messages are pretty indicative of what's happening/what happened. - There is a visual sprite that overlays over the user while parrying, with varying animation durations based on the timing values of the item being used to parry - SOUNDS! #### Timing Basics: - Windup - Active - Spindown - Perfect "frame" - Perfect leeway - Imperfect falloff - Efficiency How it works: - The parry is only considered during active - Animation is based on windup, active, and spindown - The parry sequence is considered in progress until all 3 stages complete - If an attack lands during the active window, an efficiency is calculated - A set efficiency is defined for the "perfect" frames - A leeway is set of deciseconds before and after the perfect parry point where there is still no falloff - Afterwards, for every decisecond off, you are penalized by a falloff - This impacts efficiency, which is what calculates the final mitigation percentage/how much damage you receive from an attack - An efficiency of 100 or above results in a full `BLOCK_SUCCESS` blocking in code, completely mitigating the hit. - As opposed to blocking where damage is what this threshold is. - This threshold is needed because a lot of things still only care about binary pass/fail thresholds, rather than having actual damage values - Looking at you, batons/shoves. - Specific efficiency thresholds are set which are considered "successful" and "eligible to counterattack" #### Success/Failure - Parries are considered a success if it's over a specific efficiency - You need atleast one successful parry to have the sequence succeed - Failing the sequence has a myriad of potential penalties, like slowdowns, dazes (unable to use items), clickdelays, knockdowns, etc - **This is fully customizable in code** #### Automatic Counterattacking - If a parry is efficient enough to be eligible, the user will will automatically counterattack the attacker attacking them - This has a myriad of effects, from knockdowns to disarms to attacking back to damage to custom procs - **This is fully customizable in code, before anyone complains.** #### Misc - I am tired of writing - I'm going to throw out some of the other already implemented examples of what can be done with this part of the system - As I said 5 times earlier, everything is customizable in this framework. Misc implemented and customizable things/examples: - Different efficiencies/leeways/falloffs for different attack types - don't bring a sword to a gunfight - Or do... - Parry stamina/buffer cost - Parry visual time overrides - Parry visual graphic overrides - No attacking while parrying - Not implemented yet but easy to: - No moving fast while parrying (slowdown) - Rooted in place while parrying - Only being able to parry specific attack types - Max attacks per parry - Cooldown between parries - Custom martial art implementations of parries