Como sabes, en esta serie de juegos en cada taberna, el jugador solo puede contratar un nuevo héroe por semana. Pero…
Descripción del error: si no hubo reclutamiento en la taberna externa, entonces, a partir del octavo día, puedes comprar dos héroes en dos días.
El archivo heroes4.exe desmontado del último complemento oficial "Winds of War" se utiliza para trabajar. El procedimiento de operación de la taberna fue encontrado por el equipo anteriormente y está ubicado en la dirección 4705E0. De todo el algoritmo de su trabajo, me interesa el lugar en el que se determina si es posible contratar un Héroe en la taberna en este momento, o si es necesario esperar. En el juego, esto se manifiesta por la salida del mensaje correspondiente:
Desde un punto de vista programático, esta es una nueva ventana que se crea en el juego usando la función NewWindowCreate (720C80) (las funciones reconocidas en el desensamblador reciben sus propios nombres). Hay varias llamadas a esta función en el procedimiento de la taberna, y el primer retador es una llamada a la dirección 470823. Con la ayuda del depurador, me aseguro de que, de hecho, esta llamada crea el cuadro de diálogo deseado. El código que controla esta llamada a NewWindowCreate está arriba en 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
Compro en la taberna del héroe, luego establezco el "punto de interrupción" para escribir en la celda dirigida a [ebp + 48h], después de lo cual espero 7 días en el juego. Cuando la taberna se "vacía", el depurador aparece en la dirección 470DFF. Veamos el código circundante:
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
Este breve procedimiento verifica el número de días que la taberna está cerrada para alquiler. Tenga en cuenta que se llama para todas las tabernas del mapa todos los días de juego. ¿Qué está causando el error? Por alguna razón, el programa continúa contando el número de días durante los cuales el héroe no fue contratado en la taberna y después de la semana en que la taberna estuvo cerrada (ver el mostrador en 470E06). Como resultado, obtenemos la siguiente imagen. Deja que el primer reclutamiento del héroe tenga lugar solo en el octavo día de juego. A la entrada del procedimiento, el valor de la bandera de disponibilidad de la taberna en [ecx + 48h] será igual a "1" (la taberna está cerrada), y el valor del contador de días en [ecx + 4Ch] será igual a "8". Sin embargo, después de la comparación en 470DF9, el control recibirá un código en 470DFF, ¡que reabrirá la taberna para alquilar! Esto restablecerá el contador de días.y después de contratar al segundo héroe, el algoritmo ya funcionará, como pretendían los autores. Pero después de dos semanas en el juego, todo el ciclo se repetirá.
La forma más sencilla de corregir el error es dejar de contar los días. Deje que el mostrador funcione solo cuando la taberna esté cerrada (lo cual es más lógico), y el resto del tiempo, póngalo en cero. Esto se logra de manera muy simple cambiando la transición en la dirección 00470DF7 al final de la función:
00470DF5 cmp dl, al
00470DF7 jz short loc_470E09
Ahora todo lo que queda es parchear el código existente. Para hacer esto, mire el original
y modificado
opciones.
Como puede ver, el resultado deseado se puede lograr reemplazando 0D con 10 en la dirección 470DF8. Un clásico del género: ¡corrige un error reemplazando solo un byte!