As you know, in this series of games in each tavern, the player can only hire one new Hero per week. But…
Bug description: If there was no recruitment in the external tavern, then, starting from the 8th day, you can buy two heroes within two days.
For work, the disassembled file heroes4.exe from the latest official add-on "Winds of War" is used. The tavern operation procedure was found by the team earlier and is located at the address 4705E0. From the whole algorithm of her work, I am interested in the place in which it is determined whether it is possible to hire a Hero in the tavern at the moment, or if waiting is necessary. In the game, this is manifested by the output of the corresponding message:
From a programmatic point of view, this is a new window that is created in the game using the NewWindowCreate (720C80) function (the functions recognized in the disassembler are given their own names). There are several calls to this function in the procedure of the tavern, and the first challenger is a call to the address 470823. With the help of the debugger, I make sure that, in fact, this call creates the desired dialog box. The code that controls this call to NewWindowCreate is above at 470645:
00470638 call HeroesPricesInTavern_Lost
0047063D mov al, [ebp+48h] // 0 – ; 1 – ( 7 ).
00470640 add esp, 8
00470643 test al, al
00470645 jz loc_470866 // , 470823
I buy in the Hero's tavern, then set the "breakpoint" to write to the cell addressed to [ebp + 48h], after which I wait for 7 in-game days. When the tavern is "emptied", the debugger pops up at address 470DFF. Let's see the surrounding code:
00470DF0 TavernCountDays proc near
00470DF0 mov dl, [ecx+48h] // ECX+48h – :
DL=0 – ;
DL=1 – ( 7 )
00470DF3 xor eax, eax
00470DF5 cmp dl, al
00470DF7 jz short loc_470E06
00470DF9 cmp dword ptr [ecx+4Ch], 7 // [ECX+4Ch] - . 7 – .
00470DFD jl short loc_470E06
00470DFF mov [ecx+48h], al // (AL=0)
00470E02 mov [ecx+4Ch], eax //
00470E05 retn
00470E06
00470E06 loc_470E06:
00470E06
00470E06 inc dword ptr [ecx+4Ch] //
00470E09 retn
00470E09 TavernCountDays endp
This small procedure is used to check the number of days the tavern is closed for hire. Note that it is called for every tavern on the map every game day. What is causing the bug? For some reason, the program continues to count the number of days during which there was no Hero hiring in the tavern and after the week in which the tavern was closed (see the counter at 470E06). As a result, we get the following picture. Let the first recruitment of the Hero take place only on the eighth game day. At the entrance to the procedure, the value of the tavern availability flag at [ecx + 48h] will be "1" (the tavern is closed), and the value of the days counter at [ecx + 4Ch] will be "8". However, after the comparison at 470DF9, the control will receive a code at 470DFF, which reopens the tavern for hire! This will reset the day counter.and after hiring the second Hero, the algorithm will work out as the authors intended. But after two in-game weeks, the whole cycle will repeat itself.
The easiest way to fix the bug is to skip counting the days. Let the counter work only when the tavern is closed (which is more logical), and the rest of the time, set it to zero. This is achieved very simply - by changing the transition at address 00470DF7 to the end of the function:
00470DF5 cmp dl, al
00470DF7 jz short loc_470E09
Now all that remains is to patch the existing code. To do this, look at the original
and modified
options.
As you can see, the desired result can be achieved by replacing 0D with 10 at address 470DF8. A classic of the genre: patch a bug by replacing just one byte!