EarthBound Beginnings/RAM map: Difference between revisions

From Data Crystal
Jump to navigation Jump to search
(Created page with '*$49-Enemy Encounters {| border="1" cellpadding="1"| '''Number''' || '''Function''' || '''Details''' |00||Nothing|| |- |01||Rat|| |- |02||2 rats|| |- |03||Crow|| |- |04||2 crows|…')
 
(→‎RAM: Add walk cycle timing)
 
(34 intermediate revisions by 9 users not shown)
Line 1: Line 1:
*$49-Enemy Encounters
{{rammap|game=EarthBound Beginnings}}
{| border="1" cellpadding="1"| '''Number''' || '''Function''' || '''Details'''
 
|00||Nothing||
=RAM=
 
{|border="1" cellpadding="1"
!RAM !! Purpose
|-
|0x0006 || Part of an instruction for "copy protection". $E5 on checksum failure. $00 to bypass.  "Correct"/non-hack value unknown.
|-
|0x000C || Direction Ninten is facing: 00: U. 01: U-R. 2: R. 3: R-D. 04: D. 5: D-L. 6: L. 7: L-U.
|-
|0x0015 || Current area the player is in
|-
|0x0018-0x001B || The X and Y coordinates, stored strangely; see below
|-
|0x0026-0x0027 || Used for RNG
|-
|0x0029 || Items?
|-
|0x0030-0x0031 || Pointer to [[EarthBound Beginnings/Object state data|object state data]] currently being accessed
|-
|0x003A-0x003B || New X Position of current object after movement is applied
|-
|-
|01||Rat||
|0x003C-0x003D || New Y Position of current object after movement is applied
|-
|-
|02||2 rats||
|0x003E || Movement direction of current object (see 0x00A0)
|-
|-
|03||Crow||
|0x0047 || In combat, tracks if combat is active.  00 = combat active.  01 = combat finished.
|-
|-
|04||2 crows||
|0x0048 || Which [[EarthBound Beginnings/Enemy groups#Groups|enemy group]] is being fought.
|-
|-
|05||Centipede||
|0x0056 || In combat, tracks if a boss is being fought.  00 = normal enemy.  Other values = boss ID.
|-
|-
|06||2 Centipedes||
|0x0060 || HP target value for stat increase during level up
|-
|-
|07||Stray Dog||
|0x00A0 || Direction is Ninten moving: 88: Standing still. 00: U. 01: U-R. 2: R. 3: R-D. 04: D. 5: D-L. 6: L. 7: L-U.
|-
|-
|08||Wally||
|0x00AA-0x00AB || New X Position of current object after movement is applied, stored as below
|-
|-
|09||Hippie||
|0x00AC-0x00AD || New Y Position of current object after movement is applied, stored as below
|-
|-
|0A||Bag Lady||
|0x00D9 || Controller 1 button data. [0]: Right. [1]: Left. [2]: Down. [3]: Up. [4]: Start. [5]: Select. [6]: B. [7]: A.
|-
|-
|0B||Snake||
|0x00E7 || Walk cycle timing
|-
|-
|0C||Mr. Bat||
|0x0110-0x014F || Buffer to hold data retrieved from PPU.
|-
|-
|0D||2 Mr. Bats||
|0x0600-0x061F || Ninten [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|-
|-
|0E|| ||
|0x0620-0x063F || Ally 1 [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|-
|-
|0F|| ||
|0x0640-0x065F || Ally 2 [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|-
|-
|0x0660-0x067F || Ally 3 [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|-
|0x0680-0x069F || Enemy 1 [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|-
|0x06A0-0x06BF || Enemy 2 [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|-
|0x06C0-0x06DF || Enemy 3 [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|-
|0x06E0-0x06FF || Enemy 4 [[EarthBound Beginnings/Battle Engine#Combat data|combat state]]
|}
===Coordinates===
The coordinates in RAM to not correspond to coordinates in the rest of the game.  To convert it, run this Python code (in this example, bytes $818-B are `80 19 C0 2D`):


<pre>
# replace with the values from the RAM
ram_x = 0x8019
ram_y = 0xc02d


byte0, byte1 = ram_x.to_bytes(2, "little")
byte2, byte3 = ram_y.to_bytes(2, "little")


|}
real_x = ((byte0 << 8) | (byte1 & 0xC0)) >> 2
real_y = ((byte2 << 8) - 0x1e00 | (byte3 & 0xC0)) >> 2
 
print((real_x, real_y))
</pre>
 
=SRAM (save data)=
Add $6000 to the SRAM offsets below to get the actual locations in CPU memory.
==Entire SRAM==
There are multiple saves throughout the save RAM, three for the saved data and one for the last save.  The last save is the one that was saved last, and unless an error occurred during saving, should be identical to the save slot that was last saved.
===Save RAM===
* 0000-77F: Unknown
* 780-79F: Ninten [[EarthBound Beginnings/Object state data|object state data]]
* 7A0-7F0: Unknown
* 800-D0F: Misc [[EarthBound Beginnings/Object state data|object state data]]
* 1400-16FF: Last save
* 1700-19FF: Save slot 1
* 1A00-1CFF: Save slot 2
* 1D00-1FFF: Save slot 3
 
==Saves==
Each save has this format:
===Slot metadata===
The 2-byte checksum is calculated by subtracting each byte after it (0x300 for each save, so 0x29E bytes to subtract), then running it through mod 0x10000.
Here is an example Python program that verifies it:
<pre>
def calculate_checksum(handle, slot = 0): # 0 = last save
    handle.seek(0x1400 + slot * 0x300)
    ram_checksum = int.from_bytes(handle.read(2), "little") # read the checksum from the RAM
 
    # calculate it manually
    calculated_checksum = 0x0
    for number in range(0x300 - 0x2):
        calculated_checksum = (calculated_checksum - int.from_bytes(handle.read(2), "little")) % 0x100 ** 2 # this is ran for each byte other then the checksum
 
    assert ram_checksum == calculated_checksum, "checksum is invalid" # throw an error if the checksum doesn't match
    return calculated_checksum
calculate_checksum(open("file.sav", "rb"))
</pre>
* 1400-1401: Checksum
* 1402: Slot number
*:$B0 for slot 1, $B1 for slot 2 and $B2 for slot 3
* 1403: Slot state
*:Normally $7E, deleted slots are $00.  It's possible to recover an accidentally deleted save slot by changing this back
===Main data===
* 1404-1407: Position
* 1408-140B: Current party members
*:Each number corresponds to an ally in [[EarthBound Zero:Ally data|Ally data]], 0 means empty and skips to the next value
* 140C-140F: Last save position
*:Right before showing the XP needed to level up for each character (during Dad's phone call), the game copies the position to this address, meaning that this is always the position you were when you last phoned Dad (regardless of whether you saved or not); changing it doesn't affect the position when loading the save
* 1410-1411: Current money
* 1412-1414: Money in bank
* 1415-141F: '''Unknown'''
* 1420-1430: Your name (the player name, not Ninten's name)
* 1431-143F: '''Unknown'''
===Ally status===
This is documented [[#Ally state|below]].
* 1440-147F: Ninten
* 1480-14BF: Ana
* 14C0-14FF: Lloyd
* 1500-153F: Teddy
* 1540-157F: Pippi
* 1580-15BF: EVE
* 15C0-15FF: Flying Man
===Other===
* 1600-1688: '''Unknown, except: '''
** 161D: Unlocked teleport locations
** 161E: Known melodies
* 1689-1983: Favorite food name
* 1984-16AF: '''Unknown'''
* 16B0-16CF: Items in storage
* 16D0-16FF: '''Unknown'''
 
==Ally state==
Each ally's state is stored at a place corresponding to the character, see the above section
* 00: Unknown (unused?)
* 01: Status condition
** Bit 0: Cold
** Bit 1: Poisoned
** Bit 2: Puzzled
** Bit 3: Confused
** Bit 4: Sleeping
** Bit 5: Paralyzed
** Bit 6: Stone
** Bit 7: Unconscious (can be applied even when HP isn't at 0)
* 02: '''Unknown'''
* 03-04: Max HP
* 05-06: Max PP
* 07-08: Offense
* 09-0A: Defense
* 0B: Fight
* 0C: Speed
* 0D: Wisdom
* 0E: Strength
* 0F: Force
* 10: Level
* 11-13: Experience
* 14-15: Current HP
* 16-17: Current PP
* 18-19: '''Unknown'''
* 20-27: Items
* 28: Weapon
* 29: Coin
* 2A: Ring
* 2B: Pendant
* 30-37: Learned PSI
* 38-3E: Name
* 3F: Unknown (unused?)
{{Internal Data|game=EarthBound Beginnings}}

Latest revision as of 14:28, 20 May 2025

Chip tiny.png The following article is a RAM map for EarthBound Beginnings.

RAM

RAM Purpose
0x0006 Part of an instruction for "copy protection". $E5 on checksum failure. $00 to bypass. "Correct"/non-hack value unknown.
0x000C Direction Ninten is facing: 00: U. 01: U-R. 2: R. 3: R-D. 04: D. 5: D-L. 6: L. 7: L-U.
0x0015 Current area the player is in
0x0018-0x001B The X and Y coordinates, stored strangely; see below
0x0026-0x0027 Used for RNG
0x0029 Items?
0x0030-0x0031 Pointer to object state data currently being accessed
0x003A-0x003B New X Position of current object after movement is applied
0x003C-0x003D New Y Position of current object after movement is applied
0x003E Movement direction of current object (see 0x00A0)
0x0047 In combat, tracks if combat is active. 00 = combat active. 01 = combat finished.
0x0048 Which enemy group is being fought.
0x0056 In combat, tracks if a boss is being fought. 00 = normal enemy. Other values = boss ID.
0x0060 HP target value for stat increase during level up
0x00A0 Direction is Ninten moving: 88: Standing still. 00: U. 01: U-R. 2: R. 3: R-D. 04: D. 5: D-L. 6: L. 7: L-U.
0x00AA-0x00AB New X Position of current object after movement is applied, stored as below
0x00AC-0x00AD New Y Position of current object after movement is applied, stored as below
0x00D9 Controller 1 button data. [0]: Right. [1]: Left. [2]: Down. [3]: Up. [4]: Start. [5]: Select. [6]: B. [7]: A.
0x00E7 Walk cycle timing
0x0110-0x014F Buffer to hold data retrieved from PPU.
0x0600-0x061F Ninten combat state
0x0620-0x063F Ally 1 combat state
0x0640-0x065F Ally 2 combat state
0x0660-0x067F Ally 3 combat state
0x0680-0x069F Enemy 1 combat state
0x06A0-0x06BF Enemy 2 combat state
0x06C0-0x06DF Enemy 3 combat state
0x06E0-0x06FF Enemy 4 combat state

Coordinates

The coordinates in RAM to not correspond to coordinates in the rest of the game. To convert it, run this Python code (in this example, bytes $818-B are `80 19 C0 2D`):

# replace with the values from the RAM
ram_x = 0x8019
ram_y = 0xc02d

byte0, byte1 = ram_x.to_bytes(2, "little")
byte2, byte3 = ram_y.to_bytes(2, "little")

real_x = ((byte0 << 8) | (byte1 & 0xC0)) >> 2
real_y = ((byte2 << 8) - 0x1e00 | (byte3 & 0xC0)) >> 2

print((real_x, real_y))

SRAM (save data)

Add $6000 to the SRAM offsets below to get the actual locations in CPU memory.

Entire SRAM

There are multiple saves throughout the save RAM, three for the saved data and one for the last save. The last save is the one that was saved last, and unless an error occurred during saving, should be identical to the save slot that was last saved.

Save RAM

  • 0000-77F: Unknown
  • 780-79F: Ninten object state data
  • 7A0-7F0: Unknown
  • 800-D0F: Misc object state data
  • 1400-16FF: Last save
  • 1700-19FF: Save slot 1
  • 1A00-1CFF: Save slot 2
  • 1D00-1FFF: Save slot 3

Saves

Each save has this format:

Slot metadata

The 2-byte checksum is calculated by subtracting each byte after it (0x300 for each save, so 0x29E bytes to subtract), then running it through mod 0x10000. Here is an example Python program that verifies it:

def calculate_checksum(handle, slot = 0): # 0 = last save
    handle.seek(0x1400 + slot * 0x300)
    ram_checksum = int.from_bytes(handle.read(2), "little") # read the checksum from the RAM

    # calculate it manually
    calculated_checksum = 0x0
    for number in range(0x300 - 0x2):
        calculated_checksum = (calculated_checksum - int.from_bytes(handle.read(2), "little")) % 0x100 ** 2 # this is ran for each byte other then the checksum

    assert ram_checksum == calculated_checksum, "checksum is invalid" # throw an error if the checksum doesn't match
    return calculated_checksum
calculate_checksum(open("file.sav", "rb"))
  • 1400-1401: Checksum
  • 1402: Slot number
    $B0 for slot 1, $B1 for slot 2 and $B2 for slot 3
  • 1403: Slot state
    Normally $7E, deleted slots are $00. It's possible to recover an accidentally deleted save slot by changing this back

Main data

  • 1404-1407: Position
  • 1408-140B: Current party members
    Each number corresponds to an ally in Ally data, 0 means empty and skips to the next value
  • 140C-140F: Last save position
    Right before showing the XP needed to level up for each character (during Dad's phone call), the game copies the position to this address, meaning that this is always the position you were when you last phoned Dad (regardless of whether you saved or not); changing it doesn't affect the position when loading the save
  • 1410-1411: Current money
  • 1412-1414: Money in bank
  • 1415-141F: Unknown
  • 1420-1430: Your name (the player name, not Ninten's name)
  • 1431-143F: Unknown

Ally status

This is documented below.

  • 1440-147F: Ninten
  • 1480-14BF: Ana
  • 14C0-14FF: Lloyd
  • 1500-153F: Teddy
  • 1540-157F: Pippi
  • 1580-15BF: EVE
  • 15C0-15FF: Flying Man

Other

  • 1600-1688: Unknown, except:
    • 161D: Unlocked teleport locations
    • 161E: Known melodies
  • 1689-1983: Favorite food name
  • 1984-16AF: Unknown
  • 16B0-16CF: Items in storage
  • 16D0-16FF: Unknown

Ally state

Each ally's state is stored at a place corresponding to the character, see the above section

  • 00: Unknown (unused?)
  • 01: Status condition
    • Bit 0: Cold
    • Bit 1: Poisoned
    • Bit 2: Puzzled
    • Bit 3: Confused
    • Bit 4: Sleeping
    • Bit 5: Paralyzed
    • Bit 6: Stone
    • Bit 7: Unconscious (can be applied even when HP isn't at 0)
  • 02: Unknown
  • 03-04: Max HP
  • 05-06: Max PP
  • 07-08: Offense
  • 09-0A: Defense
  • 0B: Fight
  • 0C: Speed
  • 0D: Wisdom
  • 0E: Strength
  • 0F: Force
  • 10: Level
  • 11-13: Experience
  • 14-15: Current HP
  • 16-17: Current PP
  • 18-19: Unknown
  • 20-27: Items
  • 28: Weapon
  • 29: Coin
  • 2A: Ring
  • 2B: Pendant
  • 30-37: Learned PSI
  • 38-3E: Name
  • 3F: Unknown (unused?)