[Update] Latest Cheat Table file for version 3.3 can be downloaded from here.
In my earlier post I explained how to alter the ruler designer in Crusader Kings 2 to remove the age restrictions. Many have pointed out that there are mods that already do this or that add new traits that can be picked up to just decrease the age. These discussions led me to think that the only advantage to my method is that, with a bit of extra tweaking, we could enable Iron Mode with achievements even if the ruler designer has been used. I sort of successfully tested this hypothesis and went a step further than that. The result is a pretty impressive. With this simple hack, everyone can now turn on the Ironman mode and have the Steam achievements enabled.
Nota bene, in my last post I did not research for alternatives that could achieve the same thing. I was simply not interested in that. Manipulating the game as I did was almost the entire interest that I had on the subject. The same applies to this post. I do not know and I honestly haven’t searched for alternative methods that allow someone to play with mods (and ruler designer) with achievements enabled.
I will do two things in this post. First, I will show you the quickest steps needed to achieve this in CK2 v2.1.6 by using the same Cheat Engine application. You can use any other memory hacker for this. Lastly, I will detail the steps I took in my investigation to reach to this solution, knowledge that will help you achieve similar things with any other game. Let’s dig in.
Quick steps on how to enable this in CK2 v2.1.6
1. Launch the game with your mods of choice.
2. Launch your memory hacker of choice and open the CKII process.
3. Look at the 4-byte value stored at 0x019F3F90. Copy that value. (This is a memory pointer).
4. Add 0x42 to that value (the memory pointer). The result will be the memory address of a value that tells the game if achievements are disabled or not.
5. Set to 1 the value stored at the memory address calculated in the previous step. If you click the Finish button in the ruler designer, you will have to set this value back to 1. Alternatively, some memory hackers allow you to “freeze” the value, so you only set it once to 1, freeze it, and no longer need to care about it. Or in other words, if the Ironmode button is not a green check mark, this value is zero and needs to be modified back to 1 to get the green check button.
For those of you using Cheat Engine, the program allows you to manually add a pointer directly, simplifying steps 3 to 5 . Simply click on “Add address manually” and select the following things as pictured below:
1. Open the game and Cheat Engine (CE).
2. In CE, go to File -> Open Process and choose CK2game.exe from the list.
3. In CE, go to File -> Open File to open the file you just downloaded. You will now see an entry in the list of addresses, like in the picture below. The description will be “Enable Achievements in Ironman Mode”.
4. For that new entry, double click on its value (under the Value column). It will be either 0 or 1, and you need to set it to 1.
5. For the same entry, click on the check-box in the Active column to have it checked.
6. You can now play your game with achievements enabled. CE should look like this:
This method has a chance to not work with future versions of the game, but that is unlikely since the pointer is stored in a global variable. Nonetheless, the next section explains how to correctly determine the right pointer regardless of the game version.
How did you find this out?
I needed a starting point. It appears that the game has a variable that says if the Ironman mode is selected or not. By simply searching for zeroes and ones after enabling and disabling the Ironman mode back and forth, I found the memory address of that variable. Then I set a memory access breakpoint on it to see which code reads or writes to that variable. By doing this and then toggling the Ironman mode once again, I find where the relevant code interested in this variable is. Surely, the logic on whether to enable or disable achievements has to be somewhere in that code. The steps I took thus far were very similar to the methods described in my previous post about hacking the ruler designer.
Once I had set that access breakpoint it started being hit about every second. It turns out that there is a UI thread running this code again and again, constantly checking if the Ironman mode should be enabled or not, and then updating the button seen on-screen to reflect that choice. Here is where the breakpoint is triggered and how the code looks like.
As you can see from the comments I wrote, if the user wanted to enable Ironman mode, there is an extra check that determines if achievements should be enabled or not. If achievements should be enabled (there’s no game alteration) then “push 01” instruction is executed, otherwise “push 03” instruction is executed. To understand what these are, think of the Ironman mode button as a tri-state checkbox, or a button that has 3 states. These “push”-es that you are seeing are simply updating that button state. Here is the mapping between pushed values and states:
1- Ironman mode enabled, with achievements
2- Ironman mode disabled
3- Ironman mode enabled, without achievements
Now, as a simple exercise, you can modify the “push 03” instruction to “push 02” and notice how the Ironman mode button will never say that achievements are not enabled, even if you are using mods or if you just designed a new ruler. However, this change doesn’t REALLY enable achievements, it just forces that button to look differently. If you start the game, you will not receive any achievement.
But this is more than a good starting point. We can see the function call above (“call 00E71640”) that checks if achievements should be enabled or not. Maybe we can find something in there, some common code or variables that are used in other parts of the game to tell if achievements should really be enabled or not. But before looking at the function, do notice that we can now easily get the address of the variable that tells if achievements should be enabled or not. The code above uses instruction “cmp [eax+42],bl” to test that value, so [eax+42] is the address we want. 0x42 is a static value, but EAX is not. EAX is returned by the function call previously mentioned, the one we’re going to look at right now.
Well, well, well, aren’t we lucky? This function straight away assigns EAX a static address and doesn’t modify it thereafter. “mov eax,[019F3F90]”, this is where the magical number from the previous section comes from. This is obviously a pointer to a global structure used throughout the game, and the global variable that indicates achievements are enabled or not is stored at offset 0x42 in this structure, based on the code we saw in the previous function. At this point, we really got lucky. We do not need to dig through the code anymore to see how and where that value is determined and modified. We can simply set that value ourselves every time it changes, which is not frequently. From my observations, this variable is modified by the game once when the game is launched, when it checks if there are any mods running, and secondly, this value is modified by the game once more whenever we click the “Finish” button in the ruler designer. To alter the game behavior, we simply need to override this value after the game sets it, which is what the “quick steps” section above is describing.
The solution we found is good enough. There may be some other triggers in the game code that will modify this variable throughout the game, but I haven’t found one yet, and it is also unlikely. What I have not tested is using a cheat command, as they are disabled in Ironman mode anyway. If the game would constantly update this value, or not even store it in memory, but simply compute it on demand, then we would have needed to dig a lot more into the code that actually performs these checks. But that’s not the case.
In the future the pointer may change, but since we already found all the relevant functions we need, we can just search for the assembly code in those functions to quickly find them and then look at the new pointer address. From CE this can be done from the Memory Viewer and then clicking on Search -> Find assembly code.
What could be done next? I guess I will be looking into enabling the console in Ironman mode (and still earn achievements when used).