Arrows keep counting while held down
On current Windows, the arrow buttons for numeric values count one or two steps and then stop. Until now the only cure was the “Windows 98” compatibility mode. With the patch they simply keep counting.
For Anstoss 2 Gold · Original, GOG & 2007 CD
One small window, a few ticks: the arrow buttons keep counting, the World Cup, European Championship and final videos no longer crash the game, nothing freezes after Windows has run for weeks, the sound comes out of the right device, and if you like, the goal limits are lifted. The GOG and 2007 releases also get patch 1.01, the GOG release gets its dialogs back, and its copy protection no longer turns your save into a “Raubkopie” (pirated copy). No compatibility mode needed, and every change can be taken back.
Windows XP (SP3) to 11 · .NET Framework 4.0 or later · GPL-3.0 · user interface in German, like the game
On current Windows, the arrow buttons for numeric values count one or two steps and then stop. Until now the only cure was the “Windows 98” compatibility mode. With the patch they simply keep counting.
After winning the World Cup the game crashes, because Windows no longer knows the video format of WM.AVI, EM.AVI and FINALE.AVI. The patch skips the video and the game goes on. With an Indeo codec installed, the videos play as before.
A 3-second pause turns into weeks once Windows has been running for more than 231 ms. That comes sooner than you think: Windows Fast Startup keeps the uptime across a shutdown.
The game takes the last sound device it finds instead of the one set in Windows. With monitor speakers and a headset, the sound easily ends up on the wrong one. With the patch it comes out where Windows sends it.
The game computes the free space in 32 bits. On large disks the calculation overflows, and now and then saving brings up the warning that the disk is almost full, for no reason.
A club with players on loan can get a 31st player, who overwrites the data behind the squad. The patch also counts the actual players when checking “squad full?”.
The game switches the screen to 640×480 in a way that outlives a crash. With the patch, Windows restores the resolution itself as soon as the game ends. The GOG release already gets this right; there the tick box is greyed out.
On current Windows and under Wine, the club names in the cup draw video come out twice as wide, half as high and dotted, because the game expects a picture with 16 bits per pixel and gets 32. The patch asks for the picture in 16 bits explicitly.
The preseason calculation screen takes one of its two selections from memory it never cleared. If a large value is there, the screen stays invisible and the game waits for it. Seen under Wine; on Windows that memory is usually 0, the patch makes sure.
GOG sells the 2007 release, taken out of its copy protection. What is left of it still strikes: from the second season all clubs are called “Raubkopie” (pirated copy), players drop to strength 1, and ten self-checks of run.exe fail. With the patch all checks pass.
The run.exe of GOG and that of the 2007 CD are built from version 1.00. The patch brings program and data up to the official patch 1.01, which the 1999 release already has: player lists, new players and goalkeepers, counters, event texts and more.
In GOG’s RESDLL.dll, 342 dialogs lack their title bar and 68 controls their sunken frame, such as the choices that look like buttons. The patch gives them back the styles of 1999.
GOG’s DirectDraw wrapper (ddraw.dll) shows a black line along the right and bottom edge of the animations, such as the overhead kick in the main menu. The patch fills it with the picture. Offered only with GOG’s ddraw.dll in the game folder.
The game lets a team score only while it has fewer than 6 goals up to half-time and fewer than 10 after, and halves its chances from 7 goals on. The patch raises the limit to 15 and drops the brake.
A2G-Patch.exe.From anywhere. It offers its own folder and the installed CD and GOG releases; Durchsuchen … (Browse) picks another game folder.anstoss2.exeThe game file is changed directly. First, A2G-Patch puts a backup anstoss2.exe.vor-a2g-patch next to it. Once all patches are unticked again, the file is byte for byte as before and the backup goes.
run.exeThe same, with run.exe.vor-a2g-patch. The GOG patches also change RESDLL.dll (backup next to it) and the data files of patch 1.01; unticking restores them too. A file check in GOG Galaxy restores the original; then simply apply again.
run.exe (packed)The program code is only stored encrypted on disk. So A2G-Patch puts an msvfw32.dll into the game folder, which changes the code in memory at every game start. A2G-Patch changes the data files of patch 1.01 directly. Unticking all patches deletes the DLL again.
If the game is installed under “Program Files”, only an administrator may write there. A2G-Patch then offers to restart itself as administrator.
Some scanners react to an unsigned DLL in a game folder that has the name of a system DLL; malware uses the same trick. The DLL passes every call on to the real msvfw32.dll of Windows and only changes the game’s code. The source code is open in dll/msvfw32.c.
Each patch finds its places by the instructions around them. If it doesn’t find them exactly once, in the original or the patched state, A2G-Patch doesn’t offer it instead of blindly overwriting something. The tick boxes under “Nur für die GOG-Version” (GOG release only) are only there if the files are exactly GOG’s.
A DLL that doesn’t come from A2G-Patch is never touched. One from another version of A2G-Patch is replaced on Übernehmen (Apply).
Yes. The Spielmechaniken switch in A2G-Trainer lifts the goal limits while the trainer runs, and recognizes when A2G-Patch has already done so for good.
For the curious: what exactly happens in the machine code. The same patterns apply on disk (Patches.cs) and in memory (dll/msvfw32.c).
While a button is held, a thread posts one step to the window every 60 ms, but only while none is pending (+0xF4 == 0). It marks the step pending only after PostMessageA. On Windows NT the window is often faster, still finds a 0 while handling the step, and then the thread writes a 1 that is never taken down again. The patch marks the step pending before posting, in the same 41 bytes:
; before
mov eax,[msg] / mov ecx,[esi+1C] / push 0 / push 0 / push eax / push ecx / call ebx
mov eax,[esi+F4] / mov [esi+F0],60 / inc eax / mov [esi+F4],eax
; after
mov [esi+F4],1 / mov [esi+F0],60
mov eax,[msg] / mov ecx,[esi+1C] / push 0 / push 0 / push eax / push ecx / call ebx
nop / nop / nop / jmp next
The videos are Indeo 3.2, which current Windows no longer decodes. The game’s video player doesn’t check the result of AVIStreamGetFrameOpen and then reads through a NULL pointer. The patch adds the check and on NULL takes the path the game takes anyway for a missing file. The room for it comes from a more compact encoding of the instructions before, in the same 75 bytes:
push [edi] / call AVIStreamGetFrameOpen / test eax,eax / jnz ok
mov [edi],eax / jmp release ; skip the video
ok: mov [edi-8],eax
The limit becomes a fixed value, the halving is skipped. More than 15 isn’t possible: the game stores results and half-time scores as a 4-bit value per team.
limit: setg r8 / dec r32 / and r,-4 / add r,10 → setg r8 / mov r32,15 / nop …
brakes: jle (7E) → jmp (EB)
A reply sequence waits up to 3 seconds and compares the difference of two timeGetTime values with sign. Once Windows has run for more than 231 ms, the difference turns negative and Sleep gets a huge wait time. The patch compares without sign, at both places:
sub eax,[ebp+17C] / cmp eax,0BB8 / mov [ebp+17C],eax / jge (7D) → jae (73)
While enumerating, the game remembers the device with the most 3D buffers. Since Vista all report 0 there, on a tie the last one wins, and its GUID goes to DirectSoundCreate. With NULL, DirectSound takes the Windows default device:
push &guid (68 xx xx xx xx) → push esi / nop ×4 ; esi is 0 here
The game multiplies the values from GetDiskFreeSpaceA in 32 bits. On large disks the result is the free space modulo 4 GB and now and then falls below the threshold of 1.5 MB. The patch skips the warning; the game saves anyway:
cmp eax,177000 / jae (73) → jmp (EB)
In many places the game checks whether a squad is full only by a forecast in which a player on loan counts as gone. So a 31st player fits in and is written behind the 30 slots. The patch also checks the actual squad size, in the same 32 bytes of the function:
full = forecast >= 30 → full = forecast >= 30 or squad >= 30
The game calls ChangeDisplaySettingsA with flag 0, so the change isn’t tied to the process. With CDS_FULLSCREEN it applies to the game only, and Windows restores the resolution when the game ends, even after a crash:
mov [esi+1C8],ebx (field is 0 already) → mov byte [esp+4],4 / nop
The video draws the club names with GDI into a 128×32 CreateCompatibleBitmap and reads them out with GetBitmapBits as a 16-bit picture. On current Windows and under Wine that bitmap has 32 bits per pixel even in the game’s 16-bit mode, so the game gets the upper half with each pixel split in two. The patch sends the call to added code that fetches the picture with GetDIBits explicitly in 16 bits and converts 5-5-5 to 5-6-5 where needed:
call [GetBitmapBits] → call helper / nop
helper: GetDC / GetDIBits(…, 128×-32, 16 bit) / ReleaseDC / 5-5-5 → 5-6-5 if needed / ret C
The constructor of the calculation screen sets the selection “Ermittlung der Zahlen” (how the figures are computed) to 0, but not the “Darstellung” (display) one right next to it. With a large value, drawing the list reads past its end, the error vanishes inside the window call, and the screen stays half built and invisible. The patch clears both, in the same 11 bytes:
mov word [esi+10D48],0 / mov eax,esi → mov eax,esi / and dword [esi+10D46],0 / nop / nop
Eleven places call a signature routine and subtract the expected value; 0 means “original CD”. GOG replaced the subtraction with NOPs, so every check fails. The patch puts in the result of a passed check. In addition, five places check a CRC32 of run.exe on disk and five a CRC32 of their own code; A2G-Patch stores the matching values after every change.
call check / add esp,4 / nop ×5 → call check / add esp,4 / xor eax,eax / nop ×3
The changes of 1.01 were found by comparing with the 1.01 program and the 1999 release, and rewritten in assembler (gog/a2v101.S). The code goes into a new section .a2v101 at the end of run.exe; thirteen places jump into it or change, for example the cup draw loads its MoveList.dat from the game folder instead of the CD. For the 2007 CD, msvfw32.dll puts the same code into a memory block of its own and adjusts its jumps. The three data files of 1.01 are made from GOG’s and code of our own, without any files of the patch.
All dialogs are templates in RESDLL.dll. Compared with the 1999 file, GOG’s lacks WS_CAPTION, DS_MODALFRAME, WS_EX_CLIENTEDGE and a few more styles. The patch puts them back in place; the file keeps its size, and input and result are checked by SHA-256.
The animations play in a child window exactly as large as the picture; a thread blits them into its client rect on the primary surface. GOG’s wrapper shows that rect plus one column and one row of the primary surface, where nothing was ever drawn. The patch makes the window one pixel smaller each way and blits the whole picture into it, so the extra column and row show the picture’s last ones. With a correct DirectDraw the clipper would cut them off, hence only with GOG’s wrapper.
window: add ecx,edx / add eax,edi → add ecx,edx / dec ecx / add eax,edi / dec eax
blit: call GetClientRect(window, dest) → call CopyRect(dest, source)
msvfw32 isn’t a KnownDLL, so the copy in the game folder wins. All 47 exports jump on to the real DLL, which is loaded only on the first call. A thread waits until the unpacked code is in memory and then writes only the enabled patches. Built without the C runtime so that it loads on Windows XP too.