diff --git a/docs/developer-docs/achievement-templates.md b/docs/developer-docs/achievement-templates.md index 9ea04054..178a64df 100644 --- a/docs/developer-docs/achievement-templates.md +++ b/docs/developer-docs/achievement-templates.md @@ -230,7 +230,7 @@ In this example we want to detect a value changing from `V1` to `V2` ten times: Conditional resets can be used for many things. -Let's say you want to have a reset if a player enters a certain X and Y zone of a level: +Let's say you want to have a ResetIf a player enters a certain X and Y zone of a level: **CORE** diff --git a/docs/developer-docs/console-specific-tips.md b/docs/developer-docs/console-specific-tips.md index cc11a1fc..948b7610 100644 --- a/docs/developer-docs/console-specific-tips.md +++ b/docs/developer-docs/console-specific-tips.md @@ -157,7 +157,7 @@ Checks if the 8-bit value at 0x18BAB5 is equal to 0x20. This means 0x18BAB5 cont - GameCube uses a PowerPC chipset with big-endian data. Filter using `16-Bit BE`, `32-Bit BE`, `Float BE`, and `Double32 BE` for data types wider than 1 byte (8-bits). Data is typically aligned on Gamecube, so 16-Bit data is always at an even address and 32-bit data addresses at a multiple of 4, etc. - Gamecube has one bank of RAM, 24MB, located at `0x80000000-0x817FFFFF`, which is mapped at `0x00000000-0x017FFFFF` in the RA toolkit. - Therefore, pointers found will start with 0x8, and to use them, you can mask them using `0x1fffffff` to convert to RA addressing. - - `Add Address 32-Bit BE Pointer & 0x1fffffff` + - `AddAddress 32-Bit BE Pointer & 0x1fffffff` - Uncached mirror of the RAM exists as well at `0xC0000000`. If you happen to find pointers that begin with 0xC, the same masking scheme will work to convert them to the RA addressing. ## Wii @@ -171,7 +171,7 @@ Checks if the 8-bit value at 0x18BAB5 is equal to 0x20. This means 0x18BAB5 cont - Wii uses a PowerPC chipset with big-endian data. Filter using `16-Bit BE`, `32-Bit BE`, `Float BE`, and `Double32 BE` for data types wider than 1 byte (8-bits). Data is typically aligned on Wii, so 16-Bit data is always at an even address and 32-bit data addresses at a multiple of 4, etc. - Wii has two banks of RAM, 24MB called "MEM1" located at `0x80000000-0x817FFFFF`, which is mapped at `0x00000000-0x017FFFFF` in the RA toolkit, and 64MB called "MEM2" located at `0x90000000-0x93FFFFFF`, which is mapped at `0x10000000-0x13FFFFFF` in the RA toolkit. - Therefore, pointers found will start with 0x8 or 0x9, and to use them, you can mask them using `0x1fffffff` to convert to RA addressing. - - `Add Address 32-Bit BE Pointer & 0x1fffffff` + - `AddAddress 32-Bit BE Pointer & 0x1fffffff` - Uncached mirrors of MEM1 and MEM2 exist as well at `0xC0000000` and `0xD0000000`, respectively. If you happen to find pointers that begin with 0xC or 0xD, the same masking scheme will work to convert them to the RA addressing. ## Neo Geo diff --git a/docs/developer-docs/flags/andnext-ornext.md b/docs/developer-docs/flags/andnext-ornext.md index f04023af..f7d83b46 100644 --- a/docs/developer-docs/flags/andnext-ornext.md +++ b/docs/developer-docs/flags/andnext-ornext.md @@ -29,7 +29,7 @@ ResetIf F = 1 Represents the following logical statement: ``` -reset if (((((A = 1 and B = 1) or C = 1) and D = 1) or E = 1) and F = 1) +ResetIf (((((A = 1 and B = 1) or C = 1) and D = 1) or E = 1) and F = 1) ``` [Alt Groups](/developer-docs/alt-groups) are still preferred over `OrNext` for most use cases. They allow for multiple conditions to be present in each clause of the OR, and support more than two clauses. diff --git a/docs/developer-docs/flags/measured.md b/docs/developer-docs/flags/measured.md index 34a12a0c..534181aa 100644 --- a/docs/developer-docs/flags/measured.md +++ b/docs/developer-docs/flags/measured.md @@ -21,7 +21,7 @@ Note that progress for `Measured` values is reported at the time of examination ## Limiting When a Measurement Appears or Changes -You will find cases where you don't want a measurement to update or where a measurement is invalid. You can use `Pause If` or `Measured If` to manage these cases. +You will find cases where you don't want a measurement to update or where a measurement is invalid. You can use `PauseIf` or `Measured If` to manage these cases. ### Using Measured If with Measured: To limit the scope of a `Measured` condition, you can add a `MeasuredIf` condition. A `MeasuredIf` condition must be true for the `Measured` value to be non-zero (and for the achievement to trigger). You can use `MeasuredIf` to create achievements that require playing as a certain character, or just to prevent bogus data from showing up if the player is in the wrong part of the game. If any `MeasuredIf` condition in a group is false, the `Measured` value for the group is automatically 0. @@ -33,10 +33,10 @@ To summarize, use `Measured If` when: - **Example**: When on the wrong stage or in the wrong area. - **Example**: Measuring something during a race, but the measurement addresses are different between single-race mode and tournament mode. -### Using Pause If with Measured: +### Using PauseIf with Measured: Since [`PauseIf`](/developer-docs/flags/pauseif) has precedence over `Measured`, the `Measured` value will be captured when a group becomes paused, and the captured value will be returned until the group is unpaused and `Measured` can be evaluated again. If another `Measured` exists in a non-paused group, its value will be returned even if it is lower than the captured value. -To summarize, use `Pause If` when: +To summarize, use `PauseIf` when: - You want to prevent the measurement from updating or changing - The scope of the measurement is valid, but the data is volatile - **Example**: Pause while on a loading screen where the address(es) that normally contain or determine the measurement are used for something else diff --git a/docs/developer-docs/flags/remember.md b/docs/developer-docs/flags/remember.md index 662c7835..d9b8561c 100644 --- a/docs/developer-docs/flags/remember.md +++ b/docs/developer-docs/flags/remember.md @@ -53,69 +53,69 @@ In this example it uses the stored value and compares it to a constant value of | ID | Flag | Type | Size | Memory | Cmp | Type | Size | Mem/Val | Hits | | --- | -------- | ------ | ------ | ------ | --- | ----- | ------ | ------- | ----- | | 1 | Remember | Mem | 16-bit | 0x1234 | - | Delta | 16-Bit | 0x1224 | | -| 2 | And Next | Recall | | | = | Value | | 0x05 | | -| 3 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | -| 4 | And Next | Recall | | | = | Value | | 0x14 | | -| 5 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | -| 6 | And Next | Recall | | | = | Value | | 0x64 | | -| 7 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 2 | AndNext | Recall | | | = | Value | | 0x05 | | +| 3 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 4 | AndNext | Recall | | | = | Value | | 0x14 | | +| 5 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 6 | AndNext | Recall | | | = | Value | | 0x64 | | +| 7 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | | 8 | Measured | Value | | 0x00 | = | Value | | 0x00 | 3 (0) | -In this example, we are using the stored value in multiple chains within an Add Hits chain without having to recalculate the value each time. Here we are looking for specific increases of `0x1234` to occur while the value of `0x1000` is equal to 3. Perhaps `0x1234` is money, `0x1000` is the current level, and you want to make sure the player collects a gem worth 5 units of money, one worth 20, and one worth 100 in level 3. `Recall` is used here to check all these values of the difference between Mem and Delta without having to recalculate it each time. See the [`Add Hits`](/developer-docs/flags/addhits-subhits) document for more information about how that condition works. +In this example, we are using the stored value in multiple chains within an AddHits chain without having to recalculate the value each time. Here we are looking for specific increases of `0x1234` to occur while the value of `0x1000` is equal to 3. Perhaps `0x1234` is money, `0x1000` is the current level, and you want to make sure the player collects a gem worth 5 units of money, one worth 20, and one worth 100 in level 3. `Recall` is used here to check all these values of the difference between Mem and Delta without having to recalculate it each time. See the [`AddHits`](/developer-docs/flags/addhits-subhits) document for more information about how that condition works. ::: info `Recall` retrieves the value stored in the recall accumulator. ::: -## Interaction with Pause If +## Interaction with PauseIf -Because `Pause If` logic is processed before other logic, `Pause If` logic can only recall values that have been remembered by pause logic. Values remembered during `Pause If` logic continue to be remembered during the remaining logic processing. +Because `PauseIf` logic is processed before other logic, `PauseIf` logic can only recall values that have been remembered by pause logic. Values remembered during `PauseIf` logic continue to be remembered during the remaining logic processing. -See the [`Pause If`](/developer-docs/flags/pauseif) document for more information about how that condition works. +See the [`PauseIf`](/developer-docs/flags/pauseif) document for more information about how that condition works. -### Example of Use with Pause If +### Example of Use with PauseIf | ID | Flag | Type | Size | Memory | Cmp | Type | Size | Mem/Val | Hits | | --- | -------- | ------ | ------ | ------ | --- | ----- | ------ | ---------- | ----- | | 1 | Remember | Mem | 16-bit | 0x1234 | - | Delta | 16-Bit | 0x1234 | | -| 2 | Pause If | Recall | | | >= | Value | | 0x80000000 | 1 (0) | -| 3 | And Next | Recall | | | = | Value | | 0x05 | | -| 4 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | -| 5 | And Next | Recall | | | = | Value | | 0x14 | | -| 6 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | -| 7 | And Next | Recall | | | = | Value | | 0x64 | | -| 8 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 2 | PauseIf | Recall | | | >= | Value | | 0x80000000 | 1 (0) | +| 3 | AndNext | Recall | | | = | Value | | 0x05 | | +| 4 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 5 | AndNext | Recall | | | = | Value | | 0x14 | | +| 6 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 7 | AndNext | Recall | | | = | Value | | 0x64 | | +| 8 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | | 9 | Measured | Value | | 0x00 | = | Value | | 0x00 | 3 (0) | -This example extends the previous [Using the Stored Value](#using-the-stored-value) example by adding a `Pause If` lock if the player loses money\*. Because `Remember` is a combining condition, it links with the following `Pause If` to form a chain and is processed as part of the pause processing, allowing the value to be used by the `Pause If`. The remembered value is available to the remaining logic and can therefore be used by the Add Hits chain. +This example extends the previous [Using the Stored Value](#using-the-stored-value) example by adding a `PauseIf` lock if the player loses money\*. Because `Remember` is a combining condition, it links with the following `PauseIf` to form a chain and is processed as part of the pause processing, allowing the value to be used by the `PauseIf`. The remembered value is available to the remaining logic and can therefore be used by the AddHits chain. Notes: -- \* Due to the way unsigned math works, the subtraction will underflow back to 0xfffffff at negative one, so any value greater or equal to 0x80000000 is treated as negative). -- Because pause processing happens first, you _could_ put conditions 1-2 at the end of the logic and it will still work! The value remembered by the pause logic will still be available to the Add Hits chain. However because this may be a confusing effect, we recommend putting your pause logic at the beginning when using it with `Remember` and `Recall`. +- Due to the way unsigned math works, the subtraction will underflow back to 0xfffffff at negative one, so any value greater or equal to 0x80000000 is treated as negative. +- Because pause processing happens first, you _could_ put conditions 1-2 at the end of the logic and it will still work! The value remembered by the pause logic will still be available to the AddHits chain. However because this may be a confusing effect, we recommend putting your pause logic at the beginning when using it with `Remember` and `Recall`. ::: tip To avoid unexpected behavior with `Remember` and `Recall`, place pause logic that uses these features at the top of the group. ::: -### Example of Incorrect Usage with Pause If +### Example of Incorrect Usage with PauseIf | ID | Flag | Type | Size | Memory | Cmp | Type | Size | Mem/Val | Hits | | --- | -------- | ------ | ------ | ------ | --- | ----- | ------ | --------- | ----- | | 1 | Remember | Mem | 16-bit | 0x1234 | - | Delta | 16-Bit | 0x1234 | | -| 2 | And Next | Recall | | | = | Value | | 0x05 | | -| 3 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | -| 4 | And Next | Recall | | | = | Value | | 0x14 | | -| 5 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | -| 6 | And Next | Recall | | | = | Value | | 0x64 | | -| 7 | Add Hits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 2 | AndNext | Recall | | | = | Value | | 0x05 | | +| 3 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 4 | AndNext | Recall | | | = | Value | | 0x14 | | +| 5 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | +| 6 | AndNext | Recall | | | = | Value | | 0x64 | | +| 7 | AddHits | Mem | 8-Bit | 0x1000 | = | Value | | 0x03 | 1 (0) | | 8 | Measured | Value | | 0x00 | = | Value | | 0x00 | 3 (0) | -| 9 | Pause If | Recall | | | >= | Value | | 0x8000000 | 1 (0) | +| 9 | PauseIf | Recall | | | >= | Value | | 0x8000000 | 1 (0) | -In this example, the `Remember` condition is not chained with the `Pause If`. Because of this, the `Pause If` condition will read a value of 0 from the `Recall` operand and never be paused, as a consequence of the pause logic being processed first. Fear not though, as the validation is smart enough to recognize this and will generate a warning on condition 9 that `Recall` is being used in a `Pause If` without a value being remembered in a `Pause If`. +In this example, the `Remember` condition is not chained with the `PauseIf`. Because of this, the `PauseIf` condition will read a value of 0 from the `Recall` operand and never be paused, as a consequence of the pause logic being processed first. Fear not though, as the validation is smart enough to recognize this and will generate a warning on condition 9 that `Recall` is being used in a `PauseIf` without a value being remembered in a `PauseIf`. ::: danger -When using the `Recall` type operator in Pause If logic, be sure that the `Remember` condition that sets the value you wish to use is in the same `Pause If` chain or an earlier `Pause If` chain. Otherwise the recalled value with be 0! +When using the `Recall` type operator in PauseIf logic, be sure that the `Remember` condition that sets the value you wish to use is in the same `PauseIf` chain or an earlier `PauseIf` chain. Otherwise the recalled value with be 0! ::: ## Using `Recall` within a `Remember` Condition @@ -146,12 +146,12 @@ Notes: In this example, let's say you have an address that points to a table of data, but in order to know where in the table you want to go, you have to calculate the offset from another source. `0x1234` will be used as the pointer to the table of data. `0x0789` will be the index in the table. The size of data for table entries is `0x60` bytes. And finally, the data we care about is `0x08` bytes into the data's structure. Perhaps this is "Player Health" and the index we are calculating is the index in the table where the "Player Data" exists and we need to check if this value is greater than 0. -See the [`Add Address`](/developer-docs/flags/addaddress) document for more information about how that condition works. +See the [`AddAddress`](/developer-docs/flags/addaddress) document for more information about how that condition works. Breakdown of Conditions: 1. Scales the index by the size of the data structure. Now it represents how far from the beginning of the table the data is located. -2. Uses the address for the start of the table and adds to it the stored value. Now this Add Address points to the start of the "Player Data" in the table. +2. Uses the address for the start of the table and adds to it the stored value. Now this AddAddress points to the start of the "Player Data" in the table. 3. Offsets from the Address by `0x08`, where it reads the current memory value for the Player's Health with 16-bit size, then uses a comparison to check if it is greater than zero. ## Deeper Chaining of `Remember` Conditions @@ -160,22 +160,22 @@ Breakdown of Conditions: | --- | ---------- | ---- | ------ | ------ | --- | ------ | ---- | ------- | ----- | | 1 | Remember | Mem | 8-bit | 0x0789 | \* | Value | | 0x60 | | | 2 | AddAddress | Mem | 32-bit | 0x1234 | + | Recall | | | | -| 3 | And Next | Mem | 16-bit | 0x08 | < | Delta | | 0x08 | 0 (0) | +| 3 | AndNext | Mem | 16-bit | 0x08 | < | Delta | | 0x08 | 0 (0) | | 4 | AddAddress | Mem | 32-bit | 0x1234 | + | Recall | | | | -| 5 | And Next | Mem | 8-bit | 0x24 | != | Value | | 0xff | 0 (0) | +| 5 | AndNext | Mem | 8-bit | 0x24 | != | Value | | 0xff | 0 (0) | | 6 | AddAddress | Mem | 32-bit | 0x1234 | + | Recall | | | | | 7 | Remember | Mem | 16-bit | 0x24 | \* | Value | | 0x60 | | | 8 | AddAddress | Mem | 32-bit | 0x1234 | + | Recall | | | | -| 9 | Reset If | Mem | 8-bit | 0x00 | = | Value | | 0xa7 | 0 (0) | +| 9 | ResetIf | Mem | 8-bit | 0x00 | = | Value | | 0xa7 | 0 (0) | -This example shows how using `Remember` continues the chain of And Next conditions and how you can remember new values during the chain without affecting earlier parts of the chain or breaking the chain. +This example shows how using `Remember` continues the chain of `AndNext` conditions and how you can remember new values during the chain without affecting earlier parts of the chain or breaking the chain. -In this example, we build on the previous `Add Address` example by chaining it with other conditions. Pretend this is a challenge that fails if the player loses health while holding a certain object. Suppose the player data stores the index of the object at offset `0x24` (the value of which is `0xff` if no object is held). Suppose that index is an index into the same table that holds the player data. This example shows the reset chain that accomplishes this. Suppose that offset `0x00` of object data holds the 8-bit ID of the object. +In this example, we build on the previous `AddAddress` example by chaining it with other conditions. Pretend this is a challenge that fails if the player loses health while holding a certain object. Suppose the player data stores the index of the object at offset `0x24` (the value of which is `0xff` if no object is held). Suppose that index is an index into the same table that holds the player data. This example shows the reset chain that accomplishes this. Suppose that offset `0x00` of object data holds the 8-bit ID of the object. Breakdown of Conditions: 1. Scales the index by the size of the data structure. Now it represents how far from the beginning of the table the data is located. -2. Uses the address for the start of the table and adds to it the stored value. Now this Add Address points to the start of the "Player Data" in the table. +2. Uses the address for the start of the table and adds to it the stored value. Now this AddAddress points to the start of the "Player Data" in the table. 3. Checks if the player lost health, using the offset for health established in the previous example. 4. Re-uses the address for the start of the player data 5. Checks the offset of the held object and makes sure it's not 0xff. diff --git a/docs/developer-docs/flags/resetif.md b/docs/developer-docs/flags/resetif.md index 65b7f0e8..9355cb5b 100644 --- a/docs/developer-docs/flags/resetif.md +++ b/docs/developer-docs/flags/resetif.md @@ -5,7 +5,7 @@ description: Discover how to effectively use the ResetIf flag to reset hit count # `ResetIf` -The `ResetIf` can be chosen in the Flag column of the Achievement Editor +The `ResetIf` can be chosen in the Flag column of the Achievement Editor. If the associated condition is true, **all** [hit counts](/developer-docs/hit-counts) in the achievement will be reset to 0. This includes hit counts in other groups (more about it in [Alt Groups](/developer-docs/alt-groups) below). @@ -19,4 +19,30 @@ A `ResetIf` condition with a hit count will only trigger when the hit count targ **Note**: If another `ResetIf` condition is met, all conditions, including the `ResetIf` with the hit count will have their hit counts reset to 0. -It is very common to use a condition with a hit count of 1 as a start marker for an achievement, and use a `ResetIf` to cancel the achievement before the end condition is met. A common example is a damageless achievement: "From start of (level/battle), reset if damage taken, trigger at end of (level/battle)". When the start condition is true, a hit count is captured. If it's still set when the end condition is true, the achievement triggers. If the `ResetIf` condition triggers, the hit count on the start condition is set back to zero, which makes the condition false when evaluating the state when the end condition is true, and the achievement will not trigger. +It is very common to use a condition with a hit count of 1 as a start marker for an achievement, and use a `ResetIf` to cancel the achievement before the end condition is met. A common example is a damageless achievement: + +"From start of (level/battle), ResetIf damage taken, trigger at end of (level/battle)". + +When the start condition is true, a hit count is captured. If it's still set when the end condition is true, the achievement triggers. If the `ResetIf` condition triggers, the hit count on the start condition is set back to zero, which makes the condition false when evaluating the state when the end condition is true, and the achievement will not trigger. + +## Example + +``` + 1: ResetIf Mem 8-bit 0x0007536c != Value 3 (0) + 2: Mem 8-bit 0x00065980 != Value 1 (0) + 3: Mem 8-bit 0x000a35a0 != Value 2 (0) + 4: Mem 8-bit 0x000a35a0 != Value 4 (0) + 5: Mem 8-bit 0x000a35a0 != Value 7 (0) + 6: AndNext Delta 32-bit 0x000b0c00 = Value 2 (0) + 7: Mem 32-bit 0x000b0c00 = Value 1 (2) + 8: AndNext Delta 32-bit 0x001eed30 = Value 0 (0) + 9: ResetIf Mem 32-bit 0x001eed30 = Value 1 (0) +``` + +In this achievement we want players to witness a special event twice in one round. The event is tracked using the address 0x000b0c00 - once the value jumps from 2 to 1 the event took place once. + +Every time the event started the hit target in condition gains one hit. + +Should the player lose or end the current session we wish to reset the amount of events witnessed. If we did not do that a player could see the event once, end the current session, start again and witness it only one more time in order to unlock the achievement. + +Condition 1 checks if the player is not in a session. If that condition is true they are in the main menu and thus the hit targets are cleared. \ No newline at end of file diff --git a/docs/developer-docs/flags/resetnextif.md b/docs/developer-docs/flags/resetnextif.md index e2ce81f6..3ac5a5fa 100644 --- a/docs/developer-docs/flags/resetnextif.md +++ b/docs/developer-docs/flags/resetnextif.md @@ -14,3 +14,24 @@ The `ResetNextIf` Flag is a special version of the `ResetIf` Flag that only rese `AndNext` and `OrNext` are combining logical conditions and will have their hit counts reset, as well as whatever condition follows them. All other condition flags, including `AddHits` and `SubHits`, will cause processing of the `ResetNextIf` behavior to stop. + +## Example + +``` + 1: Mem 8-bit 0x00065980 != Value 1 (0) + 2: Mem 8-bit 0x000a35a0 = Value 3 (0) + 3: Mem 8-bit 0x0007536c = Value 3 (0) + 4: Trigger Mem 32-bit 0x001bf958 >= Value 1500000 (0) + 5: Trigger Delta 32-bit 0x001bf958 <= Value 1500000 (0) + 6: Mem 16-bit 0x001bf9ac < Value 10 (0) + 7: AndNext Delta 8-bit 0x000a2774 = Value 0 (0) + 8: ResetNextIf Mem 8-bit 0x000a2774 = Value 1 (0) + 9: PauseIf Delta 8-bit 0x000a22e8 > Mem 8-bit 0x000a22e8 (1) + 10: Mem 8-bit 0x000a2774 = Value 1 (0) +``` + +In this achievement we want players to complete an objective without using a special item. The amount of items the player has is tracked in 0x000a22e8. +Once an item has been used condition 9 with the `PauseIf` will be true and prevent the achievement from unlocking. + +In order to be able to reattempt the challenge both condition 7 and 8 must be true. Since ResetNextIf is used the PauseIf will then properly be reset. +Other hit counts would not be affected by this. \ No newline at end of file diff --git a/docs/developer-docs/getting-started-as-an-achievement-developer.md b/docs/developer-docs/getting-started-as-an-achievement-developer.md index 0c3d4b75..34cfec7a 100644 --- a/docs/developer-docs/getting-started-as-an-achievement-developer.md +++ b/docs/developer-docs/getting-started-as-an-achievement-developer.md @@ -39,7 +39,7 @@ To begin, run the RALibRetro executable and login when prompted. If you have not You should now have your main window running Sonic. There are 3 other dialogs we'll be using, which can be found under **RetroAchievements** in the menu. We'll be dealing with the **Memory Inspector** first: -![memoryinspector](/meminspdocs1.png) +![memoryinspector](/new-mem-insp.png) The Memory Inspector can be used to find addresses in RAM for us to use. Essentially you are on a treasure hunt for memory locations - this dialog will help you examine and filter the game's RAM while the game is running. @@ -48,19 +48,19 @@ The Memory Inspector can be used to find addresses in RAM for us to use. Essenti **See also**: [Memory Inspector Overview](/developer-docs/memory-inspector) and [Memory Digging Tips](/developer-docs/tips-and-tricks#memory-digging-tips). -To start or restart a test, click **Reset** near the top left. +To start or restart a test, click **New Search** near the top left. To keep things simple, we'll start by looking for the memory address which holds the number of rings we have collected. Our steps will be the following: 1. Load the ROM and start a new game. -2. Reset the memory dialog: click **Reset**. +2. Reset the memory dialog: click **New Search**. 3. Run the first filter: click **Filter Once**. 4. Return to the game and change the number of rings in memory. For example, collect a ring. -5. In the memory dialog, we now want to filter for values that are 'greater than previous values' (symbol `>`). We select this, then hit **Filter** again. +5. In the memory dialog, we now want to filter for values that are 'greater than previous values' (symbol `>`). We select this, then hit **Filter Once** again. Each time you perform 4 then 5, the number of possibilities or 'candidates' will get smaller. We will continue doing this until the number of candidates reaches a very small number (as few as possible), it can take several attempts. Next we can click in the results window, and monitor the memory address in the memory viewer at the bottom. Continue using the game and you should see the values in memory change as you collect rings. If you don't, or if something doesn't look right, try another value. With the first Sonic the Hedgehog, the memory address for the number of rings should be `0xfe20`. @@ -80,7 +80,7 @@ So the memory location for the number of rings is stored at `0xfe20` - note to a Go to the **RetroAchievements** in the menu, choose **Achievement Sets** and you'll see this dialog: -![achievement_sets](/achlistdocs1.png) +![achievement_sets](/new-asset-list.png) Here we group all the achievements we know about into three sets: @@ -96,22 +96,23 @@ In the Achievements dialog, click **Local Achievements** (top left), then **Add This is how it looks: -![achievement_editor](/acheditordocs1.png) +![achievement_editor](/new-ach-editor.png) This is the final dialog where we bring all the data together. Most of the top fields are self explanatory, I.e. Title, Description, Points. The main one is the 'Requirements' part. -Let's say we want to add an achievement for collecting a certain number of rings. Let's say 15 rings for simplicity. After filling out the fields at the top and selecting a suitable icon (in this example we used the gold trophy badge (00136), but you can upload a new one), we need to fill out Requirements. We have one requirement, **that the number of rings is at least 15**. Next click is **Add New Requirement**. +Let's say we want to add an achievement for collecting a certain number of rings. Let's say 20 rings for simplicity. After filling out the fields at the top and selecting a suitable icon we need to fill out Requirements. +We have one requirement, **that the number of rings is at least 20**. Next click is **Add New Requirement**. -Clicking this button will add several default values to the Requirements list. These defaults just ensure that something relatively sensible is added to the list. For now, ignoring the field 'Special?'. When we clicked create, the default memory value will be whatever value you last left in the memory dialog. +Clicking this button will add several default values to the Requirements list. These defaults just ensure that something relatively sensible is added to the list. When we clicked create, the default memory value will be whatever value you last left in the memory dialog. Next we will change these values to the following: - **Size**: `16-bit` - we're using 16-bit because the value _can_ exceed 255 (which is 0xff in hex) - **Memory**: `0xfe20` -- **Cmp**: `>=` - this is the comparison to make. We could have any comparison here, but it's sensible to have "greater than or equal to". This is important because if we get 10 rings then a super ring box to have 20, we would miss out having _exactly_ 15 rings. -- **Type**: `Value` - we're comparing this memory value to a fixed value: 15 +- **Cmp**: `>=` - this is the comparison to make. We could have any comparison here, but it's sensible to have "greater than or equal to". This is important because if we get 15 rings then a super ring box to have 25, we would miss out having _exactly_ 20 rings. +- **Type**: `Value` - we're comparing this memory value to a fixed value: 20 - **Size**: `Empty` - this is only relevant when comparing memory to memory -- **Mem/Val**: `15` - the number of rings required: the value we are comparing the memory to +- **Mem/Val**: `20` - the number of rings required: the value we are comparing the memory to - **Hit Count**: `0` - ignore this for now, its useful for when something needs to happen a certain number of times With that set, we don't have any more conditions to add, so we return to the **Achievements Dialog**. To be safe, we should save our progress by hitting **Save Local**! This saves everything to file locally to ensure that we won't lose any progress. @@ -122,13 +123,13 @@ With that set, we don't have any more conditions to add, so we return to the **A We can now 'activate' this achievement locally by checking the box next to **Active** on the right-hand side in the Achievement Editor or by selecting the achievement in Achievement Sets and clicking **Activate Selected**. This will start monitoring these memory locations and will award the achievement once all the conditions are true. Now we can go ahead and test to see if this achievement works! -![testing_achievements](/achtestdocs1.png) +![testing_achievements](/new-pause-menu.png) If we press `Esc` in-game, you will see the achievement show up as a demonstration of what it would look like in the in-game overlay! -![testing_achievements2](/achtestdocs2.png) +![testing_achievements2](/new-unlocked.png) -Although the achievement worked fine in our tests, an achievement with logic like that is not ready to be officially released. First of all, it has only one condition: "collected rings >= 15". The problem is that the memory address used to record the number of collected rings is also used when the game runs in "demo mode" (AI playing the game after you wait a while on the title screen). So, if Sonic collects 15 rings in demo mode this achievement will trigger, which is unwanted. +Although the achievement worked fine in our tests, an achievement with logic like that is not ready to be officially released. First of all, it has only one condition: "collected rings >= 20". The problem is that the memory address used to record the number of collected rings is also used when the game runs in "demo mode" (AI playing the game after you wait a while on the title screen). So, if Sonic collects 20 rings in demo mode this achievement will trigger, which is unwanted. Check the tips in the next section below to know how to improve the logic of your achievement and then make it acceptable to be officially released. diff --git a/docs/developer-docs/leaderboards.md b/docs/developer-docs/leaderboards.md index 181e17db..e75cf020 100644 --- a/docs/developer-docs/leaderboards.md +++ b/docs/developer-docs/leaderboards.md @@ -11,20 +11,27 @@ description: Learn how to create and manage leaderboards for RetroAchievements, This is how a game's Leaderboard List looks like on the website: -![leaderboard_list](/leaderboard-list.png) +![leaderboard_list](/new-lb-list.png) -In the center you can see every already made Leaderboard, and in the right column you can see the **Code Notes** for the game. The Code Notes are here to help with some conditions we'll see below. +Here you can see the different leaderboards that exist for a game title. +By selecting any leaderboard you can view its logic in detail. -And now you can also create and edit Leaderboards through the GUI just like achievements by selecting Leaderboards from the Assets List: +![leaderboard_edit_web](/new-lb-web-detail.png) -![Leaderboards GUI](/leaderboards-gui.png) +Here you are also able to view specific conditions or review what Code Note an address it related to. + +Leaderboards can be created just like an achievement using the Assets List: + +![Leaderboards_assets_list](/new-lb-assets-list.png) + +![Leaderboards_editor](/new-lb-editor.png) Here's a brief explanation of each field of a single Leaderboard: - **Title**: the leaderboard's title. - **Description**: the leaderboard's description. - **Format**: specifies how the value should be displayed. -- **"LowerIsBetter" checkbox**: determines how the list should be sorted. When checked, lower value appear as higher ranks in the leaderboard. Time-based leaderboards usually honor faster times (lower), whereas score-based leaderboards favor higher values. +- **"Lower is Better" checkbox**: determines how the list should be sorted. When checked, lower value appear as higher ranks in the leaderboard. Time-based leaderboards usually honor faster times (lower), whereas score-based leaderboards favor higher values. - **Start**: start conditions, aka **STA**. - **Cancel**: cancel conditions, aka **CAN**. - **Submit**: submit conditions, aka **SUB**. @@ -49,67 +56,76 @@ NOTE: Once an active leaderboard is cancelled or submitted, it cannot be reactiv ## Example -The best place to start is to look at existing leaderboards and break it down to see how it works. We're going to use the [Green Hill Act 1 (Sonic the Hedgehog) Leaderboard](https://retroachievements.org/leaderboardinfo.php?i=2) for this purpose. Then let's see how it looks: +The best place to start is to look at existing leaderboards and break it down to see how it works. We're going to use the [The Wizard](https://retroachievements.org/leaderboardinfo.php?i=22955) leaderboard from Super Mario Bros. 3 for this purpose. Let's take a look: -![new_leaderboard2](/new-leaderboard2.png) +![new_leaderboard_metadata](/new-mario3-ex1.png) -The **Title/Description** fields are quite obvious. +The **Title / Description** fields are quite obvious. -The **Type** is "Time (Frames)". The value we're tracking updates once a frame, and the Genesis runs at 60 frames per second (see note below on [Value Format](/developer-docs/leaderboards#value-format) for systems that run at other speeds). +The **Format** is "Score". For more information on the different options see the documentation on [Value Formats](/developer-docs/leaderboards#value-format). -The **Lower Is Better** flag is checked, then the one who makes the shortest time will be the #1. +The **Lower Is Better** flag is unchecked so whoever scores the highest amount of points is in first place. Now we're going to break down the most important parts. ### Start Conditions -**STA**: `0xfe10=h0000_0xhf601=h0c_d0xhf601!=h0c_0xfff0=0` +![Start conditions](/new-mario3-ex2.png) -![Start conditions](/start-conditions.png) +This leaderboard will start once -- `0xfe10=h0000`: If 16-bit RAM address 0xfe10 is equivalent to hex 0000, -- `_`: AND, -- `0xhf601=h0c`: If 8-bit RAM address 0xf601 is equivalent to hex 0c, -- `_`: AND, -- `d0xhf601!=h0c`: If the previous 8-bit RAM address 0xf601 is NOT equivalent to hex 0c, -- `_`: AND, -- `0xfff0=0` If 16-bit RAM address 0xfff0 is equivalent to 0. +- The 16-bit RAM address 0x7dfc is equivalent to hex 0x00, +- AND, +- The 8-bit RAM address 0x072b is equivalent to hex 0x00, +- AND +- The fourth bit in the address 0x0017 was set to 0 in the previous frame (Delta), +- AND, +- The fourth bit in the address 0x0017 is set to 0 in the current frame (Mem), +- AND, +- The 8-bit RAM address 0x0209 is equivalent to hex 0xe5 -This might seem daunting, because we don't know what these addresses mean. That's why the **Code Notes** in the right column are pretty handy! You can see how these addresses are labeled in memory. In our example we have: +This might seem daunting, because we don't know what these addresses mean. That's why the **Code Notes** are pretty handy! You can see how these addresses are labeled in memory by hovering over an address. -- `0xfe10` is the level, and is expected to be `0` (the first level). -- `0xf601` is an 8-bit memory address, and we use the prefix `0xh` instead of `0x` to signify this. The `0xf601` is the screen mode. The second and third parts of the start statement are saying "the current mode should be _ingame_ (`0c`), and the mode on the previous frame should NOT be _ingame_". **Note**: that `d` prefix on the address represents delta, or "the previous frame's value". **Summing up:** trigger this if we've JUST arrived in a level (the start of the level, when we want to start testing their time). -- Finally we also expect `0xfff0` to be equivalent to `0`, because this address is used for demo mode, and we don't want to award a leaderboard entry when the demo is active! +![Hover example](/new-mario3-ex3.png) -**Tip**: the most common mistake when creating leaderboards through the site editor is forgetting the `h` when trying to reference an 8-bit memory address. -**Note**: You can use `HitCount`s in the Start/Submit/Cancel triggers, but you are responsible for resetting them. These triggers are evaluated every frame, and the state of the leaderboard is dependent on which ones are true. As such, the `HitCount` will increment even when the leaderboard is not active unless you have an explicit ResetIf condition. +In our example we have: -### Cancel Conditions +- `0x7dfc` is the current screen the player is on. 0x00 is equivalent to the Title Screen. +- `0x072b` is the amount of players selected. 0x00 is equivalent to Single Player mode. +- `0x0017` tracks the currently pressed buttons. Once the player presses the Start button and starts the game the fourth bit will be set to 1. +- `0x0209` checks if the Player Select screen is visible. -**CAN**: `0xhfe13 Value 0 (0) + 3: Mem 8-bit 0x0030f016 = Value 49 (0) + 4: Mem 32-bit 0x00379f6c = Value 150 (0) + 5: Mem 32-bit 0x0037a820 = Value 0 (0) + 6: AddAddress Mem 32-bit 0x003d03d8 + 7: Mem 32-bit 0x00000034 = Value 1 (0) + 8: AddAddress Mem 32-bit 0x003d03d8 + 9: Delta 32-bit 0x00000034 = Value 0 (0) +``` + +The `Cancel` group is always false. Since the leaderboard UI never shows up we do not need to cancel it either: + +### Cancel +``` + 1: Value 0 = Value 1 (0) +``` + +Finally, `Submit` is always true. The moment the `Start` group is true the leaderboard will submit whatever is defined in the `Value` group: -Leaderboards can sometimes get pretty spammy and take up a lot of screen space when starting or depending on how many are active at once. It is generally good practice to try and eliminate this as much as possible when you can. You can do this by taking advantage of the fact that you can start and submit a leaderboard on the same frame by setting the start condition to what you would normally use as the submit and then setting the submit condition so something that is always true like 1=1. +### Submit +``` + 1: Value 1 = Value 1 (0) +``` -If a game tracks a score or time that you are using to directly call for your value then consider starting and submitting the leaderboard on the same frame so that only one popup is called (for the submission) and the screen won't have extra clutter. There are still cases where it can be useful for players to have the values up on display if they are hidden in menus so use your best judgement. +If a game tracks a score or time that you are using to directly call for your value then consider starting and submitting the leaderboard on the same frame so that only one popup is called (for the submission) and the screen won't have extra clutter. There are still cases where it can be useful for players to have the values up on display if they are hidden in menus so use your best judgement. In games where levels are short and retries are quick you really don't want to have it start/cancel/submit repeatedly after each start/retry when you can help it as the popups can start stacking together and clutter the screen well past the actual attempts are over. These are a prime candidate for starting and submitting on the same frame when possible. diff --git a/docs/developer-docs/memory-inspector.md b/docs/developer-docs/memory-inspector.md index 7c126439..9da6b4c3 100644 --- a/docs/developer-docs/memory-inspector.md +++ b/docs/developer-docs/memory-inspector.md @@ -13,7 +13,7 @@ Here is an overview of the **Memory Inspector** and its features. This tool can ## Memory Inspector Dialog -![memoryinspector-num](/memoryinspector-num.png) +![memoryinspector-num](/new-editor-overview.png) ### 1. New Search @@ -23,7 +23,7 @@ The first drop down allows you to quick select All memory, System RAM, or Cartri The second drop down specifies the size of the data you're interested in finding. -The `Reset` button clears out any previously captured results (part 3 of the dialog) and captures the current memory state. +The `New Search` button clears out any previously captured results (part 3 of the dialog) and captures the current memory state. ### 2. Filter @@ -155,7 +155,7 @@ More facts about the different number notations: The bottom part of the Memory Inspector is what we call the Memory Viewer: -![memviewer](/memviewer.png) +![memviewer](/new-mem-view.png) You can see data in Memory Viewer using 8, 16 or 32-bit modes. diff --git a/docs/developer-docs/recall.md b/docs/developer-docs/recall.md index c8d8f612..ca8c5dad 100644 --- a/docs/developer-docs/recall.md +++ b/docs/developer-docs/recall.md @@ -17,7 +17,7 @@ Examples of how it can be used: - Recall a calculated value for multiple uses in logic. - Continuous operation on remembered values to perform more complicated math than `Add Source` and `Sub Source` can accomplish. -- Recall a calculated address+offset for use in `Add Address` +- Recall a calculated address+offset for use in `AddAddress` To use a remembered value, specify the `Recall` operator as the Type of operand: diff --git a/docs/guidelines/content/code-notes.md b/docs/guidelines/content/code-notes.md index e8902f6e..6325a39b 100644 --- a/docs/guidelines/content/code-notes.md +++ b/docs/guidelines/content/code-notes.md @@ -69,7 +69,8 @@ Good examples here include size, description, and different values or affects on ``` [16-bit] Player Health -Max health is 0x1200, each hit reduces it by 0x8 +0x08 = 1 Health +0x1200 = Maximum ``` #### Bad Examples @@ -105,6 +106,17 @@ Chapter II 0x2c - Inn main room (Day 1) ``` +``` +[16-bit] Current screen +0x0020 = Car / Map select +0x0017 = Main Menu +0x0025 = Title and Demo, Rankings +0x00cf = Dev logos +0xffff = Loading +0x004d = Championship exclusive menus +0x0033 = Ghost Car select, Memory Card, Race End Menu, Replay +``` + #### Bad Example ``` @@ -120,19 +132,19 @@ There are numerous way a game can store the players scores with memory, as such Good examples here will specify the size, which digits of the score are being represented, how the on screen score is calculated from the value in memory, Binary Coded Decimal (BCD) notation if applicable, as well as any other important details. ``` -[1 byte] 1P display score, digits 0000XX00 in BCD +[8-bit BCD] 1P Score - Thousands and Hundreds ``` ``` -[16bit][DEC] P2 Score XXXX0000 +[16-bit BCD] P2 Score XXXX0000 ``` ``` -Score [24-Bit BE BCD] (Determines Rank) -0-9=Pauper -0-99=Peasant -100-999=Prosperous -1000+=Professional +[24-bit BE BCD] Score - Determines Rank +0 - 9 = Pauper +10 - 99 = Peasant +100 - 999 = Prosperous +1000+ = Professional ``` #### Bad Example @@ -143,37 +155,27 @@ Player 1 score ### Bits -It's very common to run into games that need to store event or item flags. Often these will be stored as individual bits rather than taking up an entire byte per flag. It's assumed that a bit value of 0 is off/no/false, if this is not the case then that should be noted. +It's very common to run into games that need to store event or item flags. Often these will be stored as individual bits rather than taking up an entire byte per flag. +When making bitfield notes, it is assumed that a bit value of 0 is off/no/false; if this is not the case, it should be noted as "inverted". #### Good Examples Good examples here will specify each bit as well as what they represent. ``` -[Bitflags] Requests completed -Bit1 = No. 01 - Retrieve 1 Beetle Shell. -Bit2 = No. 02 - Retrieve the first old document. -Bit3 = No. 03 - I'd like to sip a Muscle Drink. -Bit4 = No. 04 - Retrieve 3 Old Lanterns. -Bit5 = No. 05 - Retrieve the second old document. -Bit6 = No. 06 - Create Jack Frost with Dia. -Bit7 = No. 07 - Retrieve 1 Lead Metal. +[8-bit] Bonuses Unlocked +Bit0 = All Replay Items +Bit1 = Unlimited Ammo (Mission 1) +Bit2 = Silver Bullets (Mission 3) +Bit3 = Bullet Shield (Mission 4) +Bit4 = Rubber Grenades +Bit5 = Men With Hats (Mission 5) +Bit6 = Always Sniper +Bit7 = Achilles Head (Mission 6) ``` ``` -Bonuses Unlocked -bit0 - All Replay Items -bit1 - Unlimited Ammo (Mission 1) -bit2 - Silver Bullets (Mission 3) -bit3 - Bullet Shield (Mission 4) -bit4 - Rubber Grenades -bit5 - Men With Hats (Mission 5) -bit6 - Always Sniper -bit7 - Achilles Head (Mission 6) -``` - -``` -[Treasure Flags 03] +[8-bit] Treasure Flags 03 Bit0=[Altair - Rebel Hideout] Potion Bit1=[Fynn - Pub Basement] Scott's Ring Bit2=[Castle Deist 1F - South Treasure Room] Stun Tome @@ -184,6 +186,14 @@ Bit6=[Castle Deist 1F] Phoenix Down Bit7=[Castle Deist 1F - NW Treasure Room] Gold Needle ``` +``` +[8-bit] Chapters Completed +Bit0 = Chapter 1 - Inverted +Bit1 = Chapter 2 - Inverted +Bit2 = Chapter 3 +Bit3 = Chapter 4 +``` + #### Bad Example ``` @@ -207,14 +217,16 @@ Pointers are more commonly found in newer consoles and their notes typically inc Good examples here will include various address offsets, each of which including details and size of the address being pointed to. ``` -Pointer to P1 Data [16-Bit] -+0x68 P1 Character ID [8-Bit] -+0xba P1 Health [8-Bit] -+0xc4 P1 Move ID [16-Bit] +[32-bit BE] Pointer to progress data ++0x24 +++0x04 ++++0x21 = [8-bit] Levels unlocked +...Bit0 = Level 5-9 +...Bit1 = Level 5-10 ``` ``` -[32-bit] Data Pointer +[32-bit] Pointer to Data +0x638 | Pointer to pointer to smells pointer ++0x6d0 | Pointer to woofs +++0xb8 | Total Woofs [32-bit] @@ -232,22 +244,22 @@ Pointer to P1 Data [16-Bit] ``` ``` -*US* Pointer [32-bits] +[32-bit] *US* Pointer --Player Kratos-- -+0x97898=Health [Float] -+0x6f570=Combo [32-bits] -+0x977a0=Coordinates Y [Float] -+0x977a4=Coordinates Z [Float] -+0x977a8=Coordinates X [Float] ++0x97898= [Float] Health ++0x6f570= [32-bit] Combo ++0x977a0= [Float] Coordinates Y ++0x977a4= [Float] Coordinates Z ++0x977a8= [Float] Coordinates X --Unlockables (Alternative)-- -+0x6f594=Poseidon's Trident [Bit0] -+0x6f598=Poseidon's Rage [Bit0] -+0x6f59c=Medusa's Gaze [Bit0] -+0x6f5a0=Zeus' Fury [Bit0] -+0x6f5a4=Army of Hades [Bit0] -+0x6f5a8=Blade of Artemis [Bit0] ++0x6f594= [Bit0] Poseidon's Trident ++0x6f598= [Bit0] Poseidon's Rage ++0x6f59c= [Bit0] Medusa's Gaze ++0x6f5a0= [Bit0] Zeus' Fury ++0x6f5a4= [Bit0] Army of Hades ++0x6f5a8= [Bit0] Blade of Artemis ``` #### Bad Example diff --git a/docs/public/new-ach-editor.png b/docs/public/new-ach-editor.png new file mode 100644 index 00000000..a85d8ce9 Binary files /dev/null and b/docs/public/new-ach-editor.png differ diff --git a/docs/public/new-asset-list.png b/docs/public/new-asset-list.png new file mode 100644 index 00000000..8fe54fb5 Binary files /dev/null and b/docs/public/new-asset-list.png differ diff --git a/docs/public/new-editor-overview.png b/docs/public/new-editor-overview.png new file mode 100644 index 00000000..c2307880 Binary files /dev/null and b/docs/public/new-editor-overview.png differ diff --git a/docs/public/new-lb-assets-list.png b/docs/public/new-lb-assets-list.png new file mode 100644 index 00000000..438d8b8c Binary files /dev/null and b/docs/public/new-lb-assets-list.png differ diff --git a/docs/public/new-lb-editor.png b/docs/public/new-lb-editor.png new file mode 100644 index 00000000..9137107d Binary files /dev/null and b/docs/public/new-lb-editor.png differ diff --git a/docs/public/new-lb-list.png b/docs/public/new-lb-list.png new file mode 100644 index 00000000..a9bf6555 Binary files /dev/null and b/docs/public/new-lb-list.png differ diff --git a/docs/public/new-lb-web-detail.png b/docs/public/new-lb-web-detail.png new file mode 100644 index 00000000..c8388bef Binary files /dev/null and b/docs/public/new-lb-web-detail.png differ diff --git a/docs/public/new-mario3-ex1.png b/docs/public/new-mario3-ex1.png new file mode 100644 index 00000000..6f383b33 Binary files /dev/null and b/docs/public/new-mario3-ex1.png differ diff --git a/docs/public/new-mario3-ex2.png b/docs/public/new-mario3-ex2.png new file mode 100644 index 00000000..c9086230 Binary files /dev/null and b/docs/public/new-mario3-ex2.png differ diff --git a/docs/public/new-mario3-ex3.png b/docs/public/new-mario3-ex3.png new file mode 100644 index 00000000..f54a27f8 Binary files /dev/null and b/docs/public/new-mario3-ex3.png differ diff --git a/docs/public/new-mario3-ex4.png b/docs/public/new-mario3-ex4.png new file mode 100644 index 00000000..b20f3cb4 Binary files /dev/null and b/docs/public/new-mario3-ex4.png differ diff --git a/docs/public/new-mario3-ex5.png b/docs/public/new-mario3-ex5.png new file mode 100644 index 00000000..70218eb4 Binary files /dev/null and b/docs/public/new-mario3-ex5.png differ diff --git a/docs/public/new-mario3-ex6.png b/docs/public/new-mario3-ex6.png new file mode 100644 index 00000000..f8889344 Binary files /dev/null and b/docs/public/new-mario3-ex6.png differ diff --git a/docs/public/new-mem-insp.png b/docs/public/new-mem-insp.png new file mode 100644 index 00000000..290607c9 Binary files /dev/null and b/docs/public/new-mem-insp.png differ diff --git a/docs/public/new-mem-view.png b/docs/public/new-mem-view.png new file mode 100644 index 00000000..5e345690 Binary files /dev/null and b/docs/public/new-mem-view.png differ diff --git a/docs/public/new-pause-menu.png b/docs/public/new-pause-menu.png new file mode 100644 index 00000000..141b5d12 Binary files /dev/null and b/docs/public/new-pause-menu.png differ diff --git a/docs/public/new-unlocked.png b/docs/public/new-unlocked.png new file mode 100644 index 00000000..5f7bb714 Binary files /dev/null and b/docs/public/new-unlocked.png differ