Claim set · data/claims/golden-sun.yaml

Golden Sun (Coaltergeist's goldensun-decomp)

Game: Golden Sun.

In the matching C of the North American and European release, eight unnamed functions (Func_80bf250 to Func_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), and delude, confuse, charm, stun, and sleep. A counter that reaches 0 ends the effect, and for a modifier also zeroes the modifier. Otherwise the unnamed Func_80bf208 rolls 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's luck − 5T + B) × 655 is at least a 16-bit RPGRandom result, 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_80bf208 calls _GetUnit with 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. golden-sun/status-recovery

About: Golden Sun Status recovery

Value
{
 "luckFactor": 3,
 "turnsFactor": 5,
 "maxTurnsLeft": 5,
 "percentScale": 655,
 "randomRange": 65536,
 "baseAttackDown": 30,
 "baseDefenseDown": 20,
 "baseResistDown": 20,
 "baseDelude": 30,
 "baseConfuse": 60,
 "baseCharm": 70,
 "baseStun": 40,
 "baseSleep": 50
}
Codegoldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · src/battle/mechanics.c#L416-L429unsigned int Func_80bf208(int arg0, int arg1, int arg2) { int v; int t; v = _GetUnit(); if (arg1 <= 5) { int e; e = *(unsigned char *)(v + 0x42); t = (e * 3 - arg1 * 5 + arg2) * 0x28f; if (t >= (_RPGRandom() & 0xffff)) return 1; } …goldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · src/battle/mechanics.c#L431-L457unsigned int Func_80bf250(int unit) { … base = _GetUnit(unit); p = base + 0x132; if (*p != 0) { c = --*p; zero = 0; if (c == 0) { base[0x133] = zero; return 1; } q = (signed char *)(base + 0x133); …goldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · src/battle/mechanics.c#L459-L513p = base + 0x134; … q = (signed char *)(base + 0x135); if (*q < 0) { if (Func_80bf208(unit, *p, 0x14) != 0) { … p = base + 0x136; … q = (signed char *)(base + 0x137); if (*q < 0) { if (Func_80bf208(unit, *p, 0x14) != 0) {goldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · src/battle/mechanics.c#L515-L587p = _GetUnit(unit) + 0x138; if (*p != 0) { if (--*p == 0) return 1; if (Func_80bf208(unit, *p, 0x1e) != 0) { *p = 0; return 1; … p = _GetUnit(unit) + 0x139; … if (Func_80bf208(unit, *p, 0x3c) != 0) { … …goldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · include/rpg.h#L30u8 luck; // 0x042goldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · include/rpg.h#L50-L60u8 attackModTurns; // 0x132 u8 attackMod; // 0x133 u8 defenseModTurns; // 0x134 u8 defenseMod; // 0x135 u8 resistModTurns; // 0x136 u8 resistMod; // 0x137 u8 delude; // 0x138 u8 confuse; // 0x139 u8 charm; // 0x13A u8 stun; // 0x13B u8 sleep; // 0x13Cgoldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · include/macros.inc#L62-L64.macro .export_func sym .thumb_stub _\sym, \sym .endmgoldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · exports/rpg/exports.s#L58.export_func RPGRandomgoldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · src/rpg/random.c#L5-L9unsigned short RPGRandom(void) { … return state >> 8;Checked by claude-agent, 2026-10-22 — read mechanics.c L416-L587 against each counter, base, and branch; rpg.h for the field names; macros.inc and exports.s for _RPGRandom as a stub to RPGRandom. To confirm the r0 reading, disassembled the ROM's bytes at 0xBF208 locally (not committed): push {r5, r6, lr}, r1 and r2 saved, then bl with r0 unchanged; the comparison is a signed blt.

The decompilers' C is matching: src/battle/mechanics.c is a src/<module>/ file, with unfinished functions as INCLUDE_ASM stubs and parked C under src/non_matching/. The mapping of 0x132..0x13C to field names comes from include/rpg.h, since the functions use raw offsets.

Cited by: Golden Sun, Status recovery

Golden Sun's RPGRandom is a linear congruential generator, x←1103515245x+12345(mod232) (0x41C64E6D and 0x3039; the state sRPGRNGState is a 32-bit unsigned int on the GBA), returning state >> 8 as an unsigned short: bits 8 to 23 of the state. RPGRandom2 scales one result to 0 to 99, as RPGRandom × 100 >> 16 (computed). These are the constants of the C standard's example rand, which returns bits 16 to 30 instead. Pokémon Emerald's Random keeps the multiplier but adds 24691 and returns the top 16 bits; pret's random.h defines a second step, ISO_RANDOMIZE2, with Golden Sun's 12345. golden-sun/rng

About: Golden Sun Random number generator

Value
{
 "multiplier": 1103515245,
 "increment": 12345,
 "stateBits": 32,
 "outputShift": 8,
 "outputBits": 16
}
Codegoldensun-decomp: a work-in-progress decompilation of Golden Sun for the Game Boy Advance (Coaltergeist/goldensun-decomp) · src/rpg/random.c#L3-L15extern unsigned int sRPGRNGState; unsigned short RPGRandom(void) { unsigned int state = sRPGRNGState * 0x41c64e6d + 0x3039; sRPGRNGState = state; return state >> 8; } … unsigned short RPGRandom2(void) { extern int RPGRandom_i(void) __asm__("RPGRandom"); return RPGRandom_i() * 0x64 >> 16; }ISO/IEC 9899:TC3, Committee Draft WG14/N1256 (C99 with Technical Corrigenda 1–3) · §7.20.2.2 ¶5, p. 312next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768;pokeemerald: decompilation of Pokémon Emerald · src/random.c#L11-L16u16 Random(void) { gRngValue = ISO_RANDOMIZE1(gRngValue); sRandCount++; return gRngValue >> 16; }pokeemerald: decompilation of Pokémon Emerald · include/random.h#L14-L17// The number 1103515245 comes from the example implementation of rand and srand // in the ISO C standard. #define ISO_RANDOMIZE1(val) (1103515245 * (val) + 24691) #define ISO_RANDOMIZE2(val) (1103515245 * (val) + 12345)Checked by claude-agent, 2026-10-22 — read goldensun random.c L3-L15, pokeemerald random.c L11-L16 and random.h L14-L17, and the C99 example in the PDF's text (sha256 matches the pin); 0x41c64e6d = 1103515245 and 0x3039 = 12345

The C standard's next is an unsigned long, at least 32 bits (rpg-battle/c99-example-lcg).

Cited by: Golden Sun