diff options
author | yenatch <yenatch@gmail.com> | 2017-09-03 18:11:57 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-03 18:11:57 -0400 |
commit | 7ea0d462c49360351006f246f0a300aaa765a843 (patch) | |
tree | c930fe4733b8ae2bc02940ae6a35fbf73f933aca /src | |
parent | cbe13acff18405e99827df7c4a772d20b851f33b (diff) | |
parent | 5afd2d5bfb1ec117d80898d9ad1c2529d28a091c (diff) |
Merge pull request #22 from DizzyEggg/clean_up
bring pokeemerald to usable state
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_ai.c | 294 | ||||
-rw-r--r-- | src/decompress.c | 597 | ||||
-rw-r--r-- | src/event_data.c | 236 | ||||
-rw-r--r-- | src/item.c | 228 | ||||
-rw-r--r-- | src/main.c | 6 | ||||
-rw-r--r-- | src/malloc.c | 4 | ||||
-rw-r--r-- | src/new_game.c | 111 | ||||
-rw-r--r-- | src/play_time.c | 73 | ||||
-rw-r--r-- | src/rtc.c | 347 | ||||
-rw-r--r-- | src/save.c | 897 | ||||
-rw-r--r-- | src/sound.c | 611 | ||||
-rw-r--r-- | src/sprite.c | 1831 | ||||
-rw-r--r-- | src/text.c | 121 | ||||
-rw-r--r-- | src/text_window.c | 125 | ||||
-rw-r--r-- | src/trig.c | 549 | ||||
-rw-r--r-- | src/window.c | 1019 |
16 files changed, 6771 insertions, 278 deletions
diff --git a/src/battle_ai.c b/src/battle_ai.c index 37960f401..7c4b7604d 100644 --- a/src/battle_ai.c +++ b/src/battle_ai.c @@ -9,10 +9,10 @@ #define AIScriptRead8(ptr) ((ptr)[0]) #define AIScriptReadPtr(ptr) (u8*) AIScriptRead32(ptr) -#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gUnknown_020244A8->ai)) -#define UNK_2016A00_STRUCT ((struct UnknownStruct2 *)(gUnknown_020244A8->unk18)) -#define UNK_2016C00_STRUCT ((struct UnknownStruct4 *)(gUnknown_020244A8->unk1C)) -#define UNK_BATTLE_STRUCT ((struct UnknownStruct1 *)(gUnknown_020244A8)) +#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) +#define UNK_2016A00_STRUCT ((struct UnknownStruct2 *)(gBattleResources->unk18)) +#define UNK_2016C00_STRUCT ((struct UnknownStruct4 *)(gBattleResources->unk1C)) +#define UNK_BATTLE_STRUCT ((struct UnknownStruct1 *)(gBattleResources)) #define AI_ACTION_UNK1 0x0001 #define AI_ACTION_UNK2 0x0002 @@ -158,7 +158,7 @@ struct UnknownStruct5 u8 filler17[0x4]; }; -extern struct UnknownStruct5 gUnknown_020242BC[]; +extern struct UnknownStruct5 gDisableStructs[]; /* gAIScriptPtr is a pointer to the next battle AI cmd command to read. @@ -170,38 +170,38 @@ AI scripts. extern u8 *gAIScriptPtr; extern u32 gBattleTypeFlags; -extern u8 gUnknown_02024064; +extern u8 gActiveBank; extern struct BattlePokemon gBattleMons[]; -extern u16 gUnknown_020241EA; -extern u8 gEnemyMonIndex; -extern u8 gUnknown_02024210; +extern u16 gCurrentMove; +extern u8 gBankTarget; +extern u8 gAbsentBankFlags; extern u16 gUnknown_02024248[]; -extern u8 *gUnknown_0202449C; -extern struct UnknownStruct1 *gUnknown_020244A8; +extern u8 *gBattleStruct; +extern struct UnknownStruct1 *gBattleResources; extern u16 gUnknown_02038BCA; extern u16 gUnknown_02038BCC; extern u8 gPlayerMonIndex; extern struct Trainer gTrainers[]; extern const u32 gBitTable[]; extern u8 *gUnknown_082DBEF8[]; -extern u32 gUnknown_020242AC[]; +extern u32 gStatuses3[]; extern u16 gUnknown_0202428E[]; extern struct BattleMove gBattleMoves[]; extern u8 gUnknown_03005D10[]; -extern u8 gUnknown_0202406E[][2]; +extern u8 gBattlePartyID[][2]; extern struct BaseStats gBaseStats[]; extern u16 gUnknown_02024400; -extern u8 gUnknown_02024474[]; +extern u8 gBattleScripting[]; extern u8 gBattleMoveFlags; extern int gBattleMoveDamage; extern u8 gCritMultiplier; extern u16 gBattleWeather; -extern u8 battle_get_per_side_status(u8); +extern u8 GetBankIdentity(u8); extern u8 b_first_side(u8, u8, u8); -extern u8 battle_get_side_with_given_state(u8); +extern u8 GetBankByPlayerAI(u8); extern void move_effectiveness_something(u16, u8, u8); -extern u8 itemid_get_x12(); +extern u8 ItemId_GetHoldEffect(); extern void b_mc_stack_push(u8 *); extern bool8 b_mc_stack_pop_cursor(void); extern void sub_8046E7C(u8, u8); @@ -212,7 +212,7 @@ extern const BattleAICmdFunc sBattleAICmdTable[]; extern u8 sub_803FECC(); extern u16 Random(); -extern u8 battle_side_get_owner(); +extern u8 GetBankSide(); extern u32 sub_8186438(); extern u32 sub_81A6FB4(); @@ -225,7 +225,7 @@ void BattleAI_DoAIProcessing(void); void BattleAI_HandleItemUseBeforeAISetup(u8 a) { s32 i; - u8 *data = (u8 *)gUnknown_020244A8->unk18; + u8 *data = (u8 *)gBattleResources->unk18; for (i = 0; (u32)i < 0x54; i++) data[i] = 0; @@ -235,8 +235,8 @@ void BattleAI_HandleItemUseBeforeAISetup(u8 a) { if (gTrainers[gUnknown_02038BCA].items[i] != 0) { - gUnknown_020244A8->unk18->unk48[gUnknown_020244A8->unk18->unk50] = gTrainers[gUnknown_02038BCA].items[i]; - gUnknown_020244A8->unk18->unk50++; + gBattleResources->unk18->unk48[gBattleResources->unk18->unk50] = gTrainers[gUnknown_02038BCA].items[i]; + gBattleResources->unk18->unk50++; } } } @@ -264,7 +264,7 @@ void BattleAI_SetupAIData(u8 a) a >>= 1; } - r6 = sub_803FECC(gUnknown_02024064, 0, 0xFF); + r6 = sub_803FECC(gActiveBank, 0, 0xFF); for (i = 0; i < 4; i++) { @@ -273,18 +273,18 @@ void BattleAI_SetupAIData(u8 a) AI_THINKING_STRUCT->unk18[i] = 100 - (Random() % 16); } - gUnknown_020244A8->unk1C->unk20 = 0; - gPlayerMonIndex = gUnknown_02024064; + gBattleResources->unk1C->unk20 = 0; + gPlayerMonIndex = gActiveBank; if (gBattleTypeFlags & 1) { - gEnemyMonIndex = (Random() & 2) + ((u32)battle_side_get_owner(gUnknown_02024064) ^ 1); - if (gUnknown_02024210 & gBitTable[gEnemyMonIndex]) - gEnemyMonIndex ^= 2; + gBankTarget = (Random() & 2) + ((u32)GetBankSide(gActiveBank) ^ 1); + if (gAbsentBankFlags & gBitTable[gBankTarget]) + gBankTarget ^= 2; } else { //_08130A60 - gEnemyMonIndex = gPlayerMonIndex ^ 1; + gBankTarget = gPlayerMonIndex ^ 1; } //_08130A68 if (gBattleTypeFlags & 0x1000000) @@ -309,7 +309,7 @@ void BattleAI_SetupAIData(u8 a) u8 sub_8130BA4(void) { - u16 r4 = gUnknown_020241EA; + u16 r4 = gCurrentMove; u8 ret; if (!(gBattleTypeFlags & 1)) @@ -317,7 +317,7 @@ u8 sub_8130BA4(void) else ret = sub_8130CF4(); - gUnknown_020241EA = r4; + gCurrentMove = r4; return ret; } @@ -404,11 +404,11 @@ u8 sub_8130CF4(void) else { if (gBattleTypeFlags & 0x20000) - BattleAI_SetupAIData(gUnknown_0202449C[0x92] >> 4); + BattleAI_SetupAIData(gBattleStruct[0x92] >> 4); else BattleAI_SetupAIData(0xF); //_08130D76 - gEnemyMonIndex = i; + gBankTarget = i; if ((i & 1) != (gPlayerMonIndex & 1)) sub_8131074(); //_08130D90 @@ -488,8 +488,8 @@ u8 sub_8130CF4(void) r4_2 = 1; } } - gEnemyMonIndex = sp8[Random() % r4_2]; - return spC[gEnemyMonIndex]; + gBankTarget = sp8[Random() % r4_2]; + return spC[gBankTarget]; } #else __attribute__((naked)) @@ -543,7 +543,7 @@ _08130D48:\n\ ands r0, r1\n\ cmp r0, 0\n\ beq _08130D70\n\ - ldr r0, =gUnknown_0202449C\n\ + ldr r0, =gBattleStruct\n\ ldr r0, [r0]\n\ adds r0, 0x92\n\ ldrb r0, [r0]\n\ @@ -555,7 +555,7 @@ _08130D70:\n\ movs r0, 0xF\n\ bl BattleAI_SetupAIData\n\ _08130D76:\n\ - ldr r0, =gEnemyMonIndex\n\ + ldr r0, =gBankTarget\n\ mov r1, r8\n\ strb r1, [r0]\n\ movs r1, 0x1\n\ @@ -568,7 +568,7 @@ _08130D76:\n\ beq _08130D90\n\ bl sub_8131074\n\ _08130D90:\n\ - ldr r2, =gUnknown_020244A8\n\ + ldr r2, =gBattleResources\n\ ldr r0, [r2]\n\ ldr r0, [r0, 0x14]\n\ movs r1, 0\n\ @@ -731,7 +731,7 @@ _08130EC4:\n\ strb r0, [r2]\n\ movs r4, 0x1\n\ mov r8, r4\n\ - ldr r6, =gEnemyMonIndex\n\ + ldr r6, =gBankTarget\n\ ldr r3, [sp, 0x18]\n\ mov r1, sp\n\ adds r1, 0x2\n\ @@ -838,12 +838,12 @@ void sub_8131074(void) for (i = 0; i < 4; i++) { - if (gUnknown_020244A8->unk18->unk0[gEnemyMonIndex][i] == gUnknown_02024248[gEnemyMonIndex]) + if (gBattleResources->unk18->unk0[gBankTarget][i] == gUnknown_02024248[gBankTarget]) break; - if (gUnknown_020244A8->unk18->unk0[gEnemyMonIndex][i] != gUnknown_02024248[gEnemyMonIndex] //HACK: This redundant condition is a hack to make the asm match. - && gUnknown_020244A8->unk18->unk0[gEnemyMonIndex][i] == 0) + if (gBattleResources->unk18->unk0[gBankTarget][i] != gUnknown_02024248[gBankTarget] //HACK: This redundant condition is a hack to make the asm match. + && gBattleResources->unk18->unk0[gBankTarget][i] == 0) { - gUnknown_020244A8->unk18->unk0[gEnemyMonIndex][i] = gUnknown_02024248[gEnemyMonIndex]; + gBattleResources->unk18->unk0[gBankTarget][i] = gUnknown_02024248[gBankTarget]; break; } } @@ -854,27 +854,27 @@ void sub_81310F0(u8 a) s32 i; for (i = 0; i < 4; i++) - gUnknown_020244A8->unk18->unk0[a][i] = 0; + gBattleResources->unk18->unk0[a][i] = 0; } -void b_history__record_ability_usage_of_player(u8 a, u8 b) +void RecordAbilityBattle(u8 a, u8 b) { - gUnknown_020244A8->unk18->unk40[a] = b; + gBattleResources->unk18->unk40[a] = b; } void sub_8131130(u8 a) { - gUnknown_020244A8->unk18->unk40[a] = 0; + gBattleResources->unk18->unk40[a] = 0; } void b_history__record_item_x12_of_player(u8 a, u8 b) { - gUnknown_020244A8->unk18->unk44[a] = b; + gBattleResources->unk18->unk44[a] = b; } void sub_8131160(u8 a) { - gUnknown_020244A8->unk18->unk44[a] = 0; + gBattleResources->unk18->unk44[a] = 0; } void BattleAICmd_if_random_less_than(void) @@ -934,7 +934,7 @@ void BattleAICmd_if_hp_less_than(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) < gAIScriptPtr[2]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); @@ -949,7 +949,7 @@ void BattleAICmd_if_hp_more_than(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) > gAIScriptPtr[2]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); @@ -964,7 +964,7 @@ void BattleAICmd_if_hp_equal(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) == gAIScriptPtr[2]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); @@ -979,7 +979,7 @@ void BattleAICmd_if_hp_not_equal(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) != gAIScriptPtr[2]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); @@ -995,7 +995,7 @@ void BattleAICmd_if_status(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; arg = AIScriptRead32(gAIScriptPtr + 2); @@ -1013,7 +1013,7 @@ void BattleAICmd_if_not_status(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; arg = AIScriptRead32(gAIScriptPtr + 2); @@ -1031,7 +1031,7 @@ void BattleAICmd_if_status2(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; arg = AIScriptRead32(gAIScriptPtr + 2); @@ -1049,7 +1049,7 @@ void BattleAICmd_if_not_status2(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; arg = AIScriptRead32(gAIScriptPtr + 2); @@ -1067,11 +1067,11 @@ void BattleAICmd_if_status3(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; arg = AIScriptRead32(gAIScriptPtr + 2); - if ((gUnknown_020242AC[index] & arg) != 0) + if ((gStatuses3[index] & arg) != 0) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); else gAIScriptPtr += 10; @@ -1085,11 +1085,11 @@ void BattleAICmd_if_not_status3(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; arg = AIScriptRead32(gAIScriptPtr + 2); - if ((gUnknown_020242AC[index] & arg) == 0) + if ((gStatuses3[index] & arg) == 0) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); else gAIScriptPtr += 10; @@ -1103,9 +1103,9 @@ void BattleAICmd_if_status4(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - arg1 = battle_get_per_side_status(index) & 1; + arg1 = GetBankIdentity(index) & 1; arg2 = AIScriptRead32(gAIScriptPtr + 2); if ((gUnknown_0202428E[arg1] & arg2) != 0) @@ -1122,9 +1122,9 @@ void BattleAICmd_if_not_status4(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - arg1 = battle_get_per_side_status(index) & 1; + arg1 = GetBankIdentity(index) & 1; arg2 = AIScriptRead32(gAIScriptPtr + 2); if ((gUnknown_0202428E[arg1] & arg2) == 0) @@ -1337,13 +1337,13 @@ void BattleAICmd_get_type(void) AI_THINKING_STRUCT->funcResult = gBattleMons[gPlayerMonIndex].type1; break; case 0: // enemy primary type - AI_THINKING_STRUCT->funcResult = gBattleMons[gEnemyMonIndex].type1; + AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type1; break; case 3: // player secondary type AI_THINKING_STRUCT->funcResult = gBattleMons[gPlayerMonIndex].type2; break; case 2: // enemy secondary type - AI_THINKING_STRUCT->funcResult = gBattleMons[gEnemyMonIndex].type2; + AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type2; break; case 4: // type of move being pointed to AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].type; @@ -1361,11 +1361,11 @@ u8 sub_8131E70(u8 index) return gPlayerMonIndex; case 0: default: - return gEnemyMonIndex; + return gBankTarget; case 3: return gPlayerMonIndex ^ 2; case 2: - return gEnemyMonIndex ^ 2; + return gBankTarget ^ 2; } } @@ -1406,7 +1406,7 @@ void BattleAICmd_is_most_powerful_move(void) ldrh r1, [r0]\n\ ldr r5, =0x0000ffff\n\ ldr r6, =gBattleMoves\n\ - ldr r2, =gUnknown_020244A8\n\ + ldr r2, =gBattleResources\n\ cmp r1, r5\n\ beq _08131F86\n\ ldr r0, [r2]\n\ @@ -1452,10 +1452,10 @@ _08131FAC:\n\ ldr r0, =gUnknown_02024400\n\ movs r1, 0\n\ strh r1, [r0]\n\ - ldr r0, =gUnknown_0202449C\n\ + ldr r0, =gBattleStruct\n\ ldr r0, [r0]\n\ strb r1, [r0, 0x13]\n\ - ldr r0, =gUnknown_02024474\n\ + ldr r0, =gBattleScripting\n\ movs r2, 0x1\n\ strb r2, [r0, 0xE]\n\ ldr r0, =gBattleMoveFlags\n\ @@ -1529,10 +1529,10 @@ _08132014:\n\ ldrb r0, [r1, 0x1]\n\ cmp r0, 0x1\n\ bls _081320C0\n\ - ldr r5, =gUnknown_020241EA\n\ + ldr r5, =gCurrentMove\n\ strh r2, [r5]\n\ ldrb r0, [r7]\n\ - ldr r4, =gEnemyMonIndex\n\ + ldr r4, =gBankTarget\n\ ldrb r1, [r4]\n\ bl sub_8046E7C\n\ ldrh r0, [r5]\n\ @@ -1542,7 +1542,7 @@ _08132014:\n\ mov r4, sp\n\ add r4, r8\n\ ldr r2, =gBattleMoveDamage\n\ - ldr r0, =gUnknown_020244A8\n\ + ldr r0, =gBattleResources\n\ ldr r0, [r0]\n\ ldr r0, [r0, 0x14]\n\ adds r0, 0x18\n\ @@ -1571,7 +1571,7 @@ _081320C8:\n\ b _08131FD0\n\ _081320D0:\n\ movs r6, 0\n\ - ldr r2, =gUnknown_020244A8\n\ + ldr r2, =gBattleResources\n\ ldr r0, [r2]\n\ ldr r0, [r0, 0x14]\n\ ldrb r0, [r0, 0x1]\n\ @@ -1640,7 +1640,7 @@ void BattleAICmd_get_move(void) if (gAIScriptPtr[1] == USER) AI_THINKING_STRUCT->funcResult = gUnknown_02024248[gPlayerMonIndex]; else - AI_THINKING_STRUCT->funcResult = gUnknown_02024248[gEnemyMonIndex]; + AI_THINKING_STRUCT->funcResult = gUnknown_02024248[gBankTarget]; gAIScriptPtr += 2; } @@ -1663,7 +1663,7 @@ void BattleAICmd_if_arg_not_equal(void) void BattleAICmd_if_would_go_first(void) { - if (b_first_side(gPlayerMonIndex, gEnemyMonIndex, 1) == gAIScriptPtr[1]) + if (b_first_side(gPlayerMonIndex, gBankTarget, 1) == gAIScriptPtr[1]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; @@ -1671,7 +1671,7 @@ void BattleAICmd_if_would_go_first(void) void BattleAICmd_if_would_not_go_first(void) { - if (b_first_side(gPlayerMonIndex, gEnemyMonIndex, 1) != gAIScriptPtr[1]) + if (b_first_side(gPlayerMonIndex, gBankTarget, 1) != gAIScriptPtr[1]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; @@ -1697,9 +1697,9 @@ void BattleAICmd_count_alive_pokemon(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - if (battle_side_get_owner(index) == 0) + if (GetBankSide(index) == 0) party = gPlayerParty; else party = gEnemyParty; @@ -1707,14 +1707,14 @@ void BattleAICmd_count_alive_pokemon(void) if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) { u32 status; - var = gUnknown_0202406E[index][0]; - status = battle_get_per_side_status(index) ^ 2; - var2 = gUnknown_0202406E[battle_get_side_with_given_state(status)][0]; + var = gBattlePartyID[index][0]; + status = GetBankIdentity(index) ^ 2; + var2 = gBattlePartyID[GetBankByPlayerAI(status)][0]; } else { - var = gUnknown_0202406E[index][0]; - var2 = gUnknown_0202406E[index][0]; + var = gBattlePartyID[index][0]; + var2 = gBattlePartyID[index][0]; } for (i = 0; i < 6; i++) @@ -1750,9 +1750,9 @@ void BattleAICmd_get_ability(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - if(gUnknown_02024064 != index) + if(gActiveBank != index) { if(UNK_2016A00_STRUCT->unk40[index] != 0) { @@ -1898,7 +1898,7 @@ void tai60_unk(void) cmp r0, 0x2\n\ bne _081325BC\n\ _0813253A:\n\ - ldr r0, =gUnknown_020244A8\n\ + ldr r0, =gBattleResources\n\ ldr r4, [r0]\n\ ldr r1, [r4, 0x18]\n\ adds r1, 0x40\n\ @@ -1968,7 +1968,7 @@ _081325BC:\n\ adds r0, r1\n\ adds r0, 0x20\n\ ldrb r3, [r0]\n\ - ldr r6, =gUnknown_020244A8\n\ + ldr r6, =gBattleResources\n\ _081325CA:\n\ cmp r3, 0\n\ bne _081325E8\n\ @@ -2015,8 +2015,8 @@ void BattleAICmd_get_highest_possible_damage(void) s32 i; gUnknown_02024400 = 0; - gUnknown_0202449C[0x13] = 0; - gUnknown_02024474[0xE] = 1; + gBattleStruct[0x13] = 0; + gBattleScripting[0xE] = 1; gBattleMoveFlags = 0; gCritMultiplier = 1; AI_THINKING_STRUCT->funcResult = 0; @@ -2024,11 +2024,11 @@ void BattleAICmd_get_highest_possible_damage(void) for (i = 0; i < 4; i++) { gBattleMoveDamage = 40; - gUnknown_020241EA = gBattleMons[gPlayerMonIndex].moves[i]; + gCurrentMove = gBattleMons[gPlayerMonIndex].moves[i]; - if (gUnknown_020241EA) + if (gCurrentMove) { - move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget); // reduce by 1/3. if (gBattleMoveDamage == 120) @@ -2055,15 +2055,15 @@ void BattleAICmd_if_damage_bonus(void) u8 damageVar; gUnknown_02024400 = 0; - gUnknown_0202449C[0x13] = 0; - gUnknown_02024474[0xE] = 1; + gBattleStruct[0x13] = 0; + gBattleScripting[0xE] = 1; gBattleMoveFlags = 0; gCritMultiplier = 1; gBattleMoveDamage = 40; - gUnknown_020241EA = AI_THINKING_STRUCT->moveConsidered; + gCurrentMove = AI_THINKING_STRUCT->moveConsidered; - move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget); if (gBattleMoveDamage == 120) gBattleMoveDamage = 80; @@ -2107,11 +2107,11 @@ void BattleAICmd_if_status_in_party(void) index = gPlayerMonIndex; break; default: - index = gEnemyMonIndex; + index = gBankTarget; break; } - party = (battle_side_get_owner(index) == 0) ? gPlayerParty : gEnemyParty; + party = (GetBankSide(index) == 0) ? gPlayerParty : gEnemyParty; statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); @@ -2144,11 +2144,11 @@ void BattleAICmd_if_status_not_in_party(void) index = gPlayerMonIndex; break; default: - index = gEnemyMonIndex; + index = gBankTarget; break; } - party = (battle_side_get_owner(index) == 0) ? gPlayerParty : gEnemyParty; + party = (GetBankSide(index) == 0) ? gPlayerParty : gEnemyParty; statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); @@ -2204,7 +2204,7 @@ void BattleAICmd_if_stat_level_less_than(void) if (gAIScriptPtr[1] == USER) party = gPlayerMonIndex; else - party = gEnemyMonIndex; + party = gBankTarget; if (gBattleMons[party].statStages[gAIScriptPtr[2]] < gAIScriptPtr[3]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); @@ -2219,7 +2219,7 @@ void BattleAICmd_if_stat_level_more_than(void) if (gAIScriptPtr[1] == USER) party = gPlayerMonIndex; else - party = gEnemyMonIndex; + party = gBankTarget; if (gBattleMons[party].statStages[gAIScriptPtr[2]] > gAIScriptPtr[3]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); @@ -2234,7 +2234,7 @@ void BattleAICmd_if_stat_level_equal(void) if (gAIScriptPtr[1] == USER) party = gPlayerMonIndex; else - party = gEnemyMonIndex; + party = gBankTarget; if (gBattleMons[party].statStages[gAIScriptPtr[2]] == gAIScriptPtr[3]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); @@ -2249,7 +2249,7 @@ void BattleAICmd_if_stat_level_not_equal(void) if (gAIScriptPtr[1] == USER) party = gPlayerMonIndex; else - party = gEnemyMonIndex; + party = gBankTarget; if (gBattleMons[party].statStages[gAIScriptPtr[2]] != gAIScriptPtr[3]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); @@ -2266,13 +2266,13 @@ void BattleAICmd_if_can_faint(void) } gUnknown_02024400 = 0; - gUnknown_0202449C[0x13] = 0; - gUnknown_02024474[0xE] = 1; + gBattleStruct[0x13] = 0; + gBattleScripting[0xE] = 1; gBattleMoveFlags = 0; gCritMultiplier = 1; - gUnknown_020241EA = AI_THINKING_STRUCT->moveConsidered; - sub_8046E7C(gPlayerMonIndex, gEnemyMonIndex); - move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + gCurrentMove = AI_THINKING_STRUCT->moveConsidered; + sub_8046E7C(gPlayerMonIndex, gBankTarget); + move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget); gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->unk18[AI_THINKING_STRUCT->movesetIndex] / 100; @@ -2280,7 +2280,7 @@ void BattleAICmd_if_can_faint(void) if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - if (gBattleMons[gEnemyMonIndex].hp <= gBattleMoveDamage) + if (gBattleMons[gBankTarget].hp <= gBattleMoveDamage) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); else gAIScriptPtr += 5; @@ -2295,19 +2295,19 @@ void BattleAICmd_if_cant_faint(void) } gUnknown_02024400 = 0; - gUnknown_0202449C[0x13] = 0; - gUnknown_02024474[0xE] = 1; + gBattleStruct[0x13] = 0; + gBattleScripting[0xE] = 1; gBattleMoveFlags = 0; gCritMultiplier = 1; - gUnknown_020241EA = AI_THINKING_STRUCT->moveConsidered; - sub_8046E7C(gPlayerMonIndex, gEnemyMonIndex); - move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + gCurrentMove = AI_THINKING_STRUCT->moveConsidered; + sub_8046E7C(gPlayerMonIndex, gBankTarget); + move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget); gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->unk18[AI_THINKING_STRUCT->movesetIndex] / 100; // this macro is missing the damage 0 = 1 assumption. - if (gBattleMons[gEnemyMonIndex].hp > gBattleMoveDamage) + if (gBattleMons[gBankTarget].hp > gBattleMoveDamage) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); else gAIScriptPtr += 5; @@ -2365,7 +2365,7 @@ void BattleAICmd_if_has_move(void) case 2: for (i = 0; i < 4; i++) { - if (UNK_2016A00_STRUCT->unk0[gEnemyMonIndex][i] == *temp_ptr) + if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] == *temp_ptr) break; } if (i == 4) @@ -2409,7 +2409,7 @@ void BattleAICmd_if_dont_have_move(void) case 2: for (i = 0; i < 4; i++) { - if (UNK_2016A00_STRUCT->unk0[gEnemyMonIndex][i] == *temp_ptr) + if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] == *temp_ptr) break; } if (i != 4) @@ -2447,7 +2447,7 @@ void BattleAICmd_if_move_effect(void) case 2: // _08133090 for (i = 0; i < 4; i++) { - if (gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[UNK_2016A00_STRUCT->unk0[gEnemyMonIndex][i]].effect == gAIScriptPtr[2]) + if (gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[UNK_2016A00_STRUCT->unk0[gBankTarget][i]].effect == gAIScriptPtr[2]) break; } if (i == 4) @@ -2480,7 +2480,7 @@ void BattleAICmd_if_not_move_effect(void) case 2: // _08133188 for (i = 0; i < 4; i++) { - if (UNK_2016A00_STRUCT->unk0[gEnemyMonIndex][i] && gBattleMoves[UNK_2016A00_STRUCT->unk0[gEnemyMonIndex][i]].effect == gAIScriptPtr[2]) + if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] && gBattleMoves[UNK_2016A00_STRUCT->unk0[gBankTarget][i]].effect == gAIScriptPtr[2]) break; } if (i != 4) @@ -2498,11 +2498,11 @@ void BattleAICmd_if_last_move_did_damage(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; if (gAIScriptPtr[2] == 0) { - if (gUnknown_020242BC[index].unk4 == 0) + if (gDisableStructs[index].unk4 == 0) { gAIScriptPtr += 7; return; @@ -2515,7 +2515,7 @@ void BattleAICmd_if_last_move_did_damage(void) gAIScriptPtr += 7; return; } - else if (gUnknown_020242BC[index].unk6 != 0) + else if (gDisableStructs[index].unk6 != 0) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); return; @@ -2528,7 +2528,7 @@ void BattleAICmd_if_encored(void) switch (gAIScriptPtr[1]) { case 0: // _08109348 - if (gUnknown_020242BC[gUnknown_02024064].unk4 == AI_THINKING_STRUCT->moveConsidered) + if (gDisableStructs[gActiveBank].unk4 == AI_THINKING_STRUCT->moveConsidered) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); return; @@ -2536,7 +2536,7 @@ void BattleAICmd_if_encored(void) gAIScriptPtr += 6; return; case 1: // _08109370 - if (gUnknown_020242BC[gUnknown_02024064].unk6 == AI_THINKING_STRUCT->moveConsidered) + if (gDisableStructs[gActiveBank].unk6 == AI_THINKING_STRUCT->moveConsidered) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); return; @@ -2556,7 +2556,7 @@ void BattleAICmd_flee(void) void BattleAICmd_if_random_100(void) { - u8 safariFleeRate = gUnknown_0202449C[0x7B] * 5; // safari flee rate, from 0-20 + u8 safariFleeRate = gBattleStruct[0x7B] * 5; // safari flee rate, from 0-20 if ((u8)(Random() % 100) < safariFleeRate) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); @@ -2577,14 +2577,14 @@ void BattleAICmd_get_hold_effect(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - if (gUnknown_02024064 != index) + if (gActiveBank != index) { - AI_THINKING_STRUCT->funcResult = itemid_get_x12(UNK_2016A00_STRUCT->unk44[index]); + AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(UNK_2016A00_STRUCT->unk44[index]); } else - AI_THINKING_STRUCT->funcResult = itemid_get_x12(gBattleMons[index].item); + AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(gBattleMons[index].item); gAIScriptPtr += 2; } @@ -2617,7 +2617,7 @@ void BattleAICmd_get_gender(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; AI_THINKING_STRUCT->funcResult = pokemon_species_get_gender_info(gBattleMons[index].species, gBattleMons[index].personality); @@ -2631,9 +2631,9 @@ void BattleAICmd_is_first_turn(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - AI_THINKING_STRUCT->funcResult = gUnknown_020242BC[index].unk16; + AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk16; gAIScriptPtr += 2; } @@ -2645,9 +2645,9 @@ void BattleAICmd_get_stockpile_count(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - AI_THINKING_STRUCT->funcResult = gUnknown_020242BC[index].unk9; + AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk9; gAIScriptPtr += 2; } @@ -2666,10 +2666,10 @@ void BattleAICmd_get_item(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; // this hack and a half matches. whatever. i dont care. someone else fix this mess later. PS: still cant fix this. - AI_THINKING_STRUCT->funcResult = gUnknown_0202449C[0xB8 + (index * 2)]; + AI_THINKING_STRUCT->funcResult = gBattleStruct[0xB8 + (index * 2)]; gAIScriptPtr += 2; } @@ -2702,9 +2702,9 @@ void BattleAICmd_get_protect_count(void) if (gAIScriptPtr[1] == USER) index = gPlayerMonIndex; else - index = gEnemyMonIndex; + index = gBankTarget; - AI_THINKING_STRUCT->funcResult = gUnknown_020242BC[index].unk8; + AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk8; gAIScriptPtr += 2; } @@ -2755,7 +2755,7 @@ void BattleAICmd_if_level_cond(void) switch (gAIScriptPtr[1]) { case 0: // greater than - if (gBattleMons[gPlayerMonIndex].level > gBattleMons[gEnemyMonIndex].level) + if (gBattleMons[gPlayerMonIndex].level > gBattleMons[gBankTarget].level) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); return; @@ -2763,7 +2763,7 @@ void BattleAICmd_if_level_cond(void) gAIScriptPtr += 6; return; case 1: // less than - if (gBattleMons[gPlayerMonIndex].level < gBattleMons[gEnemyMonIndex].level) + if (gBattleMons[gPlayerMonIndex].level < gBattleMons[gBankTarget].level) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); return; @@ -2771,7 +2771,7 @@ void BattleAICmd_if_level_cond(void) gAIScriptPtr += 6; return; case 2: // equal - if (gBattleMons[gPlayerMonIndex].level == gBattleMons[gEnemyMonIndex].level) + if (gBattleMons[gPlayerMonIndex].level == gBattleMons[gBankTarget].level) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); return; @@ -2783,7 +2783,7 @@ void BattleAICmd_if_level_cond(void) void BattleAICmd_if_taunted(void) { - if (gUnknown_020242BC[gEnemyMonIndex].taunt != 0) + if (gDisableStructs[gBankTarget].taunt != 0) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); else gAIScriptPtr += 5; @@ -2791,7 +2791,7 @@ void BattleAICmd_if_taunted(void) void BattleAICmd_if_not_taunted(void) { - if (gUnknown_020242BC[gEnemyMonIndex].taunt == 0) + if (gDisableStructs[gBankTarget].taunt == 0) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); else gAIScriptPtr += 5; @@ -2799,7 +2799,7 @@ void BattleAICmd_if_not_taunted(void) void tai5E_unk(void) { - if((gPlayerMonIndex & 1) == (gEnemyMonIndex & 1)) + if((gPlayerMonIndex & 1) == (gBankTarget & 1)) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); else gAIScriptPtr += 5; diff --git a/src/decompress.c b/src/decompress.c new file mode 100644 index 000000000..befdbaba2 --- /dev/null +++ b/src/decompress.c @@ -0,0 +1,597 @@ +#include "global.h" +#include "decompress.h" +#include "species.h" +#include "text.h" +#include "malloc.h" + +EWRAM_DATA ALIGNED(4) u8 gDecompressionBuffer[0x4000] = {0}; + +extern const struct CompressedSpriteSheet gMonFrontPicTable[]; +extern const struct CompressedSpriteSheet gMonBackPicTable[]; + +extern void DrawSpindaSpots(u16 species, u32 personality, void* dest, bool8 isFrontPic); + +static void DuplicateDeoxysTiles(void *pointer, s32 species); + +void LZDecompressWram(const void *src, void *dest) +{ + LZ77UnCompWram(src, dest); +} + +void LZDecompressVram(const void *src, void *dest) +{ + LZ77UnCompVram(src, dest); +} + +u16 LoadCompressedObjectPic(const struct CompressedSpriteSheet *src) +{ + struct SpriteSheet dest; + + LZ77UnCompWram(src->data, gDecompressionBuffer); + dest.data = gDecompressionBuffer; + dest.size = src->size; + dest.tag = src->tag; + return LoadSpriteSheet(&dest); +} + +void LoadCompressedObjectPicOverrideBuffer(const struct CompressedSpriteSheet *src, void *buffer) +{ + struct SpriteSheet dest; + + LZ77UnCompWram(src->data, buffer); + dest.data = buffer; + dest.size = src->size; + dest.tag = src->tag; + LoadSpriteSheet(&dest); +} + +void LoadCompressedObjectPalette(const struct CompressedSpritePalette *src) +{ + struct SpritePalette dest; + + LZ77UnCompWram(src->data, gDecompressionBuffer); + dest.data = (void*) gDecompressionBuffer; + dest.tag = src->tag; + LoadSpritePalette(&dest); +} + +void LoadCompressedObjectPaletteOverrideBuffer(const struct CompressedSpritePalette *a, void *buffer) +{ + struct SpritePalette dest; + + LZ77UnCompWram(a->data, buffer); + dest.data = buffer; + dest.tag = a->tag; + LoadSpritePalette(&dest); +} + +void DecompressPicFromTable(const struct CompressedSpriteSheet *src, void* buffer, s32 species) +{ + if (species > SPECIES_EGG) + LZ77UnCompWram(gMonFrontPicTable[0].data, buffer); + else + LZ77UnCompWram(src->data, buffer); + DuplicateDeoxysTiles(buffer, species); +} + +void HandleLoadSpecialPokePic(const struct CompressedSpriteSheet *src, void *dest, s32 species, u32 personality) +{ + bool8 isFrontPic; + + if (src == &gMonFrontPicTable[species]) + isFrontPic = TRUE; // frontPic + else + isFrontPic = FALSE; // backPic + + LoadSpecialPokePic_2(src, dest, species, personality, isFrontPic); +} + +void LoadSpecialPokePic(const struct CompressedSpriteSheet *src, void *dest, s32 species, u32 personality, bool8 isFrontPic) +{ + if (species == SPECIES_UNOWN) + { + u16 i = (((personality & 0x3000000) >> 18) | ((personality & 0x30000) >> 12) | ((personality & 0x300) >> 6) | (personality & 3)) % 0x1C; + + // The other Unowns are separate from Unown A. + if (i == 0) + i = SPECIES_UNOWN; + else + i += SPECIES_UNOWN_B - 1; + + if (!isFrontPic) + LZ77UnCompWram(gMonBackPicTable[i].data, dest); + else + LZ77UnCompWram(gMonFrontPicTable[i].data, dest); + } + else if (species > SPECIES_EGG) // is species unknown? draw the ? icon + LZ77UnCompWram(gMonFrontPicTable[0].data, dest); + else + LZ77UnCompWram(src->data, dest); + + DuplicateDeoxysTiles(dest, species); + DrawSpindaSpots(species, personality, dest, isFrontPic); +} + +void Unused_LZDecompressWramIndirect(const void **src, void *dest) +{ + LZ77UnCompWram(*src, dest); +} + +// This one (unused) function is really challenging, won't even try to decompile it. +__attribute__((naked)) +void sub_803471C() +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x24\n\ + mov r9, r0\n\ + str r1, [sp]\n\ + str r2, [sp, 0x4]\n\ + adds r5, r3, 0\n\ + movs r0, 0x1\n\ + mov r1, r9\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + bne _0803473C\n\ + b _080348D4\n\ +_0803473C:\n\ + asrs r0, r1, 1\n\ + adds r0, 0x4\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + str r0, [sp, 0x8]\n\ + movs r0, 0\n\ + ldr r2, [sp]\n\ + cmp r0, r2\n\ + blt _08034750\n\ + b _08034964\n\ +_08034750:\n\ + movs r4, 0x8\n\ + subs r1, r4, r1\n\ + str r1, [sp, 0x10]\n\ +_08034756:\n\ + movs r7, 0\n\ + adds r0, 0x1\n\ + str r0, [sp, 0x14]\n\ + ldr r0, [sp, 0x10]\n\ + cmp r7, r0\n\ + bge _080347D2\n\ + ldr r1, [sp, 0x8]\n\ + lsls r1, 8\n\ + str r1, [sp, 0x18]\n\ + movs r2, 0\n\ + mov r10, r2\n\ + mov r0, r9\n\ + movs r4, 0x8\n\ + subs r0, r4, r0\n\ + str r0, [sp, 0xC]\n\ +_08034774:\n\ + movs r3, 0\n\ + asrs r0, r7, 1\n\ + adds r1, r7, 0\n\ + movs r2, 0x1\n\ + ands r1, r2\n\ + str r1, [sp, 0x20]\n\ + lsls r0, 8\n\ + mov r8, r0\n\ + mov r12, r5\n\ +_08034786:\n\ + lsls r1, r3, 5\n\ + ldr r4, [sp, 0x18]\n\ + adds r0, r5, r4\n\ + adds r0, r1\n\ + mov r1, r8\n\ + adds r2, r0, r1\n\ + mov r1, r12\n\ + add r1, r8\n\ + movs r6, 0xF\n\ +_08034798:\n\ + ldr r4, [sp, 0x20]\n\ + cmp r4, 0\n\ + bne _080347A8\n\ + strb r4, [r1]\n\ + add r4, sp, 0x20\n\ + ldrb r4, [r4]\n\ + strb r4, [r2, 0x10]\n\ + b _080347B6\n\ +_080347A8:\n\ + mov r0, r10\n\ + strb r0, [r1, 0x10]\n\ + movs r4, 0x80\n\ + lsls r4, 1\n\ + adds r4, r2, r4\n\ + str r4, [sp, 0x1C]\n\ + strb r0, [r4]\n\ +_080347B6:\n\ + adds r2, 0x1\n\ + adds r1, 0x1\n\ + subs r6, 0x1\n\ + cmp r6, 0\n\ + bge _08034798\n\ + movs r0, 0x20\n\ + add r12, r0\n\ + adds r3, 0x1\n\ + cmp r3, 0x7\n\ + ble _08034786\n\ + adds r7, 0x1\n\ + ldr r1, [sp, 0xC]\n\ + cmp r7, r1\n\ + blt _08034774\n\ +_080347D2:\n\ + movs r7, 0\n\ + movs r2, 0\n\ +_080347D6:\n\ + movs r6, 0\n\ + adds r4, r7, 0x1\n\ + mov r8, r4\n\ + lsls r4, r7, 5\n\ +_080347DE:\n\ + adds r0, r6, 0x1\n\ + mov r10, r0\n\ + lsls r1, r6, 8\n\ + adds r0, r1, 0\n\ + adds r0, 0xC0\n\ + adds r0, r5, r0\n\ + adds r0, r4\n\ + adds r1, r5, r1\n\ + adds r1, r4\n\ + movs r3, 0x1F\n\ +_080347F2:\n\ + strb r2, [r1]\n\ + strb r2, [r0]\n\ + adds r0, 0x1\n\ + adds r1, 0x1\n\ + subs r3, 0x1\n\ + cmp r3, 0\n\ + bge _080347F2\n\ + mov r6, r10\n\ + cmp r6, 0x7\n\ + ble _080347DE\n\ + mov r7, r8\n\ + cmp r7, 0x1\n\ + ble _080347D6\n\ + mov r1, r9\n\ + cmp r1, 0x5\n\ + bne _08034818\n\ + movs r2, 0x90\n\ + lsls r2, 1\n\ + adds r5, r2\n\ +_08034818:\n\ + movs r7, 0\n\ + cmp r7, r9\n\ + bge _080348AE\n\ +_0803481E:\n\ + movs r3, 0\n\ + adds r7, 0x1\n\ + mov r8, r7\n\ + cmp r3, r9\n\ + bge _0803488E\n\ +_08034828:\n\ + adds r3, 0x1\n\ + mov r10, r3\n\ + ldr r4, [sp, 0x4]\n\ + adds r4, 0x20\n\ + adds r7, r5, 0\n\ + adds r7, 0x20\n\ + movs r0, 0x12\n\ + adds r0, r5\n\ + mov r12, r0\n\ + ldr r2, [sp, 0x4]\n\ + adds r3, r5, 0\n\ + movs r6, 0x3\n\ +_08034840:\n\ + ldrb r0, [r2]\n\ + mov r1, r12\n\ + strb r0, [r1]\n\ + ldrb r0, [r2, 0x1]\n\ + strb r0, [r1, 0x1]\n\ + ldrb r0, [r2, 0x2]\n\ + strb r0, [r1, 0x1E]\n\ + ldrb r0, [r2, 0x3]\n\ + strb r0, [r1, 0x1F]\n\ + movs r0, 0x81\n\ + lsls r0, 1\n\ + adds r1, r3, r0\n\ + ldrb r0, [r2, 0x10]\n\ + strb r0, [r1]\n\ + ldr r0, =0x00000103\n\ + adds r1, r3, r0\n\ + ldrb r0, [r2, 0x11]\n\ + strb r0, [r1]\n\ + movs r0, 0x90\n\ + lsls r0, 1\n\ + adds r1, r3, r0\n\ + ldrb r0, [r2, 0x12]\n\ + strb r0, [r1]\n\ + ldr r0, =0x00000121\n\ + adds r1, r3, r0\n\ + ldrb r0, [r2, 0x13]\n\ + strb r0, [r1]\n\ + movs r1, 0x4\n\ + add r12, r1\n\ + adds r2, 0x4\n\ + adds r3, 0x4\n\ + subs r6, 0x1\n\ + cmp r6, 0\n\ + bge _08034840\n\ + str r4, [sp, 0x4]\n\ + adds r5, r7, 0\n\ + mov r3, r10\n\ + cmp r3, r9\n\ + blt _08034828\n\ +_0803488E:\n\ + mov r2, r9\n\ + cmp r2, 0x7\n\ + bne _080348A0\n\ + adds r5, 0x20\n\ + b _080348A8\n\ + .pool\n\ +_080348A0:\n\ + mov r4, r9\n\ + cmp r4, 0x5\n\ + bne _080348A8\n\ + adds r5, 0x60\n\ +_080348A8:\n\ + mov r7, r8\n\ + cmp r7, r9\n\ + blt _0803481E\n\ +_080348AE:\n\ + mov r0, r9\n\ + cmp r0, 0x7\n\ + bne _080348BC\n\ + movs r1, 0x80\n\ + lsls r1, 1\n\ + adds r5, r1\n\ + b _080348C8\n\ +_080348BC:\n\ + mov r2, r9\n\ + cmp r2, 0x5\n\ + bne _080348C8\n\ + movs r4, 0xF0\n\ + lsls r4, 1\n\ + adds r5, r4\n\ +_080348C8:\n\ + ldr r0, [sp, 0x14]\n\ + ldr r1, [sp]\n\ + cmp r0, r1\n\ + bge _080348D2\n\ + b _08034756\n\ +_080348D2:\n\ + b _08034964\n\ +_080348D4:\n\ + movs r6, 0\n\ + ldr r2, [sp]\n\ + cmp r6, r2\n\ + bge _08034964\n\ +_080348DC:\n\ + adds r6, 0x1\n\ + mov r10, r6\n\ + mov r4, r9\n\ + cmp r4, 0x6\n\ + bne _080348F4\n\ + movs r0, 0\n\ + movs r3, 0xFF\n\ +_080348EA:\n\ + strb r0, [r5]\n\ + adds r5, 0x1\n\ + subs r3, 0x1\n\ + cmp r3, 0\n\ + bge _080348EA\n\ +_080348F4:\n\ + movs r7, 0\n\ + cmp r7, r9\n\ + bge _08034948\n\ +_080348FA:\n\ + adds r7, 0x1\n\ + mov r8, r7\n\ + mov r1, r9\n\ + lsls r0, r1, 5\n\ + cmp r1, 0x6\n\ + bne _08034914\n\ + movs r1, 0\n\ + movs r3, 0x1F\n\ +_0803490A:\n\ + strb r1, [r5]\n\ + adds r5, 0x1\n\ + subs r3, 0x1\n\ + cmp r3, 0\n\ + bge _0803490A\n\ +_08034914:\n\ + adds r1, r0, 0\n\ + cmp r1, 0\n\ + ble _0803492E\n\ + adds r3, r1, 0\n\ +_0803491C:\n\ + ldr r2, [sp, 0x4]\n\ + ldrb r0, [r2]\n\ + strb r0, [r5]\n\ + adds r2, 0x1\n\ + str r2, [sp, 0x4]\n\ + adds r5, 0x1\n\ + subs r3, 0x1\n\ + cmp r3, 0\n\ + bne _0803491C\n\ +_0803492E:\n\ + mov r4, r9\n\ + cmp r4, 0x6\n\ + bne _08034942\n\ + movs r0, 0\n\ + movs r3, 0x1F\n\ +_08034938:\n\ + strb r0, [r5]\n\ + adds r5, 0x1\n\ + subs r3, 0x1\n\ + cmp r3, 0\n\ + bge _08034938\n\ +_08034942:\n\ + mov r7, r8\n\ + cmp r7, r9\n\ + blt _080348FA\n\ +_08034948:\n\ + mov r0, r9\n\ + cmp r0, 0x6\n\ + bne _0803495C\n\ + movs r0, 0\n\ + movs r3, 0xFF\n\ +_08034952:\n\ + strb r0, [r5]\n\ + adds r5, 0x1\n\ + subs r3, 0x1\n\ + cmp r3, 0\n\ + bge _08034952\n\ +_0803495C:\n\ + mov r6, r10\n\ + ldr r1, [sp]\n\ + cmp r6, r1\n\ + blt _080348DC\n\ +_08034964:\n\ + add sp, 0x24\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .syntax divided"); +} + +u32 sub_8034974(void* ptr) +{ + u8* ptr_ = (u8*)(ptr); + return (ptr_[3] << 16) | (ptr_[2] << 8) | (ptr_[1]); +} + +bool8 LoadCompressedObjectPicUsingHeap(struct CompressedSpriteSheet* src) +{ + struct SpriteSheet dest; + void* buffer; + + buffer = AllocZeroed(*((u32*)(&src->data[0])) >> 8); + LZ77UnCompWram(src->data, buffer); + + dest.data = buffer; + dest.size = src->size; + dest.tag = src->tag; + + LoadSpriteSheet(&dest); + Free(buffer); + return FALSE; +} + +bool8 LoadCompressedObjectPaletteUsingHeap(const struct CompressedSpritePalette *src) +{ + struct SpritePalette dest; + void* buffer; + + buffer = AllocZeroed(*((u32*)(&src->data[0])) >> 8); + LZ77UnCompWram(src->data, buffer); + dest.data = buffer; + dest.tag = src->tag; + + LoadSpritePalette(&dest); + Free(buffer); + return FALSE; +} + +void DecompressPicFromTable_2(const struct CompressedSpriteSheet *src, void* buffer, s32 species) // a copy of DecompressPicFromTable +{ + if (species > SPECIES_EGG) + LZ77UnCompWram(gMonFrontPicTable[0].data, buffer); + else + LZ77UnCompWram(src->data, buffer); + DuplicateDeoxysTiles(buffer, species); +} + +void LoadSpecialPokePic_2(const struct CompressedSpriteSheet *src, void *dest, s32 species, u32 personality, bool8 isFrontPic) // a copy of LoadSpecialPokePic +{ + if (species == SPECIES_UNOWN) + { + u16 i = (((personality & 0x3000000) >> 18) | ((personality & 0x30000) >> 12) | ((personality & 0x300) >> 6) | (personality & 3)) % 0x1C; + + // The other Unowns are separate from Unown A. + if (i == 0) + i = SPECIES_UNOWN; + else + i += SPECIES_UNOWN_B - 1; + + if (!isFrontPic) + LZ77UnCompWram(gMonBackPicTable[i].data, dest); + else + LZ77UnCompWram(gMonFrontPicTable[i].data, dest); + } + else if (species > SPECIES_EGG) // is species unknown? draw the ? icon + LZ77UnCompWram(gMonFrontPicTable[0].data, dest); + else + LZ77UnCompWram(src->data, dest); + + DuplicateDeoxysTiles(dest, species); + DrawSpindaSpots(species, personality, dest, isFrontPic); +} + +void HandleLoadSpecialPokePic_2(const struct CompressedSpriteSheet *src, void *dest, s32 species, u32 personality) // a copy of HandleLoadSpecialPokePic +{ + bool8 isFrontPic; + + if (src == &gMonFrontPicTable[species]) + isFrontPic = TRUE; // frontPic + else + isFrontPic = FALSE; // backPic + + LoadSpecialPokePic_2(src, dest, species, personality, isFrontPic); +} + +void DecompressPicFromTable_DontHandleDeoxys(const struct CompressedSpriteSheet *src, void* buffer, s32 species) +{ + if (species > SPECIES_EGG) + LZ77UnCompWram(gMonFrontPicTable[0].data, buffer); + else + LZ77UnCompWram(src->data, buffer); +} + +void HandleLoadSpecialPokePic_DontHandleDeoxys(const struct CompressedSpriteSheet *src, void *dest, s32 species, u32 personality) +{ + bool8 isFrontPic; + + if (src == &gMonFrontPicTable[species]) + isFrontPic = TRUE; // frontPic + else + isFrontPic = FALSE; // backPic + + LoadSpecialPokePic_DontHandleDeoxys(src, dest, species, personality, isFrontPic); +} + +void LoadSpecialPokePic_DontHandleDeoxys(const struct CompressedSpriteSheet *src, void *dest, s32 species, u32 personality, bool8 isFrontPic) +{ + if (species == SPECIES_UNOWN) + { + u16 i = (((personality & 0x3000000) >> 18) | ((personality & 0x30000) >> 12) | ((personality & 0x300) >> 6) | (personality & 3)) % 0x1C; + + // The other Unowns are separate from Unown A. + if (i == 0) + i = SPECIES_UNOWN; + else + i += SPECIES_UNOWN_B - 1; + + if (!isFrontPic) + LZ77UnCompWram(gMonBackPicTable[i].data, dest); + else + LZ77UnCompWram(gMonFrontPicTable[i].data, dest); + } + else if (species > SPECIES_EGG) // is species unknown? draw the ? icon + LZ77UnCompWram(gMonFrontPicTable[0].data, dest); + else + LZ77UnCompWram(src->data, dest); + + DrawSpindaSpots(species, personality, dest, isFrontPic); +} + +static void DuplicateDeoxysTiles(void *pointer, s32 species) +{ + if (species == SPECIES_DEOXYS) + CpuCopy32(pointer + 0x800, pointer, 0x800); +} diff --git a/src/event_data.c b/src/event_data.c new file mode 100644 index 000000000..fb2edb063 --- /dev/null +++ b/src/event_data.c @@ -0,0 +1,236 @@ +#include "global.h" +#include "event_data.h" + +#define TEMP_FLAGS_SIZE 0x4 +#define TEMP_UPPER_FLAGS_SIZE 0x8 +#define TEMP_VARS_SIZE 0x20 + +EWRAM_DATA u16 gSpecialVar_0x8000 = 0; +EWRAM_DATA u16 gSpecialVar_0x8001 = 0; +EWRAM_DATA u16 gSpecialVar_0x8002 = 0; +EWRAM_DATA u16 gSpecialVar_0x8003 = 0; +EWRAM_DATA u16 gSpecialVar_0x8004 = 0; +EWRAM_DATA u16 gSpecialVar_0x8005 = 0; +EWRAM_DATA u16 gSpecialVar_0x8006 = 0; +EWRAM_DATA u16 gSpecialVar_0x8007 = 0; +EWRAM_DATA u16 gSpecialVar_0x8008 = 0; +EWRAM_DATA u16 gSpecialVar_0x8009 = 0; +EWRAM_DATA u16 gSpecialVar_0x800A = 0; +EWRAM_DATA u16 gSpecialVar_0x800B = 0; +EWRAM_DATA u16 gScriptResult = 0; +EWRAM_DATA u16 gScriptLastTalked = 0; +EWRAM_DATA u16 gScriptFacing = 0; +EWRAM_DATA u16 gSpecialVar_0x8012 = 0; +EWRAM_DATA u16 gSpecialVar_0x8013 = 0; +EWRAM_DATA u16 gSpecialVar_0x8014 = 0; +EWRAM_DATA static u8 gUnknown_020375FC[16] = {0}; + +extern u16 * const gSpecialVars[]; + +extern void sub_80BB358(void); + +void InitEventData(void) +{ + memset(gSaveBlock1Ptr->flags, 0, sizeof(gSaveBlock1Ptr->flags)); + memset(gSaveBlock1Ptr->vars, 0, sizeof(gSaveBlock1Ptr->vars)); + memset(gUnknown_020375FC, 0, sizeof(gUnknown_020375FC)); +} + +void ClearTempFieldEventData(void) +{ + memset(gSaveBlock1Ptr->flags, 0, TEMP_FLAGS_SIZE); + memset(gSaveBlock1Ptr->vars, 0, TEMP_VARS_SIZE); + FlagReset(SYS_ENC_UP_ITEM); + FlagReset(SYS_ENC_DOWN_ITEM); + FlagReset(SYS_USE_STRENGTH); + FlagReset(SYS_CTRL_OBJ_DELETE); + FlagReset(SYS_UNKNOWN_880); +} + +// probably had different flag splits at one point. +void ClearUpperFlags(void) +{ + memset(gSaveBlock1Ptr->flags + 0x124, 0, TEMP_UPPER_FLAGS_SIZE); +} + +void DisableNationalPokedex(void) +{ + u16 *nationalDexVar = GetVarPointer(VAR_NATIONAL_DEX); + gSaveBlock2Ptr->pokedex.nationalMagic = 0; + *nationalDexVar = 0; + FlagReset(SYS_NATIONAL_DEX); +} + +void EnableNationalPokedex(void) +{ + u16 *nationalDexVar = GetVarPointer(VAR_NATIONAL_DEX); + gSaveBlock2Ptr->pokedex.nationalMagic = 0xDA; + *nationalDexVar = 0x302; + FlagSet(SYS_NATIONAL_DEX); + gSaveBlock2Ptr->pokedex.unknown1 = 1; + gSaveBlock2Ptr->pokedex.order = 0; + sub_80BB358(); +} + +bool32 IsNationalPokedexEnabled(void) +{ + if (gSaveBlock2Ptr->pokedex.nationalMagic == 0xDA && VarGet(VAR_NATIONAL_DEX) == 0x302 && FlagGet(SYS_NATIONAL_DEX)) + return TRUE; + else + return FALSE; +} + +void DisableMysteryEvent(void) +{ + FlagReset(SYS_MYSTERY_EVENT_ENABLE); +} + +void EnableMysteryEvent(void) +{ + FlagSet(SYS_MYSTERY_EVENT_ENABLE); +} + +bool32 IsMysteryEventEnabled(void) +{ + return FlagGet(SYS_MYSTERY_EVENT_ENABLE); +} + +void DisableMysteryGift(void) +{ + FlagReset(SYS_MYSTERY_GIFT_ENABLE); +} + +void EnableMysteryGift(void) +{ + FlagSet(SYS_MYSTERY_GIFT_ENABLE); +} + +bool32 IsMysteryGiftEnabled(void) +{ + return FlagGet(SYS_MYSTERY_GIFT_ENABLE); +} + +void sub_809D4D8(void) +{ + FlagReset(0x1E4); + FlagReset(0x1E5); + FlagReset(0x1E6); + FlagReset(0x1E7); + FlagReset(0x1E8); + FlagReset(0x1E9); + FlagReset(0x1EA); + FlagReset(0x1EB); + FlagReset(0x1EC); + FlagReset(0x1ED); + FlagReset(0x1EE); + FlagReset(0x1EF); + FlagReset(0x1F0); + FlagReset(0x1F1); + FlagReset(0x1F2); + FlagReset(0x1F3); +} + +void sub_809D570(void) +{ + VarSet(0x40DD, 0); + VarSet(0x40DE, 0); + VarSet(0x40DF, 0); + VarSet(0x40E0, 0); + VarSet(0x40E1, 0); + VarSet(0x40E2, 0); + VarSet(0x40E3, 0); + VarSet(0x40E4, 0); +} + +void DisableResetRTC(void) +{ + VarSet(VAR_RESET_RTC_ENABLE, 0); + FlagReset(SYS_RESET_RTC_ENABLE); +} + +void EnableResetRTC(void) +{ + VarSet(VAR_RESET_RTC_ENABLE, 0x920); + FlagSet(SYS_RESET_RTC_ENABLE); +} + +bool32 CanResetRTC(void) +{ + if (FlagGet(SYS_RESET_RTC_ENABLE) && VarGet(VAR_RESET_RTC_ENABLE) == 0x920) + return TRUE; + else + return FALSE; +} + +u16 *GetVarPointer(u16 id) +{ + if (id < 0x4000) + return NULL; + + if ((s16)id >= 0) + return &gSaveBlock1Ptr->vars[id - 0x4000]; + + return gSpecialVars[id - 0x8000]; +} + +u16 VarGet(u16 id) +{ + u16 *ptr = GetVarPointer(id); + if (!ptr) + return id; + return *ptr; +} + +bool8 VarSet(u16 id, u16 value) +{ + u16 *ptr = GetVarPointer(id); + if (!ptr) + return FALSE; + *ptr = value; + return TRUE; +} + +u8 VarGetFieldObjectGraphicsId(u8 id) +{ + return VarGet(0x4010 + id); +} + +u8 *GetFlagPointer(u16 id) +{ + if (id == 0) + return 0; + + if (id < 0x4000) + return &gSaveBlock1Ptr->flags[id / 8]; + + return &gUnknown_020375FC[(id - 0x4000) / 8]; +} + +u8 FlagSet(u16 id) +{ + u8 *ptr = GetFlagPointer(id); + if (ptr) + *ptr |= 1 << (id & 7); + return 0; +} + +u8 FlagReset(u16 id) +{ + u8 *ptr = GetFlagPointer(id); + if (ptr) + *ptr &= ~(1 << (id & 7)); + return 0; +} + +bool8 FlagGet(u16 id) +{ + u8 *ptr = GetFlagPointer(id); + + if (!ptr) + return FALSE; + + if (!(((*ptr) >> (id & 7)) & 1)) + return FALSE; + + return TRUE; +} diff --git a/src/item.c b/src/item.c new file mode 100644 index 000000000..4ad70e11f --- /dev/null +++ b/src/item.c @@ -0,0 +1,228 @@ +#include "global.h" +#include "item.h" +#include "string_util.h" +#include "text.h" +#include "event_data.h" + +extern void ApplyNewEncyprtionKeyToHword(u16* hword, u32 newKey); +extern bool8 InBattlePyramid(void); + +extern const u8 gOtherText_PokeBalls[]; +extern const u8 gOtherText_Berries[]; +extern const u8 gOtherText_Berry[]; +extern const u8 gUnknown_085897E4[][28]; // not sure what this one is + +bool8 CheckPyramidBagHasItem(u16 itemId, u16 count); +bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count); + +enum +{ + ITEMS_POCKET, + BALLS_POCKET, + TMHM_POCKET, + BERRIES_POCKET, + KEYITEMS_POCKET +}; + +u16 GetBagItemQuantity(u16* quantity) +{ + return gSaveBlock2Ptr->encryptionKey ^ *quantity; +} + +void SetBagItemQuantity(u16* quantity, u16 newValue) +{ + *quantity = newValue ^ gSaveBlock2Ptr->encryptionKey; +} + +u16 GetBagItemId(u16* slot) +{ + return *slot; +} + +void SetBagItemId(u16* slot, u16 newItemId) +{ + *slot = newItemId; +} + +void ApplyNewEncyprtionKeyToBagItems(u32 newKey) +{ + u32 pocket, item; + for (pocket = 0; pocket < 5; pocket++) + { + for (item = 0; item < gBagPockets[pocket].capacity; item++) + ApplyNewEncyprtionKeyToHword(&(gBagPockets[pocket].itemSlots[item].quantity), newKey); + } +} + +void ApplyNewEncyprtionKeyToBagItems_(u32 newKey) // really GF? +{ + ApplyNewEncyprtionKeyToBagItems(newKey); +} + +// TODO: move those max values to defines + +void SetBagItemsPointers(void) +{ + gBagPockets[ITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Items; + gBagPockets[ITEMS_POCKET].capacity = 30; + + gBagPockets[KEYITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_KeyItems; + gBagPockets[KEYITEMS_POCKET].capacity = 30; + + gBagPockets[BALLS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_PokeBalls; + gBagPockets[BALLS_POCKET].capacity = 16; + + gBagPockets[TMHM_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_TMHM; + gBagPockets[TMHM_POCKET].capacity = 64; + + gBagPockets[BERRIES_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Berries; + gBagPockets[BERRIES_POCKET].capacity = 46; +} + +void CopyItemName(u16 itemId, u8 *string) +{ + StringCopy(string, ItemId_GetItem(itemId)->name); +} + +void CopyItemNameHandlePlural(u16 itemId, u8 *string, u32 quantity) +{ + if (itemId == 4) + { + if (quantity < 2) + StringCopy(string, ItemId_GetItem(4)->name); + else + StringCopy(string, gOtherText_PokeBalls); + } + else + { + if (itemId >= 0x85 && itemId <= 0xAF) + GetBerryCountString(string, gUnknown_085897E4[itemId], quantity); + else + StringCopy(string, ItemId_GetItem(itemId)->name); + } +} + +void GetBerryCountString(u8* dst, const u8* berryName, u32 quantity) +{ + const u8* berryString; + u8* txtPtr; + + if (quantity < 2) + berryString = gOtherText_Berry; + else + berryString = gOtherText_Berries; + txtPtr = StringCopy(dst, berryName); + *txtPtr = CHAR_SPACE; + StringCopy(txtPtr + 1, berryString); +} + +bool8 IsBagPocketNonEmpty(u8 pocket) +{ + u8 i; + + for (i = 0; i < gBagPockets[pocket - 1].capacity; i++) + { + if (gBagPockets[pocket - 1].itemSlots[i].itemId != 0) + return TRUE; + } + return FALSE; +} + +bool8 CheckBagHasItem(u16 itemId, u16 count) +{ + u8 i; + u8 pocket; + + if (ItemId_GetPocket(itemId) == 0) + return FALSE; + if (InBattlePyramid() || FlagGet(0x4004) == TRUE) + return CheckPyramidBagHasItem(itemId, count); + pocket = ItemId_GetPocket(itemId) - 1; + //Check for item slots that contain the item + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + { + u16 quantity; + //Does this item slot contain enough of the item? + quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); + if (quantity >= count) + return TRUE; + count -= quantity; + //Does this item slot and all previous slots contain enough of the item? + if (count == 0) + return TRUE; + } + } + return FALSE; +} + +bool8 HasAtLeastOneBerry(void) +{ + u16 i; + for (i = 0x85; i < 0xB3; i++) + { + if (CheckBagHasItem(i, 1) == TRUE) + { + gScriptResult = 1; + return TRUE; + } + } + gScriptResult = 0; + return FALSE; +} + +/* Refuses to match. +bool8 CheckBagHasSpace(u16 itemId, u16 count) +{ + u8 i; + u8 pocket; + u16 slotCapacity; + u16 quantity; + + if (ItemId_GetPocket(itemId) == 0) + return FALSE; + if (InBattlePyramid() || FlagGet(0x4004) == TRUE) + return CheckPyramidBagHasSpace(itemId, count); + pocket = ItemId_GetPocket(itemId) - 1; + if (pocket != BERRIES_POCKET) + slotCapacity = 99; + else + slotCapacity = 999; + + //Check space in any existing item slots that already contain this item + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == itemId) + { + quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity); + if (quantity + count <= slotCapacity) + return TRUE; + if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) + return FALSE; + count -= slotCapacity - quantity; + if (count == 0) + return TRUE; + } + } + + //Check space in empty item slots + if (count > 0) + { + for (i = 0; i < gBagPockets[pocket].capacity; i++) + { + if (gBagPockets[pocket].itemSlots[i].itemId == 0) + { + if (count <= slotCapacity) + return TRUE; + if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET) + return FALSE; + count -= slotCapacity; + } + } + if (count > 0) + return FALSE; //No more item slots. The bag is full + } + + return TRUE; +}*/ diff --git a/src/main.c b/src/main.c index 61280f5a7..7c8075a6f 100644 --- a/src/main.c +++ b/src/main.c @@ -22,7 +22,7 @@ extern void rfu_REQ_stopMode(void); extern void rfu_waitREQComplete(void); extern bool32 sub_8087634(void); extern bool32 sub_80875C8(void); -extern void ClearObjectCopyRequests(void); +extern void ClearSpriteCopyRequests(void); extern void PlayTimeCounter_Update(void); extern void MapMusicMain(void); extern void EnableInterrupts(u16); @@ -159,7 +159,7 @@ void AgbMain() if (sub_80875C8() == 1) { gMain.newKeys = 0; - ClearObjectCopyRequests(); + ClearSpriteCopyRequests(); gUnknown_030022B4 = 1; UpdateLinkAndCallCallbacks(); gUnknown_030022B4 = 0; @@ -217,7 +217,7 @@ void SeedRngAndSetTrainerId(void) gTrainerId = val; } -u16 GetTrainerId(void) +u16 GetGeneratedTrainerIdLower(void) { return gTrainerId; } diff --git a/src/malloc.c b/src/malloc.c index fd9dc616a..948303c6f 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -1,5 +1,7 @@ #include "global.h" +EWRAM_DATA u8 gHeap[0x1C000] = {0}; + static void *sHeapStart; static u32 sHeapSize; @@ -67,7 +69,7 @@ void *AllocInternal(void *heapStart, u32 size) // size, so split the rest into a separate block. foundBlockSize -= sizeof(struct MemBlock); foundBlockSize -= size; - + splitBlock = (struct MemBlock *)(pos->data + size); pos->flag = TRUE; diff --git a/src/new_game.c b/src/new_game.c new file mode 100644 index 000000000..649cf4e6d --- /dev/null +++ b/src/new_game.c @@ -0,0 +1,111 @@ +#include "global.h" +#include "new_game.h" +#include "rng.h" + +extern u8 gPlayerPartyCount; +extern u8 gDifferentSaveFile; +extern u16 gSaveFileStatus; +extern u8 gUnknown_030060B0; + +extern u16 GetGeneratedTrainerIdLower(void); +extern void ClearContestWinnerPicsInContestHall(void); +extern void warp1_set(s8 mapBank, s8 mapNo, s8 warpNo, s8 xPos, s8 yPos); +extern void warp_in(void); +extern void sub_80BB358(void); +extern void ZeroPlayerPartyMons(void); +extern void ZeroEnemyPartyMons(void); +extern void ResetBagScrollPositions(void); +extern void sub_813624C(void); // clears something pokeblock related +extern void ClearSav2(void); // clears something pokeblock related + +void WriteUnalignedWord(u32 var, u8 *dataPtr) +{ + dataPtr[0] = var; + dataPtr[1] = var >> 8; + dataPtr[2] = var >> 16; + dataPtr[3] = var >> 24; +} + +u32 ReadUnalignedWord(u8* dataPtr) +{ + return (dataPtr[3] << 24) | (dataPtr[2] << 16) | (dataPtr[1] << 8) | (dataPtr[0]); +} + +void CopyUnalignedWord(u8 *copyTo, u8 *copyFrom) +{ + s32 i; + for (i = 0; i < 4; i++) + copyTo[i] = copyFrom[i]; +} + +void InitPlayerTrainerId(void) +{ + u32 trainerId = (Random() << 0x10) | GetGeneratedTrainerIdLower(); + WriteUnalignedWord(trainerId, gSaveBlock2Ptr->playerTrainerId); +} + +// L=A isnt set here for some reason. +void SetDefaultOptions(void) +{ + gSaveBlock2Ptr->optionsTextSpeed = OPTIONS_TEXT_SPEED_MID; + gSaveBlock2Ptr->optionsWindowFrameType = 0; + gSaveBlock2Ptr->optionsSound = OPTIONS_SOUND_MONO; + gSaveBlock2Ptr->optionsBattleStyle = OPTIONS_BATTLE_STYLE_SHIFT; + gSaveBlock2Ptr->optionsBattleSceneOff = FALSE; + gSaveBlock2Ptr->regionMapZoom = FALSE; +} + +void ClearPokedexFlags(void) +{ + gUnknown_030060B0 = 0; + memset(&gSaveBlock2Ptr->pokedex.owned, 0, sizeof(gSaveBlock2Ptr->pokedex.owned)); + memset(&gSaveBlock2Ptr->pokedex.seen, 0, sizeof(gSaveBlock2Ptr->pokedex.seen)); +} + +extern const struct ContestWinner gContestWinnerPicDummy; + +void ClearAllContestWinnerPics(void) +{ + s32 i; + + ClearContestWinnerPicsInContestHall(); + for (i = 8; i < 13; i++) + gSaveBlock1Ptr->contestWinners[i] = gContestWinnerPicDummy; +} + +void sub_8084400(void) +{ + // probably clearing one struct for battle frontier + CpuFill32(0, gSaveBlock2Ptr->field_64C, 2272); + + // those look like strings + gSaveBlock2Ptr->field_EE1 = 0xFF; + gSaveBlock2Ptr->field_EE9 = 0xFF; +} + +void WarpToTruck(void) +{ + warp1_set(25, 40, -1, -1, -1); // inside of truck + warp_in(); +} + +void Sav2_ClearSetDefault(void) +{ + ClearSav2(); + SetDefaultOptions(); +} + +void sub_808447C(void) +{ + gDifferentSaveFile = 0; + sub_80BB358(); + ZeroPlayerPartyMons(); + ZeroEnemyPartyMons(); + ResetBagScrollPositions(); + sub_813624C(); +} +/* +void NewGameInitData(void) +{ + Finish when more header files are available +}*/ diff --git a/src/play_time.c b/src/play_time.c new file mode 100644 index 000000000..444c2c86c --- /dev/null +++ b/src/play_time.c @@ -0,0 +1,73 @@ +#include "global.h" +#include "play_time.h" + +enum +{ + STOPPED, + RUNNING, + MAXED_OUT +}; + +static u8 sPlayTimeCounterState; + +void PlayTimeCounter_Reset() +{ + sPlayTimeCounterState = STOPPED; + + gSaveBlock2Ptr->playTimeHours = 0; + gSaveBlock2Ptr->playTimeMinutes = 0; + gSaveBlock2Ptr->playTimeSeconds = 0; + gSaveBlock2Ptr->playTimeVBlanks = 0; +} + +void PlayTimeCounter_Start() +{ + sPlayTimeCounterState = RUNNING; + + if (gSaveBlock2Ptr->playTimeHours > 999) + PlayTimeCounter_SetToMax(); +} + +void PlayTimeCounter_Stop() +{ + sPlayTimeCounterState = STOPPED; +} + +void PlayTimeCounter_Update() +{ + if (sPlayTimeCounterState == RUNNING) + { + gSaveBlock2Ptr->playTimeVBlanks++; + + if (gSaveBlock2Ptr->playTimeVBlanks > 59) + { + gSaveBlock2Ptr->playTimeVBlanks = 0; + gSaveBlock2Ptr->playTimeSeconds++; + + if (gSaveBlock2Ptr->playTimeSeconds > 59) + { + gSaveBlock2Ptr->playTimeSeconds = 0; + gSaveBlock2Ptr->playTimeMinutes++; + + if (gSaveBlock2Ptr->playTimeMinutes > 59) + { + gSaveBlock2Ptr->playTimeMinutes = 0; + gSaveBlock2Ptr->playTimeHours++; + + if (gSaveBlock2Ptr->playTimeHours > 999) + PlayTimeCounter_SetToMax(); + } + } + } + } +} + +void PlayTimeCounter_SetToMax() +{ + sPlayTimeCounterState = MAXED_OUT; + + gSaveBlock2Ptr->playTimeHours = 999; + gSaveBlock2Ptr->playTimeMinutes = 59; + gSaveBlock2Ptr->playTimeSeconds = 59; + gSaveBlock2Ptr->playTimeVBlanks = 59; +} diff --git a/src/rtc.c b/src/rtc.c new file mode 100644 index 000000000..ca8b9567e --- /dev/null +++ b/src/rtc.c @@ -0,0 +1,347 @@ +#include "global.h" +#include "rtc.h" +#include "string_util.h" +#include "text.h" + +// iwram bss +IWRAM_DATA static u16 sErrorStatus; +IWRAM_DATA static struct SiiRtcInfo sRtc; +IWRAM_DATA static u8 sProbeResult; +IWRAM_DATA static u16 sSavedIme; + +// iwram common +struct Time gLocalTime; + +// const rom + +static const struct SiiRtcInfo sRtcDummy = {0, MONTH_JAN, 1}; // 2000 Jan 1 + +static const s32 sNumDaysInMonths[12] = +{ + 31, + 28, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31, +}; + +void RtcDisableInterrupts(void) +{ + sSavedIme = REG_IME; + REG_IME = 0; +} + +void RtcRestoreInterrupts(void) +{ + REG_IME = sSavedIme; +} + +u32 ConvertBcdToBinary(u8 bcd) +{ + if (bcd > 0x9F) + return 0xFF; + + if ((bcd & 0xF) <= 9) + return (10 * ((bcd >> 4) & 0xF)) + (bcd & 0xF); + else + return 0xFF; +} + +bool8 IsLeapYear(u32 year) +{ + if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) + return TRUE; + + return FALSE; +} + +u16 ConvertDateToDayCount(u8 year, u8 month, u8 day) +{ + s32 i; + u16 dayCount = 0; + + for (i = year - 1; i >= 0; i--) + { + dayCount += 365; + + if (IsLeapYear(i) == TRUE) + dayCount++; + } + + for (i = 0; i < month - 1; i++) + dayCount += sNumDaysInMonths[i]; + + if (month > MONTH_FEB && IsLeapYear(year) == TRUE) + dayCount++; + + dayCount += day; + + return dayCount; +} + +u16 RtcGetDayCount(struct SiiRtcInfo *rtc) +{ + u8 year = ConvertBcdToBinary(rtc->year); + u8 month = ConvertBcdToBinary(rtc->month); + u8 day = ConvertBcdToBinary(rtc->day); + return ConvertDateToDayCount(year, month, day); +} + +void RtcInit(void) +{ + sErrorStatus = 0; + + RtcDisableInterrupts(); + SiiRtcUnprotect(); + sProbeResult = SiiRtcProbe(); + RtcRestoreInterrupts(); + + if ((sProbeResult & 0xF) != 1) + { + sErrorStatus = RTC_INIT_ERROR; + return; + } + + if (sProbeResult & 0xF0) + sErrorStatus = RTC_INIT_WARNING; + else + sErrorStatus = 0; + + RtcGetRawInfo(&sRtc); + sErrorStatus = RtcCheckInfo(&sRtc); +} + +u16 RtcGetErrorStatus(void) +{ + return sErrorStatus; +} + +void RtcGetInfo(struct SiiRtcInfo *rtc) +{ + if (sErrorStatus & RTC_ERR_FLAG_MASK) + *rtc = sRtcDummy; + else + RtcGetRawInfo(rtc); +} + +void RtcGetDateTime(struct SiiRtcInfo *rtc) +{ + RtcDisableInterrupts(); + SiiRtcGetDateTime(rtc); + RtcRestoreInterrupts(); +} + +void RtcGetStatus(struct SiiRtcInfo *rtc) +{ + RtcDisableInterrupts(); + SiiRtcGetStatus(rtc); + RtcRestoreInterrupts(); +} + +void RtcGetRawInfo(struct SiiRtcInfo *rtc) +{ + RtcGetStatus(rtc); + RtcGetDateTime(rtc); +} + +u16 RtcCheckInfo(struct SiiRtcInfo *rtc) +{ + u16 errorFlags = 0; + s32 year; + s32 month; + s32 value; + + if (rtc->status & SIIRTCINFO_POWER) + errorFlags |= RTC_ERR_POWER_FAILURE; + + if (!(rtc->status & SIIRTCINFO_24HOUR)) + errorFlags |= RTC_ERR_12HOUR_CLOCK; + + year = ConvertBcdToBinary(rtc->year); + + if (year == 0xFF) + errorFlags |= RTC_ERR_INVALID_YEAR; + + month = ConvertBcdToBinary(rtc->month); + + if (month == 0xFF || month == 0 || month > 12) + errorFlags |= RTC_ERR_INVALID_MONTH; + + value = ConvertBcdToBinary(rtc->day); + + if (value == 0xFF) + errorFlags |= RTC_ERR_INVALID_DAY; + + if (month == MONTH_FEB) + { + if (value > IsLeapYear(year) + sNumDaysInMonths[month - 1]) + errorFlags |= RTC_ERR_INVALID_DAY; + } + else + { + if (value > sNumDaysInMonths[month - 1]) + errorFlags |= RTC_ERR_INVALID_DAY; + } + + value = ConvertBcdToBinary(rtc->hour); + + if (value > 24) + errorFlags |= RTC_ERR_INVALID_HOUR; + + value = ConvertBcdToBinary(rtc->minute); + + if (value > 60) + errorFlags |= RTC_ERR_INVALID_MINUTE; + + value = ConvertBcdToBinary(rtc->second); + + if (value > 60) + errorFlags |= RTC_ERR_INVALID_SECOND; + + return errorFlags; +} + +void RtcReset(void) +{ + RtcDisableInterrupts(); + SiiRtcReset(); + RtcRestoreInterrupts(); +} + +void FormatDecimalTime(u8 *dest, s32 hour, s32 minute, s32 second) +{ + dest = ConvertIntToDecimalStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToDecimalStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToDecimalStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void FormatHexTime(u8 *dest, s32 hour, s32 minute, s32 second) +{ + dest = ConvertIntToHexStringN(dest, hour, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToHexStringN(dest, minute, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_COLON; + dest = ConvertIntToHexStringN(dest, second, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void FormatHexRtcTime(u8 *dest) +{ + FormatHexTime(dest, sRtc.hour, sRtc.minute, sRtc.second); +} + +void FormatDecimalDate(u8 *dest, s32 year, s32 month, s32 day) +{ + dest = ConvertIntToDecimalStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToDecimalStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToDecimalStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void FormatHexDate(u8 *dest, s32 year, s32 month, s32 day) +{ + dest = ConvertIntToHexStringN(dest, year, STR_CONV_MODE_LEADING_ZEROS, 4); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToHexStringN(dest, month, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest++ = CHAR_HYPHEN; + dest = ConvertIntToHexStringN(dest, day, STR_CONV_MODE_LEADING_ZEROS, 2); + *dest = EOS; +} + +void RtcCalcTimeDifference(struct SiiRtcInfo *rtc, struct Time *result, struct Time *t) +{ + u16 days = RtcGetDayCount(rtc); + result->seconds = ConvertBcdToBinary(rtc->second) - t->seconds; + result->minutes = ConvertBcdToBinary(rtc->minute) - t->minutes; + result->hours = ConvertBcdToBinary(rtc->hour) - t->hours; + result->days = days - t->days; + + if (result->seconds < 0) + { + result->seconds += 60; + --result->minutes; + } + + if (result->minutes < 0) + { + result->minutes += 60; + --result->hours; + } + + if (result->hours < 0) + { + result->hours += 24; + --result->days; + } +} + +void RtcCalcLocalTime(void) +{ + RtcGetInfo(&sRtc); + RtcCalcTimeDifference(&sRtc, &gLocalTime, &gSaveBlock2Ptr->localTimeOffset); +} + +void RtcInitLocalTimeOffset(s32 hour, s32 minute) +{ + RtcCalcLocalTimeOffset(0, hour, minute, 0); +} + +void RtcCalcLocalTimeOffset(s32 days, s32 hours, s32 minutes, s32 seconds) +{ + gLocalTime.days = days; + gLocalTime.hours = hours; + gLocalTime.minutes = minutes; + gLocalTime.seconds = seconds; + RtcGetInfo(&sRtc); + RtcCalcTimeDifference(&sRtc, &gSaveBlock2Ptr->localTimeOffset, &gLocalTime); +} + +void CalcTimeDifference(struct Time *result, struct Time *t1, struct Time *t2) +{ + result->seconds = t2->seconds - t1->seconds; + result->minutes = t2->minutes - t1->minutes; + result->hours = t2->hours - t1->hours; + result->days = t2->days - t1->days; + + if (result->seconds < 0) + { + result->seconds += 60; + --result->minutes; + } + + if (result->minutes < 0) + { + result->minutes += 60; + --result->hours; + } + + if (result->hours < 0) + { + result->hours += 24; + --result->days; + } +} + +u32 RtcGetMinuteCount(void) +{ + RtcGetInfo(&sRtc); + return (24 * 60) * RtcGetDayCount(&sRtc) + 60 * sRtc.hour + sRtc.minute; +} + +u16 RtcGetLocalDayCount(void) +{ + return RtcGetDayCount(&sRtc); +} + diff --git a/src/save.c b/src/save.c new file mode 100644 index 000000000..ccb653f66 --- /dev/null +++ b/src/save.c @@ -0,0 +1,897 @@ +#include "global.h" +#include "gba/flash_internal.h" +#include "save.h" +#include "game_stat.h" + +extern struct SaveSectionOffsets gSaveSectionOffsets[0xE]; +extern struct SaveSectionLocation gRamSaveSectionLocations[0xE]; +extern void *gUnknown_03005D94; +extern u8 gDecompressionBuffer[]; +extern u32 gFlashMemoryPresent; +extern u16 gUnknown_03006294; + +extern void DoSaveFailedScreen(u8); // save_failed_screen +extern void LoadSerializedGame(void); // load_save +extern bool32 ProgramFlashSectorAndVerify(u8 sector, u8 *data); +extern void ReadFlash(u8 sector, u32 arg1, void* data, u32 size); + +// iwram common +u16 gLastWrittenSector; +u32 gLastSaveCounter; +u16 gLastKnownGoodSector; +u32 gDamagedSaveSectors; +u32 gSaveCounter; +struct SaveSection *gFastSaveSection; +u16 gUnknown_03006208; +u16 gSaveUnusedVar; +u16 gSaveFileStatus; +void (*gGameContinueCallback)(void); + +EWRAM_DATA struct SaveSection gSaveDataBuffer = {0}; + +void ClearSaveData(void) +{ + u16 i; + + for (i = 0; i < NUM_SECTORS_PER_SLOT; i++) + { + EraseFlashSector(i); + EraseFlashSector(i + NUM_SECTORS_PER_SLOT); // clear slot 2. + } +} + +void ResetSaveCounters(void) +{ + gSaveCounter = 0; + gLastWrittenSector = 0; + gDamagedSaveSectors = 0; +} + +bool32 SetDamagedSectorBits(u8 op, u8 bit) +{ + bool32 retVal = FALSE; + + switch (op) + { + case ENABLE: + gDamagedSaveSectors |= (1 << bit); + break; + case DISABLE: + gDamagedSaveSectors &= ~(1 << bit); + break; + case CHECK: // unused + if (gDamagedSaveSectors & (1 << bit)) + retVal = TRUE; + break; + } + + return retVal; +} + +u8 save_write_to_flash(u16 a1, const struct SaveSectionLocation *location) +{ + u32 retVal; + u16 i; + + gFastSaveSection = &gSaveDataBuffer; + + if (a1 != 0xFFFF) // for link + { + retVal = HandleWriteSector(a1, location); + } + else + { + gLastKnownGoodSector = gLastWrittenSector; // backup the current written sector before attempting to write. + gLastSaveCounter = gSaveCounter; + gLastWrittenSector++; + gLastWrittenSector = gLastWrittenSector % 0xE; // array count save sector locations + gSaveCounter++; + retVal = 1; + + for (i = 0; i < 0xE; i++) + HandleWriteSector(i, location); + + if (gDamagedSaveSectors != 0) // skip the damaged sector. + { + retVal = 0xFF; + gLastWrittenSector = gLastKnownGoodSector; + gSaveCounter = gLastSaveCounter; + } + } + + return retVal; +} + +u8 HandleWriteSector(u16 a1, const struct SaveSectionLocation *location) +{ + u16 i; + u16 sector; + u8 *data; + u16 size; + + sector = a1 + gLastWrittenSector; + sector %= 0xE; + sector += 0xE * (gSaveCounter % 2); + + data = location[a1].data; + size = location[a1].size; + + // clear save section. + for (i = 0; i < sizeof(struct SaveSection); i++) + ((char *)gFastSaveSection)[i] = 0; + + gFastSaveSection->id = a1; + gFastSaveSection->security = UNKNOWN_CHECK_VALUE; + gFastSaveSection->counter = gSaveCounter; + + for (i = 0; i < size; i++) + gFastSaveSection->data[i] = data[i]; + + gFastSaveSection->checksum = CalculateChecksum(data, size); + return TryWriteSector(sector, gFastSaveSection->data); +} + +u8 HandleWriteSectorNBytes(u8 sector, u8 *data, u16 size) +{ + u16 i; + struct SaveSection *section = &gSaveDataBuffer; + + for (i = 0; i < sizeof(struct SaveSection); i++) + ((char *)section)[i] = 0; + + section->security = UNKNOWN_CHECK_VALUE; + + for (i = 0; i < size; i++) + section->data[i] = data[i]; + + section->id = CalculateChecksum(data, size); // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used. + return TryWriteSector(sector, section->data); +} + +u8 TryWriteSector(u8 sector, u8 *data) +{ + if (ProgramFlashSectorAndVerify(sector, data) != 0) // is damaged? + { + SetDamagedSectorBits(ENABLE, sector); // set damaged sector bits. + return 0xFF; + } + else + { + SetDamagedSectorBits(DISABLE, sector); // unset damaged sector bits. it's safe now. + return 1; + } +} + +u32 RestoreSaveBackupVarsAndIncrement(const struct SaveSectionLocation *location) // location is unused +{ + gFastSaveSection = &gSaveDataBuffer; + gLastKnownGoodSector = gLastWrittenSector; + gLastSaveCounter = gSaveCounter; + gLastWrittenSector++; + gLastWrittenSector = gLastWrittenSector % 0xE; + gSaveCounter++; + gUnknown_03006208 = 0; + gDamagedSaveSectors = 0; + return 0; +} + +u32 RestoreSaveBackupVars(const struct SaveSectionLocation *location) // only ever called once, and gSaveBlock2 is passed to this function. location is unused +{ + gFastSaveSection = &gSaveDataBuffer; + gLastKnownGoodSector = gLastWrittenSector; + gLastSaveCounter = gSaveCounter; + gUnknown_03006208 = 0; + gDamagedSaveSectors = 0; + return 0; +} + +u8 sub_81529D4(u16 a1, const struct SaveSectionLocation *location) +{ + u8 retVal; + + if (gUnknown_03006208 < a1 - 1) + { + retVal = 1; + HandleWriteSector(gUnknown_03006208, location); + gUnknown_03006208++; + if (gDamagedSaveSectors) + { + retVal = 0xFF; + gLastWrittenSector = gLastKnownGoodSector; + gSaveCounter = gLastSaveCounter; + } + } + else + { + retVal = 0xFF; + } + + return retVal; +} + +u8 sub_8152A34(u16 a1, const struct SaveSectionLocation *location) +{ + u8 retVal = 1; + + ClearSaveData_2(a1 - 1, location); + + if (gDamagedSaveSectors) + { + retVal = 0xFF; + gLastWrittenSector = gLastKnownGoodSector; + gSaveCounter = gLastSaveCounter; + } + return retVal; +} + +u8 ClearSaveData_2(u16 a1, const struct SaveSectionLocation *location) +{ + u16 i; + u16 sector; + u8 *data; + u16 size; + u8 status; + + sector = a1 + gLastWrittenSector; + sector %= 0xE; + sector += 0xE * (gSaveCounter % 2); + + data = location[a1].data; + size = location[a1].size; + + // clear temp save section. + for (i = 0; i < sizeof(struct SaveSection); i++) + ((char *)gFastSaveSection)[i] = 0; + + gFastSaveSection->id = a1; + gFastSaveSection->security = UNKNOWN_CHECK_VALUE; + gFastSaveSection->counter = gSaveCounter; + + // set temp section's data. + for (i = 0; i < size; i++) + gFastSaveSection->data[i] = data[i]; + + // calculate checksum. + gFastSaveSection->checksum = CalculateChecksum(data, size); + + EraseFlashSector(sector); + + status = 1; + + for (i = 0; i < sizeof(struct UnkSaveSection); i++) + { + if (ProgramFlashByte(sector, i, ((u8 *)gFastSaveSection)[i])) + { + status = 0xFF; + break; + } + } + + if (status == 0xFF) + { + SetDamagedSectorBits(ENABLE, sector); + return 0xFF; + } + else + { + status = 1; + + for (i = 0; i < 7; i++) + { + if (ProgramFlashByte(sector, 0xFF9 + i, ((u8 *)gFastSaveSection)[0xFF9 + i])) + { + status = 0xFF; + break; + } + } + + if (status == 0xFF) + { + SetDamagedSectorBits(ENABLE, sector); + return 0xFF; + } + else + { + SetDamagedSectorBits(DISABLE, sector); + return 1; + } + } +} + +u8 sav12_xor_get(u16 a1, const struct SaveSectionLocation *location) +{ + u16 sector; + + sector = a1 + gLastWrittenSector; // no sub 1? + sector %= 0xE; + sector += 0xE * (gSaveCounter % 2); + + if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), 0x25)) + { + // sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. + SetDamagedSectorBits(ENABLE, sector); + gLastWrittenSector = gLastKnownGoodSector; + gSaveCounter = gLastSaveCounter; + return 0xFF; + } + else + { + SetDamagedSectorBits(DISABLE, sector); + return 1; + } +} + +u8 sub_8152CAC(u16 a1, const struct SaveSectionLocation *location) +{ + u16 sector; + + sector = a1 + gLastWrittenSector - 1; + sector %= 0xE; + sector += 0xE * (gSaveCounter % 2); + + if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), ((u8 *)gFastSaveSection)[sizeof(struct UnkSaveSection)])) + { + // sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. + SetDamagedSectorBits(ENABLE, sector); + gLastWrittenSector = gLastKnownGoodSector; + gSaveCounter = gLastSaveCounter; + return 0xFF; + } + else + { + SetDamagedSectorBits(DISABLE, sector); + return 1; + } +} + +u8 sub_8152D44(u16 a1, const struct SaveSectionLocation *location) +{ + u16 sector; + + sector = a1 + gLastWrittenSector - 1; // no sub 1? + sector %= 0xE; + sector += 0xE * (gSaveCounter % 2); + + if (ProgramFlashByte(sector, sizeof(struct UnkSaveSection), 0x25)) + { + // sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter. + SetDamagedSectorBits(ENABLE, sector); + gLastWrittenSector = gLastKnownGoodSector; + gSaveCounter = gLastSaveCounter; + return 0xFF; + } + else + { + SetDamagedSectorBits(DISABLE, sector); + return 1; + } +} + +u8 sub_8152DD0(u16 a1, const struct SaveSectionLocation *location) +{ + u8 retVal; + gFastSaveSection = &gSaveDataBuffer; + if (a1 != 0xFFFF) + { + retVal = 0xFF; + } + else + { + retVal = GetSaveValidStatus(location); + sub_8152E10(0xFFFF, location); + } + + return retVal; +} + +u8 sub_8152E10(u16 a1, const struct SaveSectionLocation *location) +{ + u16 i; + u16 checksum; + u16 v3 = 0xE * (gSaveCounter % 2); + u16 id; + + for (i = 0; i < 0xE; i++) + { + DoReadFlashWholeSection(i + v3, gFastSaveSection); + id = gFastSaveSection->id; + if (id == 0) + gLastWrittenSector = i; + checksum = CalculateChecksum(gFastSaveSection->data, location[id].size); + if (gFastSaveSection->security == UNKNOWN_CHECK_VALUE + && gFastSaveSection->checksum == checksum) + { + u16 j; + for (j = 0; j < location[id].size; j++) + ((u8 *)location[id].data)[j] = gFastSaveSection->data[j]; + } + } + + return 1; +} + +u8 GetSaveValidStatus(const struct SaveSectionLocation *location) +{ + u16 i; + u16 checksum; + u32 saveSlot1Counter = 0; + u32 saveSlot2Counter = 0; + u32 slotCheckField = 0; + bool8 securityPassed = FALSE; + u8 saveSlot1Status; + u8 saveSlot2Status; + + // check save slot 1. + for (i = 0; i < 0xE; i++) + { + DoReadFlashWholeSection(i, gFastSaveSection); + if (gFastSaveSection->security == UNKNOWN_CHECK_VALUE) + { + securityPassed = TRUE; + checksum = CalculateChecksum(gFastSaveSection->data, location[gFastSaveSection->id].size); + if (gFastSaveSection->checksum == checksum) + { + saveSlot1Counter = gFastSaveSection->counter; + slotCheckField |= 1 << gFastSaveSection->id; + } + } + } + + if (securityPassed) + { + if (slotCheckField == 0x3FFF) + saveSlot1Status = 1; + else + saveSlot1Status = 255; + } + else + { + saveSlot1Status = 0; + } + + slotCheckField = 0; + securityPassed = FALSE; + + // check save slot 2. + for (i = 0; i < 0xE; i++) + { + DoReadFlashWholeSection(i + 0xE, gFastSaveSection); + if (gFastSaveSection->security == UNKNOWN_CHECK_VALUE) + { + securityPassed = TRUE; + checksum = CalculateChecksum(gFastSaveSection->data, location[gFastSaveSection->id].size); + if (gFastSaveSection->checksum == checksum) + { + saveSlot2Counter = gFastSaveSection->counter; + slotCheckField |= 1 << gFastSaveSection->id; + } + } + } + + if (securityPassed) + { + if (slotCheckField == 0x3FFF) + saveSlot2Status = 1; + else + saveSlot2Status = 255; + } + else + { + saveSlot2Status = 0; + } + + if (saveSlot1Status == 1 && saveSlot2Status == 1) + { + if ((saveSlot1Counter == -1 && saveSlot2Counter == 0) || (saveSlot1Counter == 0 && saveSlot2Counter == -1)) + { + if ((unsigned)(saveSlot1Counter + 1) < (unsigned)(saveSlot2Counter + 1)) + { + gSaveCounter = saveSlot2Counter; + } + else + { + gSaveCounter = saveSlot1Counter; + } + } + else + { + if (saveSlot1Counter < saveSlot2Counter) + { + gSaveCounter = saveSlot2Counter; + } + else + { + gSaveCounter = saveSlot1Counter; + } + } + return 1; + } + + if (saveSlot1Status == 1) + { + gSaveCounter = saveSlot1Counter; + if (saveSlot2Status == 255) + return 255; + return 1; + } + + if (saveSlot2Status == 1) + { + gSaveCounter = saveSlot2Counter; + if (saveSlot1Status == 255) + return 255; + return 1; + } + + if (saveSlot1Status == 0 && saveSlot2Status == 0) + { + gSaveCounter = 0; + gLastWrittenSector = 0; + return 0; + } + + gSaveCounter = 0; + gLastWrittenSector = 0; + return 2; +} + +u8 sub_81530DC(u8 a1, u8 *data, u16 size) +{ + u16 i; + struct SaveSection *section = &gSaveDataBuffer; + DoReadFlashWholeSection(a1, section); + if (section->security == UNKNOWN_CHECK_VALUE) + { + u16 checksum = CalculateChecksum(section->data, size); + if (section->id == checksum) + { + for (i = 0; i < size; i++) + data[i] = section->data[i]; + return 1; + } + else + { + return 2; + } + } + else + { + return 0; + } +} + +u8 DoReadFlashWholeSection(u8 sector, struct SaveSection *section) +{ + ReadFlash(sector, 0, section->data, sizeof(struct SaveSection)); + return 1; +} + +u16 CalculateChecksum(void *data, u16 size) +{ + u16 i; + u32 checksum = 0; + + for (i = 0; i < (size / 4); i++) + checksum += *((u32 *)data)++; + + return ((checksum >> 16) + checksum); +} + +#ifdef NONMATCHING +// the initial allocation of the pointer and toAdd variable doesnt match up with the original function. however, forcing it is impossible since gRamSaveSectionLocations is loaded first. +void UpdateSaveAddresses(void) +{ + int i = 0; + gRamSaveSectionLocations[i].data = gSaveBlock2Ptr + gSaveSectionOffsets[0].toAdd; + gRamSaveSectionLocations[i].size = gSaveSectionOffsets[0].size; + + for(i = 1; i < 5; i++) + { + gRamSaveSectionLocations[i].data = gSaveBlock1Ptr + gSaveSectionOffsets[i].toAdd; + gRamSaveSectionLocations[i].size = gSaveSectionOffsets[i].size; + } + + for(i = 5; i < 14; i++) + { + gRamSaveSectionLocations[i].data = gUnknown_03005D94 + gSaveSectionOffsets[i].toAdd; + gRamSaveSectionLocations[i].size = gSaveSectionOffsets[i].size; + } +} +#else +__attribute__((naked)) +void UpdateSaveAddresses(void) +{ + asm(".syntax unified\n\ + push {r4,r5,lr}\n\ + ldr r3, =gRamSaveSectionLocations\n\ + ldr r0, =gSaveBlock2Ptr\n\ + ldr r2, =gSaveSectionOffsets\n\ + ldrh r1, [r2]\n\ + ldr r0, [r0]\n\ + adds r0, r1\n\ + str r0, [r3]\n\ + ldrh r0, [r2, 0x2]\n\ + strh r0, [r3, 0x4]\n\ + ldr r5, =gSaveBlock1Ptr\n\ + adds r3, 0x8\n\ + adds r2, 0x4\n\ + movs r4, 0x3\n\ +_081531AC:\n\ + ldrh r0, [r2]\n\ + ldr r1, [r5]\n\ + adds r1, r0\n\ + str r1, [r3]\n\ + ldrh r0, [r2, 0x2]\n\ + strh r0, [r3, 0x4]\n\ + adds r3, 0x8\n\ + adds r2, 0x4\n\ + subs r4, 0x1\n\ + cmp r4, 0\n\ + bge _081531AC\n\ + movs r4, 0x5\n\ + ldr r1, =gRamSaveSectionLocations\n\ + ldr r5, =gUnknown_03005D94\n\ + ldr r0, =gSaveSectionOffsets\n\ + adds r3, r1, 0\n\ + adds r3, 0x28\n\ + adds r2, r0, 0\n\ + adds r2, 0x14\n\ +_081531D2:\n\ + ldrh r0, [r2]\n\ + ldr r1, [r5]\n\ + adds r1, r0\n\ + str r1, [r3]\n\ + ldrh r0, [r2, 0x2]\n\ + strh r0, [r3, 0x4]\n\ + adds r3, 0x8\n\ + adds r2, 0x4\n\ + adds r4, 0x1\n\ + cmp r4, 0xD\n\ + ble _081531D2\n\ + pop {r4,r5}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif + +extern u32 GetGameStat(u8 index); // rom4 +extern void IncrementGameStat(u8 index); // rom4 +extern void SaveSerializedGame(void); // load_save +extern u32 gUnknown_0203CF5C; + +u8 HandleSavingData(u8 saveType) +{ + u8 i; + u32 backupVar = gUnknown_0203CF5C; + u8 *tempAddr; + + gUnknown_0203CF5C = 0; + UpdateSaveAddresses(); + switch (saveType) + { + case HOF_DELETE_SAVE: // deletes HOF before overwriting HOF completely. unused + for (i = 0xE * 2 + 0; i < 32; i++) + EraseFlashSector(i); + case HOF_SAVE: // hall of fame. + if (GetGameStat(GAME_STAT_ENTERED_HOF) < 999) + IncrementGameStat(GAME_STAT_ENTERED_HOF); + SaveSerializedGame(); + save_write_to_flash(0xFFFF, gRamSaveSectionLocations); + tempAddr = (u8 *)0x201C000; // FIXME: make this a label. + HandleWriteSectorNBytes(0x1C, tempAddr, 0xF80); + HandleWriteSectorNBytes(0x1D, tempAddr + 0xF80, 0xF80); + break; + case NORMAL_SAVE: // normal save. also called by overwriting your own save. + default: + SaveSerializedGame(); + save_write_to_flash(0xFFFF, gRamSaveSectionLocations); + break; + case LINK_SAVE: // _081532C4 + case LINK2_SAVE: + SaveSerializedGame(); + for(i = 0; i < 5; i++) + ClearSaveData_2(i, gRamSaveSectionLocations); + for(i = 0; i < 5; i++) + sav12_xor_get(i, gRamSaveSectionLocations); + break; + // support for Ereader was removed in Emerald. + /* + case EREADER_SAVE: // used in mossdeep "game corner" before/after battling old man e-reader trainer + SaveSerializedGame(); + save_write_to_flash(0, gRamSaveSectionLocations); + break; + */ + case DIFFERENT_FILE_SAVE: + for (i = (0xE * 2 + 0); i < 32; i++) + EraseFlashSector(i); // erase HOF. + SaveSerializedGame(); + save_write_to_flash(0xFFFF, gRamSaveSectionLocations); + break; + } + gUnknown_0203CF5C = backupVar; + return 0; +} + +u8 TrySavingData(u8 saveType) // TrySave +{ + if(gFlashMemoryPresent == TRUE) + { + HandleSavingData(saveType); + if(gDamagedSaveSectors) + DoSaveFailedScreen(saveType); + else + goto OK; // really? + } + gUnknown_03006294 = 0xFF; + return 0xFF; + +OK: + gUnknown_03006294 = 1; + return 1; +} + +u8 sub_8153380(void) // trade.s save +{ + if (gFlashMemoryPresent != TRUE) + return 1; + UpdateSaveAddresses(); + SaveSerializedGame(); + RestoreSaveBackupVarsAndIncrement(gRamSaveSectionLocations); + return 0; +} + +bool8 sub_81533AC(void) // trade.s save +{ + u8 retVal = sub_81529D4(0xE, gRamSaveSectionLocations); + if (gDamagedSaveSectors) + DoSaveFailedScreen(0); + if (retVal == 0xFF) + return 1; + else + return 0; +} + +u8 sub_81533E0(void) // trade.s save +{ + sub_8152A34(0xE, gRamSaveSectionLocations); + if (gDamagedSaveSectors) + DoSaveFailedScreen(0); + return 0; +} + +u8 sub_8153408(void) // trade.s save +{ + sub_8152CAC(0xE, gRamSaveSectionLocations); + if (gDamagedSaveSectors) + DoSaveFailedScreen(0); + return 0; +} + +u8 sub_8153430(void) +{ + if (gFlashMemoryPresent != TRUE) + return 1; + + UpdateSaveAddresses(); + SaveSerializedGame(); + RestoreSaveBackupVars(gRamSaveSectionLocations); + sub_8152A34(gUnknown_03006208 + 1, gRamSaveSectionLocations); + return 0; +} + +bool8 sub_8153474(void) +{ + u8 retVal = FALSE; + u16 val = ++gUnknown_03006208; + if (val <= 4) + { + sub_8152A34(gUnknown_03006208 + 1, gRamSaveSectionLocations); + sub_8152D44(val, gRamSaveSectionLocations); + } + else + { + sub_8152D44(val, gRamSaveSectionLocations); + retVal = TRUE; + } + if (gDamagedSaveSectors) + DoSaveFailedScreen(1); + return retVal; +} + +u8 sub_81534D0(u8 a1) +{ + u8 result; + + if (gFlashMemoryPresent != TRUE) + { + gSaveFileStatus = 4; + return 0xFF; + } + + UpdateSaveAddresses(); + switch (a1) + { + case 0: + default: + result = sub_8152DD0(0xFFFF, gRamSaveSectionLocations); + LoadSerializedGame(); + gSaveFileStatus = result; + gGameContinueCallback = 0; + break; + case 3: + result = sub_81530DC(0x1C, gDecompressionBuffer, 0xF80); + if(result == 1) + result = sub_81530DC(0x1D, gDecompressionBuffer + 0xF80, 0xF80); + break; + } + + return result; +} + +u16 sub_815355C(void) +{ + u16 i, v3; + struct SaveSection* savSection; + + savSection = gFastSaveSection = &gSaveDataBuffer; + if (gFlashMemoryPresent != 1) + return 0; + UpdateSaveAddresses(); + GetSaveValidStatus(gRamSaveSectionLocations); + v3 = 0xE * (gSaveCounter % 2); + for (i = 0; i < 14; i++) + { + DoReadFlashWholeSection(i + v3, gFastSaveSection); + if (gFastSaveSection->id == 0) + return savSection->data[10] + + savSection->data[11] + + savSection->data[12] + + savSection->data[13]; + } + return 0; +} + +u32 sub_81535DC(u8 sector, u8* dst) +{ + s32 i; + s32 size; + u8* savData; + + if (sector != 30 && sector != 31) + return 0xFF; + ReadFlash(sector, 0, &gSaveDataBuffer, sizeof(struct SaveSection)); + if (*(u32*)(&gSaveDataBuffer.data[0]) != 0xB39D) + return 0xFF; + // copies whole save section except u32 counter + i = 0; + size = 0xFFB; + savData = &gSaveDataBuffer.data[4]; + for (; i <= size; i++) + dst[i] = savData[i]; + return 1; +} + +u32 sub_8153634(u8 sector, u8* src) +{ + s32 i; + s32 size; + u8* savData; + void* savDataBuffer; + + if (sector != 30 && sector != 31) + return 0xFF; + savDataBuffer = &gSaveDataBuffer; + *(u32*)(savDataBuffer) = 0xB39D; + + // copies whole save section except u32 counter + i = 0; + size = 0xFFB; + savData = &gSaveDataBuffer.data[4]; + for (; i <= size; i++) + savData[i] = src[i]; + if (ProgramFlashSectorAndVerify(sector, savDataBuffer) != 0) + return 0xFF; + return 1; +} diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 000000000..a95511ece --- /dev/null +++ b/src/sound.c @@ -0,0 +1,611 @@ +#include "global.h" +#include "gba/m4a_internal.h" +#include "sound.h" +#include "battle.h" +#include "m4a.h" +#include "main.h" +#include "pokemon.h" +#include "songs.h" +#include "task.h" + +struct Fanfare +{ + u16 songNum; + u16 duration; +}; + +// ewram +EWRAM_DATA struct MusicPlayerInfo* gMPlay_PokemonCry = NULL; +EWRAM_DATA u8 gPokemonCryBGMDuckingCounter = 0; + +// iwram bss +IWRAM_DATA static u16 sCurrentMapMusic; +IWRAM_DATA static u16 sNextMapMusic; +IWRAM_DATA static u8 sMapMusicState; +IWRAM_DATA static u8 sMapMusicFadeInSpeed; +IWRAM_DATA static u16 sFanfareCounter; + +// iwram common +bool8 gDisableMusic; + +extern u32 gBattleTypeFlags; +extern struct MusicPlayerInfo gMPlay_BGM; +extern struct MusicPlayerInfo gMPlay_SE1; +extern struct MusicPlayerInfo gMPlay_SE2; +extern struct MusicPlayerInfo gMPlay_SE3; +extern struct ToneData gCryTable[]; +extern struct ToneData gCryTable2[]; +extern const struct Fanfare sFanfares[]; + +extern u16 SpeciesToCryId(u16); + +static void Task_Fanfare(u8 taskId); +static void CreateFanfareTask(void); +static void Task_DuckBGMForPokemonCry(u8 taskId); +static void RestoreBGMVolumeAfterPokemonCry(void); + +#define CRY_VOLUME 120 // was 125 in R/S + +void InitMapMusic(void) +{ + gDisableMusic = FALSE; + ResetMapMusic(); +} + +void MapMusicMain(void) +{ + switch (sMapMusicState) + { + case 0: + break; + case 1: + sMapMusicState = 2; + PlayBGM(sCurrentMapMusic); + break; + case 2: + case 3: + case 4: + break; + case 5: + if (IsBGMStopped()) + { + sNextMapMusic = 0; + sMapMusicState = 0; + } + break; + case 6: + if (IsBGMStopped() && IsFanfareTaskInactive()) + { + sCurrentMapMusic = sNextMapMusic; + sNextMapMusic = 0; + sMapMusicState = 2; + PlayBGM(sCurrentMapMusic); + } + break; + case 7: + if (IsBGMStopped() && IsFanfareTaskInactive()) + { + FadeInNewBGM(sNextMapMusic, sMapMusicFadeInSpeed); + sCurrentMapMusic = sNextMapMusic; + sNextMapMusic = 0; + sMapMusicState = 2; + sMapMusicFadeInSpeed = 0; + } + break; + } +} + +void ResetMapMusic(void) +{ + sCurrentMapMusic = 0; + sNextMapMusic = 0; + sMapMusicState = 0; + sMapMusicFadeInSpeed = 0; +} + +u16 GetCurrentMapMusic(void) +{ + return sCurrentMapMusic; +} + +void PlayNewMapMusic(u16 songNum) +{ + sCurrentMapMusic = songNum; + sNextMapMusic = 0; + sMapMusicState = 1; +} + +void StopMapMusic(void) +{ + sCurrentMapMusic = 0; + sNextMapMusic = 0; + sMapMusicState = 1; +} + +void FadeOutMapMusic(u8 speed) +{ + if (IsNotWaitingForBGMStop()) + FadeOutBGM(speed); + sCurrentMapMusic = 0; + sNextMapMusic = 0; + sMapMusicState = 5; +} + +void FadeOutAndPlayNewMapMusic(u16 songNum, u8 speed) +{ + FadeOutMapMusic(speed); + sCurrentMapMusic = 0; + sNextMapMusic = songNum; + sMapMusicState = 6; +} + +void FadeOutAndFadeInNewMapMusic(u16 songNum, u8 fadeOutSpeed, u8 fadeInSpeed) +{ + FadeOutMapMusic(fadeOutSpeed); + sCurrentMapMusic = 0; + sNextMapMusic = songNum; + sMapMusicState = 7; + sMapMusicFadeInSpeed = fadeInSpeed; +} + +void FadeInNewMapMusic(u16 songNum, u8 speed) +{ + FadeInNewBGM(songNum, speed); + sCurrentMapMusic = songNum; + sNextMapMusic = 0; + sMapMusicState = 2; + sMapMusicFadeInSpeed = 0; +} + +bool8 IsNotWaitingForBGMStop(void) +{ + if (sMapMusicState == 6) + return FALSE; + if (sMapMusicState == 5) + return FALSE; + if (sMapMusicState == 7) + return FALSE; + return TRUE; +} + +void PlayFanfareByFanfareNum(u8 fanfareNum) +{ + u16 songNum; + m4aMPlayStop(&gMPlay_BGM); + songNum = sFanfares[fanfareNum].songNum; + sFanfareCounter = sFanfares[fanfareNum].duration; + m4aSongNumStart(songNum); +} + +bool8 WaitFanfare(bool8 stop) +{ + if (sFanfareCounter) + { + sFanfareCounter--; + return FALSE; + } + else + { + if (!stop) + m4aMPlayContinue(&gMPlay_BGM); + else + m4aSongNumStart(SE_STOP); + + return TRUE; + } +} + +void StopFanfareByFanfareNum(u8 fanfareNum) +{ + m4aSongNumStop(sFanfares[fanfareNum].songNum); +} + +void PlayFanfare(u16 songNum) +{ + s32 i; + for (i = 0; (u32)i < 18; i++) + { + if (sFanfares[i].songNum == songNum) + { + PlayFanfareByFanfareNum(i); + CreateFanfareTask(); + return; + } + } + + PlayFanfareByFanfareNum(0); + CreateFanfareTask(); +} + +bool8 IsFanfareTaskInactive(void) +{ + if (FuncIsActiveTask(Task_Fanfare) == TRUE) + return FALSE; + return TRUE; +} + +static void Task_Fanfare(u8 taskId) +{ + if (sFanfareCounter) + { + sFanfareCounter--; + } + else + { + m4aMPlayContinue(&gMPlay_BGM); + DestroyTask(taskId); + } +} + +static void CreateFanfareTask(void) +{ + if (FuncIsActiveTask(Task_Fanfare) != TRUE) + CreateTask(Task_Fanfare, 80); +} + +void FadeInNewBGM(u16 songNum, u8 speed) +{ + if (gDisableMusic) + songNum = 0; + if (songNum == 0xFFFF) + songNum = 0; + m4aSongNumStart(songNum); + m4aMPlayImmInit(&gMPlay_BGM); + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 0); + m4aSongNumStop(songNum); + m4aMPlayFadeIn(&gMPlay_BGM, speed); +} + +void FadeOutBGMTemporarily(u8 speed) +{ + m4aMPlayFadeOutTemporarily(&gMPlay_BGM, speed); +} + +bool8 IsBGMPausedOrStopped(void) +{ + if (gMPlay_BGM.status & MUSICPLAYER_STATUS_PAUSE) + return TRUE; + if (!(gMPlay_BGM.status & MUSICPLAYER_STATUS_TRACK)) + return TRUE; + return FALSE; +} + +void FadeInBGM(u8 speed) +{ + m4aMPlayFadeIn(&gMPlay_BGM, speed); +} + +void FadeOutBGM(u8 speed) +{ + m4aMPlayFadeOut(&gMPlay_BGM, speed); +} + +bool8 IsBGMStopped(void) +{ + if (!(gMPlay_BGM.status & MUSICPLAYER_STATUS_TRACK)) + return TRUE; + return FALSE; +} + +void PlayCry1(u16 species, s8 pan) +{ + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 85); + PlayCryInternal(species, pan, CRY_VOLUME, 10, 0); + gPokemonCryBGMDuckingCounter = 2; + RestoreBGMVolumeAfterPokemonCry(); +} + +void PlayCry2(u16 species, s8 pan, s8 volume, u8 priority) +{ + PlayCryInternal(species, pan, volume, priority, 0); +} + +void PlayCry3(u16 species, s8 pan, u8 mode) +{ + if (mode == 1) + { + PlayCryInternal(species, pan, CRY_VOLUME, 10, 1); + } + else + { + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 85); + PlayCryInternal(species, pan, CRY_VOLUME, 10, mode); + gPokemonCryBGMDuckingCounter = 2; + RestoreBGMVolumeAfterPokemonCry(); + } +} + +void PlayCry4(u16 species, s8 pan, u8 mode) +{ + if (mode == 1) + { + PlayCryInternal(species, pan, CRY_VOLUME, 10, 1); + } + else + { + if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 85); + PlayCryInternal(species, pan, CRY_VOLUME, 10, mode); + } +} + +void PlayCry6(u16 species, s8 pan, u8 mode) // not present in R/S +{ + if (mode == 1) + { + PlayCryInternal(species, pan, CRY_VOLUME, 10, 1); + } + else + { + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 85); + PlayCryInternal(species, pan, CRY_VOLUME, 10, mode); + gPokemonCryBGMDuckingCounter = 2; + } +} + +void PlayCry5(u16 species, u8 mode) +{ + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 85); + PlayCryInternal(species, 0, CRY_VOLUME, 10, mode); + gPokemonCryBGMDuckingCounter = 2; + RestoreBGMVolumeAfterPokemonCry(); +} + +void PlayCryInternal(u16 species, s8 pan, s8 volume, u8 priority, u8 mode) +{ + bool32 v0; + u32 release; + u32 length; + u32 pitch; + u32 chorus; + u32 index; + u8 table; + + species--; + length = 140; + v0 = FALSE; + release = 0; + pitch = 15360; + chorus = 0; + + switch (mode) + { + case 0: + break; + case 1: + length = 20; + release = 225; + break; + case 2: + release = 225; + pitch = 15600; + chorus = 20; + volume = 90; + break; + case 3: + length = 50; + release = 200; + pitch = 15800; + chorus = 20; + volume = 90; + break; + case 4: + length = 25; + v0 = TRUE; + release = 100; + pitch = 15600; + chorus = 192; + volume = 90; + break; + case 5: + release = 200; + pitch = 14440; + break; + case 6: + release = 220; + pitch = 15555; + chorus = 192; + volume = 70; + break; + case 7: + length = 10; + release = 100; + pitch = 14848; + break; + case 8: + length = 60; + release = 225; + pitch = 15616; + break; + case 9: + length = 15; + v0 = TRUE; + release = 125; + pitch = 15200; + break; + case 10: + length = 100; + release = 225; + pitch = 15200; + break; + case 12: + length = 20; + release = 225; + case 11: + pitch = 15000; + break; + } + + SetPokemonCryVolume(volume); + SetPokemonCryPanpot(pan); + SetPokemonCryPitch(pitch); + SetPokemonCryLength(length); + SetPokemonCryProgress(0); + SetPokemonCryRelease(release); + SetPokemonCryChorus(chorus); + SetPokemonCryPriority(priority); + + // This is a fancy way to get a cry of a pokemon. + // It creates 4 sets of 128 mini cry tables. + // If you wish to expand pokemon, you need to + // append new cases to the switch. + species = SpeciesToCryId(species); + index = species & 0x7F; + table = species / 128; + + switch (table) + { + case 0: + gMPlay_PokemonCry = SetPokemonCryTone( + v0 ? &gCryTable2[(128 * 0) + index] : &gCryTable[(128 * 0) + index]); + break; + case 1: + gMPlay_PokemonCry = SetPokemonCryTone( + v0 ? &gCryTable2[(128 * 1) + index] : &gCryTable[(128 * 1) + index]); + break; + case 2: + gMPlay_PokemonCry = SetPokemonCryTone( + v0 ? &gCryTable2[(128 * 2) + index] : &gCryTable[(128 * 2) + index]); + break; + case 3: + gMPlay_PokemonCry = SetPokemonCryTone( + v0 ? &gCryTable2[(128 * 3) + index] : &gCryTable[(128 * 3) + index]); + break; + } +} + +bool8 IsCryFinished(void) +{ + if (FuncIsActiveTask(Task_DuckBGMForPokemonCry) == TRUE) + { + return FALSE; + } + else + { + ClearPokemonCrySongs(); + return TRUE; + } +} + +void StopCryAndClearCrySongs(void) +{ + m4aMPlayStop(gMPlay_PokemonCry); + ClearPokemonCrySongs(); +} + +void StopCry(void) +{ + m4aMPlayStop(gMPlay_PokemonCry); +} + +bool8 IsCryPlayingOrClearCrySongs(void) +{ + if (IsPokemonCryPlaying(gMPlay_PokemonCry)) + { + return TRUE; + } + else + { + ClearPokemonCrySongs(); + return FALSE; + } +} + +bool8 IsCryPlaying(void) +{ + if (IsPokemonCryPlaying(gMPlay_PokemonCry)) + return TRUE; + else + return FALSE; +} + +static void Task_DuckBGMForPokemonCry(u8 taskId) +{ + if (gPokemonCryBGMDuckingCounter) + { + gPokemonCryBGMDuckingCounter--; + return; + } + + if (!IsPokemonCryPlaying(gMPlay_PokemonCry)) + { + m4aMPlayVolumeControl(&gMPlay_BGM, 0xFFFF, 256); + DestroyTask(taskId); + } +} + +static void RestoreBGMVolumeAfterPokemonCry(void) +{ + if (FuncIsActiveTask(Task_DuckBGMForPokemonCry) != TRUE) + CreateTask(Task_DuckBGMForPokemonCry, 80); +} + +void PlayBGM(u16 songNum) +{ + if (gDisableMusic) + songNum = 0; + if (songNum == 0xFFFF) + songNum = 0; + m4aSongNumStart(songNum); +} + +void PlaySE(u16 songNum) +{ + m4aSongNumStart(songNum); +} + +void PlaySE12WithPanning(u16 songNum, s8 pan) +{ + m4aSongNumStart(songNum); + m4aMPlayImmInit(&gMPlay_SE1); + m4aMPlayImmInit(&gMPlay_SE2); + m4aMPlayPanpotControl(&gMPlay_SE1, 0xFFFF, pan); + m4aMPlayPanpotControl(&gMPlay_SE2, 0xFFFF, pan); +} + +void PlaySE1WithPanning(u16 songNum, s8 pan) +{ + m4aSongNumStart(songNum); + m4aMPlayImmInit(&gMPlay_SE1); + m4aMPlayPanpotControl(&gMPlay_SE1, 0xFFFF, pan); +} + +void PlaySE2WithPanning(u16 songNum, s8 pan) +{ + m4aSongNumStart(songNum); + m4aMPlayImmInit(&gMPlay_SE2); + m4aMPlayPanpotControl(&gMPlay_SE2, 0xFFFF, pan); +} + +void SE12PanpotControl(s8 pan) +{ + m4aMPlayPanpotControl(&gMPlay_SE1, 0xFFFF, pan); + m4aMPlayPanpotControl(&gMPlay_SE2, 0xFFFF, pan); +} + +bool8 IsSEPlaying(void) +{ + if ((gMPlay_SE1.status & MUSICPLAYER_STATUS_PAUSE) && (gMPlay_SE2.status & MUSICPLAYER_STATUS_PAUSE)) + return FALSE; + if (!(gMPlay_SE1.status & MUSICPLAYER_STATUS_TRACK) && !(gMPlay_SE2.status & MUSICPLAYER_STATUS_TRACK)) + return FALSE; + return TRUE; +} + +bool8 IsBGMPlaying(void) +{ + if (gMPlay_BGM.status & MUSICPLAYER_STATUS_PAUSE) + return FALSE; + if (!(gMPlay_BGM.status & MUSICPLAYER_STATUS_TRACK)) + return FALSE; + return TRUE; +} + +bool8 IsSpecialSEPlaying(void) +{ + if (gMPlay_SE3.status & MUSICPLAYER_STATUS_PAUSE) + return FALSE; + if (!(gMPlay_SE3.status & MUSICPLAYER_STATUS_TRACK)) + return FALSE; + return TRUE; +} diff --git a/src/sprite.c b/src/sprite.c new file mode 100644 index 000000000..17b0f181a --- /dev/null +++ b/src/sprite.c @@ -0,0 +1,1831 @@ +#include "global.h" +#include "sprite.h" +#include "main.h" +#include "palette.h" + +#define MAX_SPRITE_COPY_REQUESTS 64 + +#define OAM_MATRIX_COUNT 32 + +#define SET_SPRITE_TILE_RANGE(index, start, count) \ +{ \ + sSpriteTileRanges[index * 2] = start; \ + (sSpriteTileRanges + 1)[index * 2] = count; \ +} + +#define ALLOC_SPRITE_TILE(n) \ +{ \ + gSpriteTileAllocBitmap[(n) / 8] |= (1 << ((n) % 8)); \ +} + +#define FREE_SPRITE_TILE(n) \ +{ \ + gSpriteTileAllocBitmap[(n) / 8] &= ~(1 << ((n) % 8)); \ +} + +#define SPRITE_TILE_IS_ALLOCATED(n) ((gSpriteTileAllocBitmap[(n) / 8] >> ((n) % 8)) & 1) + + +struct SpriteCopyRequest +{ + const u8 *src; + u8 *dest; + u16 size; +}; + +struct OamDimensions +{ + s8 width; + s8 height; +}; + +static void UpdateOamCoords(void); +static void BuildSpritePriorities(void); +static void SortSprites(void); +static void CopyMatricesToOamBuffer(void); +static void AddSpritesToOamBuffer(void); +static u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority); +static void ResetOamMatrices(void); +static void ResetSprite(struct Sprite *sprite); +static s16 AllocSpriteTiles(u16 tileCount); +static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); +static void ResetAllSprites(void); +static void BeginAnim(struct Sprite *sprite); +static void ContinueAnim(struct Sprite *sprite); +static void AnimCmd_frame(struct Sprite *sprite); +static void AnimCmd_end(struct Sprite *sprite); +static void AnimCmd_jump(struct Sprite *sprite); +static void AnimCmd_loop(struct Sprite *sprite); +static void BeginAnimLoop(struct Sprite *sprite); +static void ContinueAnimLoop(struct Sprite *sprite); +static void JumpToTopOfAnimLoop(struct Sprite *sprite); +static void BeginAffineAnim(struct Sprite *sprite); +static void ContinueAffineAnim(struct Sprite *sprite); +static void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite); +static void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite); +static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite); +static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix); +static u8 GetSpriteMatrixNum(struct Sprite *sprite); +static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); +static void AffineAnimStateRestartAnim(u8 matrixNum); +static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum); +static void AffineAnimStateReset(u8 matrixNum); +static void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static void DecrementAnimDelayCounter(struct Sprite *sprite); +static bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum); +static void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static s16 ConvertScaleParam(s16 scale); +static void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd); +static void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd); +static u8 IndexOfSpriteTileTag(u16 tag); +static void AllocSpriteTileRange(u16 tag, u16 start, u16 count); +static void DoLoadSpritePalette(const u16 *src, u16 paletteOffset); +static void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2); + +typedef void (*AnimFunc)(struct Sprite *); +typedef void (*AnimCmdFunc)(struct Sprite *); +typedef void (*AffineAnimCmdFunc)(u8 matrixNum, struct Sprite *); + +#define DUMMY_OAM_DATA \ +{ \ + 160, /* Y (off-screen) */ \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 304, /* X */ \ + 0, \ + 0, \ + 0, \ + 3, /* lowest priority */ \ + 0, \ + 0 \ +} + +#define ANIM_END 0xFFFF +#define AFFINE_ANIM_END 0x7FFF + +// forward declarations +const union AnimCmd * const gDummySpriteAnimTable[]; +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[]; +const struct SpriteTemplate gDummySpriteTemplate; + +// Unreferenced data. Also unreferenced in R/S. +static const u8 sUnknownData[24] = +{ + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, + 0x01, 0x04, 0x10, 0x40, + 0x02, 0x04, 0x08, 0x20, + 0x02, 0x04, 0x08, 0x20, +}; + +static const u8 sCenterToCornerVecTable[3][4][2] = +{ + { // square + { -4, -4 }, + { -8, -8 }, + { -16, -16 }, + { -32, -32 }, + }, + { // horizontal rectangle + { -8, -4 }, + { -16, -4 }, + { -16, -8 }, + { -32, -16 }, + }, + { // vertical rectangle + { -4, -8 }, + { -4, -16 }, + { -8, -16 }, + { -16, -32 }, + }, +}; + +static const struct Sprite sDummySprite = +{ + .oam = DUMMY_OAM_DATA, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .template = &gDummySpriteTemplate, + .subspriteTables = NULL, + .callback = SpriteCallbackDummy, + .pos1 = { 304, 160 }, + .pos2 = { 0, 0 }, + .centerToCornerVecX = 0, + .centerToCornerVecY = 0, + .animNum = 0, + .animCmdIndex = 0, + .animDelayCounter = 0, + .animPaused = 0, + .affineAnimPaused = 0, + .animLoopCounter = 0, + .data0 = 0, + .data1 = 0, + .data2 = 0, + .data3 = 0, + .data4 = 0, + .data5 = 0, + .data6 = 0, + .data7 = 0, + .inUse = 0, + .coordOffsetEnabled = 0, + .invisible = 0, + .flags_3 = 0, + .flags_4 = 0, + .flags_5 = 0, + .flags_6 = 0, + .flags_7 = 0, + .hFlip = 0, + .vFlip = 0, + .animBeginning = 0, + .affineAnimBeginning = 0, + .animEnded = 0, + .affineAnimEnded = 0, + .usingSheet = 0, + .flags_f = 0, + .sheetTileStart = 0, + .subspriteTableNum = 0, + .subspriteMode = 0, + .subpriority = 0xFF +}; + +const struct OamData gDummyOamData = DUMMY_OAM_DATA; + +static const union AnimCmd sDummyAnim = { ANIM_END }; + +const union AnimCmd * const gDummySpriteAnimTable[] = { &sDummyAnim }; + +static const union AffineAnimCmd sDummyAffineAnim = { AFFINE_ANIM_END }; + +const union AffineAnimCmd * const gDummySpriteAffineAnimTable[] = { &sDummyAffineAnim }; + +const struct SpriteTemplate gDummySpriteTemplate = +{ + .tileTag = 0, + .paletteTag = 0xFFFF, + .oam = &gDummyOamData, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy +}; + +static const AnimFunc sAnimFuncs[] = +{ + ContinueAnim, + BeginAnim, +}; + +static const AnimFunc sAffineAnimFuncs[] = +{ + ContinueAffineAnim, + BeginAffineAnim, +}; + +static const AnimCmdFunc sAnimCmdFuncs[] = +{ + AnimCmd_loop, + AnimCmd_jump, + AnimCmd_end, + AnimCmd_frame, +}; + +static const AffineAnimCmdFunc sAffineAnimCmdFuncs[] = +{ + AffineAnimCmd_loop, + AffineAnimCmd_jump, + AffineAnimCmd_end, + AffineAnimCmd_frame, +}; + +static const s32 gUnknown_082EC6F4[24] = +{ + 8, 8, 0x10, 0x10, 0x20, 0x20, + 0x40, 0x40, 0x10, 8, 0x20, 8, + 0x20, 0x10, 0x40, 0x20, 8, 0x10, + 8, 0x20, 0x10, 0x20, 0x20, 0x40, +}; + +static const struct OamDimensions sOamDimensions[3][4] = +{ + { // square + { 8, 8 }, + { 16, 16 }, + { 32, 32 }, + { 64, 64 }, + }, + { // horizontal rectangle + { 16, 8 }, + { 32, 8 }, + { 32, 16 }, + { 64, 32 }, + }, + { // vertical rectangle + { 8, 16 }, + { 8, 32 }, + { 16, 32 }, + { 32, 64 }, + }, +}; + +// iwram bss +IWRAM_DATA static u16 sSpriteTileRangeTags[MAX_SPRITES]; +IWRAM_DATA static u16 sSpriteTileRanges[MAX_SPRITES * 2]; +IWRAM_DATA static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; +IWRAM_DATA static u16 sSpritePaletteTags[16]; + +// iwram common +u32 gOamMatrixAllocBitmap; +u8 gReservedSpritePaletteCount; + +EWRAM_DATA struct Sprite gSprites[MAX_SPRITES + 1] = {0}; +EWRAM_DATA u16 gSpritePriorities[MAX_SPRITES] = {0}; +EWRAM_DATA u8 gSpriteOrder[MAX_SPRITES] = {0}; +EWRAM_DATA bool8 gShouldProcessSpriteCopyRequests = 0; +EWRAM_DATA u8 gSpriteCopyRequestCount = 0; +EWRAM_DATA struct SpriteCopyRequest gSpriteCopyRequests[MAX_SPRITES] = {0}; +EWRAM_DATA u8 gOamLimit = 0; +EWRAM_DATA u16 gReservedSpriteTileCount = 0; +EWRAM_DATA u8 gSpriteTileAllocBitmap[128] = {0}; +EWRAM_DATA s16 gSpriteCoordOffsetX = 0; +EWRAM_DATA s16 gSpriteCoordOffsetY = 0; +EWRAM_DATA struct OamMatrix gOamMatrices[OAM_MATRIX_COUNT] = {0}; +EWRAM_DATA bool8 gAffineAnimsDisabled = 0; + +void ResetSpriteData(void) +{ + ResetOamRange(0, 128); + ResetAllSprites(); + ClearSpriteCopyRequests(); + ResetAffineAnimData(); + FreeSpriteTileRanges(); + gOamLimit = 64; + gReservedSpriteTileCount = 0; + AllocSpriteTiles(0); + gSpriteCoordOffsetX = 0; + gSpriteCoordOffsetY = 0; +} + +void AnimateSprites(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (sprite->inUse) + { + sprite->callback(sprite); + + if (sprite->inUse) + AnimateSprite(sprite); + } + } +} + +void BuildOamBuffer(void) +{ + u8 temp; + UpdateOamCoords(); + BuildSpritePriorities(); + SortSprites(); + temp = gMain.oamLoadDisabled; + gMain.oamLoadDisabled = TRUE; + AddSpritesToOamBuffer(); + CopyMatricesToOamBuffer(); + gMain.oamLoadDisabled = temp; + gShouldProcessSpriteCopyRequests = TRUE; +} + +void UpdateOamCoords(void) +{ + u8 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + if (sprite->inUse && !sprite->invisible) + { + if (sprite->coordOffsetEnabled) + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY; + } + else + { + sprite->oam.x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX; + sprite->oam.y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY; + } + } + } +} + +void BuildSpritePriorities(void) +{ + u16 i; + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + u16 priority = sprite->subpriority | (sprite->oam.priority << 8); + gSpritePriorities[i] = priority; + } +} + +void SortSprites(void) +{ + u8 i; + for (i = 1; i < MAX_SPRITES; i++) + { + u8 j = i; + struct Sprite *sprite1 = &gSprites[gSpriteOrder[i - 1]]; + struct Sprite *sprite2 = &gSprites[gSpriteOrder[i]]; + u16 sprite1Priority = gSpritePriorities[gSpriteOrder[i - 1]]; + u16 sprite2Priority = gSpritePriorities[gSpriteOrder[i]]; + s16 sprite1Y = sprite1->oam.y; + s16 sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == 3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == 2) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == 3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + + while (j > 0 + && ((sprite1Priority > sprite2Priority) + || (sprite1Priority == sprite2Priority && sprite1Y < sprite2Y))) + { + u8 temp = gSpriteOrder[j]; + gSpriteOrder[j] = gSpriteOrder[j - 1]; + gSpriteOrder[j - 1] = temp; + + // UB: If j equals 1, then j-- makes j equal 0. + // Then, gSpriteOrder[-1] gets accessed below. + // Although this doesn't result in a bug in the ROM, + // the behavior is undefined. + j--; + + sprite1 = &gSprites[gSpriteOrder[j - 1]]; + sprite2 = &gSprites[gSpriteOrder[j]]; + sprite1Priority = gSpritePriorities[gSpriteOrder[j - 1]]; + sprite2Priority = gSpritePriorities[gSpriteOrder[j]]; + sprite1Y = sprite1->oam.y; + sprite2Y = sprite2->oam.y; + + if (sprite1Y >= DISPLAY_HEIGHT) + sprite1Y = sprite1Y - 256; + + if (sprite2Y >= DISPLAY_HEIGHT) + sprite2Y = sprite2Y - 256; + + if (sprite1->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite1->oam.size == 3) + { + u32 shape = sprite1->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite1Y > 128) + sprite1Y = sprite1Y - 256; + } + } + + if (sprite2->oam.affineMode == ST_OAM_AFFINE_DOUBLE + && sprite2->oam.size == 3) + { + u32 shape = sprite2->oam.shape; + if (shape == ST_OAM_SQUARE || shape == ST_OAM_V_RECTANGLE) + { + if (sprite2Y > 128) + sprite2Y = sprite2Y - 256; + } + } + } + } +} + +void CopyMatricesToOamBuffer(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + u32 base = 4 * i; + gMain.oamBuffer[base + 0].affineParam = gOamMatrices[i].a; + gMain.oamBuffer[base + 1].affineParam = gOamMatrices[i].b; + gMain.oamBuffer[base + 2].affineParam = gOamMatrices[i].c; + gMain.oamBuffer[base + 3].affineParam = gOamMatrices[i].d; + } +} + +void AddSpritesToOamBuffer(void) +{ + u8 i = 0; + u8 oamIndex = 0; + + while (i < MAX_SPRITES) + { + struct Sprite *sprite = &gSprites[gSpriteOrder[i]]; + if (sprite->inUse && !sprite->invisible && AddSpriteToOamBuffer(sprite, &oamIndex)) + return; + i++; + } + + while (oamIndex < gOamLimit) + { + gMain.oamBuffer[oamIndex] = gDummyOamData; + oamIndex++; + } +} + +u8 CreateSprite(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateSpriteAtEnd(const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + s16 i; + + for (i = MAX_SPRITES - 1; i > -1; i--) + if (!gSprites[i].inUse) + return CreateSpriteAt(i, template, x, y, subpriority); + + return MAX_SPRITES; +} + +u8 CreateInvisibleSprite(void (*callback)(struct Sprite *)) +{ + u8 index = CreateSprite(&gDummySpriteTemplate, 0, 0, 31); + + if (index == MAX_SPRITES) + { + return MAX_SPRITES; + } + else + { + gSprites[index].invisible = TRUE; + gSprites[index].callback = callback; + return index; + } +} + +u8 CreateSpriteAt(u8 index, const struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + struct Sprite *sprite = &gSprites[index]; + + ResetSprite(sprite); + + sprite->inUse = TRUE; + sprite->animBeginning = TRUE; + sprite->affineAnimBeginning = TRUE; + sprite->usingSheet = TRUE; + + sprite->subpriority = subpriority; + sprite->oam = *template->oam; + sprite->anims = template->anims; + sprite->affineAnims = template->affineAnims; + sprite->template = template; + sprite->callback = template->callback; + sprite->pos1.x = x; + sprite->pos1.y = y; + + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + + if (template->tileTag == 0xFFFF) + { + s16 tileNum; + sprite->images = template->images; + tileNum = AllocSpriteTiles((u8)(sprite->images->size / TILE_SIZE_4BPP)); + if (tileNum == -1) + { + ResetSprite(sprite); + return MAX_SPRITES; + } + sprite->oam.tileNum = tileNum; + sprite->usingSheet = FALSE; + sprite->sheetTileStart = 0; + } + else + { + sprite->sheetTileStart = GetSpriteTileStartByTag(template->tileTag); + SetSpriteSheetFrameTileNum(sprite); + } + + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + InitSpriteAffineAnim(sprite); + + if (template->paletteTag != 0xFFFF) + sprite->oam.paletteNum = IndexOfSpritePaletteTag(template->paletteTag); + + return index; +} + +u8 CreateSpriteAndAnimate(struct SpriteTemplate *template, s16 x, s16 y, u8 subpriority) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + struct Sprite *sprite = &gSprites[i]; + + if (!gSprites[i].inUse) + { + u8 index = CreateSpriteAt(i, template, x, y, subpriority); + + if (index == MAX_SPRITES) + return MAX_SPRITES; + + gSprites[i].callback(sprite); + + if (gSprites[i].inUse) + AnimateSprite(sprite); + + return index; + } + } + + return MAX_SPRITES; +} + +void DestroySprite(struct Sprite *sprite) +{ + if (sprite->inUse) + { + if (!sprite->usingSheet) + { + u16 i; + u16 tileEnd = (sprite->images->size / TILE_SIZE_4BPP) + sprite->oam.tileNum; + for (i = sprite->oam.tileNum; i < tileEnd; i++) + FREE_SPRITE_TILE(i); + } + ResetSprite(sprite); + } +} + +void ResetOamRange(u8 a, u8 b) +{ + u8 i; + + for (i = a; i < b; i++) + { + struct OamData *oamBuffer = gMain.oamBuffer; + oamBuffer[i] = *(struct OamData *)&gDummyOamData; + } +} + +void LoadOam(void) +{ + if (!gMain.oamLoadDisabled) + CpuCopy32(gMain.oamBuffer, (void *)OAM, sizeof(gMain.oamBuffer)); +} + +void ClearSpriteCopyRequests(void) +{ + u8 i; + + gShouldProcessSpriteCopyRequests = FALSE; + gSpriteCopyRequestCount = 0; + + for (i = 0; i < MAX_SPRITE_COPY_REQUESTS; i++) + { + gSpriteCopyRequests[i].src = 0; + gSpriteCopyRequests[i].dest = 0; + gSpriteCopyRequests[i].size = 0; + } +} + +void ResetOamMatrices(void) +{ + u8 i; + for (i = 0; i < OAM_MATRIX_COUNT; i++) + { + // set to identity matrix + gOamMatrices[i].a = 0x0100; + gOamMatrices[i].b = 0x0000; + gOamMatrices[i].c = 0x0000; + gOamMatrices[i].d = 0x0100; + } +} + +void SetOamMatrix(u8 matrixNum, u16 a, u16 b, u16 c, u16 d) +{ + gOamMatrices[matrixNum].a = a; + gOamMatrices[matrixNum].b = b; + gOamMatrices[matrixNum].c = c; + gOamMatrices[matrixNum].d = d; +} + +void ResetSprite(struct Sprite *sprite) +{ + *sprite = sDummySprite; +} + +void CalcCenterToCornerVec(struct Sprite *sprite, u8 shape, u8 size, u8 affineMode) +{ + u8 x = sCenterToCornerVecTable[shape][size][0]; + u8 y = sCenterToCornerVecTable[shape][size][1]; + + if (affineMode & ST_OAM_AFFINE_DOUBLE_MASK) + { + x *= 2; + y *= 2; + } + + sprite->centerToCornerVecX = x; + sprite->centerToCornerVecY = y; +} + +s16 AllocSpriteTiles(u16 tileCount) +{ + u16 i; + s16 start; + u16 numTilesFound; + + if (tileCount == 0) + { + // Free all unreserved tiles if the tile count is 0. + for (i = gReservedSpriteTileCount; i < TOTAL_OBJ_TILE_COUNT; i++) + FREE_SPRITE_TILE(i); + + return 0; + } + + i = gReservedSpriteTileCount; + + for (;;) + { + while (SPRITE_TILE_IS_ALLOCATED(i)) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + } + + start = i; + numTilesFound = 1; + + while (numTilesFound != tileCount) + { + i++; + + if (i == TOTAL_OBJ_TILE_COUNT) + return -1; + + if (!SPRITE_TILE_IS_ALLOCATED(i)) + numTilesFound++; + else + break; + } + + if (numTilesFound == tileCount) + break; + } + + for (i = start; i < tileCount + start; i++) + ALLOC_SPRITE_TILE(i); + + return start; +} + +u8 SpriteTileAllocBitmapOp(u16 bit, u8 op) +{ + u8 index = bit / 8; + u8 shift = bit % 8; + u8 val = bit % 8; + u8 retVal = 0; + + if (op == 0) + { + val = ~(1 << val); + gSpriteTileAllocBitmap[index] &= val; + } + else if (op == 1) + { + val = (1 << val); + gSpriteTileAllocBitmap[index] |= val; + } + else + { + retVal = 1 << shift; + retVal &= gSpriteTileAllocBitmap[index]; + } + + return retVal; +} + +void SpriteCallbackDummy(struct Sprite *sprite) +{ +} + +void ProcessSpriteCopyRequests(void) +{ + if (gShouldProcessSpriteCopyRequests) + { + u8 i = 0; + + while (gSpriteCopyRequestCount > 0) + { + CpuCopy16(gSpriteCopyRequests[i].src, gSpriteCopyRequests[i].dest, gSpriteCopyRequests[i].size); + gSpriteCopyRequestCount--; + i++; + } + + gShouldProcessSpriteCopyRequests = FALSE; + } +} + +void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images) +{ + if (gSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + gSpriteCopyRequests[gSpriteCopyRequestCount].src = images[index].data; + gSpriteCopyRequests[gSpriteCopyRequestCount].dest = (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileNum; + gSpriteCopyRequests[gSpriteCopyRequestCount].size = images[index].size; + gSpriteCopyRequestCount++; + } +} + +void RequestSpriteCopy(const u8 *src, u8 *dest, u16 size) +{ + if (gSpriteCopyRequestCount < MAX_SPRITE_COPY_REQUESTS) + { + gSpriteCopyRequests[gSpriteCopyRequestCount].src = src; + gSpriteCopyRequests[gSpriteCopyRequestCount].dest = dest; + gSpriteCopyRequests[gSpriteCopyRequestCount].size = size; + gSpriteCopyRequestCount++; + } +} + +void CopyFromSprites(u8 *dest) +{ + u32 i; + u8 *src = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + dest++; + src++; + } +} + +void CopyToSprites(u8 *src) +{ + u32 i; + u8 *dest = (u8 *)gSprites; + for (i = 0; i < sizeof(struct Sprite) * MAX_SPRITES; i++) + { + *dest = *src; + src++; + dest++; + } +} + +void ResetAllSprites(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + ResetSprite(&gSprites[i]); + gSpriteOrder[i] = i; + } + + ResetSprite(&gSprites[i]); +} + +void FreeSpriteTiles(struct Sprite *sprite) +{ + if (sprite->template->tileTag != 0xFFFF) + FreeSpriteTilesByTag(sprite->template->tileTag); +} + +void FreeSpritePalette(struct Sprite *sprite) +{ + FreeSpritePaletteByTag(sprite->template->paletteTag); +} + +void FreeSpriteOamMatrix(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + FreeOamMatrix(sprite->oam.matrixNum); + sprite->oam.affineMode = ST_OAM_AFFINE_OFF; + } +} + +void DestroySpriteAndFreeResources(struct Sprite *sprite) +{ + FreeSpriteTiles(sprite); + FreeSpritePalette(sprite); + FreeSpriteOamMatrix(sprite); + DestroySprite(sprite); +} + +void AnimateSprite(struct Sprite *sprite) +{ + sAnimFuncs[sprite->animBeginning](sprite); + + if (!gAffineAnimsDisabled) + sAffineAnimFuncs[sprite->affineAnimBeginning](sprite); +} + +void BeginAnim(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = 0; + sprite->animEnded = FALSE; + sprite->animLoopCounter = 0; + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + + if (imageValue != -1) + { + sprite->animBeginning = FALSE; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); + } +} + +void ContinueAnim(struct Sprite *sprite) +{ + if (sprite->animDelayCounter) + { + u8 hFlip; + u8 vFlip; + DecrementAnimDelayCounter(sprite); + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + } + else if (!sprite->animPaused) + { + s16 type; + s16 funcIndex; + sprite->animCmdIndex++; + type = sprite->anims[sprite->animNum][sprite->animCmdIndex].type; + funcIndex = 3; + if (type < 0) + funcIndex = type + 3; + sAnimCmdFuncs[funcIndex](sprite); + } +} + +void AnimCmd_frame(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +void AnimCmd_end(struct Sprite *sprite) +{ + sprite->animCmdIndex--; + sprite->animEnded = TRUE; +} + +void AnimCmd_jump(struct Sprite *sprite) +{ + s16 imageValue; + u8 duration; + u8 hFlip; + u8 vFlip; + + sprite->animCmdIndex = sprite->anims[sprite->animNum][sprite->animCmdIndex].jump.target; + + imageValue = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + duration = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.duration; + hFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.hFlip; + vFlip = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.vFlip; + + if (duration) + duration--; + + sprite->animDelayCounter = duration; + + if (!(sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK)) + SetSpriteOamFlipBits(sprite, hFlip, vFlip); + + if (sprite->usingSheet) + sprite->oam.tileNum = sprite->sheetTileStart + imageValue; + else + RequestSpriteFrameImageCopy(imageValue, sprite->oam.tileNum, sprite->images); +} + +void AnimCmd_loop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + ContinueAnimLoop(sprite); + else + BeginAnimLoop(sprite); +} + +void BeginAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter = sprite->anims[sprite->animNum][sprite->animCmdIndex].loop.count; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +void ContinueAnimLoop(struct Sprite *sprite) +{ + sprite->animLoopCounter--; + JumpToTopOfAnimLoop(sprite); + ContinueAnim(sprite); +} + +void JumpToTopOfAnimLoop(struct Sprite *sprite) +{ + if (sprite->animLoopCounter) + { + sprite->animCmdIndex--; + + while (sprite->anims[sprite->animNum][sprite->animCmdIndex - 1].type != -3) + { + if (sprite->animCmdIndex == 0) + break; + sprite->animCmdIndex--; + } + + sprite->animCmdIndex--; + } +} + +void BeginAffineAnim(struct Sprite *sprite) +{ + if ((sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) && sprite->affineAnims[0][0].type != 32767) + { + struct AffineAnimFrameCmd frameCmd; + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateRestartAnim(matrixNum); + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + sprite->affineAnimBeginning = FALSE; + sprite->affineAnimEnded = FALSE; + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; + if (sprite->flags_f) + obj_update_pos2(sprite, sprite->data6, sprite->data7); + } +} + +void ContinueAffineAnim(struct Sprite *sprite) +{ + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + { + u8 matrixNum = GetSpriteMatrixNum(sprite); + + if (sAffineAnimStates[matrixNum].delayCounter) + AffineAnimDelay(matrixNum, sprite); + else if (sprite->affineAnimPaused) + return; + else + { + s16 type; + s16 funcIndex; + sAffineAnimStates[matrixNum].animCmdIndex++; + type = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].type; + funcIndex = 3; + if (type >= 32765) + funcIndex = type - 32765; + sAffineAnimCmdFuncs[funcIndex](matrixNum, sprite); + } + if (sprite->flags_f) + obj_update_pos2(sprite, sprite->data6, sprite->data7); + } +} + +void AffineAnimDelay(u8 matrixNum, struct Sprite *sprite) +{ + if (!DecrementAffineAnimDelayCounter(sprite, matrixNum)) + { + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &frameCmd); + } +} + +void AffineAnimCmd_loop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + ContinueAffineAnimLoop(matrixNum, sprite); + else + BeginAffineAnimLoop(matrixNum, sprite); +} + +void BeginAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].loop.count; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +void ContinueAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + sAffineAnimStates[matrixNum].loopCounter--; + JumpToTopOfAffineAnimLoop(matrixNum, sprite); + ContinueAffineAnim(sprite); +} + +void JumpToTopOfAffineAnimLoop(u8 matrixNum, struct Sprite *sprite) +{ + if (sAffineAnimStates[matrixNum].loopCounter) + { + sAffineAnimStates[matrixNum].animCmdIndex--; + + while (sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex - 1].type != 32765) + { + if (sAffineAnimStates[matrixNum].animCmdIndex == 0) + break; + sAffineAnimStates[matrixNum].animCmdIndex--; + } + + sAffineAnimStates[matrixNum].animCmdIndex--; + } +} + +void AffineAnimCmd_jump(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + sAffineAnimStates[matrixNum].animCmdIndex = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].jump.target; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + sprite->affineAnimEnded = TRUE; + sAffineAnimStates[matrixNum].animCmdIndex--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); +} + +void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite) +{ + struct AffineAnimFrameCmd frameCmd; + GetAffineAnimFrame(matrixNum, sprite, &frameCmd); + ApplyAffineAnimFrame(matrixNum, &frameCmd); + sAffineAnimStates[matrixNum].delayCounter = frameCmd.duration; +} + +void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix) +{ + gOamMatrices[destMatrixIndex].a = srcMatrix->a; + gOamMatrices[destMatrixIndex].b = srcMatrix->b; + gOamMatrices[destMatrixIndex].c = srcMatrix->c; + gOamMatrices[destMatrixIndex].d = srcMatrix->d; +} + +u8 GetSpriteMatrixNum(struct Sprite *sprite) +{ + u8 matrixNum = 0; + if (sprite->oam.affineMode & ST_OAM_AFFINE_ON_MASK) + matrixNum = sprite->oam.matrixNum; + return matrixNum; +} + +void sub_8007E18(struct Sprite* sprite, s16 a2, s16 a3) +{ + sprite->data6 = a2; + sprite->data7 = a3; + sprite->flags_f = 1; +} + +s32 sub_8007E28(s32 a0, s32 a1, s32 a2) +{ + s32 subResult, var1; + + subResult = a1 - a0; + if (subResult < 0) + var1 = -(subResult) >> 9; + else + var1 = -(subResult >> 9); + return a2 - ((u32)(a2 * a1) / (u32)(a0) + var1); +} + +#ifdef NONMATCHING +void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2) +{ + s32 var0, var1, var2; + u8 matrixNum = sprite->oam.matrixNum; + if (a1 != 0x800) + { + var0 = gUnknown_082EC6F4[sprite->oam.size * 8 + sprite->oam.shape * 32]; + var1 = var0 << 8; + var2 = (var0 << 16) / gOamMatrices[matrixNum].a; + sprite->pos2.x = sub_8007E28(var1, var2, a1); + } + if (a2 != 0x800) + { + var0 = gUnknown_082EC6F4[4 + (sprite->oam.size * 8 + sprite->oam.shape * 32)]; + var1 = var0 << 8; + var2 = (var0 << 16) / gOamMatrices[matrixNum].d; + sprite->pos2.y = sub_8007E28(var1, var2, a2); + } +} +#else +__attribute__((naked)) +void obj_update_pos2(struct Sprite* sprite, s32 a1, s32 a2) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r9\n\ + mov r6, r8\n\ + push {r6,r7}\n\ + adds r5, r0, 0\n\ + adds r6, r1, 0\n\ + mov r8, r2\n\ + ldrb r1, [r5, 0x3]\n\ + lsls r0, r1, 26\n\ + lsrs r7, r0, 27\n\ + movs r0, 0x80\n\ + lsls r0, 4\n\ + mov r9, r0\n\ + cmp r6, r9\n\ + beq _08007EA2\n\ + ldr r2, =gUnknown_082EC6F4\n\ + lsrs r1, 6\n\ + lsls r1, 3\n\ + ldrb r0, [r5, 0x1]\n\ + lsrs r0, 6\n\ + lsls r0, 5\n\ + adds r1, r0\n\ + adds r1, r2\n\ + ldr r0, [r1]\n\ + lsls r4, r0, 8\n\ + lsls r0, 16\n\ + ldr r2, =gOamMatrices\n\ + lsls r1, r7, 3\n\ + adds r1, r2\n\ + movs r2, 0\n\ + ldrsh r1, [r1, r2]\n\ + bl __divsi3\n\ + adds r1, r0, 0\n\ + adds r0, r4, 0\n\ + adds r2, r6, 0\n\ + bl sub_8007E28\n\ + strh r0, [r5, 0x24]\n\ +_08007EA2:\n\ + cmp r8, r9\n\ + beq _08007EDA\n\ + ldr r2, =gUnknown_082EC6F4\n\ + ldrb r1, [r5, 0x3]\n\ + lsrs r1, 6\n\ + lsls r1, 3\n\ + ldrb r0, [r5, 0x1]\n\ + lsrs r0, 6\n\ + lsls r0, 5\n\ + adds r1, r0\n\ + adds r2, 0x4\n\ + adds r1, r2\n\ + ldr r0, [r1]\n\ + lsls r4, r0, 8\n\ + lsls r0, 16\n\ + ldr r2, =gOamMatrices\n\ + lsls r1, r7, 3\n\ + adds r1, r2\n\ + movs r2, 0x6\n\ + ldrsh r1, [r1, r2]\n\ + bl __divsi3\n\ + adds r1, r0, 0\n\ + adds r0, r4, 0\n\ + mov r2, r8\n\ + bl sub_8007E28\n\ + strh r0, [r5, 0x26]\n\ +_08007EDA:\n\ + pop {r3,r4}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif // NONMATCHING + +void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip) +{ + sprite->oam.matrixNum &= 0x7; + sprite->oam.matrixNum |= (((hFlip ^ sprite->hFlip) & 1) << 3); + sprite->oam.matrixNum |= (((vFlip ^ sprite->vFlip) & 1) << 4); +} + +void AffineAnimStateRestartAnim(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; +} + +void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum) +{ + sAffineAnimStates[matrixNum].animNum = animNum; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +void AffineAnimStateReset(u8 matrixNum) +{ + sAffineAnimStates[matrixNum].animNum = 0; + sAffineAnimStates[matrixNum].animCmdIndex = 0; + sAffineAnimStates[matrixNum].delayCounter = 0; + sAffineAnimStates[matrixNum].loopCounter = 0; + sAffineAnimStates[matrixNum].xScale = 0x0100; + sAffineAnimStates[matrixNum].yScale = 0x0100; + sAffineAnimStates[matrixNum].rotation = 0; +} + +void ApplyAffineAnimFrameAbsolute(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + sAffineAnimStates[matrixNum].xScale = frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale = frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = frameCmd->rotation << 8; +} + +void DecrementAnimDelayCounter(struct Sprite *sprite) +{ + if (!sprite->animPaused) + sprite->animDelayCounter--; +} + +bool8 DecrementAffineAnimDelayCounter(struct Sprite *sprite, u8 matrixNum) +{ + if (!sprite->affineAnimPaused) + --sAffineAnimStates[matrixNum].delayCounter; + return sprite->affineAnimPaused; +} + +void ApplyAffineAnimFrameRelativeAndUpdateMatrix(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + sAffineAnimStates[matrixNum].xScale += frameCmd->xScale; + sAffineAnimStates[matrixNum].yScale += frameCmd->yScale; + sAffineAnimStates[matrixNum].rotation = (sAffineAnimStates[matrixNum].rotation + (frameCmd->rotation << 8)) & ~0xFF; + srcData.xScale = ConvertScaleParam(sAffineAnimStates[matrixNum].xScale); + srcData.yScale = ConvertScaleParam(sAffineAnimStates[matrixNum].yScale); + srcData.rotation = sAffineAnimStates[matrixNum].rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +s16 ConvertScaleParam(s16 scale) +{ + s32 val = 0x10000; + return val / scale; +} + +void GetAffineAnimFrame(u8 matrixNum, struct Sprite *sprite, struct AffineAnimFrameCmd *frameCmd) +{ + frameCmd->xScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.xScale; + frameCmd->yScale = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.yScale; + frameCmd->rotation = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.rotation; + frameCmd->duration = sprite->affineAnims[sAffineAnimStates[matrixNum].animNum][sAffineAnimStates[matrixNum].animCmdIndex].frame.duration; +} + +void ApplyAffineAnimFrame(u8 matrixNum, struct AffineAnimFrameCmd *frameCmd) +{ + struct AffineAnimFrameCmd dummyFrameCmd = {0}; + + if (frameCmd->duration) + { + frameCmd->duration--; + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, frameCmd); + } + else + { + ApplyAffineAnimFrameAbsolute(matrixNum, frameCmd); + ApplyAffineAnimFrameRelativeAndUpdateMatrix(matrixNum, &dummyFrameCmd); + } +} + +void StartSpriteAnim(struct Sprite *sprite, u8 animNum) +{ + sprite->animNum = animNum; + sprite->animBeginning = TRUE; + sprite->animEnded = FALSE; +} + +void StartSpriteAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + if (sprite->animNum != animNum) + StartSpriteAnim(sprite, animNum); +} + +void SeekSpriteAnim(struct Sprite *sprite, u8 animCmdIndex) +{ + u8 temp = sprite->animPaused; + sprite->animCmdIndex = animCmdIndex - 1; + sprite->animDelayCounter = 0; + sprite->animBeginning = FALSE; + sprite->animEnded = FALSE; + sprite->animPaused = FALSE; + ContinueAnim(sprite); + if (sprite->animDelayCounter) + sprite->animDelayCounter++; + sprite->animPaused = temp; +} + +void StartSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + AffineAnimStateStartAnim(matrixNum, animNum); + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void StartSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + StartSpriteAffineAnim(sprite, animNum); +} + +void ChangeSpriteAffineAnim(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + sAffineAnimStates[matrixNum].animNum = animNum; + sprite->affineAnimBeginning = TRUE; + sprite->affineAnimEnded = FALSE; +} + +void ChangeSpriteAffineAnimIfDifferent(struct Sprite *sprite, u8 animNum) +{ + u8 matrixNum = GetSpriteMatrixNum(sprite); + if (sAffineAnimStates[matrixNum].animNum != animNum) + ChangeSpriteAffineAnim(sprite, animNum); +} + +void SetSpriteSheetFrameTileNum(struct Sprite *sprite) +{ + if (sprite->usingSheet) + { + s16 tileOffset = sprite->anims[sprite->animNum][sprite->animCmdIndex].frame.imageValue; + if (tileOffset < 0) + tileOffset = 0; + sprite->oam.tileNum = sprite->sheetTileStart + tileOffset; + } +} + +void ResetAffineAnimData(void) +{ + u8 i; + + gAffineAnimsDisabled = 0; + gOamMatrixAllocBitmap = 0; + + ResetOamMatrices(); + + for (i = 0; i < OAM_MATRIX_COUNT; i++) + AffineAnimStateReset(i); +} + +u8 AllocOamMatrix(void) +{ + u8 i = 0; + u32 bit = 1; + u32 bitmap = gOamMatrixAllocBitmap; + + while (i < OAM_MATRIX_COUNT) + { + if (!(bitmap & bit)) + { + gOamMatrixAllocBitmap |= bit; + return i; + } + + i++; + bit <<= 1; + } + + return 0xFF; +} + +void FreeOamMatrix(u8 matrixNum) +{ + u8 i = 0; + u32 bit = 1; + + while (i < matrixNum) + { + i++; + bit <<= 1; + } + + gOamMatrixAllocBitmap &= ~bit; + SetOamMatrix(matrixNum, 0x100, 0, 0, 0x100); +} + +void InitSpriteAffineAnim(struct Sprite *sprite) +{ + u8 matrixNum = AllocOamMatrix(); + if (matrixNum != 0xFF) + { + CalcCenterToCornerVec(sprite, sprite->oam.shape, sprite->oam.size, sprite->oam.affineMode); + sprite->oam.matrixNum = matrixNum; + sprite->affineAnimBeginning = TRUE; + AffineAnimStateReset(matrixNum); + } +} + +void SetOamMatrixRotationScaling(u8 matrixNum, s16 xScale, s16 yScale, u16 rotation) +{ + struct ObjAffineSrcData srcData; + struct OamMatrix matrix; + srcData.xScale = ConvertScaleParam(xScale); + srcData.yScale = ConvertScaleParam(yScale); + srcData.rotation = rotation; + ObjAffineSet(&srcData, &matrix, 1, 2); + CopyOamMatrix(matrixNum, &matrix); +} + +u16 LoadSpriteSheet(const struct SpriteSheet *sheet) +{ + s16 tileStart = AllocSpriteTiles(sheet->size / TILE_SIZE_4BPP); + + if (tileStart < 0) + { + return 0; + } + else + { + AllocSpriteTileRange(sheet->tag, (u16)tileStart, sheet->size / TILE_SIZE_4BPP); + CpuCopy16(sheet->data, (u8 *)OBJ_VRAM0 + TILE_SIZE_4BPP * tileStart, sheet->size); + return (u16)tileStart; + } +} + +void LoadSpriteSheets(const struct SpriteSheet *sheets) +{ + u8 i; + for (i = 0; sheets[i].data != NULL; i++) + LoadSpriteSheet(&sheets[i]); +} + +void FreeSpriteTilesByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index != 0xFF) + { + u16 i; + u16 *rangeStarts; + u16 *rangeCounts; + u16 start; + u16 count; + rangeStarts = sSpriteTileRanges; + start = rangeStarts[index * 2]; + rangeCounts = sSpriteTileRanges + 1; + count = rangeCounts[index * 2]; + + for (i = start; i < start + count; i++) + FREE_SPRITE_TILE(i); + + sSpriteTileRangeTags[index] = 0xFFFF; + } +} + +void FreeSpriteTileRanges(void) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + sSpriteTileRangeTags[i] = 0xFFFF; + SET_SPRITE_TILE_RANGE(i, 0, 0); + } +} + +u16 GetSpriteTileStartByTag(u16 tag) +{ + u8 index = IndexOfSpriteTileTag(tag); + if (index == 0xFF) + return 0xFFFF; + return sSpriteTileRanges[index * 2]; +} + +u8 IndexOfSpriteTileTag(u16 tag) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + if (sSpriteTileRangeTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpriteTileTagByTileStart(u16 start) +{ + u8 i; + + for (i = 0; i < MAX_SPRITES; i++) + { + if (sSpriteTileRangeTags[i] != 0xFFFF && sSpriteTileRanges[i * 2] == start) + return sSpriteTileRangeTags[i]; + } + + return 0xFFFF; +} + +void AllocSpriteTileRange(u16 tag, u16 start, u16 count) +{ + u8 freeIndex = IndexOfSpriteTileTag(0xFFFF); + sSpriteTileRangeTags[freeIndex] = tag; + SET_SPRITE_TILE_RANGE(freeIndex, start, count); +} + +void FreeAllSpritePalettes(void) +{ + u8 i; + gReservedSpritePaletteCount = 0; + for (i = 0; i < 16; i++) + sSpritePaletteTags[i] = 0xFFFF; +} + +u8 LoadSpritePalette(const struct SpritePalette *palette) +{ + u8 index = IndexOfSpritePaletteTag(palette->tag); + + if (index != 0xFF) + return index; + + index = IndexOfSpritePaletteTag(0xFFFF); + + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = palette->tag; + DoLoadSpritePalette(palette->data, index * 16); + return index; + } +} + +void LoadSpritePalettes(const struct SpritePalette *palettes) +{ + u8 i; + for (i = 0; palettes[i].data != NULL; i++) + if (LoadSpritePalette(&palettes[i]) == 0xFF) + break; +} + +void DoLoadSpritePalette(const u16 *src, u16 paletteOffset) +{ + LoadPalette(src, paletteOffset + 0x100, 32); +} + +u8 AllocSpritePalette(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(0xFFFF); + if (index == 0xFF) + { + return 0xFF; + } + else + { + sSpritePaletteTags[index] = tag; + return index; + } +} + +u8 IndexOfSpritePaletteTag(u16 tag) +{ + u8 i; + for (i = gReservedSpritePaletteCount; i < 16; i++) + if (sSpritePaletteTags[i] == tag) + return i; + + return 0xFF; +} + +u16 GetSpritePaletteTagByPaletteNum(u8 paletteNum) +{ + return sSpritePaletteTags[paletteNum]; +} + +void FreeSpritePaletteByTag(u16 tag) +{ + u8 index = IndexOfSpritePaletteTag(tag); + if (index != 0xFF) + sSpritePaletteTags[index] = 0xFFFF; +} + +void SetSubspriteTables(struct Sprite *sprite, const struct SubspriteTable *subspriteTables) +{ + sprite->subspriteTables = subspriteTables; + sprite->subspriteTableNum = 0; + sprite->subspriteMode = SUBSPRITES_ON; +} + +bool8 AddSpriteToOamBuffer(struct Sprite *sprite, u8 *oamIndex) +{ + if (*oamIndex >= gOamLimit) + return 1; + + if (!sprite->subspriteTables || sprite->subspriteMode == SUBSPRITES_OFF) + { + gMain.oamBuffer[*oamIndex] = sprite->oam; + (*oamIndex)++; + return 0; + } + else + { + return AddSubspritesToOamBuffer(sprite, &gMain.oamBuffer[*oamIndex], oamIndex); + } +} + +bool8 AddSubspritesToOamBuffer(struct Sprite *sprite, struct OamData *destOam, u8 *oamIndex) +{ + const struct SubspriteTable *subspriteTable; + struct OamData *oam; + + if (*oamIndex >= gOamLimit) + return 1; + + subspriteTable = &sprite->subspriteTables[sprite->subspriteTableNum]; + oam = &sprite->oam; + + if (!subspriteTable || !subspriteTable->subsprites) + { + *destOam = *oam; + (*oamIndex)++; + return 0; + } + else + { + u16 tileNum; + u16 baseX; + u16 baseY; + u8 subspriteCount; + u8 hFlip; + u8 vFlip; + u8 i; + + tileNum = oam->tileNum; + subspriteCount = subspriteTable->subspriteCount; + hFlip = ((s32)oam->matrixNum >> 3) & 1; + vFlip = ((s32)oam->matrixNum >> 4) & 1; + baseX = oam->x - sprite->centerToCornerVecX; + baseY = oam->y - sprite->centerToCornerVecY; + + for (i = 0; i < subspriteCount; i++, (*oamIndex)++) + { + u16 x; + u16 y; + + if (*oamIndex >= gOamLimit) + return 1; + + x = subspriteTable->subsprites[i].x; + y = subspriteTable->subsprites[i].y; + + if (hFlip) + { + s8 width = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].width; + s16 right = x; + right += width; + x = right; + x = ~x + 1; + } + + if (vFlip) + { + s8 height = sOamDimensions[subspriteTable->subsprites[i].shape][subspriteTable->subsprites[i].size].height; + s16 bottom = y; + bottom += height; + y = bottom; + y = ~y + 1; + } + + destOam[i] = *oam; + destOam[i].shape = subspriteTable->subsprites[i].shape; + destOam[i].size = subspriteTable->subsprites[i].size; + destOam[i].x = (s16)baseX + (s16)x; + destOam[i].y = baseY + y; + destOam[i].tileNum = tileNum + subspriteTable->subsprites[i].tileOffset; + + if (sprite->subspriteMode != SUBSPRITES_IGNORE_PRIORITY) + destOam[i].priority = subspriteTable->subsprites[i].priority; + } + } + + return 0; +} diff --git a/src/text.c b/src/text.c index 6981b9370..6754e1a42 100644 --- a/src/text.c +++ b/src/text.c @@ -12,12 +12,11 @@ extern u8 GetKeypadIconWidth(u8 keypadIconId); extern void CopyWindowToVram(u8 windowId, u8 mode); extern u16 Font6Func(struct TextPrinter *textPrinter); extern u32 GetGlyphWidthFont6(u16 glyphId, bool32 isJapanese); -extern void audio_play(u16 songNum); +extern void PlaySE(u16 songNum); extern u8* sub_81AFC74(u8 a1); -extern struct Window gWindows[20]; -EWRAM_DATA struct TextPrinter gTempTextPrinter = {}; -EWRAM_DATA struct TextPrinter gTextPrinters[NUM_TEXT_PRINTERS] = {}; +EWRAM_DATA struct TextPrinter gTempTextPrinter = {0}; +EWRAM_DATA struct TextPrinter gTextPrinters[NUM_TEXT_PRINTERS] = {0}; static u16 gFontHalfRowLookupTable[0x51]; static u16 gLastTextBgColor; @@ -177,18 +176,18 @@ bool16 AddTextPrinter(struct TextSubPrinter *textSubPrinter, u8 speed, void (*ca if (!gFonts) return FALSE; - + gTempTextPrinter.sub_union.sub.active = 1; gTempTextPrinter.state = 0; gTempTextPrinter.text_speed = speed; gTempTextPrinter.delayCounter = 0; gTempTextPrinter.scrollDistance = 0; - + for (i = 0; i < 7; ++i) { gTempTextPrinter.sub_union.sub_fields[i] = 0; } - + gTempTextPrinter.subPrinter = *textSubPrinter; gTempTextPrinter.callback = callback; gTempTextPrinter.minLetterSpacing = 0; @@ -208,7 +207,7 @@ bool16 AddTextPrinter(struct TextSubPrinter *textSubPrinter, u8 speed, void (*ca if ((u32)RenderFont(&gTempTextPrinter) == 1) break; } - + if (speed != 0xFF) CopyWindowToVram(gTempTextPrinter.subPrinter.windowId, 2); gTextPrinters[textSubPrinter->windowId].sub_union.sub.active = 0; @@ -266,11 +265,11 @@ u32 RenderFont(struct TextPrinter *textPrinter) void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor) { u16* current = gFontHalfRowLookupTable; - + gLastTextBgColor = bgColor; gLastTextFgColor = fgColor; gLastTextShadowColor = shadowColor; - + *(current++) = (bgColor << 12) | (bgColor << 8) | (bgColor << 4) | bgColor; *(current++) = (fgColor << 12) | (bgColor << 8) | (bgColor << 4) | bgColor; *(current++) = (shadowColor << 12) | (bgColor << 8) | (bgColor << 4) | bgColor; @@ -857,7 +856,7 @@ void RestoreTextColors(u8 *fgColor, u8 *bgColor, u8 *shadowColor) void DecompressGlyphTile(const u16 *src, u16 *dest) { u32 temp; - + temp = src[0]; *(dest++) = (gFontHalfRowLookupTable[gFontHalfRowOffsets[temp & 0xFF]] << 16) | gFontHalfRowLookupTable[gFontHalfRowOffsets[temp >> 8]]; temp = src[1]; @@ -1773,10 +1772,10 @@ void ClearTextSpan(struct TextPrinter *textPrinter, u32 width) pixels_data.pixels = window->tileData; pixels_data.width = window->window.width << 3; pixels_data.height = window->window.height << 3; - + gUnk = gUnknown_03002F90; glyphHeight = &gUnk[0x81]; - + FillBitmapRect4Bit( &pixels_data, textPrinter->subPrinter.currentX, @@ -1790,7 +1789,7 @@ void ClearTextSpan(struct TextPrinter *textPrinter, u32 width) u16 Font0Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 0; @@ -1802,7 +1801,7 @@ u16 Font0Func(struct TextPrinter *textPrinter) u16 Font1Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 1; @@ -1814,7 +1813,7 @@ u16 Font1Func(struct TextPrinter *textPrinter) u16 Font2Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 2; @@ -1826,7 +1825,7 @@ u16 Font2Func(struct TextPrinter *textPrinter) u16 Font3Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 3; @@ -1838,7 +1837,7 @@ u16 Font3Func(struct TextPrinter *textPrinter) u16 Font4Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 4; @@ -1850,7 +1849,7 @@ u16 Font4Func(struct TextPrinter *textPrinter) u16 Font5Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 5; @@ -1862,7 +1861,7 @@ u16 Font5Func(struct TextPrinter *textPrinter) u16 Font7Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 7; @@ -1874,7 +1873,7 @@ u16 Font7Func(struct TextPrinter *textPrinter) u16 Font8Func(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->field_1_top == 0) { textPrinter->sub_union.sub.font_type = 8; @@ -1886,7 +1885,7 @@ u16 Font8Func(struct TextPrinter *textPrinter) void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (gTextFlags.flag_2 == 1) subStruct->frames_visible_counter = 0; else @@ -1916,7 +1915,7 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) textPrinter->subPrinter.currentY, 0x8, 0x10); - + switch (gTextFlags.flag_1) { case 0: @@ -1927,7 +1926,7 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) arrowTiles = gDarkDownArrowTiles; break; } - + BlitBitmapRectToWindow( textPrinter->subPrinter.windowId, arrowTiles, @@ -1940,7 +1939,7 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) 0x8, 0x10); CopyWindowToVram(textPrinter->subPrinter.windowId, 0x2); - + subStruct->field_1 = 0x8; subStruct->field_1_upmid = (*(u32*)subStruct << 17 >> 30) + 1; } @@ -1962,7 +1961,7 @@ void TextPrinterClearDownArrow(struct TextPrinter *textPrinter) bool8 TextPrinterWaitAutoMode(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = &textPrinter->sub_union.sub; - + if (subStruct->frames_visible_counter == 49) { return TRUE; @@ -1987,7 +1986,7 @@ bool8 TextPrinterWaitWithDownArrow(struct TextPrinter *textPrinter) if (gMain.newKeys & (A_BUTTON | B_BUTTON)) { result = TRUE; - audio_play(5); + PlaySE(5); } } return result; @@ -2005,7 +2004,7 @@ bool8 TextPrinterWait(struct TextPrinter *textPrinter) if (gMain.newKeys & (A_BUTTON | B_BUTTON)) { result = TRUE; - audio_play(5); + PlaySE(5); } } return result; @@ -2014,7 +2013,7 @@ bool8 TextPrinterWait(struct TextPrinter *textPrinter) void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *counter, u8 *yCoordIndex) { const u8 *arrowTiles; - + if (*counter != 0) { --*counter; @@ -2034,7 +2033,7 @@ void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *c arrowTiles = gDarkDownArrowTiles; break; } - + BlitBitmapRectToWindow( windowId, arrowTiles, @@ -2382,7 +2381,7 @@ _08005A5C:\n\ add r1, #0x1\n\ str r1, [r6]\n\ add r0, r3, #0\n\ - bl song_play_for_text\n\ + bl PlayBGM\n\ b _08005A0A\n\ _08005A76:\n\ ldr r0, [r6]\n\ @@ -2395,7 +2394,7 @@ _08005A76:\n\ add r1, #0x1\n\ str r1, [r6]\n\ add r0, r3, #0\n\ - bl audio_play\n\ + bl PlaySE\n\ b _08005A0A\n\ _08005A90:\n\ ldr r1, [r6]\n\ @@ -2752,7 +2751,7 @@ _08005D44:\n\ strb r0, [r6, #0x1C]\n\ b _08005B56\n\ _08005D48:\n\ - bl mplay_has_finished_maybe\n\ + bl IsSEPlaying\n\ lsl r0, #24\n\ lsr r0, #24\n\ cmp r0, #0\n\ @@ -2800,7 +2799,7 @@ u32 GetStringWidthFixedWidthFont(u8 *str, u8 fontId, u8 letterSpacing) line = 0; strLocal = str; strPos = 0; - + do { temp = strLocal[strPos++]; @@ -2861,26 +2860,26 @@ u32 GetStringWidthFixedWidthFont(u8 *str, u8 fontId, u8 letterSpacing) break; } } while (temp != 0xFF); - + for (width = 0, strPos = 0; strPos < 8; ++strPos) { if (width < lineWidths[strPos]) width = lineWidths[strPos]; } - + return (u8)(GetFontAttribute(fontId, 0) + letterSpacing) * width; } u32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32) { u32 i; - + for (i = 0; i < 9; ++i) { if (glyphId == gGlyphWidthFuncs[i].font_id) return gGlyphWidthFuncs[i].func; } - + return 0; } @@ -2898,20 +2897,20 @@ s32 GetStringWidth(u8 fontId, u8 *str, s16 letterSpacing) isJapanese = 0; minGlyphWidth = 0; - + func = GetFontWidthFunc(fontId); if (func == NULL) return 0; - + if (letterSpacing == -1) localLetterSpacing = GetFontAttribute(fontId, 2); else localLetterSpacing = letterSpacing; - + width = 0; lineWidth = 0; bufferPointer = 0; - + while (*str != 0xFF) { switch (*str) @@ -3016,7 +3015,7 @@ s32 GetStringWidth(u8 fontId, u8 *str, s16 letterSpacing) glyphWidth = func(*++str | 0x100, isJapanese); else glyphWidth = GetKeypadIconWidth(*++str); - + if (minGlyphWidth > 0) { if (glyphWidth < minGlyphWidth) @@ -3051,7 +3050,7 @@ s32 GetStringWidth(u8 fontId, u8 *str, s16 letterSpacing) } ++str; } - + if (lineWidth > width) return lineWidth; return width; @@ -3069,15 +3068,15 @@ u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str) u8 bgColor; SaveTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); - + fgColor = 1; bgColor = 0; shadowColor = 3; - + GenerateFontHalfRowLookupTable(1, 0, 3); strLocal = str; strPos = 0; - + do { temp = strLocal[strPos++]; @@ -3154,7 +3153,7 @@ u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str) DecompressGlyphFont1(temp, 1); break; } - + CpuCopy32(gUnknown_03002F90, pixels, 0x20); CpuCopy32(gUnknown_03002F90 + 0x40, pixels + 0x20, 0x20); pixels += 0x40; @@ -3162,7 +3161,7 @@ u8 RenderTextFont9(u8 *pixels, u8 fontId, u8 *str) } } while (temp != 0xFF); - + RestoreTextColors(&colorBackup[0], &colorBackup[1], &colorBackup[2]); return 1; } @@ -3257,7 +3256,7 @@ void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese) { glyphs = gFont0LatinGlyphs + (0x20 * glyphId); gUnknown_03002F90[0x80] = gFont0LatinGlyphWidths[glyphId]; - + if (gUnknown_03002F90[0x80] <= 8) { DecompressGlyphTile(glyphs, (u16 *)gUnknown_03002F90); @@ -3270,7 +3269,7 @@ void DecompressGlyphFont0(u16 glyphId, bool32 isJapanese) DecompressGlyphTile(glyphs + 0x10, (u16 *)(gUnknown_03002F90 + 0x40)); DecompressGlyphTile(glyphs + 0x18, (u16 *)(gUnknown_03002F90 + 0x60)); } - + gUnknown_03002F90[0x81] = 13; } } @@ -3286,7 +3285,7 @@ u32 GetGlyphWidthFont0(u16 glyphId, bool32 isJapanese) void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese) { const u16* glyphs; - + if (isJapanese == TRUE) { int eff; @@ -3300,7 +3299,7 @@ void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese) { glyphs = gFont7LatinGlyphs + (0x20 * glyphId); gUnknown_03002F90[0x80] = gFont7LatinGlyphWidths[glyphId]; - + if (gUnknown_03002F90[0x80] <= 8) { DecompressGlyphTile(glyphs, (u16 *)gUnknown_03002F90); @@ -3313,7 +3312,7 @@ void DecompressGlyphFont7(u16 glyphId, bool32 isJapanese) DecompressGlyphTile(glyphs + 0x10, (u16 *)(gUnknown_03002F90 + 0x40)); DecompressGlyphTile(glyphs + 0x18, (u16 *)(gUnknown_03002F90 + 0x60)); } - + gUnknown_03002F90[0x81] = 15; } } @@ -3342,7 +3341,7 @@ void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese) { glyphs = gFont8LatinGlyphs + (0x20 * glyphId); gUnknown_03002F90[0x80] = gFont8LatinGlyphWidths[glyphId]; - + if (gUnknown_03002F90[0x80] <= 8) { DecompressGlyphTile(glyphs, (u16 *)gUnknown_03002F90); @@ -3355,7 +3354,7 @@ void DecompressGlyphFont8(u16 glyphId, bool32 isJapanese) DecompressGlyphTile(glyphs + 0x10, (u16 *)(gUnknown_03002F90 + 0x40)); DecompressGlyphTile(glyphs + 0x18, (u16 *)(gUnknown_03002F90 + 0x60)); } - + gUnknown_03002F90[0x81] = 12; } } @@ -3386,7 +3385,7 @@ void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese) { glyphs = gFont2LatinGlyphs + (0x20 * glyphId); gUnknown_03002F90[0x80] = gFont2LatinGlyphWidths[glyphId]; - + if (gUnknown_03002F90[0x80] <= 8) { DecompressGlyphTile(glyphs, (u16 *)gUnknown_03002F90); @@ -3399,7 +3398,7 @@ void DecompressGlyphFont2(u16 glyphId, bool32 isJapanese) DecompressGlyphTile(glyphs + 0x10, (u16 *)(gUnknown_03002F90 + 0x40)); DecompressGlyphTile(glyphs + 0x18, (u16 *)(gUnknown_03002F90 + 0x60)); } - + gUnknown_03002F90[0x81] = 14; } } @@ -3415,7 +3414,7 @@ u32 GetGlyphWidthFont2(u16 glyphId, bool32 isJapanese) void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese) { const u16* glyphs; - + if (isJapanese == TRUE) { int eff; @@ -3429,7 +3428,7 @@ void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese) { glyphs = gFont1LatinGlyphs + (0x20 * glyphId); gUnknown_03002F90[0x80] = gFont1LatinGlyphWidths[glyphId]; - + if (gUnknown_03002F90[0x80] <= 8) { DecompressGlyphTile(glyphs, (u16 *)gUnknown_03002F90); @@ -3442,7 +3441,7 @@ void DecompressGlyphFont1(u16 glyphId, bool32 isJapanese) DecompressGlyphTile(glyphs + 0x10, (u16 *)(gUnknown_03002F90 + 0x40)); DecompressGlyphTile(glyphs + 0x18, (u16 *)(gUnknown_03002F90 + 0x60)); } - + gUnknown_03002F90[0x81] = 15; } } diff --git a/src/text_window.c b/src/text_window.c new file mode 100644 index 000000000..55aedf688 --- /dev/null +++ b/src/text_window.c @@ -0,0 +1,125 @@ +#include "global.h" +#include "text.h" +#include "text_window.h" +#include "window.h" +#include "palette.h" + +extern u8 LoadBgTiles(u8 bg, const void *src, u16 size, u16 destOffset); +extern void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette); + +extern const struct TilesPal gUnknown_0851021C[]; +extern const u32 gUnknown_08DDD748[]; +extern const u16 gUnknown_0851017C[]; +extern const u16 gUnknown_08DDD728[]; + +const struct TilesPal* sub_8098758(u8 id) +{ + if (id > 19) + return &gUnknown_0851021C[0]; + else + return &gUnknown_0851021C[id]; +} + +void copy_textbox_border_tile_patterns_to_vram(u8 windowId, u16 destOffset, u8 palOffset) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_PRIORITY), gUnknown_08DDD748, 0x1C0, destOffset); + LoadPalette(sub_8098C64(), palOffset, 0x20); +} + +void box_border_load_tiles_and_pal(u8 windowId, u16 destOffset, u8 palOffset) +{ + sub_809882C(windowId, destOffset, palOffset); +} + +void sub_80987D4(u8 windowId, u8 frameId, u16 destOffset, u8 palOffset) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_PRIORITY), gUnknown_0851021C[frameId].tiles, 0x120, destOffset); + LoadPalette(gUnknown_0851021C[frameId].pal, palOffset, 0x20); +} + +void sub_809882C(u8 windowId, u16 destOffset, u8 palOffset) +{ + sub_80987D4(windowId, gSaveBlock2Ptr->optionsWindowFrameType, destOffset, palOffset); +} + +void sub_8098858(u8 windowId, u16 tileNum, u8 palNum) +{ + u8 bgLayer = GetWindowAttribute(windowId, WINDOW_PRIORITY); + u16 tilemapLeft = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT); + u16 tilemapTop = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP); + u16 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u16 height = GetWindowAttribute(windowId, WINDOW_HEIGHT); + + FillBgTilemapBufferRect(bgLayer, tileNum + 0, tilemapLeft - 1, tilemapTop - 1, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 1, tilemapLeft, tilemapTop - 1, width, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 2, tilemapLeft + width, tilemapTop - 1, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 3, tilemapLeft - 1, tilemapTop, 1, height, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 5, tilemapLeft + width, tilemapTop, 1, height, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 6, tilemapLeft - 1, tilemapTop + height, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 7, tilemapLeft, tilemapTop + height, width, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 8, tilemapLeft + width, tilemapTop + height, 1, 1, palNum); +} + +void sub_80989E0(u8 windowId, u16 tileNum, u8 palNum) +{ + u8 bgLayer = GetWindowAttribute(windowId, WINDOW_PRIORITY); + u16 tilemapLeft = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT); + u16 tilemapTop = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP); + u16 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u16 height = GetWindowAttribute(windowId, WINDOW_HEIGHT); + + FillBgTilemapBufferRect(bgLayer, tileNum + 0, tilemapLeft, tilemapTop, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 1, tilemapLeft + 1, tilemapTop, width - 2, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 2, tilemapLeft + width - 1, tilemapTop, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 3, tilemapLeft, tilemapTop + 1, 1, height - 2, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 5, tilemapLeft + width - 1, tilemapTop + 1, 1, height - 2, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 6, tilemapLeft, tilemapTop + height - 1, 1, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 7, tilemapLeft + 1, tilemapTop + height - 1, width - 2, 1, palNum); + FillBgTilemapBufferRect(bgLayer, tileNum + 8, tilemapLeft + width - 1, tilemapTop + height - 1, 1, 1, palNum); +} + +void rbox_fill_rectangle(u8 windowId) +{ + u8 bgLayer = GetWindowAttribute(windowId, WINDOW_PRIORITY); + u16 tilemapLeft = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT); + u16 tilemapTop = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP); + u16 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u16 height = GetWindowAttribute(windowId, WINDOW_HEIGHT); + + FillBgTilemapBufferRect(bgLayer, 0, tilemapLeft - 1, tilemapTop - 1, width + 2, height + 2, 0x11); +} + +const u16* stdpal_get(u8 id) +{ + switch (id) + { + case 0: + id = 0; + break; + case 1: + id = 0x10; + break; + case 2: + id = 0x20; + break; + case 3: + id = 0x30; + break; + case 4: + default: + id = 0x40; + break; + } + return &gUnknown_0851017C[id]; +} + +const u16* sub_8098C64(void) +{ + return gUnknown_08DDD728; +} + +void sub_8098C6C(u8 bg, u16 destOffset, u8 palOffset) +{ + LoadBgTiles(bg, gUnknown_0851021C[gSaveBlock2Ptr->optionsWindowFrameType].tiles, 0x120, destOffset); + LoadPalette(sub_8098758(gSaveBlock2Ptr->optionsWindowFrameType)->pal, palOffset, 0x20); +} diff --git a/src/trig.c b/src/trig.c new file mode 100644 index 000000000..e16a69e63 --- /dev/null +++ b/src/trig.c @@ -0,0 +1,549 @@ +#include "global.h" +#include "trig.h" + +// Converts a number to Q8.8 fixed-point format +#define Q_8_8(n) ((s16)((n) * 256)) + +// Converts a number to Q4.12 fixed-point format +#define Q_4_12(n) ((s16)((n) * 4096)) + +// Values of sin(x*(π/128)) as Q8.8 fixed-point numbers from x = 0 to x = 319 +const s16 gSineTable[] = +{ + Q_8_8(0), // sin(0*(π/128)) + Q_8_8(0.0234375), // sin(1*(π/128)) + Q_8_8(0.046875), // sin(2*(π/128)) + Q_8_8(0.0703125), // sin(3*(π/128)) + Q_8_8(0.09765625), // sin(4*(π/128)) + Q_8_8(0.12109375), // sin(5*(π/128)) + Q_8_8(0.14453125), // sin(6*(π/128)) + Q_8_8(0.16796875), // sin(7*(π/128)) + Q_8_8(0.19140625), // sin(8*(π/128)) + Q_8_8(0.21875), // sin(9*(π/128)) + Q_8_8(0.2421875), // sin(10*(π/128)) + Q_8_8(0.265625), // sin(11*(π/128)) + Q_8_8(0.2890625), // sin(12*(π/128)) + Q_8_8(0.3125), // sin(13*(π/128)) + Q_8_8(0.3359375), // sin(14*(π/128)) + Q_8_8(0.359375), // sin(15*(π/128)) + Q_8_8(0.37890625), // sin(16*(π/128)) + Q_8_8(0.40234375), // sin(17*(π/128)) + Q_8_8(0.42578125), // sin(18*(π/128)) + Q_8_8(0.44921875), // sin(19*(π/128)) + Q_8_8(0.46875), // sin(20*(π/128)) + Q_8_8(0.4921875), // sin(21*(π/128)) + Q_8_8(0.51171875), // sin(22*(π/128)) + Q_8_8(0.53125), // sin(23*(π/128)) + Q_8_8(0.5546875), // sin(24*(π/128)) + Q_8_8(0.57421875), // sin(25*(π/128)) + Q_8_8(0.59375), // sin(26*(π/128)) + Q_8_8(0.61328125), // sin(27*(π/128)) + Q_8_8(0.6328125), // sin(28*(π/128)) + Q_8_8(0.65234375), // sin(29*(π/128)) + Q_8_8(0.66796875), // sin(30*(π/128)) + Q_8_8(0.6875), // sin(31*(π/128)) + Q_8_8(0.70703125), // sin(32*(π/128)) + Q_8_8(0.72265625), // sin(33*(π/128)) + Q_8_8(0.73828125), // sin(34*(π/128)) + Q_8_8(0.75390625), // sin(35*(π/128)) + Q_8_8(0.76953125), // sin(36*(π/128)) + Q_8_8(0.78515625), // sin(37*(π/128)) + Q_8_8(0.80078125), // sin(38*(π/128)) + Q_8_8(0.81640625), // sin(39*(π/128)) + Q_8_8(0.828125), // sin(40*(π/128)) + Q_8_8(0.84375), // sin(41*(π/128)) + Q_8_8(0.85546875), // sin(42*(π/128)) + Q_8_8(0.8671875), // sin(43*(π/128)) + Q_8_8(0.87890625), // sin(44*(π/128)) + Q_8_8(0.890625), // sin(45*(π/128)) + Q_8_8(0.90234375), // sin(46*(π/128)) + Q_8_8(0.9140625), // sin(47*(π/128)) + Q_8_8(0.921875), // sin(48*(π/128)) + Q_8_8(0.9296875), // sin(49*(π/128)) + Q_8_8(0.94140625), // sin(50*(π/128)) + Q_8_8(0.94921875), // sin(51*(π/128)) + Q_8_8(0.953125), // sin(52*(π/128)) + Q_8_8(0.9609375), // sin(53*(π/128)) + Q_8_8(0.96875), // sin(54*(π/128)) + Q_8_8(0.97265625), // sin(55*(π/128)) + Q_8_8(0.98046875), // sin(56*(π/128)) + Q_8_8(0.984375), // sin(57*(π/128)) + Q_8_8(0.98828125), // sin(58*(π/128)) + Q_8_8(0.9921875), // sin(59*(π/128)) + Q_8_8(0.9921875), // sin(60*(π/128)) + Q_8_8(0.99609375), // sin(61*(π/128)) + Q_8_8(0.99609375), // sin(62*(π/128)) + Q_8_8(0.99609375), // sin(63*(π/128)) + Q_8_8(1), // sin(64*(π/128)) + Q_8_8(0.99609375), // sin(65*(π/128)) + Q_8_8(0.99609375), // sin(66*(π/128)) + Q_8_8(0.99609375), // sin(67*(π/128)) + Q_8_8(0.9921875), // sin(68*(π/128)) + Q_8_8(0.9921875), // sin(69*(π/128)) + Q_8_8(0.98828125), // sin(70*(π/128)) + Q_8_8(0.984375), // sin(71*(π/128)) + Q_8_8(0.98046875), // sin(72*(π/128)) + Q_8_8(0.97265625), // sin(73*(π/128)) + Q_8_8(0.96875), // sin(74*(π/128)) + Q_8_8(0.9609375), // sin(75*(π/128)) + Q_8_8(0.953125), // sin(76*(π/128)) + Q_8_8(0.94921875), // sin(77*(π/128)) + Q_8_8(0.94140625), // sin(78*(π/128)) + Q_8_8(0.9296875), // sin(79*(π/128)) + Q_8_8(0.921875), // sin(80*(π/128)) + Q_8_8(0.9140625), // sin(81*(π/128)) + Q_8_8(0.90234375), // sin(82*(π/128)) + Q_8_8(0.890625), // sin(83*(π/128)) + Q_8_8(0.87890625), // sin(84*(π/128)) + Q_8_8(0.8671875), // sin(85*(π/128)) + Q_8_8(0.85546875), // sin(86*(π/128)) + Q_8_8(0.84375), // sin(87*(π/128)) + Q_8_8(0.828125), // sin(88*(π/128)) + Q_8_8(0.81640625), // sin(89*(π/128)) + Q_8_8(0.80078125), // sin(90*(π/128)) + Q_8_8(0.78515625), // sin(91*(π/128)) + Q_8_8(0.76953125), // sin(92*(π/128)) + Q_8_8(0.75390625), // sin(93*(π/128)) + Q_8_8(0.73828125), // sin(94*(π/128)) + Q_8_8(0.72265625), // sin(95*(π/128)) + Q_8_8(0.70703125), // sin(96*(π/128)) + Q_8_8(0.6875), // sin(97*(π/128)) + Q_8_8(0.66796875), // sin(98*(π/128)) + Q_8_8(0.65234375), // sin(99*(π/128)) + Q_8_8(0.6328125), // sin(100*(π/128)) + Q_8_8(0.61328125), // sin(101*(π/128)) + Q_8_8(0.59375), // sin(102*(π/128)) + Q_8_8(0.57421875), // sin(103*(π/128)) + Q_8_8(0.5546875), // sin(104*(π/128)) + Q_8_8(0.53125), // sin(105*(π/128)) + Q_8_8(0.51171875), // sin(106*(π/128)) + Q_8_8(0.4921875), // sin(107*(π/128)) + Q_8_8(0.46875), // sin(108*(π/128)) + Q_8_8(0.44921875), // sin(109*(π/128)) + Q_8_8(0.42578125), // sin(110*(π/128)) + Q_8_8(0.40234375), // sin(111*(π/128)) + Q_8_8(0.37890625), // sin(112*(π/128)) + Q_8_8(0.359375), // sin(113*(π/128)) + Q_8_8(0.3359375), // sin(114*(π/128)) + Q_8_8(0.3125), // sin(115*(π/128)) + Q_8_8(0.2890625), // sin(116*(π/128)) + Q_8_8(0.265625), // sin(117*(π/128)) + Q_8_8(0.2421875), // sin(118*(π/128)) + Q_8_8(0.21875), // sin(119*(π/128)) + Q_8_8(0.19140625), // sin(120*(π/128)) + Q_8_8(0.16796875), // sin(121*(π/128)) + Q_8_8(0.14453125), // sin(122*(π/128)) + Q_8_8(0.12109375), // sin(123*(π/128)) + Q_8_8(0.09765625), // sin(124*(π/128)) + Q_8_8(0.0703125), // sin(125*(π/128)) + Q_8_8(0.046875), // sin(126*(π/128)) + Q_8_8(0.0234375), // sin(127*(π/128)) + Q_8_8(0), // sin(128*(π/128)) + Q_8_8(-0.0234375), // sin(129*(π/128)) + Q_8_8(-0.046875), // sin(130*(π/128)) + Q_8_8(-0.0703125), // sin(131*(π/128)) + Q_8_8(-0.09765625), // sin(132*(π/128)) + Q_8_8(-0.12109375), // sin(133*(π/128)) + Q_8_8(-0.14453125), // sin(134*(π/128)) + Q_8_8(-0.16796875), // sin(135*(π/128)) + Q_8_8(-0.19140625), // sin(136*(π/128)) + Q_8_8(-0.21875), // sin(137*(π/128)) + Q_8_8(-0.2421875), // sin(138*(π/128)) + Q_8_8(-0.265625), // sin(139*(π/128)) + Q_8_8(-0.2890625), // sin(140*(π/128)) + Q_8_8(-0.3125), // sin(141*(π/128)) + Q_8_8(-0.3359375), // sin(142*(π/128)) + Q_8_8(-0.359375), // sin(143*(π/128)) + Q_8_8(-0.37890625), // sin(144*(π/128)) + Q_8_8(-0.40234375), // sin(145*(π/128)) + Q_8_8(-0.42578125), // sin(146*(π/128)) + Q_8_8(-0.44921875), // sin(147*(π/128)) + Q_8_8(-0.46875), // sin(148*(π/128)) + Q_8_8(-0.4921875), // sin(149*(π/128)) + Q_8_8(-0.51171875), // sin(150*(π/128)) + Q_8_8(-0.53125), // sin(151*(π/128)) + Q_8_8(-0.5546875), // sin(152*(π/128)) + Q_8_8(-0.57421875), // sin(153*(π/128)) + Q_8_8(-0.59375), // sin(154*(π/128)) + Q_8_8(-0.61328125), // sin(155*(π/128)) + Q_8_8(-0.6328125), // sin(156*(π/128)) + Q_8_8(-0.65234375), // sin(157*(π/128)) + Q_8_8(-0.66796875), // sin(158*(π/128)) + Q_8_8(-0.6875), // sin(159*(π/128)) + Q_8_8(-0.70703125), // sin(160*(π/128)) + Q_8_8(-0.72265625), // sin(161*(π/128)) + Q_8_8(-0.73828125), // sin(162*(π/128)) + Q_8_8(-0.75390625), // sin(163*(π/128)) + Q_8_8(-0.76953125), // sin(164*(π/128)) + Q_8_8(-0.78515625), // sin(165*(π/128)) + Q_8_8(-0.80078125), // sin(166*(π/128)) + Q_8_8(-0.81640625), // sin(167*(π/128)) + Q_8_8(-0.828125), // sin(168*(π/128)) + Q_8_8(-0.84375), // sin(169*(π/128)) + Q_8_8(-0.85546875), // sin(170*(π/128)) + Q_8_8(-0.8671875), // sin(171*(π/128)) + Q_8_8(-0.87890625), // sin(172*(π/128)) + Q_8_8(-0.890625), // sin(173*(π/128)) + Q_8_8(-0.90234375), // sin(174*(π/128)) + Q_8_8(-0.9140625), // sin(175*(π/128)) + Q_8_8(-0.921875), // sin(176*(π/128)) + Q_8_8(-0.9296875), // sin(177*(π/128)) + Q_8_8(-0.94140625), // sin(178*(π/128)) + Q_8_8(-0.94921875), // sin(179*(π/128)) + Q_8_8(-0.953125), // sin(180*(π/128)) + Q_8_8(-0.9609375), // sin(181*(π/128)) + Q_8_8(-0.96875), // sin(182*(π/128)) + Q_8_8(-0.97265625), // sin(183*(π/128)) + Q_8_8(-0.98046875), // sin(184*(π/128)) + Q_8_8(-0.984375), // sin(185*(π/128)) + Q_8_8(-0.98828125), // sin(186*(π/128)) + Q_8_8(-0.9921875), // sin(187*(π/128)) + Q_8_8(-0.9921875), // sin(188*(π/128)) + Q_8_8(-0.99609375), // sin(189*(π/128)) + Q_8_8(-0.99609375), // sin(190*(π/128)) + Q_8_8(-0.99609375), // sin(191*(π/128)) + Q_8_8(-1), // sin(192*(π/128)) + Q_8_8(-0.99609375), // sin(193*(π/128)) + Q_8_8(-0.99609375), // sin(194*(π/128)) + Q_8_8(-0.99609375), // sin(195*(π/128)) + Q_8_8(-0.9921875), // sin(196*(π/128)) + Q_8_8(-0.9921875), // sin(197*(π/128)) + Q_8_8(-0.98828125), // sin(198*(π/128)) + Q_8_8(-0.984375), // sin(199*(π/128)) + Q_8_8(-0.98046875), // sin(200*(π/128)) + Q_8_8(-0.97265625), // sin(201*(π/128)) + Q_8_8(-0.96875), // sin(202*(π/128)) + Q_8_8(-0.9609375), // sin(203*(π/128)) + Q_8_8(-0.953125), // sin(204*(π/128)) + Q_8_8(-0.94921875), // sin(205*(π/128)) + Q_8_8(-0.94140625), // sin(206*(π/128)) + Q_8_8(-0.9296875), // sin(207*(π/128)) + Q_8_8(-0.921875), // sin(208*(π/128)) + Q_8_8(-0.9140625), // sin(209*(π/128)) + Q_8_8(-0.90234375), // sin(210*(π/128)) + Q_8_8(-0.890625), // sin(211*(π/128)) + Q_8_8(-0.87890625), // sin(212*(π/128)) + Q_8_8(-0.8671875), // sin(213*(π/128)) + Q_8_8(-0.85546875), // sin(214*(π/128)) + Q_8_8(-0.84375), // sin(215*(π/128)) + Q_8_8(-0.828125), // sin(216*(π/128)) + Q_8_8(-0.81640625), // sin(217*(π/128)) + Q_8_8(-0.80078125), // sin(218*(π/128)) + Q_8_8(-0.78515625), // sin(219*(π/128)) + Q_8_8(-0.76953125), // sin(220*(π/128)) + Q_8_8(-0.75390625), // sin(221*(π/128)) + Q_8_8(-0.73828125), // sin(222*(π/128)) + Q_8_8(-0.72265625), // sin(223*(π/128)) + Q_8_8(-0.70703125), // sin(224*(π/128)) + Q_8_8(-0.6875), // sin(225*(π/128)) + Q_8_8(-0.66796875), // sin(226*(π/128)) + Q_8_8(-0.65234375), // sin(227*(π/128)) + Q_8_8(-0.6328125), // sin(228*(π/128)) + Q_8_8(-0.61328125), // sin(229*(π/128)) + Q_8_8(-0.59375), // sin(230*(π/128)) + Q_8_8(-0.57421875), // sin(231*(π/128)) + Q_8_8(-0.5546875), // sin(232*(π/128)) + Q_8_8(-0.53125), // sin(233*(π/128)) + Q_8_8(-0.51171875), // sin(234*(π/128)) + Q_8_8(-0.4921875), // sin(235*(π/128)) + Q_8_8(-0.46875), // sin(236*(π/128)) + Q_8_8(-0.44921875), // sin(237*(π/128)) + Q_8_8(-0.42578125), // sin(238*(π/128)) + Q_8_8(-0.40234375), // sin(239*(π/128)) + Q_8_8(-0.37890625), // sin(240*(π/128)) + Q_8_8(-0.359375), // sin(241*(π/128)) + Q_8_8(-0.3359375), // sin(242*(π/128)) + Q_8_8(-0.3125), // sin(243*(π/128)) + Q_8_8(-0.2890625), // sin(244*(π/128)) + Q_8_8(-0.265625), // sin(245*(π/128)) + Q_8_8(-0.2421875), // sin(246*(π/128)) + Q_8_8(-0.21875), // sin(247*(π/128)) + Q_8_8(-0.19140625), // sin(248*(π/128)) + Q_8_8(-0.16796875), // sin(249*(π/128)) + Q_8_8(-0.14453125), // sin(250*(π/128)) + Q_8_8(-0.12109375), // sin(251*(π/128)) + Q_8_8(-0.09765625), // sin(252*(π/128)) + Q_8_8(-0.0703125), // sin(253*(π/128)) + Q_8_8(-0.046875), // sin(254*(π/128)) + Q_8_8(-0.0234375), // sin(255*(π/128)) + Q_8_8(0), // sin(256*(π/128)) + Q_8_8(0.0234375), // sin(257*(π/128)) + Q_8_8(0.046875), // sin(258*(π/128)) + Q_8_8(0.0703125), // sin(259*(π/128)) + Q_8_8(0.09765625), // sin(260*(π/128)) + Q_8_8(0.12109375), // sin(261*(π/128)) + Q_8_8(0.14453125), // sin(262*(π/128)) + Q_8_8(0.16796875), // sin(263*(π/128)) + Q_8_8(0.19140625), // sin(264*(π/128)) + Q_8_8(0.21875), // sin(265*(π/128)) + Q_8_8(0.2421875), // sin(266*(π/128)) + Q_8_8(0.265625), // sin(267*(π/128)) + Q_8_8(0.2890625), // sin(268*(π/128)) + Q_8_8(0.3125), // sin(269*(π/128)) + Q_8_8(0.3359375), // sin(270*(π/128)) + Q_8_8(0.359375), // sin(271*(π/128)) + Q_8_8(0.37890625), // sin(272*(π/128)) + Q_8_8(0.40234375), // sin(273*(π/128)) + Q_8_8(0.42578125), // sin(274*(π/128)) + Q_8_8(0.44921875), // sin(275*(π/128)) + Q_8_8(0.46875), // sin(276*(π/128)) + Q_8_8(0.4921875), // sin(277*(π/128)) + Q_8_8(0.51171875), // sin(278*(π/128)) + Q_8_8(0.53125), // sin(279*(π/128)) + Q_8_8(0.5546875), // sin(280*(π/128)) + Q_8_8(0.57421875), // sin(281*(π/128)) + Q_8_8(0.59375), // sin(282*(π/128)) + Q_8_8(0.61328125), // sin(283*(π/128)) + Q_8_8(0.6328125), // sin(284*(π/128)) + Q_8_8(0.65234375), // sin(285*(π/128)) + Q_8_8(0.66796875), // sin(286*(π/128)) + Q_8_8(0.6875), // sin(287*(π/128)) + Q_8_8(0.70703125), // sin(288*(π/128)) + Q_8_8(0.72265625), // sin(289*(π/128)) + Q_8_8(0.73828125), // sin(290*(π/128)) + Q_8_8(0.75390625), // sin(291*(π/128)) + Q_8_8(0.76953125), // sin(292*(π/128)) + Q_8_8(0.78515625), // sin(293*(π/128)) + Q_8_8(0.80078125), // sin(294*(π/128)) + Q_8_8(0.81640625), // sin(295*(π/128)) + Q_8_8(0.828125), // sin(296*(π/128)) + Q_8_8(0.84375), // sin(297*(π/128)) + Q_8_8(0.85546875), // sin(298*(π/128)) + Q_8_8(0.8671875), // sin(299*(π/128)) + Q_8_8(0.87890625), // sin(300*(π/128)) + Q_8_8(0.890625), // sin(301*(π/128)) + Q_8_8(0.90234375), // sin(302*(π/128)) + Q_8_8(0.9140625), // sin(303*(π/128)) + Q_8_8(0.921875), // sin(304*(π/128)) + Q_8_8(0.9296875), // sin(305*(π/128)) + Q_8_8(0.94140625), // sin(306*(π/128)) + Q_8_8(0.94921875), // sin(307*(π/128)) + Q_8_8(0.953125), // sin(308*(π/128)) + Q_8_8(0.9609375), // sin(309*(π/128)) + Q_8_8(0.96875), // sin(310*(π/128)) + Q_8_8(0.97265625), // sin(311*(π/128)) + Q_8_8(0.98046875), // sin(312*(π/128)) + Q_8_8(0.984375), // sin(313*(π/128)) + Q_8_8(0.98828125), // sin(314*(π/128)) + Q_8_8(0.9921875), // sin(315*(π/128)) + Q_8_8(0.9921875), // sin(316*(π/128)) + Q_8_8(0.99609375), // sin(317*(π/128)) + Q_8_8(0.99609375), // sin(318*(π/128)) + Q_8_8(0.99609375), // sin(319*(π/128)) +}; + +// values of sin(x) as Q4.12 fixed-point numbers from x = 0° to x = 179° +const s16 gSineDegreeTable[] = +{ + Q_4_12(0), // sin(0°) + Q_4_12(0.017333984375), // sin(1°) + Q_4_12(0.034912109375), // sin(2°) + Q_4_12(0.05224609375), // sin(3°) + Q_4_12(0.06982421875), // sin(4°) + Q_4_12(0.087158203125), // sin(5°) + Q_4_12(0.1044921875), // sin(6°) + Q_4_12(0.121826171875), // sin(7°) + Q_4_12(0.13916015625), // sin(8°) + Q_4_12(0.156494140625), // sin(9°) + Q_4_12(0.173583984375), // sin(10°) + Q_4_12(0.19091796875), // sin(11°) + Q_4_12(0.2080078125), // sin(12°) + Q_4_12(0.224853515625), // sin(13°) + Q_4_12(0.241943359375), // sin(14°) + Q_4_12(0.2587890625), // sin(15°) + Q_4_12(0.275634765625), // sin(16°) + Q_4_12(0.29248046875), // sin(17°) + Q_4_12(0.30908203125), // sin(18°) + Q_4_12(0.32568359375), // sin(19°) + Q_4_12(0.342041015625), // sin(20°) + Q_4_12(0.3583984375), // sin(21°) + Q_4_12(0.37451171875), // sin(22°) + Q_4_12(0.390625), // sin(23°) + Q_4_12(0.40673828125), // sin(24°) + Q_4_12(0.422607421875), // sin(25°) + Q_4_12(0.4384765625), // sin(26°) + Q_4_12(0.4541015625), // sin(27°) + Q_4_12(0.469482421875), // sin(28°) + Q_4_12(0.48486328125), // sin(29°) + Q_4_12(0.5), // sin(30°) + Q_4_12(0.51513671875), // sin(31°) + Q_4_12(0.530029296875), // sin(32°) + Q_4_12(0.544677734375), // sin(33°) + Q_4_12(0.55908203125), // sin(34°) + Q_4_12(0.573486328125), // sin(35°) + Q_4_12(0.587890625), // sin(36°) + Q_4_12(0.601806640625), // sin(37°) + Q_4_12(0.61572265625), // sin(38°) + Q_4_12(0.62939453125), // sin(39°) + Q_4_12(0.642822265625), // sin(40°) + Q_4_12(0.656005859375), // sin(41°) + Q_4_12(0.669189453125), // sin(42°) + Q_4_12(0.681884765625), // sin(43°) + Q_4_12(0.694580078125), // sin(44°) + Q_4_12(0.70703125), // sin(45°) + Q_4_12(0.71923828125), // sin(46°) + Q_4_12(0.7314453125), // sin(47°) + Q_4_12(0.7431640625), // sin(48°) + Q_4_12(0.754638671875), // sin(49°) + Q_4_12(0.76611328125), // sin(50°) + Q_4_12(0.777099609375), // sin(51°) + Q_4_12(0.7880859375), // sin(52°) + Q_4_12(0.798583984375), // sin(53°) + Q_4_12(0.80908203125), // sin(54°) + Q_4_12(0.819091796875), // sin(55°) + Q_4_12(0.8291015625), // sin(56°) + Q_4_12(0.838623046875), // sin(57°) + Q_4_12(0.84814453125), // sin(58°) + Q_4_12(0.857177734375), // sin(59°) + Q_4_12(0.865966796875), // sin(60°) + Q_4_12(0.87451171875), // sin(61°) + Q_4_12(0.883056640625), // sin(62°) + Q_4_12(0.89111328125), // sin(63°) + Q_4_12(0.898681640625), // sin(64°) + Q_4_12(0.90625), // sin(65°) + Q_4_12(0.91357421875), // sin(66°) + Q_4_12(0.92041015625), // sin(67°) + Q_4_12(0.92724609375), // sin(68°) + Q_4_12(0.93359375), // sin(69°) + Q_4_12(0.939697265625), // sin(70°) + Q_4_12(0.945556640625), // sin(71°) + Q_4_12(0.951171875), // sin(72°) + Q_4_12(0.956298828125), // sin(73°) + Q_4_12(0.961181640625), // sin(74°) + Q_4_12(0.9658203125), // sin(75°) + Q_4_12(0.97021484375), // sin(76°) + Q_4_12(0.974365234375), // sin(77°) + Q_4_12(0.97802734375), // sin(78°) + Q_4_12(0.981689453125), // sin(79°) + Q_4_12(0.98486328125), // sin(80°) + Q_4_12(0.98779296875), // sin(81°) + Q_4_12(0.990234375), // sin(82°) + Q_4_12(0.992431640625), // sin(83°) + Q_4_12(0.994384765625), // sin(84°) + Q_4_12(0.99609375), // sin(85°) + Q_4_12(0.99755859375), // sin(86°) + Q_4_12(0.99853515625), // sin(87°) + Q_4_12(0.999267578125), // sin(88°) + Q_4_12(0.999755859375), // sin(89°) + Q_4_12(1), // sin(90°) + Q_4_12(0.999755859375), // sin(91°) + Q_4_12(0.999267578125), // sin(92°) + Q_4_12(0.99853515625), // sin(93°) + Q_4_12(0.99755859375), // sin(94°) + Q_4_12(0.99609375), // sin(95°) + Q_4_12(0.994384765625), // sin(96°) + Q_4_12(0.992431640625), // sin(97°) + Q_4_12(0.990234375), // sin(98°) + Q_4_12(0.98779296875), // sin(99°) + Q_4_12(0.98486328125), // sin(100°) + Q_4_12(0.981689453125), // sin(101°) + Q_4_12(0.97802734375), // sin(102°) + Q_4_12(0.974365234375), // sin(103°) + Q_4_12(0.97021484375), // sin(104°) + Q_4_12(0.9658203125), // sin(105°) + Q_4_12(0.961181640625), // sin(106°) + Q_4_12(0.956298828125), // sin(107°) + Q_4_12(0.951171875), // sin(108°) + Q_4_12(0.945556640625), // sin(109°) + Q_4_12(0.939697265625), // sin(110°) + Q_4_12(0.93359375), // sin(111°) + Q_4_12(0.92724609375), // sin(112°) + Q_4_12(0.92041015625), // sin(113°) + Q_4_12(0.91357421875), // sin(114°) + Q_4_12(0.90625), // sin(115°) + Q_4_12(0.898681640625), // sin(116°) + Q_4_12(0.89111328125), // sin(117°) + Q_4_12(0.883056640625), // sin(118°) + Q_4_12(0.87451171875), // sin(119°) + Q_4_12(0.865966796875), // sin(120°) + Q_4_12(0.857177734375), // sin(121°) + Q_4_12(0.84814453125), // sin(122°) + Q_4_12(0.838623046875), // sin(123°) + Q_4_12(0.8291015625), // sin(124°) + Q_4_12(0.819091796875), // sin(125°) + Q_4_12(0.80908203125), // sin(126°) + Q_4_12(0.798583984375), // sin(127°) + Q_4_12(0.7880859375), // sin(128°) + Q_4_12(0.777099609375), // sin(129°) + Q_4_12(0.76611328125), // sin(130°) + Q_4_12(0.754638671875), // sin(131°) + Q_4_12(0.7431640625), // sin(132°) + Q_4_12(0.7314453125), // sin(133°) + Q_4_12(0.71923828125), // sin(134°) + Q_4_12(0.70703125), // sin(135°) + Q_4_12(0.694580078125), // sin(136°) + Q_4_12(0.681884765625), // sin(137°) + Q_4_12(0.669189453125), // sin(138°) + Q_4_12(0.656005859375), // sin(139°) + Q_4_12(0.642822265625), // sin(140°) + Q_4_12(0.62939453125), // sin(141°) + Q_4_12(0.61572265625), // sin(142°) + Q_4_12(0.601806640625), // sin(143°) + Q_4_12(0.587890625), // sin(144°) + Q_4_12(0.573486328125), // sin(145°) + Q_4_12(0.55908203125), // sin(146°) + Q_4_12(0.544677734375), // sin(147°) + Q_4_12(0.530029296875), // sin(148°) + Q_4_12(0.51513671875), // sin(149°) + Q_4_12(0.5), // sin(150°) + Q_4_12(0.48486328125), // sin(151°) + Q_4_12(0.469482421875), // sin(152°) + Q_4_12(0.4541015625), // sin(153°) + Q_4_12(0.4384765625), // sin(154°) + Q_4_12(0.422607421875), // sin(155°) + Q_4_12(0.40673828125), // sin(156°) + Q_4_12(0.390625), // sin(157°) + Q_4_12(0.37451171875), // sin(158°) + Q_4_12(0.3583984375), // sin(159°) + Q_4_12(0.342041015625), // sin(160°) + Q_4_12(0.32568359375), // sin(161°) + Q_4_12(0.30908203125), // sin(162°) + Q_4_12(0.29248046875), // sin(163°) + Q_4_12(0.275634765625), // sin(164°) + Q_4_12(0.2587890625), // sin(165°) + Q_4_12(0.241943359375), // sin(166°) + Q_4_12(0.224853515625), // sin(167°) + Q_4_12(0.2080078125), // sin(168°) + Q_4_12(0.19091796875), // sin(169°) + Q_4_12(0.173583984375), // sin(170°) + Q_4_12(0.156494140625), // sin(171°) + Q_4_12(0.13916015625), // sin(172°) + Q_4_12(0.121826171875), // sin(173°) + Q_4_12(0.1044921875), // sin(174°) + Q_4_12(0.087158203125), // sin(175°) + Q_4_12(0.06982421875), // sin(176°) + Q_4_12(0.05224609375), // sin(177°) + Q_4_12(0.034912109375), // sin(178°) + Q_4_12(0.017333984375), // sin(179°) +}; + +// amplitude * sin(index*(π/128)) +s16 Sin(s16 index, s16 amplitude) +{ + return (amplitude * gSineTable[index]) >> 8; +} + +// amplitude * cos(index*(π/128)) +s16 Cos(s16 index, s16 amplitude) +{ + return (amplitude * gSineTable[index + 64]) >> 8; +} + +// angle in degrees +s16 Sin2(u16 angle) +{ + s32 angleMod = angle % 180; + s32 negate = ((angle / 180) & 1); + s16 value = gSineDegreeTable[angleMod]; + + if (negate) + return -value; + else + return value; +} + +// angle in degrees +s16 Cos2(u16 angle) +{ + return Sin2(angle + 90); +} diff --git a/src/window.c b/src/window.c index aeae9e1ed..f3d2e833e 100644 --- a/src/window.c +++ b/src/window.c @@ -1,33 +1,38 @@ #include "global.h" #include "window.h" +#include "malloc.h" extern u8 gUnknown_03002F60; extern void* gUnknown_03002F70[]; extern u32 gUnneededFireRedVariable; -EWRAM_DATA struct Window gWindows[20]; + +#define WINDOWS_MAX 32 + +EWRAM_DATA struct Window gWindows[WINDOWS_MAX] = {0}; +EWRAM_DATA static struct Window* sWindowPtr = NULL; +EWRAM_DATA static u16 sWindowSize = 0; extern void* GetBgTilemapBuffer(u8 bg); extern int DummiedOutFireRedLeafGreenTileAllocFunc(int, int, int, int); extern u16 GetBgAttribute(u8 bg, u8 attributeId); -extern void *AllocZeroed(u16 size); -extern void FreeAllWindowBuffers(void); extern void SetBgTilemapBuffer(u8 bg, void *tilemap); -extern u8 GetNumActiveWindowsOnBg(u8 bgId); -extern void Free(void *pointer); extern void CopyBgTilemapBufferToVram(u8 bg); extern u8 LoadBgTiles(u8 bg, void *src, u16 size, u16 destOffset); extern void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, u16 tileNumDelta); extern void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette); extern void BlitBitmapRect4Bit(struct Bitmap *src, struct Bitmap *dest, u16 srcX, u16 srcY, u16 destX, u16 destY, u16 width, u16 height, u8 colorKey); +extern void BlitBitmapRect4BitTo8Bit(struct Bitmap *src, struct Bitmap *dest, u16 srcX, u16 srcY, u16 destX, u16 destY, u16 width, u16 height, u8 colorKey, u8 paletteNum); extern void FillBitmapRect4Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); +extern void FillBitmapRect8Bit(struct Bitmap *surface, u16 x, u16 y, u16 width, u16 height, u8 fillValue); -void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight); +static u8 GetNumActiveWindowsOnBg(u8 bgId); +static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId); -extern const struct WindowTemplate gDummyWindowTemplate; +static const struct WindowTemplate sDummyWindowTemplate = {0xFF, 0, 0, 0, 0, 0, 0}; -void nullsub_8(void) +static void nullsub_8(void) { - + } bool16 InitWindows(struct WindowTemplate *templates) @@ -39,7 +44,7 @@ bool16 InitWindows(struct WindowTemplate *templates) u16 attrib; u8* allocatedTilemapBuffer; int allocatedBaseBlock; - + for (i = 0; i < 0x4; ++i) { bgTilemapBuffer = GetBgTilemapBuffer(i); @@ -48,13 +53,13 @@ bool16 InitWindows(struct WindowTemplate *templates) else gUnknown_03002F70[i] = bgTilemapBuffer; } - + for (i = 0; i < 0x20; ++i) { - gWindows[i].window = gDummyWindowTemplate; + gWindows[i].window = sDummyWindowTemplate; gWindows[i].tileData = NULL; } - + for (i = 0, allocatedBaseBlock = 0, bgLayer = templates[i].priority; bgLayer != 0xFF && i < 0x20; ++i, bgLayer = templates[i].priority) { if (gUnneededFireRedVariable == 1) @@ -63,31 +68,31 @@ bool16 InitWindows(struct WindowTemplate *templates) if (allocatedBaseBlock == -1) return FALSE; } - + if (gUnknown_03002F70[bgLayer] == NULL) { attrib = GetBgAttribute(bgLayer, 0x8); - + if (attrib != 0xFFFF) { allocatedTilemapBuffer = AllocZeroed(attrib); - + if (allocatedTilemapBuffer == NULL) { FreeAllWindowBuffers(); return FALSE; } - + for (j = 0; j < attrib; ++j) allocatedTilemapBuffer[j] = 0; - + gUnknown_03002F70[bgLayer] = allocatedTilemapBuffer; SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); } } - - allocatedTilemapBuffer = AllocZeroed(0x20 * (templates[i].width * templates[i].height)); - + + allocatedTilemapBuffer = AllocZeroed((u16)(0x20 * (templates[i].width * templates[i].height))); + if (allocatedTilemapBuffer == NULL) { if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gUnknown_03002F70[bgLayer] != nullsub_8)) @@ -95,20 +100,20 @@ bool16 InitWindows(struct WindowTemplate *templates) Free(gUnknown_03002F70[bgLayer]); gUnknown_03002F70[bgLayer] = allocatedTilemapBuffer; } - + return FALSE; } - + gWindows[i].tileData = allocatedTilemapBuffer; gWindows[i].window = templates[i]; - + if (gUnneededFireRedVariable == 1) { gWindows[i].window.baseBlock = allocatedBaseBlock; DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, allocatedBaseBlock, templates[i].width * templates[i].height, 1); } } - + gUnknown_03002F60 = 0; return TRUE; } @@ -127,42 +132,42 @@ u16 AddWindow(struct WindowTemplate *template) if ((bgLayer = gWindows[win].window.priority) == 0xFF) break; } - + if (win == 0x20) return 0xFF; - + bgLayer = template->priority; allocatedBaseBlock = 0; - + if (gUnneededFireRedVariable == 1) { allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); - + if (allocatedBaseBlock == -1) return 0xFF; } - + if (gUnknown_03002F70[bgLayer] == NULL) { attrib = GetBgAttribute(bgLayer, 0x8); - + if (attrib != 0xFFFF) { allocatedTilemapBuffer = AllocZeroed(attrib); - + if (allocatedTilemapBuffer == NULL) return 0xFF; - + for (i = 0; i < attrib; ++i) allocatedTilemapBuffer[i] = 0; - + gUnknown_03002F70[bgLayer] = allocatedTilemapBuffer; SetBgTilemapBuffer(bgLayer, allocatedTilemapBuffer); } } - - allocatedTilemapBuffer = AllocZeroed(0x20 * (template->width * template->height)); - + + allocatedTilemapBuffer = AllocZeroed((u16)(0x20 * (template->width * template->height))); + if (allocatedTilemapBuffer == NULL) { if ((GetNumActiveWindowsOnBg(bgLayer) == 0) && (gUnknown_03002F70[bgLayer] != nullsub_8)) @@ -172,10 +177,10 @@ u16 AddWindow(struct WindowTemplate *template) } return 0xFF; } - + gWindows[win].tileData = allocatedTilemapBuffer; gWindows[win].window = *template; - + if (gUnneededFireRedVariable == 1) { gWindows[win].window.baseBlock = allocatedBaseBlock; @@ -190,29 +195,29 @@ int AddWindowWithoutTileMap(struct WindowTemplate *template) u16 win; u8 bgLayer; int allocatedBaseBlock; - + for (win = 0; win < 0x20; ++win) { if (gWindows[win].window.priority == 0xFF) break; } - + if (win == 0x20) return 0xFF; - + bgLayer = template->priority; allocatedBaseBlock = 0; - + if (gUnneededFireRedVariable == 1) { allocatedBaseBlock = DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, 0, template->width * template->height, 0); - + if (allocatedBaseBlock == -1) return 0xFF; } - + gWindows[win].window = *template; - + if (gUnneededFireRedVariable == 1) { gWindows[win].window.baseBlock = allocatedBaseBlock; @@ -225,14 +230,14 @@ int AddWindowWithoutTileMap(struct WindowTemplate *template) void RemoveWindow(u8 windowId) { u8 bgLayer = gWindows[windowId].window.priority; - + if (gUnneededFireRedVariable == 1) { DummiedOutFireRedLeafGreenTileAllocFunc(bgLayer, gWindows[windowId].window.baseBlock, gWindows[windowId].window.width * gWindows[windowId].window.height, 2); } - - gWindows[windowId].window = gDummyWindowTemplate; - + + gWindows[windowId].window = sDummyWindowTemplate; + if (GetNumActiveWindowsOnBg(bgLayer) == 0) { if (gUnknown_03002F70[bgLayer] != nullsub_8) @@ -241,7 +246,7 @@ void RemoveWindow(u8 windowId) gUnknown_03002F70[bgLayer] = 0; } } - + if (gWindows[windowId].tileData != NULL) { Free(gWindows[windowId].tileData); @@ -252,7 +257,7 @@ void RemoveWindow(u8 windowId) void FreeAllWindowBuffers(void) { int i; - + for (i = 0; i < 4; ++i) { if (gUnknown_03002F70[i] != NULL && gUnknown_03002F70[i] != nullsub_8) @@ -261,7 +266,7 @@ void FreeAllWindowBuffers(void) gUnknown_03002F70[i] = NULL; } } - + for (i = 0; i < 0x20; ++i) { if (gWindows[i].tileData != NULL) @@ -301,14 +306,14 @@ void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h) if (w != 0 && h != 0) { windowLocal = gWindows[windowId]; - + rectSize = ((h - 1) * windowLocal.window.width); rectSize += (windowLocal.window.width - x); rectSize -= (windowLocal.window.width - (x + w)); rectSize *= 32; - + rectPos = (y * windowLocal.window.width) + x; - + switch (mode) { case 1: @@ -328,7 +333,7 @@ void CopyWindowRectToVram(u32 windowId, u32 mode, u32 x, u32 y, u32 w, u32 h) void PutWindowTilemap(u8 windowId) { struct Window windowLocal = gWindows[windowId]; - + WriteSequenceToBgTilemapBuffer( windowLocal.window.priority, GetBgAttribute(windowLocal.window.priority, 0xA) + windowLocal.window.baseBlock, @@ -345,7 +350,7 @@ void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 h struct Window windowLocal = gWindows[windowId]; u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.priority, 0xA); int i; - + for (i = 0; i < height; ++i) { WriteSequenceToBgTilemapBuffer( @@ -357,7 +362,7 @@ void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 h 1, palette, 1); - + currentRow += windowLocal.window.width; } } @@ -365,7 +370,7 @@ void PutWindowRectTilemapOverridePalette(u8 windowId, u8 x, u8 y, u8 width, u8 h void ClearWindowTilemap(u8 windowId) { struct Window windowLocal = gWindows[windowId]; - + FillBgTilemapBufferRect( windowLocal.window.priority, gUnknown_03002F60, @@ -381,7 +386,7 @@ void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) struct Window windowLocal = gWindows[windowId]; u16 currentRow = windowLocal.window.baseBlock + (y * windowLocal.window.width) + x + GetBgAttribute(windowLocal.window.priority, 0xA); int i; - + for (i = 0; i < height; ++i) { WriteSequenceToBgTilemapBuffer( @@ -393,7 +398,7 @@ void PutWindowRectTilemap(u8 windowId, u8 x, u8 y, u8 width, u8 height) 1, windowLocal.window.paletteNum, 1); - + currentRow += windowLocal.window.width; } } @@ -415,11 +420,11 @@ void BlitBitmapRectToWindow(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u destRect.pixels = gWindows[windowId].tileData; destRect.width = 8 * gWindows[windowId].window.width; destRect.height = 8 * gWindows[windowId].window.height; - + BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0); } -void BlitBitmapRectToWindowWithColorKey(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 colorKey) +static void BlitBitmapRectToWindowWithColorKey(u8 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 colorKey) { struct Bitmap sourceRect; struct Bitmap destRect; @@ -431,7 +436,7 @@ void BlitBitmapRectToWindowWithColorKey(u8 windowId, const u8 *pixels, u16 srcX, destRect.pixels = gWindows[windowId].tileData; destRect.width = 8 * gWindows[windowId].window.width; destRect.height = 8 * gWindows[windowId].window.height; - + BlitBitmapRect4Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, colorKey); } @@ -442,7 +447,7 @@ void FillWindowPixelRect(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 pixelRect.pixels = gWindows[windowId].tileData; pixelRect.width = 8 * gWindows[windowId].window.width; pixelRect.height = 8 * gWindows[windowId].window.height; - + FillBitmapRect4Bit(&pixelRect, x, y, width, height, fillValue); } @@ -459,3 +464,885 @@ void FillWindowPixelBuffer(u8 windowId, u8 fillValue) int fillSize = gWindows[windowId].window.width * gWindows[windowId].window.height; CpuFastFill8(fillValue, gWindows[windowId].tileData, 0x20 * fillSize); } + +// functionally equivalent, its fucking hard to match +#ifdef NONMATCHING +void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue) +{ + s32 i, id1, id2, size; + u32 distanceLoop, toFill, width; + u8 *tileData; + struct WindowTemplate window; + + tileData = gWindows[windowId].tileData; + toFill = (fillValue << 0x18) | (fillValue << 0x10) | (fillValue << 8) | fillValue; + window = gWindows[windowId].window; + size = 0x20 * (window.height * window.width); + width = window.width; + if (direction != 1) + { + s32 signedDirection = direction; + if (signedDirection <= 1) + { + if (signedDirection == 0) + { + for (i = 0; i < size; i += 0x20) + { + distanceLoop = distance; + id1 = i + 0; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + + distanceLoop++; + id1 = i + 4; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + + distanceLoop++; + id1 = i + 8; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + + distanceLoop++; + id1 = i + 12; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + + distanceLoop++; + id1 = i + 16; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + + distanceLoop++; + id1 = i + 20; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + + distanceLoop++; + id1 = i + 24; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + + distanceLoop++; + id1 = i + 28; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData + id1) = *(u32*)(tileData + id2); + else + *(u32*)(tileData + id1) = toFill; + } + } + } + } + else + { + tileData += size - 4; + for (i = 0; i < size; i += 0x20) + { + distanceLoop = distance; + id1 = i + 0; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + + distanceLoop++; + id1 = i + 4; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + + distanceLoop++; + id1 = i + 8; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + + distanceLoop++; + id1 = i + 12; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + + distanceLoop++; + id1 = i + 16; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + + distanceLoop++; + id1 = i + 20; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + + distanceLoop++; + id1 = i + 24; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + + distanceLoop++; + id1 = i + 28; + id2 = i + (((width * ((distanceLoop) & ~(7))) | ((distanceLoop) & 7)) * 4); + if (id2 < size) + *(u32*)(tileData - id1) = *(u32*)(tileData - id2); + else + *(u32*)(tileData - id1) = toFill; + } + } +} +#else +__attribute__((naked)) +void ScrollWindow(u8 windowId, u8 direction, u8 distance, u8 fillValue) +{ + asm(".syntax unified\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0x8\n\ + lsls r0, 24\n\ + lsrs r0, 24\n\ + lsls r1, 24\n\ + lsrs r1, 24\n\ + mov r8, r1\n\ + lsls r2, 24\n\ + lsrs r2, 24\n\ + str r2, [sp]\n\ + lsls r3, 24\n\ + lsrs r3, 24\n\ + ldr r2, =gWindows\n\ + lsls r1, r0, 1\n\ + adds r1, r0\n\ + lsls r1, 2\n\ + adds r4, r1, r2\n\ + adds r2, 0x8\n\ + adds r1, r2\n\ + ldr r5, [r1]\n\ + lsls r7, r3, 24\n\ + lsls r0, r3, 16\n\ + orrs r7, r0\n\ + lsls r0, r3, 8\n\ + orrs r7, r0\n\ + orrs r7, r3\n\ + ldr r1, [r4]\n\ + ldr r2, [r4, 0x4]\n\ + ldrb r3, [r4, 0x4]\n\ + lsrs r0, r1, 24\n\ + muls r0, r3\n\ + lsls r6, r0, 5\n\ + lsrs r1, 24\n\ + mov r12, r1\n\ + mov r0, r8\n\ + cmp r0, 0x1\n\ + bne _08003CE8\n\ + b _08003E9E\n\ +_08003CE8:\n\ + cmp r0, 0x1\n\ + ble _08003CEE\n\ + b _08004046\n\ +_08003CEE:\n\ + cmp r0, 0\n\ + beq _08003CF4\n\ + b _08004046\n\ +_08003CF4:\n\ + movs r4, 0\n\ + cmp r4, r6\n\ + blt _08003CFC\n\ + b _08004046\n\ +_08003CFC:\n\ + movs r1, 0x8\n\ + negs r1, r1\n\ + mov r9, r1\n\ + movs r2, 0x7\n\ + mov r8, r2\n\ + mov r10, r5\n\ +_08003D08:\n\ + ldr r3, [sp]\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + adds r0, r3, 0\n\ + mov r2, r8\n\ + ands r0, r2\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003D34\n\ + adds r0, r5, r1\n\ + ldr r0, [r0]\n\ + mov r1, r10\n\ + str r0, [r1]\n\ + b _08003D38\n\ + .pool\n\ +_08003D34:\n\ + mov r2, r10\n\ + str r7, [r2]\n\ +_08003D38:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0x4\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003D64\n\ + adds r0, r5, r2\n\ + adds r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003D68\n\ +_08003D64:\n\ + adds r0, r5, r2\n\ + str r7, [r0]\n\ +_08003D68:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x8\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003D96\n\ + adds r0, r5, r2\n\ + adds r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003D9A\n\ +_08003D96:\n\ + adds r0, r5, r2\n\ + str r7, [r0]\n\ +_08003D9A:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0xC\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003DC8\n\ + adds r0, r5, r2\n\ + adds r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003DCC\n\ +_08003DC8:\n\ + adds r0, r5, r2\n\ + str r7, [r0]\n\ +_08003DCC:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x10\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003DFA\n\ + adds r0, r5, r2\n\ + adds r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003DFE\n\ +_08003DFA:\n\ + adds r0, r5, r2\n\ + str r7, [r0]\n\ +_08003DFE:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x14\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003E2C\n\ + adds r0, r5, r2\n\ + adds r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003E30\n\ +_08003E2C:\n\ + adds r0, r5, r2\n\ + str r7, [r0]\n\ +_08003E30:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x18\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003E5E\n\ + adds r0, r5, r2\n\ + adds r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003E62\n\ +_08003E5E:\n\ + adds r0, r5, r2\n\ + str r7, [r0]\n\ +_08003E62:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x1C\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + adds r0, r1, 0\n\ + mov r1, r8\n\ + ands r3, r1\n\ + orrs r0, r3\n\ + lsls r0, 2\n\ + adds r1, r4, r0\n\ + cmp r1, r6\n\ + bge _08003E8C\n\ + adds r0, r5, r2\n\ + adds r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003E90\n\ +_08003E8C:\n\ + adds r0, r5, r2\n\ + str r7, [r0]\n\ +_08003E90:\n\ + movs r2, 0x20\n\ + add r10, r2\n\ + adds r4, 0x20\n\ + cmp r4, r6\n\ + bge _08003E9C\n\ + b _08003D08\n\ +_08003E9C:\n\ + b _08004046\n\ +_08003E9E:\n\ + subs r0, r6, 0x4\n\ + adds r5, r0\n\ + movs r4, 0\n\ + cmp r4, r6\n\ + blt _08003EAA\n\ + b _08004046\n\ +_08003EAA:\n\ + movs r0, 0x8\n\ + negs r0, r0\n\ + mov r9, r0\n\ + movs r1, 0x7\n\ + mov r8, r1\n\ + mov r10, r5\n\ +_08003EB6:\n\ + ldr r3, [sp]\n\ + adds r0, r3, 0\n\ + mov r2, r9\n\ + ands r0, r2\n\ + mov r1, r12\n\ + muls r1, r0\n\ + adds r0, r3, 0\n\ + mov r2, r8\n\ + ands r0, r2\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003EDC\n\ + subs r0, r5, r1\n\ + ldr r0, [r0]\n\ + mov r1, r10\n\ + str r0, [r1]\n\ + b _08003EE0\n\ +_08003EDC:\n\ + mov r2, r10\n\ + str r7, [r2]\n\ +_08003EE0:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0x4\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003F0C\n\ + subs r0, r5, r2\n\ + subs r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003F10\n\ +_08003F0C:\n\ + subs r0, r5, r2\n\ + str r7, [r0]\n\ +_08003F10:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x8\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003F3E\n\ + subs r0, r5, r2\n\ + subs r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003F42\n\ +_08003F3E:\n\ + subs r0, r5, r2\n\ + str r7, [r0]\n\ +_08003F42:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0xC\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003F70\n\ + subs r0, r5, r2\n\ + subs r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003F74\n\ +_08003F70:\n\ + subs r0, r5, r2\n\ + str r7, [r0]\n\ +_08003F74:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x10\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003FA2\n\ + subs r0, r5, r2\n\ + subs r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003FA6\n\ +_08003FA2:\n\ + subs r0, r5, r2\n\ + str r7, [r0]\n\ +_08003FA6:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x14\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08003FD4\n\ + subs r0, r5, r2\n\ + subs r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08003FD8\n\ +_08003FD4:\n\ + subs r0, r5, r2\n\ + str r7, [r0]\n\ +_08003FD8:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x18\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + str r1, [sp, 0x4]\n\ + adds r0, r3, 0\n\ + mov r1, r8\n\ + ands r0, r1\n\ + ldr r1, [sp, 0x4]\n\ + orrs r1, r0\n\ + lsls r1, 2\n\ + adds r1, r4, r1\n\ + cmp r1, r6\n\ + bge _08004006\n\ + subs r0, r5, r2\n\ + subs r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _0800400A\n\ +_08004006:\n\ + subs r0, r5, r2\n\ + str r7, [r0]\n\ +_0800400A:\n\ + adds r3, 0x1\n\ + adds r2, r4, 0\n\ + adds r2, 0x1C\n\ + adds r0, r3, 0\n\ + mov r1, r9\n\ + ands r0, r1\n\ + mov r1, r12\n\ + muls r1, r0\n\ + adds r0, r1, 0\n\ + mov r1, r8\n\ + ands r3, r1\n\ + orrs r0, r3\n\ + lsls r0, 2\n\ + adds r1, r4, r0\n\ + cmp r1, r6\n\ + bge _08004034\n\ + subs r0, r5, r2\n\ + subs r1, r5, r1\n\ + ldr r1, [r1]\n\ + str r1, [r0]\n\ + b _08004038\n\ +_08004034:\n\ + subs r0, r5, r2\n\ + str r7, [r0]\n\ +_08004038:\n\ + movs r2, 0x20\n\ + negs r2, r2\n\ + add r10, r2\n\ + adds r4, 0x20\n\ + cmp r4, r6\n\ + bge _08004046\n\ + b _08003EB6\n\ +_08004046:\n\ + add sp, 0x8\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .syntax divided"); +} +#endif // NONMATCHING + +void CallWindowFunction(u8 windowId, void ( *func)(u8, u8, u8, u8, u8, u8)) +{ + struct WindowTemplate window = gWindows[windowId].window; + func(window.priority, window.tilemapLeft, window.tilemapTop, window.width, window.height, window.paletteNum); +} + +bool8 SetWindowAttribute(u8 windowId, u8 attributeId, u32 value) +{ + switch (attributeId) + { + case WINDOW_TILEMAP_LEFT: + gWindows[windowId].window.tilemapLeft = value; + return FALSE; + case WINDOW_TILEMAP_TOP: + gWindows[windowId].window.tilemapTop = value; + return FALSE; + case WINDOW_PALETTE_NUM: + gWindows[windowId].window.paletteNum = value; + return FALSE; + case WINDOW_BASE_BLOCK: + gWindows[windowId].window.baseBlock = value; + return FALSE; + case WINDOW_TILE_DATA: + gWindows[windowId].tileData = (u8*)(value); + return TRUE; + case WINDOW_PRIORITY: + case WINDOW_WIDTH: + case WINDOW_HEIGHT: + default: + return TRUE; + } +} + +u32 GetWindowAttribute(u8 windowId, u8 attributeId) +{ + switch (attributeId) + { + case WINDOW_PRIORITY: + return gWindows[windowId].window.priority; + case WINDOW_TILEMAP_LEFT: + return gWindows[windowId].window.tilemapLeft; + case WINDOW_TILEMAP_TOP: + return gWindows[windowId].window.tilemapTop; + case WINDOW_WIDTH: + return gWindows[windowId].window.width; + case WINDOW_HEIGHT: + return gWindows[windowId].window.height; + case WINDOW_PALETTE_NUM: + return gWindows[windowId].window.paletteNum; + case WINDOW_BASE_BLOCK: + return gWindows[windowId].window.baseBlock; + case WINDOW_TILE_DATA: + return (u32)(gWindows[windowId].tileData); + default: + return 0; + } +} + +static u8 GetNumActiveWindowsOnBg(u8 bgId) +{ + u8 windowsNum = 0; + s32 i; + for (i = 0; i < WINDOWS_MAX; i++) + { + if (gWindows[i].window.priority == bgId) + windowsNum++; + } + return windowsNum; +} + +static void nullsub_9(void) +{ + +} + +u16 AddWindow8Bit(struct WindowTemplate *template) +{ + u16 windowId; + u8* memAddress; + u8 bgLayer; + + for (windowId = 0; windowId < 32; windowId++) + { + if (gWindows[windowId].window.priority == 0xFF) + break; + } + if (windowId == WINDOWS_MAX) + return 0xFF; + bgLayer = template->priority; + if (gUnknown_03002F70[bgLayer] == 0) + { + u16 attribute = GetBgAttribute(bgLayer, 8); + if (attribute != 0xFFFF) + { + s32 i; + memAddress = Alloc(attribute); + if (memAddress == NULL) + return 0xFF; + for (i = 0; i < attribute; i++) // if we're going to zero out the memory anyway, why not call AllocZeroed? + memAddress[i] = 0; + gUnknown_03002F70[bgLayer] = memAddress; + SetBgTilemapBuffer(bgLayer, memAddress); + } + } + memAddress = Alloc((u16)(0x40 * (template->width * template->height))); + if (memAddress == NULL) + { + if (GetNumActiveWindowsOnBg8Bit(bgLayer) == 0 && gUnknown_03002F70[bgLayer] != nullsub_9) + { + Free(gUnknown_03002F70[bgLayer]); + gUnknown_03002F70[bgLayer] = NULL; + } + return 0xFF; + } + else + { + gWindows[windowId].tileData = memAddress; + gWindows[windowId].window = *template; + return windowId; + } +} + +void FillWindowPixelBuffer8Bit(u8 windowId, u8 fillValue) +{ + s32 i; + s32 size; + + size = (u16)(0x40 * (gWindows[windowId].window.width * gWindows[windowId].window.height)); + for (i = 0; i < size; i++) + gWindows[windowId].tileData[i] = fillValue; +} + +void FillWindowPixelRect8Bit(u8 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height) +{ + struct Bitmap pixelRect; + + pixelRect.pixels = gWindows[windowId].tileData; + pixelRect.width = 8 * gWindows[windowId].window.width; + pixelRect.height = 8 * gWindows[windowId].window.height; + + FillBitmapRect8Bit(&pixelRect, x, y, width, height, fillValue); +} + +void BlitBitmapRectToWindow4BitTo8Bit(u8 windowId, u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum) +{ + struct Bitmap sourceRect; + struct Bitmap destRect; + + sourceRect.pixels = (u8*)pixels; + sourceRect.width = srcWidth; + sourceRect.height = srcHeight; + + destRect.pixels = gWindows[windowId].tileData; + destRect.width = 8 * gWindows[windowId].window.width; + destRect.height = 8 * gWindows[windowId].window.height; + + BlitBitmapRect4BitTo8Bit(&sourceRect, &destRect, srcX, srcY, destX, destY, rectWidth, rectHeight, 0, paletteNum); +} + +void CopyWindowToVram8Bit(u8 windowId, u8 mode) +{ + sWindowPtr = &gWindows[windowId]; + sWindowSize = 0x40 * (sWindowPtr->window.width * sWindowPtr->window.height); + + switch (mode) + { + case 1: + CopyBgTilemapBufferToVram(sWindowPtr->window.priority); + break; + case 2: + LoadBgTiles(sWindowPtr->window.priority, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + break; + case 3: + LoadBgTiles(sWindowPtr->window.priority, sWindowPtr->tileData, sWindowSize, sWindowPtr->window.baseBlock); + CopyBgTilemapBufferToVram(sWindowPtr->window.priority); + break; + } +} + +static u8 GetNumActiveWindowsOnBg8Bit(u8 bgId) +{ + u8 windowsNum = 0; + s32 i; + for (i = 0; i < WINDOWS_MAX; i++) + { + if (gWindows[i].window.priority == bgId) + windowsNum++; + } + return windowsNum; +} |