Last active
January 7, 2018 17:56
-
-
Save JakobBruenker/a2a8c1e9d7afb136e1963a92bca51507 to your computer and use it in GitHub Desktop.
Mirror's Edge TAS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
// Take care to call the Bindings as extended Key Press if the keys have an | |
// extended scan code | |
const WORD const BINDINGS[21] = { | |
0x11, // Move Forward | |
0x1F, // Move Backward | |
0x1E, // Strafe Left | |
0x20, // Strafe Right | |
0x39, // Up Action | |
0x2A, // Down Action | |
0x1D, // Walk | |
0x10, // Turn 90/180 | |
0x49, // Attack | |
0x12, // Interact | |
0x13, // Reaction Time | |
0x51, // Pick Up/Drop | |
0x21, // Weapon Zoom | |
0x0F, // Objectives/Time Trial Reset | |
0x32, // Hint | |
0x01, // Escape | |
0x48, // Up Arrow | |
0x50, // Down Arrow | |
0x4B, // Left Arrow | |
0x4D, // Right Arrow | |
0x1C, // Enter | |
}; | |
INPUT MakeKeyboardInput(WORD wScan) { | |
INPUT kip; | |
kip.type = INPUT_KEYBOARD; | |
kip.ki.time = 0; | |
kip.ki.wVk = 0; | |
kip.ki.dwExtraInfo = 0; | |
// use hardware scan code instead of virtual key code | |
kip.ki.dwFlags = KEYEVENTF_SCANCODE; | |
kip.ki.wScan = wScan; | |
return kip; | |
} | |
void SendKey(WORD wScan, int state) { | |
INPUT kip = MakeKeyboardInput(wScan); | |
switch (state) { | |
case 1: | |
kip.ki.dwFlags |= KEYEVENTF_KEYUP; | |
break; | |
case 0: | |
// fall through | |
default: | |
break; | |
} | |
SendInput(1, &kip, sizeof (INPUT)); | |
} | |
void SendKeyDown(WORD wScan) { | |
SendKey(wScan, 0); | |
} | |
void SendKeyUp(WORD wScan) { | |
SendKey(wScan, 1); | |
} | |
void SendKeyPress(WORD wScan) { | |
INPUT kip = MakeKeyboardInput(wScan); | |
kip.ki.dwFlags &= ~KEYEVENTF_KEYUP; | |
SendInput(1, &kip, sizeof (INPUT)); | |
kip.ki.dwFlags |= KEYEVENTF_KEYUP; | |
SendInput(1, &kip, sizeof (INPUT)); | |
} | |
void SendExtendedKeyPress(WORD wScan) { | |
INPUT kip = MakeKeyboardInput(wScan); | |
kip.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; | |
kip.ki.dwFlags &= ~KEYEVENTF_KEYUP; | |
SendInput(1, &kip, sizeof (INPUT)); | |
kip.ki.dwFlags |= KEYEVENTF_KEYUP; | |
SendInput(1, &kip, sizeof (INPUT)); | |
} | |
// Try to avoid using this as it can interfere with key presses and mouse | |
// movement | |
void SendClick(int button) { | |
INPUT mip; | |
mip.type = INPUT_MOUSE; | |
mip.mi.dx = 0L; | |
mip.mi.dy = 0L; | |
mip.mi.time = 0; | |
mip.mi.mouseData = 0; | |
mip.mi.dwExtraInfo = 0; | |
WORD dwFlagsDown; | |
WORD dwFlagsUp; | |
switch (button) { | |
case 1: | |
dwFlagsDown = MOUSEEVENTF_RIGHTDOWN; | |
dwFlagsUp = MOUSEEVENTF_RIGHTUP; | |
break; | |
case 0: | |
// fall through | |
default: | |
dwFlagsDown = MOUSEEVENTF_LEFTDOWN; | |
dwFlagsUp = MOUSEEVENTF_LEFTUP; | |
break; | |
} | |
mip.mi.dwFlags = dwFlagsDown; | |
SendInput(1, &mip, sizeof(INPUT)); | |
mip.mi.dwFlags = dwFlagsUp; | |
SendInput(1, &mip, sizeof(INPUT)); | |
} | |
// Try to avoid using this as it can interfere with key presses and mouse | |
// movement | |
void SendLeftClick() { | |
SendClick(0); | |
} | |
// Try to avoid using this as it can interfere with key presses and mouse | |
// movement | |
void SendRightClick() { | |
SendClick(1); | |
} | |
void SendMouseMove(int dx, int dy) { | |
INPUT mip; | |
mip.type = INPUT_MOUSE; | |
mip.mi.dx = (LONG)dx; | |
mip.mi.dy = (LONG)dy; | |
mip.mi.time = 0; | |
mip.mi.mouseData = 0; | |
mip.mi.dwExtraInfo = 0; | |
mip.mi.dwFlags = MOUSEEVENTF_MOVE; | |
SendInput(1, &mip, sizeof(INPUT)); | |
} | |
void StartForward() { | |
SendKeyDown(BINDINGS[0]); | |
} | |
void StopForward() { | |
SendKeyUp(BINDINGS[0]); | |
} | |
void StartBackward() { | |
SendKeyDown(BINDINGS[1]); | |
} | |
void StopBackward() { | |
SendKeyUp(BINDINGS[1]); | |
} | |
void StartLeft() { | |
SendKeyDown(BINDINGS[2]); | |
} | |
void StopLeft() { | |
SendKeyUp(BINDINGS[2]); | |
} | |
void StartRight() { | |
SendKeyDown(BINDINGS[3]); | |
} | |
void StopRight() { | |
SendKeyUp(BINDINGS[3]); | |
} | |
void Jump() { | |
SendKeyPress(BINDINGS[4]); | |
} | |
void StartDown() { | |
SendKeyDown(BINDINGS[5]); | |
} | |
void StopDown() { | |
SendKeyUp(BINDINGS[5]); | |
} | |
void StartWalk() { | |
SendKeyDown(BINDINGS[6]); | |
} | |
void StopWalk() { | |
SendKeyUp(BINDINGS[6]); | |
} | |
void Turn() { | |
SendKeyPress(BINDINGS[7]); | |
} | |
void Attack() { | |
SendExtendedKeyPress(BINDINGS[8]); | |
} | |
void Interact() { | |
SendKeyPress(BINDINGS[9]); | |
} | |
void Reaction() { | |
SendKeyPress(BINDINGS[10]); | |
} | |
void PickUp() { | |
SendExtendedKeyPress(BINDINGS[11]); | |
} | |
void Zoom() { | |
SendKeyPress(BINDINGS[12]); | |
} | |
void Objectives() { | |
SendKeyPress(BINDINGS[13]); | |
} | |
void StartHint() { | |
SendKeyDown(BINDINGS[14]); | |
} | |
void StopHint() { | |
SendKeyUp(BINDINGS[14]); | |
} | |
void Esc() { | |
SendKeyPress(BINDINGS[15]); | |
} | |
void UpArrow() { | |
SendExtendedKeyPress(BINDINGS[16]); | |
} | |
void DownArrow() { | |
SendExtendedKeyPress(BINDINGS[17]); | |
} | |
void LeftArrow() { | |
SendExtendedKeyPress(BINDINGS[18]); | |
} | |
void RightArrow() { | |
SendExtendedKeyPress(BINDINGS[19]); | |
} | |
void Enter() { | |
SendKeyPress(BINDINGS[20]); | |
} | |
void Action(char* action) { | |
if (!strncmp("fd", action, 2)) { | |
StartForward(); | |
puts("fd"); | |
} else if (!strncmp("fu", action, 2)) { | |
StopForward(); | |
puts("fu"); | |
} else if (!strncmp("bd", action, 2)) { | |
StartBackward(); | |
puts("bd"); | |
} else if (!strncmp("bu", action, 2)) { | |
StopBackward(); | |
puts("bu"); | |
} else if (!strncmp("ld", action, 2)) { | |
StartLeft(); | |
puts("ld"); | |
} else if (!strncmp("lu", action, 2)) { | |
StopLeft(); | |
puts("lu"); | |
} else if (!strncmp("rd", action, 2)) { | |
StartRight(); | |
puts("rd"); | |
} else if (!strncmp("ru", action, 2)) { | |
StopRight(); | |
puts("ru"); | |
} else if (!strncmp("jp", action, 2)) { | |
Jump(); | |
puts("jp"); | |
} else if (!strncmp("dd", action, 2)) { | |
StartDown(); | |
puts("dd"); | |
} else if (!strncmp("du", action, 2)) { | |
StopDown(); | |
puts("du"); | |
} else if (!strncmp("wd", action, 2)) { | |
StartWalk(); | |
puts("wd"); | |
} else if (!strncmp("wu", action, 2)) { | |
StopWalk(); | |
puts("wu"); | |
} else if (!strncmp("tp", action, 2)) { | |
Turn(); | |
puts("tp"); | |
} else if (!strncmp("ap", action, 2)) { | |
Attack(); | |
puts("ap"); | |
} else if (!strncmp("ip", action, 2)) { | |
Interact(); | |
puts("ip"); | |
} else if (!strncmp("rp", action, 2)) { | |
Reaction(); | |
puts("rp"); | |
} else if (!strncmp("pp", action, 2)) { | |
PickUp(); | |
puts("pp"); | |
} else if (!strncmp("zp", action, 2)) { | |
Zoom(); | |
puts("zp"); | |
} else if (!strncmp("op", action, 2)) { | |
Objectives(); | |
puts("op"); | |
} else if (!strncmp("hd", action, 2)) { | |
StartHint(); | |
puts("hp"); | |
} else if (!strncmp("hu", action, 2)) { | |
StopHint(); | |
puts("hu"); | |
} else if (!strncmp("ep", action, 2)) { | |
Esc(); | |
puts("ep"); | |
} else if (!strncmp("ua", action, 2)) { | |
UpArrow(); | |
puts("ua"); | |
} else if (!strncmp("da", action, 2)) { | |
DownArrow(); | |
puts("da"); | |
} else if (!strncmp("la", action, 2)) { | |
LeftArrow(); | |
puts("la"); | |
} else if (!strncmp("ra", action, 2)) { | |
RightArrow(); | |
puts("ra"); | |
} else if (!strncmp("en", action, 2)) { | |
Enter(); | |
puts("en"); | |
} else if (!strncmp("wt", action, 2)) { | |
// wait | |
} else if (!strncmp("#", action, 1)) { | |
// comment | |
} else if (!strncmp("--", action, 2)) { | |
// comment | |
} else if (!strncmp("//", action, 2)) { | |
// comment | |
} else if (!strncmp("/*", action, 2)) { | |
// comment | |
} else { | |
printf("Warning: unrecognized action \"%s\"\n", action); | |
} | |
} | |
// tries to wait 100us less than msWait specifies, just to leave some time for | |
// overhead | |
void Wait(int msWait, LARGE_INTEGER freq) { | |
LARGE_INTEGER startTime, endTime, tmsElapsed; | |
QueryPerformanceCounter(&startTime); | |
if (msWait > 20) { | |
Sleep(msWait - 20); | |
} | |
int tmsWait = 10 * msWait; | |
do { | |
QueryPerformanceCounter(&endTime); | |
tmsElapsed.QuadPart = endTime.QuadPart - startTime.QuadPart; | |
tmsElapsed.QuadPart *= 10000; | |
tmsElapsed.QuadPart /= freq.QuadPart; | |
} while (tmsElapsed.QuadPart < tmsWait - 1); | |
} | |
int main(int argc, char* argv[]) { | |
const char* fileName; | |
if (argc > 1) { | |
fileName = argv[1]; | |
} else { | |
puts("Usage"); | |
exit(EXIT_FAILURE); | |
} | |
LARGE_INTEGER freq; | |
QueryPerformanceFrequency(&freq); | |
LPCSTR windowTitle = "Mirror's Edge™"; | |
HWND window = FindWindow(NULL, windowTitle); | |
SetForegroundWindow(window); | |
WINDOWPLACEMENT windowPlacement; | |
windowPlacement.length = sizeof (WINDOWPLACEMENT); | |
GetWindowPlacement(window, &windowPlacement); | |
windowPlacement.showCmd = SW_RESTORE; | |
SetWindowPlacement(window, &windowPlacement); | |
Sleep(100); // Mouse movements might not work without this Sleep | |
FILE* fp; | |
char buffer[100]; | |
int wait; | |
char action[2]; | |
int dx; | |
int dy; | |
int ret; | |
fp = fopen(fileName, "r"); | |
while (fgets(buffer, 100, fp)) { | |
if (buffer[0] == '>') { | |
printf("%s", buffer); | |
} else if (buffer[1] != '\0') { | |
ret = sscanf(buffer, "%d %s %d %d", &wait, action, &dx, &dy); | |
switch (ret) { | |
case 2: | |
Wait(wait, freq); | |
Action(action); | |
break; | |
case 4: | |
Wait(wait, freq); | |
SendMouseMove(dx, dy); | |
break; | |
default: | |
ret = sscanf(buffer, "%s %d %d", action, &dx, &dy); | |
switch (ret) { | |
case 1: | |
Action(action); | |
break; | |
case 3: | |
SendMouseMove(dx, dy); | |
break; | |
default: | |
// Everything that doesn't look right will be skipped | |
// Except for comments | |
if (strncmp("#", action, 1) && | |
strncmp("--", action, 2) && | |
strncmp("//", action, 2) && | |
strncmp("/*", action, 2)) { | |
printf("Warning: skipped line %s", buffer); | |
} | |
continue; | |
} | |
break; | |
} | |
} | |
} | |
fclose(fp); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment