Golden Sun
Camelot's 2001 Game Boy Advance role-playing game, read through Coaltergeist's goldensun-decomp, a matching decompilation in progress.
On this page
Golden Sun is Camelot Software Planning’s 2001 role-playing game for the Game Boy Advance. The code read here is Coaltergeist’s goldensun-decomp, which builds a byte-identical North American and European ROM. Its battle damage, critical, and Psynergy formulas were still assembly at the commit read.
A lowered stat or a status such as Sleep can end early, on a roll that the unit’s Luck raises and the turns left lower1. The rolls come from a linear congruential generator with the C standard’s example constants, where Pokémon Emerald’s generator adds 246912.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Status recovery | Stat roll | a lowered stat or a status ends at 0 turns, or earlier on a roll of about (3 × Luck − 5 × turns left + a base)% once 5 or fewer turns remain |
| Random number generator | Formula | the C standard's example constants, 1103515245 and 12345, with bits 8 to 23 as the result |
Every claim about this game, by concept (2)
References
- ^In the matching C of the North American and European release, eight unnamed functions (
Func_80bf250toFunc_80bf484) each count down one of a unit's turn counters by 1 per call: the attack, defense, and resist modifiers (attackModTurns,defenseModTurns,resistModTurns, field names from the decompilers'struct Unit), anddelude,confuse,charm,stun, andsleep. A counter that reaches 0 ends the effect, and for a modifier also zeroes the modifier. Otherwise the unnamedFunc_80bf208rolls for an early end, with the turns left T and a base B per counter: 30 for an attack modifier, 20 for defense and resist, 30 for delude, 60 for confuse, 70 for charm, 40 for stun, 50 for sleep. A modifier rolls only while it is negative (a lowered stat), so a raised stat lasts its full count. The roll happens only when T is 5 or less, and succeeds when (3 × the unit'sluck− 5T + B) × 655 is at least a 16-bitRPGRandomresult, so a check succeeds about (3 × Luck − 5T + B)% of the time (computed: 655 is about 1% of 65,536; the comparison is signed, so a negative sum never succeeds, and a sum over 100 always does). Success zeroes the counter, and a modifier's value too.Func_80bf208calls_GetUnitwith no argument, so the unit it reads is whatever its first argument left in r0, the unit being checked (the atlas's reading of the matching build). Which routines call these eight, and how often, is still assembly.CodeCoaltergeist/goldensun-decompHow we know
416unsigned int Func_80bf208(int arg0, int arg1, int arg2) ⋮ 418 int v; 419 int t; 420 v = _GetUnit(); 421 if (arg1 <= 5) { 422 int e; 423 e = *(unsigned char *)(v + 0x42); 424 t = (e * 3 - arg1 * 5 + arg2) * 0x28f; 425 if (t >= (_RPGRandom() & 0xffff)) 426 return 1; ⋮ 428 return 0;
src/battle/mechanics.c lines 416–429 at 2e5c504 · upstream ↗ 431unsigned int Func_80bf250(int unit) { ⋮ 438 base = _GetUnit(unit); 439 p = base + 0x132; 440 if (*p != 0) { 441 c = --*p; 442 zero = 0; 443 if (c == 0) { 444 base[0x133] = zero; 445 return 1; ⋮ 447 q = (signed char *)(base + 0x133); 448 if (*q < 0) { 449 if (Func_80bf208(unit, *p, 0x1e) != 0) { ⋮
src/battle/mechanics.c lines 431–457 at 2e5c504 · upstream ↗ 467 p = base + 0x134; ⋮ 475 q = (signed char *)(base + 0x135); 476 if (*q < 0) { 477 if (Func_80bf208(unit, *p, 0x14) != 0) { ⋮ 495 p = base + 0x136; ⋮ 503 q = (signed char *)(base + 0x137); 504 if (*q < 0) { 505 if (Func_80bf208(unit, *p, 0x14) != 0) {
src/battle/mechanics.c lines 459–513 at 2e5c504 · upstream ↗ 518 p = _GetUnit(unit) + 0x138; 519 if (*p != 0) { 520 if (--*p == 0) 521 return 1; 522 if (Func_80bf208(unit, *p, 0x1e) != 0) { 523 *p = 0; 524 return 1; ⋮ 533 p = _GetUnit(unit) + 0x139; 534 if (*p != 0) { 535 if (--*p == 0) 536 return 1; 537 if (Func_80bf208(unit, *p, 0x3c) != 0) { ⋮
src/battle/mechanics.c lines 515–587 at 2e5c504 · upstream ↗ 30 u8 luck; // 0x042include/rpg.h line 30 at 2e5c504 · upstream ↗ 50 u8 attackModTurns; // 0x132 51 u8 attackMod; // 0x133 52 u8 defenseModTurns; // 0x134 53 u8 defenseMod; // 0x135 54 u8 resistModTurns; // 0x136 55 u8 resistMod; // 0x137 56 u8 delude; // 0x138 57 u8 confuse; // 0x139 58 u8 charm; // 0x13A 59 u8 stun; // 0x13B 60 u8 sleep; // 0x13C
include/rpg.h lines 50–60 at 2e5c504 · upstream ↗ 62 .macro .export_func sym 63 .thumb_stub _\sym, \sym 64 .endm
include/macros.inc lines 62–64 at 2e5c504 · upstream ↗ 58 .export_func RPGRandomexports/rpg/exports.s line 58 at 2e5c504 · upstream ↗ 5unsigned short RPGRandom(void) { ⋮ 8 return state >> 8;
src/rpg/random.c lines 5–9 at 2e5c504 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-27.
- ^Golden Sun's
RPGRandomis a linear congruential generator, (0x41C64E6D and 0x3039; the statesRPGRNGStateis a 32-bit unsigned int on the GBA), returningstate >> 8as an unsigned short: bits 8 to 23 of the state.RPGRandom2scales one result to 0 to 99, as RPGRandom × 100 >> 16 (computed). These are the constants of the C standard's examplerand, which returns bits 16 to 30 instead. Pokémon Emerald'sRandomkeeps the multiplier but adds 24691 and returns the top 16 bits; pret'srandom.hdefines a second step,ISO_RANDOMIZE2, with Golden Sun's 12345.CodeCoaltergeist/goldensun-decomp · C99 draft N1256 · pret/pokeemeraldHow we know
3extern unsigned int sRPGRNGState; ⋮ 5unsigned short RPGRandom(void) { 6 unsigned int state = sRPGRNGState * 0x41c64e6d + 0x3039; 7 sRPGRNGState = state; 8 return state >> 8; ⋮ 12unsigned short RPGRandom2(void) { 13 extern int RPGRandom_i(void) __asm__("RPGRandom"); 14 return RPGRandom_i() * 0x64 >> 16;
src/rpg/random.c lines 3–15 at 2e5c504 · upstream ↗ next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768;
§7.20.2.2 ¶5, p. 312 · archived copy ↗ 11u16 Random(void) ⋮ 13 gRngValue = ISO_RANDOMIZE1(gRngValue); 14 sRandCount++; 15 return gRngValue >> 16;
src/random.c lines 11–16 at 731ad5b · upstream ↗ 14// The number 1103515245 comes from the example implementation of rand and srand 15// in the ISO C standard. 16#define ISO_RANDOMIZE1(val) (1103515245 * (val) + 24691) 17#define ISO_RANDOMIZE2(val) (1103515245 * (val) + 12345)
include/random.h lines 14–17 at 731ad5b · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-27.
Sources
Code
- Coaltergeist and goldensun-decomp contributors. 2026. “goldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp).” Commit 2e5c504. Coaltergeist/goldensun-decomp @ 2e5c504 · licence, all uses
- pret contributors. 2026. “pokeemerald: decompilation of Pokémon Emerald.” pret. Commit 731ad5b. pret/pokeemerald @ 731ad5b · licence, all uses
Primary
- JTC1/SC22/WG14, ISO/IEC. 2007. “ISO/IEC 9899:TC3, Committee Draft WG14/N1256 (C99 with Technical Corrigenda 1–3).” ISO/IEC JTC1/SC22/WG14. original · archived · licence, all uses