Skip to content

Instantly share code, notes, and snippets.

@MikuAuahDark
Last active May 14, 2022 04:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MikuAuahDark/50a9c6f527f5383e00d13bf3adbe3b57 to your computer and use it in GitHub Desktop.
Save MikuAuahDark/50a9c6f527f5383e00d13bf3adbe3b57 to your computer and use it in GitHub Desktop.
Change PvZ Plant Names Without Modding
-- Cheat Engine Lua script to replace plant names in PvZ to names by Kobo Kanaeru.
-- Written by Miku AuahDark.
-- This file falls under Public Domain
-- To apply the plant names:
-- 1. Start PvZ and let it load until main menu
-- 2. Load 32-bit Cheat Engine and hook to PvZ process.
-- 3. Click Table -> Show Cheat Table Lua Script or press Ctrl+Alt+L
-- 4. Copy and paste this whole script then press "Execute Script"
-- 5. Cheat Engine may hang for a while, it's normal.
-- 6. After you regain control back to CE window, the script is done.
REPLACE_LIST = {
-- Note: Some items are ordered in specific way to prevent ambiguity when doing AOBScan.
{"Cherry Bomb", "Biji Meledak"},
{"Peashooter", "Kipli"},
-- Twin Sunflower first, then Sunflower
{"Twin Sunflower", "Dewa Dewi"},
{"Sunflower", "Dewi"},
-- "Giant Wall-nut" is NOT actually named by Kobo but added to prevent ambiguity!
{"Giant Wall-nut", "Beni Besar"},
{"Wall-nut", "Beni"},
{"Potato Mine", "Gilang"},
{"Snow Pea", "Es Kipli"},
{"Repeater", "Kiplipli"},
{"Puff-shroom", "Ucup"},
{"Grave Buster", "Ikhsan"},
{"Hypno-shroom", "Ojan"},
{"Scaredy-shroom", "Ujang"},
{"Ice-shroom", "James"}, -- Is it?
{"Doom-shroom", "Ihshaap"},
{"Lily Pad", "Dimas"},
{"Squash", "Candra"},
{"Threepeater", "Terkiplikipli"},
{"Tangle Kelp", "Tatang"},
{"Jalapeno", "Juna"},
{"Torchwood", "Garok"},
{"Spikeweed", "Syafiq Hidayat"},
{"Tall-nut", "Fahrul Gunawan"},
}
local function str2u16le(s)
local result = {}
for i = 1, #s do
result[#result + 1] = s:byte(i, i)
result[#result + 1] = 0
end
return result
end
local function intTab2Hex(t)
local result = {}
for _, v in ipairs(t) do
result[#result + 1] = string.format("%02X", v)
end
return table.concat(result, " ")
end
local function checkWStringValidity(ptr, strlen)
-- We can't really sure.
local wlen = readInteger(ptr + 16)
local capacity
if strlen < 8 then
capacity = readInteger(ptr + 20) == 7
else
-- Is it PO2? Not sure, assume 10x max
local capacityInt = readInteger(ptr + 20)
capacity = capacityInt >= wlen and capacityInt <= wlen * 10
end
return capacity and wlen == strlen
end
local function findWString(str)
local hex = intTab2Hex(str2u16le(str.."\0"))
local scan = AOBScan(hex, "+W", 0, 0)
if scan then
-- Iterate result
for i = 1, scan.Count do
local address = tonumber(scan[i - 1], 16)
-- Here's a complicated explanation. If the str length we're looking for
-- is less than 8, that means it's in short string mode.
if #str < 8 then
-- This means we're attempt to scan directly, check directly this address.
if checkWStringValidity(address, #str) then
return address, address
end
else
-- This means this string is referenced somewhere.
local reference = AOBScan(string.format("%02X %02X %02X %02X", table.unpack(dwordToByteTable(address))), "+W", 0, 0)
if reference then
for j = 1, reference.Count do
local baseAddress = tonumber(reference[j - 1], 16)
if checkWStringValidity(baseAddress, #str) then
return baseAddress, address
end
end
end
end
end
end
return nil
end
local scratchBuffer = allocateMemory(4096)
local scratchStart = scratchBuffer
print(string.format("Allocating temporary buffer at 0x%08X", scratchBuffer))
for _, v in ipairs(REPLACE_LIST) do
print("Replacing \""..v[1].."\" to \""..v[2].."\"")
-- Convert to UTF-16LE string hex with null terminator
local pointer, address = findWString(v[1])
if pointer then
print(string.format("Found string 0x%08X referenced in 0x%08X", address, pointer))
local byteTable = str2u16le(v[2].."\0")
if #v[2] >= readInteger(pointer + 20) then
print("Using temporary buffer")
-- Write to the scratch buffer first then write the pointer
writeBytes(scratchStart, byteTable)
writeInteger(pointer, scratchStart)
-- Write capacity
writeInteger(pointer + 20, #v[2])
scratchStart = scratchStart + #byteTable
else
-- Fits in std::wstring::capacity
local byteTable = str2u16le(v[2].."\0")
if #v[2] < 8 then
print("Using short string mode")
-- Obey short string optimization
writeBytes(pointer, byteTable)
-- Write capacity
writeInteger(pointer + 20, 7)
else
-- Write directly
writeBytes(address, byteTable)
end
-- Write the length
writeInteger(pointer + 16, #v[2])
end
else
print("Warning: Cannot replace \""..v[1].."\". Is it already patched?")
end
end
@ikr4-m
Copy link

ikr4-m commented May 13, 2022

Nice project sir

@ikr4-m
Copy link

ikr4-m commented May 14, 2022

Sedikit revisi, di bagian ini:

Load 32-bit Cheat Engine and hook to PvZ process

Untuk CE 64-bit, gua dah coba dan worked, kemungkinan di lapak lain gatau tapi di guanya sendiri work kok.

@MikuAuahDark
Copy link
Author

Saya cocokin dengan bitness gamenya. 32-bit karena PvZ itu 32-bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment