SunBeam on 13/10/2013 at 08:53
Hello everyone.
Been busy lately updating DarkHook to work with NewDark version of the game. I noticed there is actually only
one executable for all games in the series, despite the file size. I'm guessing the different size is cause of file resources - icon, xml versioning, etc.. - although the caption in T1, TG and T2 states "Thief 2 Final 1.21". Back on track, I'll describe below how
DarkHook works now.
[
PRE-REQUISITES ]
First off, you will need to get
Cheat Engine from this location: [ (
http://cheatengine.org/downloads.php) ]
I'm currently using Cheat Engine 6.3. Although not accustomed with, you may find good uses for it in other games as well.
Next up, fetch the hotlinked archive: [ (
http://www.mediafire.com/download/ddiz7nbstc6nd20/DarkHook.zip) ] (mirror it please)
It contains two tables: one for T1, TG, T2 v1.21 - and - one for DromEd v1.21. The reason why there are two tables is simple: DromEd contains way too much functions than the game executable, so for the game release I had to "improvise" and rebuild missing functions or properties. Such as: physics, ai_aware_of_player, ai_sleep_all, ai_wake_all - and probably future more.
[
MECHANICS ]
To use the table, follow the steps below:
- open the game;
- open Cheat Engine;
- in CE, choose
File >
Open Process - OR - click the first top icon (a computer with a magnifying glass);
- once the Process List is up, find 'thief.exe', 'thief2.exe' OR 'DROMED.exe' in there;
- once found, double-click it - OR - click
Open;
Top part of CE should look
like this now: (note that the process ID will be different on your end - e.g.: 00000F88)
Inline Image:
http://i.imgur.com/46Do6wF.pngBased on your preference: T1, G, T2 - OR - DromEd, open the corresponding table from the provided archive via
File >
Open File - OR -
Ctrl+O - OR - clicking the second icon in CE's top part. Choose 'DarkHook.CT' and hit Open. Once that is done, the table data should appear in CE's bottom window:
Inline Image:
http://i.imgur.com/tpmlQdY.pngTo proceed, click
[Enable]. When you do that, two things can happen: the checkbox doesn't tick - meaning something wasn't found (at which point please notify me) - or everything is OK and the line will look like the below:
Inline Image:
http://i.imgur.com/PLTy1Mj.pngFor future reference, when you see the checkbox, everything is OK.
[Enable] is a script - you can open it selecting the line, then hitting Enter key, if curious what it contains - that uses patterns to identify locations in game's code for later use or just simple hooking. Once active, it will allow access to sub-sections:
[Coordinates] - here you will find Garrett's in-game coordinates (you have to be in a map);
[Scripts] - here you will find DarkHook script;
It's best you ignore the [Debug] section. Or if you want to fool around, be my guest :p
To activate DarkHook, tick
[Scripts], then tick
DarkHook. Everything should look like this now:
Inline Image:
http://i.imgur.com/1JU9cg2.png[
FEATURES ]
Get back in-game and use the following hotkeys for their effects:
F2: Will display the menu.
NUMPAD1: PlayersOnly.
The name of the option is taken from UnrealEngine's command, where, once activated, it would freeze entire world but the player. In DarkEngine, you may know it as the combo
ai_sleep_all/
ai_wake_all. I found that the aforementioned engine functions are a bit buggy - if you knock-out or kill an AI, then use ai_wake_all, they'll be back on their feet, although inactive. This might be a bit strange when you play the game, to find AIs that were taken care of staring at you :) ai_sleep_all sets the AIs state to 0 (Asleep), without storing previous state. ai_wake_all sets state to 3 (Normal), only for the Asleep AIs (state 0). This is where I intend to make some changes of logic: get each AI state through GetProperty, store it and when setting state through SetProperty, check stored AI states and restore their original ones instead of forcing them all to Normal for the Asleep ones.
-- UPDATE --
PlayersOnly works perfectly now! When activated, AI IDs and states are backed-up, then Asleep state (0) is set for all of them. When deactivated, AI states are restored based on the backed-up values. You should now be able to blackjack an AI, "pause" game while he begins to fall, then "unpause" to see him touch the ground.
Toggleable ON/OFF with the press of the key.
NUMPAD2: Fly.
This option makes use of two functions:
PhysSetGravity and
PhysSetBaseFriction. When active, it will 0 the gravity and set friction to 320.0f. When inactive, will restore original state, setting gravity to 1 and friction to 0.
Toggleable ON/OFF with the press of the key.
NUMPAD3: Ghost.
Option name taken from UE again. What it actually uses from DarkEngine is
physics, setting it to 0 or 1. When active, you will notice the message "Collisions: OFF" (meaning you can walk through doors, walls, or if you jump, fall through the map). I suggest you use Fly with it. When inactive, message will be "Collisions: ON". The
physics BOOL is checked in two locations: one which is generic, taking care of all objects AND one which only works for trees, doors, AIs but not walls, floors. If need be, I can adjust this to work to the player's advantage, thus allowing you to play normally without Fly, but without the ability to walk through walls.
In the game release, the checks were removed, so I had to find the spots, hook them and "plant" the missing code :)
Toggleable ON/OFF with the press of the key.
NUMPAD4: Super Speed.
Option will mimic the effects of the Speed Potion. You can play with the values if you want, by changing code inside DarkHook script here:
Inline Image:
http://i.imgur.com/qSR4gmr.pngNote that setting higher values will result in the player movement setting off, like an airplane :)
Toggleable ON/OFF with the press of the key.
NUMPAD5: God Mode.
This option makes use of a hook location (where your health is decremented) and two adjacent functions:
ObjGetMaxHitPoints and
ObjSetHitPoints. What they do is to acquire the max health points your character (Garrett) can have and set them accordingly. Option works like healing as well: say you got 2 bars left and want to just heal yourself - what you do is hit the key twice (hitting it once will enable God, but at the same time heal you to your maximum health; hitting the key again will disable God).
Toggleable ON/OFF with the press of the key.
NUMPAD6: Activate/Deactivate LockCheat Script
This feature should only be used in
Thief or
Thief Gold. Read below, in the LockCheat section!
NUMPAD7: LockCheat.
You may know this cheat. To work with it, one would have to open up
user.cfg and type it in there on a line, save file, load game, and all locks would be open. Well, now you can do this without having to type it in the .cfg file. Option works via two functions:
hash_set and
hash_delete. Their purpose is to fetch strings and hash them to values. Based on these values, corresponding options are activated/deactivated - such as these cheats.
Toggleable ON/OFF with the press of the key.
-- UPDATE --
In Thief or Thief Gold, LockCheat is not available. I've managed to get a workaround ready, so follow below steps:
- load up T1 or TG and target it in CE;
- activate
[Enable] script, then activate Scripts >
DarkHook;
- back in-game, hit NUMPAD6 to activate
LockCheat Script script - you'll see it becoming active in CE's list and
bOldThief address is set to
1 <- DO NOT TOUCH IT! (as in, change its value - it's done on NUMPAD6 key press);
- use NUMPAD7 as before to activate/deactivate the option;
Inside technical:
- when you enable LockCheat Script in T1/TG, you will see the message "LockCheat Script is enabled." in-game - so you know it'on;
- a secondary BOOL is used - bOldThief - that becomes 0 or 1, depending on
LockCheat Script's state (active or disabled);
- bOldThief is checked for in DarkHook, so: when it's 0, normal LockCheat is executed (for T2); when it's 1, the T1/TG version is executed;
- how do you know which one is active when you hit NUMPAD7? For T2, message is "LockCheat: ON" or "OFF"; for T1/TG, message will be "LockCheat: Active" or "Inactive";
- furthermore, since array pattern won't be found, you won't be able to activate it in T2 (it won't get enabled/ticked) :)
In T2, the check happens in
gen.osm. In T1/TG, most missions have their own .osm files. Therefore, you will have to do it like this:
- play a mission - hit NUMPAD6, to activate script, then NUMPAD7 to activate option;
- if you finish mission OR reload map, .osm gets reloaded - hit NUMPAD6 to deactivate script, and one more time to activate it (you will see status on screen), then use NUMPAD7 as you wish;
NUMPAD8: Infinite Item Timeout.
This feature can also be set in the .cfg files, but I've managed to go without it. Simple as is, once enabled you'll see: "Inventory Item Timeout: OFF", meaning all inventory items will remain on your screen indefinitely. Turning it off will show "Inventory Item Timeout: ON", restoring the timeout.
Toggleable ON/OFF with the press of the key.
NUMPAD9: AI Awareness.
Option will mimic the DromEd BOOL. This variable was used to check whether AI Sight and Listening casts would involve the player as well. It was removed in the game release, so I had to hook the 2 or 3 locations where this BOOL was used. Simply put - when enabled, you will see: "AI Awareness: OFF" - AIs will ignore you on sight or sound. Turning it off will show "AI Awareness: ON" - you'll be 'visible' again :)
Toggleable ON/OFF with the press of the key.
NUMPAD0: Set Weapon Amount to 100.
Option uses
g_pPlayerInventory pointer to fetch currently in-use weapon (located at 0x1C in this structure). If not NULL, will use
Set::cStoredProperty function to raise quota to 100. In short, select a weapon - sword and blackjack work too - and then hit the key. You'll see "100" displayed next to the weapon on your left screen side.
NUMPAD. (NUMPAD DEL): Set Item Amount to 100.
Option uses
g_pPlayerInventory pointer to fetch currently in-use item (located at 0x20 in this structure). If not NULL, will use
Set::cStoredProperty function to raise quota to 100. In short, select any item and then hit the key. You'll see "100" displayed next to it on your right screen side.
Values can be changed in the DarkHook script to suit your needs:
Inline Image:
http://i.imgur.com/vGVVgSd.pngJust alter the lines with "push 64" (100 in hexa).
F3: Will kill use of keys, in case you decide you don't want to use the features anymore or just want free numeric keys usage without turning on/off DarkHook options. In case you change your mind, hit the key again to restore use.
Note that the keys can easily be changed in the DarkHook script itself. If interested how, do let me know.
That's about it for now. Feel free to post feedback, as it helps perfecting it.
Best regards,
Sun
SunBeam on 13/10/2013 at 13:40
I've dug a little bit deeper in
ai_sleep_all /
ai_wake_all functions. I loaded up 'miss1.mis' in DromEd 1.21 and used
g_pAIManager and
_g_pAIModeProperty pointers to fetch number of AIs I got in map and getting to the AI I desired. Pictogramatically speaking, I've done the below:
Inline Image:
http://i.imgur.com/RR1Miqc.pngAs you can see, my target is a bowman - first on the left as you enter the courtyard in first mission. His ID is
155 and state he's in is Normal (if you do the counting, top to bottom, that is
3). The map has a total of
16 AIs. That is the correlation between what you see in DromEd and what you see in CE (what I've marked with arrows).
Now, I wanted to alter my AI's state. Therefore, I enabled
ai_aware_of_player so they couldn't see or hear me. Went behind my guy and whacked him. The result:
Inline Image:
http://i.imgur.com/POJxfJR.pngApparently, when you blackjack a person, its state turns to
5 (which, based on above explanation of 'Current mode', means
Dead). I think there is a different BOOL being set to determine if he's dead or just asleep.
What ai_sleep_all does is to set state to
0 for all AIs (Asleep). Their original state is not saved, so when you use ai_wake_all, what the function will do is to set state to
3 (Normal) to every AI, regardless of the state they were in before. Since you blackjacked the guy, he'll get up and stand in front of you doing nothing.
As previously explained, what we want is to allocate a spot (a cave) in which, when we call our modified ai_sleep_all function, we save their original states (AI_ID and AI_State). Once saved, we can then do what the original function did - set all the states to 0 (Asleep). Later on, when ai_wake_all is used, we won't set state to 3 (Normal). Instead, we pick up each AI_ID and their corresponding AI_State and set those instead ;) That way we do a perfect restore of each AI behavior.
I recommend watching below video directly on youtube, at 1080p resolution to be able to read the text.
[video=youtube;ip8rZM7bqvY]http://www.youtube.com/watch?v=ip8rZM7bqvY[/video]
Be back with more later.
BR,
Sun