Four BepInEx mods for Nine Sols that change how parrying works. Each one is independent - install any combination.
| Mod | What it does |
|---|---|
| Perfect Parry | Sets the perfect-parry window in frames, Sekiro-style. Optionally makes an imperfect parry cost real health instead of internal injury. |
| Any Direction Parry | Parry regardless of which way you are facing. |
| Counter Charge Tuner | Retimes the Unbounded Counter: shorter hold to trigger, and it loops instead of expiring until you release parry. |
| Harness Force Jade | Reworks the Harness Force jade so a perfect parry banks a full charge with no need to hold attack beforehand. |
Built against Nine Sols with BepInEx 5.4.23.5 and HarmonyX 2.9.
These mods were written with Anthropic's Claude (Claude Code, Opus 5), and that covers most of it: decompiling the game's assemblies to work out what to patch, the C# source, the build scripts, the test harnesses, and this README. The design decisions, the in-game testing and the "no, that feels wrong" calls are mine.
Saying so plainly because you are about to run this inside your game. What that's worth in practice:
- Every mod has a behaviour test suite in
tests/that runs the compiled DLL against a transcription of the relevant game code, with the plugin's patch bodies wired in where Harmony would put them. Not a mock of the mod - the real built artefact. build/checkrefs.pyresolves every external type and member reference against the installed game assemblies and compares call arity, which catches the mistakes that otherwise only surface as aMissingMethodExceptionmid-fight.- Every patch is explained in a comment above it, quoting the decompiled method it targets, so you can check the reasoning against your own copy of the game.
That's automated verification, not a substitute for reading the code yourself if you would
rather. It is all in mods/ - four files, none of them long.
You need BepInEx 5 first. The easiest route is r2modman, which installs BepInEx for you.
- Download the
.zipfiles you want from Releases. Do not unzip them. - In r2modman, pick your Nine Sols profile → Settings → Import local mod.
- Select a zip. Repeat for each mod.
- Start modded from r2modman.
Drop the .dll from inside a zip into BepInEx/plugins/. Config files appear in
BepInEx/config/ after the first launch.
Every setting on every mod applies live - change it and the game picks it up on the next parry, no restart.
Install
ConfigurationManager
and press F1 in game to edit settings with a UI. Otherwise edit the .cfg files in
BepInEx/config/ directly:
supidowagon.PerfectParry.cfg
supidowagon.AnyDirectionParry.cfg
supidowagon.CounterChargeTuner.cfg
supidowagon.HarnessForceJade.cfg
Every mod has an Enabled toggle that restores stock behaviour without uninstalling anything.
Vanilla gives you 8 frames to land a perfect parry. This sets that number.
Why 12 by default: the goal is to make Nine Sols parrying feel like Sekiro deflecting - a window generous enough to reward reading an attack rather than memorising it.
The imperfect-parry damage option comes from the same intent. In Sekiro, a hit you block but do
not deflect costs real vitality; there is no grey bar you win back by swinging. Nine Sols hands
you internal injury instead, which heals back on its own as you attack, so a sloppy parry barely
costs anything. Turning ImperfectParryTakesRealDamage on closes that gap: a wide window to
land the deflect, a real price for missing it. Both halves are independent - use either alone.
| Setting | Default | |
|---|---|---|
Enabled |
true |
|
PerfectParryFrames |
12 |
Vanilla is 8. Fractions allowed. Below 8 is harder than stock. |
FramesPerSecond |
60 |
The unit for the above. The game's own check is time-based. |
ImperfectParryTakesRealDamage |
false |
Imperfect parries cost real health instead of internal injury. |
ImperfectParryDamageScale |
1 |
Multiplies that damage. |
IgnoreChipDamageRatio |
false |
Take the attack's full damage, not the chip-damage slice. |
The last three make the game harder - internal injury heals back by attacking, real health needs a potion. They pair naturally with a widened window: reward precision, punish sloppiness.
Unlike the mod this started from, the game's own timing check is left in place and only the window moves, so mash penalties and the QTE tutorial still behave normally.
Parries connect no matter which way you are facing.
| Setting | Default | |
|---|---|---|
IgnoreParryDirection |
true |
|
PlayerOnly |
true |
Off applies the same rule to enemies, which is not recommended. |
| Setting | Default | |
|---|---|---|
MinHoldSeconds |
0.2 |
Hold time before the counter triggers. Vanilla is 0.33333. |
MaxHoldSeconds |
0 |
How long it stays available. 0 means no limit. Vanilla is 1.4. |
HoldCounterIndefinitely |
true |
Keeps the counter releasable however long you hold. |
LoopChargeAnimation |
true |
Replays the charge clip so a held counter keeps animating. |
ChargeLoopRestartAt |
0 |
Normalized time each loop restarts from. |
ChargeAnimationName |
ParryCounterPrepare |
Only change if the game renames the clip. |
AlignParryCounterEnhance |
true |
Apply the same timings to ParryCounterEnhance's early-entry path. |
LogCounterDiagnostics |
false |
Noisy; for investigating only. |
Two things worth knowing.
The counter is entered out of the parry state - PlayerParryState.OnStateUpdate polls
Player.ParryCounterCheck every frame and ends the parry when it fires. So lowering
MinHoldSeconds shortens how long a held parry lasts before it converts. Tapping parry is
unaffected. Set it to 0.33333 for vanilla parry feel while keeping the rest.
With the Charge Chi jade equipped, LoopChargeAnimation re-fires the clip's animation events
each loop, including the one that grants chi - so holding the counter farms chi. Set
ChargeLoopRestartAt past that event, or turn the loop off, if you do not want that.
Stock, the jade only finishes a charge you were already holding when you perfect parry. This makes every perfect parry hand you a full charge, banked and glowing, waiting for your next attack.
| Setting | Default | |
|---|---|---|
Enabled |
true |
|
RequireJadeEquipped |
true |
Off gives you the effect without spending the jade slot. |
FireOnAttackPress |
true |
Off means press swings and release fires, the way charging normally works. |
BankSeconds |
0 |
How long a banked charge waits. 0 means until you use it. |
LogChargeBank |
false |
Noisy; for investigating only. |
All four are designed to run together and are tested that way. They also coexist with ParryCounterEnhance - Counter Charge Tuner detects it and aligns its timings.
No .NET SDK needed; the build uses the C# compiler that ships with Windows, against the game's own assemblies plus small hand-written stubs for BepInEx and Harmony.
cd build
.\build-pp.ps1 # or build-adp / build-cch / build-hfjEdit the $managed path at the top of a build script if Nine Sols is not on G:.
Each mod has a behaviour test suite that runs the compiled DLL against a transcription of the relevant game code, with the plugin's patch bodies wired in where Harmony would put them:
cd tests
.\run-tests-pp.ps1build/checkrefs.py resolves every external type and member reference of a built DLL against
the installed assemblies, comparing call arity - it catches the class of mistake that only
shows up as a MissingMethodException at runtime.
build/check-thunderstore.py validates the built zips against Thunderstore's upload rules -
required files at the zip root, manifest field formats, description length, dependency
strings, and the icon being exactly 256x256:
python build\check-thunderstore.py dist\*.zipPerfect Parry began from nozwock's mod of
the same name. That version forced IsAlwaysAccurate so every parry in the window counted as
perfect; this one is a rewrite that moves the window instead. Thanks to nozwock for the
original and for the idea. No license was included with the original package.
Counter Charge Tuner optionally aligns with ParryCounterEnhance by ForOne.
Everything in this repository is MIT licensed - see LICENSE.