Skip to content

Achievement Templates

WARNING: EVERY GAME IS DIFFERENT!

Here you'll see examples of some typical achievements. You can use them as inspiration to create your own achievement. But keep in mind the following:

EVERY GAME IS DIFFERENT! The memory has a different behavior from game to game.

So do NOT take these templates as a rule. They are here just for educational purposes.

In these examples we use the following convention 0xLEVEL is the memory address with the level ID; 0xLIFE is the address used for the character life; 0xTIME for time, 0xITEM for getting an item, etc...

Collecting an Item N times

There are some situations where you want to award an achievement for collecting an item (like a coin or a ring) N times. You'll need to find in the memory the address responsible to count how much of the item you have. Once you have the address, this logic usually does the job:

IDFlagTypeMemoryCmpTypeMem/ValHits
1Mem0xCOUNT>Delta0xCOUNT(N)

But you most likely will want to be more specific, for example "get item N times without dying". Then you should use another condition with a ResetIf, like this:

IDFlagTypeMemoryCmpTypeMem/ValHits
1Mem0xCOUNT>Delta0xCOUNT(N)
2ResetIfMem0xLIVES<Delta0xLIVES

The ResetIf condition could be "while in level X", "without using a bomb", etc.

Finish Level N

In this example we want to award when the player finish the level N and goes to level N+1.

IDFlagTypeMemoryCmpTypeMem/ValHits
1Delta0xLEVEL=ValueN(0)
2Mem0xLEVEL=ValueN+1(0)

Requirements

  • 1: On Level N in previous frame.
  • 2: Now at level N+1 on current frame.

This logic is true only on the exact frame the level advances from N to N+1, which makes it safe from being triggered by a level select cheat or loading a password to Level N+1. For robust achievement logic, you'll want other conditions too, such as checking the player is in-game or there is no demo active.

Finish Level N Before Time Reaches T

In this example we consider a game where the time decreases (e.g.: Super Mario Bros). Adapt it accordingly the time on your game has a different behavior.

We want to award if the player finishes the level N while time is greater than T.

IDFlagTypeMemoryCmpTypeMem/ValHits
1Delta0xLEVEL=ValueN
2TriggerMem0xLEVEL=ValueN+1
3Mem0xTIME>ValueT

Requirements

  • 1-2: Functionally the same as conditions 1-2 from the Finish Level N template, but with a Trigger on the final line so that the challenge icon shows to the player while the challenge is active.
  • 3: Ensure the TIME address has a value greater than the failure time. When the time is at or below this value, a non-Trigger-flagged condition is now false and the challenge icon will disappear, indicating a failure to the user.

Notes

  • Keep in mind that besides knowing how the time behaves in game you also need to research how it behaves in memory.

Finish Level N In Under Time T When There Is No In-Game Timer

In this example we consider a game where there is no in-game timer to use for a speed run.

We want to award if the player finishes the level N before a time T in the level, calculated as number of frames, has passed.

IDFlagTypeMemoryCmpTypeMem/ValHits
1Delta0xLEVEL=ValueN
2TriggerMem0xLEVEL=ValueN+1
3PauseIfMem0xLEVEL=ValueN(T*FRAMERATE)

Requirements

  • 1-2: Functionally the same as conditions 1-2 from the Finish Level N template, but with a Trigger on the final line so that the challenge icon shows to the player while the challenge is active.
  • 3: The hit target T*FRAMERATE should be set equal to the number of frames that equal the time at which the challenge fails. For a system that runs at 60 frames per second, T*FRAMERATE = TimeInSeconds x 60. When the player is in the level for that many frames, the PauseIf will become true and locked achievement processing in the core group until a Reset occurs (see Notes, below).

Notes

  • A player should be able to re-try this challenge. You will need a Reset to clear the pause lock at an appropriate time, such as dying. You can use a ResetIf in an alt group (an active PauseIf will prevent a reset in the core group from working), or you can attach a ResetNextIf right before the PauseIf.
  • You may want some other conditions on the PauseIf. You can link more using AndNext flag. If a game has a flag that indicates the player has control of the character, this may be a good choice. Experiment!

Finish Level N without Dying

(or getting hit, using a weapon, etc.)

IDFlagTypeMemoryCmpTypeMem/ValHits
1AndNextMem0xLEVEL=ValueN
2Mem0xLVL_STATE=ValueLVL_N_INTRO(1)
3Delta0xLEVEL=ValueN
4TriggerMem0xLEVEL=ValueN+1
5ResetIfMem0xLEVEL=ValueTITLE
6AndNextMem0xLEVEL=ValueN
7ResetIfMem0xLIVES<Delta0xLIVES

Requirements

  • 1-2 Supposes there is a LEVEL_STATE address that has values like "In Level Intro Screen," "Playing Level," etc and sets a checkpoint hit when you are in the correct level's intro. This is a stand in for some "checkpoint" where you want the challenge to start. You will need to determine the proper conditions and timing and set up your own appropriate start checkpoint.
  • 3-4: Functionally the same as conditions 1-2 from the Finish Level N template, but with a Trigger on the final line so that the challenge icon shows to the player while the challenge is active.
  • 5: Resets the start checkpoint if the player has a game over or otherwise is able to quit back to the title screen early. Prevents the checkpoint hit from sticking around when it shouldn't.
  • 6-7: A Reset for when the LEVEL address has the value of level N and the LIVES address is less than it was on the previous frame, indicating the player lost a life. Clears the starting checkpoint hit and so fails the challenge.

Notes

  • The requirements in 6-7 can also be modified to reset hit count if a weapon was used, damage taken, or anything else that you want the player to NOT do. -The requirements in 1-2 may vary widely depending on the game.

Finish Level N with Item

IDFlagTypeMemoryCmpTypeMem/ValHits
1Delta0xLEVEL=ValueN(0)
2TriggerMem0xLEVEL=ValueN+1(0)
3Mem0xITEM=ValueTRUE(0)

Requirements

  • 1-2: Functionally the same as conditions 1-2 from the Finish Level N template, but with a Trigger on the final line so that the challenge icon shows to the player while the challenge is active.
  • 3: Value that is true when the player has the correct item. The lack of a Trigger flag here allows the icon to appear while the player has the item, and disappear when the player does not have it.

Collect an Item In a Specific Level

This template is for battery save or password protection for items. It avoids awarding "get item X" by loading a password or save where the player already has the item. It checks that an item is collected in the level/room ID it is supposed to be collected, and only allows it be earned at that time.

IDFlagTypeMemoryCmpTypeMem/ValHits
1Mem0xLEVEL=ValueCOLLECT_LEVEL(0)
2Mem0xLEVEL=Delta0xLEVEL(0)
3Delta0xITEM=ValueFALSE(0)
4Mem0xITEM=ValueTRUE(0)

Requirements

  • 1-2: Must be in the correct Level (COLLECT_LEVEL) for at least two frames during the frame at which the item status changes, preventing the following conditions from triggering the logic on load.
  • 3: Did not have the item last frame
  • 4: Have the item on the current frame.

Notes

  • Requirements 1 and 2 together mean you have to have been in the level for at least two frames. The frame at which you load the data (from password or save) will be considered false, so any change in the item status at this time won't cause the trigger.
  • It does not necessarily have to be level/Room ID. There are other ways to approach this problem, for example a unique Mem/Val that only occurs on collection. Etc.

Collected 100 Percent of Something

This is limited battery save/password protection for when a player will collect 100% of something like clearing each stage in Super Mario world, or getting a 100% collection rate in Super Metroid. It's necessary so that a player cannot just load a save at 100% and get the achievement for free. (As usual there are other ways to approach this problem too.)

IDFlagTypeMemoryCmpTypeMem/ValHits
1Delta0xCollectPercent<Value100% value
2Mem0xCollectPercent=Value100% value
3Mem0xGuardConditions=ValueWhen to Check for Increase

Using the correct condition or conditions for requirement 3+ is especially important. You need to find an address or addresses that represents a unique time in the game where this percent increases. You'd not want the achievement to trigger when the player is loading their in game save file, which means this achievement must evaluate to False at that time.

Examples

IDFlagTypeMemoryCmpTypeMem/ValHits
3Mem0xGAME_STATE=ValueIN_GAME(0)
4Mem0xGAME_STATE=Delta0xGAME_STATE(0)
  • In Super Mario World this change happens while the player sees the world map after completing a stage. So you construct your conditions for this timing in a way to distinguish that from loading a save. Here the player state would be
IDFlagTypeMemoryCmpTypeMem/ValHits
3Mem0xPlayerState=ValueReturned to map from completed

Circumvent the Problem of a Counter Incrementing Twice in the Same Frame

In the Collecting an Item N times we are counting how many times the counter goes up. But in some games there are situations where the counter goes up twice in the same frame, and the hit counter is incremented only by one. This behavior, obviously, ruins our logic. We're going to see a way to circumvent this issue.

The technique used here relies on two other ones:

Here's the trick:

IDFlagTypeMemoryCmpTypeMem/ValHits
1SubSourceDelta0xCOUNT
2AddHitsMem0xCOUNT=Value0x02
3Mem0xCOUNT>Delta0xCOUNT(N)
4ResetIfMem0xLIVES<Delta0xLIVES

It can look a bit confusing at a first sight, but maybe using a real example it can be more clear. Check the Circumvent the Problem of a Counter Incrementing Twice in the Same Frame.

Check for a Specific Value Changing to Another Specific Value Ten Times

In this example we want to detect a value changing from V1 to V2 ten times:

IDFlagTypeMemoryCmpTypeMem/ValHits
1AndNextDelta0xADDRESS=Value0xV1
2Mem0xADDRESS=Value0xV2(10)

Requirements

  • 1: If value in 0xADDRESS in the previous frame is 0xV1
  • 2: AND If the current value in 0xADDRESS is 0xV2, increases the hitcount (up to 10).

Conditional Resets

Conditional resets can be used for many things.

Lets say you want to have a reset if a player enters a certain X and Y zone of a level:

CORE

  • The Core is whatever condition(s) you need for your achievement to be true. It can also include normal reset behavior.

ALT1

IDFlagTypeMemoryCmpTypeMem/Val
1ResetIfMem0xLEVEL=ValueLEVELID
2PauseIfMem0xX-COORDS>ValueRESET-X-ZONE
3PauseIfMem0xX-COORDS<ValueRESET-X-ZONE
4PauseIfMem0xY-COORDS>ValueRESET-Y-ZONE
5PauseIfMem0xY-COORDS<ValueRESET-Y-ZONE
  • The reset will only happen if all of the PauseIf conditions are not true.
  • The pause is local to the alt but the reset resets the entire achievement.

ALT2

IDFlagTypeMemoryCmpTypeMem/Val
1Mem0x1=Mem0x1
  • Any true condition. (to satisfy alt behavior having an always true alt is needed)

Notes

  • You can use multiple conditional resets, each one in their own alt group to have far greater control of reset behavior.

Pause Until-Using PauseIf to Prevent Achievement Processing Until Some Condition is Met

Sometimes it will be very difficult to identify an on-going timing for when to process hit counts or other hit-related events. Or, there are a lot of conditions for when something might look valid, but not be valid. This situation may lead to convoluted logic in order to guard against invalid hit counts. One method to mitigate this is a Pause Until:

Basic Construction of the "Pause Until"

IDFlagTypeMemoryCmpTypeMem/ValHits
1AndNextDelta0xSTATE=ValueVALUE_A0 (0)
2ResetNextIfMem0xSTATE=ValueVALUE_B1 (0)
3PauseIfValue1=Value10 (0)

Explanation of Conditions:

  • 1-2: This transition from VALUE_A to VALUE_B may mark the 'start of game/level/sequence' definitively. However, VALUE_B may not definitively identify the 'in-game/in-level/in-sequence' that you care about for the challenge. The ResetNextIf here will latch to true upon this transition and suppress the "always-true" PauseIf in the following condition, allowing the rest of the logic to be processed. The single hit target here is important for this to function properly.
  • 3: This PauseIf condition will always be true. That is, unless the ResetNextIf before it is latched to 'true' but receiving a hit towards its target of 1 hit! That's what makes this a "Pause Until" structure: The group is paused until the ResetNextIf occurs.

An Example of Logic towards an Achievement

Suppose our actual goal is to "Complete Game/Level/Sequence in under X units of time without losing health."

IDFlagTypeMemoryCmpTypeMem/ValHits
4Delta0xCOMPLETE_FLAG=Value00 (0)
5TriggerMem0xCOMPLETE_FLAG=Value10 (0)

In place of conditions 4 and 5 here, you would use whatever logic definitively identifies the completion of the challenge you are constructing. This is just one example of a set of conditions you might have to identify the completion of the challenge.

IDFlagTypeMemoryCmpTypeMem/ValHits
6ResetIfMem0xHEALTH<Delta0xHEALTH0 (0)
7ResetIfValue0=Value0x0NUM_FRAMES_EQUAL_TO_TIME_X (0)

Here, either ResetIf statement will remove the hit from the ResetNextIf and result in the achievement becoming Paused, preventing the timing hits from accruing until the game/level/sequence start transition happens again. Because the group is paused until the challenge starts, the timer reset will never falsely accrue hits outside of the challenge.

Something To Keep In Mind

There will rarely be a time where this structure is needed. Usually the developer should be able to find some conditions to join with the timer or other counter (using the AndNext flag, etc) in order to restrict them to a specific window, along with any other resets needed to clear the counter hits to zero for other failure cases.

Changelog

Released under the GPL-3 License. There are no copyright-protected ROMs available for download on RetroAchievements.