I wanted to see just how poor it would be, and it was even worse than I imagined (and I imagined it being extremely poor). It can be seen in single-player on a map with a blademaster with Critical Strike. Not sure if it works on anything else. Trying it online will result in an even poorer result, where it is hard to notice if it's even working (and it is, hard as that is to believe by watching it).
It's not meant for serious use, just for testing. Bear this in mind if you try and use it. To use, extract all files and run inject2.exe. If the console window appears, and no message boxes appear with errors, it's on. You can then try it with a Blademaster hero with the Critical Strike ability learned (he must be selected, everything else is handled by the program; it would even work if you alt-tabbed out at that point). As for the "slow stops" in single-player, that's because of how long it takes for the Stop action to occur; the order is issued the instant an attack is prepared, before animation of the attack even begins. No orders are issued if the attack will result in a critical strike.
(Also note that this wasn't precisely using the method originally described as spamming Stop until a critical appears... instead, it stops a swing if it would result in a non-critical strike; spamming stop might actually work better for getting criticals online, but would completely immobilize you, making it somewhat worthless in my opinion)
Program is attached, but I see no harm in posting the source in case someone wishes to investigate further.
Edit: Works with Bash as well
Compile with BUILD_DLL defined.
Code:
#ifndef __TFTC_H__
#define __TFTC_H__
#include <windows.h>
#include <stdio.h>
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
DLL_EXPORT BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
#ifdef __cplusplus
}
#endif
#endif // __TFTC_H__
Code:
#include "tftc.h"
void writeByte(unsigned char* addr, unsigned char write) {
DWORD pOld;
VirtualProtect(addr, 1, PAGE_EXECUTE_READWRITE, &pOld);
*addr = write;
VirtualProtect(addr, 1, pOld, &pOld);
}
void writeDword(DWORD* addr, DWORD write) {
DWORD pOld;
VirtualProtect(addr, 4, PAGE_EXECUTE_READWRITE, &pOld);
*addr = write;
VirtualProtect(addr, 4, pOld, &pOld);
}
void writeWord(WORD* addr, WORD write) {
DWORD pOld;
VirtualProtect(addr, sizeof(WORD), PAGE_EXECUTE_READWRITE, &pOld);
*addr = write;
VirtualProtect(addr, sizeof(WORD), pOld, &pOld);
}
void writeFloat(float* addr, float write) {
DWORD pOld;
VirtualProtect(addr, 4, PAGE_EXECUTE_READWRITE, &pOld);
*addr = write;
VirtualProtect(addr, 4, pOld, &pOld);
}
void callPatch(DWORD from, DWORD to) {
DWORD write;
write = to - (from+5);
writeByte((unsigned char*)from, 0xE8);
writeDword( (DWORD*)((char*)from + 1), write);
}
void jmpPatch(DWORD from, DWORD to) {
DWORD write = to - (from+5);
writeByte((unsigned char*)from, 0xE9);
writeDword( (DWORD*)((char*)from + 1), write);
}
DWORD retn = 0;
void onNonCrit() {
asm(
"leave;"
"addl $1, 0x84(%esi);"
"pushl $0;"
"pushl $0;"
"pushl $0;"
"pushl $1;"
"pushl $0x000D0004;"
"pushl $0;"
"movl $0x6F37B830, _retn;"
"call *(_retn);"
"movl $0x6F1B24D9, _retn;"
"jmp *(_retn);"
);
}
void onAttach() {
jmpPatch(0x6F1B24D2, (DWORD)onNonCrit);
writeWord((WORD*)0x6F1B24D7, 0x9090);
}
DLL_EXPORT BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH: {
onAttach();
break;
}
case DLL_PROCESS_DETACH: {
break;
}
case DLL_THREAD_ATTACH: {
break;
}
case DLL_THREAD_DETACH: {
break;
}
}
return TRUE;
}