// Copyright (c) 2026 StackAndPointer
// SPDX-License-Identifier: MIT
//
// Plants vs. Zombies x86 target:
// Board::Update at 0x415D40 receives Board* this in ECX.
include "SigilHook.ash"
uint64 g_boardUpdateHook = SH_INVALID_HANDLE;
void onBoardUpdate() {
const uint64 board = shReg(SH_REG_CX);
array<uint64> args(2);
args[0] = 1;
args[1] = board;
uint64 result = 0;
const uint8 status = shCallUsercall(
0x41B960,
"void",
"int,void*",
"usercall:ret=none;arg0=ecx;arg1=eax",
args,
result);
if (status != SH_OK) {
shLog("Board::AddSunMoney call failed: " + shStatusString(status));
}
// Call the relocated original Update after inserting the AddSunMoney call.
const uint64 original = shTrampoline(g_boardUpdateHook);
if (original == 0) {
shLog("Board::Update trampoline is unavailable");
shSkipOriginal();
return;
}
array<uint64> originalArgs(1);
originalArgs[0] = board;
const uint8 originalStatus = shCallUsercall(
original,
"void",
"void*",
"usercall:ret=none;arg0=ecx",
originalArgs,
result);
if (originalStatus != SH_OK) {
shLog("Board::Update original call failed: " + shStatusString(originalStatus));
}
shSkipOriginal();
}
void main() {
installAddSunMoneyHook();
g_boardUpdateHook = shHookUsercall(
0x415D40,
"void onBoardUpdate()",
"void:void*",
"usercall:ret=none;arg0=ecx");
if (!shIsValidHook(g_boardUpdateHook)) {
shLog("Board::Update hook failed: " + shLastError());
}
}
void unload() {
if (shIsValidHook(g_boardUpdateHook)) {
shDestroyHook(g_boardUpdateHook);
g_boardUpdateHook = SH_INVALID_HANDLE;
}
uninstallAddSunMoneyHook();
}
// Copyright (c) 2026 StackAndPointer
// SPDX-License-Identifier: MIT
//
// Plants vs. Zombies x86 target:
// Board::AddSunMoney at 0x41B960 receives theAmount in ECX and this in EAX.
include "SigilHook.ash"
uint64 g_addSunMoneyHook = SH_INVALID_HANDLE;
void onAddSunMoney() {
const uint64 amount = shReg(SH_REG_CX);
shSetReg(SH_REG_CX, amount * 0);
shKeepOriginal();
}
void installAddSunMoneyHook() {
g_addSunMoneyHook = shHookUsercall(
0x41B960,
"void onAddSunMoney()",
"void:int,void*",
"usercall:ret=none;arg0=ecx;arg1=eax");
if (!shIsValidHook(g_addSunMoneyHook)) {
shLog("Board::AddSunMoney hook failed: " + shLastError());
}
}
void uninstallAddSunMoneyHook() {
if (shIsValidHook(g_addSunMoneyHook)) {
shDestroyHook(g_addSunMoneyHook);
g_addSunMoneyHook = SH_INVALID_HANDLE;
}
}