AddAddress modifies the memory address(es) of the following condition by the calculated value. It works similar to
AddSource, but modifies the address, not the resulting value. Additionally, it affects addresses on both sides of the condition.
AddAddress only affects the next condition. If multiple
AddAddress lines are chained together, each lookup in the chain will be altered; the values won't all be added to the final lookup.
The 32-bit value at 0x0112F8 is a pointer to the data for the first character in the party. When the party order changes, the pointer will point at a different block of memory, but data within the block will have the same structure.
- The value is an address in the actual system representation and differs from the addresses provided by the memory inspector. However, you can rely on the fact that the memory inspector represents the same memory, so while the actual address may differ, the sequence of bytes does not.
To translate the real pointer to a memory inspector address, we compare the two values. For example:
- The 32-bit value at 0x0112F8 is 0x800110B8.
- The memory we're interested in is at 0x011114 in the memory inspector.
- Using a 24-bit read instead of a 32-bit read gives us 0x0110B8
- 0x011114 - 0x0110B8 = 0x00005C, so that becomes the "base address" in the second condition.
Types of Pointerslink
AddAddress is how RAIntegration handles pointers. There are four major types of pointer support:
Direct Pointer: The pointer contains another address that is referenced without modification. These are most commonly used for string pointers. To use a direct pointer, the base address to which the pointer is added would be 0.
Indirect Pointer: The pointer contains another address that indicates the start of some block of data. The data of interest is a fixed number of bytes into the block of data. These are commonly used for attributes of a character/object.
For both Direct and Indirect Pointers, the
AddAddress line should reference the pointer, and the address in the following line should be the offset into the block of data for the information relevant to the condition. While you would typically use 0 for a Direct Pointers, the following line would also contain any value necessary to convert between a real address and a memory inspector address.
The example above is an Indirect Pointer, where the data is 0x5C bytes into a block of data. The conversion from a real address to a memory inspector address is handled by using a 24-bit read instead of a 32-bit read.
Array Index: The pointer contains an offset to apply to a fixed pointer.
Scaled Array Index: The pointer contains an offset to apply to a fixed pointer after it has been scaled.
For Array Indices, the
AddAddress line should reference the offset to apply, and the following line should contain the address of the first element of the array (index 0). For example:
AddAddress 16-bit Mem 0x1234 8-bit Mem 0x4567
Would read a 16-bit number from 0x1234 and read the single byte that is that many bytes after 0x4567.
To scale an array index, click on the space in the Cmp column for the array index address and select the
* symbol. Then enter the size of each array item in the second mem/val column. For example:
AddAddress 16-bit Mem 0x1234 * Value 4 8-bit Mem 0x4567
Would read a 16-bit number from 0x1234, multiply it by 4, and read the single byte that is that many bytes after 0x4567.
AddAddress can be chained to perform multi-step lookups, but only one step at a time. As such, you can reference data pointed at by a pointer that's pointed at by another pointer, but you can't reference data in an array that's pointed at by another pointer unless either the array or the array index is at a fixed address.
Using Delta with Chained Pointerslink
To do a delta check on an
AddAddress chain, you should only put the delta on the final condition. You want to use the current value for each step of the chain to derive the final result, and you only care about the changes in the final value. Using previous values for the pointers will have you reading invalid memory and will likely cause problems.
A) AddAddress Mem 0000 B) AddAddress Mem 0000 C) Delta 0000
Assuming Mem: $0000=0, $0001=2, and $0002=4, this will evaluate to 0 for the first few frames, and when Mem 0 changes to 1, the following happens:
Frame N : A = Mem = 1 (delta = 0), B = Mem[A] = Mem = 2 (delta B = 0), C = Mem[B] = Mem = 4 (delta C = 0) Frame N+1: A = Mem = 1 (delta = 1), B = Mem[A] = Mem = 2 (delta B = 2), C = Mem[B] = Mem = 4 (delta C = 4)
You can see the entire delta chain updates in the same frame (one frame after the change occurs).
If you use Delta for A and B, something different happens:
A) AddAddress Delta 0000 B) AddAddress Delta 0000 C) Delta 0000
Frame N : Mem = 1 (delta = 0), B = Mem[deltaA] = Mem = 1 (delta B = 0), C = Mem[deltaB] = Mem = 1 (delta C = 0) Frame N+1: Mem = 1 (delta = 1), B = Mem[deltaA] = Mem = 2 (delta B = 1), C = Mem[deltaB] = Mem = 2 (delta C = 1) Frame N+2: Mem = 1 (delta = 1), B = Mem[deltaA] = Mem = 2 (delta B = 2), C = Mem[deltaB] = Mem = 4 (delta C = 2) Frame N+3: Mem = 1 (delta = 1), B = Mem[deltaA] = Mem = 2 (delta B = 2), C = Mem[deltaB] = Mem = 4 (delta C = 4)
Not only does it take two extra frames for delta C to be correct, it has two intermediate values that are not correct. The value went from 0 to 4 in a single frame and never was 1 or 2.
The experienced achievement creator wilhitewarrior made a nice video showing how to work with pointers and AddAddress flag.
You can check it here: https://www.youtube.com/watch?v=_gk0vYYlm-E.
Last 10 changes on this page:
[2021-10-06 19:35] Jamiras:Updated AddAddress Flag (markdown)
[2021-08-08 18:59] Jamiras:update for scaled array index support
[2020-08-05 02:06] meleu:cosmetic
[2020-08-05 01:58] meleu:add link to wilhitewarrio's video tutorial
[2019-11-17 22:18] meleu:fix markdown formats
[2019-11-16 07:53] Jamiras:Updated AddAddress Flag (markdown)
[2019-11-14 20:25] Jamiras:Created AddAddress Flag (markdown)