gvargas wrote: ↑Sun Mar 12, 2017 2:43 am
Guys I have a question, is it possible to make a script that mods ALL the 1000 items in the Container at once? I used to do that with a multiline code in the GameGenie but here I have no idea how, it would be nice to be able to mod the Quality and other values of all the items in the container at once and not have to highlight each one, we know the quality address of the first item in the container is 14149C5A6 and the second one is 14149C5DA so the difference is +34 between each items, if someone can help make a script that runs 1000 times modding those addresses skipping +34 for the next one it would be great! Sorry if for some reason I didn't make myself clear but I'm just getting the hang of it...
Yes! The "right" way is to script things the way Cielson does. Since you've mentioned Atelier Sophie earlier, Shinkansen's table is the best example I can think of for this situation. Below is his item script (all the options just decide which parts of this script are used.)
Code: Select all
[ENABLE]
label(itemstats_savedAOB)
label(itemstats_returnhere)
label(itemstats_originalcode)
label(itemstats_exit)
label(itemstats_update_exit)
label(itemstats_set_exit)
label(itemstats_qualityset_exit)
label(itemstats_synthesisset_exit)
label(itemstats_sizeset_exit)
label(itemstats_countset_exit)
label(itemstats_quantityset_exit)
registersymbol(itemstats_savedAOB)
//0070C6A3 - 56 - push esi
//0070C6A4 - 8B 75 08 - mov esi,[ebp+08]
//0070C6A7 - 66 8B 46 02 - mov ax,[esi+02]
// Accesses Item ID
//0070C6AB - 66 3B 41 02 - cmp ax,[ecx+02]
//0070C6AF - 74 07 - je 0070C6B8
//0070C6B1 - 32 C0 - xor al,al
//0070C6B3 - 5E - pop esi
aobscan(itemstats_searchedAOB, 66 8B 46 02 66 3B 41 02 74 07)
alloc(itemstats_newmem, 2048, itemstats_searchedAOB)
alloc(itemstats_temp1, 4, itemstats_searchedAOB)
alloc(itemstats_temp2, 4, itemstats_searchedAOB)
alloc(itemstats_temp3, 4, itemstats_searchedAOB)
alloc(itemstats_temp4, 4, itemstats_searchedAOB)
itemstats_newmem:
mov [itemstats_temp1], eax
mov [itemstats_temp2], ebx
mov [itemstats_temp3], ecx
mov [itemstats_temp4], edx
cmp dword ptr [itemstats_update_enable], #0
je itemstats_update_exit
mov [itemstats_basepointer], ecx
itemstats_update_exit:
cmp dword ptr [itemstats_set_enable], #0
je itemstats_set_exit
itemstats_set_exit:
cmp dword ptr [itemstats_qualityset_enable], #0
je itemstats_qualityset_exit
mov [ecx+4], (float)999
itemstats_qualityset_exit:
cmp dword ptr [itemstats_synthesisset_enable], #0
je itemstats_synthesisset_exit
mov word ptr [ecx+16], #8
itemstats_synthesisset_exit:
cmp dword ptr [itemstats_sizeset_enable], #0
je itemstats_sizeset_exit
mov word ptr [ecx+18], #2048
itemstats_sizeset_exit:
cmp dword ptr [itemstats_countset_enable], #0
je itemstats_countset_exit
mov word ptr [ecx+1a], #999
itemstats_countset_exit:
cmp dword ptr [itemstats_quantityset_enable], #0
je itemstats_quantityset_exit
mov word ptr [ecx+22], #99
itemstats_quantityset_exit:
mov eax, [itemstats_temp1]
mov ebx, [itemstats_temp2]
mov ecx, [itemstats_temp3]
mov edx, [itemstats_temp4]
itemstats_originalcode:
db 66 8B 46 02 66 3B 41 02
//mov ax,[esi+02]
//cmp ax,[ecx+02]
itemstats_exit:
jmp itemstats_returnhere
itemstats_searchedAOB:
itemstats_savedAOB:
jmp itemstats_newmem
nop
nop
nop
itemstats_returnhere:
[DISABLE]
itemstats_savedAOB:
db 66 8B 46 02 66 3B 41 02
//mov ax,[esi+02]
//cmp ax,[ecx+02]
unregistersymbol(itemstats_savedAOB)
dealloc(itemstats_newmem)
dealloc(itemstats_temp1)
dealloc(itemstats_temp2)
dealloc(itemstats_temp3)
dealloc(itemstats_temp4)
Note that it uses symbols registered and memory allocated by the "Enable this first" box though, which is why it has to be enabled first to begin with.
If you can understand the code above at all, then use that method. I say this because I can barely read it well enough to understand what it's doing, and I assume if you're asking you don't know the language it uses either; but we can still do it, just... not quite so neatly or easily. If you're serious about using cheat engine to do whatever you can think of, though, learning how to use the code above (you can check Cielos's code out too by right clicking his headers and clicking Change Script) is a necessity.
But for container codes, or most batch RPG codes in general really, you can uh... cheat clumsily, which is how I made my initial "By a narb" version.
Code: Select all
--First we use a code to get the Address List
local al = getAddressList()
--This is just to make a header called Basket Inventory to sort our codes into; I like sorting things.
local base = al.createMemoryRecord()
base.Description = "Basket Inventory Quality"
base.IsGroupHeader = true
base.options = "[moHideChildren, moRecursiveSetValue]"
--This is defining the address (It's a pointer; this address is where the basket "starts". How to get that is a seperate conversation.)
local basketaddr = "A18.exe+014D57C8"
--This is to create a slot "number" for the description to use to number the container slots.
local bsktslotnum = 1
--This line is the offset from the initial "Basket" pointer. In this example, it's exactly +4
--from the start of the first basket slot that holds the Quality, so it's 0x4. This is something you find in the process of getting a pointer,
--which again is a seperate conversation. There are way way way better guides out there than I could write on how to find that.
local offsetBasketQuality = 0x4
--for i = 1, 100 means it'll repeat the loop 100 times. 1000 for 1000 container spaces, you get the idea.
for i = 1, 100 do
--[[This creates an entry to the cheat table. local recQuality = al.createMemoryRecord() creates a memory record accessed by the
internal variable recQuality. It then sets the description, the base address, adds an offset (since the address itself only
points to the start of the basket), sets that offset to the address for quality, puts it under the header we made earlier, and sets
the value type to Float.
--]]
local recQuality = al.createMemoryRecord()
recQuality.Description = string.format("Basket Slot %d Quality", bsktslotnum)
recQuality.Address = basketaddr
recQuality.OffsetCount = 1
recQuality.Offset[0] = offsetBasketQuality
recQuality.appendToEntry(base)
recQuality.type = vtSingle
--[[This makes sure that instead of creating the same address 100 times, it moves to the next inventory slot. Each slot in the
basket is 34 apart, so we add 34 to the offset each time. The slot number is increased each time to make sure the address
is labeled properly.
--]]
offsetBasketQuality = offsetBasketQuality + 0x34
bsktslotnum = bsktslotnum + 1
end
The above is lua code that, when run, creates 100 basket quality codes. I put a bunch of comments in to explain what each step does and why. Using something similar, you could create a code that lists all 3500+ possible container quality entries, for instance, and then set the quality on the header (after enabling RecursiveSetValue either in lua or just by right clicking the header and going to group options) to whatever you like and it would change every single entry. You could then just freeze all the values. Since this nets you thousands and thousands of cheat code entries it's the crappy way to be about it though.
I like this solution better for situations like using cheat engine on fire emblem games, or something, because by creating a header-per-slot, then subcodes for all the various stats I can view and edit each character individually. This is useful because I rarely want to edit my entire army to be near-clones. On atelier games though, not so useful.