Re: z Baldur's Gate 3
Posted: Tue Aug 29, 2023 9:16 pm
how should i spawn an npc? i found who i want to spawn in the character_dict.json but im not sure what to do after
Community Cheat Tables of Cheat Engine
https://fearlessrevolution.com/
Thanks, was using the wrong tabbearyPanda wrote: ↑Tue Aug 29, 2023 9:26 pmDownload [Link], open it, go to the last tab (I think it's called savegame debugger) and there put in your safefile.
*ControlID
s are important here, as they are used for automatically loading the console commands, when the game is ready, and then registering the commands, again when they are ready to do that. I've manually edited the XML and changed the <ID>#</ID>
to a VERY high number, so it hopefully would never conflict with the autogenerated ones. The ID is an int64 (int32 on 32-bit systems?), so it can't be any high number print()
was executed, but is also useful for debugging. Change the VerboseLevel
setting to specify how much should be output to the logfile.onMemRecPostExecute
and MainForm.OnProcessOpened
CE global functions that are triggered when Memory Record have been enabled/disabled, and when a process have been opened/attached (i.e. attached to bg3).on*
event functions, such as opening/attaching to the game process.Code: Select all
local bg3Executable = { 'bg3_dx11.exe', 'bg3.exe' } -- Fallback if ExecutablePath+File doesn't exist.
----------------------
-- DEFAULT SETTINGS --
--vvvvvvvvvvvvvvvvvv--
bg3setting = {}
bg3setting['SettingsFile'] = 'bg3_cheatTable.settings.txt'
bg3setting['EnableLogging'] = true
bg3setting['LogFile'] = 'bg3_cheatTable.log'
bg3setting['ColorReady'] = '00FF00'
bg3setting['ColorPending'] = 'FF8000'
bg3setting['ColorNotReady'] = '0000FF'
bg3setting['Attach'] = true
bg3setting['AttachTimeout'] = 600 -- Set to zero to disable timeout. 600 = 10 minutes.
bg3setting['Reattach'] = true -- Otherwise will only attach once.
bg3setting['ReattachControlID'] = 200000001
bg3setting['LoadCommandsControlID'] = 100000001
bg3setting['RegisterCommandsControlID'] = 100000002
bg3setting['ExecutableAutoStart'] = false
bg3setting['ExecutablePath'] = ''
bg3setting['ExecutableFile'] = ''
bg3setting['executableParameters'] = '--skip-launcher'
bg3setting['VerboseLevel'] = 1 -- 0 = Never. 1 = OnFailure. 2 = OnSuccess. 4 = Debug
bg3setting['TimerInterval'] = 5000 -- Milliseconds between ticks.
--^^^^^^^^^^^^^^^^^^--
-- DEFAULT SETTINGS --
----------------------
--[[ READ SETTINGS from file
EvenLess
Parses settings from a file.
]]
for line in io.lines(bg3setting['SettingsFile']) do
--[[ Validate syntax of the read line.
Valid line CAN begin with zero or more spaces.
The property value can only consist of alphanumeric characters and under-
scores. All spaces before and after the property name will be stripped.
The property name and property value is separated with one "equal" (=)
character. Anything after the first "equal" (=) character, will be part of
the property value. This is on purpose to allow for more or less any
possible value. Can just trim() that as well, if wanted.
]]
if string.match(line, '^ *[a-zA-Z0-9_]') and string.find(line, '=') then
local position = string.find(line, '=')
local property = string.sub(line, 1, position-1):trim()
local value = string.sub(line, position+1)
bg3setting[property] = value
end
end
--[[ Write to logfile.
EvenLess
If EnableLogging is true, the supplied string will be written to the LogFile
specified in the settings.
]]
function writeLog(s)
if bg3setting['EnableLogging'] ~= true then return end
local logMessage = tostring(s)
local logFile = io.open(bg3setting['LogFile'], 'a')
local logTime = tostring(os.date('%Y-%m-%d %H:%M:%S'))
io.output(logFile):write(string.format("%s %s\n", logTime, logMessage))
io.close(logFile)
end
writeLog('Cheat Table opened.')
----------------------
-- GLOBAL FUNCTIONS --
-- AND VARIABLES --
--vvvvvvvvvvvvvvvvvv--
--[[ Convert string to boolean.
EvenLess
Lazy method. Any string is true, unless one of the specified ones.
]]
function toboolean(s)
local s2b = {}
s2b['0'] = false
s2b['no'] = false
s2b['off'] = false
s2b['false'] = false
if s2b[string.lower(tostring(s):trim())] ~= nil then return false end
return true
end
--[[ Add Compact View menu to Cheat Engine.
https://forum.cheatengine.org/viewtopic.php?p=5510752#5510752
]]
-- Text for menu item, so easier to change in one place, instead of 3.
compactMenuText = {}
compactMenuText['enable'] = 'Enable Compact View'
compactMenuText['disable'] = 'Disable Compact View'
-- Switches between Compact View being enabled/disabled.
function cycleFullCompact(sender, force)
local state = not(compactMenuItem.Caption == compactMenuText['enable'])
if force ~= nil then
state = not force
end
compactMenuItem.Caption = state and compactMenuText['enable'] or compactMenuText['disable']
getMainForm().Splitter1.Visible = state
getMainForm().Panel4.Visible = state
getMainForm().Panel5.Visible = state
end
-- Add the compact menu item to the Cheat Engine menu.
function addCompactMenu()
if compactMenuAlreadyExists then return end
local parent = getMainForm().Menu.Items
compactMenuItem = createMenuItem(parent)
parent.add(compactMenuItem)
compactMenuItem.Caption = compactMenuText['enable']
compactMenuItem.OnClick = cycleFullCompact
compactMenuAlreadyExists = 'yes'
end
addCompactMenu()
--[[ onMemRecPreExecute
https://github.com/cheat-engine/cheat-engine/blob/master/Cheat%20Engine/bin/celua.txt#L2271
EvenLess
Do something before enable/disable of CheatEntry.
]]
function onMemRecPreExecute(memoryRecord, newState)
-- placeholder
end
--[[ onMemRecPostExecute
https://github.com/cheat-engine/cheat-engine/blob/master/Cheat%20Engine/bin/celua.txt#L2271
https://forum.cheatengine.org/viewtopic.php?p=5712091#5712091 (ParkourPenguin)
EvenLess
Do something after enable/disable of CheatEntry.
]]
function onMemRecPostExecute(memoryRecord, newState, succeeded)
--print(string.format('DEBUG: "%s" [ID: %s] state changed.', memoryRecord.Description, memoryRecord.ID))
if succeeded == true and memoryRecord.Type == vtAutoAssembler and memoryRecord.Active == true then
-- A AutoAssembler script was successfully enabled.
--[[ Find Console Commands was enabled.
EvenLess
Things to do if "Find ConsoleCommands" were enabled.
]]
if memoryRecord.ID == bg3setting['LoadCommandsControlID'] then
-- Update Register Commands to reflect it's state.
local mRec = AddressList.getMemoryRecordByID(bg3setting['RegisterCommandsControlID'])
mRec.Description = 'Register Commands not ready.'
mRec.Color = tonumber(bg3setting['ColorNotReady'], 16)
-- Check if cmdList was populated and get number of commands (max. 3000).
local numberOfCommands = nil
local commandList = readPointer("cmdList")
if commandList ~= nil and commandList ~= 0 then
numberOfCommands = readInteger(commandList + 0x2C)
if numberOfCommands > 0 then
if numberOfCommands > 3000 then
numberOfCommands = 3000 -- just in case
end
end
end
commandList = readPointer(commandList + 0x20)
if commandList ~= nil and commandList ~= 0 then
-- cmdList was populated and more than 0 commands was found.
mRec.Description = string.format('Register >>%s<< Commands',
numberOfCommands)
mRec.Color = tonumber(bg3setting['ColorPending'], 16)
mRec.Active = true
end
end
if memoryRecord.ID == bg3setting['RegisterCommandsControlID'] then
if verbose >= 4 then
writeLog(string.format('Record "%s" [ID: %s] was activated.',
tostring(memoryRecord.Description),
tostring(memoryRecord.ID)))
end
local numberOfCommands = string.match(memoryRecord.Description, '>>(%d+)<<')
memoryRecord.Description = string.format('Registered >>%s<< Commands',
numberOfCommands)
memoryRecard.Color = tonumber(bg3setting['ColorReady'], 16)
end
end
if succeeded == true and memoryRecord.Type == vtAutoAssembler and memoryRecord.Active == false then
-- Do something when disabled.
end
end
--[[ MainForm.OnProcessOpened
https://github.com/cheat-engine/cheat-engine/blob/65b383535cba0325c25b95310137e13b409e75ae/Cheat%20Engine/bin/celua.txt#L377C14-L377C14
EvenLess
]]
MainForm.OnProcessOpened = function (openedPID, processHandle, caption)
--local openedPath = enumModules(openedPID)[1].PathToFile
--local openedFilePath = extractFilePath(openedPath)
--local openedFileName = extractFileName(openedPath)
--local openedProcess = process
local verbose = tonumber(bg3setting['VerboseLevel'])
if verbose >= 4 then
writeLog(string.format('Opened process "%s" [PID: %s].',
tostring(caption),
tostring(openedPID)))
end
local memoryRecord = AddressList.getMemoryRecordByID(bg3setting['LoadCommandsControlID'])
memoryRecord.Color = tonumber(bg3setting['ColorNotReady'], 16) -- Convert from hexadecimal to number.
if verbose >= 4 then
writeLog(string.format('getMemoryRecordByID(%s): %s',
tostring(bg3setting['LoadCommandsControlID']),
tostring(memoryRecord.Description)))
end
-- Verify that it was the bg3 executable that was opened/attached.
local actualPID = nil
for i = 1, #bg3Executable do
actualPID = getProcessIDFromProcessName(bg3Executable[i])
if verbose >= 4 then
writeLog(string.format("getProcessIDFromProcessName(%s): %s",
tostring(bg3Executable[i]),
tostring(actualPID)))
end
if actualPID ~= nil then break end
end
if openedPID == actualPID then
if verbose >= 4 then
writeLog(string.format("openedPID(%s) == actualPID(%s)",
tostring(openedPID),
tostring(actualPID)))
end
memoryRecord.Color = tonumber(bg3setting['ColorReady'], 16) -- Convert from hexadecimal to number.
memoryRecord.Active = true
memoryRecord.Description = "Console Commands loaded."
end
end
--^^^^^^^^^^^^^^^^^^--
-- GLOBAL FUNCTIONS --
-- AND VARIABLES --
----------------------
--[[ Timer. Check/execute things ad-hoc.
https://wiki.cheatengine.org/index.php?title=Tutorials:Lua:Setup_Auto_Attach
EvenLess
Continously checks/executes various tasks.
]]
local tickCounter = 0 -- Used to calculate runtime.
local attachCount = 0 -- Used to count number of times attached to game process.
local function bg3Timer_callback(timer) -- Tick callback function.
local runtime = bg3setting['TimerInterval'] * tickCounter
local attach = toboolean(bg3setting['Attach'])
local reattach = toboolean(bg3setting['Reattach'])
local timeout = bg3setting['AttachTimeout'] * 1000
local verbose = tonumber(bg3setting['VerboseLevel'])
--[[ Find the active game process, if any.
EvenLess
Attempt to find process ID for both bg3 executables (in their specified order).
If Game process is found, store the process ID and update settings with actual
ExecutablePath and ExecutableFile.
]]
local actualPID = nil
for i = 1, #bg3Executable do
-- Loop through the bg3Executables to get its PID, if the game is running.
actualPID = getProcessIDFromProcessName(bg3Executable[i])
if actualPID ~= nil then
if verbose >= 4 then
writeLog(string.format('Found game process "%s" [PID: %s].',
tostring(bg3Executable[i]),
tostring(actualPID)))
end
-- Get path for the found process and update settings, if they do not match.
local executablePath = enumModules(actualPID)[1].PathToFile
local executableFilePath = extractFilePath(executablePath)
local executableFileName = extractFileName(executablePath)
if bg3setting['ExecutablePath'] ~= executableFilePath then
bg3setting['ExecutablePath'] = executableFilePath
end
if bg3setting['ExecutableFile'] ~= executableFileName then
bg3setting['ExecutableFile'] = executableFileName
end
break
end
end
--[[ If the game process is NOT running.
EvenLess
]]
if actualPID == nil then
if verbose >= 4 then
writeLog("The game process isn't found. Waiting for the game to be started ...")
end
--[[ If ExecutableAutoStart is set to true.
if toboolean(bg3setting['ExecutableAutoStart']) == true then
-- AutoStart is enabled.
if fileExists(bg3setting['ExecutablePath'] .. bg3setting['ExecutableFile']) then
if verbose >= 2 then
writeLog(string.format('Attempting to run "%s".', tostring(bg3setting['ExecutablePath') .. tostring(bg3setting['ExecutableFile'])))
end
end
-- Start the game.
createProcess(bg3setting['ExecutablePath'] .. bg3setting['ExecutableFile'], bg3setting['ExecutableParameters'])
actualPID = getProcessIDFromProcessName(bg3setting['ExecutableFile'])
end
]]
end
--[[ If the game process IS running.
EvenLess
]]
if actualPID ~= nil then
-- Placeholder
end
--[[ If if the (actual) game process isn't opened/attached.
EvenLess
]]
local openedPID = getOpenedProcessID()
if actualPID ~= openedPID then
if verbose >= 4 then
writeLog(string.format("The game process [PID: %s] isn't opened/attached [PID: %s].",
tostring(actualPID),
tostring(openedPID)))
end
--[[ Update memoryRecords to reflect state.
EvenLess
]]
-- Update Register Commands to indicate "Not Ready".
local memoryRecord = AddressList.getMemoryRecordByID(bg3setting['RegisterCommandsControlID'])
--memoryRecord.Active = false
memoryRecord.disableWithoutExecute()
memoryRecord.Color = tonumber(bg3setting['ColorNotReady'], 16) -- Convert from hexadecimal to number.
memoryRecord.Description = 'Console Commands not loaded'
-- Update Console Commands to indicate "Not Ready".
local memoryRecord = AddressList.getMemoryRecordByID(bg3setting['LoadCommandsControlID'])
--memoryRecord.Active = false
memoryRecord.disableWithoutExecute()
memoryRecord.Color = tonumber(bg3setting['ColorNotReady'], 16) -- Convert from hexadecimal to number.
memoryRecord.Description = 'Console Commands not ready'
--[[ If the game process IS running.
]]
if actualPID ~= nil then
if attach == true then
if reattach == true or attachCount <= 0 then
openProcess(actualPID)
attachCount = attachCount + 1
if verbose >= 2 then
writeLog(string.format('Attached to "%s" [PID: %s].',
tostring(executableFileName),
tostring(openedPID)))
end
end
end
end
end
-- If "Find Console Commands" is enabled.
local memoryRecord = AddressList.getMemoryRecordByID(bg3setting['LoadCommandsControlID'])
if memoryRecord.Active == true then
if verbose >= 4 then
writeLog(string.format("getMemoryRecordByID(%s).Active == true",
tostring(bg3setting['LoadCommandsControlID'])))
end
local numberOfCommands = nil
local commandList = readPointer("cmdList")
if commandList ~= nil and commandList ~= 0 then
if verbose >= 4 then
writeLog("commandList ~= nil and commandList ~= 0")
end
numberOfCommands = readInteger(commandList + 0x2C)
if numberOfCommands > 0 then
if verbose >= 4 then
writeLog(string.format("numberOfCommands(%s) > 0", tostring(numberOfCommands)))
end
if numberOfCommands > 3000 then
numberOfCommands = 3000 -- just in case
end
end
commandList = readPointer(commandList + 0x20)
if commandList ~= nil and commandList ~= 0 then
local memoryRecord = AddressList.getMemoryRecordByID(bg3setting['RegisterCommandsControlID'])
memoryRecord.Description = string.format('Register >>%s<< Commands',
numberOfCommands)
memoryRecord.Color = tonumber(bg3setting['ColorReady'], 16)
memoryRecord.Active = true
end
end
end
tickCounter = tickCounter + 1
end
-- Create the timer and attach the callback function.
local bg3Timer = createTimer(getMainForm()) -- Create timer with the main form as its parent.
bg3Timer.Interval = bg3setting['TimerInterval'] -- Set timer interval.
bg3Timer.OnTimer = bg3Timer_callback -- Set timer tick callback function.
--[[ Initialize the speech engine.
EvenLess
For som reason speak() or speakEnglish() must be run at least once from the
Cheat Table LUA Script, otherwise calls in the AssemblerScripts doesn't work.
]]
speakEnglish('')
For anyone else looking to do this remove the status, not the passive and it will work. Very similar names.Oxiras wrote: ↑Tue Aug 22, 2023 12:08 pmTried this, it doesn’t work. You can only remove the passive added through AddPassive this way. The boon seems like a separate feature.oilnarak01 wrote: ↑Tue Aug 22, 2023 3:54 amnew entry "HAG_Hair_STR_Passive"
new entry "HAG_Hair_CON_Passive"
new entry "HAG_Hair_DEX_Passive"
new entry "HAG_Hair_INT_Passive"
new entry "HAG_Hair_WIS_Passive"
use command removepassive should do
Code: Select all
{$lua}
if syntaxcheck then return end
status = "HAG_HAIR_DEX"
[ENABLE]
RemoveStatusFromPlayer(status)
[DISABLE]
[DISABLE]
Awesome, it works, thank you so much.Base_N wrote: ↑Tue Aug 29, 2023 6:46 pmActually it did heh. So it is tied to a flag as I suspected after all. So here's the BrainDamage cleaner
My initial hypothesis seems to also be correct (as in that we're probably not adding some passives properly). It's possible that a lot of other passives are like that and when we just add them without their flags, there could be consequences if checks in the engine depend on the flag. Some reports of added passives appearing on the char sheet but not working properly could be exactly this. We should probably build a db of dependencies but it sounds no easy task as we would probably have to pull these from savegame files.Code: Select all
{$lua} if syntaxcheck then return end passive = { "CRE_BRAINDAMAGE_INT", "CRE_BRAINDAMAGE_WIS", "CRE_BRAINDAMAGE_CON" } flag = { "75d34f4d-9c2b-4a24-ae37-1f97ed7e3c5f", "af9dce87-4534-413d-9b54-2e8db6857216", "bf6318b5-50eb-44b6-80ae-4e451440df6e" } [ENABLE] ClearFlagOnPlayer(flag) RemoveStatusFromPlayer(passive) RemovePassiveFromPlayer(passive) [DISABLE]
PS. Also repacking with LSLib as you found out triggers the anti-tampering check. There's a checksum hash involved somewhere that needs to be adjusted.