Hooks
ATTENTION: it's possible a hook won't work, due to the parameters not matching, if you find one, report it to the modders channel or the hoh2 wiki discussion in the Hammerwatch Discord.
Hooks are script functions that are called at specific moments. This way, you can insert code into the game.
They are specified in script files and tagged with the Hook specifier. They also must be placed within a namespace to avoid ambiguity between multiple mods.
The following is an example of such a file:
namespace MyTestMod
{
[Hook]
void BaseGameModeConstructor(BaseGameMode@ baseGameMode){
print("Hello World");
}
}
GetGeneratedAttributes
void GetGeneratedAttributes(PlayerStatsDetail@ stats, array<string>@ strArray, array<string>@ icons, bool isHandHeld)
PlayerDamagedActor
void PlayerDamagedActor(Player@ player, Actor@ actor, DamageInfo@ di)
PlayerDamageActor
void PlayerDamageActor(PlayerBase@ playerBase, Actor@ actor, DamageInfo@ damageInfo, Skills::Skill@ skill)
PlayerDamageActorNoWeapon
void PlayerDamageActorNoWeapon(PlayerBase@ playerBase, Actor@ actor, DamageInfo@ damageInfo)
PlayerDamage
void PlayerDamage(Player@ player, DamageInfo di)
PlayerDamageTaken
void PlayerDamageTaken(Player@ player, DamageInfo di)
PlayerInitialize
void PlayerInitialize(PlayerBase@ playerBase)
PlayerRefreshScene
void PlayerRefreshScene(PlayerBase@ playerBase)
Called each tick to make sure the player's unit scene is up to date. Useful if you want to add or attach any graphical element on top of the player unit.
PlayerRecordConstructor
void PlayerRecordConstructor(PlayerRecord@ record)
PickedCharacter
void PickedCharacter(PlayerRecord@ record)
CreateCharacter
void CreateCharacter(PlayerRecord@ record)
PlayerRecordSave
void PlayerRecordSave(PlayerRecord@ record, SValueBuilder &builder)
Called when a player record is being saved. Use builder to serialize data.
PlayerRecordLoad
void PlayerRecordLoad(PlayerRecord@ record, SValue@ data)
Called when a player record is being loaded. Use sval to deserialize data.
PlayerRecordRefreshModifiers
void PlayerRecordRefreshModifiers(PlayerRecord@ record)
LevelupCharacter
void LevelupCharacter(PlayerRecord@ record)
GameModeStart
void GameModeStart(AGameplayGameMode@ aGameplayGameMode, SValue@ save)
Called in the Campaign gamemode's Start() function. This allows to initialize things and additionally loading any saved data saved in the GameModeSave hook using the save parameter. This paramater is null if there is no save.
GameModePostStart
void GameModePostStart(AGameplayGameMode@ aGameplayGameMode)
Called in the Campaign gamemode's PostStart() function. This function is usually used to load things after all the unit behaviors have loaded in, and just before the player is ready to spawn.
GameModePreRenderFrame
void GameModePreRenderFrame(AGameplayGameMode@ aGameplayGameMode, int idt)
GameModeRenderFrame
void GameModeRenderFrame(AGameplayGameMode@ aGameplayGameMode, int idt, SpriteBatch& sb)
Called for each rendered frame before any UI is drawn. If you're looking for a hook called after the UI is drawn, use the GameModeRenderWidgets hook instead. You can use sb to render things to the screen. The idt parameter is the current time in milliseconds since the last update tick, which means the value will be between 0 and 33. Divide this value by 33.0f to get a normalized interpolation factor for animations.
GameModeSpawnPlayer
void GameModeSpawnPlayer(AGameplayGameMode@ aGameplayGameMode, PlayerRecord@ record)
GameModeSpawnPlayerCorpse
void GameModeSpawnPlayerCorpse(AGameplayGameMode@ aGameplayGameMode, PlayerRecord@ record)
BaseGameModeConstructor
void BaseGameModeConstructor(BaseGameMode@ baseGameMode)
Called when the Campaign gamemode is being constructed. Useful for initial setting up, for example to add new definitions for items, sets, shops, fountain effects, etc.
GameModeUpdatePaused
void GameModeUpdatePaused(BaseGameMode@ baseGameMode, int ms, GameInput& gameInput, MenuInput& menuInput)
GameModeUpdate
void GameModeUpdate(BaseGameMode@ baseGameMode, int ms, GameInput& gameInput, MenuInput& menuInput)
Called every tick from the Campaign gamemode's update function. Use dt to determine how many milliseconds have passed since the last tick. Note that ticks are different from rendered frames. Ticks typically run at a fixed rate of 30 FPS. You can use gameInput and menuInput here to get information about current controls.
LoadWidgetProducers
void LoadWidgetProducers(GUIBuilder@ builder)
Called when widget producers should be loaded. This allows you to initialize custom widget producers that can produce custom widgets. builder is where you would call AddWidgetProducer on to initialize the widget producer.
HUDConstructor
void HUDConstructor(HUD@ hud, GUIBuilder@ b)
TownRecordConstructor
void TownRecordConstructor(TownRecord@ townRecord)
TownRecordSave
void TownRecordSave(TownRecord@ townRecord, SValueBuilder& builder)
Called when the town record is being saved. Use builder to serialize data.
TownRecordLoad
void TownRecordLoad(TownRecord@ townRecord, SValue@ save)
Called when the town record is being loaded. Use sval to deserialize data.
TownRecordSpawnTown
void TownRecordSpawnTown(TownRecord@ townRecord)
TownRecordRefreshHeroTitles
void TownRecordRefreshHeroTitles(TownRecord@ townRecord)
TownRecordRefreshDonationTitles
void TownRecordRefreshDonationTitles(TownRecord@ townRecord)
At a specific point in the core game code, a line similar to the following is executed: Hooks::Call("NameOfHook", argument1, argument2, ...);
This function automatically looks up and executes any custom functions (Hooks) that have been registered with the matching name. Every hook is defined by its name (the first string argument in Hooks::Call) and its required arguments.
Crucially: For a custom hook function to execute, its name and arguments must exactly match the definition in the core game's Hooks::Call.
Example using the BaseGameModeConstructor Hook, let's look at the core game call for this example:
| Component | Description |
|---|---|
| Hooks::Call("BaseGameModeConstructor", @this); | the complete line inside BaseGameMode.as |
| BaseGameModeConstructor | This is the Hook Name you must use. |
| @this | This is the Required Argument. |
@this refers to the instance of the class the hook is called from, which in this case is the BaseGameMode class itself. To use this hook in a mod, you must create a function that matches the name and accepts a BaseGameMode object as its argument. Your custom hook function must be placed inside a namespace and be decorated with the [Hook] attribute.
namespace MyTestMod // Always use a namespace to prevent conflicts!
{
// The [Hook] attribute tells the game that this is a custom hook function.
// Without it, the function will not be recognized or executed.
[Hook]
void BaseGameModeConstructor(BaseGameMode@ baseGameMode) // Matches name and argument type!
{
// This code will run every time the BaseGameMode constructor executes
// Hooks::Call("BaseGameModeConstructor", @this);
print("Hello World from MyTestMod!");
}
}
Important Note on Arguments: If the arguments in your custom hook function do not match the arguments in the core game's Hooks::Call, the hook will either fail to execute silently or return an error in the console. Argument matching is mandatory.
Can you create Hooks yourself?
You should be able to yes, especially if you overwrite the base game files you can put hooks everywhere, although this is HIGHLY discouraged.
These files need to be updated every game update, although there have been talking about a community based hooks to make use of hooks in places we want them, there never have been made plans.