A Deadworks server plugin for Deadlock. Every player's four ability slots are replaced with abilities borrowed from other heroes, and pressing any ability key casts a random one of those four rather than the one under the key. The borrowed set is temporary: it is redrawn on a timer, so a match keeps changing instead of settling into one fixed loadout.
Server-side only. Players do not install anything.
- All four slots hold abilities from other heroes, drawn at runtime from whatever heroes the server actually has.
- Any ability key fires a random one of your four. The key you press does not decide which ability goes off.
- Passive abilities are skipped and re-rolled inside the same key press, so a key never wastes a press.
- The whole set is redrawn every 60 seconds by default.
- Ability points you have spent are carried across a redraw, so a slot you unlocked stays unlocked.
- Each player gets an explanation in their console and chat shortly after joining, since four unfamiliar abilities on keys that cast something else otherwise reads as a broken server.
Requires the .NET 10 SDK and a Deadworks install in your Deadlock folder.
dotnet build -c Release
The build copies GameDeadlockPlugin.dll into <Deadlock>\game\bin\win64\managed\plugins. If your
Steam library is elsewhere, point the build at it:
dotnet build -c Release -p:DeadlockDir="C:\Program Files (x86)\Steam\steamapps\common\Deadlock"
Then start deadworks.exe with no arguments.
A prebuilt pool ships in this repo (ability_roulette_pool.txt, 38 heroes) and the build copies it
next to the plugin, so a fresh install works straight away. It is only copied when the game does not
already have one, so it will not overwrite a pool you harvested yourself.
That prebuilt pool reflects one particular install at one patch. If your server has different heroes, or a patch renames abilities, rebuild it from your own game — once, on a live pawn:
/roulette_harvest
It takes a couple of minutes and rewrites ability_roulette_pool.txt next to the plugin. Later boots
load it from there. Heroes or abilities whose resources are missing are left out of the pool rather
than installed and left broken, and entries the current build no longer recognises are skipped on
load rather than treated as errors.
Add this to server.cfg, or managed timers stop ticking on an idle server and reshuffles never fire:
sv_hibernate_when_empty 0
| Command | Effect |
|---|---|
/roulette |
Current status: pool size, interval, your installed set |
/roulette_help |
Re-print the explanation |
/roulette_shuffle |
Redraw everyone now |
/roulette_restore |
Give everyone their original abilities back |
/roulette_harvest |
Build the ability pool (slow, needs a live pawn) |
Each also works from the server console with the dw_ prefix, e.g. dw_roulette_shuffle.
| ConVar | Default | Effect |
|---|---|---|
dw_roulette_enabled |
1 |
Master switch |
dw_roulette_shuffle_interval |
60 |
Seconds between redraws; 0 disables them |
dw_roulette_briefing |
1 |
Explain the mod to each player after they join |
dw_roulette_announce |
0 |
Print every single roll to the caster's chat (noisy in a real match) |
dw_roulette_shuffle_interval takes effect immediately, including 0 to stop reshuffling and a
later non-zero value to resume. No reload needed.
Three measured facts shape it, and each one cost a bug to learn:
Slots are strictly partitioned. A full 172-ability by 4-slot install test found that abilities from source slots 1-3 install only into slots 1-3, and ultimates only into slot 4 — 43 heroes, zero exceptions. The pool is split into two sets accordingly rather than shuffled as one list.
Ability points live on the ability entity, not the slot. Swapping a slot means
RemoveAbility + AddAbility, which destroys the entity holding the spent point, and the
replacement arrives with UpgradeBits = 0 — the slot silently goes back to locked. Every swap reads
UpgradeBits off the outgoing ability and writes it onto the new one.
A real client has no pawn when it connects. Measured against a live client: a human's pawn is
still null at OnClientFullConnect and hero initialization lands about 8 seconds later, while a bot
has its pawn at FullConnect within milliseconds. Anything sent at connect time therefore goes out
to a client still loading the map. The join briefing hangs off OnPawnHeroInitialized plus a delay
instead.
Also worth knowing if you work on this: practice bots have no ability points and never press ability keys, so testing with bots alone hides whole classes of bug.
MIT. See LICENSE.